• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #define LOG_TAG "BitmapFactory"
2 
3 #include "BitmapFactory.h"
4 #include "NinePatchPeeker.h"
5 #include "SkData.h"
6 #include "SkFrontBufferedStream.h"
7 #include "SkImageDecoder.h"
8 #include "SkImageRef_ashmem.h"
9 #include "SkImageRef_GlobalPool.h"
10 #include "SkPixelRef.h"
11 #include "SkStream.h"
12 #include "SkTemplates.h"
13 #include "SkUtils.h"
14 #include "CreateJavaOutputStreamAdaptor.h"
15 #include "AutoDecodeCancel.h"
16 #include "Utils.h"
17 #include "JNIHelp.h"
18 #include "GraphicsJNI.h"
19 
20 #include <android_runtime/AndroidRuntime.h>
21 #include <androidfw/Asset.h>
22 #include <androidfw/ResourceTypes.h>
23 #include <netinet/in.h>
24 #include <stdio.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 
28 jfieldID gOptions_justBoundsFieldID;
29 jfieldID gOptions_sampleSizeFieldID;
30 jfieldID gOptions_configFieldID;
31 jfieldID gOptions_premultipliedFieldID;
32 jfieldID gOptions_mutableFieldID;
33 jfieldID gOptions_ditherFieldID;
34 jfieldID gOptions_purgeableFieldID;
35 jfieldID gOptions_shareableFieldID;
36 jfieldID gOptions_preferQualityOverSpeedFieldID;
37 jfieldID gOptions_scaledFieldID;
38 jfieldID gOptions_densityFieldID;
39 jfieldID gOptions_screenDensityFieldID;
40 jfieldID gOptions_targetDensityFieldID;
41 jfieldID gOptions_widthFieldID;
42 jfieldID gOptions_heightFieldID;
43 jfieldID gOptions_mimeFieldID;
44 jfieldID gOptions_mCancelID;
45 jfieldID gOptions_bitmapFieldID;
46 jfieldID gBitmap_nativeBitmapFieldID;
47 jfieldID gBitmap_layoutBoundsFieldID;
48 
49 #if 0
50     #define TRACE_BITMAP(code)  code
51 #else
52     #define TRACE_BITMAP(code)
53 #endif
54 
55 using namespace android;
56 
validOrNeg1(bool isValid,int32_t value)57 static inline int32_t validOrNeg1(bool isValid, int32_t value) {
58 //    return isValid ? value : -1;
59     SkASSERT((int)isValid == 0 || (int)isValid == 1);
60     return ((int32_t)isValid - 1) | value;
61 }
62 
getMimeTypeString(JNIEnv * env,SkImageDecoder::Format format)63 jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
64     static const struct {
65         SkImageDecoder::Format fFormat;
66         const char*            fMimeType;
67     } gMimeTypes[] = {
68         { SkImageDecoder::kBMP_Format,  "image/bmp" },
69         { SkImageDecoder::kGIF_Format,  "image/gif" },
70         { SkImageDecoder::kICO_Format,  "image/x-ico" },
71         { SkImageDecoder::kJPEG_Format, "image/jpeg" },
72         { SkImageDecoder::kPNG_Format,  "image/png" },
73         { SkImageDecoder::kWEBP_Format, "image/webp" },
74         { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
75     };
76 
77     const char* cstr = NULL;
78     for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
79         if (gMimeTypes[i].fFormat == format) {
80             cstr = gMimeTypes[i].fMimeType;
81             break;
82         }
83     }
84 
85     jstring jstr = 0;
86     if (NULL != cstr) {
87         jstr = env->NewStringUTF(cstr);
88     }
89     return jstr;
90 }
91 
optionsPurgeable(JNIEnv * env,jobject options)92 static bool optionsPurgeable(JNIEnv* env, jobject options) {
93     return options != NULL && env->GetBooleanField(options, gOptions_purgeableFieldID);
94 }
95 
optionsShareable(JNIEnv * env,jobject options)96 static bool optionsShareable(JNIEnv* env, jobject options) {
97     return options != NULL && env->GetBooleanField(options, gOptions_shareableFieldID);
98 }
99 
optionsJustBounds(JNIEnv * env,jobject options)100 static bool optionsJustBounds(JNIEnv* env, jobject options) {
101     return options != NULL && env->GetBooleanField(options, gOptions_justBoundsFieldID);
102 }
103 
scaleNinePatchChunk(android::Res_png_9patch * chunk,float scale)104 static void scaleNinePatchChunk(android::Res_png_9patch* chunk, float scale) {
105     chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
106     chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
107     chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
108     chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
109 
110     for (int i = 0; i < chunk->numXDivs; i++) {
111         chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f);
112         if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) {
113             chunk->xDivs[i]++;
114         }
115     }
116 
117     for (int i = 0; i < chunk->numYDivs; i++) {
118         chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
119         if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
120             chunk->yDivs[i]++;
121         }
122     }
123 }
124 
installPixelRef(SkBitmap * bitmap,SkStreamRewindable * stream,int sampleSize,bool ditherImage)125 static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
126         int sampleSize, bool ditherImage) {
127 
128     SkImageInfo bitmapInfo;
129     if (!bitmap->asImageInfo(&bitmapInfo)) {
130         ALOGW("bitmap has unknown configuration so no memory has been allocated");
131         return NULL;
132     }
133 
134     SkImageRef* pr;
135     // only use ashmem for large images, since mmaps come at a price
136     if (bitmap->getSize() >= 32 * 1024) {
137         pr = new SkImageRef_ashmem(bitmapInfo, stream, sampleSize);
138     } else {
139         pr = new SkImageRef_GlobalPool(bitmapInfo, stream, sampleSize);
140     }
141     pr->setDitherImage(ditherImage);
142     bitmap->setPixelRef(pr)->unref();
143     pr->isOpaque(bitmap);
144     return pr;
145 }
146 
configForScaledOutput(SkBitmap::Config config)147 static SkBitmap::Config configForScaledOutput(SkBitmap::Config config) {
148     switch (config) {
149         case SkBitmap::kNo_Config:
150         case SkBitmap::kIndex8_Config:
151             return SkBitmap::kARGB_8888_Config;
152         default:
153             break;
154     }
155     return config;
156 }
157 
158 class ScaleCheckingAllocator : public SkBitmap::HeapAllocator {
159 public:
ScaleCheckingAllocator(float scale,int size)160     ScaleCheckingAllocator(float scale, int size)
161             : mScale(scale), mSize(size) {
162     }
163 
allocPixelRef(SkBitmap * bitmap,SkColorTable * ctable)164     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
165         // accounts for scale in final allocation, using eventual size and config
166         const int bytesPerPixel = SkBitmap::ComputeBytesPerPixel(
167                 configForScaledOutput(bitmap->config()));
168         const int requestedSize = bytesPerPixel *
169                 int(bitmap->width() * mScale + 0.5f) *
170                 int(bitmap->height() * mScale + 0.5f);
171         if (requestedSize > mSize) {
172             ALOGW("bitmap for alloc reuse (%d bytes) can't fit scaled bitmap (%d bytes)",
173                     mSize, requestedSize);
174             return false;
175         }
176         return SkBitmap::HeapAllocator::allocPixelRef(bitmap, ctable);
177     }
178 private:
179     const float mScale;
180     const int mSize;
181 };
182 
183 class RecyclingPixelAllocator : public SkBitmap::Allocator {
184 public:
RecyclingPixelAllocator(SkPixelRef * pixelRef,unsigned int size)185     RecyclingPixelAllocator(SkPixelRef* pixelRef, unsigned int size)
186             : mPixelRef(pixelRef), mSize(size) {
187         SkSafeRef(mPixelRef);
188     }
189 
~RecyclingPixelAllocator()190     ~RecyclingPixelAllocator() {
191         SkSafeUnref(mPixelRef);
192     }
193 
allocPixelRef(SkBitmap * bitmap,SkColorTable * ctable)194     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
195         if (!bitmap->getSize64().is32() || bitmap->getSize() > mSize) {
196             ALOGW("bitmap marked for reuse (%d bytes) can't fit new bitmap (%d bytes)",
197                     mSize, bitmap->getSize());
198             return false;
199         }
200 
201         SkImageInfo bitmapInfo;
202         if (!bitmap->asImageInfo(&bitmapInfo)) {
203             ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
204             return false;
205         }
206 
207         // Create a new pixelref with the new ctable that wraps the previous pixelref
208         SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef),
209                 bitmapInfo, bitmap->rowBytes(), ctable);
210 
211         bitmap->setPixelRef(pr)->unref();
212         // since we're already allocated, we lockPixels right away
213         // HeapAllocator/JavaPixelAllocator behaves this way too
214         bitmap->lockPixels();
215         return true;
216     }
217 
218 private:
219     SkPixelRef* const mPixelRef;
220     const unsigned int mSize;
221 };
222 
223 // since we "may" create a purgeable imageref, we require the stream be ref'able
224 // i.e. dynamically allocated, since its lifetime may exceed the current stack
225 // frame.
doDecode(JNIEnv * env,SkStreamRewindable * stream,jobject padding,jobject options,bool allowPurgeable,bool forcePurgeable=false)226 static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding,
227         jobject options, bool allowPurgeable, bool forcePurgeable = false) {
228 
229     int sampleSize = 1;
230 
231     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
232     SkBitmap::Config prefConfig = SkBitmap::kARGB_8888_Config;
233 
234     bool doDither = true;
235     bool isMutable = false;
236     float scale = 1.0f;
237     bool isPurgeable = forcePurgeable || (allowPurgeable && optionsPurgeable(env, options));
238     bool preferQualityOverSpeed = false;
239     bool requireUnpremultiplied = false;
240 
241     jobject javaBitmap = NULL;
242 
243     if (options != NULL) {
244         sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
245         if (optionsJustBounds(env, options)) {
246             mode = SkImageDecoder::kDecodeBounds_Mode;
247         }
248 
249         // initialize these, in case we fail later on
250         env->SetIntField(options, gOptions_widthFieldID, -1);
251         env->SetIntField(options, gOptions_heightFieldID, -1);
252         env->SetObjectField(options, gOptions_mimeFieldID, 0);
253 
254         jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
255         prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
256         isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
257         doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
258         preferQualityOverSpeed = env->GetBooleanField(options,
259                 gOptions_preferQualityOverSpeedFieldID);
260         requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
261         javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
262 
263         if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
264             const int density = env->GetIntField(options, gOptions_densityFieldID);
265             const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
266             const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
267             if (density != 0 && targetDensity != 0 && density != screenDensity) {
268                 scale = (float) targetDensity / density;
269             }
270         }
271     }
272 
273     const bool willScale = scale != 1.0f;
274     isPurgeable &= !willScale;
275 
276     SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
277     if (decoder == NULL) {
278         return nullObjectReturn("SkImageDecoder::Factory returned null");
279     }
280 
281     decoder->setSampleSize(sampleSize);
282     decoder->setDitherImage(doDither);
283     decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
284     decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
285 
286     SkBitmap* outputBitmap = NULL;
287     unsigned int existingBufferSize = 0;
288     if (javaBitmap != NULL) {
289         outputBitmap = (SkBitmap*) env->GetIntField(javaBitmap, gBitmap_nativeBitmapFieldID);
290         if (outputBitmap->isImmutable()) {
291             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
292             javaBitmap = NULL;
293             outputBitmap = NULL;
294         } else {
295             existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
296         }
297     }
298 
299     SkAutoTDelete<SkBitmap> adb(outputBitmap == NULL ? new SkBitmap : NULL);
300     if (outputBitmap == NULL) outputBitmap = adb.get();
301 
302     NinePatchPeeker peeker(decoder);
303     decoder->setPeeker(&peeker);
304 
305     SkImageDecoder::Mode decodeMode = isPurgeable ? SkImageDecoder::kDecodeBounds_Mode : mode;
306 
307     JavaPixelAllocator javaAllocator(env);
308     RecyclingPixelAllocator recyclingAllocator(outputBitmap->pixelRef(), existingBufferSize);
309     ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
310     SkBitmap::Allocator* outputAllocator = (javaBitmap != NULL) ?
311             (SkBitmap::Allocator*)&recyclingAllocator : (SkBitmap::Allocator*)&javaAllocator;
312     if (decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
313         if (!willScale) {
314             // If the java allocator is being used to allocate the pixel memory, the decoder
315             // need not write zeroes, since the memory is initialized to 0.
316             decoder->setSkipWritingZeroes(outputAllocator == &javaAllocator);
317             decoder->setAllocator(outputAllocator);
318         } else if (javaBitmap != NULL) {
319             // check for eventual scaled bounds at allocation time, so we don't decode the bitmap
320             // only to find the scaled result too large to fit in the allocation
321             decoder->setAllocator(&scaleCheckingAllocator);
322         }
323     }
324 
325     // Only setup the decoder to be deleted after its stack-based, refcounted
326     // components (allocators, peekers, etc) are declared. This prevents RefCnt
327     // asserts from firing due to the order objects are deleted from the stack.
328     SkAutoTDelete<SkImageDecoder> add(decoder);
329 
330     AutoDecoderCancel adc(options, decoder);
331 
332     // To fix the race condition in case "requestCancelDecode"
333     // happens earlier than AutoDecoderCancel object is added
334     // to the gAutoDecoderCancelMutex linked list.
335     if (options != NULL && env->GetBooleanField(options, gOptions_mCancelID)) {
336         return nullObjectReturn("gOptions_mCancelID");
337     }
338 
339     SkBitmap decodingBitmap;
340     if (!decoder->decode(stream, &decodingBitmap, prefConfig, decodeMode)) {
341         return nullObjectReturn("decoder->decode returned false");
342     }
343 
344     int scaledWidth = decodingBitmap.width();
345     int scaledHeight = decodingBitmap.height();
346 
347     if (willScale && mode != SkImageDecoder::kDecodeBounds_Mode) {
348         scaledWidth = int(scaledWidth * scale + 0.5f);
349         scaledHeight = int(scaledHeight * scale + 0.5f);
350     }
351 
352     // update options (if any)
353     if (options != NULL) {
354         env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
355         env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
356         env->SetObjectField(options, gOptions_mimeFieldID,
357                 getMimeTypeString(env, decoder->getFormat()));
358     }
359 
360     // if we're in justBounds mode, return now (skip the java bitmap)
361     if (mode == SkImageDecoder::kDecodeBounds_Mode) {
362         return NULL;
363     }
364 
365     jbyteArray ninePatchChunk = NULL;
366     if (peeker.fPatch != NULL) {
367         if (willScale) {
368             scaleNinePatchChunk(peeker.fPatch, scale);
369         }
370 
371         size_t ninePatchArraySize = peeker.fPatch->serializedSize();
372         ninePatchChunk = env->NewByteArray(ninePatchArraySize);
373         if (ninePatchChunk == NULL) {
374             return nullObjectReturn("ninePatchChunk == null");
375         }
376 
377         jbyte* array = (jbyte*) env->GetPrimitiveArrayCritical(ninePatchChunk, NULL);
378         if (array == NULL) {
379             return nullObjectReturn("primitive array == null");
380         }
381 
382         peeker.fPatch->serialize(array);
383         env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
384     }
385 
386     jintArray layoutBounds = NULL;
387     if (peeker.fLayoutBounds != NULL) {
388         layoutBounds = env->NewIntArray(4);
389         if (layoutBounds == NULL) {
390             return nullObjectReturn("layoutBounds == null");
391         }
392 
393         jint scaledBounds[4];
394         if (willScale) {
395             for (int i=0; i<4; i++) {
396                 scaledBounds[i] = (jint)((((jint*)peeker.fLayoutBounds)[i]*scale) + .5f);
397             }
398         } else {
399             memcpy(scaledBounds, (jint*)peeker.fLayoutBounds, sizeof(scaledBounds));
400         }
401         env->SetIntArrayRegion(layoutBounds, 0, 4, scaledBounds);
402         if (javaBitmap != NULL) {
403             env->SetObjectField(javaBitmap, gBitmap_layoutBoundsFieldID, layoutBounds);
404         }
405     }
406 
407     if (willScale) {
408         // This is weird so let me explain: we could use the scale parameter
409         // directly, but for historical reasons this is how the corresponding
410         // Dalvik code has always behaved. We simply recreate the behavior here.
411         // The result is slightly different from simply using scale because of
412         // the 0.5f rounding bias applied when computing the target image size
413         const float sx = scaledWidth / float(decodingBitmap.width());
414         const float sy = scaledHeight / float(decodingBitmap.height());
415 
416         // TODO: avoid copying when scaled size equals decodingBitmap size
417         SkBitmap::Config config = configForScaledOutput(decodingBitmap.config());
418         // FIXME: If the alphaType is kUnpremul and the image has alpha, the
419         // colors may not be correct, since Skia does not yet support drawing
420         // to/from unpremultiplied bitmaps.
421         outputBitmap->setConfig(config, scaledWidth, scaledHeight, 0,
422                                 decodingBitmap.alphaType());
423         if (!outputBitmap->allocPixels(outputAllocator, NULL)) {
424             return nullObjectReturn("allocation failed for scaled bitmap");
425         }
426 
427         // If outputBitmap's pixels are newly allocated by Java, there is no need
428         // to erase to 0, since the pixels were initialized to 0.
429         if (outputAllocator != &javaAllocator) {
430             outputBitmap->eraseColor(0);
431         }
432 
433         SkPaint paint;
434         paint.setFilterLevel(SkPaint::kLow_FilterLevel);
435 
436         SkCanvas canvas(*outputBitmap);
437         canvas.scale(sx, sy);
438         canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
439     } else {
440         outputBitmap->swap(decodingBitmap);
441     }
442 
443     if (padding) {
444         if (peeker.fPatch != NULL) {
445             GraphicsJNI::set_jrect(env, padding,
446                     peeker.fPatch->paddingLeft, peeker.fPatch->paddingTop,
447                     peeker.fPatch->paddingRight, peeker.fPatch->paddingBottom);
448         } else {
449             GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1);
450         }
451     }
452 
453     SkPixelRef* pr;
454     if (isPurgeable) {
455         pr = installPixelRef(outputBitmap, stream, sampleSize, doDither);
456     } else {
457         // if we get here, we're in kDecodePixels_Mode and will therefore
458         // already have a pixelref installed.
459         pr = outputBitmap->pixelRef();
460     }
461     if (pr == NULL) {
462         return nullObjectReturn("Got null SkPixelRef");
463     }
464 
465     if (!isMutable && javaBitmap == NULL) {
466         // promise we will never change our pixels (great for sharing and pictures)
467         pr->setImmutable();
468     }
469 
470     // detach bitmap from its autodeleter, since we want to own it now
471     adb.detach();
472 
473     if (javaBitmap != NULL) {
474         bool isPremultiplied = !requireUnpremultiplied;
475         GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap, isPremultiplied);
476         outputBitmap->notifyPixelsChanged();
477         // If a java bitmap was passed in for reuse, pass it back
478         return javaBitmap;
479     }
480 
481     int bitmapCreateFlags = 0x0;
482     if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
483     if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
484 
485     // now create the java bitmap
486     return GraphicsJNI::createBitmap(env, outputBitmap, javaAllocator.getStorageObj(),
487             bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
488 }
489 
490 // Need to buffer enough input to be able to rewind as much as might be read by a decoder
491 // trying to determine the stream's format. Currently the most is 64, read by
492 // SkImageDecoder_libwebp.
493 // FIXME: Get this number from SkImageDecoder
494 #define BYTES_TO_BUFFER 64
495 
nativeDecodeStream(JNIEnv * env,jobject clazz,jobject is,jbyteArray storage,jobject padding,jobject options)496 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
497         jobject padding, jobject options) {
498 
499     jobject bitmap = NULL;
500     SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
501 
502     if (stream.get()) {
503         SkAutoTUnref<SkStreamRewindable> bufferedStream(
504                 SkFrontBufferedStream::Create(stream, BYTES_TO_BUFFER));
505         SkASSERT(bufferedStream.get() != NULL);
506         // for now we don't allow purgeable with java inputstreams
507         bitmap = doDecode(env, bufferedStream, padding, options, false, false);
508     }
509     return bitmap;
510 }
511 
nativeDecodeFileDescriptor(JNIEnv * env,jobject clazz,jobject fileDescriptor,jobject padding,jobject bitmapFactoryOptions)512 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
513         jobject padding, jobject bitmapFactoryOptions) {
514 
515     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
516 
517     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
518 
519     struct stat fdStat;
520     if (fstat(descriptor, &fdStat) == -1) {
521         doThrowIOE(env, "broken file descriptor");
522         return nullObjectReturn("fstat return -1");
523     }
524 
525     // Restore the descriptor's offset on exiting this function.
526     AutoFDSeek autoRestore(descriptor);
527 
528     FILE* file = fdopen(descriptor, "r");
529     if (file == NULL) {
530         return nullObjectReturn("Could not open file");
531     }
532 
533     SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file,
534                          SkFILEStream::kCallerRetains_Ownership));
535 
536     SkAutoTUnref<SkStreamRewindable> stream;
537 
538     // Retain the old behavior of allowing purgeable if both purgeable and
539     // shareable are set to true.
540     bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions)
541                        && optionsShareable(env, bitmapFactoryOptions);
542     if (isPurgeable) {
543         // Copy the stream, so the image can be decoded multiple times without
544         // continuing to modify the original file descriptor.
545         // Copy beginning from the current position.
546         const size_t fileSize = fileStream->getLength() - fileStream->getPosition();
547         void* buffer = sk_malloc_flags(fileSize, 0);
548         if (buffer == NULL) {
549             return nullObjectReturn("Could not make a copy for ashmem");
550         }
551 
552         SkAutoTUnref<SkData> data(SkData::NewFromMalloc(buffer, fileSize));
553 
554         if (fileStream->read(buffer, fileSize) != fileSize) {
555             return nullObjectReturn("Could not read the file.");
556         }
557 
558         stream.reset(new SkMemoryStream(data));
559     } else {
560         // Use a buffered stream. Although an SkFILEStream can be rewound, this
561         // ensures that SkImageDecoder::Factory never rewinds beyond the
562         // current position of the file descriptor.
563         stream.reset(SkFrontBufferedStream::Create(fileStream, BYTES_TO_BUFFER));
564     }
565 
566     return doDecode(env, stream, padding, bitmapFactoryOptions, isPurgeable);
567 }
568 
nativeDecodeAsset(JNIEnv * env,jobject clazz,jint native_asset,jobject padding,jobject options)569 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jint native_asset,
570         jobject padding, jobject options) {
571 
572     SkStreamRewindable* stream;
573     Asset* asset = reinterpret_cast<Asset*>(native_asset);
574     bool forcePurgeable = optionsPurgeable(env, options);
575     if (forcePurgeable) {
576         // if we could "ref/reopen" the asset, we may not need to copy it here
577         // and we could assume optionsShareable, since assets are always RO
578         stream = CopyAssetToStream(asset);
579         if (stream == NULL) {
580             return NULL;
581         }
582     } else {
583         // since we know we'll be done with the asset when we return, we can
584         // just use a simple wrapper
585         stream = new AssetStreamAdaptor(asset,
586                                         AssetStreamAdaptor::kNo_OwnAsset,
587                                         AssetStreamAdaptor::kNo_HasMemoryBase);
588     }
589     SkAutoUnref aur(stream);
590     return doDecode(env, stream, padding, options, forcePurgeable, forcePurgeable);
591 }
592 
nativeDecodeByteArray(JNIEnv * env,jobject,jbyteArray byteArray,int offset,int length,jobject options)593 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
594         int offset, int length, jobject options) {
595 
596     /*  If optionsShareable() we could decide to just wrap the java array and
597         share it, but that means adding a globalref to the java array object
598         and managing its lifetime. For now we just always copy the array's data
599         if optionsPurgeable(), unless we're just decoding bounds.
600      */
601     bool purgeable = optionsPurgeable(env, options) && !optionsJustBounds(env, options);
602     AutoJavaByteArray ar(env, byteArray);
603     SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable);
604     SkAutoUnref aur(stream);
605     return doDecode(env, stream, NULL, options, purgeable);
606 }
607 
nativeRequestCancel(JNIEnv *,jobject joptions)608 static void nativeRequestCancel(JNIEnv*, jobject joptions) {
609     (void)AutoDecoderCancel::RequestCancel(joptions);
610 }
611 
nativeIsSeekable(JNIEnv * env,jobject,jobject fileDescriptor)612 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
613     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
614     return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
615 }
616 
617 ///////////////////////////////////////////////////////////////////////////////
618 
619 static JNINativeMethod gMethods[] = {
620     {   "nativeDecodeStream",
621         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
622         (void*)nativeDecodeStream
623     },
624 
625     {   "nativeDecodeFileDescriptor",
626         "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
627         (void*)nativeDecodeFileDescriptor
628     },
629 
630     {   "nativeDecodeAsset",
631         "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
632         (void*)nativeDecodeAsset
633     },
634 
635     {   "nativeDecodeByteArray",
636         "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
637         (void*)nativeDecodeByteArray
638     },
639 
640     {   "nativeIsSeekable",
641         "(Ljava/io/FileDescriptor;)Z",
642         (void*)nativeIsSeekable
643     },
644 };
645 
646 static JNINativeMethod gOptionsMethods[] = {
647     {   "requestCancel", "()V", (void*)nativeRequestCancel }
648 };
649 
getFieldIDCheck(JNIEnv * env,jclass clazz,const char fieldname[],const char type[])650 static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
651                                 const char fieldname[], const char type[]) {
652     jfieldID id = env->GetFieldID(clazz, fieldname, type);
653     SkASSERT(id);
654     return id;
655 }
656 
register_android_graphics_BitmapFactory(JNIEnv * env)657 int register_android_graphics_BitmapFactory(JNIEnv* env) {
658     jclass options_class = env->FindClass("android/graphics/BitmapFactory$Options");
659     SkASSERT(options_class);
660     gOptions_bitmapFieldID = getFieldIDCheck(env, options_class, "inBitmap",
661         "Landroid/graphics/Bitmap;");
662     gOptions_justBoundsFieldID = getFieldIDCheck(env, options_class, "inJustDecodeBounds", "Z");
663     gOptions_sampleSizeFieldID = getFieldIDCheck(env, options_class, "inSampleSize", "I");
664     gOptions_configFieldID = getFieldIDCheck(env, options_class, "inPreferredConfig",
665             "Landroid/graphics/Bitmap$Config;");
666     gOptions_premultipliedFieldID = getFieldIDCheck(env, options_class, "inPremultiplied", "Z");
667     gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z");
668     gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z");
669     gOptions_purgeableFieldID = getFieldIDCheck(env, options_class, "inPurgeable", "Z");
670     gOptions_shareableFieldID = getFieldIDCheck(env, options_class, "inInputShareable", "Z");
671     gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class,
672             "inPreferQualityOverSpeed", "Z");
673     gOptions_scaledFieldID = getFieldIDCheck(env, options_class, "inScaled", "Z");
674     gOptions_densityFieldID = getFieldIDCheck(env, options_class, "inDensity", "I");
675     gOptions_screenDensityFieldID = getFieldIDCheck(env, options_class, "inScreenDensity", "I");
676     gOptions_targetDensityFieldID = getFieldIDCheck(env, options_class, "inTargetDensity", "I");
677     gOptions_widthFieldID = getFieldIDCheck(env, options_class, "outWidth", "I");
678     gOptions_heightFieldID = getFieldIDCheck(env, options_class, "outHeight", "I");
679     gOptions_mimeFieldID = getFieldIDCheck(env, options_class, "outMimeType", "Ljava/lang/String;");
680     gOptions_mCancelID = getFieldIDCheck(env, options_class, "mCancel", "Z");
681 
682     jclass bitmap_class = env->FindClass("android/graphics/Bitmap");
683     SkASSERT(bitmap_class);
684     gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, bitmap_class, "mNativeBitmap", "I");
685     gBitmap_layoutBoundsFieldID = getFieldIDCheck(env, bitmap_class, "mLayoutBounds", "[I");
686     int ret = AndroidRuntime::registerNativeMethods(env,
687                                     "android/graphics/BitmapFactory$Options",
688                                     gOptionsMethods,
689                                     SK_ARRAY_COUNT(gOptionsMethods));
690     if (ret) {
691         return ret;
692     }
693     return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/BitmapFactory",
694                                          gMethods, SK_ARRAY_COUNT(gMethods));
695 }
696