BitmapFactory.cpp revision 2dcfbefbbeac406d16ec379c6430dd9ee9fd23a1
1#define LOG_TAG "BitmapFactory"
2
3#include "BitmapFactory.h"
4#include "SkImageDecoder.h"
5#include "SkImageRef_ashmem.h"
6#include "SkImageRef_GlobalPool.h"
7#include "SkPixelRef.h"
8#include "SkStream.h"
9#include "SkTemplates.h"
10#include "SkUtils.h"
11#include "CreateJavaOutputStreamAdaptor.h"
12#include "AutoDecodeCancel.h"
13
14#include <android_runtime/AndroidRuntime.h>
15#include <utils/Asset.h>
16#include <utils/ResourceTypes.h>
17#include <netinet/in.h>
18#include <sys/mman.h>
19#include <sys/stat.h>
20
21jclass gOptions_class;
22jfieldID gOptions_justBoundsFieldID;
23jfieldID gOptions_sampleSizeFieldID;
24jfieldID gOptions_configFieldID;
25jfieldID gOptions_ditherFieldID;
26jfieldID gOptions_purgeableFieldID;
27jfieldID gOptions_shareableFieldID;
28jfieldID gOptions_nativeAllocFieldID;
29jfieldID gOptions_widthFieldID;
30jfieldID gOptions_heightFieldID;
31jfieldID gOptions_mimeFieldID;
32jfieldID gOptions_mCancelID;
33
34static jclass gFileDescriptor_class;
35static jfieldID gFileDescriptor_descriptor;
36
37#if 0
38    #define TRACE_BITMAP(code)  code
39#else
40    #define TRACE_BITMAP(code)
41#endif
42
43using namespace android;
44
45class NinePatchPeeker : public SkImageDecoder::Peeker {
46    SkImageDecoder* fHost;
47public:
48    NinePatchPeeker(SkImageDecoder* host) {
49        // the host lives longer than we do, so a raw ptr is safe
50        fHost = host;
51        fPatchIsValid = false;
52    }
53
54    ~NinePatchPeeker() {
55        if (fPatchIsValid) {
56            free(fPatch);
57        }
58    }
59
60    bool    fPatchIsValid;
61    Res_png_9patch*  fPatch;
62
63    virtual bool peek(const char tag[], const void* data, size_t length) {
64        if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) {
65            Res_png_9patch* patch = (Res_png_9patch*) data;
66            size_t patchSize = patch->serializedSize();
67            assert(length == patchSize);
68            // You have to copy the data because it is owned by the png reader
69            Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
70            memcpy(patchNew, patch, patchSize);
71            // this relies on deserialization being done in place
72            Res_png_9patch::deserialize(patchNew);
73            patchNew->fileToDevice();
74            if (fPatchIsValid) {
75                free(fPatch);
76            }
77            fPatch = patchNew;
78            //printf("9patch: (%d,%d)-(%d,%d)\n",
79            //       fPatch.sizeLeft, fPatch.sizeTop,
80            //       fPatch.sizeRight, fPatch.sizeBottom);
81            fPatchIsValid = true;
82
83            // now update our host to force index or 32bit config
84            // 'cause we don't want 565 predithered, since as a 9patch, we know
85            // we will be stretched, and therefore we want to dither afterwards.
86            static const SkBitmap::Config gNo565Pref[] = {
87                SkBitmap::kIndex8_Config,
88                SkBitmap::kIndex8_Config,
89                SkBitmap::kARGB_8888_Config,
90                SkBitmap::kARGB_8888_Config,
91                SkBitmap::kARGB_8888_Config,
92                SkBitmap::kARGB_8888_Config,
93            };
94            fHost->setPrefConfigTable(gNo565Pref);
95        } else {
96            fPatch = NULL;
97        }
98        return true;    // keep on decoding
99    }
100};
101
102class AssetStreamAdaptor : public SkStream {
103public:
104    AssetStreamAdaptor(Asset* a) : fAsset(a) {}
105
106    virtual bool rewind() {
107        off_t pos = fAsset->seek(0, SEEK_SET);
108        if (pos == (off_t)-1) {
109            SkDebugf("----- fAsset->seek(rewind) failed\n");
110            return false;
111        }
112        return true;
113    }
114
115    virtual size_t read(void* buffer, size_t size) {
116        ssize_t amount;
117
118        if (NULL == buffer) {
119            if (0 == size) {  // caller is asking us for our total length
120                return fAsset->getLength();
121            }
122            // asset->seek returns new total offset
123            // we want to return amount that was skipped
124
125            off_t oldOffset = fAsset->seek(0, SEEK_CUR);
126            if (-1 == oldOffset) {
127                SkDebugf("---- fAsset->seek(oldOffset) failed\n");
128                return 0;
129            }
130            off_t newOffset = fAsset->seek(size, SEEK_CUR);
131            if (-1 == newOffset) {
132                SkDebugf("---- fAsset->seek(%d) failed\n", size);
133                return 0;
134            }
135            amount = newOffset - oldOffset;
136        } else {
137            amount = fAsset->read(buffer, size);
138            if (amount <= 0) {
139                SkDebugf("---- fAsset->read(%d) returned %d\n", size, amount);
140            }
141        }
142
143        if (amount < 0) {
144            amount = 0;
145        }
146        return amount;
147    }
148
149private:
150    Asset*  fAsset;
151};
152
153///////////////////////////////////////////////////////////////////////////////
154
155static inline int32_t validOrNeg1(bool isValid, int32_t value) {
156//    return isValid ? value : -1;
157    SkASSERT((int)isValid == 0 || (int)isValid == 1);
158    return ((int32_t)isValid - 1) | value;
159}
160
161jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
162    static const struct {
163        SkImageDecoder::Format fFormat;
164        const char*            fMimeType;
165    } gMimeTypes[] = {
166        { SkImageDecoder::kBMP_Format,  "image/bmp" },
167        { SkImageDecoder::kGIF_Format,  "image/gif" },
168        { SkImageDecoder::kICO_Format,  "image/x-ico" },
169        { SkImageDecoder::kJPEG_Format, "image/jpeg" },
170        { SkImageDecoder::kPNG_Format,  "image/png" },
171        { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
172    };
173
174    const char* cstr = NULL;
175    for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
176        if (gMimeTypes[i].fFormat == format) {
177            cstr = gMimeTypes[i].fMimeType;
178            break;
179        }
180    }
181
182    jstring jstr = 0;
183    if (NULL != cstr) {
184        jstr = env->NewStringUTF(cstr);
185    }
186    return jstr;
187}
188
189static bool optionsPurgeable(JNIEnv* env, jobject options) {
190    return options != NULL &&
191            env->GetBooleanField(options, gOptions_purgeableFieldID);
192}
193
194static bool optionsShareable(JNIEnv* env, jobject options) {
195    return options != NULL &&
196            env->GetBooleanField(options, gOptions_shareableFieldID);
197}
198
199static bool optionsReportSizeToVM(JNIEnv* env, jobject options) {
200    return NULL == options ||
201            !env->GetBooleanField(options, gOptions_nativeAllocFieldID);
202}
203
204static jobject nullObjectReturn(const char msg[]) {
205    if (msg) {
206        SkDebugf("--- %s\n", msg);
207    }
208    return NULL;
209}
210
211static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
212                                   int sampleSize, bool ditherImage) {
213    SkImageRef* pr;
214    // only use ashmem for large images, since mmaps come at a price
215    if (bitmap->getSize() >= 32 * 1024) {
216        pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize);
217    } else {
218        pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize);
219    }
220    pr->setDitherImage(ditherImage);
221    bitmap->setPixelRef(pr)->unref();
222    pr->isOpaque(bitmap);
223    return pr;
224}
225
226// since we "may" create a purgeable imageref, we require the stream be ref'able
227// i.e. dynamically allocated, since its lifetime may exceed the current stack
228// frame.
229static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
230                        jobject options, bool allowPurgeable,
231                        bool forcePurgeable = false) {
232    int sampleSize = 1;
233    SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
234    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
235    bool doDither = true;
236    bool isPurgeable = forcePurgeable ||
237                        (allowPurgeable && optionsPurgeable(env, options));
238    bool reportSizeToVM = optionsReportSizeToVM(env, options);
239
240    if (NULL != options) {
241        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
242        if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) {
243            mode = SkImageDecoder::kDecodeBounds_Mode;
244        }
245        // initialize these, in case we fail later on
246        env->SetIntField(options, gOptions_widthFieldID, -1);
247        env->SetIntField(options, gOptions_heightFieldID, -1);
248        env->SetObjectField(options, gOptions_mimeFieldID, 0);
249
250        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
251        prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
252        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
253    }
254
255    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
256    if (NULL == decoder) {
257        return nullObjectReturn("SkImageDecoder::Factory returned null");
258    }
259
260    decoder->setSampleSize(sampleSize);
261    decoder->setDitherImage(doDither);
262
263    NinePatchPeeker     peeker(decoder);
264    JavaPixelAllocator  javaAllocator(env, reportSizeToVM);
265    SkBitmap*           bitmap = new SkBitmap;
266    Res_png_9patch      dummy9Patch;
267
268    SkAutoTDelete<SkImageDecoder>   add(decoder);
269    SkAutoTDelete<SkBitmap>         adb(bitmap);
270
271    decoder->setPeeker(&peeker);
272    if (!isPurgeable) {
273        decoder->setAllocator(&javaAllocator);
274    }
275
276    AutoDecoderCancel   adc(options, decoder);
277
278    // To fix the race condition in case "requestCancelDecode"
279    // happens earlier than AutoDecoderCancel object is added
280    // to the gAutoDecoderCancelMutex linked list.
281    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
282        return nullObjectReturn("gOptions_mCancelID");;
283    }
284
285    SkImageDecoder::Mode decodeMode = mode;
286    if (isPurgeable) {
287        decodeMode = SkImageDecoder::kDecodeBounds_Mode;
288    }
289    if (!decoder->decode(stream, bitmap, prefConfig, decodeMode)) {
290        return nullObjectReturn("decoder->decode returned false");
291    }
292
293    // update options (if any)
294    if (NULL != options) {
295        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
296        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
297        // TODO: set the mimeType field with the data from the codec.
298        // but how to reuse a set of strings, rather than allocating new one
299        // each time?
300        env->SetObjectField(options, gOptions_mimeFieldID,
301                            getMimeTypeString(env, decoder->getFormat()));
302    }
303
304    // if we're in justBounds mode, return now (skip the java bitmap)
305    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
306        return NULL;
307    }
308
309    jbyteArray ninePatchChunk = NULL;
310    if (peeker.fPatchIsValid) {
311        size_t ninePatchArraySize = peeker.fPatch->serializedSize();
312        ninePatchChunk = env->NewByteArray(ninePatchArraySize);
313        if (NULL == ninePatchChunk) {
314            return nullObjectReturn("ninePatchChunk == null");
315        }
316        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk,
317                                                              NULL);
318        if (NULL == array) {
319            return nullObjectReturn("primitive array == null");
320        }
321        peeker.fPatch->serialize(array);
322        env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
323    }
324
325    // detach bitmap from its autotdeleter, since we want to own it now
326    adb.detach();
327
328    if (padding) {
329        if (peeker.fPatchIsValid) {
330            GraphicsJNI::set_jrect(env, padding,
331                                   peeker.fPatch->paddingLeft,
332                                   peeker.fPatch->paddingTop,
333                                   peeker.fPatch->paddingRight,
334                                   peeker.fPatch->paddingBottom);
335        } else {
336            GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1);
337        }
338    }
339
340    SkPixelRef* pr;
341    if (isPurgeable) {
342        pr = installPixelRef(bitmap, stream, sampleSize, doDither);
343    } else {
344        // if we get here, we're in kDecodePixels_Mode and will therefore
345        // already have a pixelref installed.
346        pr = bitmap->pixelRef();
347    }
348    // promise we will never change our pixels (great for sharing and pictures)
349    pr->setImmutable();
350    // now create the java bitmap
351    return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk);
352}
353
354static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
355                                  jobject is,       // InputStream
356                                  jbyteArray storage,   // byte[]
357                                  jobject padding,
358                                  jobject options) {  // BitmapFactory$Options
359    jobject bitmap = NULL;
360    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0);
361
362    if (stream) {
363        // for now we don't allow purgeable with java inputstreams
364        bitmap = doDecode(env, stream, padding, options, false);
365        stream->unref();
366    }
367    return bitmap;
368}
369
370static ssize_t getFDSize(int fd) {
371    off_t curr = ::lseek(fd, 0, SEEK_CUR);
372    if (curr < 0) {
373        return 0;
374    }
375    size_t size = ::lseek(fd, 0, SEEK_END);
376    ::lseek(fd, curr, SEEK_SET);
377    return size;
378}
379
380/** Restore the file descriptor's offset in our destructor
381 */
382class AutoFDSeek {
383public:
384    AutoFDSeek(int fd) : fFD(fd) {
385        fCurr = ::lseek(fd, 0, SEEK_CUR);
386    }
387    ~AutoFDSeek() {
388        if (fCurr >= 0) {
389            ::lseek(fFD, fCurr, SEEK_SET);
390        }
391    }
392private:
393    int     fFD;
394    off_t   fCurr;
395};
396
397static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
398                                          jobject fileDescriptor,
399                                          jobject padding,
400                                          jobject bitmapFactoryOptions) {
401    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
402
403    jint descriptor = env->GetIntField(fileDescriptor,
404                                       gFileDescriptor_descriptor);
405
406    bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
407    bool isShareable = optionsShareable(env, bitmapFactoryOptions);
408    bool weOwnTheFD = false;
409    if (isPurgeable && isShareable) {
410        int newFD = ::dup(descriptor);
411        if (-1 != newFD) {
412            weOwnTheFD = true;
413            descriptor = newFD;
414        }
415    }
416
417    SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
418    SkAutoUnref aur(stream);
419    if (!stream->isValid()) {
420        return NULL;
421    }
422
423    /* Restore our offset when we leave, so we can be called more than once
424       with the same descriptor. This is only required if we didn't dup the
425       file descriptor, but it is OK to do it all the time.
426    */
427    AutoFDSeek as(descriptor);
428
429    /* Allow purgeable iff we own the FD, i.e., in the puregeable and
430       shareable case.
431    */
432    return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD);
433}
434
435/*  make a deep copy of the asset, and return it as a stream, or NULL if there
436    was an error.
437 */
438static SkStream* copyAssetToStream(Asset* asset) {
439    // if we could "ref/reopen" the asset, we may not need to copy it here
440    off_t size = asset->seek(0, SEEK_SET);
441    if ((off_t)-1 == size) {
442        SkDebugf("---- copyAsset: asset rewind failed\n");
443        return NULL;
444    }
445
446    size = asset->getLength();
447    if (size <= 0) {
448        SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size);
449        return NULL;
450    }
451
452    SkStream* stream = new SkMemoryStream(size);
453    void* data = const_cast<void*>(stream->getMemoryBase());
454    off_t len = asset->read(data, size);
455    if (len != size) {
456        SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len);
457        delete stream;
458        stream = NULL;
459    }
460    return stream;
461}
462
463static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz,
464                                 jint native_asset,    // Asset
465                                 jobject padding,       // Rect
466                                 jobject options) { // BitmapFactory$Options
467    SkStream* stream;
468    Asset* asset = reinterpret_cast<Asset*>(native_asset);
469    bool forcePurgeable = optionsPurgeable(env, options);
470    if (forcePurgeable) {
471        // if we could "ref/reopen" the asset, we may not need to copy it here
472        // and we could assume optionsShareable, since assets are always RO
473        stream = copyAssetToStream(asset);
474        if (NULL == stream) {
475            return NULL;
476        }
477    } else {
478        // since we know we'll be done with the asset when we return, we can
479        // just use a simple wrapper
480        stream = new AssetStreamAdaptor(asset);
481    }
482    SkAutoUnref aur(stream);
483    return doDecode(env, stream, padding, options, true, forcePurgeable);
484}
485
486static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
487                                     int offset, int length, jobject options) {
488    /*  If optionsShareable() we could decide to just wrap the java array and
489        share it, but that means adding a globalref to the java array object
490        and managing its lifetime. For now we just always copy the array's data
491        if optionsPurgeable().
492     */
493    AutoJavaByteArray ar(env, byteArray);
494    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length,
495                                          optionsPurgeable(env, options));
496    SkAutoUnref aur(stream);
497    return doDecode(env, stream, NULL, options, true);
498}
499
500static void nativeRequestCancel(JNIEnv*, jobject joptions) {
501    (void)AutoDecoderCancel::RequestCancel(joptions);
502}
503
504static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale,
505        jobject padding) {
506
507    jbyte* array = env->GetByteArrayElements(chunkObject, 0);
508    if (array != NULL) {
509        size_t chunkSize = env->GetArrayLength(chunkObject);
510        void* storage = alloca(chunkSize);
511        android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage);
512        memcpy(chunk, array, chunkSize);
513        android::Res_png_9patch::deserialize(chunk);
514
515        chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
516        chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
517        chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
518        chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
519
520        for (int i = 0; i < chunk->numXDivs; i++) {
521            chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f);
522            if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) {
523                chunk->xDivs[i]++;
524            }
525        }
526
527        for (int i = 0; i < chunk->numYDivs; i++) {
528            chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
529            if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
530                chunk->yDivs[i]++;
531            }
532        }
533
534        memcpy(array, chunk, chunkSize);
535
536        if (padding) {
537            GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop,
538                    chunk->paddingRight, chunk->paddingBottom);
539        }
540
541        env->ReleaseByteArrayElements(chunkObject, array, 0);
542    }
543    return chunkObject;
544}
545
546static void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) {
547    SkBitmap::Config config = static_cast<SkBitmap::Config>(nativeConfig);
548
549    // these are the only default configs that make sense for codecs right now
550    static const SkBitmap::Config gValidDefConfig[] = {
551        SkBitmap::kRGB_565_Config,
552        SkBitmap::kARGB_8888_Config,
553    };
554
555    for (size_t i = 0; i < SK_ARRAY_COUNT(gValidDefConfig); i++) {
556        if (config == gValidDefConfig[i]) {
557            SkImageDecoder::SetDeviceConfig(config);
558            break;
559        }
560    }
561}
562
563static SkMemoryStream* buildSkMemoryStream(SkStream *stream) {
564    size_t bufferSize = 4096;
565    size_t streamLen = 0;
566    size_t len;
567    char* data = (char*)sk_malloc_throw(bufferSize);
568
569    while ((len = stream->read(data + streamLen,
570                    bufferSize - streamLen)) != 0) {
571        streamLen += len;
572        if (streamLen == bufferSize) {
573            bufferSize *= 2;
574            data = (char*)sk_realloc_throw(data, bufferSize);
575        }
576    }
577    data = (char*)sk_realloc_throw(data, streamLen);
578    SkMemoryStream* streamMem = new SkMemoryStream();
579    streamMem->setMemoryOwned(data, streamLen);
580    return streamMem;
581}
582
583static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
584    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
585    int width, height;
586    if (NULL == decoder) {
587        doThrowIOE(env, "Image format not supported");
588        return nullObjectReturn("SkImageDecoder::Factory returned null");
589    }
590
591    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
592    decoder->setAllocator(javaAllocator);
593    JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
594    decoder->setReporter(javaMemoryReporter);
595    javaAllocator->unref();
596    javaMemoryReporter->unref();
597
598    if (!decoder->buildTileIndex(stream, &width, &height)) {
599        char msg[100];
600        snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
601                decoder->getFormatName());
602        doThrowIOE(env, msg);
603        return nullObjectReturn("decoder->buildTileIndex returned false");
604    }
605
606    SkLargeBitmap *bm = new SkLargeBitmap(decoder, width, height);
607
608    return GraphicsJNI::createLargeBitmap(env, bm);
609}
610
611static jobject nativeCreateLargeBitmapFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
612                                     int offset, int length, jboolean isShareable) {
613    /*  If isShareable we could decide to just wrap the java array and
614        share it, but that means adding a globalref to the java array object
615        For now we just always copy the array's data if isShareable.
616     */
617    AutoJavaByteArray ar(env, byteArray);
618    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
619    return doBuildTileIndex(env, stream);
620}
621
622static jobject nativeCreateLargeBitmapFromFileDescriptor(JNIEnv* env, jobject clazz,
623                                          jobject fileDescriptor, jboolean isShareable) {
624    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
625
626    jint descriptor = env->GetIntField(fileDescriptor,
627                                       gFileDescriptor_descriptor);
628    SkStream *stream = NULL;
629    struct stat fdStat;
630    int newFD;
631    if (fstat(descriptor, &fdStat) == -1) {
632        doThrowIOE(env, "broken file descriptor");
633        return nullObjectReturn("fstat return -1");
634    }
635
636    if (isShareable &&
637            S_ISREG(fdStat.st_mode) &&
638            (newFD = ::dup(descriptor)) != -1) {
639        SkFDStream* fdStream = new SkFDStream(newFD, true);
640        if (!fdStream->isValid()) {
641            fdStream->unref();
642            return NULL;
643        }
644        stream = fdStream;
645    } else {
646        SkFDStream* fdStream = new SkFDStream(descriptor, false);
647        if (!fdStream->isValid()) {
648            fdStream->unref();
649            return NULL;
650        }
651        stream = buildSkMemoryStream(fdStream);
652        fdStream->unref();
653    }
654
655    /* Restore our offset when we leave, so we can be called more than once
656       with the same descriptor. This is only required if we didn't dup the
657       file descriptor, but it is OK to do it all the time.
658    */
659    AutoFDSeek as(descriptor);
660
661    return doBuildTileIndex(env, stream);
662}
663
664static jobject nativeCreateLargeBitmapFromStream(JNIEnv* env, jobject clazz,
665                                  jobject is,       // InputStream
666                                  jbyteArray storage, // byte[]
667                                  jboolean isShareable) {
668    jobject largeBitmap = NULL;
669    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
670
671    if (stream) {
672        // for now we don't allow shareable with java inputstreams
673        SkMemoryStream *mStream = buildSkMemoryStream(stream);
674        largeBitmap = doBuildTileIndex(env, mStream);
675        stream->unref();
676    }
677    return largeBitmap;
678}
679
680static jobject nativeCreateLargeBitmapFromAsset(JNIEnv* env, jobject clazz,
681                                 jint native_asset, // Asset
682                                 jboolean isShareable) {
683    SkStream* stream, *assStream;
684    Asset* asset = reinterpret_cast<Asset*>(native_asset);
685    assStream = new AssetStreamAdaptor(asset);
686    stream = buildSkMemoryStream(assStream);
687    assStream->unref();
688    return doBuildTileIndex(env, stream);
689}
690
691///////////////////////////////////////////////////////////////////////////////
692
693static JNINativeMethod gMethods[] = {
694    {   "nativeDecodeStream",
695        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
696        (void*)nativeDecodeStream
697    },
698
699    {   "nativeDecodeFileDescriptor",
700        "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
701        (void*)nativeDecodeFileDescriptor
702    },
703
704    {   "nativeDecodeAsset",
705        "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
706        (void*)nativeDecodeAsset
707    },
708
709    {   "nativeDecodeByteArray",
710        "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
711        (void*)nativeDecodeByteArray
712    },
713
714    {   "nativeScaleNinePatch",
715        "([BFLandroid/graphics/Rect;)[B",
716        (void*)nativeScaleNinePatch
717    },
718
719    {   "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
720
721    {   "nativeCreateLargeBitmap",
722        "([BIIZ)Landroid/graphics/LargeBitmap;",
723        (void*)nativeCreateLargeBitmapFromByteArray
724    },
725
726    {   "nativeCreateLargeBitmap",
727        "(Ljava/io/InputStream;[BZ)Landroid/graphics/LargeBitmap;",
728        (void*)nativeCreateLargeBitmapFromStream
729    },
730
731    {   "nativeCreateLargeBitmap",
732        "(Ljava/io/FileDescriptor;Z)Landroid/graphics/LargeBitmap;",
733        (void*)nativeCreateLargeBitmapFromFileDescriptor
734    },
735
736    {   "nativeCreateLargeBitmap",
737        "(IZ)Landroid/graphics/LargeBitmap;",
738        (void*)nativeCreateLargeBitmapFromAsset
739    },
740};
741
742static JNINativeMethod gOptionsMethods[] = {
743    {   "requestCancel", "()V", (void*)nativeRequestCancel }
744};
745
746static jclass make_globalref(JNIEnv* env, const char classname[]) {
747    jclass c = env->FindClass(classname);
748    SkASSERT(c);
749    return (jclass)env->NewGlobalRef(c);
750}
751
752static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
753                                const char fieldname[], const char type[]) {
754    jfieldID id = env->GetFieldID(clazz, fieldname, type);
755    SkASSERT(id);
756    return id;
757}
758
759#define kClassPathName  "android/graphics/BitmapFactory"
760
761#define RETURN_ERR_IF_NULL(value) \
762    do { if (!(value)) { assert(0); return -1; } } while (false)
763
764int register_android_graphics_BitmapFactory(JNIEnv* env);
765int register_android_graphics_BitmapFactory(JNIEnv* env) {
766    gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options");
767    gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z");
768    gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
769    gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
770            "Landroid/graphics/Bitmap$Config;");
771    gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
772    gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
773    gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
774    gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z");
775    gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
776    gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
777    gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
778    gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z");
779
780    gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
781    gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
782
783    int ret = AndroidRuntime::registerNativeMethods(env,
784                                    "android/graphics/BitmapFactory$Options",
785                                    gOptionsMethods,
786                                    SK_ARRAY_COUNT(gOptionsMethods));
787    if (ret) {
788        return ret;
789    }
790    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
791                                         gMethods, SK_ARRAY_COUNT(gMethods));
792}
793