1 /*
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
19 #ifdef __ANDROID__
20 #include <binder/Parcel.h>
21 #endif
22
23 #include "Bitmap.h"
24 #include "GraphicsJNI.h"
25 #include "ScopedParcel.h"
26 #include "graphics_jni_helpers.h"
27
28 namespace android {
29
30 static jclass gGainmap_class;
31 static jmethodID gGainmap_constructorMethodID;
32
33 using namespace uirenderer;
34
fromJava(jlong gainmap)35 static Gainmap* fromJava(jlong gainmap) {
36 return reinterpret_cast<Gainmap*>(gainmap);
37 }
38
getCreateFlags(const sk_sp<Bitmap> & bitmap)39 static int getCreateFlags(const sk_sp<Bitmap>& bitmap) {
40 int flags = 0;
41 if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
42 flags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
43 }
44 if (!bitmap->isImmutable()) {
45 flags |= android::bitmap::kBitmapCreateFlag_Mutable;
46 }
47 return flags;
48 }
49
Gainmap_extractFromBitmap(JNIEnv * env,const Bitmap & bitmap)50 jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap) {
51 auto gainmap = bitmap.gainmap();
52 jobject jGainmapImage;
53
54 {
55 // Scope to guard the release of nativeBitmap
56 auto nativeBitmap = gainmap->bitmap;
57 const int createFlags = getCreateFlags(nativeBitmap);
58 jGainmapImage = bitmap::createBitmap(env, nativeBitmap.release(), createFlags);
59 }
60
61 // Grab a ref for the jobject
62 gainmap->incStrong(0);
63 jobject obj = env->NewObject(gGainmap_class, gGainmap_constructorMethodID, jGainmapImage,
64 gainmap.get());
65
66 if (env->ExceptionCheck() != 0) {
67 // sadtrombone
68 gainmap->decStrong(0);
69 ALOGE("*** Uncaught exception returned from Java call!\n");
70 env->ExceptionDescribe();
71 }
72 return obj;
73 }
74
Gainmap_destructor(Gainmap * gainmap)75 static void Gainmap_destructor(Gainmap* gainmap) {
76 gainmap->decStrong(0);
77 }
78
Gainmap_getNativeFinalizer(JNIEnv *,jobject)79 static jlong Gainmap_getNativeFinalizer(JNIEnv*, jobject) {
80 return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Gainmap_destructor));
81 }
82
Gainmap_createEmpty(JNIEnv *,jobject)83 jlong Gainmap_createEmpty(JNIEnv*, jobject) {
84 Gainmap* gainmap = new Gainmap();
85 gainmap->incStrong(0);
86 return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
87 }
88
Gainmap_createCopy(JNIEnv *,jobject,jlong sourcePtr)89 jlong Gainmap_createCopy(JNIEnv*, jobject, jlong sourcePtr) {
90 Gainmap* gainmap = new Gainmap();
91 gainmap->incStrong(0);
92 if (sourcePtr) {
93 Gainmap* src = fromJava(sourcePtr);
94 gainmap->info = src->info;
95 }
96 return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
97 }
98
Gainmap_setBitmap(JNIEnv * env,jobject,jlong gainmapPtr,jobject jBitmap)99 static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) {
100 android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap);
101 fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap);
102 }
103
Gainmap_setRatioMin(JNIEnv *,jobject,jlong gainmapPtr,jfloat r,jfloat g,jfloat b)104 static void Gainmap_setRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
105 fromJava(gainmapPtr)->info.fGainmapRatioMin = {r, g, b, 1.f};
106 }
107
Gainmap_getRatioMin(JNIEnv * env,jobject,jlong gainmapPtr,jfloatArray components)108 static void Gainmap_getRatioMin(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
109 const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMin;
110 jfloat buf[3]{value.fR, value.fG, value.fB};
111 env->SetFloatArrayRegion(components, 0, 3, buf);
112 }
113
Gainmap_setRatioMax(JNIEnv *,jobject,jlong gainmapPtr,jfloat r,jfloat g,jfloat b)114 static void Gainmap_setRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
115 fromJava(gainmapPtr)->info.fGainmapRatioMax = {r, g, b, 1.f};
116 }
117
Gainmap_getRatioMax(JNIEnv * env,jobject,jlong gainmapPtr,jfloatArray components)118 static void Gainmap_getRatioMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
119 const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMax;
120 jfloat buf[3]{value.fR, value.fG, value.fB};
121 env->SetFloatArrayRegion(components, 0, 3, buf);
122 }
123
Gainmap_setGamma(JNIEnv *,jobject,jlong gainmapPtr,jfloat r,jfloat g,jfloat b)124 static void Gainmap_setGamma(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
125 fromJava(gainmapPtr)->info.fGainmapGamma = {r, g, b, 1.f};
126 }
127
Gainmap_getGamma(JNIEnv * env,jobject,jlong gainmapPtr,jfloatArray components)128 static void Gainmap_getGamma(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
129 const auto value = fromJava(gainmapPtr)->info.fGainmapGamma;
130 jfloat buf[3]{value.fR, value.fG, value.fB};
131 env->SetFloatArrayRegion(components, 0, 3, buf);
132 }
133
Gainmap_setEpsilonSdr(JNIEnv *,jobject,jlong gainmapPtr,jfloat r,jfloat g,jfloat b)134 static void Gainmap_setEpsilonSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
135 jfloat b) {
136 fromJava(gainmapPtr)->info.fEpsilonSdr = {r, g, b, 1.f};
137 }
138
Gainmap_getEpsilonSdr(JNIEnv * env,jobject,jlong gainmapPtr,jfloatArray components)139 static void Gainmap_getEpsilonSdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
140 const auto value = fromJava(gainmapPtr)->info.fEpsilonSdr;
141 jfloat buf[3]{value.fR, value.fG, value.fB};
142 env->SetFloatArrayRegion(components, 0, 3, buf);
143 }
144
Gainmap_setEpsilonHdr(JNIEnv *,jobject,jlong gainmapPtr,jfloat r,jfloat g,jfloat b)145 static void Gainmap_setEpsilonHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
146 jfloat b) {
147 fromJava(gainmapPtr)->info.fEpsilonHdr = {r, g, b, 1.f};
148 }
149
Gainmap_getEpsilonHdr(JNIEnv * env,jobject,jlong gainmapPtr,jfloatArray components)150 static void Gainmap_getEpsilonHdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
151 const auto value = fromJava(gainmapPtr)->info.fEpsilonHdr;
152 jfloat buf[3]{value.fR, value.fG, value.fB};
153 env->SetFloatArrayRegion(components, 0, 3, buf);
154 }
155
Gainmap_setDisplayRatioHdr(JNIEnv *,jobject,jlong gainmapPtr,jfloat max)156 static void Gainmap_setDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
157 fromJava(gainmapPtr)->info.fDisplayRatioHdr = max;
158 }
159
Gainmap_getDisplayRatioHdr(JNIEnv *,jobject,jlong gainmapPtr)160 static jfloat Gainmap_getDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr) {
161 return fromJava(gainmapPtr)->info.fDisplayRatioHdr;
162 }
163
Gainmap_setDisplayRatioSdr(JNIEnv *,jobject,jlong gainmapPtr,jfloat min)164 static void Gainmap_setDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
165 fromJava(gainmapPtr)->info.fDisplayRatioSdr = min;
166 }
167
Gainmap_getDisplayRatioSdr(JNIEnv *,jobject,jlong gainmapPtr)168 static jfloat Gainmap_getDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr) {
169 return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
170 }
171
172 // ----------------------------------------------------------------------------
173 // Serialization
174 // ----------------------------------------------------------------------------
175
Gainmap_writeToParcel(JNIEnv * env,jobject,jlong nativeObject,jobject parcel)176 static void Gainmap_writeToParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
177 #ifdef __ANDROID__ // Layoutlib does not support parcel
178 if (parcel == NULL) {
179 ALOGD("write null parcel\n");
180 return;
181 }
182 ScopedParcel p(env, parcel);
183 SkGainmapInfo info = fromJava(nativeObject)->info;
184 // write gainmap to parcel
185 // ratio min
186 p.writeFloat(info.fGainmapRatioMin.fR);
187 p.writeFloat(info.fGainmapRatioMin.fG);
188 p.writeFloat(info.fGainmapRatioMin.fB);
189 // ratio max
190 p.writeFloat(info.fGainmapRatioMax.fR);
191 p.writeFloat(info.fGainmapRatioMax.fG);
192 p.writeFloat(info.fGainmapRatioMax.fB);
193 // gamma
194 p.writeFloat(info.fGainmapGamma.fR);
195 p.writeFloat(info.fGainmapGamma.fG);
196 p.writeFloat(info.fGainmapGamma.fB);
197 // epsilonsdr
198 p.writeFloat(info.fEpsilonSdr.fR);
199 p.writeFloat(info.fEpsilonSdr.fG);
200 p.writeFloat(info.fEpsilonSdr.fB);
201 // epsilonhdr
202 p.writeFloat(info.fEpsilonHdr.fR);
203 p.writeFloat(info.fEpsilonHdr.fG);
204 p.writeFloat(info.fEpsilonHdr.fB);
205 // display ratio sdr
206 p.writeFloat(info.fDisplayRatioSdr);
207 // display ratio hdr
208 p.writeFloat(info.fDisplayRatioHdr);
209 // base image type
210 p.writeInt32(static_cast<int32_t>(info.fBaseImageType));
211 #else
212 doThrowRE(env, "Cannot use parcels outside of Android!");
213 #endif
214 }
215
Gainmap_readFromParcel(JNIEnv * env,jobject,jlong nativeObject,jobject parcel)216 static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
217 #ifdef __ANDROID__ // Layoutlib does not support parcel
218 if (parcel == NULL) {
219 jniThrowNullPointerException(env, "parcel cannot be null");
220 return;
221 }
222 ScopedParcel p(env, parcel);
223
224 SkGainmapInfo info;
225 info.fGainmapRatioMin = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
226 info.fGainmapRatioMax = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
227 info.fGainmapGamma = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
228 info.fEpsilonSdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
229 info.fEpsilonHdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
230 info.fDisplayRatioSdr = p.readFloat();
231 info.fDisplayRatioHdr = p.readFloat();
232 info.fBaseImageType = static_cast<SkGainmapInfo::BaseImageType>(p.readInt32());
233
234 fromJava(nativeObject)->info = info;
235 #else
236 jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
237 #endif
238 }
239
240 // ----------------------------------------------------------------------------
241 // JNI Glue
242 // ----------------------------------------------------------------------------
243
244 static const JNINativeMethod gGainmapMethods[] = {
245 {"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
246 {"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
247 {"nCreateCopy", "(J)J", (void*)Gainmap_createCopy},
248 {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap},
249 {"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin},
250 {"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin},
251 {"nSetRatioMax", "(JFFF)V", (void*)Gainmap_setRatioMax},
252 {"nGetRatioMax", "(J[F)V", (void*)Gainmap_getRatioMax},
253 {"nSetGamma", "(JFFF)V", (void*)Gainmap_setGamma},
254 {"nGetGamma", "(J[F)V", (void*)Gainmap_getGamma},
255 {"nSetEpsilonSdr", "(JFFF)V", (void*)Gainmap_setEpsilonSdr},
256 {"nGetEpsilonSdr", "(J[F)V", (void*)Gainmap_getEpsilonSdr},
257 {"nSetEpsilonHdr", "(JFFF)V", (void*)Gainmap_setEpsilonHdr},
258 {"nGetEpsilonHdr", "(J[F)V", (void*)Gainmap_getEpsilonHdr},
259 {"nSetDisplayRatioHdr", "(JF)V", (void*)Gainmap_setDisplayRatioHdr},
260 {"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
261 {"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
262 {"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
263 {"nWriteGainmapToParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_writeToParcel},
264 {"nReadGainmapFromParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_readFromParcel},
265 };
266
register_android_graphics_Gainmap(JNIEnv * env)267 int register_android_graphics_Gainmap(JNIEnv* env) {
268 gGainmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Gainmap"));
269 gGainmap_constructorMethodID =
270 GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;J)V");
271 return android::RegisterMethodsOrDie(env, "android/graphics/Gainmap", gGainmapMethods,
272 NELEM(gGainmapMethods));
273 }
274
275 } // namespace android
276