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