Make gainmap parcelable.
Bug: 267215989
Test: android.graphics.cts.GainmapTest
Change-Id: I189f652f26f2f92e37afdc3f69ae7b7653d69bf0
diff --git a/core/api/current.txt b/core/api/current.txt
index d54290b..4b160d9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -15497,8 +15497,9 @@
ctor @Deprecated public EmbossMaskFilter(float[], float, float, float);
}
- public final class Gainmap {
+ public final class Gainmap implements android.os.Parcelable {
ctor public Gainmap(@NonNull android.graphics.Bitmap);
+ method public int describeContents();
method @NonNull public float getDisplayRatioForFullHdr();
method @NonNull public float[] getEpsilonHdr();
method @NonNull public float[] getEpsilonSdr();
@@ -15515,6 +15516,8 @@
method @NonNull public void setMinDisplayRatioForHdrTransition(@FloatRange(from=1.0f) float);
method @NonNull public void setRatioMax(float, float, float);
method @NonNull public void setRatioMin(float, float, float);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.graphics.Gainmap> CREATOR;
}
public class HardwareBufferRenderer implements java.lang.AutoCloseable {
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index b1abc2a1..a39dd08 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -2175,23 +2175,26 @@
public static final @NonNull Parcelable.Creator<Bitmap> CREATOR
= new Parcelable.Creator<Bitmap>() {
- /**
- * Rebuilds a bitmap previously stored with writeToParcel().
- *
- * @param p Parcel object to read the bitmap from
- * @return a new bitmap created from the data in the parcel
- */
- public Bitmap createFromParcel(Parcel p) {
- Bitmap bm = nativeCreateFromParcel(p);
- if (bm == null) {
- throw new RuntimeException("Failed to unparcel Bitmap");
- }
- return bm;
- }
- public Bitmap[] newArray(int size) {
- return new Bitmap[size];
- }
- };
+ /**
+ * Rebuilds a bitmap previously stored with writeToParcel().
+ *
+ * @param p Parcel object to read the bitmap from
+ * @return a new bitmap created from the data in the parcel
+ */
+ public Bitmap createFromParcel(Parcel p) {
+ Bitmap bm = nativeCreateFromParcel(p);
+ if (bm == null) {
+ throw new RuntimeException("Failed to unparcel Bitmap");
+ }
+ if (p.readBoolean()) {
+ bm.setGainmap(p.readTypedObject(Gainmap.CREATOR));
+ }
+ return bm;
+ }
+ public Bitmap[] newArray(int size) {
+ return new Bitmap[size];
+ }
+ };
/**
* No special parcel contents.
@@ -2215,6 +2218,12 @@
if (!nativeWriteToParcel(mNativePtr, mDensity, p)) {
throw new RuntimeException("native writeToParcel failed");
}
+ if (hasGainmap()) {
+ p.writeBoolean(true);
+ p.writeTypedObject(mGainmap, flags);
+ } else {
+ p.writeBoolean(false);
+ }
}
/**
diff --git a/graphics/java/android/graphics/Gainmap.java b/graphics/java/android/graphics/Gainmap.java
index 53f23c0..470a06c 100644
--- a/graphics/java/android/graphics/Gainmap.java
+++ b/graphics/java/android/graphics/Gainmap.java
@@ -18,6 +18,8 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
import libcore.util.NativeAllocationRegistry;
@@ -76,7 +78,7 @@
*
* In the above math, log() is a natural logarithm and exp() is natural exponentiation.
*/
-public final class Gainmap {
+public final class Gainmap implements Parcelable {
// Use a Holder to allow static initialization of Gainmap in the boot image.
private static class NoImagePreloadHolder {
@@ -284,6 +286,50 @@
return nGetDisplayRatioSdr(mNativePtr);
}
+ /**
+ * No special parcel contents.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write the gainmap to the parcel.
+ *
+ * @param dest Parcel object to write the gainmap data into
+ * @param flags Additional flags about how the object should be written.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ if (mNativePtr == 0) {
+ throw new IllegalStateException("Cannot be written to a parcel");
+ }
+ dest.writeTypedObject(mGainmapContents, flags);
+ // write gainmapinfo into parcel
+ nWriteGainmapToParcel(mNativePtr, dest);
+ }
+
+ public static final @NonNull Parcelable.Creator<Gainmap> CREATOR =
+ new Parcelable.Creator<Gainmap>() {
+ /**
+ * Rebuilds a gainmap previously stored with writeToParcel().
+ *
+ * @param in Parcel object to read the gainmap from
+ * @return a new gainmap created from the data in the parcel
+ */
+ public Gainmap createFromParcel(Parcel in) {
+ Gainmap gm = new Gainmap(in.readTypedObject(Bitmap.CREATOR));
+ // read gainmapinfo from parcel
+ nReadGainmapFromParcel(gm.mNativePtr, in);
+ return gm;
+ }
+
+ public Gainmap[] newArray(int size) {
+ return new Gainmap[size];
+ }
+ };
+
private static native long nGetFinalizer();
private static native long nCreateEmpty();
@@ -309,4 +355,6 @@
private static native void nSetDisplayRatioSdr(long ptr, float min);
private static native float nGetDisplayRatioSdr(long ptr);
+ private static native void nWriteGainmapToParcel(long ptr, Parcel dest);
+ private static native void nReadGainmapFromParcel(long ptr, Parcel src);
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 9e3f115..b221654 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -364,6 +364,7 @@
"jni/PathMeasure.cpp",
"jni/Picture.cpp",
"jni/Region.cpp",
+ "jni/ScopedParcel.cpp",
"jni/Shader.cpp",
"jni/RenderEffect.cpp",
"jni/Typeface.cpp",
diff --git a/libs/hwui/jni/Bitmap.cpp b/libs/hwui/jni/Bitmap.cpp
index e71a2a5..3f9c4bd 100644
--- a/libs/hwui/jni/Bitmap.cpp
+++ b/libs/hwui/jni/Bitmap.cpp
@@ -10,6 +10,7 @@
#include "Gainmap.h"
#include "GraphicsJNI.h"
#include "HardwareBufferHelpers.h"
+#include "ScopedParcel.h"
#include "SkBitmap.h"
#include "SkBlendMode.h"
#include "SkCanvas.h"
@@ -27,12 +28,7 @@
#ifdef __ANDROID__ // Layoutlib does not support graphic buffer, parcel or render thread
#include <android-base/unique_fd.h>
-#include <android/binder_parcel.h>
-#include <android/binder_parcel_jni.h>
-#include <android/binder_parcel_platform.h>
-#include <cutils/ashmem.h>
#include <renderthread/RenderProxy.h>
-#include <sys/mman.h>
#endif
#include <inttypes.h>
@@ -616,91 +612,7 @@
///////////////////////////////////////////////////////////////////////////////
// TODO: Move somewhere else
-#ifdef __ANDROID__ // Layoutlib does not support parcel
-
-class ScopedParcel {
-public:
- explicit ScopedParcel(JNIEnv* env, jobject parcel) {
- mParcel = AParcel_fromJavaParcel(env, parcel);
- }
-
- ~ScopedParcel() { AParcel_delete(mParcel); }
-
- int32_t readInt32() {
- int32_t temp = 0;
- // TODO: This behavior-matches what android::Parcel does
- // but this should probably be better
- if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
- temp = 0;
- }
- return temp;
- }
-
- uint32_t readUint32() {
- uint32_t temp = 0;
- // TODO: This behavior-matches what android::Parcel does
- // but this should probably be better
- if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
- temp = 0;
- }
- return temp;
- }
-
- void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
-
- void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
-
- bool allowFds() const { return AParcel_getAllowFds(mParcel); }
-
- std::optional<sk_sp<SkData>> readData() {
- struct Data {
- void* ptr = nullptr;
- size_t size = 0;
- } data;
- auto error = AParcel_readByteArray(mParcel, &data,
- [](void* arrayData, int32_t length,
- int8_t** outBuffer) -> bool {
- Data* data = reinterpret_cast<Data*>(arrayData);
- if (length > 0) {
- data->ptr = sk_malloc_canfail(length);
- if (!data->ptr) {
- return false;
- }
- *outBuffer =
- reinterpret_cast<int8_t*>(data->ptr);
- data->size = length;
- }
- return true;
- });
- if (error != STATUS_OK || data.size <= 0) {
- sk_free(data.ptr);
- return std::nullopt;
- } else {
- return SkData::MakeFromMalloc(data.ptr, data.size);
- }
- }
-
- void writeData(const std::optional<sk_sp<SkData>>& optData) {
- if (optData) {
- const auto& data = *optData;
- AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
- data->size());
- } else {
- AParcel_writeByteArray(mParcel, nullptr, -1);
- }
- }
-
- AParcel* get() { return mParcel; }
-
-private:
- AParcel* mParcel;
-};
-
-enum class BlobType : int32_t {
- IN_PLACE,
- ASHMEM,
-};
-
+#ifdef __ANDROID__ // Layoutlib does not support parcel
#define ON_ERROR_RETURN(X) \
if ((error = (X)) != STATUS_OK) return error
diff --git a/libs/hwui/jni/Gainmap.cpp b/libs/hwui/jni/Gainmap.cpp
index 9cd3fb0..0f8a85d 100644
--- a/libs/hwui/jni/Gainmap.cpp
+++ b/libs/hwui/jni/Gainmap.cpp
@@ -16,8 +16,13 @@
#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 {
@@ -154,6 +159,81 @@
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));
+ // type
+ p.writeInt32(static_cast<int32_t>(info.fType));
+#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());
+ info.fType = static_cast<SkGainmapInfo::Type>(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},
@@ -172,6 +252,8 @@
{"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) {
diff --git a/libs/hwui/jni/ScopedParcel.cpp b/libs/hwui/jni/ScopedParcel.cpp
new file mode 100644
index 0000000..b0f5423
--- /dev/null
+++ b/libs/hwui/jni/ScopedParcel.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "ScopedParcel.h"
+
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+
+using namespace android;
+
+int32_t ScopedParcel::readInt32() {
+ int32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readInt32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+}
+
+uint32_t ScopedParcel::readUint32() {
+ uint32_t temp = 0;
+ // TODO: This behavior-matches what android::Parcel does
+ // but this should probably be better
+ if (AParcel_readUint32(mParcel, &temp) != STATUS_OK) {
+ temp = 0;
+ }
+ return temp;
+}
+
+float ScopedParcel::readFloat() {
+ float temp = 0.;
+ if (AParcel_readFloat(mParcel, &temp) != STATUS_OK) {
+ temp = 0.;
+ }
+ return temp;
+}
+
+std::optional<sk_sp<SkData>> ScopedParcel::readData() {
+ struct Data {
+ void* ptr = nullptr;
+ size_t size = 0;
+ } data;
+ auto error = AParcel_readByteArray(
+ mParcel, &data, [](void* arrayData, int32_t length, int8_t** outBuffer) -> bool {
+ Data* data = reinterpret_cast<Data*>(arrayData);
+ if (length > 0) {
+ data->ptr = sk_malloc_canfail(length);
+ if (!data->ptr) {
+ return false;
+ }
+ *outBuffer = reinterpret_cast<int8_t*>(data->ptr);
+ data->size = length;
+ }
+ return true;
+ });
+ if (error != STATUS_OK || data.size <= 0) {
+ sk_free(data.ptr);
+ return std::nullopt;
+ } else {
+ return SkData::MakeFromMalloc(data.ptr, data.size);
+ }
+}
+
+void ScopedParcel::writeData(const std::optional<sk_sp<SkData>>& optData) {
+ if (optData) {
+ const auto& data = *optData;
+ AParcel_writeByteArray(mParcel, reinterpret_cast<const int8_t*>(data->data()),
+ data->size());
+ } else {
+ AParcel_writeByteArray(mParcel, nullptr, -1);
+ }
+}
+#endif // __ANDROID__ // Layoutlib does not support parcel
diff --git a/libs/hwui/jni/ScopedParcel.h b/libs/hwui/jni/ScopedParcel.h
new file mode 100644
index 0000000..fd8d6a2
--- /dev/null
+++ b/libs/hwui/jni/ScopedParcel.h
@@ -0,0 +1,63 @@
+/*
+ * 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 "SkData.h"
+
+#ifdef __ANDROID__ // Layoutlib does not support parcel
+#include <android-base/unique_fd.h>
+#include <android/binder_parcel.h>
+#include <android/binder_parcel_jni.h>
+#include <android/binder_parcel_platform.h>
+#include <cutils/ashmem.h>
+#include <renderthread/RenderProxy.h>
+
+class ScopedParcel {
+public:
+ explicit ScopedParcel(JNIEnv* env, jobject parcel) {
+ mParcel = AParcel_fromJavaParcel(env, parcel);
+ }
+
+ ~ScopedParcel() { AParcel_delete(mParcel); }
+
+ int32_t readInt32();
+
+ uint32_t readUint32();
+
+ float readFloat();
+
+ void writeInt32(int32_t value) { AParcel_writeInt32(mParcel, value); }
+
+ void writeUint32(uint32_t value) { AParcel_writeUint32(mParcel, value); }
+
+ void writeFloat(float value) { AParcel_writeFloat(mParcel, value); }
+
+ bool allowFds() const { return AParcel_getAllowFds(mParcel); }
+
+ std::optional<sk_sp<SkData>> readData();
+
+ void writeData(const std::optional<sk_sp<SkData>>& optData);
+
+ AParcel* get() { return mParcel; }
+
+private:
+ AParcel* mParcel;
+};
+
+enum class BlobType : int32_t {
+ IN_PLACE,
+ ASHMEM,
+};
+
+#endif // __ANDROID__ // Layoutlib does not support parcel
\ No newline at end of file