blob: eb56ae310231f509fd123b45cfcafae9d4fc8341 [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
Derek Sollenberger5368eda2019-10-25 11:20:03 -040017#undef LOG_TAG
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080018#define LOG_TAG "BitmapRegionDecoder"
19
Ben Wagner60126ef2015-08-07 12:13:48 -040020#include "BitmapFactory.h"
21#include "CreateJavaOutputStreamAdaptor.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080022#include "GraphicsJNI.h"
Matt Sarett1f979632015-10-27 10:33:20 -040023#include "Utils.h"
24
Leon Scroggins III23ac0362020-05-04 15:38:58 -040025#include "BitmapRegionDecoder.h"
Matt Sarett1f979632015-10-27 10:33:20 -040026#include "SkBitmap.h"
Matt Sarett1f979632015-10-27 10:33:20 -040027#include "SkCodec.h"
Kevin Lubick07d6aae2022-04-01 14:03:11 -040028#include "SkColorSpace.h"
Matt Sarett1f979632015-10-27 10:33:20 -040029#include "SkData.h"
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080030#include "SkStream.h"
Matt Sarett1f979632015-10-27 10:33:20 -040031
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -050032#include <HardwareBitmapUploader.h>
Ben Wagner60126ef2015-08-07 12:13:48 -040033#include <androidfw/Asset.h>
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080034#include <sys/stat.h>
35
Ben Wagner18bd8852016-10-24 14:50:10 -040036#include <memory>
37
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080038using namespace android;
39
Leon Scroggins III23ac0362020-05-04 15:38:58 -040040static jobject createBitmapRegionDecoder(JNIEnv* env, sk_sp<SkData> data) {
41 auto brd = skia::BitmapRegionDecoder::Make(std::move(data));
Ben Wagner18bd8852016-10-24 14:50:10 -040042 if (!brd) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080043 doThrowIOE(env, "Image format not supported");
Matt Sarett1f979632015-10-27 10:33:20 -040044 return nullObjectReturn("CreateBitmapRegionDecoder returned null");
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080045 }
46
Ben Wagner18bd8852016-10-24 14:50:10 -040047 return GraphicsJNI::createBitmapRegionDecoder(env, brd.release());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080048}
49
50static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
Leon Scroggins III96a13882020-03-04 10:29:04 -050051 jint offset, jint length) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080052 AutoJavaByteArray ar(env, byteArray);
Leon Scroggins III23ac0362020-05-04 15:38:58 -040053 return createBitmapRegionDecoder(env, SkData::MakeWithCopy(ar.ptr() + offset, length));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080054}
55
56static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
Leon Scroggins III96a13882020-03-04 10:29:04 -050057 jobject fileDescriptor) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080058 NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
59
Elliott Hughesa3804cf2011-04-11 16:50:19 -070060 jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
Derek Sollenberger5827cb52013-07-26 14:58:06 -040061
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080062 struct stat fdStat;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080063 if (fstat(descriptor, &fdStat) == -1) {
64 doThrowIOE(env, "broken file descriptor");
65 return nullObjectReturn("fstat return -1");
66 }
67
Leon Scroggins III23ac0362020-05-04 15:38:58 -040068 return createBitmapRegionDecoder(env, SkData::MakeFromFD(descriptor));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080069}
70
Leon Scroggins III96a13882020-03-04 10:29:04 -050071static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, jobject is, // InputStream
72 jbyteArray storage) { // byte[]
Leon Scroggins III23ac0362020-05-04 15:38:58 -040073 jobject brd = nullptr;
74 sk_sp<SkData> data = CopyJavaInputStream(env, is, storage);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080075
Leon Scroggins III23ac0362020-05-04 15:38:58 -040076 if (data) {
77 brd = createBitmapRegionDecoder(env, std::move(data));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080078 }
Derek Sollenberger5827cb52013-07-26 14:58:06 -040079 return brd;
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080080}
81
Leon Scroggins III96a13882020-03-04 10:29:04 -050082static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, jlong native_asset) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080083 Asset* asset = reinterpret_cast<Asset*>(native_asset);
Leon Scroggins III23ac0362020-05-04 15:38:58 -040084 sk_sp<SkData> data = CopyAssetToData(asset);
85 if (!data) {
86 return nullptr;
Leon Scroggins IIIca320212013-08-20 17:59:39 -040087 }
Derek Sollenberger5827cb52013-07-26 14:58:06 -040088
Leon Scroggins III23ac0362020-05-04 15:38:58 -040089 return createBitmapRegionDecoder(env, data);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080090}
91
92/*
93 * nine patch not supported
Wei-Ta Chen6b849e22010-09-07 17:32:18 +080094 * purgeable not supported
95 * reportSizeToVM not supported
96 */
Matt Sarett1f979632015-10-27 10:33:20 -040097static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint inputX,
Leon Scroggins III71fae622019-03-26 16:28:41 -040098 jint inputY, jint inputWidth, jint inputHeight, jobject options, jlong inBitmapHandle,
99 jlong colorSpaceHandle) {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800100
Matt Sarett1f979632015-10-27 10:33:20 -0400101 // Set default options.
102 int sampleSize = 1;
103 SkColorType colorType = kN32_SkColorType;
104 bool requireUnpremul = false;
Leon Scroggins III71fae622019-03-26 16:28:41 -0400105 jobject javaBitmap = nullptr;
sergeyvda6c8ffc2016-11-22 18:28:54 -0800106 bool isHardware = false;
Leon Scroggins III0e443d12018-12-19 11:38:35 -0500107 sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
Matt Sarett1f979632015-10-27 10:33:20 -0400108 // Update the default options with any options supplied by the client.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800109 if (NULL != options) {
110 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
Matt Sarett1f979632015-10-27 10:33:20 -0400111 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
112 colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
sergeyvda6c8ffc2016-11-22 18:28:54 -0800113 isHardware = GraphicsJNI::isHardwareConfig(env, jconfig);
Matt Sarett1f979632015-10-27 10:33:20 -0400114 requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
115 javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
116 // The Java options of ditherMode and preferQualityOverSpeed are deprecated. We will
117 // ignore the values of these fields.
118
119 // Initialize these fields to indicate a failure. If the decode succeeds, we
120 // will update them later on.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800121 env->SetIntField(options, gOptions_widthFieldID, -1);
122 env->SetIntField(options, gOptions_heightFieldID, -1);
123 env->SetObjectField(options, gOptions_mimeFieldID, 0);
Romain Guy95648b82017-04-13 18:43:42 -0700124 env->SetObjectField(options, gOptions_outConfigFieldID, 0);
125 env->SetObjectField(options, gOptions_outColorSpaceFieldID, 0);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800126 }
127
Matt Sarett1f979632015-10-27 10:33:20 -0400128 // Recycle a bitmap if possible.
sergeyvc1c54062016-10-19 18:47:26 -0700129 android::Bitmap* recycledBitmap = nullptr;
Matt Sarett1f979632015-10-27 10:33:20 -0400130 size_t recycledBytes = 0;
131 if (javaBitmap) {
Leon Scroggins III71fae622019-03-26 16:28:41 -0400132 recycledBitmap = &bitmap::toBitmap(inBitmapHandle);
sergeyvc69853c2016-10-07 14:14:09 -0700133 if (recycledBitmap->isImmutable()) {
Matt Sarett1f979632015-10-27 10:33:20 -0400134 ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
135 }
Leon Scroggins IIIca8aef62019-03-26 12:11:27 -0400136 recycledBytes = recycledBitmap->getAllocationByteCount();
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800137 }
138
Leon Scroggins III23ac0362020-05-04 15:38:58 -0400139 auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
Leon Scroggins III8d592f92018-03-12 15:44:03 -0400140 SkColorType decodeColorType = brd->computeOutputColorType(colorType);
Alec Mouri1efd0a52022-01-20 13:58:23 -0800141
142 if (isHardware) {
143 if (decodeColorType == kRGBA_F16_SkColorType &&
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500144 !uirenderer::HardwareBitmapUploader::hasFP16Support()) {
Alec Mouri1efd0a52022-01-20 13:58:23 -0800145 decodeColorType = kN32_SkColorType;
146 }
147 if (decodeColorType == kRGBA_1010102_SkColorType &&
148 !uirenderer::HardwareBitmapUploader::has1010102Support()) {
149 decodeColorType = kN32_SkColorType;
150 }
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500151 }
Leon Scroggins III8d592f92018-03-12 15:44:03 -0400152
Matt Sarett1f979632015-10-27 10:33:20 -0400153 // Set up the pixel allocator
Leon Scroggins III23ac0362020-05-04 15:38:58 -0400154 skia::BRDAllocator* allocator = nullptr;
Matt Sarett1f979632015-10-27 10:33:20 -0400155 RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes);
sergeyv45082182016-09-29 18:25:40 -0700156 HeapAllocator heapAlloc;
Matt Sarett1f979632015-10-27 10:33:20 -0400157 if (javaBitmap) {
158 allocator = &recycleAlloc;
159 // We are required to match the color type of the recycled bitmap.
Romain Guy95648b82017-04-13 18:43:42 -0700160 decodeColorType = recycledBitmap->info().colorType();
Matt Sarett1f979632015-10-27 10:33:20 -0400161 } else {
sergeyv45082182016-09-29 18:25:40 -0700162 allocator = &heapAlloc;
Matt Sarett1f979632015-10-27 10:33:20 -0400163 }
164
Leon Scroggins III8d592f92018-03-12 15:44:03 -0400165 sk_sp<SkColorSpace> decodeColorSpace = brd->computeOutputColorSpace(
166 decodeColorType, colorSpace);
167
Matt Sarett1f979632015-10-27 10:33:20 -0400168 // Decode the region.
169 SkIRect subset = SkIRect::MakeXYWH(inputX, inputY, inputWidth, inputHeight);
John Reckf29ed282015-04-07 07:32:03 -0700170 SkBitmap bitmap;
Romain Guy95648b82017-04-13 18:43:42 -0700171 if (!brd->decodeRegion(&bitmap, allocator, subset, sampleSize,
172 decodeColorType, requireUnpremul, decodeColorSpace)) {
Matt Sarett1f979632015-10-27 10:33:20 -0400173 return nullObjectReturn("Failed to decode region.");
Owen Linf970c2e2012-04-25 18:49:09 +0800174 }
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800175
Matt Sarett1f979632015-10-27 10:33:20 -0400176 // If the client provided options, indicate that the decode was successful.
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800177 if (NULL != options) {
John Reckf29ed282015-04-07 07:32:03 -0700178 env->SetIntField(options, gOptions_widthFieldID, bitmap.width());
179 env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
Romain Guy95648b82017-04-13 18:43:42 -0700180
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800181 env->SetObjectField(options, gOptions_mimeFieldID,
Leon Scroggins III407b5442019-11-22 17:10:20 -0500182 getMimeTypeAsJavaString(env, brd->getEncodedFormat()));
Matt Sarettd31512b2015-12-09 15:16:31 -0500183 if (env->ExceptionCheck()) {
184 return nullObjectReturn("OOM in encodedFormatToString()");
185 }
Romain Guy95648b82017-04-13 18:43:42 -0700186
187 jint configID = GraphicsJNI::colorTypeToLegacyBitmapConfig(decodeColorType);
188 if (isHardware) {
189 configID = GraphicsJNI::kHardware_LegacyBitmapConfig;
190 }
191 jobject config = env->CallStaticObjectMethod(gBitmapConfig_class,
192 gBitmapConfig_nativeToConfigMethodID, configID);
193 env->SetObjectField(options, gOptions_outConfigFieldID, config);
194
195 env->SetObjectField(options, gOptions_outColorSpaceFieldID,
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500196 GraphicsJNI::getColorSpace(env, decodeColorSpace.get(), decodeColorType));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800197 }
198
Matt Sarett1f979632015-10-27 10:33:20 -0400199 // If we may have reused a bitmap, we need to indicate that the pixels have changed.
200 if (javaBitmap) {
201 recycleAlloc.copyIfNecessary();
Romain Guy55455182017-04-15 21:41:22 -0700202 bitmap::reinitBitmap(env, javaBitmap, recycledBitmap->info(), !requireUnpremul);
Matt Sarett1f979632015-10-27 10:33:20 -0400203 return javaBitmap;
Owen Linf970c2e2012-04-25 18:49:09 +0800204 }
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800205
Chris Craik1abf5d62013-08-16 12:47:03 -0700206 int bitmapCreateFlags = 0;
Matt Sarett1f979632015-10-27 10:33:20 -0400207 if (!requireUnpremul) {
sergeyvc69853c2016-10-07 14:14:09 -0700208 bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
Matt Sarett1f979632015-10-27 10:33:20 -0400209 }
sergeyvda6c8ffc2016-11-22 18:28:54 -0800210 if (isHardware) {
211 sk_sp<Bitmap> hardwareBitmap = Bitmap::allocateHardwareBitmap(bitmap);
212 return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags);
213 }
sergeyvc69853c2016-10-07 14:14:09 -0700214 return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800215}
216
Ashok Bhatb091d472014-01-08 14:32:49 +0000217static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
Leon Scroggins III23ac0362020-05-04 15:38:58 -0400218 auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
Matt Sarett1f979632015-10-27 10:33:20 -0400219 return static_cast<jint>(brd->height());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800220}
221
Ashok Bhatb091d472014-01-08 14:32:49 +0000222static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) {
Leon Scroggins III23ac0362020-05-04 15:38:58 -0400223 auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
Matt Sarett1f979632015-10-27 10:33:20 -0400224 return static_cast<jint>(brd->width());
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800225}
226
Ashok Bhatb091d472014-01-08 14:32:49 +0000227static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) {
Leon Scroggins III23ac0362020-05-04 15:38:58 -0400228 auto* brd = reinterpret_cast<skia::BitmapRegionDecoder*>(brdHandle);
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800229 delete brd;
230}
231
232///////////////////////////////////////////////////////////////////////////////
233
Daniel Micay76f6a862015-09-19 17:31:01 -0400234static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800235 { "nativeDecodeRegion",
Leon Scroggins III71fae622019-03-26 16:28:41 -0400236 "(JIIIILandroid/graphics/BitmapFactory$Options;JJ)Landroid/graphics/Bitmap;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800237 (void*)nativeDecodeRegion},
238
Ashok Bhatb091d472014-01-08 14:32:49 +0000239 { "nativeGetHeight", "(J)I", (void*)nativeGetHeight},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800240
Ashok Bhatb091d472014-01-08 14:32:49 +0000241 { "nativeGetWidth", "(J)I", (void*)nativeGetWidth},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800242
Ashok Bhatb091d472014-01-08 14:32:49 +0000243 { "nativeClean", "(J)V", (void*)nativeClean},
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800244
245 { "nativeNewInstance",
Leon Scroggins III96a13882020-03-04 10:29:04 -0500246 "([BII)Landroid/graphics/BitmapRegionDecoder;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800247 (void*)nativeNewInstanceFromByteArray
248 },
249
250 { "nativeNewInstance",
Leon Scroggins III96a13882020-03-04 10:29:04 -0500251 "(Ljava/io/InputStream;[B)Landroid/graphics/BitmapRegionDecoder;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800252 (void*)nativeNewInstanceFromStream
253 },
254
255 { "nativeNewInstance",
Leon Scroggins III96a13882020-03-04 10:29:04 -0500256 "(Ljava/io/FileDescriptor;)Landroid/graphics/BitmapRegionDecoder;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800257 (void*)nativeNewInstanceFromFileDescriptor
258 },
259
260 { "nativeNewInstance",
Leon Scroggins III96a13882020-03-04 10:29:04 -0500261 "(J)Landroid/graphics/BitmapRegionDecoder;",
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800262 (void*)nativeNewInstanceFromAsset
263 },
264};
265
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800266int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
267{
Andreas Gampeed6b9df2014-11-20 22:02:20 -0800268 return android::RegisterMethodsOrDie(env, "android/graphics/BitmapRegionDecoder",
269 gBitmapRegionDecoderMethods, NELEM(gBitmapRegionDecoderMethods));
Wei-Ta Chen6b849e22010-09-07 17:32:18 +0800270}