blob: 90fd3d87cba7f2a256bc3a56bef2b28b82a5bb83 [file] [log] [blame]
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -04001/*
2 * Copyright (C) 2017 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
Leon Scroggins III671cce22018-01-14 16:52:17 -050017#include "ImageDecoder.h"
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040018
Leon Scroggins III2bcdf6f2020-04-21 14:08:32 -040019#include <FrontBufferedStream.h>
John Reck5bd537e2023-01-24 20:13:45 -050020#include <HardwareBitmapUploader.h>
Kevin Lubick08409e22023-02-14 14:29:25 +000021#include <SkAlphaType.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040022#include <SkAndroidCodec.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050023#include <SkBitmap.h>
Kevin Lubick08409e22023-02-14 14:29:25 +000024#include <SkCodec.h>
25#include <SkCodecAnimation.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050026#include <SkColorSpace.h>
Kevin Lubick08409e22023-02-14 14:29:25 +000027#include <SkColorType.h>
Xiao Huangfff1a292023-04-12 17:37:36 +000028#include <SkEncodedImageFormat.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050029#include <SkImageInfo.h>
30#include <SkRect.h>
Kevin Lubick08409e22023-02-14 14:29:25 +000031#include <SkSize.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040032#include <SkStream.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050033#include <SkString.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040034#include <androidfw/Asset.h>
Derek Sollenbergerc5882c42019-10-25 11:11:32 -040035#include <fcntl.h>
John Reck5bd537e2023-01-24 20:13:45 -050036#include <gui/TraceUtils.h>
37#include <hwui/Bitmap.h>
38#include <hwui/ImageDecoder.h>
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -050039#include <sys/stat.h>
Alec Mouri0ba21a72024-10-10 22:45:08 +000040#include <utils/StatsUtils.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040041
John Reck5bd537e2023-01-24 20:13:45 -050042#include "Bitmap.h"
43#include "BitmapFactory.h"
44#include "ByteBufferStreamAdaptor.h"
45#include "CreateJavaOutputStreamAdaptor.h"
46#include "Gainmap.h"
47#include "GraphicsJNI.h"
48#include "NinePatchPeeker.h"
49#include "Utils.h"
50
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040051using namespace android;
52
Xiao Huangfff1a292023-04-12 17:37:36 +000053jclass gImageDecoder_class;
54jmethodID gImageDecoder_isP010SupportedForHEVCMethodID;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050055static jclass gSize_class;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040056static jclass gDecodeException_class;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040057static jclass gCanvas_class;
58static jmethodID gImageDecoder_constructorMethodID;
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -050059static jmethodID gImageDecoder_postProcessMethodID;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050060static jmethodID gSize_constructorMethodID;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040061static jmethodID gDecodeException_constructorMethodID;
Leon Scroggins IIIedf26d62018-01-09 16:55:24 -050062static jmethodID gCallback_onPartialImageMethodID;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040063static jmethodID gCanvas_constructorMethodID;
64static jmethodID gCanvas_releaseMethodID;
65
Leon Scroggins III753a56f2019-12-11 11:02:15 -050066// These need to stay in sync with ImageDecoder.java's Allocator constants.
67enum Allocator {
68 kDefault_Allocator = 0,
69 kSoftware_Allocator = 1,
70 kSharedMemory_Allocator = 2,
71 kHardware_Allocator = 3,
72};
73
74// These need to stay in sync with ImageDecoder.java's Error constants.
75enum Error {
76 kSourceException = 1,
77 kSourceIncomplete = 2,
78 kSourceMalformedData = 3,
79};
80
81// These need to stay in sync with PixelFormat.java's Format constants.
82enum PixelFormat {
83 kUnknown = 0,
84 kTranslucent = -3,
85 kOpaque = -1,
86};
87
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040088// Clear and return any pending exception for handling other than throwing directly.
89static jthrowable get_and_clear_exception(JNIEnv* env) {
90 jthrowable jexception = env->ExceptionOccurred();
91 if (jexception) {
92 env->ExceptionClear();
93 }
94 return jexception;
95}
96
97// Throw a new ImageDecoder.DecodeException. Returns null for convenience.
Leon Scroggins III753a56f2019-12-11 11:02:15 -050098static jobject throw_exception(JNIEnv* env, Error error, const char* msg,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040099 jthrowable cause, jobject source) {
100 jstring jstr = nullptr;
101 if (msg) {
102 jstr = env->NewStringUTF(msg);
103 if (!jstr) {
104 // Out of memory.
105 return nullptr;
106 }
107 }
108 jthrowable exception = (jthrowable) env->NewObject(gDecodeException_class,
109 gDecodeException_constructorMethodID, error, jstr, cause, source);
110 // Only throw if not out of memory.
111 if (exception) {
112 env->Throw(exception);
113 }
114 return nullptr;
115}
116
Chong Zhangcba27922019-07-12 16:38:47 -0700117static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
118 jobject source, jboolean preferAnimation) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400119 if (!stream.get()) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500120 return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400121 nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400122 }
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500123 sk_sp<NinePatchPeeker> peeker(new NinePatchPeeker);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500124 SkCodec::Result result;
Chong Zhangcba27922019-07-12 16:38:47 -0700125 auto codec = SkCodec::MakeFromStream(
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500126 std::move(stream), &result, peeker.get(),
Chong Zhangcba27922019-07-12 16:38:47 -0700127 preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation
128 : SkCodec::SelectionPolicy::kPreferStillImage);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400129 if (jthrowable jexception = get_and_clear_exception(env)) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500130 return throw_exception(env, kSourceException, "", jexception, source);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400131 }
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500132 if (!codec) {
133 switch (result) {
134 case SkCodec::kIncompleteInput:
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500135 return throw_exception(env, kSourceIncomplete, "", nullptr, source);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500136 default:
137 SkString msg;
138 msg.printf("Failed to create image decoder with message '%s'",
139 SkCodec::ResultToString(result));
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500140 return throw_exception(env, kSourceMalformedData, msg.c_str(),
Leon Scroggins IIIcf7294f2018-03-22 09:21:29 -0400141 nullptr, source);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500142
Leon Scroggins III671cce22018-01-14 16:52:17 -0500143 }
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500144 }
145
Leon Scroggins III671cce22018-01-14 16:52:17 -0500146 const bool animated = codec->getFrameCount() > 1;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400147 if (jthrowable jexception = get_and_clear_exception(env)) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500148 return throw_exception(env, kSourceException, "", jexception, source);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400149 }
150
Leon Scroggins III139145b2020-12-17 15:43:54 -0500151 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec));
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500152 if (!androidCodec.get()) {
153 return throw_exception(env, kSourceMalformedData, "", nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400154 }
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400155
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500156 const bool isNinePatch = peeker->mPatch != nullptr;
Leon Scroggins III368a7a52020-11-20 12:23:27 -0500157 ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker),
158 SkCodec::kYes_ZeroInitialized);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400159 return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
Leon Scroggins III139145b2020-12-17 15:43:54 -0500160 reinterpret_cast<jlong>(decoder), decoder->width(), decoder->height(),
Leon Scroggins III7d940ba2018-04-04 16:19:33 -0400161 animated, isNinePatch);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400162}
163
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500164static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
Leon Scroggins IIIc3fda892020-09-10 14:57:11 -0400165 jobject fileDescriptor, jlong length, jboolean preferAnimation, jobject source) {
Michael Hoisiebbaf2ab2024-07-11 20:51:16 +0000166#ifdef _WIN32 // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
167 return throw_exception(env, kSourceException, "Not supported on Windows", nullptr, source);
Derek Sollenbergerc5882c42019-10-25 11:11:32 -0400168#else
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500169 int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
170
171 struct stat fdStat;
172 if (fstat(descriptor, &fdStat) == -1) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500173 return throw_exception(env, kSourceMalformedData,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400174 "broken file descriptor; fstat returned -1", nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500175 }
176
Nick Kralevich4b3a08c2019-01-28 10:39:10 -0800177 int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500178 FILE* file = fdopen(dupDescriptor, "r");
179 if (file == NULL) {
180 close(dupDescriptor);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500181 return throw_exception(env, kSourceMalformedData, "Could not open file",
Leon Scroggins IIIcf7294f2018-03-22 09:21:29 -0400182 nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500183 }
Leon Scroggins III0c699ad2018-05-07 16:20:13 -0400184
Leon Scroggins IIIc3fda892020-09-10 14:57:11 -0400185 std::unique_ptr<SkFILEStream> fileStream;
186 if (length == -1) {
187 // -1 corresponds to AssetFileDescriptor.UNKNOWN_LENGTH. Pass no length
188 // so SkFILEStream will figure out the size of the file on its own.
189 fileStream.reset(new SkFILEStream(file));
190 } else {
191 fileStream.reset(new SkFILEStream(file, length));
192 }
Chong Zhangcba27922019-07-12 16:38:47 -0700193 return native_create(env, std::move(fileStream), source, preferAnimation);
Derek Sollenbergerc5882c42019-10-25 11:11:32 -0400194#endif
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500195}
196
197static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
Chong Zhangcba27922019-07-12 16:38:47 -0700198 jobject is, jbyteArray storage, jboolean preferAnimation, jobject source) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500199 std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
200
201 if (!stream.get()) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500202 return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400203 nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500204 }
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400205
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500206 std::unique_ptr<SkStream> bufferedStream(
Leon Scroggins III2bcdf6f2020-04-21 14:08:32 -0400207 skia::FrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
Chong Zhangcba27922019-07-12 16:38:47 -0700208 return native_create(env, std::move(bufferedStream), source, preferAnimation);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500209}
210
Chong Zhangcba27922019-07-12 16:38:47 -0700211static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/,
212 jlong assetPtr, jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400213 Asset* asset = reinterpret_cast<Asset*>(assetPtr);
214 std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
Chong Zhangcba27922019-07-12 16:38:47 -0700215 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400216}
217
Chong Zhangcba27922019-07-12 16:38:47 -0700218static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/,
219 jobject jbyteBuffer, jint initialPosition, jint limit,
220 jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400221 std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
222 initialPosition, limit);
223 if (!stream) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500224 return throw_exception(env, kSourceMalformedData, "Failed to read ByteBuffer",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400225 nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400226 }
Chong Zhangcba27922019-07-12 16:38:47 -0700227 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400228}
229
Chong Zhangcba27922019-07-12 16:38:47 -0700230static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/,
231 jbyteArray byteArray, jint offset, jint length,
232 jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400233 std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
Chong Zhangcba27922019-07-12 16:38:47 -0700234 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400235}
236
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500237jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500238 jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
239 reinterpret_cast<jlong>(canvas.get()));
240 if (!jcanvas) {
241 doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500242 return kUnknown;
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500243 }
244
245 // jcanvas now owns canvas.
246 canvas.release();
247
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500248 return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID, jcanvas);
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500249}
250
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400251static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400252 jobject jdecoder, jboolean jpostProcess,
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500253 jint targetWidth, jint targetHeight, jobject jsubset,
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400254 jboolean requireMutable, jint allocator,
255 jboolean requireUnpremul, jboolean preferRamOverQuality,
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500256 jboolean asAlphaMask, jlong colorSpaceHandle,
257 jboolean extended) {
John Reck5bd537e2023-01-24 20:13:45 -0500258 ATRACE_CALL();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400259 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500260 if (!decoder->setTargetSize(targetWidth, targetHeight)) {
261 doThrowISE(env, "Could not scale to target size!");
262 return nullptr;
263 }
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500264 if (requireUnpremul && !decoder->setUnpremultipliedRequired(true)) {
Leon Scroggins IIIea978db2018-01-13 11:40:42 -0500265 doThrowISE(env, "Cannot scale unpremultiplied pixels!");
266 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400267 }
268
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400269 SkColorType colorType = kN32_SkColorType;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500270 if (asAlphaMask && decoder->gray()) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400271 // We have to trick Skia to decode this to a single channel.
272 colorType = kGray_8_SkColorType;
273 } else if (preferRamOverQuality) {
274 // FIXME: The post-process might add alpha, which would make a 565
275 // result incorrect. If we call the postProcess before now and record
276 // to a picture, we can know whether alpha was added, and if not, we
277 // can still use 565.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500278 if (decoder->opaque() && !jpostProcess) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400279 // If the final result will be hardware, decoding to 565 and then
280 // uploading to the gpu as 8888 will not save memory. This still
281 // may save us from using F16, but do not go down to 565.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500282 if (allocator != kHardware_Allocator &&
283 (allocator != kDefault_Allocator || requireMutable)) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400284 colorType = kRGB_565_SkColorType;
285 }
286 }
287 // Otherwise, stick with N32
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500288 } else if (extended) {
289 colorType = kRGBA_F16_SkColorType;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400290 } else {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500291 colorType = decoder->mCodec->computeOutputColorType(colorType);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400292 }
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500293
294 const bool isHardware = !requireMutable
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500295 && (allocator == kDefault_Allocator ||
296 allocator == kHardware_Allocator)
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500297 && colorType != kGray_8_SkColorType;
298
299 if (colorType == kRGBA_F16_SkColorType && isHardware &&
300 !uirenderer::HardwareBitmapUploader::hasFP16Support()) {
301 colorType = kN32_SkColorType;
302 }
303
Xiao Huangfff1a292023-04-12 17:37:36 +0000304 // b/276879147, fallback to RGBA_8888 when decoding HEIF and P010 is not supported.
305 if (colorType == kRGBA_1010102_SkColorType &&
306 decoder->mCodec->getEncodedFormat() == SkEncodedImageFormat::kHEIF &&
307 env->CallStaticBooleanMethod(gImageDecoder_class,
308 gImageDecoder_isP010SupportedForHEVCMethodID) == JNI_FALSE) {
309 colorType = kN32_SkColorType;
310 }
311
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500312 if (!decoder->setOutColorType(colorType)) {
313 doThrowISE(env, "Failed to set out color type!");
314 return nullptr;
315 }
316
317 {
318 sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
319 colorSpace = decoder->mCodec->computeOutputColorSpace(colorType, colorSpace);
320 decoder->setOutColorSpace(std::move(colorSpace));
321 }
322
323 if (jsubset) {
324 SkIRect subset;
325 GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
326 if (!decoder->setCropRect(&subset)) {
327 doThrowISE(env, "Invalid crop rect!");
328 return nullptr;
329 }
330 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400331
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500332 SkImageInfo bitmapInfo = decoder->getOutputInfo();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400333 if (asAlphaMask && colorType == kGray_8_SkColorType) {
334 bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
335 }
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500336
337 SkBitmap bm;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400338 if (!bm.setInfo(bitmapInfo)) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500339 doThrowIOE(env, "Failed to setInfo properly");
340 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400341 }
342
343 sk_sp<Bitmap> nativeBitmap;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500344 if (allocator == kSharedMemory_Allocator) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400345 nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
346 } else {
347 nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
348 }
349 if (!nativeBitmap) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500350 SkString msg;
351 msg.printf("OOM allocating Bitmap with dimensions %i x %i",
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500352 bitmapInfo.width(), bitmapInfo.height());
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500353 doThrowOOME(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400354 return nullptr;
355 }
356
John Reck5bd537e2023-01-24 20:13:45 -0500357 ATRACE_FORMAT("Decoding %dx%d bitmap", bitmapInfo.width(), bitmapInfo.height());
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500358 SkCodec::Result result = decoder->decode(bm.getPixels(), bm.rowBytes());
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400359 jthrowable jexception = get_and_clear_exception(env);
John Reck5bd537e2023-01-24 20:13:45 -0500360 int onPartialImageError = jexception ? kSourceException : 0; // No error.
361
362 // Only attempt to extract the gainmap if we're not post-processing, as we can't automatically
363 // mimic that to the gainmap and expect it to be meaningful. And also don't extract the gainmap
364 // if we're prioritizing RAM over quality, since the gainmap improves quality at the
365 // cost of RAM
366 if (result == SkCodec::kSuccess && !jpostProcess && !preferRamOverQuality) {
367 // The gainmap costs RAM to improve quality, so skip this if we're prioritizing RAM instead
Sally Qicaa2ef52023-03-07 15:13:16 -0800368 result = decoder->extractGainmap(nativeBitmap.get(),
369 allocator == kSharedMemory_Allocator ? true : false);
John Reck5bd537e2023-01-24 20:13:45 -0500370 jexception = get_and_clear_exception(env);
371 }
372
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400373 switch (result) {
374 case SkCodec::kSuccess:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500375 // Ignore the exception, since the decode was successful anyway.
376 jexception = nullptr;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500377 onPartialImageError = 0;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400378 break;
379 case SkCodec::kIncompleteInput:
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500380 if (!jexception) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500381 onPartialImageError = kSourceIncomplete;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400382 }
383 break;
384 case SkCodec::kErrorInInput:
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500385 if (!jexception) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500386 onPartialImageError = kSourceMalformedData;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400387 }
388 break;
389 default:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500390 SkString msg;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500391 msg.printf("getPixels failed with error %s", SkCodec::ResultToString(result));
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500392 doThrowIOE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400393 return nullptr;
394 }
395
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400396 if (onPartialImageError) {
397 env->CallVoidMethod(jdecoder, gCallback_onPartialImageMethodID, onPartialImageError,
398 jexception);
Leon Scroggins IIIedf26d62018-01-09 16:55:24 -0500399 if (env->ExceptionCheck()) {
400 return nullptr;
401 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400402 }
403
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400404 jbyteArray ninePatchChunk = nullptr;
405 jobject ninePatchInsets = nullptr;
406
407 // Ignore ninepatch when post-processing.
408 if (!jpostProcess) {
409 // FIXME: Share more code with BitmapFactory.cpp.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500410 auto* peeker = reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get());
411 if (peeker->mPatch != nullptr) {
412 size_t ninePatchArraySize = peeker->mPatch->serializedSize();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400413 ninePatchChunk = env->NewByteArray(ninePatchArraySize);
414 if (ninePatchChunk == nullptr) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500415 doThrowOOME(env, "Failed to allocate nine patch chunk.");
416 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400417 }
418
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500419 env->SetByteArrayRegion(ninePatchChunk, 0, peeker->mPatchSize,
420 reinterpret_cast<jbyte*>(peeker->mPatch));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400421 }
422
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500423 if (peeker->mHasInsets) {
424 ninePatchInsets = peeker->createNinePatchInsets(env, 1.0f);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400425 if (ninePatchInsets == nullptr) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500426 doThrowOOME(env, "Failed to allocate nine patch insets.");
427 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400428 }
429 }
430 }
431
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400432 if (jpostProcess) {
433 std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400434
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400435 jint pixelFormat = postProcessAndRelease(env, jdecoder, std::move(canvas));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400436 if (env->ExceptionCheck()) {
437 return nullptr;
438 }
439
440 SkAlphaType newAlphaType = bm.alphaType();
441 switch (pixelFormat) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500442 case kUnknown:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400443 break;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500444 case kTranslucent:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400445 newAlphaType = kPremul_SkAlphaType;
446 break;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500447 case kOpaque:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400448 newAlphaType = kOpaque_SkAlphaType;
449 break;
450 default:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500451 SkString msg;
452 msg.printf("invalid return from postProcess: %i", pixelFormat);
453 doThrowIAE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400454 return nullptr;
455 }
456
457 if (newAlphaType != bm.alphaType()) {
458 if (!bm.setAlphaType(newAlphaType)) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500459 SkString msg;
460 msg.printf("incompatible return from postProcess: %i", pixelFormat);
461 doThrowIAE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400462 return nullptr;
463 }
464 nativeBitmap->setAlphaType(newAlphaType);
465 }
466 }
467
468 int bitmapCreateFlags = 0x0;
469 if (!requireUnpremul) {
470 // Even if the image is opaque, setting this flag means that
471 // if alpha is added (e.g. by PostProcess), it will be marked as
472 // premultiplied.
473 bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Premultiplied;
474 }
475
476 if (requireMutable) {
477 bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Mutable;
478 } else {
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500479 if (isHardware) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400480 sk_sp<Bitmap> hwBitmap = Bitmap::allocateHardwareBitmap(bm);
481 if (hwBitmap) {
482 hwBitmap->setImmutable();
John Reck5bd537e2023-01-24 20:13:45 -0500483 if (nativeBitmap->hasGainmap()) {
Sally Qi587fb572023-03-03 15:50:06 -0800484 auto gm = uirenderer::Gainmap::allocateHardwareGainmap(nativeBitmap->gainmap());
485 if (gm) {
486 hwBitmap->setGainmap(std::move(gm));
487 }
John Reck5bd537e2023-01-24 20:13:45 -0500488 }
Alec Mouri0ba21a72024-10-10 22:45:08 +0000489 uirenderer::logBitmapDecode(*hwBitmap);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400490 return bitmap::createBitmap(env, hwBitmap.release(), bitmapCreateFlags,
491 ninePatchChunk, ninePatchInsets);
492 }
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500493 if (allocator == kHardware_Allocator) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500494 doThrowOOME(env, "failed to allocate hardware Bitmap!");
495 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400496 }
497 // If we failed to create a hardware bitmap, go ahead and create a
498 // software one.
499 }
500
501 nativeBitmap->setImmutable();
502 }
Alec Mouri0ba21a72024-10-10 22:45:08 +0000503
504 uirenderer::logBitmapDecode(*nativeBitmap);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400505 return bitmap::createBitmap(env, nativeBitmap.release(), bitmapCreateFlags, ninePatchChunk,
506 ninePatchInsets);
507}
508
509static jobject ImageDecoder_nGetSampledSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
510 jint sampleSize) {
511 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III5a5c2ce2021-01-15 14:09:13 -0500512 SkISize size = decoder->getSampledDimensions(sampleSize);
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500513 return env->NewObject(gSize_class, gSize_constructorMethodID, size.width(), size.height());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400514}
515
516static void ImageDecoder_nGetPadding(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
517 jobject outPadding) {
518 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500519 reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get())->getPadding(env, outPadding);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400520}
521
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500522static void ImageDecoder_nClose(JNIEnv* /*env*/, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400523 delete reinterpret_cast<ImageDecoder*>(nativePtr);
524}
525
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500526static jstring ImageDecoder_nGetMimeType(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
527 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III407b5442019-11-22 17:10:20 -0500528 return getMimeTypeAsJavaString(env, decoder->mCodec->getEncodedFormat());
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500529}
530
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400531static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
532 auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500533 auto colorType = codec->computeOutputColorType(kN32_SkColorType);
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400534 sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500535 return GraphicsJNI::getColorSpace(env, colorSpace.get(), colorType);
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400536}
537
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400538static const JNINativeMethod gImageDecoderMethods[] = {
Chong Zhangcba27922019-07-12 16:38:47 -0700539 { "nCreate", "(JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset },
540 { "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
541 { "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
542 { "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
Leon Scroggins IIIc3fda892020-09-10 14:57:11 -0400543 { "nCreate", "(Ljava/io/FileDescriptor;JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500544 { "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400545 (void*) ImageDecoder_nDecodeBitmap },
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500546 { "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400547 { "nGetPadding", "(JLandroid/graphics/Rect;)V", (void*) ImageDecoder_nGetPadding },
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500548 { "nClose", "(J)V", (void*) ImageDecoder_nClose},
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500549 { "nGetMimeType", "(J)Ljava/lang/String;", (void*) ImageDecoder_nGetMimeType },
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400550 { "nGetColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*) ImageDecoder_nGetColorSpace },
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400551};
552
553int register_android_graphics_ImageDecoder(JNIEnv* env) {
554 gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
Leon Scroggins III7d940ba2018-04-04 16:19:33 -0400555 gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500556 gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
Xiao Huangfff1a292023-04-12 17:37:36 +0000557 gImageDecoder_isP010SupportedForHEVCMethodID =
558 GetStaticMethodIDOrDie(env, gImageDecoder_class, "isP010SupportedForHEVC", "()Z");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400559
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500560 gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
561 gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400562
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400563 gDecodeException_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$DecodeException"));
564 gDecodeException_constructorMethodID = GetMethodIDOrDie(env, gDecodeException_class, "<init>", "(ILjava/lang/String;Ljava/lang/Throwable;Landroid/graphics/ImageDecoder$Source;)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400565
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400566 gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(ILjava/lang/Throwable;)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400567
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400568 gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
569 gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
570 gCanvas_releaseMethodID = GetMethodIDOrDie(env, gCanvas_class, "release", "()V");
571
572 return android::RegisterMethodsOrDie(env, "android/graphics/ImageDecoder", gImageDecoderMethods,
573 NELEM(gImageDecoderMethods));
574}