blob: 71972d01b94fafb4808bcd6cb4cfe5df9f5bcbe5 [file] [log] [blame]
John Reck5bd537e2023-01-24 20:13:45 -05001/*
2 * Copyright (C) 2023 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 <Gainmap.h>
18
Alec Mourid7e90a62024-08-29 19:21:35 +000019#include "SkColorType.h"
20#include "SkGainmapInfo.h"
21
Sally Qi9d2d9342023-02-06 11:11:31 -080022#ifdef __ANDROID__
23#include <binder/Parcel.h>
24#endif
25
John Reck5bd537e2023-01-24 20:13:45 -050026#include "Bitmap.h"
27#include "GraphicsJNI.h"
Sally Qi9d2d9342023-02-06 11:11:31 -080028#include "ScopedParcel.h"
John Reck5bd537e2023-01-24 20:13:45 -050029#include "graphics_jni_helpers.h"
30
31namespace android {
32
33static jclass gGainmap_class;
34static jmethodID gGainmap_constructorMethodID;
35
36using namespace uirenderer;
37
38static Gainmap* fromJava(jlong gainmap) {
39 return reinterpret_cast<Gainmap*>(gainmap);
40}
41
Alec Mourid7e90a62024-08-29 19:21:35 +000042static SkGainmapInfo::BaseImageType baseImageTypeFromJava(jint direction) {
43 switch (direction) {
44 case 0:
45 return SkGainmapInfo::BaseImageType::kSDR;
46 case 1:
47 return SkGainmapInfo::BaseImageType::kHDR;
48 default:
49 LOG_ALWAYS_FATAL("Unrecognized Gainmap direction: %d", direction);
50 }
51}
52
53static jint baseImageTypeToJava(SkGainmapInfo::BaseImageType type) {
54 switch (type) {
55 case SkGainmapInfo::BaseImageType::kSDR:
56 return 0;
57 case SkGainmapInfo::BaseImageType::kHDR:
58 return 1;
59 default:
60 LOG_ALWAYS_FATAL("Unrecognized base image: %d", type);
61 }
62}
63
John Reck5bd537e2023-01-24 20:13:45 -050064static int getCreateFlags(const sk_sp<Bitmap>& bitmap) {
65 int flags = 0;
66 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
67 flags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
68 }
69 if (!bitmap->isImmutable()) {
70 flags |= android::bitmap::kBitmapCreateFlag_Mutable;
71 }
72 return flags;
73}
74
75jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap) {
76 auto gainmap = bitmap.gainmap();
77 jobject jGainmapImage;
John Reck5bd537e2023-01-24 20:13:45 -050078
79 {
80 // Scope to guard the release of nativeBitmap
81 auto nativeBitmap = gainmap->bitmap;
82 const int createFlags = getCreateFlags(nativeBitmap);
John Reck5bd537e2023-01-24 20:13:45 -050083 jGainmapImage = bitmap::createBitmap(env, nativeBitmap.release(), createFlags);
84 }
85
86 // Grab a ref for the jobject
87 gainmap->incStrong(0);
88 jobject obj = env->NewObject(gGainmap_class, gGainmap_constructorMethodID, jGainmapImage,
John Reck3e98bce2023-02-07 13:38:28 -050089 gainmap.get());
John Reck5bd537e2023-01-24 20:13:45 -050090
91 if (env->ExceptionCheck() != 0) {
92 // sadtrombone
93 gainmap->decStrong(0);
94 ALOGE("*** Uncaught exception returned from Java call!\n");
95 env->ExceptionDescribe();
96 }
97 return obj;
98}
99
100static void Gainmap_destructor(Gainmap* gainmap) {
101 gainmap->decStrong(0);
102}
103
104static jlong Gainmap_getNativeFinalizer(JNIEnv*, jobject) {
105 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Gainmap_destructor));
106}
107
John Reck3e98bce2023-02-07 13:38:28 -0500108jlong Gainmap_createEmpty(JNIEnv*, jobject) {
109 Gainmap* gainmap = new Gainmap();
110 gainmap->incStrong(0);
111 return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
John Reck5bd537e2023-01-24 20:13:45 -0500112}
113
John Reckb1c20ee2023-06-07 17:58:16 -0400114jlong Gainmap_createCopy(JNIEnv*, jobject, jlong sourcePtr) {
115 Gainmap* gainmap = new Gainmap();
116 gainmap->incStrong(0);
117 if (sourcePtr) {
118 Gainmap* src = fromJava(sourcePtr);
119 gainmap->info = src->info;
120 }
121 return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
122}
123
John Reck3e98bce2023-02-07 13:38:28 -0500124static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) {
125 android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap);
126 fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap);
127}
128
129static void Gainmap_setRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
130 fromJava(gainmapPtr)->info.fGainmapRatioMin = {r, g, b, 1.f};
131}
132
133static void Gainmap_getRatioMin(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
134 const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMin;
135 jfloat buf[3]{value.fR, value.fG, value.fB};
John Reck5bd537e2023-01-24 20:13:45 -0500136 env->SetFloatArrayRegion(components, 0, 3, buf);
137}
138
John Reck3e98bce2023-02-07 13:38:28 -0500139static void Gainmap_setRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
140 fromJava(gainmapPtr)->info.fGainmapRatioMax = {r, g, b, 1.f};
John Reck5bd537e2023-01-24 20:13:45 -0500141}
142
John Reck3e98bce2023-02-07 13:38:28 -0500143static void Gainmap_getRatioMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
144 const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMax;
145 jfloat buf[3]{value.fR, value.fG, value.fB};
146 env->SetFloatArrayRegion(components, 0, 3, buf);
John Reck5bd537e2023-01-24 20:13:45 -0500147}
148
John Reck3e98bce2023-02-07 13:38:28 -0500149static void Gainmap_setGamma(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
150 fromJava(gainmapPtr)->info.fGainmapGamma = {r, g, b, 1.f};
John Reck5bd537e2023-01-24 20:13:45 -0500151}
152
John Reck3e98bce2023-02-07 13:38:28 -0500153static void Gainmap_getGamma(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
154 const auto value = fromJava(gainmapPtr)->info.fGainmapGamma;
155 jfloat buf[3]{value.fR, value.fG, value.fB};
156 env->SetFloatArrayRegion(components, 0, 3, buf);
157}
158
159static void Gainmap_setEpsilonSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
160 jfloat b) {
161 fromJava(gainmapPtr)->info.fEpsilonSdr = {r, g, b, 1.f};
162}
163
164static void Gainmap_getEpsilonSdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
165 const auto value = fromJava(gainmapPtr)->info.fEpsilonSdr;
166 jfloat buf[3]{value.fR, value.fG, value.fB};
167 env->SetFloatArrayRegion(components, 0, 3, buf);
168}
169
170static void Gainmap_setEpsilonHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
171 jfloat b) {
172 fromJava(gainmapPtr)->info.fEpsilonHdr = {r, g, b, 1.f};
173}
174
175static void Gainmap_getEpsilonHdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
176 const auto value = fromJava(gainmapPtr)->info.fEpsilonHdr;
177 jfloat buf[3]{value.fR, value.fG, value.fB};
178 env->SetFloatArrayRegion(components, 0, 3, buf);
179}
180
181static void Gainmap_setDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
182 fromJava(gainmapPtr)->info.fDisplayRatioHdr = max;
183}
184
185static jfloat Gainmap_getDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr) {
186 return fromJava(gainmapPtr)->info.fDisplayRatioHdr;
187}
188
189static void Gainmap_setDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
190 fromJava(gainmapPtr)->info.fDisplayRatioSdr = min;
191}
192
193static jfloat Gainmap_getDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr) {
194 return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
John Reck5bd537e2023-01-24 20:13:45 -0500195}
196
Alec Mourid7e90a62024-08-29 19:21:35 +0000197static void Gainmap_setAlternativeColorSpace(JNIEnv*, jobject, jlong gainmapPtr,
198 jlong colorSpacePtr) {
199 auto colorSpace = GraphicsJNI::getNativeColorSpace(colorSpacePtr);
200 fromJava(gainmapPtr)->info.fGainmapMathColorSpace = colorSpace;
201}
202
203static jobject Gainmap_getAlternativeColorSpace(JNIEnv* env, jobject, jlong gainmapPtr) {
204 const auto javaGainmap = fromJava(gainmapPtr);
205 auto colorSpace = javaGainmap->info.fGainmapMathColorSpace.get();
206 if (colorSpace == nullptr) {
207 return nullptr;
208 }
209
210 auto colorType = javaGainmap->bitmap->colorType();
211 // A8 bitmaps don't support colorspaces, but an alternative colorspace is
212 // still valid for configuring the gainmap math, so use RGBA8888 instead.
213 if (colorType == kAlpha_8_SkColorType) {
214 colorType = kRGBA_8888_SkColorType;
215 }
216 return GraphicsJNI::getColorSpace(env, colorSpace, colorType);
217}
218
219static void Gainmap_setDirection(JNIEnv*, jobject, jlong gainmapPtr, jint direction) {
220 fromJava(gainmapPtr)->info.fBaseImageType = baseImageTypeFromJava(direction);
221}
222
223static jint Gainmap_getDirection(JNIEnv* env, jobject, jlong gainmapPtr) {
224 return baseImageTypeToJava(fromJava(gainmapPtr)->info.fBaseImageType);
225}
226
Sally Qi9d2d9342023-02-06 11:11:31 -0800227// ----------------------------------------------------------------------------
228// Serialization
229// ----------------------------------------------------------------------------
230
231static void Gainmap_writeToParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
232#ifdef __ANDROID__ // Layoutlib does not support parcel
233 if (parcel == NULL) {
234 ALOGD("write null parcel\n");
235 return;
236 }
237 ScopedParcel p(env, parcel);
238 SkGainmapInfo info = fromJava(nativeObject)->info;
239 // write gainmap to parcel
240 // ratio min
241 p.writeFloat(info.fGainmapRatioMin.fR);
242 p.writeFloat(info.fGainmapRatioMin.fG);
243 p.writeFloat(info.fGainmapRatioMin.fB);
244 // ratio max
245 p.writeFloat(info.fGainmapRatioMax.fR);
246 p.writeFloat(info.fGainmapRatioMax.fG);
247 p.writeFloat(info.fGainmapRatioMax.fB);
248 // gamma
249 p.writeFloat(info.fGainmapGamma.fR);
250 p.writeFloat(info.fGainmapGamma.fG);
251 p.writeFloat(info.fGainmapGamma.fB);
252 // epsilonsdr
253 p.writeFloat(info.fEpsilonSdr.fR);
254 p.writeFloat(info.fEpsilonSdr.fG);
255 p.writeFloat(info.fEpsilonSdr.fB);
256 // epsilonhdr
257 p.writeFloat(info.fEpsilonHdr.fR);
258 p.writeFloat(info.fEpsilonHdr.fG);
259 p.writeFloat(info.fEpsilonHdr.fB);
260 // display ratio sdr
261 p.writeFloat(info.fDisplayRatioSdr);
262 // display ratio hdr
263 p.writeFloat(info.fDisplayRatioHdr);
264 // base image type
265 p.writeInt32(static_cast<int32_t>(info.fBaseImageType));
Sally Qi9d2d9342023-02-06 11:11:31 -0800266#else
267 doThrowRE(env, "Cannot use parcels outside of Android!");
268#endif
269}
270
271static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
272#ifdef __ANDROID__ // Layoutlib does not support parcel
273 if (parcel == NULL) {
274 jniThrowNullPointerException(env, "parcel cannot be null");
275 return;
276 }
277 ScopedParcel p(env, parcel);
278
279 SkGainmapInfo info;
280 info.fGainmapRatioMin = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
281 info.fGainmapRatioMax = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
282 info.fGainmapGamma = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
283 info.fEpsilonSdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
284 info.fEpsilonHdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
285 info.fDisplayRatioSdr = p.readFloat();
286 info.fDisplayRatioHdr = p.readFloat();
287 info.fBaseImageType = static_cast<SkGainmapInfo::BaseImageType>(p.readInt32());
Sally Qi9d2d9342023-02-06 11:11:31 -0800288
289 fromJava(nativeObject)->info = info;
290#else
291 jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
292#endif
293}
294
295// ----------------------------------------------------------------------------
296// JNI Glue
297// ----------------------------------------------------------------------------
298
John Reck5bd537e2023-01-24 20:13:45 -0500299static const JNINativeMethod gGainmapMethods[] = {
300 {"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
John Reck3e98bce2023-02-07 13:38:28 -0500301 {"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
John Reckb1c20ee2023-06-07 17:58:16 -0400302 {"nCreateCopy", "(J)J", (void*)Gainmap_createCopy},
John Reck3e98bce2023-02-07 13:38:28 -0500303 {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap},
304 {"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin},
305 {"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin},
306 {"nSetRatioMax", "(JFFF)V", (void*)Gainmap_setRatioMax},
307 {"nGetRatioMax", "(J[F)V", (void*)Gainmap_getRatioMax},
308 {"nSetGamma", "(JFFF)V", (void*)Gainmap_setGamma},
309 {"nGetGamma", "(J[F)V", (void*)Gainmap_getGamma},
310 {"nSetEpsilonSdr", "(JFFF)V", (void*)Gainmap_setEpsilonSdr},
311 {"nGetEpsilonSdr", "(J[F)V", (void*)Gainmap_getEpsilonSdr},
312 {"nSetEpsilonHdr", "(JFFF)V", (void*)Gainmap_setEpsilonHdr},
313 {"nGetEpsilonHdr", "(J[F)V", (void*)Gainmap_getEpsilonHdr},
314 {"nSetDisplayRatioHdr", "(JF)V", (void*)Gainmap_setDisplayRatioHdr},
315 {"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
316 {"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
317 {"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
Alec Mourid7e90a62024-08-29 19:21:35 +0000318 {"nSetAlternativeColorSpace", "(JJ)V", (void*)Gainmap_setAlternativeColorSpace},
319 {"nGetAlternativeColorSpace", "(J)Landroid/graphics/ColorSpace;",
320 (void*)Gainmap_getAlternativeColorSpace},
321 {"nSetDirection", "(JI)V", (void*)Gainmap_setDirection},
322 {"nGetDirection", "(J)I", (void*)Gainmap_getDirection},
Sally Qi9d2d9342023-02-06 11:11:31 -0800323 {"nWriteGainmapToParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_writeToParcel},
324 {"nReadGainmapFromParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_readFromParcel},
John Reck5bd537e2023-01-24 20:13:45 -0500325};
326
327int register_android_graphics_Gainmap(JNIEnv* env) {
328 gGainmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Gainmap"));
329 gGainmap_constructorMethodID =
John Reck3e98bce2023-02-07 13:38:28 -0500330 GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;J)V");
John Reck5bd537e2023-01-24 20:13:45 -0500331 return android::RegisterMethodsOrDie(env, "android/graphics/Gainmap", gGainmapMethods,
332 NELEM(gGainmapMethods));
333}
334
335} // namespace android