BitmapRegionDecoder.cpp revision 5e49b497ae2019586937aae0e8159292363728b5
1e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin/*
2e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * Copyright (C) 2010 The Android Open Source Project
3e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin *
4e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * Licensed under the Apache License, Version 2.0 (the "License");
5e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * you may not use this file except in compliance with the License.
6e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * You may obtain a copy of the License at
7e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin *
8e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin *      http://www.apache.org/licenses/LICENSE-2.0
9e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin *
10e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * Unless required by applicable law or agreed to in writing, software
11e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * distributed under the License is distributed on an "AS IS" BASIS,
12e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * See the License for the specific language governing permissions and
14e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * limitations under the License.
15e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin */
16e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin
17e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#define LOG_TAG "BitmapRegionDecoder"
18e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin
191b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "SkBitmap.h"
20e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkData.h"
21e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkImageEncoder.h"
22e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "GraphicsJNI.h"
23e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkUtils.h"
24e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkTemplates.h"
25e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkPixelRef.h"
26e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkStream.h"
27e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "BitmapFactory.h"
28e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "AutoDecodeCancel.h"
291b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "CreateJavaOutputStreamAdaptor.h"
301b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "Utils.h"
311b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "JNIHelp.h"
321b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
33e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include <android_runtime/AndroidRuntime.h>
34e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "android_util_Binder.h"
35e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "android_nio_utils.h"
361b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "CreateJavaOutputStreamAdaptor.h"
371b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
381b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <binder/Parcel.h>
391b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <jni.h>
401b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <androidfw/Asset.h>
411b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <sys/stat.h>
421b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
431b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#if 0
441b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    #define TRACE_BITMAP(code)  code
451b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#else
461b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    #define TRACE_BITMAP(code)
471b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#endif
481b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
491b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinusing namespace android;
501b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
511b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinclass SkBitmapRegionDecoder {
521b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinpublic:
531b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    SkBitmapRegionDecoder(SkImageDecoder* decoder, int width, int height) {
541b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        fDecoder = decoder;
551b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        fWidth = width;
561b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        fHeight = height;
571b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    }
581b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    ~SkBitmapRegionDecoder() {
591b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        SkDELETE(fDecoder);
601b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    }
611b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
621b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect,
631b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin                      SkBitmap::Config pref, int sampleSize) {
64e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin        fDecoder->setSampleSize(sampleSize);
651b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        return fDecoder->decodeRegion(bitmap, rect, pref);
661b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    }
671b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
681b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    SkImageDecoder* getDecoder() const { return fDecoder; }
691b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    int getWidth() const { return fWidth; }
701b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    int getHeight() const { return fHeight; }
711b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
721b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinprivate:
731b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    SkImageDecoder* fDecoder;
741b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    int fWidth;
751b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    int fHeight;
761b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin};
771b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
781b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinstatic jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) {
791b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
801b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    int width, height;
811b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    if (NULL == decoder) {
821b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        doThrowIOE(env, "Image format not supported");
831b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        return nullObjectReturn("SkImageDecoder::Factory returned null");
841b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    }
85e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin
86e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env);
87e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    decoder->setAllocator(javaAllocator);
88e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    javaAllocator->unref();
89e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin
90e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    if (!decoder->buildTileIndex(stream, &width, &height)) {
91e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin        char msg[100];
92e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin        snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
93e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin                decoder->getFormatName());
941b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        doThrowIOE(env, msg);
951b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        SkDELETE(decoder);
96e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin        return nullObjectReturn("decoder->buildTileIndex returned false");
97e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    }
98e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin
99e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
100e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    return GraphicsJNI::createBitmapRegionDecoder(env, bm);
101e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin}
1021b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
1031b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinstatic jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
1041b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin                                     int offset, int length, jboolean isShareable) {
1051b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    /*  If isShareable we could decide to just wrap the java array and
1061b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        share it, but that means adding a globalref to the java array object
1071b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        For now we just always copy the array's data if isShareable.
1081b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin     */
1091b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    AutoJavaByteArray ar(env, byteArray);
1101b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    SkStreamRewindable* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
1111b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
1121b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    jobject brd = createBitmapRegionDecoder(env, stream);
1131b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    SkSafeUnref(stream); // the decoder now holds a reference
1141b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    return brd;
1151b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin}
1161b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
1171b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinstatic jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
1181b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin                                          jobject fileDescriptor, jboolean isShareable) {
1191b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
1201b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
1211b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
1221b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
1231b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    struct stat fdStat;
1241b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    if (fstat(descriptor, &fdStat) == -1) {
1251b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        doThrowIOE(env, "broken file descriptor");
1261b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin        return nullObjectReturn("fstat return -1");
1271b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin    }
1281b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin
129e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin    SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor));
130    SkMemoryStream* stream = new SkMemoryStream(data);
131
132    jobject brd = createBitmapRegionDecoder(env, stream);
133    SkSafeUnref(stream); // the decoder now holds a reference
134    return brd;
135}
136
137static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
138                                  jobject is,       // InputStream
139                                  jbyteArray storage, // byte[]
140                                  jboolean isShareable) {
141    jobject brd = NULL;
142    // for now we don't allow shareable with java inputstreams
143    SkStreamRewindable* stream = CopyJavaInputStream(env, is, storage);
144
145    if (stream) {
146        brd = createBitmapRegionDecoder(env, stream);
147        stream->unref(); // the decoder now holds a reference
148    }
149    return brd;
150}
151
152static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
153                                 jint native_asset, // Asset
154                                 jboolean isShareable) {
155    Asset* asset = reinterpret_cast<Asset*>(native_asset);
156    SkAutoTUnref<SkMemoryStream> stream(CopyAssetToStream(asset));
157    if (NULL == stream.get()) {
158        return NULL;
159    }
160
161    jobject brd = createBitmapRegionDecoder(env, stream.get());
162    // The decoder now holds a reference to stream.
163    return brd;
164}
165
166/*
167 * nine patch not supported
168 *
169 * purgeable not supported
170 * reportSizeToVM not supported
171 */
172static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
173                                int start_x, int start_y, int width, int height, jobject options) {
174    jobject tileBitmap = NULL;
175    SkImageDecoder *decoder = brd->getDecoder();
176    int sampleSize = 1;
177    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
178    bool doDither = true;
179    bool preferQualityOverSpeed = false;
180    bool requireUnpremultiplied = false;
181
182    if (NULL != options) {
183        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
184        // initialize these, in case we fail later on
185        env->SetIntField(options, gOptions_widthFieldID, -1);
186        env->SetIntField(options, gOptions_heightFieldID, -1);
187        env->SetObjectField(options, gOptions_mimeFieldID, 0);
188
189        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
190        prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
191        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
192        preferQualityOverSpeed = env->GetBooleanField(options,
193                gOptions_preferQualityOverSpeedFieldID);
194        // Get the bitmap for re-use if it exists.
195        tileBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
196        requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
197    }
198
199    decoder->setDitherImage(doDither);
200    decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
201    decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
202    AutoDecoderCancel adc(options, decoder);
203
204    // To fix the race condition in case "requestCancelDecode"
205    // happens earlier than AutoDecoderCancel object is added
206    // to the gAutoDecoderCancelMutex linked list.
207    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
208        return nullObjectReturn("gOptions_mCancelID");;
209    }
210
211    SkIRect region;
212    region.fLeft = start_x;
213    region.fTop = start_y;
214    region.fRight = start_x + width;
215    region.fBottom = start_y + height;
216    SkBitmap* bitmap = NULL;
217    SkAutoTDelete<SkBitmap> adb;
218
219    if (tileBitmap != NULL) {
220        // Re-use bitmap.
221        bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap);
222    }
223    if (bitmap == NULL) {
224        bitmap = new SkBitmap;
225        adb.reset(bitmap);
226    }
227
228    if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
229        return nullObjectReturn("decoder->decodeRegion returned false");
230    }
231
232    // update options (if any)
233    if (NULL != options) {
234        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
235        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
236        // TODO: set the mimeType field with the data from the codec.
237        // but how to reuse a set of strings, rather than allocating new one
238        // each time?
239        env->SetObjectField(options, gOptions_mimeFieldID,
240                            getMimeTypeString(env, decoder->getFormat()));
241    }
242
243    if (tileBitmap != NULL) {
244        return tileBitmap;
245    }
246
247    // detach bitmap from its autodeleter, since we want to own it now
248    adb.detach();
249
250    JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator();
251    jbyteArray buff = allocator->getStorageObjAndReset();
252
253    int bitmapCreateFlags = 0;
254    if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
255    return GraphicsJNI::createBitmap(env, bitmap, buff, bitmapCreateFlags, NULL, NULL, -1);
256}
257
258static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
259    return brd->getHeight();
260}
261
262static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
263    return brd->getWidth();
264}
265
266static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
267    delete brd;
268}
269
270///////////////////////////////////////////////////////////////////////////////
271
272#include <android_runtime/AndroidRuntime.h>
273
274static JNINativeMethod gBitmapRegionDecoderMethods[] = {
275    {   "nativeDecodeRegion",
276        "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
277        (void*)nativeDecodeRegion},
278
279    {   "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
280
281    {   "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
282
283    {   "nativeClean", "(I)V", (void*)nativeClean},
284
285    {   "nativeNewInstance",
286        "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
287        (void*)nativeNewInstanceFromByteArray
288    },
289
290    {   "nativeNewInstance",
291        "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
292        (void*)nativeNewInstanceFromStream
293    },
294
295    {   "nativeNewInstance",
296        "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
297        (void*)nativeNewInstanceFromFileDescriptor
298    },
299
300    {   "nativeNewInstance",
301        "(IZ)Landroid/graphics/BitmapRegionDecoder;",
302        (void*)nativeNewInstanceFromAsset
303    },
304};
305
306#define kClassPathName  "android/graphics/BitmapRegionDecoder"
307
308int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
309{
310    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
311            gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
312}
313