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