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