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