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