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