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