• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define LOG_TAG "BitmapFactory"
2 
3 #include "BitmapFactory.h"
4 #include "CreateJavaOutputStreamAdaptor.h"
5 #include "GraphicsJNI.h"
6 #include "NinePatchPeeker.h"
7 #include "SkAndroidCodec.h"
8 #include "SkBRDAllocator.h"
9 #include "SkFrontBufferedStream.h"
10 #include "SkMakeUnique.h"
11 #include "SkMath.h"
12 #include "SkPixelRef.h"
13 #include "SkStream.h"
14 #include "SkUtils.h"
15 #include "Utils.h"
16 #include "core_jni_helpers.h"
17 
18 #include <nativehelper/JNIHelp.h>
19 #include <androidfw/Asset.h>
20 #include <androidfw/ResourceTypes.h>
21 #include <cutils/compiler.h>
22 #include <memory>
23 #include <netinet/in.h>
24 #include <stdio.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 
28 jfieldID gOptions_justBoundsFieldID;
29 jfieldID gOptions_sampleSizeFieldID;
30 jfieldID gOptions_configFieldID;
31 jfieldID gOptions_colorSpaceFieldID;
32 jfieldID gOptions_premultipliedFieldID;
33 jfieldID gOptions_mutableFieldID;
34 jfieldID gOptions_ditherFieldID;
35 jfieldID gOptions_preferQualityOverSpeedFieldID;
36 jfieldID gOptions_scaledFieldID;
37 jfieldID gOptions_densityFieldID;
38 jfieldID gOptions_screenDensityFieldID;
39 jfieldID gOptions_targetDensityFieldID;
40 jfieldID gOptions_widthFieldID;
41 jfieldID gOptions_heightFieldID;
42 jfieldID gOptions_mimeFieldID;
43 jfieldID gOptions_outConfigFieldID;
44 jfieldID gOptions_outColorSpaceFieldID;
45 jfieldID gOptions_mCancelID;
46 jfieldID gOptions_bitmapFieldID;
47 
48 jfieldID gBitmap_ninePatchInsetsFieldID;
49 
50 jclass gBitmapConfig_class;
51 jmethodID gBitmapConfig_nativeToConfigMethodID;
52 
53 using namespace android;
54 
encodedFormatToString(JNIEnv * env,SkEncodedImageFormat format)55 jstring encodedFormatToString(JNIEnv* env, SkEncodedImageFormat format) {
56     const char* mimeType;
57     switch (format) {
58         case SkEncodedImageFormat::kBMP:
59             mimeType = "image/bmp";
60             break;
61         case SkEncodedImageFormat::kGIF:
62             mimeType = "image/gif";
63             break;
64         case SkEncodedImageFormat::kICO:
65             mimeType = "image/x-ico";
66             break;
67         case SkEncodedImageFormat::kJPEG:
68             mimeType = "image/jpeg";
69             break;
70         case SkEncodedImageFormat::kPNG:
71             mimeType = "image/png";
72             break;
73         case SkEncodedImageFormat::kWEBP:
74             mimeType = "image/webp";
75             break;
76         case SkEncodedImageFormat::kHEIF:
77             mimeType = "image/heif";
78             break;
79         case SkEncodedImageFormat::kWBMP:
80             mimeType = "image/vnd.wap.wbmp";
81             break;
82         case SkEncodedImageFormat::kDNG:
83             mimeType = "image/x-adobe-dng";
84             break;
85         default:
86             mimeType = nullptr;
87             break;
88     }
89 
90     jstring jstr = nullptr;
91     if (mimeType) {
92         // NOTE: Caller should env->ExceptionCheck() for OOM
93         // (can't check for nullptr as it's a valid return value)
94         jstr = env->NewStringUTF(mimeType);
95     }
96     return jstr;
97 }
98 
99 class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
100 public:
ScaleCheckingAllocator(float scale,int size)101     ScaleCheckingAllocator(float scale, int size)
102             : mScale(scale), mSize(size) {
103     }
104 
allocPixelRef(SkBitmap * bitmap)105     virtual bool allocPixelRef(SkBitmap* bitmap) {
106         // accounts for scale in final allocation, using eventual size and config
107         const int bytesPerPixel = SkColorTypeBytesPerPixel(bitmap->colorType());
108         const int requestedSize = bytesPerPixel *
109                 int(bitmap->width() * mScale + 0.5f) *
110                 int(bitmap->height() * mScale + 0.5f);
111         if (requestedSize > mSize) {
112             ALOGW("bitmap for alloc reuse (%d bytes) can't fit scaled bitmap (%d bytes)",
113                     mSize, requestedSize);
114             return false;
115         }
116         return SkBitmap::HeapAllocator::allocPixelRef(bitmap);
117     }
118 private:
119     const float mScale;
120     const int mSize;
121 };
122 
123 class RecyclingPixelAllocator : public SkBitmap::Allocator {
124 public:
RecyclingPixelAllocator(android::Bitmap * bitmap,unsigned int size)125     RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size)
126             : mBitmap(bitmap), mSize(size) {
127     }
128 
~RecyclingPixelAllocator()129     ~RecyclingPixelAllocator() {
130     }
131 
allocPixelRef(SkBitmap * bitmap)132     virtual bool allocPixelRef(SkBitmap* bitmap) {
133         const SkImageInfo& info = bitmap->info();
134         if (info.colorType() == kUnknown_SkColorType) {
135             ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
136             return false;
137         }
138 
139         const size_t size = info.computeByteSize(bitmap->rowBytes());
140         if (size > SK_MaxS32) {
141             ALOGW("bitmap is too large");
142             return false;
143         }
144 
145         if (size > mSize) {
146             ALOGW("bitmap marked for reuse (%u bytes) can't fit new bitmap "
147                   "(%zu bytes)", mSize, size);
148             return false;
149         }
150 
151         mBitmap->reconfigure(info, bitmap->rowBytes());
152         bitmap->setPixelRef(sk_ref_sp(mBitmap), 0, 0);
153         return true;
154     }
155 
156 private:
157     android::Bitmap* const mBitmap;
158     const unsigned int mSize;
159 };
160 
161 // Necessary for decodes when the native decoder cannot scale to appropriately match the sampleSize
162 // (for example, RAW). If the sampleSize divides evenly into the dimension, we require that the
163 // scale matches exactly. If sampleSize does not divide evenly, we allow the decoder to choose how
164 // best to round.
needsFineScale(const int fullSize,const int decodedSize,const int sampleSize)165 static bool needsFineScale(const int fullSize, const int decodedSize, const int sampleSize) {
166     if (fullSize % sampleSize == 0 && fullSize / sampleSize != decodedSize) {
167         return true;
168     } else if ((fullSize / sampleSize + 1) != decodedSize &&
169                (fullSize / sampleSize) != decodedSize) {
170         return true;
171     }
172     return false;
173 }
174 
needsFineScale(const SkISize fullSize,const SkISize decodedSize,const int sampleSize)175 static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
176                            const int sampleSize) {
177     return needsFineScale(fullSize.width(), decodedSize.width(), sampleSize) ||
178            needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
179 }
180 
doDecode(JNIEnv * env,std::unique_ptr<SkStreamRewindable> stream,jobject padding,jobject options)181 static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
182                         jobject padding, jobject options) {
183     // Set default values for the options parameters.
184     int sampleSize = 1;
185     bool onlyDecodeSize = false;
186     SkColorType prefColorType = kN32_SkColorType;
187     bool isHardware = false;
188     bool isMutable = false;
189     float scale = 1.0f;
190     bool requireUnpremultiplied = false;
191     jobject javaBitmap = NULL;
192     sk_sp<SkColorSpace> prefColorSpace = nullptr;
193 
194     // Update with options supplied by the client.
195     if (options != NULL) {
196         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
197         // Correct a non-positive sampleSize.  sampleSize defaults to zero within the
198         // options object, which is strange.
199         if (sampleSize <= 0) {
200             sampleSize = 1;
201         }
202 
203         if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) {
204             onlyDecodeSize = true;
205         }
206 
207         // initialize these, in case we fail later on
208         env->SetIntField(options, gOptions_widthFieldID, -1);
209         env->SetIntField(options, gOptions_heightFieldID, -1);
210         env->SetObjectField(options, gOptions_mimeFieldID, 0);
211         env->SetObjectField(options, gOptions_outConfigFieldID, 0);
212         env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0);
213 
214         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
215         prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
216         jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
217         prefColorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
218         isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
219         isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
220         requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
221         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
222 
223         if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
224             const int density = env->GetIntField(options, gOptions_densityFieldID);
225             const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
226             const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
227             if (density != 0 && targetDensity != 0 && density != screenDensity) {
228                 scale = (float) targetDensity / density;
229             }
230         }
231     }
232 
233     if (isMutable && isHardware) {
234         doThrowIAE(env, "Bitmaps with Config.HARWARE are always immutable");
235         return nullObjectReturn("Cannot create mutable hardware bitmap");
236     }
237 
238     // Create the codec.
239     NinePatchPeeker peeker;
240     std::unique_ptr<SkAndroidCodec> codec;
241     {
242         SkCodec::Result result;
243         std::unique_ptr<SkCodec> c = SkCodec::MakeFromStream(std::move(stream), &result,
244                                                              &peeker);
245         if (!c) {
246             SkString msg;
247             msg.printf("Failed to create image decoder with message '%s'",
248                        SkCodec::ResultToString(result));
249             return nullObjectReturn(msg.c_str());
250         }
251 
252         codec = SkAndroidCodec::MakeFromCodec(std::move(c));
253         if (!codec) {
254             return nullObjectReturn("SkAndroidCodec::MakeFromCodec returned null");
255         }
256     }
257 
258     // Do not allow ninepatch decodes to 565.  In the past, decodes to 565
259     // would dither, and we do not want to pre-dither ninepatches, since we
260     // know that they will be stretched.  We no longer dither 565 decodes,
261     // but we continue to prevent ninepatches from decoding to 565, in order
262     // to maintain the old behavior.
263     if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) {
264         prefColorType = kN32_SkColorType;
265     }
266 
267     // Determine the output size.
268     SkISize size = codec->getSampledDimensions(sampleSize);
269 
270     int scaledWidth = size.width();
271     int scaledHeight = size.height();
272     bool willScale = false;
273 
274     // Apply a fine scaling step if necessary.
275     if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize)) {
276         willScale = true;
277         scaledWidth = codec->getInfo().width() / sampleSize;
278         scaledHeight = codec->getInfo().height() / sampleSize;
279     }
280 
281     // Set the decode colorType
282     SkColorType decodeColorType = codec->computeOutputColorType(prefColorType);
283     sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(
284             decodeColorType, prefColorSpace);
285 
286     // Set the options and return if the client only wants the size.
287     if (options != NULL) {
288         jstring mimeType = encodedFormatToString(
289                 env, (SkEncodedImageFormat)codec->getEncodedFormat());
290         if (env->ExceptionCheck()) {
291             return nullObjectReturn("OOM in encodedFormatToString()");
292         }
293         env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
294         env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
295         env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
296 
297         jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType);
298         if (isHardware) {
299             configID = GraphicsJNI::kHardware_LegacyBitmapConfig;
300         }
301         jobject config = env->CallStaticObjectMethod(gBitmapConfig_class,
302                 gBitmapConfig_nativeToConfigMethodID, configID);
303         env->SetObjectField(options, gOptions_outConfigFieldID, config);
304 
305         env->SetObjectField(options, gOptions_outColorSpaceFieldID,
306                 GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
307 
308         if (onlyDecodeSize) {
309             return nullptr;
310         }
311     }
312 
313     // Scale is necessary due to density differences.
314     if (scale != 1.0f) {
315         willScale = true;
316         scaledWidth = static_cast<int>(scaledWidth * scale + 0.5f);
317         scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
318     }
319 
320     android::Bitmap* reuseBitmap = nullptr;
321     unsigned int existingBufferSize = 0;
322     if (javaBitmap != NULL) {
323         reuseBitmap = &bitmap::toBitmap(env, javaBitmap);
324         if (reuseBitmap->isImmutable()) {
325             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
326             javaBitmap = NULL;
327             reuseBitmap = nullptr;
328         } else {
329             existingBufferSize = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
330         }
331     }
332 
333     HeapAllocator defaultAllocator;
334     RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
335     ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
336     SkBitmap::HeapAllocator heapAllocator;
337     SkBitmap::Allocator* decodeAllocator;
338     if (javaBitmap != nullptr && willScale) {
339         // This will allocate pixels using a HeapAllocator, since there will be an extra
340         // scaling step that copies these pixels into Java memory.  This allocator
341         // also checks that the recycled javaBitmap is large enough.
342         decodeAllocator = &scaleCheckingAllocator;
343     } else if (javaBitmap != nullptr) {
344         decodeAllocator = &recyclingAllocator;
345     } else if (willScale || isHardware) {
346         // This will allocate pixels using a HeapAllocator,
347         // for scale case: there will be an extra scaling step.
348         // for hardware case: there will be extra swizzling & upload to gralloc step.
349         decodeAllocator = &heapAllocator;
350     } else {
351         decodeAllocator = &defaultAllocator;
352     }
353 
354     SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
355 
356     const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(),
357             decodeColorType, alphaType, decodeColorSpace);
358 
359     // For wide gamut images, we will leave the color space on the SkBitmap.  Otherwise,
360     // use the default.
361     SkImageInfo bitmapInfo = decodeInfo;
362     if (decodeInfo.colorSpace() && decodeInfo.colorSpace()->isSRGB()) {
363         bitmapInfo = bitmapInfo.makeColorSpace(GraphicsJNI::colorSpaceForType(decodeColorType));
364     }
365 
366     if (decodeColorType == kGray_8_SkColorType) {
367         // The legacy implementation of BitmapFactory used kAlpha8 for
368         // grayscale images (before kGray8 existed).  While the codec
369         // recognizes kGray8, we need to decode into a kAlpha8 bitmap
370         // in order to avoid a behavior change.
371         bitmapInfo =
372                 bitmapInfo.makeColorType(kAlpha_8_SkColorType).makeAlphaType(kPremul_SkAlphaType);
373     }
374     SkBitmap decodingBitmap;
375     if (!decodingBitmap.setInfo(bitmapInfo) ||
376             !decodingBitmap.tryAllocPixels(decodeAllocator)) {
377         // SkAndroidCodec should recommend a valid SkImageInfo, so setInfo()
378         // should only only fail if the calculated value for rowBytes is too
379         // large.
380         // tryAllocPixels() can fail due to OOM on the Java heap, OOM on the
381         // native heap, or the recycled javaBitmap being too small to reuse.
382         return nullptr;
383     }
384 
385     // Use SkAndroidCodec to perform the decode.
386     SkAndroidCodec::AndroidOptions codecOptions;
387     codecOptions.fZeroInitialized = decodeAllocator == &defaultAllocator ?
388             SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
389     codecOptions.fSampleSize = sampleSize;
390     SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(),
391             decodingBitmap.rowBytes(), &codecOptions);
392     switch (result) {
393         case SkCodec::kSuccess:
394         case SkCodec::kIncompleteInput:
395             break;
396         default:
397             return nullObjectReturn("codec->getAndroidPixels() failed.");
398     }
399 
400     // This is weird so let me explain: we could use the scale parameter
401     // directly, but for historical reasons this is how the corresponding
402     // Dalvik code has always behaved. We simply recreate the behavior here.
403     // The result is slightly different from simply using scale because of
404     // the 0.5f rounding bias applied when computing the target image size
405     const float scaleX = scaledWidth / float(decodingBitmap.width());
406     const float scaleY = scaledHeight / float(decodingBitmap.height());
407 
408     jbyteArray ninePatchChunk = NULL;
409     if (peeker.mPatch != NULL) {
410         if (willScale) {
411             peeker.scale(scaleX, scaleY, scaledWidth, scaledHeight);
412         }
413 
414         size_t ninePatchArraySize = peeker.mPatch->serializedSize();
415         ninePatchChunk = env->NewByteArray(ninePatchArraySize);
416         if (ninePatchChunk == NULL) {
417             return nullObjectReturn("ninePatchChunk == null");
418         }
419 
420         jbyte* array = (jbyte*) env->GetPrimitiveArrayCritical(ninePatchChunk, NULL);
421         if (array == NULL) {
422             return nullObjectReturn("primitive array == null");
423         }
424 
425         memcpy(array, peeker.mPatch, peeker.mPatchSize);
426         env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
427     }
428 
429     jobject ninePatchInsets = NULL;
430     if (peeker.mHasInsets) {
431         ninePatchInsets = peeker.createNinePatchInsets(env, scale);
432         if (ninePatchInsets == NULL) {
433             return nullObjectReturn("nine patch insets == null");
434         }
435         if (javaBitmap != NULL) {
436             env->SetObjectField(javaBitmap, gBitmap_ninePatchInsetsFieldID, ninePatchInsets);
437         }
438     }
439 
440     SkBitmap outputBitmap;
441     if (willScale) {
442         // Set the allocator for the outputBitmap.
443         SkBitmap::Allocator* outputAllocator;
444         if (javaBitmap != nullptr) {
445             outputAllocator = &recyclingAllocator;
446         } else {
447             outputAllocator = &defaultAllocator;
448         }
449 
450         SkColorType scaledColorType = decodingBitmap.colorType();
451         // FIXME: If the alphaType is kUnpremul and the image has alpha, the
452         // colors may not be correct, since Skia does not yet support drawing
453         // to/from unpremultiplied bitmaps.
454         outputBitmap.setInfo(
455                 bitmapInfo.makeWH(scaledWidth, scaledHeight).makeColorType(scaledColorType));
456         if (!outputBitmap.tryAllocPixels(outputAllocator)) {
457             // This should only fail on OOM.  The recyclingAllocator should have
458             // enough memory since we check this before decoding using the
459             // scaleCheckingAllocator.
460             return nullObjectReturn("allocation failed for scaled bitmap");
461         }
462 
463         SkPaint paint;
464         // kSrc_Mode instructs us to overwrite the uninitialized pixels in
465         // outputBitmap.  Otherwise we would blend by default, which is not
466         // what we want.
467         paint.setBlendMode(SkBlendMode::kSrc);
468         paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering
469 
470         SkCanvas canvas(outputBitmap, SkCanvas::ColorBehavior::kLegacy);
471         canvas.scale(scaleX, scaleY);
472         canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
473     } else {
474         outputBitmap.swap(decodingBitmap);
475     }
476 
477     if (padding) {
478         peeker.getPadding(env, padding);
479     }
480 
481     // If we get here, the outputBitmap should have an installed pixelref.
482     if (outputBitmap.pixelRef() == NULL) {
483         return nullObjectReturn("Got null SkPixelRef");
484     }
485 
486     if (!isMutable && javaBitmap == NULL) {
487         // promise we will never change our pixels (great for sharing and pictures)
488         outputBitmap.setImmutable();
489     }
490 
491     bool isPremultiplied = !requireUnpremultiplied;
492     if (javaBitmap != nullptr) {
493         bitmap::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
494         outputBitmap.notifyPixelsChanged();
495         // If a java bitmap was passed in for reuse, pass it back
496         return javaBitmap;
497     }
498 
499     int bitmapCreateFlags = 0x0;
500     if (isMutable) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Mutable;
501     if (isPremultiplied) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
502 
503     if (isHardware) {
504         sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(outputBitmap);
505         if (!hardwareBitmap.get()) {
506             return nullObjectReturn("Failed to allocate a hardware bitmap");
507         }
508         return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags,
509                 ninePatchChunk, ninePatchInsets, -1);
510     }
511 
512     // now create the java bitmap
513     return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
514             bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
515 }
516 
nativeDecodeStream(JNIEnv * env,jobject clazz,jobject is,jbyteArray storage,jobject padding,jobject options)517 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
518         jobject padding, jobject options) {
519 
520     jobject bitmap = NULL;
521     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
522 
523     if (stream.get()) {
524         std::unique_ptr<SkStreamRewindable> bufferedStream(
525                 SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
526         SkASSERT(bufferedStream.get() != NULL);
527         bitmap = doDecode(env, std::move(bufferedStream), padding, options);
528     }
529     return bitmap;
530 }
531 
nativeDecodeFileDescriptor(JNIEnv * env,jobject clazz,jobject fileDescriptor,jobject padding,jobject bitmapFactoryOptions)532 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
533         jobject padding, jobject bitmapFactoryOptions) {
534 
535     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
536 
537     int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
538 
539     struct stat fdStat;
540     if (fstat(descriptor, &fdStat) == -1) {
541         doThrowIOE(env, "broken file descriptor");
542         return nullObjectReturn("fstat return -1");
543     }
544 
545     // Restore the descriptor's offset on exiting this function. Even though
546     // we dup the descriptor, both the original and dup refer to the same open
547     // file description and changes to the file offset in one impact the other.
548     AutoFDSeek autoRestore(descriptor);
549 
550     // Duplicate the descriptor here to prevent leaking memory. A leak occurs
551     // if we only close the file descriptor and not the file object it is used to
552     // create.  If we don't explicitly clean up the file (which in turn closes the
553     // descriptor) the buffers allocated internally by fseek will be leaked.
554     int dupDescriptor = dup(descriptor);
555 
556     FILE* file = fdopen(dupDescriptor, "r");
557     if (file == NULL) {
558         // cleanup the duplicated descriptor since it will not be closed when the
559         // file is cleaned up (fclose).
560         close(dupDescriptor);
561         return nullObjectReturn("Could not open file");
562     }
563 
564     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
565 
566     // If there is no offset for the file descriptor, we use SkFILEStream directly.
567     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
568         assert(isSeekable(dupDescriptor));
569         return doDecode(env, std::move(fileStream), padding, bitmapFactoryOptions);
570     }
571 
572     // Use a buffered stream. Although an SkFILEStream can be rewound, this
573     // ensures that SkImageDecoder::Factory never rewinds beyond the
574     // current position of the file descriptor.
575     std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream),
576             SkCodec::MinBufferedBytesNeeded()));
577 
578     return doDecode(env, std::move(stream), padding, bitmapFactoryOptions);
579 }
580 
nativeDecodeAsset(JNIEnv * env,jobject clazz,jlong native_asset,jobject padding,jobject options)581 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
582         jobject padding, jobject options) {
583 
584     Asset* asset = reinterpret_cast<Asset*>(native_asset);
585     // since we know we'll be done with the asset when we return, we can
586     // just use a simple wrapper
587     return doDecode(env, skstd::make_unique<AssetStreamAdaptor>(asset), padding, options);
588 }
589 
nativeDecodeByteArray(JNIEnv * env,jobject,jbyteArray byteArray,jint offset,jint length,jobject options)590 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
591         jint offset, jint length, jobject options) {
592 
593     AutoJavaByteArray ar(env, byteArray);
594     return doDecode(env, skstd::make_unique<SkMemoryStream>(ar.ptr() + offset, length, false),
595                     nullptr, options);
596 }
597 
nativeIsSeekable(JNIEnv * env,jobject,jobject fileDescriptor)598 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
599     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
600     return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE;
601 }
602 
decodeBitmap(JNIEnv * env,void * data,size_t size)603 jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
604     return doDecode(env, skstd::make_unique<SkMemoryStream>(data, size),
605                     nullptr, nullptr);
606 }
607 
608 ///////////////////////////////////////////////////////////////////////////////
609 
610 static const JNINativeMethod gMethods[] = {
611     {   "nativeDecodeStream",
612         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
613         (void*)nativeDecodeStream
614     },
615 
616     {   "nativeDecodeFileDescriptor",
617         "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
618         (void*)nativeDecodeFileDescriptor
619     },
620 
621     {   "nativeDecodeAsset",
622         "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
623         (void*)nativeDecodeAsset
624     },
625 
626     {   "nativeDecodeByteArray",
627         "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
628         (void*)nativeDecodeByteArray
629     },
630 
631     {   "nativeIsSeekable",
632         "(Ljava/io/FileDescriptor;)Z",
633         (void*)nativeIsSeekable
634     },
635 };
636 
register_android_graphics_BitmapFactory(JNIEnv * env)637 int register_android_graphics_BitmapFactory(JNIEnv* env) {
638     jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
639     gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
640             "Landroid/graphics/Bitmap;");
641     gOptions_justBoundsFieldID = GetFieldIDOrDie(env, options_class, "inJustDecodeBounds", "Z");
642     gOptions_sampleSizeFieldID = GetFieldIDOrDie(env, options_class, "inSampleSize", "I");
643     gOptions_configFieldID = GetFieldIDOrDie(env, options_class, "inPreferredConfig",
644             "Landroid/graphics/Bitmap$Config;");
645     gOptions_colorSpaceFieldID = GetFieldIDOrDie(env, options_class, "inPreferredColorSpace",
646             "Landroid/graphics/ColorSpace;");
647     gOptions_premultipliedFieldID = GetFieldIDOrDie(env, options_class, "inPremultiplied", "Z");
648     gOptions_mutableFieldID = GetFieldIDOrDie(env, options_class, "inMutable", "Z");
649     gOptions_ditherFieldID = GetFieldIDOrDie(env, options_class, "inDither", "Z");
650     gOptions_preferQualityOverSpeedFieldID = GetFieldIDOrDie(env, options_class,
651             "inPreferQualityOverSpeed", "Z");
652     gOptions_scaledFieldID = GetFieldIDOrDie(env, options_class, "inScaled", "Z");
653     gOptions_densityFieldID = GetFieldIDOrDie(env, options_class, "inDensity", "I");
654     gOptions_screenDensityFieldID = GetFieldIDOrDie(env, options_class, "inScreenDensity", "I");
655     gOptions_targetDensityFieldID = GetFieldIDOrDie(env, options_class, "inTargetDensity", "I");
656     gOptions_widthFieldID = GetFieldIDOrDie(env, options_class, "outWidth", "I");
657     gOptions_heightFieldID = GetFieldIDOrDie(env, options_class, "outHeight", "I");
658     gOptions_mimeFieldID = GetFieldIDOrDie(env, options_class, "outMimeType", "Ljava/lang/String;");
659     gOptions_outConfigFieldID = GetFieldIDOrDie(env, options_class, "outConfig",
660              "Landroid/graphics/Bitmap$Config;");
661     gOptions_outColorSpaceFieldID = GetFieldIDOrDie(env, options_class, "outColorSpace",
662              "Landroid/graphics/ColorSpace;");
663     gOptions_mCancelID = GetFieldIDOrDie(env, options_class, "mCancel", "Z");
664 
665     jclass bitmap_class = FindClassOrDie(env, "android/graphics/Bitmap");
666     gBitmap_ninePatchInsetsFieldID = GetFieldIDOrDie(env, bitmap_class, "mNinePatchInsets",
667             "Landroid/graphics/NinePatch$InsetStruct;");
668 
669     gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
670             "android/graphics/Bitmap$Config"));
671     gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class,
672             "nativeToConfig", "(I)Landroid/graphics/Bitmap$Config;");
673 
674     return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
675                                          gMethods, NELEM(gMethods));
676 }
677