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