blob: da91d46b0738faf92948eb0c75c517afdc5fe3f9 [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
17#include "Bitmap.h"
Leon Scroggins III1fad09d2017-12-22 12:54:20 -050018#include "BitmapFactory.h"
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040019#include "ByteBufferStreamAdaptor.h"
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -050020#include "CreateJavaOutputStreamAdaptor.h"
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040021#include "GraphicsJNI.h"
Leon Scroggins III671cce22018-01-14 16:52:17 -050022#include "ImageDecoder.h"
Leon Scroggins III753a56f2019-12-11 11:02:15 -050023#include "NinePatchPeeker.h"
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040024#include "Utils.h"
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040025
26#include <hwui/Bitmap.h>
Leon Scroggins III753a56f2019-12-11 11:02:15 -050027#include <hwui/ImageDecoder.h>
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -050028#include <HardwareBitmapUploader.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040029
Leon Scroggins III2bcdf6f2020-04-21 14:08:32 -040030#include <FrontBufferedStream.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040031#include <SkAndroidCodec.h>
32#include <SkEncodedImageFormat.h>
33#include <SkStream.h>
34
35#include <androidfw/Asset.h>
Derek Sollenbergerc5882c42019-10-25 11:11:32 -040036#include <fcntl.h>
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -050037#include <sys/stat.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040038
39using namespace android;
40
41static jclass gImageDecoder_class;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050042static jclass gSize_class;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040043static jclass gDecodeException_class;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040044static jclass gCanvas_class;
45static jmethodID gImageDecoder_constructorMethodID;
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -050046static jmethodID gImageDecoder_postProcessMethodID;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050047static jmethodID gSize_constructorMethodID;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040048static jmethodID gDecodeException_constructorMethodID;
Leon Scroggins IIIedf26d62018-01-09 16:55:24 -050049static jmethodID gCallback_onPartialImageMethodID;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040050static jmethodID gCanvas_constructorMethodID;
51static jmethodID gCanvas_releaseMethodID;
52
Leon Scroggins III753a56f2019-12-11 11:02:15 -050053// These need to stay in sync with ImageDecoder.java's Allocator constants.
54enum Allocator {
55 kDefault_Allocator = 0,
56 kSoftware_Allocator = 1,
57 kSharedMemory_Allocator = 2,
58 kHardware_Allocator = 3,
59};
60
61// These need to stay in sync with ImageDecoder.java's Error constants.
62enum Error {
63 kSourceException = 1,
64 kSourceIncomplete = 2,
65 kSourceMalformedData = 3,
66};
67
68// These need to stay in sync with PixelFormat.java's Format constants.
69enum PixelFormat {
70 kUnknown = 0,
71 kTranslucent = -3,
72 kOpaque = -1,
73};
74
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040075// Clear and return any pending exception for handling other than throwing directly.
76static jthrowable get_and_clear_exception(JNIEnv* env) {
77 jthrowable jexception = env->ExceptionOccurred();
78 if (jexception) {
79 env->ExceptionClear();
80 }
81 return jexception;
82}
83
84// Throw a new ImageDecoder.DecodeException. Returns null for convenience.
Leon Scroggins III753a56f2019-12-11 11:02:15 -050085static jobject throw_exception(JNIEnv* env, Error error, const char* msg,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040086 jthrowable cause, jobject source) {
87 jstring jstr = nullptr;
88 if (msg) {
89 jstr = env->NewStringUTF(msg);
90 if (!jstr) {
91 // Out of memory.
92 return nullptr;
93 }
94 }
95 jthrowable exception = (jthrowable) env->NewObject(gDecodeException_class,
96 gDecodeException_constructorMethodID, error, jstr, cause, source);
97 // Only throw if not out of memory.
98 if (exception) {
99 env->Throw(exception);
100 }
101 return nullptr;
102}
103
Chong Zhangcba27922019-07-12 16:38:47 -0700104static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
105 jobject source, jboolean preferAnimation) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400106 if (!stream.get()) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500107 return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400108 nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400109 }
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500110 sk_sp<NinePatchPeeker> peeker(new NinePatchPeeker);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500111 SkCodec::Result result;
Chong Zhangcba27922019-07-12 16:38:47 -0700112 auto codec = SkCodec::MakeFromStream(
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500113 std::move(stream), &result, peeker.get(),
Chong Zhangcba27922019-07-12 16:38:47 -0700114 preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation
115 : SkCodec::SelectionPolicy::kPreferStillImage);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400116 if (jthrowable jexception = get_and_clear_exception(env)) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500117 return throw_exception(env, kSourceException, "", jexception, source);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400118 }
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500119 if (!codec) {
120 switch (result) {
121 case SkCodec::kIncompleteInput:
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500122 return throw_exception(env, kSourceIncomplete, "", nullptr, source);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500123 default:
124 SkString msg;
125 msg.printf("Failed to create image decoder with message '%s'",
126 SkCodec::ResultToString(result));
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500127 return throw_exception(env, kSourceMalformedData, msg.c_str(),
Leon Scroggins IIIcf7294f2018-03-22 09:21:29 -0400128 nullptr, source);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500129
Leon Scroggins III671cce22018-01-14 16:52:17 -0500130 }
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500131 }
132
Leon Scroggins III671cce22018-01-14 16:52:17 -0500133 const bool animated = codec->getFrameCount() > 1;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400134 if (jthrowable jexception = get_and_clear_exception(env)) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500135 return throw_exception(env, kSourceException, "", jexception, source);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400136 }
137
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500138 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
Leon Scroggins IIIac1928b2018-01-17 11:34:43 -0500139 SkAndroidCodec::ExifOrientationBehavior::kRespect);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500140 if (!androidCodec.get()) {
141 return throw_exception(env, kSourceMalformedData, "", nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400142 }
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400143
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500144 const auto& info = androidCodec->getInfo();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400145 const int width = info.width();
146 const int height = info.height();
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500147 const bool isNinePatch = peeker->mPatch != nullptr;
148 ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400149 return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500150 reinterpret_cast<jlong>(decoder), width, height,
Leon Scroggins III7d940ba2018-04-04 16:19:33 -0400151 animated, isNinePatch);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400152}
153
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500154static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
Leon Scroggins IIIc3fda892020-09-10 14:57:11 -0400155 jobject fileDescriptor, jlong length, jboolean preferAnimation, jobject source) {
Derek Sollenbergerc5882c42019-10-25 11:11:32 -0400156#ifndef __ANDROID__ // LayoutLib for Windows does not support F_DUPFD_CLOEXEC
157 return throw_exception(env, kSourceException, "Only supported on Android", nullptr, source);
158#else
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500159 int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
160
161 struct stat fdStat;
162 if (fstat(descriptor, &fdStat) == -1) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500163 return throw_exception(env, kSourceMalformedData,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400164 "broken file descriptor; fstat returned -1", nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500165 }
166
Nick Kralevich4b3a08c2019-01-28 10:39:10 -0800167 int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500168 FILE* file = fdopen(dupDescriptor, "r");
169 if (file == NULL) {
170 close(dupDescriptor);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500171 return throw_exception(env, kSourceMalformedData, "Could not open file",
Leon Scroggins IIIcf7294f2018-03-22 09:21:29 -0400172 nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500173 }
Leon Scroggins III0c699ad2018-05-07 16:20:13 -0400174
Leon Scroggins IIIc3fda892020-09-10 14:57:11 -0400175 std::unique_ptr<SkFILEStream> fileStream;
176 if (length == -1) {
177 // -1 corresponds to AssetFileDescriptor.UNKNOWN_LENGTH. Pass no length
178 // so SkFILEStream will figure out the size of the file on its own.
179 fileStream.reset(new SkFILEStream(file));
180 } else {
181 fileStream.reset(new SkFILEStream(file, length));
182 }
Chong Zhangcba27922019-07-12 16:38:47 -0700183 return native_create(env, std::move(fileStream), source, preferAnimation);
Derek Sollenbergerc5882c42019-10-25 11:11:32 -0400184#endif
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500185}
186
187static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
Chong Zhangcba27922019-07-12 16:38:47 -0700188 jobject is, jbyteArray storage, jboolean preferAnimation, jobject source) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500189 std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
190
191 if (!stream.get()) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500192 return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400193 nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500194 }
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400195
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500196 std::unique_ptr<SkStream> bufferedStream(
Leon Scroggins III2bcdf6f2020-04-21 14:08:32 -0400197 skia::FrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
Chong Zhangcba27922019-07-12 16:38:47 -0700198 return native_create(env, std::move(bufferedStream), source, preferAnimation);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500199}
200
Chong Zhangcba27922019-07-12 16:38:47 -0700201static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/,
202 jlong assetPtr, jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400203 Asset* asset = reinterpret_cast<Asset*>(assetPtr);
204 std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
Chong Zhangcba27922019-07-12 16:38:47 -0700205 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400206}
207
Chong Zhangcba27922019-07-12 16:38:47 -0700208static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/,
209 jobject jbyteBuffer, jint initialPosition, jint limit,
210 jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400211 std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
212 initialPosition, limit);
213 if (!stream) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500214 return throw_exception(env, kSourceMalformedData, "Failed to read ByteBuffer",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400215 nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400216 }
Chong Zhangcba27922019-07-12 16:38:47 -0700217 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400218}
219
Chong Zhangcba27922019-07-12 16:38:47 -0700220static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/,
221 jbyteArray byteArray, jint offset, jint length,
222 jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400223 std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
Chong Zhangcba27922019-07-12 16:38:47 -0700224 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400225}
226
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500227jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500228 jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
229 reinterpret_cast<jlong>(canvas.get()));
230 if (!jcanvas) {
231 doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500232 return kUnknown;
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500233 }
234
235 // jcanvas now owns canvas.
236 canvas.release();
237
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500238 return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID, jcanvas);
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500239}
240
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400241static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400242 jobject jdecoder, jboolean jpostProcess,
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500243 jint targetWidth, jint targetHeight, jobject jsubset,
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400244 jboolean requireMutable, jint allocator,
245 jboolean requireUnpremul, jboolean preferRamOverQuality,
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500246 jboolean asAlphaMask, jlong colorSpaceHandle,
247 jboolean extended) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400248 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500249 if (!decoder->setTargetSize(targetWidth, targetHeight)) {
250 doThrowISE(env, "Could not scale to target size!");
251 return nullptr;
252 }
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500253 if (requireUnpremul && !decoder->setUnpremultipliedRequired(true)) {
Leon Scroggins IIIea978db2018-01-13 11:40:42 -0500254 doThrowISE(env, "Cannot scale unpremultiplied pixels!");
255 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400256 }
257
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400258 SkColorType colorType = kN32_SkColorType;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500259 if (asAlphaMask && decoder->gray()) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400260 // We have to trick Skia to decode this to a single channel.
261 colorType = kGray_8_SkColorType;
262 } else if (preferRamOverQuality) {
263 // FIXME: The post-process might add alpha, which would make a 565
264 // result incorrect. If we call the postProcess before now and record
265 // to a picture, we can know whether alpha was added, and if not, we
266 // can still use 565.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500267 if (decoder->opaque() && !jpostProcess) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400268 // If the final result will be hardware, decoding to 565 and then
269 // uploading to the gpu as 8888 will not save memory. This still
270 // may save us from using F16, but do not go down to 565.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500271 if (allocator != kHardware_Allocator &&
272 (allocator != kDefault_Allocator || requireMutable)) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400273 colorType = kRGB_565_SkColorType;
274 }
275 }
276 // Otherwise, stick with N32
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500277 } else if (extended) {
278 colorType = kRGBA_F16_SkColorType;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400279 } else {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500280 colorType = decoder->mCodec->computeOutputColorType(colorType);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400281 }
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500282
283 const bool isHardware = !requireMutable
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500284 && (allocator == kDefault_Allocator ||
285 allocator == kHardware_Allocator)
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500286 && colorType != kGray_8_SkColorType;
287
288 if (colorType == kRGBA_F16_SkColorType && isHardware &&
289 !uirenderer::HardwareBitmapUploader::hasFP16Support()) {
290 colorType = kN32_SkColorType;
291 }
292
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500293 if (!decoder->setOutColorType(colorType)) {
294 doThrowISE(env, "Failed to set out color type!");
295 return nullptr;
296 }
297
298 {
299 sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
300 colorSpace = decoder->mCodec->computeOutputColorSpace(colorType, colorSpace);
301 decoder->setOutColorSpace(std::move(colorSpace));
302 }
303
304 if (jsubset) {
305 SkIRect subset;
306 GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
307 if (!decoder->setCropRect(&subset)) {
308 doThrowISE(env, "Invalid crop rect!");
309 return nullptr;
310 }
311 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400312
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500313 SkImageInfo bitmapInfo = decoder->getOutputInfo();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400314 if (asAlphaMask && colorType == kGray_8_SkColorType) {
315 bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
316 }
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500317
318 SkBitmap bm;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400319 if (!bm.setInfo(bitmapInfo)) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500320 doThrowIOE(env, "Failed to setInfo properly");
321 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400322 }
323
324 sk_sp<Bitmap> nativeBitmap;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500325 if (allocator == kSharedMemory_Allocator) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400326 nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
327 } else {
328 nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
329 }
330 if (!nativeBitmap) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500331 SkString msg;
332 msg.printf("OOM allocating Bitmap with dimensions %i x %i",
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500333 bitmapInfo.width(), bitmapInfo.height());
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500334 doThrowOOME(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400335 return nullptr;
336 }
337
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500338 SkCodec::Result result = decoder->decode(bm.getPixels(), bm.rowBytes());
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400339 jthrowable jexception = get_and_clear_exception(env);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500340 int onPartialImageError = jexception ? kSourceException
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500341 : 0; // No error.
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400342 switch (result) {
343 case SkCodec::kSuccess:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500344 // Ignore the exception, since the decode was successful anyway.
345 jexception = nullptr;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500346 onPartialImageError = 0;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400347 break;
348 case SkCodec::kIncompleteInput:
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500349 if (!jexception) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500350 onPartialImageError = kSourceIncomplete;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400351 }
352 break;
353 case SkCodec::kErrorInInput:
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500354 if (!jexception) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500355 onPartialImageError = kSourceMalformedData;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400356 }
357 break;
358 default:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500359 SkString msg;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500360 msg.printf("getPixels failed with error %s", SkCodec::ResultToString(result));
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500361 doThrowIOE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400362 return nullptr;
363 }
364
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400365 if (onPartialImageError) {
366 env->CallVoidMethod(jdecoder, gCallback_onPartialImageMethodID, onPartialImageError,
367 jexception);
Leon Scroggins IIIedf26d62018-01-09 16:55:24 -0500368 if (env->ExceptionCheck()) {
369 return nullptr;
370 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400371 }
372
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400373 jbyteArray ninePatchChunk = nullptr;
374 jobject ninePatchInsets = nullptr;
375
376 // Ignore ninepatch when post-processing.
377 if (!jpostProcess) {
378 // FIXME: Share more code with BitmapFactory.cpp.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500379 auto* peeker = reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get());
380 if (peeker->mPatch != nullptr) {
381 size_t ninePatchArraySize = peeker->mPatch->serializedSize();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400382 ninePatchChunk = env->NewByteArray(ninePatchArraySize);
383 if (ninePatchChunk == nullptr) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500384 doThrowOOME(env, "Failed to allocate nine patch chunk.");
385 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400386 }
387
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500388 env->SetByteArrayRegion(ninePatchChunk, 0, peeker->mPatchSize,
389 reinterpret_cast<jbyte*>(peeker->mPatch));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400390 }
391
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500392 if (peeker->mHasInsets) {
393 ninePatchInsets = peeker->createNinePatchInsets(env, 1.0f);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400394 if (ninePatchInsets == nullptr) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500395 doThrowOOME(env, "Failed to allocate nine patch insets.");
396 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400397 }
398 }
399 }
400
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400401 if (jpostProcess) {
402 std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400403
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400404 jint pixelFormat = postProcessAndRelease(env, jdecoder, std::move(canvas));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400405 if (env->ExceptionCheck()) {
406 return nullptr;
407 }
408
409 SkAlphaType newAlphaType = bm.alphaType();
410 switch (pixelFormat) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500411 case kUnknown:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400412 break;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500413 case kTranslucent:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400414 newAlphaType = kPremul_SkAlphaType;
415 break;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500416 case kOpaque:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400417 newAlphaType = kOpaque_SkAlphaType;
418 break;
419 default:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500420 SkString msg;
421 msg.printf("invalid return from postProcess: %i", pixelFormat);
422 doThrowIAE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400423 return nullptr;
424 }
425
426 if (newAlphaType != bm.alphaType()) {
427 if (!bm.setAlphaType(newAlphaType)) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500428 SkString msg;
429 msg.printf("incompatible return from postProcess: %i", pixelFormat);
430 doThrowIAE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400431 return nullptr;
432 }
433 nativeBitmap->setAlphaType(newAlphaType);
434 }
435 }
436
437 int bitmapCreateFlags = 0x0;
438 if (!requireUnpremul) {
439 // Even if the image is opaque, setting this flag means that
440 // if alpha is added (e.g. by PostProcess), it will be marked as
441 // premultiplied.
442 bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Premultiplied;
443 }
444
445 if (requireMutable) {
446 bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Mutable;
447 } else {
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500448 if (isHardware) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400449 sk_sp<Bitmap> hwBitmap = Bitmap::allocateHardwareBitmap(bm);
450 if (hwBitmap) {
451 hwBitmap->setImmutable();
452 return bitmap::createBitmap(env, hwBitmap.release(), bitmapCreateFlags,
453 ninePatchChunk, ninePatchInsets);
454 }
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500455 if (allocator == kHardware_Allocator) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500456 doThrowOOME(env, "failed to allocate hardware Bitmap!");
457 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400458 }
459 // If we failed to create a hardware bitmap, go ahead and create a
460 // software one.
461 }
462
463 nativeBitmap->setImmutable();
464 }
465 return bitmap::createBitmap(env, nativeBitmap.release(), bitmapCreateFlags, ninePatchChunk,
466 ninePatchInsets);
467}
468
469static jobject ImageDecoder_nGetSampledSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
470 jint sampleSize) {
471 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
472 SkISize size = decoder->mCodec->getSampledDimensions(sampleSize);
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500473 return env->NewObject(gSize_class, gSize_constructorMethodID, size.width(), size.height());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400474}
475
476static void ImageDecoder_nGetPadding(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
477 jobject outPadding) {
478 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500479 reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get())->getPadding(env, outPadding);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400480}
481
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500482static void ImageDecoder_nClose(JNIEnv* /*env*/, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400483 delete reinterpret_cast<ImageDecoder*>(nativePtr);
484}
485
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500486static jstring ImageDecoder_nGetMimeType(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
487 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III407b5442019-11-22 17:10:20 -0500488 return getMimeTypeAsJavaString(env, decoder->mCodec->getEncodedFormat());
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500489}
490
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400491static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
492 auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500493 auto colorType = codec->computeOutputColorType(kN32_SkColorType);
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400494 sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500495 return GraphicsJNI::getColorSpace(env, colorSpace.get(), colorType);
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400496}
497
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400498static const JNINativeMethod gImageDecoderMethods[] = {
Chong Zhangcba27922019-07-12 16:38:47 -0700499 { "nCreate", "(JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset },
500 { "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
501 { "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
502 { "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
Leon Scroggins IIIc3fda892020-09-10 14:57:11 -0400503 { "nCreate", "(Ljava/io/FileDescriptor;JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500504 { "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400505 (void*) ImageDecoder_nDecodeBitmap },
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500506 { "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400507 { "nGetPadding", "(JLandroid/graphics/Rect;)V", (void*) ImageDecoder_nGetPadding },
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500508 { "nClose", "(J)V", (void*) ImageDecoder_nClose},
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500509 { "nGetMimeType", "(J)Ljava/lang/String;", (void*) ImageDecoder_nGetMimeType },
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400510 { "nGetColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*) ImageDecoder_nGetColorSpace },
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400511};
512
513int register_android_graphics_ImageDecoder(JNIEnv* env) {
514 gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
Leon Scroggins III7d940ba2018-04-04 16:19:33 -0400515 gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500516 gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400517
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500518 gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
519 gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400520
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400521 gDecodeException_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$DecodeException"));
522 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 -0400523
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400524 gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(ILjava/lang/Throwable;)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400525
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400526 gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
527 gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
528 gCanvas_releaseMethodID = GetMethodIDOrDie(env, gCanvas_class, "release", "()V");
529
530 return android::RegisterMethodsOrDie(env, "android/graphics/ImageDecoder", gImageDecoderMethods,
531 NELEM(gImageDecoderMethods));
532}