blob: e17e057d75c70f297269228eba494856efe98ec9 [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"
25#include "core_jni_helpers.h"
26
27#include <hwui/Bitmap.h>
Leon Scroggins III753a56f2019-12-11 11:02:15 -050028#include <hwui/ImageDecoder.h>
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -050029#include <HardwareBitmapUploader.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040030
31#include <SkAndroidCodec.h>
32#include <SkEncodedImageFormat.h>
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -050033#include <SkFrontBufferedStream.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040034#include <SkStream.h>
35
36#include <androidfw/Asset.h>
37#include <jni.h>
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -050038#include <sys/stat.h>
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040039
40using namespace android;
41
42static jclass gImageDecoder_class;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050043static jclass gSize_class;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040044static jclass gDecodeException_class;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040045static jclass gCanvas_class;
46static jmethodID gImageDecoder_constructorMethodID;
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -050047static jmethodID gImageDecoder_postProcessMethodID;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -050048static jmethodID gSize_constructorMethodID;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040049static jmethodID gDecodeException_constructorMethodID;
Leon Scroggins IIIedf26d62018-01-09 16:55:24 -050050static jmethodID gCallback_onPartialImageMethodID;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -040051static jmethodID gCanvas_constructorMethodID;
52static jmethodID gCanvas_releaseMethodID;
53
Leon Scroggins III753a56f2019-12-11 11:02:15 -050054// These need to stay in sync with ImageDecoder.java's Allocator constants.
55enum Allocator {
56 kDefault_Allocator = 0,
57 kSoftware_Allocator = 1,
58 kSharedMemory_Allocator = 2,
59 kHardware_Allocator = 3,
60};
61
62// These need to stay in sync with ImageDecoder.java's Error constants.
63enum Error {
64 kSourceException = 1,
65 kSourceIncomplete = 2,
66 kSourceMalformedData = 3,
67};
68
69// These need to stay in sync with PixelFormat.java's Format constants.
70enum PixelFormat {
71 kUnknown = 0,
72 kTranslucent = -3,
73 kOpaque = -1,
74};
75
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040076// Clear and return any pending exception for handling other than throwing directly.
77static jthrowable get_and_clear_exception(JNIEnv* env) {
78 jthrowable jexception = env->ExceptionOccurred();
79 if (jexception) {
80 env->ExceptionClear();
81 }
82 return jexception;
83}
84
85// Throw a new ImageDecoder.DecodeException. Returns null for convenience.
Leon Scroggins III753a56f2019-12-11 11:02:15 -050086static jobject throw_exception(JNIEnv* env, Error error, const char* msg,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -040087 jthrowable cause, jobject source) {
88 jstring jstr = nullptr;
89 if (msg) {
90 jstr = env->NewStringUTF(msg);
91 if (!jstr) {
92 // Out of memory.
93 return nullptr;
94 }
95 }
96 jthrowable exception = (jthrowable) env->NewObject(gDecodeException_class,
97 gDecodeException_constructorMethodID, error, jstr, cause, source);
98 // Only throw if not out of memory.
99 if (exception) {
100 env->Throw(exception);
101 }
102 return nullptr;
103}
104
Chong Zhangcba27922019-07-12 16:38:47 -0700105static jobject native_create(JNIEnv* env, std::unique_ptr<SkStream> stream,
106 jobject source, jboolean preferAnimation) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400107 if (!stream.get()) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500108 return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400109 nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400110 }
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500111 sk_sp<NinePatchPeeker> peeker(new NinePatchPeeker);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500112 SkCodec::Result result;
Chong Zhangcba27922019-07-12 16:38:47 -0700113 auto codec = SkCodec::MakeFromStream(
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500114 std::move(stream), &result, peeker.get(),
Chong Zhangcba27922019-07-12 16:38:47 -0700115 preferAnimation ? SkCodec::SelectionPolicy::kPreferAnimation
116 : SkCodec::SelectionPolicy::kPreferStillImage);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400117 if (jthrowable jexception = get_and_clear_exception(env)) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500118 return throw_exception(env, kSourceException, "", jexception, source);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400119 }
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500120 if (!codec) {
121 switch (result) {
122 case SkCodec::kIncompleteInput:
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500123 return throw_exception(env, kSourceIncomplete, "", nullptr, source);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500124 default:
125 SkString msg;
126 msg.printf("Failed to create image decoder with message '%s'",
127 SkCodec::ResultToString(result));
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500128 return throw_exception(env, kSourceMalformedData, msg.c_str(),
Leon Scroggins IIIcf7294f2018-03-22 09:21:29 -0400129 nullptr, source);
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500130
Leon Scroggins III671cce22018-01-14 16:52:17 -0500131 }
Leon Scroggins IIIc782ad82018-01-14 10:50:45 -0500132 }
133
Leon Scroggins III671cce22018-01-14 16:52:17 -0500134 const bool animated = codec->getFrameCount() > 1;
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400135 if (jthrowable jexception = get_and_clear_exception(env)) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500136 return throw_exception(env, kSourceException, "", jexception, source);
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400137 }
138
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500139 auto androidCodec = SkAndroidCodec::MakeFromCodec(std::move(codec),
Leon Scroggins IIIac1928b2018-01-17 11:34:43 -0500140 SkAndroidCodec::ExifOrientationBehavior::kRespect);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500141 if (!androidCodec.get()) {
142 return throw_exception(env, kSourceMalformedData, "", nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400143 }
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400144
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500145 const auto& info = androidCodec->getInfo();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400146 const int width = info.width();
147 const int height = info.height();
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500148 const bool isNinePatch = peeker->mPatch != nullptr;
149 ImageDecoder* decoder = new ImageDecoder(std::move(androidCodec), std::move(peeker));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400150 return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500151 reinterpret_cast<jlong>(decoder), width, height,
Leon Scroggins III7d940ba2018-04-04 16:19:33 -0400152 animated, isNinePatch);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400153}
154
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500155static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
Chong Zhangcba27922019-07-12 16:38:47 -0700156 jobject fileDescriptor, jboolean preferAnimation, jobject source) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500157 int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
158
159 struct stat fdStat;
160 if (fstat(descriptor, &fdStat) == -1) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500161 return throw_exception(env, kSourceMalformedData,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400162 "broken file descriptor; fstat returned -1", nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500163 }
164
Nick Kralevich4b3a08c2019-01-28 10:39:10 -0800165 int dupDescriptor = fcntl(descriptor, F_DUPFD_CLOEXEC, 0);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500166 FILE* file = fdopen(dupDescriptor, "r");
167 if (file == NULL) {
168 close(dupDescriptor);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500169 return throw_exception(env, kSourceMalformedData, "Could not open file",
Leon Scroggins IIIcf7294f2018-03-22 09:21:29 -0400170 nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500171 }
Leon Scroggins III0c699ad2018-05-07 16:20:13 -0400172
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500173 std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file));
Chong Zhangcba27922019-07-12 16:38:47 -0700174 return native_create(env, std::move(fileStream), source, preferAnimation);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500175}
176
177static jobject ImageDecoder_nCreateInputStream(JNIEnv* env, jobject /*clazz*/,
Chong Zhangcba27922019-07-12 16:38:47 -0700178 jobject is, jbyteArray storage, jboolean preferAnimation, jobject source) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500179 std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage, false));
180
181 if (!stream.get()) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500182 return throw_exception(env, kSourceMalformedData, "Failed to create a stream",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400183 nullptr, source);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500184 }
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400185
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500186 std::unique_ptr<SkStream> bufferedStream(
187 SkFrontBufferedStream::Make(std::move(stream),
188 SkCodec::MinBufferedBytesNeeded()));
Chong Zhangcba27922019-07-12 16:38:47 -0700189 return native_create(env, std::move(bufferedStream), source, preferAnimation);
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500190}
191
Chong Zhangcba27922019-07-12 16:38:47 -0700192static jobject ImageDecoder_nCreateAsset(JNIEnv* env, jobject /*clazz*/,
193 jlong assetPtr, jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400194 Asset* asset = reinterpret_cast<Asset*>(assetPtr);
195 std::unique_ptr<SkStream> stream(new AssetStreamAdaptor(asset));
Chong Zhangcba27922019-07-12 16:38:47 -0700196 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400197}
198
Chong Zhangcba27922019-07-12 16:38:47 -0700199static jobject ImageDecoder_nCreateByteBuffer(JNIEnv* env, jobject /*clazz*/,
200 jobject jbyteBuffer, jint initialPosition, jint limit,
201 jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400202 std::unique_ptr<SkStream> stream = CreateByteBufferStreamAdaptor(env, jbyteBuffer,
203 initialPosition, limit);
204 if (!stream) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500205 return throw_exception(env, kSourceMalformedData, "Failed to read ByteBuffer",
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400206 nullptr, source);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400207 }
Chong Zhangcba27922019-07-12 16:38:47 -0700208 return native_create(env, std::move(stream), source, preferAnimation);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400209}
210
Chong Zhangcba27922019-07-12 16:38:47 -0700211static jobject ImageDecoder_nCreateByteArray(JNIEnv* env, jobject /*clazz*/,
212 jbyteArray byteArray, jint offset, jint length,
213 jboolean preferAnimation, jobject source) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400214 std::unique_ptr<SkStream> stream(CreateByteArrayStreamAdaptor(env, byteArray, offset, length));
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
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500218jint postProcessAndRelease(JNIEnv* env, jobject jimageDecoder, std::unique_ptr<Canvas> canvas) {
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500219 jobject jcanvas = env->NewObject(gCanvas_class, gCanvas_constructorMethodID,
220 reinterpret_cast<jlong>(canvas.get()));
221 if (!jcanvas) {
222 doThrowOOME(env, "Failed to create Java Canvas for PostProcess!");
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500223 return kUnknown;
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500224 }
225
226 // jcanvas now owns canvas.
227 canvas.release();
228
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500229 return env->CallIntMethod(jimageDecoder, gImageDecoder_postProcessMethodID, jcanvas);
Leon Scroggins III8c9d8f22018-01-14 14:41:46 -0500230}
231
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400232static jobject ImageDecoder_nDecodeBitmap(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400233 jobject jdecoder, jboolean jpostProcess,
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500234 jint targetWidth, jint targetHeight, jobject jsubset,
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400235 jboolean requireMutable, jint allocator,
236 jboolean requireUnpremul, jboolean preferRamOverQuality,
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500237 jboolean asAlphaMask, jlong colorSpaceHandle,
238 jboolean extended) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400239 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500240 if (!decoder->setTargetSize(targetWidth, targetHeight)) {
241 doThrowISE(env, "Could not scale to target size!");
242 return nullptr;
243 }
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500244 if (requireUnpremul && !decoder->setUnpremultipliedRequired(true)) {
Leon Scroggins IIIea978db2018-01-13 11:40:42 -0500245 doThrowISE(env, "Cannot scale unpremultiplied pixels!");
246 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400247 }
248
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400249 SkColorType colorType = kN32_SkColorType;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500250 if (asAlphaMask && decoder->gray()) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400251 // We have to trick Skia to decode this to a single channel.
252 colorType = kGray_8_SkColorType;
253 } else if (preferRamOverQuality) {
254 // FIXME: The post-process might add alpha, which would make a 565
255 // result incorrect. If we call the postProcess before now and record
256 // to a picture, we can know whether alpha was added, and if not, we
257 // can still use 565.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500258 if (decoder->opaque() && !jpostProcess) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400259 // If the final result will be hardware, decoding to 565 and then
260 // uploading to the gpu as 8888 will not save memory. This still
261 // may save us from using F16, but do not go down to 565.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500262 if (allocator != kHardware_Allocator &&
263 (allocator != kDefault_Allocator || requireMutable)) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400264 colorType = kRGB_565_SkColorType;
265 }
266 }
267 // Otherwise, stick with N32
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500268 } else if (extended) {
269 colorType = kRGBA_F16_SkColorType;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400270 } else {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500271 colorType = decoder->mCodec->computeOutputColorType(colorType);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400272 }
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500273
274 const bool isHardware = !requireMutable
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500275 && (allocator == kDefault_Allocator ||
276 allocator == kHardware_Allocator)
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500277 && colorType != kGray_8_SkColorType;
278
279 if (colorType == kRGBA_F16_SkColorType && isHardware &&
280 !uirenderer::HardwareBitmapUploader::hasFP16Support()) {
281 colorType = kN32_SkColorType;
282 }
283
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500284 if (!decoder->setOutColorType(colorType)) {
285 doThrowISE(env, "Failed to set out color type!");
286 return nullptr;
287 }
288
289 {
290 sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
291 colorSpace = decoder->mCodec->computeOutputColorSpace(colorType, colorSpace);
292 decoder->setOutColorSpace(std::move(colorSpace));
293 }
294
295 if (jsubset) {
296 SkIRect subset;
297 GraphicsJNI::jrect_to_irect(env, jsubset, &subset);
298 if (!decoder->setCropRect(&subset)) {
299 doThrowISE(env, "Invalid crop rect!");
300 return nullptr;
301 }
302 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400303
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500304 SkImageInfo bitmapInfo = decoder->getOutputInfo();
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500305 if (decoder->opaque()) {
306 bitmapInfo = bitmapInfo.makeAlphaType(kOpaque_SkAlphaType);
307 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400308 if (asAlphaMask && colorType == kGray_8_SkColorType) {
309 bitmapInfo = bitmapInfo.makeColorType(kAlpha_8_SkColorType);
310 }
Leon Scroggins III1ade46d2020-01-15 05:41:06 -0500311
312 SkBitmap bm;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400313 if (!bm.setInfo(bitmapInfo)) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500314 doThrowIOE(env, "Failed to setInfo properly");
315 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400316 }
317
318 sk_sp<Bitmap> nativeBitmap;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500319 if (allocator == kSharedMemory_Allocator) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400320 nativeBitmap = Bitmap::allocateAshmemBitmap(&bm);
321 } else {
322 nativeBitmap = Bitmap::allocateHeapBitmap(&bm);
323 }
324 if (!nativeBitmap) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500325 SkString msg;
326 msg.printf("OOM allocating Bitmap with dimensions %i x %i",
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500327 bitmapInfo.width(), bitmapInfo.height());
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500328 doThrowOOME(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400329 return nullptr;
330 }
331
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500332 SkCodec::Result result = decoder->decode(bm.getPixels(), bm.rowBytes());
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400333 jthrowable jexception = get_and_clear_exception(env);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500334 int onPartialImageError = jexception ? kSourceException
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500335 : 0; // No error.
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400336 switch (result) {
337 case SkCodec::kSuccess:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500338 // Ignore the exception, since the decode was successful anyway.
339 jexception = nullptr;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500340 onPartialImageError = 0;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400341 break;
342 case SkCodec::kIncompleteInput:
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500343 if (!jexception) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500344 onPartialImageError = kSourceIncomplete;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400345 }
346 break;
347 case SkCodec::kErrorInInput:
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500348 if (!jexception) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500349 onPartialImageError = kSourceMalformedData;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400350 }
351 break;
352 default:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500353 SkString msg;
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500354 msg.printf("getPixels failed with error %s", SkCodec::ResultToString(result));
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500355 doThrowIOE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400356 return nullptr;
357 }
358
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400359 if (onPartialImageError) {
360 env->CallVoidMethod(jdecoder, gCallback_onPartialImageMethodID, onPartialImageError,
361 jexception);
Leon Scroggins IIIedf26d62018-01-09 16:55:24 -0500362 if (env->ExceptionCheck()) {
363 return nullptr;
364 }
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400365 }
366
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400367 jbyteArray ninePatchChunk = nullptr;
368 jobject ninePatchInsets = nullptr;
369
370 // Ignore ninepatch when post-processing.
371 if (!jpostProcess) {
372 // FIXME: Share more code with BitmapFactory.cpp.
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500373 auto* peeker = reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get());
374 if (peeker->mPatch != nullptr) {
375 size_t ninePatchArraySize = peeker->mPatch->serializedSize();
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400376 ninePatchChunk = env->NewByteArray(ninePatchArraySize);
377 if (ninePatchChunk == nullptr) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500378 doThrowOOME(env, "Failed to allocate nine patch chunk.");
379 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400380 }
381
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500382 env->SetByteArrayRegion(ninePatchChunk, 0, peeker->mPatchSize,
383 reinterpret_cast<jbyte*>(peeker->mPatch));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400384 }
385
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500386 if (peeker->mHasInsets) {
387 ninePatchInsets = peeker->createNinePatchInsets(env, 1.0f);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400388 if (ninePatchInsets == nullptr) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500389 doThrowOOME(env, "Failed to allocate nine patch insets.");
390 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400391 }
392 }
393 }
394
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400395 if (jpostProcess) {
396 std::unique_ptr<Canvas> canvas(Canvas::create_canvas(bm));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400397
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400398 jint pixelFormat = postProcessAndRelease(env, jdecoder, std::move(canvas));
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400399 if (env->ExceptionCheck()) {
400 return nullptr;
401 }
402
403 SkAlphaType newAlphaType = bm.alphaType();
404 switch (pixelFormat) {
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500405 case kUnknown:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400406 break;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500407 case kTranslucent:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400408 newAlphaType = kPremul_SkAlphaType;
409 break;
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500410 case kOpaque:
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400411 newAlphaType = kOpaque_SkAlphaType;
412 break;
413 default:
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500414 SkString msg;
415 msg.printf("invalid return from postProcess: %i", pixelFormat);
416 doThrowIAE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400417 return nullptr;
418 }
419
420 if (newAlphaType != bm.alphaType()) {
421 if (!bm.setAlphaType(newAlphaType)) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500422 SkString msg;
423 msg.printf("incompatible return from postProcess: %i", pixelFormat);
424 doThrowIAE(env, msg.c_str());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400425 return nullptr;
426 }
427 nativeBitmap->setAlphaType(newAlphaType);
428 }
429 }
430
431 int bitmapCreateFlags = 0x0;
432 if (!requireUnpremul) {
433 // Even if the image is opaque, setting this flag means that
434 // if alpha is added (e.g. by PostProcess), it will be marked as
435 // premultiplied.
436 bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Premultiplied;
437 }
438
439 if (requireMutable) {
440 bitmapCreateFlags |= bitmap::kBitmapCreateFlag_Mutable;
441 } else {
Leon Scroggins IIIee3bfe72019-01-31 08:42:23 -0500442 if (isHardware) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400443 sk_sp<Bitmap> hwBitmap = Bitmap::allocateHardwareBitmap(bm);
444 if (hwBitmap) {
445 hwBitmap->setImmutable();
446 return bitmap::createBitmap(env, hwBitmap.release(), bitmapCreateFlags,
447 ninePatchChunk, ninePatchInsets);
448 }
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500449 if (allocator == kHardware_Allocator) {
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500450 doThrowOOME(env, "failed to allocate hardware Bitmap!");
451 return nullptr;
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400452 }
453 // If we failed to create a hardware bitmap, go ahead and create a
454 // software one.
455 }
456
457 nativeBitmap->setImmutable();
458 }
459 return bitmap::createBitmap(env, nativeBitmap.release(), bitmapCreateFlags, ninePatchChunk,
460 ninePatchInsets);
461}
462
463static jobject ImageDecoder_nGetSampledSize(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
464 jint sampleSize) {
465 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
466 SkISize size = decoder->mCodec->getSampledDimensions(sampleSize);
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500467 return env->NewObject(gSize_class, gSize_constructorMethodID, size.width(), size.height());
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400468}
469
470static void ImageDecoder_nGetPadding(JNIEnv* env, jobject /*clazz*/, jlong nativePtr,
471 jobject outPadding) {
472 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III753a56f2019-12-11 11:02:15 -0500473 reinterpret_cast<NinePatchPeeker*>(decoder->mPeeker.get())->getPadding(env, outPadding);
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400474}
475
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500476static void ImageDecoder_nClose(JNIEnv* /*env*/, jobject /*clazz*/, jlong nativePtr) {
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400477 delete reinterpret_cast<ImageDecoder*>(nativePtr);
478}
479
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500480static jstring ImageDecoder_nGetMimeType(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
481 auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
Leon Scroggins III407b5442019-11-22 17:10:20 -0500482 return getMimeTypeAsJavaString(env, decoder->mCodec->getEncodedFormat());
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500483}
484
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400485static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
486 auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500487 auto colorType = codec->computeOutputColorType(kN32_SkColorType);
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400488 sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
Derek Sollenbergerbf3e4642019-01-30 11:28:27 -0500489 return GraphicsJNI::getColorSpace(env, colorSpace.get(), colorType);
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400490}
491
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400492static const JNINativeMethod gImageDecoderMethods[] = {
Chong Zhangcba27922019-07-12 16:38:47 -0700493 { "nCreate", "(JZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateAsset },
494 { "nCreate", "(Ljava/nio/ByteBuffer;IIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
495 { "nCreate", "([BIIZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
496 { "nCreate", "(Ljava/io/InputStream;[BZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
497 { "nCreate", "(Ljava/io/FileDescriptor;ZLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
Leon Scroggins III28f3943f2019-02-19 11:03:44 -0500498 { "nDecodeBitmap", "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400499 (void*) ImageDecoder_nDecodeBitmap },
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500500 { "nGetSampledSize","(JI)Landroid/util/Size;", (void*) ImageDecoder_nGetSampledSize },
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400501 { "nGetPadding", "(JLandroid/graphics/Rect;)V", (void*) ImageDecoder_nGetPadding },
Leon Scroggins IIIed074fd2017-12-11 13:47:23 -0500502 { "nClose", "(J)V", (void*) ImageDecoder_nClose},
Leon Scroggins III1fad09d2017-12-22 12:54:20 -0500503 { "nGetMimeType", "(J)Ljava/lang/String;", (void*) ImageDecoder_nGetMimeType },
Leon Scroggins III1a69f452018-03-29 09:48:47 -0400504 { "nGetColorSpace", "(J)Landroid/graphics/ColorSpace;", (void*) ImageDecoder_nGetColorSpace },
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400505};
506
507int register_android_graphics_ImageDecoder(JNIEnv* env) {
508 gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
Leon Scroggins III7d940ba2018-04-04 16:19:33 -0400509 gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500510 gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400511
Leon Scroggins IIIe5de9aa2018-01-10 20:56:51 -0500512 gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
513 gSize_constructorMethodID = GetMethodIDOrDie(env, gSize_class, "<init>", "(II)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400514
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400515 gDecodeException_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder$DecodeException"));
516 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 -0400517
Leon Scroggins III1d2bf2b2018-03-14 16:07:43 -0400518 gCallback_onPartialImageMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "onPartialImage", "(ILjava/lang/Throwable;)V");
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400519
Leon Scroggins III0c01dbf2017-10-20 14:08:11 -0400520 gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
521 gCanvas_constructorMethodID = GetMethodIDOrDie(env, gCanvas_class, "<init>", "(J)V");
522 gCanvas_releaseMethodID = GetMethodIDOrDie(env, gCanvas_class, "release", "()V");
523
524 return android::RegisterMethodsOrDie(env, "android/graphics/ImageDecoder", gImageDecoderMethods,
525 NELEM(gImageDecoderMethods));
526}