blob: 0fffee744be0564ffbb0b6686d3bb06805249010 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <Gainmap.h>
#ifdef __ANDROID__
#include <binder/Parcel.h>
#endif
#include "Bitmap.h"
#include "GraphicsJNI.h"
#include "ScopedParcel.h"
#include "graphics_jni_helpers.h"
namespace android {
static jclass gGainmap_class;
static jmethodID gGainmap_constructorMethodID;
using namespace uirenderer;
static Gainmap* fromJava(jlong gainmap) {
return reinterpret_cast<Gainmap*>(gainmap);
}
static int getCreateFlags(const sk_sp<Bitmap>& bitmap) {
int flags = 0;
if (bitmap->info().alphaType() == kPremul_SkAlphaType) {
flags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
}
if (!bitmap->isImmutable()) {
flags |= android::bitmap::kBitmapCreateFlag_Mutable;
}
return flags;
}
jobject Gainmap_extractFromBitmap(JNIEnv* env, const Bitmap& bitmap) {
auto gainmap = bitmap.gainmap();
jobject jGainmapImage;
{
// Scope to guard the release of nativeBitmap
auto nativeBitmap = gainmap->bitmap;
const int createFlags = getCreateFlags(nativeBitmap);
jGainmapImage = bitmap::createBitmap(env, nativeBitmap.release(), createFlags);
}
// Grab a ref for the jobject
gainmap->incStrong(0);
jobject obj = env->NewObject(gGainmap_class, gGainmap_constructorMethodID, jGainmapImage,
gainmap.get());
if (env->ExceptionCheck() != 0) {
// sadtrombone
gainmap->decStrong(0);
ALOGE("*** Uncaught exception returned from Java call!\n");
env->ExceptionDescribe();
}
return obj;
}
static void Gainmap_destructor(Gainmap* gainmap) {
gainmap->decStrong(0);
}
static jlong Gainmap_getNativeFinalizer(JNIEnv*, jobject) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Gainmap_destructor));
}
jlong Gainmap_createEmpty(JNIEnv*, jobject) {
Gainmap* gainmap = new Gainmap();
gainmap->incStrong(0);
return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
}
jlong Gainmap_createCopy(JNIEnv*, jobject, jlong sourcePtr) {
Gainmap* gainmap = new Gainmap();
gainmap->incStrong(0);
if (sourcePtr) {
Gainmap* src = fromJava(sourcePtr);
gainmap->info = src->info;
}
return static_cast<jlong>(reinterpret_cast<uintptr_t>(gainmap));
}
static void Gainmap_setBitmap(JNIEnv* env, jobject, jlong gainmapPtr, jobject jBitmap) {
android::Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, jBitmap);
fromJava(gainmapPtr)->bitmap = sk_ref_sp(bitmap);
}
static void Gainmap_setRatioMin(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
fromJava(gainmapPtr)->info.fGainmapRatioMin = {r, g, b, 1.f};
}
static void Gainmap_getRatioMin(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMin;
jfloat buf[3]{value.fR, value.fG, value.fB};
env->SetFloatArrayRegion(components, 0, 3, buf);
}
static void Gainmap_setRatioMax(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
fromJava(gainmapPtr)->info.fGainmapRatioMax = {r, g, b, 1.f};
}
static void Gainmap_getRatioMax(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
const auto value = fromJava(gainmapPtr)->info.fGainmapRatioMax;
jfloat buf[3]{value.fR, value.fG, value.fB};
env->SetFloatArrayRegion(components, 0, 3, buf);
}
static void Gainmap_setGamma(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g, jfloat b) {
fromJava(gainmapPtr)->info.fGainmapGamma = {r, g, b, 1.f};
}
static void Gainmap_getGamma(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
const auto value = fromJava(gainmapPtr)->info.fGainmapGamma;
jfloat buf[3]{value.fR, value.fG, value.fB};
env->SetFloatArrayRegion(components, 0, 3, buf);
}
static void Gainmap_setEpsilonSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
jfloat b) {
fromJava(gainmapPtr)->info.fEpsilonSdr = {r, g, b, 1.f};
}
static void Gainmap_getEpsilonSdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
const auto value = fromJava(gainmapPtr)->info.fEpsilonSdr;
jfloat buf[3]{value.fR, value.fG, value.fB};
env->SetFloatArrayRegion(components, 0, 3, buf);
}
static void Gainmap_setEpsilonHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat r, jfloat g,
jfloat b) {
fromJava(gainmapPtr)->info.fEpsilonHdr = {r, g, b, 1.f};
}
static void Gainmap_getEpsilonHdr(JNIEnv* env, jobject, jlong gainmapPtr, jfloatArray components) {
const auto value = fromJava(gainmapPtr)->info.fEpsilonHdr;
jfloat buf[3]{value.fR, value.fG, value.fB};
env->SetFloatArrayRegion(components, 0, 3, buf);
}
static void Gainmap_setDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat max) {
fromJava(gainmapPtr)->info.fDisplayRatioHdr = max;
}
static jfloat Gainmap_getDisplayRatioHdr(JNIEnv*, jobject, jlong gainmapPtr) {
return fromJava(gainmapPtr)->info.fDisplayRatioHdr;
}
static void Gainmap_setDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr, jfloat min) {
fromJava(gainmapPtr)->info.fDisplayRatioSdr = min;
}
static jfloat Gainmap_getDisplayRatioSdr(JNIEnv*, jobject, jlong gainmapPtr) {
return fromJava(gainmapPtr)->info.fDisplayRatioSdr;
}
// ----------------------------------------------------------------------------
// Serialization
// ----------------------------------------------------------------------------
static void Gainmap_writeToParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
#ifdef __ANDROID__ // Layoutlib does not support parcel
if (parcel == NULL) {
ALOGD("write null parcel\n");
return;
}
ScopedParcel p(env, parcel);
SkGainmapInfo info = fromJava(nativeObject)->info;
// write gainmap to parcel
// ratio min
p.writeFloat(info.fGainmapRatioMin.fR);
p.writeFloat(info.fGainmapRatioMin.fG);
p.writeFloat(info.fGainmapRatioMin.fB);
// ratio max
p.writeFloat(info.fGainmapRatioMax.fR);
p.writeFloat(info.fGainmapRatioMax.fG);
p.writeFloat(info.fGainmapRatioMax.fB);
// gamma
p.writeFloat(info.fGainmapGamma.fR);
p.writeFloat(info.fGainmapGamma.fG);
p.writeFloat(info.fGainmapGamma.fB);
// epsilonsdr
p.writeFloat(info.fEpsilonSdr.fR);
p.writeFloat(info.fEpsilonSdr.fG);
p.writeFloat(info.fEpsilonSdr.fB);
// epsilonhdr
p.writeFloat(info.fEpsilonHdr.fR);
p.writeFloat(info.fEpsilonHdr.fG);
p.writeFloat(info.fEpsilonHdr.fB);
// display ratio sdr
p.writeFloat(info.fDisplayRatioSdr);
// display ratio hdr
p.writeFloat(info.fDisplayRatioHdr);
// base image type
p.writeInt32(static_cast<int32_t>(info.fBaseImageType));
#else
doThrowRE(env, "Cannot use parcels outside of Android!");
#endif
}
static void Gainmap_readFromParcel(JNIEnv* env, jobject, jlong nativeObject, jobject parcel) {
#ifdef __ANDROID__ // Layoutlib does not support parcel
if (parcel == NULL) {
jniThrowNullPointerException(env, "parcel cannot be null");
return;
}
ScopedParcel p(env, parcel);
SkGainmapInfo info;
info.fGainmapRatioMin = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
info.fGainmapRatioMax = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
info.fGainmapGamma = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
info.fEpsilonSdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
info.fEpsilonHdr = {p.readFloat(), p.readFloat(), p.readFloat(), 1.f};
info.fDisplayRatioSdr = p.readFloat();
info.fDisplayRatioHdr = p.readFloat();
info.fBaseImageType = static_cast<SkGainmapInfo::BaseImageType>(p.readInt32());
fromJava(nativeObject)->info = info;
#else
jniThrowRuntimeException(env, "Cannot use parcels outside of Android");
#endif
}
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
static const JNINativeMethod gGainmapMethods[] = {
{"nGetFinalizer", "()J", (void*)Gainmap_getNativeFinalizer},
{"nCreateEmpty", "()J", (void*)Gainmap_createEmpty},
{"nCreateCopy", "(J)J", (void*)Gainmap_createCopy},
{"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*)Gainmap_setBitmap},
{"nSetRatioMin", "(JFFF)V", (void*)Gainmap_setRatioMin},
{"nGetRatioMin", "(J[F)V", (void*)Gainmap_getRatioMin},
{"nSetRatioMax", "(JFFF)V", (void*)Gainmap_setRatioMax},
{"nGetRatioMax", "(J[F)V", (void*)Gainmap_getRatioMax},
{"nSetGamma", "(JFFF)V", (void*)Gainmap_setGamma},
{"nGetGamma", "(J[F)V", (void*)Gainmap_getGamma},
{"nSetEpsilonSdr", "(JFFF)V", (void*)Gainmap_setEpsilonSdr},
{"nGetEpsilonSdr", "(J[F)V", (void*)Gainmap_getEpsilonSdr},
{"nSetEpsilonHdr", "(JFFF)V", (void*)Gainmap_setEpsilonHdr},
{"nGetEpsilonHdr", "(J[F)V", (void*)Gainmap_getEpsilonHdr},
{"nSetDisplayRatioHdr", "(JF)V", (void*)Gainmap_setDisplayRatioHdr},
{"nGetDisplayRatioHdr", "(J)F", (void*)Gainmap_getDisplayRatioHdr},
{"nSetDisplayRatioSdr", "(JF)V", (void*)Gainmap_setDisplayRatioSdr},
{"nGetDisplayRatioSdr", "(J)F", (void*)Gainmap_getDisplayRatioSdr},
{"nWriteGainmapToParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_writeToParcel},
{"nReadGainmapFromParcel", "(JLandroid/os/Parcel;)V", (void*)Gainmap_readFromParcel},
};
int register_android_graphics_Gainmap(JNIEnv* env) {
gGainmap_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Gainmap"));
gGainmap_constructorMethodID =
GetMethodIDOrDie(env, gGainmap_class, "<init>", "(Landroid/graphics/Bitmap;J)V");
return android::RegisterMethodsOrDie(env, "android/graphics/Gainmap", gGainmapMethods,
NELEM(gGainmapMethods));
}
} // namespace android