BitmapFactory.cpp revision 2a3d754549abc4b55e6cfc2d0c986d29782b2492
1525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#define LOG_TAG "BitmapFactory"
2525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
3525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "BitmapFactory.h"
4525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkImageDecoder.h"
5525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkImageRef_ashmem.h"
6525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkImageRef_GlobalPool.h"
7525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkPixelRef.h"
8525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkStream.h"
9525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkTemplates.h"
10525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "SkUtils.h"
11525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "CreateJavaOutputStreamAdaptor.h"
12525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "AutoDecodeCancel.h"
13525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include "Utils.h"
14525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
15525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <android_runtime/AndroidRuntime.h>
16525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <utils/Asset.h>
17525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <utils/ResourceTypes.h>
18525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <netinet/in.h>
19525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#include <sys/mman.h>
2013f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov#include <sys/stat.h>
21525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
2213f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganovjclass gOptions_class;
2313f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_justBoundsFieldID;
24525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_sampleSizeFieldID;
25525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_configFieldID;
26525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_ditherFieldID;
2799a82437ed8e0537d9a355a124d2bb30aea46ad8Svet GanovjfieldID gOptions_purgeableFieldID;
28525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_shareableFieldID;
2913f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_nativeAllocFieldID;
30525a66b2bb5abf844aff2109bdc9ed819566beceSvet GanovjfieldID gOptions_widthFieldID;
3113f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_heightFieldID;
3213f542cabd635c55ade5442764cc4a3d2f7880eaSvet GanovjfieldID gOptions_mimeFieldID;
336f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslavjfieldID gOptions_mCancelID;
346f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav
35525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jclass gFileDescriptor_class;
36525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jfieldID gFileDescriptor_descriptor;
37525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
38525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#if 0
3913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    #define TRACE_BITMAP(code)  code
4013f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov#else
4162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    #define TRACE_BITMAP(code)
42df6444931b030d3cdd9769e23f16f0a16fe9c654Svet Ganov#endif
43525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
4413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganovusing namespace android;
45525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
46525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovclass NinePatchPeeker : public SkImageDecoder::Peeker {
47525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkImageDecoder* fHost;
48525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovpublic:
49525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    NinePatchPeeker(SkImageDecoder* host) {
50525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // the host lives longer than we do, so a raw ptr is safe
51525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        fHost = host;
52525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        fPatchIsValid = false;
53525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
5415cbc8a03250eafdf947cd8ad4e77f34444d5ba4Svetoslav
55525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    ~NinePatchPeeker() {
56525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (fPatchIsValid) {
57525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            free(fPatch);
58525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
59525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
60525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
61525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool    fPatchIsValid;
62525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    Res_png_9patch*  fPatch;
63525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
64525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    virtual bool peek(const char tag[], const void* data, size_t length) {
65525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (strcmp("npTc", tag) == 0 && length >= sizeof(Res_png_9patch)) {
66525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            Res_png_9patch* patch = (Res_png_9patch*) data;
67525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            size_t patchSize = patch->serializedSize();
68525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            assert(length == patchSize);
69525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            // You have to copy the data because it is owned by the png reader
70525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            Res_png_9patch* patchNew = (Res_png_9patch*) malloc(patchSize);
71525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            memcpy(patchNew, patch, patchSize);
72525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            // this relies on deserialization being done in place
73525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            Res_png_9patch::deserialize(patchNew);
74525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            patchNew->fileToDevice();
75525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            if (fPatchIsValid) {
76525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                free(fPatch);
77525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            }
78066bf81b983ce23b91d19b85b7c37a61fba7a9a6Philip P. Moltmann            fPatch = patchNew;
79525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            //printf("9patch: (%d,%d)-(%d,%d)\n",
80525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            //       fPatch.sizeLeft, fPatch.sizeTop,
81fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov            //       fPatch.sizeRight, fPatch.sizeBottom);
82fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov            fPatchIsValid = true;
83525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
84525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            // now update our host to force index or 32bit config
85525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            // 'cause we don't want 565 predithered, since as a 9patch, we know
86525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            // we will be stretched, and therefore we want to dither afterwards.
87525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            static const SkBitmap::Config gNo565Pref[] = {
88525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                SkBitmap::kIndex8_Config,
89525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                SkBitmap::kIndex8_Config,
90fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov                SkBitmap::kARGB_8888_Config,
91525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                SkBitmap::kARGB_8888_Config,
92525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                SkBitmap::kARGB_8888_Config,
93525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                SkBitmap::kARGB_8888_Config,
94525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            };
95525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            fHost->setPrefConfigTable(gNo565Pref);
96525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        } else {
97525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            fPatch = NULL;
98525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
99525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return true;    // keep on decoding
100525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
101525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov};
102525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
103525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov///////////////////////////////////////////////////////////////////////////////
104525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
105525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic inline int32_t validOrNeg1(bool isValid, int32_t value) {
106525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov//    return isValid ? value : -1;
107525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkASSERT((int)isValid == 0 || (int)isValid == 1);
108525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return ((int32_t)isValid - 1) | value;
109c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov}
110c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov
111c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganovjstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
112c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov    static const struct {
113c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        SkImageDecoder::Format fFormat;
114c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        const char*            fMimeType;
115c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov    } gMimeTypes[] = {
116c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        { SkImageDecoder::kBMP_Format,  "image/bmp" },
117c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        { SkImageDecoder::kGIF_Format,  "image/gif" },
118c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        { SkImageDecoder::kICO_Format,  "image/x-ico" },
11938fdd4f486fea2a816ca43f365e68118fe747c61Philip P. Moltmann        { SkImageDecoder::kJPEG_Format, "image/jpeg" },
120c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        { SkImageDecoder::kPNG_Format,  "image/png" },
121525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
122525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    };
123525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
124525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    const char* cstr = NULL;
1254237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
126c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        if (gMimeTypes[i].fFormat == format) {
127c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov            cstr = gMimeTypes[i].fMimeType;
128c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov            break;
129c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        }
130525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
131525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
132525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jstring jstr = 0;
133525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (NULL != cstr) {
134525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        jstr = env->NewStringUTF(cstr);
135525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
136525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return jstr;
137525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
138254361f136aa9461e16f11f0170fde05e83a1b92Svetoslav
139525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsPurgeable(JNIEnv* env, jobject options) {
140525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return options != NULL &&
141525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            env->GetBooleanField(options, gOptions_purgeableFieldID);
142525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
143525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
144525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsShareable(JNIEnv* env, jobject options) {
145525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return options != NULL &&
146525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            env->GetBooleanField(options, gOptions_shareableFieldID);
147525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
148525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
149525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsJustBounds(JNIEnv* env, jobject options) {
150525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return options != NULL &&
151525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            env->GetBooleanField(options, gOptions_justBoundsFieldID);
152525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
153525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
154525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic bool optionsReportSizeToVM(JNIEnv* env, jobject options) {
155525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return NULL == options ||
156525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            !env->GetBooleanField(options, gOptions_nativeAllocFieldID);
157525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
1580d2d9637ed4f46062d508cfa7da0e9776fc444f8Svetoslav
159525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
160525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStream* stream,
161525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                   int sampleSize, bool ditherImage) {
162525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkImageRef* pr;
163525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // only use ashmem for large images, since mmaps come at a price
164525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (bitmap->getSize() >= 32 * 1024) {
165525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize);
166525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    } else {
167525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize);
168525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
169525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    pr->setDitherImage(ditherImage);
170525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bitmap->setPixelRef(pr)->unref();
171525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    pr->isOpaque(bitmap);
172525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return pr;
173525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
174525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
175525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov// since we "may" create a purgeable imageref, we require the stream be ref'able
176c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov// i.e. dynamically allocated, since its lifetime may exceed the current stack
177525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov// frame.
178525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
179525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                        jobject options, bool allowPurgeable,
180525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                        bool forcePurgeable = false) {
181525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    int sampleSize = 1;
182525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
183525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
184525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool doDither = true;
185525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool isPurgeable = forcePurgeable ||
186525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                        (allowPurgeable && optionsPurgeable(env, options));
187525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool reportSizeToVM = optionsReportSizeToVM(env, options);
188525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
189525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (NULL != options) {
190525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
191525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (optionsJustBounds(env, options)) {
192525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            mode = SkImageDecoder::kDecodeBounds_Mode;
193525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
194525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // initialize these, in case we fail later on
195525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->SetIntField(options, gOptions_widthFieldID, -1);
196525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->SetIntField(options, gOptions_heightFieldID, -1);
197525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->SetObjectField(options, gOptions_mimeFieldID, 0);
198525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
199525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
200525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
201525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
202525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
203525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
204525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
205525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (NULL == decoder) {
206525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return nullObjectReturn("SkImageDecoder::Factory returned null");
207525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
208525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
209525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    decoder->setSampleSize(sampleSize);
210525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    decoder->setDitherImage(doDither);
211525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
212525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    NinePatchPeeker     peeker(decoder);
213525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    JavaPixelAllocator  javaAllocator(env, reportSizeToVM);
214525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkBitmap*           bitmap = new SkBitmap;
215525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    Res_png_9patch      dummy9Patch;
216525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
217525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkAutoTDelete<SkImageDecoder>   add(decoder);
218525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkAutoTDelete<SkBitmap>         adb(bitmap);
219525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
220525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    decoder->setPeeker(&peeker);
221525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (!isPurgeable) {
222525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        decoder->setAllocator(&javaAllocator);
223525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
224525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
225525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    AutoDecoderCancel   adc(options, decoder);
226525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
227525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // To fix the race condition in case "requestCancelDecode"
228525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // happens earlier than AutoDecoderCancel object is added
229525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // to the gAutoDecoderCancelMutex linked list.
230525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
231525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return nullObjectReturn("gOptions_mCancelID");;
232525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
233525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
234525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkImageDecoder::Mode decodeMode = mode;
235525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (isPurgeable) {
236525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        decodeMode = SkImageDecoder::kDecodeBounds_Mode;
237525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
238525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (!decoder->decode(stream, bitmap, prefConfig, decodeMode)) {
239525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return nullObjectReturn("decoder->decode returned false");
240525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
241525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
242525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // update options (if any)
243525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (NULL != options) {
244525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
245525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
246525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // TODO: set the mimeType field with the data from the codec.
247525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // but how to reuse a set of strings, rather than allocating new one
248525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // each time?
249525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->SetObjectField(options, gOptions_mimeFieldID,
250525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                            getMimeTypeString(env, decoder->getFormat()));
251525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
252525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
253525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // if we're in justBounds mode, return now (skip the java bitmap)
254525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
255525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return NULL;
256525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
257525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
258525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jbyteArray ninePatchChunk = NULL;
259525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (peeker.fPatchIsValid) {
260525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        size_t ninePatchArraySize = peeker.fPatch->serializedSize();
261525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        ninePatchChunk = env->NewByteArray(ninePatchArraySize);
262525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (NULL == ninePatchChunk) {
263525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            return nullObjectReturn("ninePatchChunk == null");
264525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
265525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ninePatchChunk,
266525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                                              NULL);
267525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (NULL == array) {
268525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            return nullObjectReturn("primitive array == null");
269525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
270525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        peeker.fPatch->serialize(array);
271525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        env->ReleasePrimitiveArrayCritical(ninePatchChunk, array, 0);
272525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
273525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
274525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // detach bitmap from its autotdeleter, since we want to own it now
275525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    adb.detach();
276525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
277525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (padding) {
278525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (peeker.fPatchIsValid) {
279525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            GraphicsJNI::set_jrect(env, padding,
280525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                   peeker.fPatch->paddingLeft,
281525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                   peeker.fPatch->paddingTop,
282525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                   peeker.fPatch->paddingRight,
283525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                   peeker.fPatch->paddingBottom);
284525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        } else {
285525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            GraphicsJNI::set_jrect(env, padding, -1, -1, -1, -1);
286525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
287525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
288525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
289525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkPixelRef* pr;
290525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (isPurgeable) {
291525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        pr = installPixelRef(bitmap, stream, sampleSize, doDither);
292525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    } else {
293525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // if we get here, we're in kDecodePixels_Mode and will therefore
294525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // already have a pixelref installed.
295525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        pr = bitmap->pixelRef();
296525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
297525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // promise we will never change our pixels (great for sharing and pictures)
298525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    pr->setImmutable();
299525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // now create the java bitmap
300525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return GraphicsJNI::createBitmap(env, bitmap, false, ninePatchChunk);
301525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
302525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
303525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
304525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                  jobject is,       // InputStream
305525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                  jbyteArray storage,   // byte[]
306525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                  jobject padding,
307525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                  jobject options) {  // BitmapFactory$Options
308525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jobject bitmap = NULL;
309525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 0);
310525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
311525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (stream) {
312525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // for now we don't allow purgeable with java inputstreams
313525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        bitmap = doDecode(env, stream, padding, options, false);
314525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        stream->unref();
315525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
316525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return bitmap;
317525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
318525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
319525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic ssize_t getFDSize(int fd) {
320525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    off_t curr = ::lseek(fd, 0, SEEK_CUR);
321525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (curr < 0) {
322525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return 0;
323525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
324525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    size_t size = ::lseek(fd, 0, SEEK_END);
325525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    ::lseek(fd, curr, SEEK_SET);
326525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return size;
327525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
328525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
329525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
330525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                          jobject fileDescriptor,
331e6ecba59fd618b80dd13f581b625eea420672a0aSvetoslav                                          jobject padding,
332525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                          jobject bitmapFactoryOptions) {
333525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
334525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
335525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jint descriptor = env->GetIntField(fileDescriptor,
336525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                       gFileDescriptor_descriptor);
337525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
338525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
339525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool isShareable = optionsShareable(env, bitmapFactoryOptions);
3406f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav    bool weOwnTheFD = false;
341525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (isPurgeable && isShareable) {
342525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        int newFD = ::dup(descriptor);
3436f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav        if (-1 != newFD) {
344525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            weOwnTheFD = true;
345525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            descriptor = newFD;
3466f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav        }
3476f249835a4ff9e7e7e3ca0190b7ecf72e689656dSvetoslav    }
348525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
349525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkFDStream* stream = new SkFDStream(descriptor, weOwnTheFD);
350525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkAutoUnref aur(stream);
351525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (!stream->isValid()) {
352525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return NULL;
353525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
354525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
355525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    /* Restore our offset when we leave, so we can be called more than once
356525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov       with the same descriptor. This is only required if we didn't dup the
357525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov       file descriptor, but it is OK to do it all the time.
358525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    */
359525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    AutoFDSeek as(descriptor);
360525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
361525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    /* Allow purgeable iff we own the FD, i.e., in the puregeable and
362525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov       shareable case.
363525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    */
364525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return doDecode(env, stream, padding, bitmapFactoryOptions, weOwnTheFD);
365525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
366525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
367525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov/*  make a deep copy of the asset, and return it as a stream, or NULL if there
36813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    was an error.
36913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov */
370525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic SkStream* copyAssetToStream(Asset* asset) {
371525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    // if we could "ref/reopen" the asset, we may not need to copy it here
37213f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    off_t size = asset->seek(0, SEEK_SET);
373525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if ((off_t)-1 == size) {
374525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        SkDebugf("---- copyAsset: asset rewind failed\n");
375525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return NULL;
376525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
377525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
378525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    size = asset->getLength();
379525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (size <= 0) {
380525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        SkDebugf("---- copyAsset: asset->getLength() returned %d\n", size);
381525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return NULL;
382525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
383525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
384525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkStream* stream = new SkMemoryStream(size);
385525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    void* data = const_cast<void*>(stream->getMemoryBase());
386525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    off_t len = asset->read(data, size);
387525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (len != size) {
38813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        SkDebugf("---- copyAsset: asset->read(%d) returned %d\n", size, len);
389525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        delete stream;
390525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        stream = NULL;
391525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
392525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return stream;
393525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
394525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
395525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jobject nativeDecodeAsset(JNIEnv* env, jobject clazz,
396525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                 jint native_asset,    // Asset
397525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                 jobject padding,       // Rect
398525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                 jobject options) { // BitmapFactory$Options
399525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkStream* stream;
400525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    Asset* asset = reinterpret_cast<Asset*>(native_asset);
401525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool forcePurgeable = optionsPurgeable(env, options);
402525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (forcePurgeable) {
403525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // if we could "ref/reopen" the asset, we may not need to copy it here
404525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // and we could assume optionsShareable, since assets are always RO
405525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        stream = copyAssetToStream(asset);
406525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (NULL == stream) {
407525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            return NULL;
408525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
409525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    } else {
410525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // since we know we'll be done with the asset when we return, we can
411525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        // just use a simple wrapper
412525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        stream = new AssetStreamAdaptor(asset);
413525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
414525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkAutoUnref aur(stream);
415525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return doDecode(env, stream, padding, options, true, forcePurgeable);
41613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov}
41713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov
41813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganovstatic jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
419525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                     int offset, int length, jobject options) {
420525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    /*  If optionsShareable() we could decide to just wrap the java array and
421525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        share it, but that means adding a globalref to the java array object
422525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        and managing its lifetime. For now we just always copy the array's data
423525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if optionsPurgeable(), unless we're just decoding bounds.
424525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov     */
425525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    bool purgeable = optionsPurgeable(env, options)
426525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            && !optionsJustBounds(env, options);
42713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    AutoJavaByteArray ar(env, byteArray);
42813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, purgeable);
429525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkAutoUnref aur(stream);
430f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov    return doDecode(env, stream, NULL, options, purgeable);
431f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov}
4329e795e19c7f900fb2636c5dff3ba30098da65f1bSvetoslav
4334237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganovstatic void nativeRequestCancel(JNIEnv*, jobject joptions) {
4349e795e19c7f900fb2636c5dff3ba30098da65f1bSvetoslav    (void)AutoDecoderCancel::RequestCancel(joptions);
435fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov}
436525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
437525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObject, jfloat scale,
438525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        jobject padding) {
439525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
440525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jbyte* array = env->GetByteArrayElements(chunkObject, 0);
441525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (array != NULL) {
442525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        size_t chunkSize = env->GetArrayLength(chunkObject);
443525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        void* storage = alloca(chunkSize);
44413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        android::Res_png_9patch* chunk = static_cast<android::Res_png_9patch*>(storage);
44513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        memcpy(chunk, array, chunkSize);
44613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        android::Res_png_9patch::deserialize(chunk);
44713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov
44813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        chunk->paddingLeft = int(chunk->paddingLeft * scale + 0.5f);
44913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        chunk->paddingTop = int(chunk->paddingTop * scale + 0.5f);
45013f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        chunk->paddingRight = int(chunk->paddingRight * scale + 0.5f);
45113f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        chunk->paddingBottom = int(chunk->paddingBottom * scale + 0.5f);
45213f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov
45313f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        for (int i = 0; i < chunk->numXDivs; i++) {
45413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov            chunk->xDivs[i] = int(chunk->xDivs[i] * scale + 0.5f);
45513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov            if (i > 0 && chunk->xDivs[i] == chunk->xDivs[i - 1]) {
45613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov                chunk->xDivs[i]++;
45713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov            }
45813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        }
459f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov
460525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        for (int i = 0; i < chunk->numYDivs; i++) {
461525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
462525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
463525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                chunk->yDivs[i]++;
464525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            }
465525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
466f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov
467f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov        memcpy(array, chunk, chunkSize);
468525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
469525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        if (padding) {
470525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            GraphicsJNI::set_jrect(env, padding, chunk->paddingLeft, chunk->paddingTop,
471525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                    chunk->paddingRight, chunk->paddingBottom);
472525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        }
473c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov
474c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov        env->ReleaseByteArrayElements(chunkObject, array, 0);
475c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov    }
476c80814e70aea8940d0d43cd7170baae8c0c4e8e3Svet Ganov    return chunkObject;
477525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
478525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
4794237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganovstatic void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) {
4804237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    SkBitmap::Config config = static_cast<SkBitmap::Config>(nativeConfig);
4814237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov
4824237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    // these are the only default configs that make sense for codecs right now
4834237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    static const SkBitmap::Config gValidDefConfig[] = {
4844237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov        SkBitmap::kRGB_565_Config,
4854237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov        SkBitmap::kARGB_8888_Config,
4864237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    };
487525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
48813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    for (size_t i = 0; i < SK_ARRAY_COUNT(gValidDefConfig); i++) {
48913f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        if (config == gValidDefConfig[i]) {
490eaaf0512fcbf03b926cdbbbb7f54df474ecf861aSvet Ganov            SkImageDecoder::SetDeviceConfig(config);
491eaaf0512fcbf03b926cdbbbb7f54df474ecf861aSvet Ganov            break;
492eaaf0512fcbf03b926cdbbbb7f54df474ecf861aSvet Ganov        }
49313f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    }
49413f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov}
49513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov
49613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov///////////////////////////////////////////////////////////////////////////////
497525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
498525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic JNINativeMethod gMethods[] = {
499525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    {   "nativeDecodeStream",
500525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
501525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        (void*)nativeDecodeStream
502525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    },
503525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
504525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    {   "nativeDecodeFileDescriptor",
505525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
506525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        (void*)nativeDecodeFileDescriptor
5077fd5ada98aa9e035682531d9fe25633fdd24a058Svetoslav    },
508525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
509525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    {   "nativeDecodeAsset",
5104237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov        "(ILandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
5114237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov        (void*)nativeDecodeAsset
5124237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    },
513172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann
514172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann    {   "nativeDecodeByteArray",
515172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann        "([BIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
516172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann        (void*)nativeDecodeByteArray
517172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann    },
518172d840cd133969a5d6c9e9657927ffdbcd44093Philip P. Moltmann
5194237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    {   "nativeScaleNinePatch",
520f6cd14dbc99b38af7afe1e5f72347395603d7de2Svet Ganov        "([BFLandroid/graphics/Rect;)[B",
5214237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov        (void*)nativeScaleNinePatch
5224237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov    },
5234237c92d850b7fb0fa0be15df94e4d1689e353fcSvet Ganov
524525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    {   "nativeSetDefaultConfig", "(I)V", (void*)nativeSetDefaultConfig },
525525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov};
526525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
527525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic JNINativeMethod gOptionsMethods[] = {
528525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    {   "requestCancel", "()V", (void*)nativeRequestCancel }
529525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov};
530525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
531525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovstatic jclass make_globalref(JNIEnv* env, const char classname[]) {
532525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jclass c = env->FindClass(classname);
533525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkASSERT(c);
534525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return (jclass)env->NewGlobalRef(c);
535525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
5361710e0318db5db833974e390eb4bde54ab2f3c62Svetoslav
5371710e0318db5db833974e390eb4bde54ab2f3c62Svetoslavstatic jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
538525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                const char fieldname[], const char type[]) {
539525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    jfieldID id = env->GetFieldID(clazz, fieldname, type);
540525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    SkASSERT(id);
541525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return id;
542525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
543525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
544525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#define kClassPathName  "android/graphics/BitmapFactory"
545525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
546525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov#define RETURN_ERR_IF_NULL(value) \
547525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    do { if (!(value)) { assert(0); return -1; } } while (false)
548525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
549525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovint register_android_graphics_BitmapFactory(JNIEnv* env);
550525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganovint register_android_graphics_BitmapFactory(JNIEnv* env) {
551525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options");
552525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z");
553525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
554525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
555525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            "Landroid/graphics/Bitmap$Config;");
556525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
557525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
558525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
559525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z");
560525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
561525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
562525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
563525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z");
564525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
565525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
566525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
567525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov
568525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    int ret = AndroidRuntime::registerNativeMethods(env,
569525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                    "android/graphics/BitmapFactory$Options",
570525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                    gOptionsMethods,
571525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                    SK_ARRAY_COUNT(gOptionsMethods));
572525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    if (ret) {
573525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov        return ret;
574525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    }
575525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
576525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov                                         gMethods, SK_ARRAY_COUNT(gMethods));
577525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov}
578525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov