blob: f831c051182ec000b9b121e3f9ea6b1fa19d9415 [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 "BitmapFactory.h"
20#include "CreateJavaOutputStreamAdaptor.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080021#include "GraphicsJNI.h"
Matt Sarett1f979632015-10-27 10:33:20 -040022#include "Utils.h"
23
24#include "SkBitmap.h"
25#include "SkBitmapRegionDecoder.h"
26#include "SkCodec.h"
27#include "SkData.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080028#include "SkUtils.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080029#include "SkPixelRef.h"
30#include "SkStream.h"
Matt Sarett1f979632015-10-27 10:33:20 -040031
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080032#include "android_nio_utils.h"
Ben Wagner60126ef2015-08-07 12:13:48 -040033#include "android_util_Binder.h"
34#include "core_jni_helpers.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080035
Steven Moreland2279b252017-07-19 09:50:45 -070036#include <nativehelper/JNIHelp.h>
Ben Wagner60126ef2015-08-07 12:13:48 -040037#include <androidfw/Asset.h>
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080038#include <binder/Parcel.h>
39#include <jni.h>
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080040#include <sys/stat.h>
41
Ben Wagner18bd8852016-10-24 14:50:10 -040042#include <memory>
43
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080044using namespace android;
45
Ben Wagnerd8b5c312016-08-03 15:55:25 -040046static jobject createBitmapRegionDecoder(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream) {
Ben Wagner18bd8852016-10-24 14:50:10 -040047 std::unique_ptr<SkBitmapRegionDecoder> brd(
Ben Wagnerd8b5c312016-08-03 15:55:25 -040048 SkBitmapRegionDecoder::Create(stream.release(),
49 SkBitmapRegionDecoder::kAndroidCodec_Strategy));
Ben Wagner18bd8852016-10-24 14:50:10 -040050 if (!brd) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080051 doThrowIOE(env, "Image format not supported");
Matt Sarett1f979632015-10-27 10:33:20 -040052 return nullObjectReturn("CreateBitmapRegionDecoder returned null");
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080053 }
54
Ben Wagner18bd8852016-10-24 14:50:10 -040055 return GraphicsJNI::createBitmapRegionDecoder(env, brd.release());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080056}
57
58static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
Ashok Bhatb091d472014-01-08 14:32:49 +000059 jint offset, jint length, jboolean isShareable) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080060 /* If isShareable we could decide to just wrap the java array and
61 share it, but that means adding a globalref to the java array object
62 For now we just always copy the array's data if isShareable.
63 */
64 AutoJavaByteArray ar(env, byteArray);
Ben Wagnerd8b5c312016-08-03 15:55:25 -040065 std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, true));
Derek Sollenberger5827cb52013-07-26 14:58:06 -040066
Leon Scroggins III34497892015-01-20 15:52:43 -050067 // the decoder owns the stream.
Ben Wagnerd8b5c312016-08-03 15:55:25 -040068 jobject brd = createBitmapRegionDecoder(env, std::move(stream));
Derek Sollenberger5827cb52013-07-26 14:58:06 -040069 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080070}
71
72static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
73 jobject fileDescriptor, jboolean isShareable) {
74 NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
75
Elliott Hughesa3804cf2011-04-11 16:50:19 -070076 jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
Derek Sollenberger5827cb52013-07-26 14:58:06 -040077
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080078 struct stat fdStat;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080079 if (fstat(descriptor, &fdStat) == -1) {
80 doThrowIOE(env, "broken file descriptor");
81 return nullObjectReturn("fstat return -1");
82 }
83
Ben Wagnerd8b5c312016-08-03 15:55:25 -040084 sk_sp<SkData> data(SkData::MakeFromFD(descriptor));
85 std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(std::move(data)));
Wei-Ta Chen58c1579c2010-10-21 20:56:28 -070086
Leon Scroggins III34497892015-01-20 15:52:43 -050087 // the decoder owns the stream.
Ben Wagnerd8b5c312016-08-03 15:55:25 -040088 jobject brd = createBitmapRegionDecoder(env, std::move(stream));
Derek Sollenberger5827cb52013-07-26 14:58:06 -040089 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080090}
91
92static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
93 jobject is, // InputStream
94 jbyteArray storage, // byte[]
95 jboolean isShareable) {
Derek Sollenberger5827cb52013-07-26 14:58:06 -040096 jobject brd = NULL;
Leon Scroggins IIIca320212013-08-20 17:59:39 -040097 // for now we don't allow shareable with java inputstreams
Ben Wagnerd8b5c312016-08-03 15:55:25 -040098 std::unique_ptr<SkStreamRewindable> stream(CopyJavaInputStream(env, is, storage));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080099
100 if (stream) {
Leon Scroggins III34497892015-01-20 15:52:43 -0500101 // the decoder owns the stream.
Ben Wagnerd8b5c312016-08-03 15:55:25 -0400102 brd = createBitmapRegionDecoder(env, std::move(stream));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800103 }
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400104 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800105}
106
107static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
Ashok Bhatb091d472014-01-08 14:32:49 +0000108 jlong native_asset, // Asset
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800109 jboolean isShareable) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800110 Asset* asset = reinterpret_cast<Asset*>(native_asset);
Ben Wagnerd8b5c312016-08-03 15:55:25 -0400111 std::unique_ptr<SkMemoryStream> stream(CopyAssetToStream(asset));
Leon Scroggins III34497892015-01-20 15:52:43 -0500112 if (NULL == stream) {
Leon Scroggins IIIca320212013-08-20 17:59:39 -0400113 return NULL;
114 }
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400115
Leon Scroggins III34497892015-01-20 15:52:43 -0500116 // the decoder owns the stream.
Ben Wagnerd8b5c312016-08-03 15:55:25 -0400117 jobject brd = createBitmapRegionDecoder(env, std::move(stream));
Derek Sollenberger5827cb52013-07-26 14:58:06 -0400118 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800119}
120
121/*
122 * nine patch not supported
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800123 * purgeable not supported
124 * reportSizeToVM not supported
125 */
Matt Sarett1f979632015-10-27 10:33:20 -0400126static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint inputX,
127 jint inputY, jint inputWidth, jint inputHeight, jobject options) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800128
Matt Sarett1f979632015-10-27 10:33:20 -0400129 // Set default options.
130 int sampleSize = 1;
131 SkColorType colorType = kN32_SkColorType;
132 bool requireUnpremul = false;
133 jobject javaBitmap = NULL;
sergeyvda6c8ffc2016-11-22 18:28:54 -0800134 bool isHardware = false;
Romain Guy95648b82017-04-13 18:43:42 -0700135 sk_sp<SkColorSpace> colorSpace = nullptr;
Matt Sarett1f979632015-10-27 10:33:20 -0400136 // Update the default options with any options supplied by the client.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800137 if (NULL != options) {
138 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
Matt Sarett1f979632015-10-27 10:33:20 -0400139 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
140 colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
Romain Guy95648b82017-04-13 18:43:42 -0700141 jobject jcolorSpace = env->GetObjectField(options, gOptions_colorSpaceFieldID);
142 colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
sergeyvda6c8ffc2016-11-22 18:28:54 -0800143 isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
Matt Sarett1f979632015-10-27 10:33:20 -0400144 requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
145 javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
146 // The Java options of ditherMode and preferQualityOverSpeed are deprecated. We will
147 // ignore the values of these fields.
148
149 // Initialize these fields to indicate a failure. If the decode succeeds, we
150 // will update them later on.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800151 env->SetIntField(options, gOptions_widthFieldID, -1);
152 env->SetIntField(options, gOptions_heightFieldID, -1);
153 env->SetObjectField(options, gOptions_mimeFieldID, 0);
Romain Guy95648b82017-04-13 18:43:42 -0700154 env->SetObjectField(options, gOptions_outConfigFieldID, 0);
155 env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800156 }
157
Matt Sarett1f979632015-10-27 10:33:20 -0400158 // Recycle a bitmap if possible.
sergeyvc1c54062016-10-19 18:47:26 -0700159 android::Bitmap* recycledBitmap = nullptr;
Matt Sarett1f979632015-10-27 10:33:20 -0400160 size_t recycledBytes = 0;
161 if (javaBitmap) {
sergeyvaed7f582016-10-14 16:30:21 -0700162 recycledBitmap = &bitmap::toBitmap(env, javaBitmap);
sergeyvc69853c2016-10-07 14:14:09 -0700163 if (recycledBitmap->isImmutable()) {
Matt Sarett1f979632015-10-27 10:33:20 -0400164 ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
165 }
sergeyvc69853c2016-10-07 14:14:09 -0700166 recycledBytes = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800167 }
168
Leon Scroggins III8d592f92018-03-12 15:44:03 -0400169 SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
170 SkColorType decodeColorType = brd->computeOutputColorType(colorType);
171
Matt Sarett1f979632015-10-27 10:33:20 -0400172 // Set up the pixel allocator
173 SkBRDAllocator* allocator = nullptr;
174 RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes);
sergeyv45082182016-09-29 18:25:40 -0700175 HeapAllocator heapAlloc;
Matt Sarett1f979632015-10-27 10:33:20 -0400176 if (javaBitmap) {
177 allocator = &recycleAlloc;
178 // We are required to match the color type of the recycled bitmap.
Romain Guy95648b82017-04-13 18:43:42 -0700179 decodeColorType = recycledBitmap->info().colorType();
Matt Sarett1f979632015-10-27 10:33:20 -0400180 } else {
sergeyv45082182016-09-29 18:25:40 -0700181 allocator = &heapAlloc;
Matt Sarett1f979632015-10-27 10:33:20 -0400182 }
183
Leon Scroggins III8d592f92018-03-12 15:44:03 -0400184 sk_sp<SkColorSpace> decodeColorSpace = brd->computeOutputColorSpace(
185 decodeColorType, colorSpace);
186
Matt Sarett1f979632015-10-27 10:33:20 -0400187 // Decode the region.
188 SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
John Reckf29ed282015-04-07 07:32:03 -0700189 SkBitmap bitmap;
Romain Guy95648b82017-04-13 18:43:42 -0700190 if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize,
191 decodeColorType, requireUnpremul, decodeColorSpace)) {
Matt Sarett1f979632015-10-27 10:33:20 -0400192 return nullObjectReturn("Failed to decode region.");
Owen Linf970c2e2012-04-25 18:49:09 +0800193 }
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800194
Matt Sarett1f979632015-10-27 10:33:20 -0400195 // If the client provided options, indicate that the decode was successful.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800196 if (NULL != options) {
John Reckf29ed282015-04-07 07:32:03 -0700197 env->SetIntField(options, gOptions_widthFieldID, bitmap.width());
198 env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
Romain Guy95648b82017-04-13 18:43:42 -0700199
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800200 env->SetObjectField(options, gOptions_mimeFieldID,
Hal Canary10219fb2016-11-23 20:41:22 -0500201 encodedFormatToString(env, (SkEncodedImageFormat)brd->getEncodedFormat()));
Matt Sarettd31512b2015-12-09 15:16:31 -0500202 if (env->ExceptionCheck()) {
203 return nullObjectReturn("OOM in encodedFormatToString()");
204 }
Romain Guy95648b82017-04-13 18:43:42 -0700205
206 jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType);
207 if (isHardware) {
208 configID = GraphicsJNI::kHardware_LegacyBitmapConfig;
209 }
210 jobject config = env->CallStaticObjectMethod(gBitmapConfig_class,
211 gBitmapConfig_nativeToConfigMethodID, configID);
212 env->SetObjectField(options, gOptions_outConfigFieldID, config);
213
214 env->SetObjectField(options, gOptions_outColorSpaceFieldID,
215 GraphicsJNI::getColorSpace(env, decodeColorSpace, decodeColorType));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800216 }
217
Matt Sarett1f979632015-10-27 10:33:20 -0400218 // If we may have reused a bitmap, we need to indicate that the pixels have changed.
219 if (javaBitmap) {
220 recycleAlloc.copyIfNecessary();
Romain Guy55455182017-04-15 21:41:22 -0700221 bitmap::reinitBitmap(env, javaBitmap, recycledBitmap->info(), !requireUnpremul);
Matt Sarett1f979632015-10-27 10:33:20 -0400222 return javaBitmap;
Owen Linf970c2e2012-04-25 18:49:09 +0800223 }
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800224
Chris Craik1abf5d62013-08-16 12:47:03 -0700225 int bitmapCreateFlags = 0;
Matt Sarett1f979632015-10-27 10:33:20 -0400226 if (!requireUnpremul) {
sergeyvc69853c2016-10-07 14:14:09 -0700227 bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
Matt Sarett1f979632015-10-27 10:33:20 -0400228 }
sergeyvda6c8ffc2016-11-22 18:28:54 -0800229 if (isHardware) {
230 sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(bitmap);
231 return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags);
232 }
sergeyvc69853c2016-10-07 14:14:09 -0700233 return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800234}
235
Ashok Bhatb091d472014-01-08 14:32:49 +0000236static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
Matt Sarett1f979632015-10-27 10:33:20 -0400237 SkBitmapRegionDecoder* brd =
238 reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
239 return static_cast<jint>(brd->height());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800240}
241
Ashok Bhatb091d472014-01-08 14:32:49 +0000242static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) {
Matt Sarett1f979632015-10-27 10:33:20 -0400243 SkBitmapRegionDecoder* brd =
244 reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
245 return static_cast<jint>(brd->width());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800246}
247
Ashok Bhatb091d472014-01-08 14:32:49 +0000248static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) {
Matt Sarett1f979632015-10-27 10:33:20 -0400249 SkBitmapRegionDecoder* brd =
250 reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800251 delete brd;
252}
253
254///////////////////////////////////////////////////////////////////////////////
255
Daniel Micay76f6a862015-09-19 17:31:01 -0400256static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800257 { "nativeDecodeRegion",
Ashok Bhatb091d472014-01-08 14:32:49 +0000258 "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800259 (void*)nativeDecodeRegion},
260
Ashok Bhatb091d472014-01-08 14:32:49 +0000261 { "nativeGetHeight", "(J)I", (void*)nativeGetHeight},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800262
Ashok Bhatb091d472014-01-08 14:32:49 +0000263 { "nativeGetWidth", "(J)I", (void*)nativeGetWidth},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800264
Ashok Bhatb091d472014-01-08 14:32:49 +0000265 { "nativeClean", "(J)V", (void*)nativeClean},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800266
267 { "nativeNewInstance",
268 "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
269 (void*)nativeNewInstanceFromByteArray
270 },
271
272 { "nativeNewInstance",
273 "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
274 (void*)nativeNewInstanceFromStream
275 },
276
277 { "nativeNewInstance",
278 "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
279 (void*)nativeNewInstanceFromFileDescriptor
280 },
281
282 { "nativeNewInstance",
Ashok Bhatb091d472014-01-08 14:32:49 +0000283 "(JZ)Landroid/graphics/BitmapRegionDecoder;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800284 (void*)nativeNewInstanceFromAsset
285 },
286};
287
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800288int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
289{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800290 return android::RegisterMethodsOrDie(env, "android/graphics/BitmapRegionDecoder",
291 gBitmapRegionDecoderMethods, NELEM(gBitmapRegionDecoderMethods));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800292}