blob: 8535e6a8c97548476d321ef9ad5c1d1ffb8f88e2 [file] [log] [blame]
Wei-Ta Chen6b849e22010-09-07 17:32:18 +08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "BitmapRegionDecoder"
18
Ben Wagner60126ef2015-08-07 12:13:48 -040019#include "AutoDecodeCancel.h"
20#include "BitmapFactory.h"
21#include "CreateJavaOutputStreamAdaptor.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080022#include "SkBitmap.h"
Derek Sollenberger5827cb52013-07-26 14:58:06 -040023#include "SkData.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080024#include "GraphicsJNI.h"
Ben Wagner60126ef2015-08-07 12:13:48 -040025#include "SkImageEncoder.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080026#include "SkUtils.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080027#include "SkPixelRef.h"
28#include "SkStream.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080029#include "Utils.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080030#include "android_nio_utils.h"
Ben Wagner60126ef2015-08-07 12:13:48 -040031#include "android_util_Binder.h"
32#include "core_jni_helpers.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080033
Ben Wagner60126ef2015-08-07 12:13:48 -040034#include <JNIHelp.h>
35#include <androidfw/Asset.h>
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080036#include <binder/Parcel.h>
37#include <jni.h>
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080038#include <sys/stat.h>
39
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080040using namespace android;
41
Derek Sollenberger5827cb52013-07-26 14:58:06 -040042class SkBitmapRegionDecoder {
43public:
44 SkBitmapRegionDecoder(SkImageDecoder* decoder, int width, int height) {
45 fDecoder = decoder;
46 fWidth = width;
47 fHeight = height;
48 }
49 ~SkBitmapRegionDecoder() {
50 SkDELETE(fDecoder);
51 }
52
53 bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect,
Mike Reed42a1d082014-07-07 18:06:18 -040054 SkColorType pref, int sampleSize) {
Derek Sollenberger5827cb52013-07-26 14:58:06 -040055 fDecoder->setSampleSize(sampleSize);
Leon Scrogginscc11f152014-03-31 16:52:13 -040056 return fDecoder->decodeSubset(bitmap, rect, pref);
Derek Sollenberger5827cb52013-07-26 14:58:06 -040057 }
58
59 SkImageDecoder* getDecoder() const { return fDecoder; }
60 int getWidth() const { return fWidth; }
61 int getHeight() const { return fHeight; }
62
63private:
64 SkImageDecoder* fDecoder;
65 int fWidth;
66 int fHeight;
67};
68
Leon Scroggins III34497892015-01-20 15:52:43 -050069// Takes ownership of the SkStreamRewindable. For consistency, deletes stream even
70// when returning null.
Derek Sollenbergered79ff02013-11-20 14:50:51 -050071static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080072 SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
73 int width, height;
74 if (NULL == decoder) {
Leon Scroggins III34497892015-01-20 15:52:43 -050075 SkDELETE(stream);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080076 doThrowIOE(env, "Image format not supported");
77 return nullObjectReturn("SkImageDecoder::Factory returned null");
78 }
79
Patrick Dubroye4ac2d62010-12-01 11:23:13 -080080 JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080081 decoder->setAllocator(javaAllocator);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080082 javaAllocator->unref();
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080083
Leon Scroggins III34497892015-01-20 15:52:43 -050084 // This call passes ownership of stream to the decoder, or deletes on failure.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080085 if (!decoder->buildTileIndex(stream, &width, &height)) {
86 char msg[100];
87 snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
88 decoder->getFormatName());
89 doThrowIOE(env, msg);
Derek Sollenberger5827cb52013-07-26 14:58:06 -040090 SkDELETE(decoder);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080091 return nullObjectReturn("decoder->buildTileIndex returned false");
92 }
93
Derek Sollenberger5827cb52013-07-26 14:58:06 -040094 SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080095 return GraphicsJNI::createBitmapRegionDecoder(env, bm);
96}
97
98static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
Ashok Bhatb091d472014-01-08 14:32:49 +000099 jint offset, jint length, jboolean isShareable) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800100 /* If isShareable we could decide to just wrap the java array and
101 share it, but that means adding a globalref to the java array object
102 For now we just always copy the array's data if isShareable.
103 */
104 AutoJavaByteArray ar(env, byteArray);
Derek Sollenbergered79ff02013-11-20 14:50:51 -0500105 SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400106
Leon Scroggins III34497892015-01-20 15:52:43 -0500107 // the decoder owns the stream.
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400108 jobject brd = createBitmapRegionDecoder(env, stream);
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400109 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800110}
111
112static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
113 jobject fileDescriptor, jboolean isShareable) {
114 NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
115
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700116 jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400117
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800118 struct stat fdStat;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800119 if (fstat(descriptor, &fdStat) == -1) {
120 doThrowIOE(env, "broken file descriptor");
121 return nullObjectReturn("fstat return -1");
122 }
123
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400124 SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor));
125 SkMemoryStream* stream = new SkMemoryStream(data);
Wei-Ta Chen58c1579c2010-10-21 20:56:28 -0700126
Leon Scroggins III34497892015-01-20 15:52:43 -0500127 // the decoder owns the stream.
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400128 jobject brd = createBitmapRegionDecoder(env, stream);
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400129 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800130}
131
132static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
133 jobject is, // InputStream
134 jbyteArray storage, // byte[]
135 jboolean isShareable) {
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400136 jobject brd = NULL;
Leon Scroggins IIIca320212013-08-20 17:59:39 -0400137 // for now we don't allow shareable with java inputstreams
Leon Scroggins IIIc7797522013-09-03 11:35:00 -0400138 SkStreamRewindable* stream = CopyJavaInputStream(env, is, storage);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800139
140 if (stream) {
Leon Scroggins III34497892015-01-20 15:52:43 -0500141 // the decoder owns the stream.
Leon Scroggins IIIca320212013-08-20 17:59:39 -0400142 brd = createBitmapRegionDecoder(env, stream);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800143 }
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400144 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800145}
146
147static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
Ashok Bhatb091d472014-01-08 14:32:49 +0000148 jlong native_asset, // Asset
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800149 jboolean isShareable) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800150 Asset* asset = reinterpret_cast<Asset*>(native_asset);
Leon Scroggins III34497892015-01-20 15:52:43 -0500151 SkMemoryStream* stream = CopyAssetToStream(asset);
152 if (NULL == stream) {
Leon Scroggins IIIca320212013-08-20 17:59:39 -0400153 return NULL;
154 }
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400155
Leon Scroggins III34497892015-01-20 15:52:43 -0500156 // the decoder owns the stream.
157 jobject brd = createBitmapRegionDecoder(env, stream);
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400158 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800159}
160
161/*
162 * nine patch not supported
163 *
164 * purgeable not supported
165 * reportSizeToVM not supported
166 */
Ashok Bhatb091d472014-01-08 14:32:49 +0000167static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle,
168 jint start_x, jint start_y, jint width, jint height, jobject options) {
169 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
Owen Linf970c2e2012-04-25 18:49:09 +0800170 jobject tileBitmap = NULL;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800171 SkImageDecoder *decoder = brd->getDecoder();
172 int sampleSize = 1;
Mike Reed42a1d082014-07-07 18:06:18 -0400173 SkColorType prefColorType = kUnknown_SkColorType;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800174 bool doDither = true;
Wei-Ta Chen953f9092010-12-03 14:06:18 -0800175 bool preferQualityOverSpeed = false;
Chris Craik1abf5d62013-08-16 12:47:03 -0700176 bool requireUnpremultiplied = false;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800177
178 if (NULL != options) {
179 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
180 // initialize these, in case we fail later on
181 env->SetIntField(options, gOptions_widthFieldID, -1);
182 env->SetIntField(options, gOptions_heightFieldID, -1);
183 env->SetObjectField(options, gOptions_mimeFieldID, 0);
184
185 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
Mike Reed42a1d082014-07-07 18:06:18 -0400186 prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800187 doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
Wei-Ta Chen953f9092010-12-03 14:06:18 -0800188 preferQualityOverSpeed = env->GetBooleanField(options,
189 gOptions_preferQualityOverSpeedFieldID);
Owen Linf970c2e2012-04-25 18:49:09 +0800190 // Get the bitmap for re-use if it exists.
191 tileBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
Leon Scroggins III2cc409a2013-08-26 14:27:15 -0400192 requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800193 }
194
195 decoder->setDitherImage(doDither);
Wei-Ta Chen953f9092010-12-03 14:06:18 -0800196 decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
Chris Craik1abf5d62013-08-16 12:47:03 -0700197 decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
198 AutoDecoderCancel adc(options, decoder);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800199
200 // To fix the race condition in case "requestCancelDecode"
201 // happens earlier than AutoDecoderCancel object is added
202 // to the gAutoDecoderCancelMutex linked list.
203 if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
204 return nullObjectReturn("gOptions_mCancelID");;
205 }
206
207 SkIRect region;
208 region.fLeft = start_x;
209 region.fTop = start_y;
210 region.fRight = start_x + width;
211 region.fBottom = start_y + height;
John Reckf29ed282015-04-07 07:32:03 -0700212 SkBitmap bitmap;
Owen Linf970c2e2012-04-25 18:49:09 +0800213
214 if (tileBitmap != NULL) {
215 // Re-use bitmap.
John Reckf29ed282015-04-07 07:32:03 -0700216 GraphicsJNI::getSkBitmap(env, tileBitmap, &bitmap);
Owen Linf970c2e2012-04-25 18:49:09 +0800217 }
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800218
John Reckf29ed282015-04-07 07:32:03 -0700219 if (!brd->decodeRegion(&bitmap, region, prefColorType, sampleSize)) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800220 return nullObjectReturn("decoder->decodeRegion returned false");
221 }
222
223 // update options (if any)
224 if (NULL != options) {
John Reckf29ed282015-04-07 07:32:03 -0700225 env->SetIntField(options, gOptions_widthFieldID, bitmap.width());
226 env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800227 // TODO: set the mimeType field with the data from the codec.
228 // but how to reuse a set of strings, rather than allocating new one
229 // each time?
230 env->SetObjectField(options, gOptions_mimeFieldID,
231 getMimeTypeString(env, decoder->getFormat()));
232 }
233
Owen Linf970c2e2012-04-25 18:49:09 +0800234 if (tileBitmap != NULL) {
John Reckf29ed282015-04-07 07:32:03 -0700235 bitmap.notifyPixelsChanged();
Owen Linf970c2e2012-04-25 18:49:09 +0800236 return tileBitmap;
237 }
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800238
Patrick Dubroyafde46e2010-12-15 11:52:01 -0800239 JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator();
Chris Craik1abf5d62013-08-16 12:47:03 -0700240
241 int bitmapCreateFlags = 0;
242 if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
John Reckf29ed282015-04-07 07:32:03 -0700243 return GraphicsJNI::createBitmap(env, allocator->getStorageObjAndReset(),
244 bitmapCreateFlags);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800245}
246
Ashok Bhatb091d472014-01-08 14:32:49 +0000247static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
248 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
249 return static_cast<jint>(brd->getHeight());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800250}
251
Ashok Bhatb091d472014-01-08 14:32:49 +0000252static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) {
253 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
254 return static_cast<jint>(brd->getWidth());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800255}
256
Ashok Bhatb091d472014-01-08 14:32:49 +0000257static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) {
258 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800259 delete brd;
260}
261
262///////////////////////////////////////////////////////////////////////////////
263
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800264static JNINativeMethod gBitmapRegionDecoderMethods[] = {
265 { "nativeDecodeRegion",
Ashok Bhatb091d472014-01-08 14:32:49 +0000266 "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800267 (void*)nativeDecodeRegion},
268
Ashok Bhatb091d472014-01-08 14:32:49 +0000269 { "nativeGetHeight", "(J)I", (void*)nativeGetHeight},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800270
Ashok Bhatb091d472014-01-08 14:32:49 +0000271 { "nativeGetWidth", "(J)I", (void*)nativeGetWidth},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800272
Ashok Bhatb091d472014-01-08 14:32:49 +0000273 { "nativeClean", "(J)V", (void*)nativeClean},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800274
275 { "nativeNewInstance",
276 "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
277 (void*)nativeNewInstanceFromByteArray
278 },
279
280 { "nativeNewInstance",
281 "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
282 (void*)nativeNewInstanceFromStream
283 },
284
285 { "nativeNewInstance",
286 "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
287 (void*)nativeNewInstanceFromFileDescriptor
288 },
289
290 { "nativeNewInstance",
Ashok Bhatb091d472014-01-08 14:32:49 +0000291 "(JZ)Landroid/graphics/BitmapRegionDecoder;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800292 (void*)nativeNewInstanceFromAsset
293 },
294};
295
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800296int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
297{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800298 return android::RegisterMethodsOrDie(env, "android/graphics/BitmapRegionDecoder",
299 gBitmapRegionDecoderMethods, NELEM(gBitmapRegionDecoderMethods));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800300}