Merge "Wrap RenderArea creation in a builder pattern" into main
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index de0aafa..a1c10f5 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -79,7 +79,10 @@
cc_defaults {
name: "dumpstate_defaults",
- defaults: ["dumpstate_cflag_defaults"],
+ defaults: [
+ "aconfig_lib_cc_static_link.defaults",
+ "dumpstate_cflag_defaults",
+ ],
shared_libs: [
"android.hardware.dumpstate@1.0",
"android.hardware.dumpstate@1.1",
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index d4f30ef..01f523b 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -58,7 +58,7 @@
#define __INTRODUCED_IN(__api_level) /* nothing */
#endif
#if !defined(__DEPRECATED_IN)
-#define __DEPRECATED_IN(__api_level) __attribute__((__deprecated__))
+#define __DEPRECATED_IN(__api_level, ...) __attribute__((__deprecated__))
#endif
__BEGIN_DECLS
@@ -133,7 +133,7 @@
*/
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data)
- __INTRODUCED_IN(24) __DEPRECATED_IN(29);
+ __INTRODUCED_IN(24) __DEPRECATED_IN(29, "Use AChoreographer_postFrameCallback64 instead");
/**
* Deprecated: Use AChoreographer_postFrameCallbackDelayed64 instead.
@@ -141,7 +141,7 @@
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data,
long delayMillis) __INTRODUCED_IN(24)
- __DEPRECATED_IN(29);
+ __DEPRECATED_IN(29, "Use AChoreographer_postFrameCallbackDelayed64 instead");
/**
* Post a callback to be run on the next frame. The data pointer provided will
diff --git a/include/android/looper.h b/include/android/looper.h
index e50730d..6a02916 100644
--- a/include/android/looper.h
+++ b/include/android/looper.h
@@ -35,7 +35,7 @@
// This file may also be built on glibc or on Windows/MacOS libc's, so
// deprecated definitions are provided.
#if !defined(__REMOVED_IN)
-#define __REMOVED_IN(__api_level) __attribute__((__deprecated__))
+#define __REMOVED_IN(__api_level, msg) __attribute__((__deprecated__(msg)))
#endif
struct ALooper;
@@ -213,7 +213,8 @@
* Removed in API 34 as ALooper_pollAll can swallow ALooper_wake calls.
* Use ALooper_pollOnce instead.
*/
-int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) __REMOVED_IN(1);
+int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData)
+ __REMOVED_IN(1, "ALooper_pollAll may ignore wakes. Use ALooper_pollOnce instead. See https://github.com/android/ndk/discussions/2020 for more information");
/**
* Wakes the poll asynchronously.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index a618393..e3c1ccf 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -60,7 +60,7 @@
#define __INTRODUCED_IN(__api_level) /* nothing */
#endif
#if !defined(__DEPRECATED_IN)
-#define __DEPRECATED_IN(__api_level) __attribute__((__deprecated__))
+#define __DEPRECATED_IN(__api_level, msg) __attribute__((__deprecated__(msg)))
#endif
#ifdef __cplusplus
@@ -748,7 +748,8 @@
* ASensorManager* sensorManager = ASensorManager_getInstance();
*
*/
-ASensorManager* ASensorManager_getInstance() __DEPRECATED_IN(26);
+ASensorManager* ASensorManager_getInstance()
+ __DEPRECATED_IN(26, "Use ASensorManager_getInstanceForPackage instead");
/**
* Get a reference to the sensor manager. ASensorManager is a singleton
diff --git a/include/ftl/algorithm.h b/include/ftl/algorithm.h
index c0f6768..68826bb 100644
--- a/include/ftl/algorithm.h
+++ b/include/ftl/algorithm.h
@@ -24,6 +24,18 @@
namespace android::ftl {
+// Determines if a container contains a value. This is a simplified version of the C++23
+// std::ranges::contains function.
+//
+// const ftl::StaticVector vector = {1, 2, 3};
+// assert(ftl::contains(vector, 1));
+//
+// TODO: Remove in C++23.
+template <typename Container, typename Value>
+auto contains(const Container& container, const Value& value) -> bool {
+ return std::find(container.begin(), container.end(), value) != container.end();
+}
+
// Adapter for std::find_if that converts the return value from iterator to optional.
//
// const ftl::StaticVector vector = {"upside"sv, "down"sv, "cake"sv};
diff --git a/include/ftl/details/hash.h b/include/ftl/details/hash.h
new file mode 100644
index 0000000..f9a7fa8
--- /dev/null
+++ b/include/ftl/details/hash.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include <cinttypes>
+#include <cstring>
+
+namespace android::ftl::details {
+
+// Based on CityHash64 v1.0.1 (http://code.google.com/p/cityhash/), but slightly
+// modernized and trimmed for cases with bounded lengths.
+
+template <typename T = std::uint64_t>
+inline T read_unaligned(const void* ptr) {
+ T v;
+ std::memcpy(&v, ptr, sizeof(T));
+ return v;
+}
+
+template <bool NonZeroShift = false>
+constexpr std::uint64_t rotate(std::uint64_t v, std::uint8_t shift) {
+ if constexpr (!NonZeroShift) {
+ if (shift == 0) return v;
+ }
+ return (v >> shift) | (v << (64 - shift));
+}
+
+constexpr std::uint64_t shift_mix(std::uint64_t v) {
+ return v ^ (v >> 47);
+}
+
+constexpr std::uint64_t hash_length_16(std::uint64_t u, std::uint64_t v) {
+ constexpr std::uint64_t kPrime = 0x9ddfea08eb382d69ull;
+ auto a = (u ^ v) * kPrime;
+ a ^= (a >> 47);
+ auto b = (v ^ a) * kPrime;
+ b ^= (b >> 47);
+ b *= kPrime;
+ return b;
+}
+
+constexpr std::uint64_t kPrime0 = 0xc3a5c85c97cb3127ull;
+constexpr std::uint64_t kPrime1 = 0xb492b66fbe98f273ull;
+constexpr std::uint64_t kPrime2 = 0x9ae16a3b2f90404full;
+constexpr std::uint64_t kPrime3 = 0xc949d7c7509e6557ull;
+
+inline std::uint64_t hash_length_0_to_16(const char* str, std::uint64_t length) {
+ if (length > 8) {
+ const auto a = read_unaligned(str);
+ const auto b = read_unaligned(str + length - 8);
+ return hash_length_16(a, rotate<true>(b + length, static_cast<std::uint8_t>(length))) ^ b;
+ }
+ if (length >= 4) {
+ const auto a = read_unaligned<std::uint32_t>(str);
+ const auto b = read_unaligned<std::uint32_t>(str + length - 4);
+ return hash_length_16(length + (a << 3), b);
+ }
+ if (length > 0) {
+ const auto a = static_cast<unsigned char>(str[0]);
+ const auto b = static_cast<unsigned char>(str[length >> 1]);
+ const auto c = static_cast<unsigned char>(str[length - 1]);
+ const auto y = static_cast<std::uint32_t>(a) + (static_cast<std::uint32_t>(b) << 8);
+ const auto z = static_cast<std::uint32_t>(length) + (static_cast<std::uint32_t>(c) << 2);
+ return shift_mix(y * kPrime2 ^ z * kPrime3) * kPrime2;
+ }
+ return kPrime2;
+}
+
+inline std::uint64_t hash_length_17_to_32(const char* str, std::uint64_t length) {
+ const auto a = read_unaligned(str) * kPrime1;
+ const auto b = read_unaligned(str + 8);
+ const auto c = read_unaligned(str + length - 8) * kPrime2;
+ const auto d = read_unaligned(str + length - 16) * kPrime0;
+ return hash_length_16(rotate(a - b, 43) + rotate(c, 30) + d,
+ a + rotate(b ^ kPrime3, 20) - c + length);
+}
+
+inline std::uint64_t hash_length_33_to_64(const char* str, std::uint64_t length) {
+ auto z = read_unaligned(str + 24);
+ auto a = read_unaligned(str) + (length + read_unaligned(str + length - 16)) * kPrime0;
+ auto b = rotate(a + z, 52);
+ auto c = rotate(a, 37);
+
+ a += read_unaligned(str + 8);
+ c += rotate(a, 7);
+ a += read_unaligned(str + 16);
+
+ const auto vf = a + z;
+ const auto vs = b + rotate(a, 31) + c;
+
+ a = read_unaligned(str + 16) + read_unaligned(str + length - 32);
+ z += read_unaligned(str + length - 8);
+ b = rotate(a + z, 52);
+ c = rotate(a, 37);
+ a += read_unaligned(str + length - 24);
+ c += rotate(a, 7);
+ a += read_unaligned(str + length - 16);
+
+ const auto wf = a + z;
+ const auto ws = b + rotate(a, 31) + c;
+ const auto r = shift_mix((vf + ws) * kPrime2 + (wf + vs) * kPrime0);
+ return shift_mix(r * kPrime0 + vs) * kPrime2;
+}
+
+} // namespace android::ftl::details
diff --git a/include/ftl/hash.h b/include/ftl/hash.h
new file mode 100644
index 0000000..29a6f71
--- /dev/null
+++ b/include/ftl/hash.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include <cinttypes>
+#include <optional>
+#include <string_view>
+
+#include <ftl/details/hash.h>
+
+namespace android::ftl {
+
+// Non-cryptographic hash function (namely CityHash64) for strings with at most 64 characters.
+// Unlike std::hash, which returns std::size_t and is only required to produce the same result
+// for the same input within a single execution of a program, this hash is stable.
+inline std::optional<std::uint64_t> stable_hash(std::string_view view) {
+ const auto length = view.length();
+ if (length <= 16) {
+ return details::hash_length_0_to_16(view.data(), length);
+ }
+ if (length <= 32) {
+ return details::hash_length_17_to_32(view.data(), length);
+ }
+ if (length <= 64) {
+ return details::hash_length_33_to_64(view.data(), length);
+ }
+ return {};
+}
+
+} // namespace android::ftl
diff --git a/include/ftl/non_null.h b/include/ftl/non_null.h
index 35d09d7..4a5d8bf 100644
--- a/include/ftl/non_null.h
+++ b/include/ftl/non_null.h
@@ -68,26 +68,28 @@
constexpr NonNull(const NonNull&) = default;
constexpr NonNull& operator=(const NonNull&) = default;
- constexpr const Pointer& get() const { return pointer_; }
- constexpr explicit operator const Pointer&() const { return get(); }
+ [[nodiscard]] constexpr const Pointer& get() const { return pointer_; }
+ [[nodiscard]] constexpr explicit operator const Pointer&() const { return get(); }
// Move operations. These break the invariant, so care must be taken to avoid subsequent access.
constexpr NonNull(NonNull&&) = default;
constexpr NonNull& operator=(NonNull&&) = default;
- constexpr Pointer take() && { return std::move(pointer_); }
- constexpr explicit operator Pointer() && { return take(); }
+ [[nodiscard]] constexpr Pointer take() && { return std::move(pointer_); }
+ [[nodiscard]] constexpr explicit operator Pointer() && { return take(); }
// Dereferencing.
- constexpr decltype(auto) operator*() const { return *get(); }
- constexpr decltype(auto) operator->() const { return get(); }
+ [[nodiscard]] constexpr decltype(auto) operator*() const { return *get(); }
+ [[nodiscard]] constexpr decltype(auto) operator->() const { return get(); }
+
+ [[nodiscard]] constexpr explicit operator bool() const { return !(pointer_ == nullptr); }
// Private constructor for ftl::as_non_null. Excluded from candidate constructors for conversions
// through the passkey idiom, for clear compilation errors.
template <typename P>
constexpr NonNull(Passkey, P&& pointer) : pointer_(std::forward<P>(pointer)) {
- if (!pointer_) std::abort();
+ if (pointer_ == nullptr) std::abort();
}
private:
@@ -98,11 +100,13 @@
};
template <typename P>
-constexpr auto as_non_null(P&& pointer) -> NonNull<std::decay_t<P>> {
+[[nodiscard]] constexpr auto as_non_null(P&& pointer) -> NonNull<std::decay_t<P>> {
using Passkey = typename NonNull<std::decay_t<P>>::Passkey;
return {Passkey{}, std::forward<P>(pointer)};
}
+// NonNull<P> <=> NonNull<Q>
+
template <typename P, typename Q>
constexpr bool operator==(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
return lhs.get() == rhs.get();
@@ -113,4 +117,96 @@
return !operator==(lhs, rhs);
}
+template <typename P, typename Q>
+constexpr bool operator<(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
+ return lhs.get() < rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator<=(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
+ return lhs.get() <= rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator>=(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
+ return lhs.get() >= rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator>(const NonNull<P>& lhs, const NonNull<Q>& rhs) {
+ return lhs.get() > rhs.get();
+}
+
+// NonNull<P> <=> Q
+
+template <typename P, typename Q>
+constexpr bool operator==(const NonNull<P>& lhs, const Q& rhs) {
+ return lhs.get() == rhs;
+}
+
+template <typename P, typename Q>
+constexpr bool operator!=(const NonNull<P>& lhs, const Q& rhs) {
+ return lhs.get() != rhs;
+}
+
+template <typename P, typename Q>
+constexpr bool operator<(const NonNull<P>& lhs, const Q& rhs) {
+ return lhs.get() < rhs;
+}
+
+template <typename P, typename Q>
+constexpr bool operator<=(const NonNull<P>& lhs, const Q& rhs) {
+ return lhs.get() <= rhs;
+}
+
+template <typename P, typename Q>
+constexpr bool operator>=(const NonNull<P>& lhs, const Q& rhs) {
+ return lhs.get() >= rhs;
+}
+
+template <typename P, typename Q>
+constexpr bool operator>(const NonNull<P>& lhs, const Q& rhs) {
+ return lhs.get() > rhs;
+}
+
+// P <=> NonNull<Q>
+
+template <typename P, typename Q>
+constexpr bool operator==(const P& lhs, const NonNull<Q>& rhs) {
+ return lhs == rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator!=(const P& lhs, const NonNull<Q>& rhs) {
+ return lhs != rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator<(const P& lhs, const NonNull<Q>& rhs) {
+ return lhs < rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator<=(const P& lhs, const NonNull<Q>& rhs) {
+ return lhs <= rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator>=(const P& lhs, const NonNull<Q>& rhs) {
+ return lhs >= rhs.get();
+}
+
+template <typename P, typename Q>
+constexpr bool operator>(const P& lhs, const NonNull<Q>& rhs) {
+ return lhs > rhs.get();
+}
+
} // namespace android::ftl
+
+// Specialize std::hash for ftl::NonNull<T>
+template <typename P>
+struct std::hash<android::ftl::NonNull<P>> {
+ std::size_t operator()(const android::ftl::NonNull<P>& ptr) const {
+ return std::hash<P>()(ptr.get());
+ }
+};
diff --git a/include/input/Input.h b/include/input/Input.h
index 00757a7..3f81fb0 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -43,7 +43,7 @@
#ifdef __linux__
/* This event was generated or modified by accessibility service. */
AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
- android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+ android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT,
#else
AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800,
#endif
@@ -54,11 +54,11 @@
AKEY_EVENT_FLAG_START_TRACKING = 0x40000000,
/* Key event is inconsistent with previously sent key events. */
- AKEY_EVENT_FLAG_TAINTED = 0x80000000,
+ AKEY_EVENT_FLAG_TAINTED = android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED,
};
enum {
-
+ // AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED is defined in include/android/input.h
/**
* This flag indicates that the window that received this motion event is partly
* or wholly obscured by another visible window above it. This flag is set to true
@@ -69,13 +69,16 @@
* to drop the suspect touches or to take additional precautions to confirm the user's
* actual intent.
*/
- AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2,
-
+ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED =
+ android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED,
+ AMOTION_EVENT_FLAG_HOVER_EXIT_PENDING =
+ android::os::IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING,
/**
* This flag indicates that the event has been generated by a gesture generator. It
* provides a hint to the GestureDetector to not apply any touch slop.
*/
- AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8,
+ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE =
+ android::os::IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE,
/**
* This flag indicates that the event will not cause a focus change if it is directed to an
@@ -83,20 +86,24 @@
* gestures to allow the user to direct gestures to an unfocused window without bringing it
* into focus.
*/
- AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40,
+ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE =
+ android::os::IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE,
#if defined(__linux__)
/**
* This event was generated or modified by accessibility service.
*/
AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT =
- android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, // 0x800,
+ android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT,
#else
AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800,
#endif
+ AMOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS =
+ android::os::IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS,
+
/* Motion event is inconsistent with previously sent motion events. */
- AMOTION_EVENT_FLAG_TAINTED = 0x80000000,
+ AMOTION_EVENT_FLAG_TAINTED = android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED,
};
/**
@@ -116,9 +123,10 @@
/**
* This flag indicates that the point up event has been canceled.
* Typically this is used for palm event when the user has accidental touches.
- * TODO: Adjust flag to public api
+ * TODO(b/338143308): Add this to NDK
*/
-constexpr int32_t AMOTION_EVENT_FLAG_CANCELED = 0x20;
+constexpr int32_t AMOTION_EVENT_FLAG_CANCELED =
+ android::os::IInputConstants::INPUT_EVENT_FLAG_CANCELED;
enum {
/*
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index b6b4121..e93fe8c 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -130,8 +130,9 @@
INPUT = 0,
PLAYER_ID = 1,
KEYBOARD_BACKLIGHT = 2,
+ KEYBOARD_MIC_MUTE = 3,
- ftl_last = KEYBOARD_BACKLIGHT
+ ftl_last = KEYBOARD_MIC_MUTE
};
enum class InputDeviceLightCapability : uint32_t {
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 57a48d7..090e35b 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -446,7 +446,7 @@
},
}
-cc_library_static {
+cc_library {
name: "libbinder_rpc_no_kernel",
vendor_available: true,
defaults: [
@@ -458,7 +458,7 @@
],
}
-cc_library_static {
+cc_library {
name: "libbinder_rpc_no_blob",
vendor_available: true,
defaults: [
@@ -474,7 +474,7 @@
],
}
-cc_library_static {
+cc_library {
name: "libbinder_rpc_no_native_handle",
vendor_available: true,
defaults: [
@@ -490,7 +490,7 @@
],
}
-cc_library_static {
+cc_library {
name: "libbinder_rpc_single_threaded",
defaults: [
"libbinder_common_defaults",
@@ -505,7 +505,7 @@
],
}
-cc_library_static {
+cc_library {
name: "libbinder_rpc_single_threaded_no_kernel",
defaults: [
"libbinder_common_defaults",
diff --git a/libs/binder/liblog_stub/include/log/log.h b/libs/binder/liblog_stub/include/log/log.h
index 91c9632..dad0020 100644
--- a/libs/binder/liblog_stub/include/log/log.h
+++ b/libs/binder/liblog_stub/include/log/log.h
@@ -54,16 +54,16 @@
#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
-#define ALOG(priority, tag, fmt, ...) \
- do { \
- if (false)[[/*VERY*/ unlikely]] { /* ignore unused __VA_ARGS__ */ \
- std::fprintf(stderr, fmt __VA_OPT__(, ) __VA_ARGS__); \
- } \
- IF_ALOG(priority, tag) { \
- __android_log_print(ANDROID_##priority, tag, \
- tag ": " fmt "\n" __VA_OPT__(, ) __VA_ARGS__); \
- } \
- if constexpr (ANDROID_##priority == ANDROID_LOG_FATAL) std::abort(); \
+#define ALOG(priority, tag, fmt, ...) \
+ do { \
+ if (false)[[/*VERY*/ unlikely]] { /* ignore unused __VA_ARGS__ */ \
+ std::fprintf(stderr, fmt __VA_OPT__(, ) __VA_ARGS__); \
+ } \
+ IF_ALOG(priority, tag) { \
+ __android_log_print(ANDROID_##priority, tag, "%s: " fmt "\n", \
+ (tag)__VA_OPT__(, ) __VA_ARGS__); \
+ } \
+ if constexpr (ANDROID_##priority == ANDROID_LOG_FATAL) std::abort(); \
} while (false)
#define ALOGV(...) ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define ALOGD(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index c665ad8..52edae4 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,11 +18,8 @@
#include <android/binder_ibinder.h>
#include <android/binder_status.h>
-#include <sys/cdefs.h>
-
-#ifndef __TRUSTY__
#include <android/llndk-versioning.h>
-#endif
+#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 35002eb..6800a8d 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -200,9 +200,11 @@
defaults: [
"binder_test_defaults",
],
+ header_libs: [
+ "libbinder_headers_base",
+ ],
shared_libs: [
"libbase",
- "liblog",
],
srcs: [
"FileUtils.cpp",
diff --git a/libs/binder/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
new file mode 100644
index 0000000..3ae3d8f
--- /dev/null
+++ b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+#pragma once
+
+#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
diff --git a/libs/binder/trusty/ndk/include/sys/cdefs.h b/libs/binder/trusty/ndk/include/sys/cdefs.h
index 7528f2b..4e9b0e8 100644
--- a/libs/binder/trusty/ndk/include/sys/cdefs.h
+++ b/libs/binder/trusty/ndk/include/sys/cdefs.h
@@ -27,4 +27,3 @@
#endif
#define __INTRODUCED_IN(x) /* nothing on Trusty */
-#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 32b2b68..4b41152 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -24,6 +24,7 @@
"flags_test.cpp",
"function_test.cpp",
"future_test.cpp",
+ "hash_test.cpp",
"match_test.cpp",
"mixins_test.cpp",
"non_null_test.cpp",
diff --git a/libs/ftl/algorithm_test.cpp b/libs/ftl/algorithm_test.cpp
index 487b1b8..11569f2 100644
--- a/libs/ftl/algorithm_test.cpp
+++ b/libs/ftl/algorithm_test.cpp
@@ -24,6 +24,17 @@
namespace android::test {
// Keep in sync with example usage in header file.
+TEST(Algorithm, Contains) {
+ const ftl::StaticVector vector = {1, 2, 3};
+ EXPECT_TRUE(ftl::contains(vector, 1));
+
+ EXPECT_FALSE(ftl::contains(vector, 0));
+ EXPECT_TRUE(ftl::contains(vector, 2));
+ EXPECT_TRUE(ftl::contains(vector, 3));
+ EXPECT_FALSE(ftl::contains(vector, 4));
+}
+
+// Keep in sync with example usage in header file.
TEST(Algorithm, FindIf) {
using namespace std::string_view_literals;
diff --git a/libs/ftl/hash_test.cpp b/libs/ftl/hash_test.cpp
new file mode 100644
index 0000000..9c7b8c2
--- /dev/null
+++ b/libs/ftl/hash_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024 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 <ftl/hash.h>
+#include <gtest/gtest.h>
+
+#include <numeric>
+#include <string>
+
+namespace android::test {
+
+TEST(Hash, StableHash) {
+ EXPECT_EQ(11160318154034397263ull, (ftl::stable_hash({})));
+
+ std::string string(64, '?');
+ std::iota(string.begin(), string.end(), 'A');
+
+ // Maximum length is 64 characters.
+ EXPECT_FALSE(ftl::stable_hash(string + '\n'));
+
+ EXPECT_EQ(6278090252846864564ull, ftl::stable_hash(std::string_view(string).substr(0, 8)));
+ EXPECT_EQ(1883356980931444616ull, ftl::stable_hash(std::string_view(string).substr(0, 16)));
+ EXPECT_EQ(8073093283835059304ull, ftl::stable_hash(std::string_view(string).substr(0, 32)));
+ EXPECT_EQ(18197365392429149980ull, ftl::stable_hash(string));
+}
+
+} // namespace android::test
diff --git a/libs/ftl/non_null_test.cpp b/libs/ftl/non_null_test.cpp
index bd0462b..367b398 100644
--- a/libs/ftl/non_null_test.cpp
+++ b/libs/ftl/non_null_test.cpp
@@ -14,12 +14,17 @@
* limitations under the License.
*/
+#include <ftl/algorithm.h>
#include <ftl/non_null.h>
#include <gtest/gtest.h>
#include <memory>
+#include <set>
#include <string>
#include <string_view>
+#include <type_traits>
+#include <unordered_set>
+#include <vector>
namespace android::test {
namespace {
@@ -47,7 +52,7 @@
// Keep in sync with example usage in header file.
TEST(NonNull, Example) {
const auto string_ptr = ftl::as_non_null(std::make_shared<std::string>("android"));
- std::size_t size;
+ std::size_t size{};
get_length(string_ptr, ftl::as_non_null(&size));
EXPECT_EQ(size, 7u);
@@ -71,5 +76,84 @@
static_assert(longest(kApplePtr, kOrangePtr) == kOrangePtr);
+static_assert(static_cast<bool>(kApplePtr));
+
+static_assert(std::is_same_v<decltype(ftl::as_non_null(std::declval<const int* const>())),
+ ftl::NonNull<const int*>>);
+
} // namespace
+
+TEST(NonNull, SwapRawPtr) {
+ int i1 = 123;
+ int i2 = 456;
+ auto ptr1 = ftl::as_non_null(&i1);
+ auto ptr2 = ftl::as_non_null(&i2);
+
+ std::swap(ptr1, ptr2);
+
+ EXPECT_EQ(*ptr1, 456);
+ EXPECT_EQ(*ptr2, 123);
+}
+
+TEST(NonNull, SwapSmartPtr) {
+ auto ptr1 = ftl::as_non_null(std::make_shared<int>(123));
+ auto ptr2 = ftl::as_non_null(std::make_shared<int>(456));
+
+ std::swap(ptr1, ptr2);
+
+ EXPECT_EQ(*ptr1, 456);
+ EXPECT_EQ(*ptr2, 123);
+}
+
+TEST(NonNull, VectorOfRawPtr) {
+ int i = 1;
+ std::vector<ftl::NonNull<int*>> vpi;
+ vpi.push_back(ftl::as_non_null(&i));
+ EXPECT_FALSE(ftl::contains(vpi, nullptr));
+ EXPECT_TRUE(ftl::contains(vpi, &i));
+ EXPECT_TRUE(ftl::contains(vpi, vpi.front()));
+}
+
+TEST(NonNull, VectorOfSmartPtr) {
+ std::vector<ftl::NonNull<std::shared_ptr<int>>> vpi;
+ vpi.push_back(ftl::as_non_null(std::make_shared<int>(2)));
+ EXPECT_FALSE(ftl::contains(vpi, nullptr));
+ EXPECT_TRUE(ftl::contains(vpi, vpi.front().get()));
+ EXPECT_TRUE(ftl::contains(vpi, vpi.front()));
+}
+
+TEST(NonNull, SetOfRawPtr) {
+ int i = 1;
+ std::set<ftl::NonNull<int*>> spi;
+ spi.insert(ftl::as_non_null(&i));
+ EXPECT_FALSE(ftl::contains(spi, nullptr));
+ EXPECT_TRUE(ftl::contains(spi, &i));
+ EXPECT_TRUE(ftl::contains(spi, *spi.begin()));
+}
+
+TEST(NonNull, SetOfSmartPtr) {
+ std::set<ftl::NonNull<std::shared_ptr<int>>> spi;
+ spi.insert(ftl::as_non_null(std::make_shared<int>(2)));
+ EXPECT_FALSE(ftl::contains(spi, nullptr));
+ EXPECT_TRUE(ftl::contains(spi, spi.begin()->get()));
+ EXPECT_TRUE(ftl::contains(spi, *spi.begin()));
+}
+
+TEST(NonNull, UnorderedSetOfRawPtr) {
+ int i = 1;
+ std::unordered_set<ftl::NonNull<int*>> spi;
+ spi.insert(ftl::as_non_null(&i));
+ EXPECT_FALSE(ftl::contains(spi, nullptr));
+ EXPECT_TRUE(ftl::contains(spi, &i));
+ EXPECT_TRUE(ftl::contains(spi, *spi.begin()));
+}
+
+TEST(NonNull, UnorderedSetOfSmartPtr) {
+ std::unordered_set<ftl::NonNull<std::shared_ptr<int>>> spi;
+ spi.insert(ftl::as_non_null(std::make_shared<int>(2)));
+ EXPECT_FALSE(ftl::contains(spi, nullptr));
+ EXPECT_TRUE(ftl::contains(spi, spi.begin()->get()));
+ EXPECT_TRUE(ftl::contains(spi, *spi.begin()));
+}
+
} // namespace android::test
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 628f016..cc0649c 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -89,11 +89,6 @@
bindgen_flags: [
"--verbose",
- "--allowlist-var=AMOTION_EVENT_FLAG_CANCELED",
- "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED",
- "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED",
- "--allowlist-var=AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT",
- "--allowlist-var=AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE",
"--allowlist-var=AMOTION_EVENT_ACTION_CANCEL",
"--allowlist-var=AMOTION_EVENT_ACTION_UP",
"--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN",
@@ -246,10 +241,10 @@
shared_libs: [
"libbase",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"liblog",
"libPlatformProperties",
- "libstatslog",
"libtinyxml2",
"libutils",
"libz", // needed by libkernelconfigs
diff --git a/libs/input/MotionPredictorMetricsManager.cpp b/libs/input/MotionPredictorMetricsManager.cpp
index 149a36e..cda39ce 100644
--- a/libs/input/MotionPredictorMetricsManager.cpp
+++ b/libs/input/MotionPredictorMetricsManager.cpp
@@ -21,7 +21,6 @@
#include <algorithm>
#include <android-base/logging.h>
-#include <statslog.h>
#include "Eigen/Core"
#include "Eigen/Geometry"
@@ -45,18 +44,9 @@
void MotionPredictorMetricsManager::defaultReportAtomFunction(
const MotionPredictorMetricsManager::AtomFields& atomFields) {
- android::util::stats_write(android::util::STYLUS_PREDICTION_METRICS_REPORTED,
- /*stylus_vendor_id=*/0,
- /*stylus_product_id=*/0,
- atomFields.deltaTimeBucketMilliseconds,
- atomFields.alongTrajectoryErrorMeanMillipixels,
- atomFields.alongTrajectoryErrorStdMillipixels,
- atomFields.offTrajectoryRmseMillipixels,
- atomFields.pressureRmseMilliunits,
- atomFields.highVelocityAlongTrajectoryRmse,
- atomFields.highVelocityOffTrajectoryRmse,
- atomFields.scaleInvariantAlongTrajectoryRmse,
- atomFields.scaleInvariantOffTrajectoryRmse);
+ // TODO(b/338106546): Fix bootanimation build dependency issue, then re-add
+ // the stats_write function call here.
+ (void)atomFields;
}
MotionPredictorMetricsManager::MotionPredictorMetricsManager(
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 8f6f95b..90ed2b7 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -49,12 +49,105 @@
const int POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY = 0x20000;
/**
+ * This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it and the event directly passed through
+ * the obscured area.
+ *
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ */
+ const int MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1;
+
+ /**
+ * This flag indicates that the window that received this motion event is partly
+ * or wholly obscured by another visible window above it and the event did not directly pass
+ * through the obscured area.
+ *
+ * A security sensitive application can check this flag to identify situations in which
+ * a malicious application may have covered up part of its content for the purpose
+ * of misleading the user or hijacking touches. An appropriate response might be
+ * to drop the suspect touches or to take additional precautions to confirm the user's
+ * actual intent.
+ *
+ * Unlike FLAG_WINDOW_IS_OBSCURED, this is only true if the window that received this event is
+ * obstructed in areas other than the touched location.
+ */
+ const int MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2;
+
+ /**
+ * This private flag is only set on {@link #ACTION_HOVER_MOVE} events and indicates that
+ * this event will be immediately followed by a {@link #ACTION_HOVER_EXIT}. It is used to
+ * prevent generating redundant {@link #ACTION_HOVER_ENTER} events.
+ * @hide
+ */
+ const int MOTION_EVENT_FLAG_HOVER_EXIT_PENDING = 0x4;
+
+ /**
+ * This flag indicates that the event has been generated by a gesture generator. It
+ * provides a hint to the GestureDetector to not apply any touch slop.
+ *
+ * @hide
+ */
+ const int MOTION_EVENT_FLAG_IS_GENERATED_GESTURE = 0x8;
+
+ /**
+ * This flag is only set for events with {@link #ACTION_POINTER_UP} and {@link #ACTION_CANCEL}.
+ * It indicates that the pointer going up was an unintentional user touch. When FLAG_CANCELED
+ * is set, the typical actions that occur in response for a pointer going up (such as click
+ * handlers, end of drawing) should be aborted. This flag is typically set when the user was
+ * accidentally touching the screen, such as by gripping the device, or placing the palm on the
+ * screen.
+ *
+ * @see #ACTION_POINTER_UP
+ * @see #ACTION_CANCEL
+ */
+ const int INPUT_EVENT_FLAG_CANCELED = 0x20;
+
+ /**
+ * This flag indicates that the event will not cause a focus change if it is directed to an
+ * unfocused window, even if it an {@link #ACTION_DOWN}. This is typically used with pointer
+ * gestures to allow the user to direct gestures to an unfocused window without bringing the
+ * window into focus.
+ * @hide
+ */
+ const int MOTION_EVENT_FLAG_NO_FOCUS_CHANGE = 0x40;
+
+ /**
* The input event was generated or modified by accessibility service.
* Shared by both KeyEvent and MotionEvent flags, so this value should not overlap with either
* set of flags, including in input/Input.h and in android/input.h.
*/
const int INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = 0x800;
+ /**
+ * Private flag that indicates when the system has detected that this motion event
+ * may be inconsistent with respect to the sequence of previously delivered motion events,
+ * such as when a pointer move event is sent but the pointer is not down.
+ *
+ * @hide
+ * @see #isTainted
+ * @see #setTainted
+ */
+ const int INPUT_EVENT_FLAG_TAINTED = 0x80000000;
+
+ /**
+ * Private flag indicating that this event was synthesized by the system and should be delivered
+ * to the accessibility focused view first. When being dispatched such an event is not handled
+ * by predecessors of the accessibility focused view and after the event reaches that view the
+ * flag is cleared and normal event dispatch is performed. This ensures that the platform can
+ * click on any view that has accessibility focus which is semantically equivalent to asking the
+ * view to perform a click accessibility action but more generic as views not implementing click
+ * action correctly can still be activated.
+ *
+ * @hide
+ * @see #isTargetAccessibilityFocus()
+ * @see #setTargetAccessibilityFocus(boolean)
+ */
+ const int MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS = 0x40000000;
+
/* The default pointer acceleration value. */
const int DEFAULT_POINTER_ACCELERATION = 3;
diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs
index d4f2426..d0dbd6f 100644
--- a/libs/input/rust/input.rs
+++ b/libs/input/rust/input.rs
@@ -17,6 +17,15 @@
//! Common definitions of the Android Input Framework in rust.
use bitflags::bitflags;
+use inputconstants::aidl::android::os::IInputConstants::INPUT_EVENT_FLAG_CANCELED;
+use inputconstants::aidl::android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+use inputconstants::aidl::android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED;
+use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING;
+use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
+use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
+use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS;
+use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+use inputconstants::aidl::android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
use std::fmt;
/// The InputDevice ID.
@@ -182,22 +191,24 @@
/// MotionEvent flags.
#[derive(Debug)]
pub struct MotionFlags: u32 {
- /// FLAG_CANCELED
- const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED as u32;
/// FLAG_WINDOW_IS_OBSCURED
- const WINDOW_IS_OBSCURED = input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ const WINDOW_IS_OBSCURED = MOTION_EVENT_FLAG_WINDOW_IS_OBSCURED as u32;
/// FLAG_WINDOW_IS_PARTIALLY_OBSCURED
- const WINDOW_IS_PARTIALLY_OBSCURED =
- input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- /// FLAG_IS_ACCESSIBILITY_EVENT
- const IS_ACCESSIBILITY_EVENT =
- input_bindgen::AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
- /// FLAG_NO_FOCUS_CHANGE
- const NO_FOCUS_CHANGE = input_bindgen::AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
+ const WINDOW_IS_PARTIALLY_OBSCURED = MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED as u32;
+ /// FLAG_HOVER_EXIT_PENDING
+ const HOVER_EXIT_PENDING = MOTION_EVENT_FLAG_HOVER_EXIT_PENDING as u32;
/// FLAG_IS_GENERATED_GESTURE
- const IS_GENERATED_GESTURE = input_bindgen::AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
+ const IS_GENERATED_GESTURE = MOTION_EVENT_FLAG_IS_GENERATED_GESTURE as u32;
+ /// FLAG_CANCELED
+ const CANCELED = INPUT_EVENT_FLAG_CANCELED as u32;
+ /// FLAG_NO_FOCUS_CHANGE
+ const NO_FOCUS_CHANGE = MOTION_EVENT_FLAG_NO_FOCUS_CHANGE as u32;
+ /// FLAG_IS_ACCESSIBILITY_EVENT
+ const IS_ACCESSIBILITY_EVENT = INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT as u32;
/// FLAG_TAINTED
- const TAINTED = input_bindgen::AMOTION_EVENT_FLAG_TAINTED;
+ const TAINTED = INPUT_EVENT_FLAG_TAINTED as u32;
+ /// FLAG_TARGET_ACCESSIBILITY_FOCUS
+ const TARGET_ACCESSIBILITY_FOCUS = MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS as u32;
}
}
diff --git a/libs/renderengine/skia/VulkanInterface.cpp b/libs/renderengine/skia/VulkanInterface.cpp
index 21d553c..fc16c56 100644
--- a/libs/renderengine/skia/VulkanInterface.cpp
+++ b/libs/renderengine/skia/VulkanInterface.cpp
@@ -244,7 +244,9 @@
VK_CHECK(vkEnumerateInstanceVersion(&instanceVersion));
if (instanceVersion < VK_MAKE_VERSION(1, 1, 0)) {
- return;
+ BAIL("Vulkan instance API version %" PRIu32 ".%" PRIu32 ".%" PRIu32 " < 1.1.0",
+ VK_VERSION_MAJOR(instanceVersion), VK_VERSION_MINOR(instanceVersion),
+ VK_VERSION_PATCH(instanceVersion));
}
const VkApplicationInfo appInfo = {
@@ -323,8 +325,11 @@
}
vkGetPhysicalDeviceProperties2(physicalDevice, &physDevProps);
- if (physDevProps.properties.apiVersion < VK_MAKE_VERSION(1, 1, 0)) {
- BAIL("Could not find a Vulkan 1.1+ physical device");
+ const uint32_t physicalDeviceApiVersion = physDevProps.properties.apiVersion;
+ if (physicalDeviceApiVersion < VK_MAKE_VERSION(1, 1, 0)) {
+ BAIL("Vulkan physical device API version %" PRIu32 ".%" PRIu32 ".%" PRIu32 " < 1.1.0",
+ VK_VERSION_MAJOR(physicalDeviceApiVersion), VK_VERSION_MINOR(physicalDeviceApiVersion),
+ VK_VERSION_PATCH(physicalDeviceApiVersion));
}
// Check for syncfd support. Bail if we cannot both import and export them.
@@ -539,7 +544,7 @@
mDevice = device;
mQueue = graphicsQueue;
mQueueIndex = graphicsQueueIndex;
- mApiVersion = physDevProps.properties.apiVersion;
+ mApiVersion = physicalDeviceApiVersion;
// grExtensions already constructed
// feature pointers already constructed
mGrGetProc = sGetProc;
diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp
index 82e5427..0908ae8 100644
--- a/libs/ui/DisplayIdentification.cpp
+++ b/libs/ui/DisplayIdentification.cpp
@@ -23,67 +23,13 @@
#include <optional>
#include <span>
+#include <ftl/hash.h>
#include <log/log.h>
-
#include <ui/DisplayIdentification.h>
namespace android {
namespace {
-template <class T>
-inline T load(const void* p) {
- static_assert(std::is_integral<T>::value, "T must be integral");
-
- T r;
- std::memcpy(&r, p, sizeof(r));
- return r;
-}
-
-uint64_t rotateByAtLeast1(uint64_t val, uint8_t shift) {
- return (val >> shift) | (val << (64 - shift));
-}
-
-uint64_t shiftMix(uint64_t val) {
- return val ^ (val >> 47);
-}
-
-__attribute__((no_sanitize("unsigned-integer-overflow")))
-uint64_t hash64Len16(uint64_t u, uint64_t v) {
- constexpr uint64_t kMul = 0x9ddfea08eb382d69;
- uint64_t a = (u ^ v) * kMul;
- a ^= (a >> 47);
- uint64_t b = (v ^ a) * kMul;
- b ^= (b >> 47);
- b *= kMul;
- return b;
-}
-
-__attribute__((no_sanitize("unsigned-integer-overflow")))
-uint64_t hash64Len0To16(const char* s, uint64_t len) {
- constexpr uint64_t k2 = 0x9ae16a3b2f90404f;
- constexpr uint64_t k3 = 0xc949d7c7509e6557;
-
- if (len > 8) {
- const uint64_t a = load<uint64_t>(s);
- const uint64_t b = load<uint64_t>(s + len - 8);
- return hash64Len16(a, rotateByAtLeast1(b + len, static_cast<uint8_t>(len))) ^ b;
- }
- if (len >= 4) {
- const uint32_t a = load<uint32_t>(s);
- const uint32_t b = load<uint32_t>(s + len - 4);
- return hash64Len16(len + (a << 3), b);
- }
- if (len > 0) {
- const unsigned char a = static_cast<unsigned char>(s[0]);
- const unsigned char b = static_cast<unsigned char>(s[len >> 1]);
- const unsigned char c = static_cast<unsigned char>(s[len - 1]);
- const uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
- const uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
- return shiftMix(y * k2 ^ z * k3) * k2;
- }
- return k2;
-}
-
using byte_view = std::span<const uint8_t>;
constexpr size_t kEdidBlockSize = 128;
@@ -320,7 +266,7 @@
// Hash model string instead of using product code or (integer) serial number, since the latter
// have been observed to change on some displays with multiple inputs. Use a stable hash instead
// of std::hash which is only required to be same within a single execution of a program.
- const uint32_t modelHash = static_cast<uint32_t>(cityHash64Len0To16(modelString));
+ const uint32_t modelHash = static_cast<uint32_t>(*ftl::stable_hash(modelString));
// Parse extension blocks.
std::optional<Cea861ExtensionBlock> cea861Block;
@@ -394,13 +340,4 @@
return PhysicalDisplayId::fromEdid(0, kVirtualEdidManufacturerId, id);
}
-uint64_t cityHash64Len0To16(std::string_view sv) {
- auto len = sv.length();
- if (len > 16) {
- ALOGE("%s called with length %zu. Only hashing the first 16 chars", __FUNCTION__, len);
- len = 16;
- }
- return hash64Len0To16(sv.data(), len);
-}
-
} // namespace android
diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h
index fc9c0f4..8bc2017 100644
--- a/libs/ui/include/ui/DisplayIdentification.h
+++ b/libs/ui/include/ui/DisplayIdentification.h
@@ -80,7 +80,4 @@
PhysicalDisplayId getVirtualDisplayId(uint32_t id);
-// CityHash64 implementation that only hashes at most the first 16 characters of the given string.
-uint64_t cityHash64Len0To16(std::string_view sv);
-
} // namespace android
diff --git a/libs/ui/tests/DisplayIdentification_test.cpp b/libs/ui/tests/DisplayIdentification_test.cpp
index 736979a..721b466 100644
--- a/libs/ui/tests/DisplayIdentification_test.cpp
+++ b/libs/ui/tests/DisplayIdentification_test.cpp
@@ -21,9 +21,9 @@
#include <functional>
#include <string_view>
+#include <ftl/hash.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <ui/DisplayIdentification.h>
using ::testing::ElementsAre;
@@ -135,7 +135,7 @@
}
uint32_t hash(const char* str) {
- return static_cast<uint32_t>(cityHash64Len0To16(str));
+ return static_cast<uint32_t>(*ftl::stable_hash(str));
}
} // namespace
@@ -188,6 +188,7 @@
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
EXPECT_EQ(hash("121AT11-801"), edid->modelHash);
+ EXPECT_EQ(hash("121AT11-801"), 626564263);
EXPECT_TRUE(edid->displayName.empty());
EXPECT_EQ(12610, edid->productId);
EXPECT_EQ(21, edid->manufactureOrModelYear);
@@ -199,6 +200,7 @@
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
EXPECT_EQ(hash("HP ZR30w"), edid->modelHash);
+ EXPECT_EQ(hash("HP ZR30w"), 918492362);
EXPECT_EQ("HP ZR30w", edid->displayName);
EXPECT_EQ(10348, edid->productId);
EXPECT_EQ(22, edid->manufactureOrModelYear);
@@ -210,6 +212,7 @@
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
EXPECT_EQ(hash("SAMSUNG"), edid->modelHash);
+ EXPECT_EQ(hash("SAMSUNG"), 1201368132);
EXPECT_EQ("SAMSUNG", edid->displayName);
EXPECT_EQ(2302, edid->productId);
EXPECT_EQ(21, edid->manufactureOrModelYear);
@@ -227,6 +230,7 @@
EXPECT_EQ(13481, edid->manufacturerId);
EXPECT_STREQ("MEI", edid->pnpId.data());
EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash);
+ EXPECT_EQ(hash("Panasonic-TV"), 3876373262);
EXPECT_EQ("Panasonic-TV", edid->displayName);
EXPECT_EQ(41622, edid->productId);
EXPECT_EQ(29, edid->manufactureOrModelYear);
@@ -244,6 +248,7 @@
EXPECT_EQ(8355, edid->manufacturerId);
EXPECT_STREQ("HEC", edid->pnpId.data());
EXPECT_EQ(hash("Hisense"), edid->modelHash);
+ EXPECT_EQ(hash("Hisense"), 2859844809);
EXPECT_EQ("Hisense", edid->displayName);
EXPECT_EQ(0, edid->productId);
EXPECT_EQ(29, edid->manufactureOrModelYear);
@@ -261,6 +266,7 @@
EXPECT_EQ(3724, edid->manufacturerId);
EXPECT_STREQ("CTL", edid->pnpId.data());
EXPECT_EQ(hash("LP2361"), edid->modelHash);
+ EXPECT_EQ(hash("LP2361"), 1523181158);
EXPECT_EQ("LP2361", edid->displayName);
EXPECT_EQ(9373, edid->productId);
EXPECT_EQ(23, edid->manufactureOrModelYear);
@@ -281,6 +287,7 @@
// Serial number should be used as fallback if display name is invalid.
const auto modelHash = hash("CN4202137Q");
EXPECT_EQ(modelHash, edid->modelHash);
+ EXPECT_EQ(modelHash, 3582951527);
EXPECT_TRUE(edid->displayName.empty());
// Parsing should succeed even if EDID is truncated.
diff --git a/libs/ultrahdr/OWNERS b/libs/ultrahdr/OWNERS
deleted file mode 100644
index 6ace354..0000000
--- a/libs/ultrahdr/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arifdikici@google.com
-dichenzhang@google.com
-kyslov@google.com
\ No newline at end of file
diff --git a/libs/ultrahdr/adobe-hdr-gain-map-license/Android.bp b/libs/ultrahdr/adobe-hdr-gain-map-license/Android.bp
deleted file mode 100644
index 2fa361f..0000000
--- a/libs/ultrahdr/adobe-hdr-gain-map-license/Android.bp
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 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.
-
-license {
- name: "adobe_hdr_gain_map_license-deprecated",
- license_kinds: ["legacy_by_exception_only"],
- license_text: ["NOTICE"],
-}
diff --git a/libs/ultrahdr/adobe-hdr-gain-map-license/NOTICE b/libs/ultrahdr/adobe-hdr-gain-map-license/NOTICE
deleted file mode 100644
index 3f6c594..0000000
--- a/libs/ultrahdr/adobe-hdr-gain-map-license/NOTICE
+++ /dev/null
@@ -1 +0,0 @@
-This product includes Gain Map technology under license by Adobe.
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
deleted file mode 100644
index f1f4035..0000000
--- a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 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.
- */
-
-// System include files
-#include <fuzzer/FuzzedDataProvider.h>
-#include <iostream>
-#include <vector>
-
-// User include files
-#include "ultrahdr/jpegr.h"
-
-using namespace android::ultrahdr;
-
-// Transfer functions for image data, sync with ultrahdr.h
-const int kOfMin = ULTRAHDR_OUTPUT_UNSPECIFIED + 1;
-const int kOfMax = ULTRAHDR_OUTPUT_MAX;
-
-class UltraHdrDecFuzzer {
-public:
- UltraHdrDecFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
-
-private:
- FuzzedDataProvider mFdp;
-};
-
-void UltraHdrDecFuzzer::process() {
- // hdr_of
- auto of = static_cast<ultrahdr_output_format>(mFdp.ConsumeIntegralInRange<int>(kOfMin, kOfMax));
- auto buffer = mFdp.ConsumeRemainingBytes<uint8_t>();
- jpegr_compressed_struct jpegImgR{buffer.data(), (int)buffer.size(), (int)buffer.size(),
- ULTRAHDR_COLORGAMUT_UNSPECIFIED};
-
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
- JpegR jpegHdr;
- (void)jpegHdr.getJPEGRInfo(&jpegImgR, &info);
-//#define DUMP_PARAM
-#ifdef DUMP_PARAM
- std::cout << "input buffer size " << jpegImgR.length << std::endl;
- std::cout << "image dimensions " << info.width << " x " << info.width << std::endl;
-#endif
- size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
- jpegr_uncompressed_struct decodedJpegR;
- auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
- decodedJpegR.data = decodedRaw.get();
- ultrahdr_metadata_struct metadata;
- jpegr_uncompressed_struct decodedGainMap{};
- (void)jpegHdr.decodeJPEGR(&jpegImgR, &decodedJpegR,
- mFdp.ConsumeFloatingPointInRange<float>(1.0, FLT_MAX), nullptr, of,
- &decodedGainMap, &metadata);
- if (decodedGainMap.data) free(decodedGainMap.data);
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- UltraHdrDecFuzzer fuzzHandle(data, size);
- fuzzHandle.process();
- return 0;
-}
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
deleted file mode 100644
index 2d59e8b..0000000
--- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright 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.
- */
-
-// System include files
-#include <fuzzer/FuzzedDataProvider.h>
-#include <algorithm>
-#include <iostream>
-#include <random>
-#include <vector>
-
-// User include files
-#include "ultrahdr/gainmapmath.h"
-#include "ultrahdr/jpegdecoderhelper.h"
-#include "ultrahdr/jpegencoderhelper.h"
-#include "utils/Log.h"
-
-using namespace android::ultrahdr;
-
-// Color gamuts for image data, sync with ultrahdr.h
-const int kCgMin = ULTRAHDR_COLORGAMUT_UNSPECIFIED + 1;
-const int kCgMax = ULTRAHDR_COLORGAMUT_MAX;
-
-// Transfer functions for image data, sync with ultrahdr.h
-const int kTfMin = ULTRAHDR_TF_UNSPECIFIED + 1;
-const int kTfMax = ULTRAHDR_TF_PQ;
-
-// Transfer functions for image data, sync with ultrahdr.h
-const int kOfMin = ULTRAHDR_OUTPUT_UNSPECIFIED + 1;
-const int kOfMax = ULTRAHDR_OUTPUT_MAX;
-
-// quality factor
-const int kQfMin = 0;
-const int kQfMax = 100;
-
-class UltraHdrEncFuzzer {
-public:
- UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
- void process();
- void fillP010Buffer(uint16_t* data, int width, int height, int stride);
- void fill420Buffer(uint8_t* data, int width, int height, int stride);
-
-private:
- FuzzedDataProvider mFdp;
-};
-
-void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, int stride) {
- uint16_t* tmp = data;
- std::vector<uint16_t> buffer(16);
- for (int i = 0; i < buffer.size(); i++) {
- buffer[i] = (mFdp.ConsumeIntegralInRange<int>(0, (1 << 10) - 1)) << 6;
- }
- for (int j = 0; j < height; j++) {
- for (int i = 0; i < width; i += buffer.size()) {
- memcpy(tmp + i, buffer.data(),
- std::min((int)buffer.size(), (width - i)) * sizeof(*data));
- std::shuffle(buffer.begin(), buffer.end(),
- std::default_random_engine(std::random_device{}()));
- }
- tmp += stride;
- }
-}
-
-void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int width, int height, int stride) {
- uint8_t* tmp = data;
- std::vector<uint8_t> buffer(16);
- mFdp.ConsumeData(buffer.data(), buffer.size());
- for (int j = 0; j < height; j++) {
- for (int i = 0; i < width; i += buffer.size()) {
- memcpy(tmp + i, buffer.data(),
- std::min((int)buffer.size(), (width - i)) * sizeof(*data));
- std::shuffle(buffer.begin(), buffer.end(),
- std::default_random_engine(std::random_device{}()));
- }
- tmp += stride;
- }
-}
-
-void UltraHdrEncFuzzer::process() {
- while (mFdp.remaining_bytes()) {
- struct jpegr_uncompressed_struct p010Img {};
- struct jpegr_uncompressed_struct yuv420Img {};
- struct jpegr_uncompressed_struct grayImg {};
- struct jpegr_compressed_struct jpegImgR {};
- struct jpegr_compressed_struct jpegImg {};
- struct jpegr_compressed_struct jpegGainMap {};
-
- // which encode api to select
- int muxSwitch = mFdp.ConsumeIntegralInRange<int>(0, 4);
-
- // quality factor
- int quality = mFdp.ConsumeIntegralInRange<int>(kQfMin, kQfMax);
-
- // hdr_tf
- auto tf = static_cast<ultrahdr_transfer_function>(
- mFdp.ConsumeIntegralInRange<int>(kTfMin, kTfMax));
-
- // p010 Cg
- auto p010Cg =
- static_cast<ultrahdr_color_gamut>(mFdp.ConsumeIntegralInRange<int>(kCgMin, kCgMax));
-
- // 420 Cg
- auto yuv420Cg =
- static_cast<ultrahdr_color_gamut>(mFdp.ConsumeIntegralInRange<int>(kCgMin, kCgMax));
-
- // hdr_of
- auto of = static_cast<ultrahdr_output_format>(
- mFdp.ConsumeIntegralInRange<int>(kOfMin, kOfMax));
-
- int width = mFdp.ConsumeIntegralInRange<int>(kMinWidth, kMaxWidth);
- width = (width >> 1) << 1;
-
- int height = mFdp.ConsumeIntegralInRange<int>(kMinHeight, kMaxHeight);
- height = (height >> 1) << 1;
-
- std::unique_ptr<uint16_t[]> bufferYHdr = nullptr;
- std::unique_ptr<uint16_t[]> bufferUVHdr = nullptr;
- std::unique_ptr<uint8_t[]> bufferYSdr = nullptr;
- std::unique_ptr<uint8_t[]> bufferUVSdr = nullptr;
- std::unique_ptr<uint8_t[]> grayImgRaw = nullptr;
- if (muxSwitch != 4) {
- // init p010 image
- bool isUVContiguous = mFdp.ConsumeBool();
- bool hasYStride = mFdp.ConsumeBool();
- int yStride = hasYStride ? mFdp.ConsumeIntegralInRange<int>(width, width + 128) : width;
- p010Img.width = width;
- p010Img.height = height;
- p010Img.colorGamut = p010Cg;
- p010Img.luma_stride = hasYStride ? yStride : 0;
- int bppP010 = 2;
- if (isUVContiguous) {
- size_t p010Size = yStride * height * 3 / 2;
- bufferYHdr = std::make_unique<uint16_t[]>(p010Size);
- p010Img.data = bufferYHdr.get();
- p010Img.chroma_data = nullptr;
- p010Img.chroma_stride = 0;
- fillP010Buffer(bufferYHdr.get(), width, height, yStride);
- fillP010Buffer(bufferYHdr.get() + yStride * height, width, height / 2, yStride);
- } else {
- int uvStride = mFdp.ConsumeIntegralInRange<int>(width, width + 128);
- size_t p010YSize = yStride * height;
- bufferYHdr = std::make_unique<uint16_t[]>(p010YSize);
- p010Img.data = bufferYHdr.get();
- fillP010Buffer(bufferYHdr.get(), width, height, yStride);
- size_t p010UVSize = uvStride * p010Img.height / 2;
- bufferUVHdr = std::make_unique<uint16_t[]>(p010UVSize);
- p010Img.chroma_data = bufferUVHdr.get();
- p010Img.chroma_stride = uvStride;
- fillP010Buffer(bufferUVHdr.get(), width, height / 2, uvStride);
- }
- } else {
- size_t map_width = width / kMapDimensionScaleFactor;
- size_t map_height = height / kMapDimensionScaleFactor;
- // init 400 image
- grayImg.width = map_width;
- grayImg.height = map_height;
- grayImg.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
-
- const size_t graySize = map_width * map_height;
- grayImgRaw = std::make_unique<uint8_t[]>(graySize);
- grayImg.data = grayImgRaw.get();
- fill420Buffer(grayImgRaw.get(), map_width, map_height, map_width);
- grayImg.chroma_data = nullptr;
- grayImg.luma_stride = 0;
- grayImg.chroma_stride = 0;
- }
-
- if (muxSwitch > 0) {
- // init 420 image
- bool isUVContiguous = mFdp.ConsumeBool();
- bool hasYStride = mFdp.ConsumeBool();
- int yStride = hasYStride ? mFdp.ConsumeIntegralInRange<int>(width, width + 128) : width;
- yuv420Img.width = width;
- yuv420Img.height = height;
- yuv420Img.colorGamut = yuv420Cg;
- yuv420Img.luma_stride = hasYStride ? yStride : 0;
- if (isUVContiguous) {
- size_t yuv420Size = yStride * height * 3 / 2;
- bufferYSdr = std::make_unique<uint8_t[]>(yuv420Size);
- yuv420Img.data = bufferYSdr.get();
- yuv420Img.chroma_data = nullptr;
- yuv420Img.chroma_stride = 0;
- fill420Buffer(bufferYSdr.get(), width, height, yStride);
- fill420Buffer(bufferYSdr.get() + yStride * height, width / 2, height / 2,
- yStride / 2);
- fill420Buffer(bufferYSdr.get() + yStride * height * 5 / 4, width / 2, height / 2,
- yStride / 2);
- } else {
- int uvStride = mFdp.ConsumeIntegralInRange<int>(width / 2, width / 2 + 128);
- size_t yuv420YSize = yStride * height;
- bufferYSdr = std::make_unique<uint8_t[]>(yuv420YSize);
- yuv420Img.data = bufferYSdr.get();
- fill420Buffer(bufferYSdr.get(), width, height, yStride);
- size_t yuv420UVSize = uvStride * yuv420Img.height / 2 * 2;
- bufferUVSdr = std::make_unique<uint8_t[]>(yuv420UVSize);
- yuv420Img.chroma_data = bufferUVSdr.get();
- yuv420Img.chroma_stride = uvStride;
- fill420Buffer(bufferUVSdr.get(), width / 2, height / 2, uvStride);
- fill420Buffer(bufferUVSdr.get() + uvStride * height / 2, width / 2, height / 2,
- uvStride);
- }
- }
-
- // dest
- // 2 * p010 size as input data is random, DCT compression might not behave as expected
- jpegImgR.maxLength = std::max(8 * 1024 /* min size 8kb */, width * height * 3 * 2);
- auto jpegImgRaw = std::make_unique<uint8_t[]>(jpegImgR.maxLength);
- jpegImgR.data = jpegImgRaw.get();
-
-//#define DUMP_PARAM
-#ifdef DUMP_PARAM
- std::cout << "Api Select " << muxSwitch << std::endl;
- std::cout << "image dimensions " << width << " x " << height << std::endl;
- std::cout << "p010 color gamut " << p010Img.colorGamut << std::endl;
- std::cout << "p010 luma stride " << p010Img.luma_stride << std::endl;
- std::cout << "p010 chroma stride " << p010Img.chroma_stride << std::endl;
- std::cout << "420 color gamut " << yuv420Img.colorGamut << std::endl;
- std::cout << "420 luma stride " << yuv420Img.luma_stride << std::endl;
- std::cout << "420 chroma stride " << yuv420Img.chroma_stride << std::endl;
- std::cout << "quality factor " << quality << std::endl;
-#endif
-
- JpegR jpegHdr;
- android::status_t status = android::UNKNOWN_ERROR;
- if (muxSwitch == 0) { // api 0
- jpegImgR.length = 0;
- status = jpegHdr.encodeJPEGR(&p010Img, tf, &jpegImgR, quality, nullptr);
- } else if (muxSwitch == 1) { // api 1
- jpegImgR.length = 0;
- status = jpegHdr.encodeJPEGR(&p010Img, &yuv420Img, tf, &jpegImgR, quality, nullptr);
- } else {
- // compressed img
- JpegEncoderHelper encoder;
- struct jpegr_uncompressed_struct yuv420ImgCopy = yuv420Img;
- if (yuv420ImgCopy.luma_stride == 0) yuv420ImgCopy.luma_stride = yuv420Img.width;
- if (!yuv420ImgCopy.chroma_data) {
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420Img.data);
- yuv420ImgCopy.chroma_data = data + yuv420Img.luma_stride * yuv420Img.height;
- yuv420ImgCopy.chroma_stride = yuv420Img.luma_stride >> 1;
- }
-
- if (encoder.compressImage(reinterpret_cast<uint8_t*>(yuv420ImgCopy.data),
- reinterpret_cast<uint8_t*>(yuv420ImgCopy.chroma_data),
- yuv420ImgCopy.width, yuv420ImgCopy.height,
- yuv420ImgCopy.luma_stride, yuv420ImgCopy.chroma_stride,
- quality, nullptr, 0)) {
- jpegImg.length = encoder.getCompressedImageSize();
- jpegImg.maxLength = jpegImg.length;
- jpegImg.data = encoder.getCompressedImagePtr();
- jpegImg.colorGamut = yuv420Cg;
-
- if (muxSwitch == 2) { // api 2
- jpegImgR.length = 0;
- status = jpegHdr.encodeJPEGR(&p010Img, &yuv420Img, &jpegImg, tf, &jpegImgR);
- } else if (muxSwitch == 3) { // api 3
- jpegImgR.length = 0;
- status = jpegHdr.encodeJPEGR(&p010Img, &jpegImg, tf, &jpegImgR);
- } else if (muxSwitch == 4) { // api 4
- jpegImgR.length = 0;
- JpegEncoderHelper gainMapEncoder;
- if (gainMapEncoder.compressImage(reinterpret_cast<uint8_t*>(grayImg.data),
- nullptr, grayImg.width, grayImg.height,
- grayImg.width, 0, quality, nullptr, 0)) {
- jpegGainMap.length = gainMapEncoder.getCompressedImageSize();
- jpegGainMap.maxLength = jpegImg.length;
- jpegGainMap.data = gainMapEncoder.getCompressedImagePtr();
- jpegGainMap.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- ultrahdr_metadata_struct metadata;
- metadata.version = kJpegrVersion;
- if (tf == ULTRAHDR_TF_HLG) {
- metadata.maxContentBoost = kHlgMaxNits / kSdrWhiteNits;
- } else if (tf == ULTRAHDR_TF_PQ) {
- metadata.maxContentBoost = kPqMaxNits / kSdrWhiteNits;
- } else {
- metadata.maxContentBoost = 1.0f;
- }
- metadata.minContentBoost = 1.0f;
- metadata.gamma = 1.0f;
- metadata.offsetSdr = 0.0f;
- metadata.offsetHdr = 0.0f;
- metadata.hdrCapacityMin = 1.0f;
- metadata.hdrCapacityMax = metadata.maxContentBoost;
- status = jpegHdr.encodeJPEGR(&jpegImg, &jpegGainMap, &metadata, &jpegImgR);
- }
- }
- }
- }
- if (status == android::OK) {
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
- status = jpegHdr.getJPEGRInfo(&jpegImgR, &info);
- if (status == android::OK) {
- size_t outSize =
- info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4);
- jpegr_uncompressed_struct decodedJpegR;
- auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
- decodedJpegR.data = decodedRaw.get();
- ultrahdr_metadata_struct metadata;
- jpegr_uncompressed_struct decodedGainMap{};
- status = jpegHdr.decodeJPEGR(&jpegImgR, &decodedJpegR,
- mFdp.ConsumeFloatingPointInRange<float>(1.0, FLT_MAX),
- nullptr, of, &decodedGainMap, &metadata);
- if (status != android::OK) {
- ALOGE("encountered error during decoding %d", status);
- }
- if (decodedGainMap.data) free(decodedGainMap.data);
- } else {
- ALOGE("encountered error during get jpeg info %d", status);
- }
- } else {
- ALOGE("encountered error during encoding %d", status);
- }
- }
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- UltraHdrEncFuzzer fuzzHandle(data, size);
- fuzzHandle.process();
- return 0;
-}
diff --git a/libs/ultrahdr/gainmapmath.cpp b/libs/ultrahdr/gainmapmath.cpp
deleted file mode 100644
index ae9c4ca..0000000
--- a/libs/ultrahdr/gainmapmath.cpp
+++ /dev/null
@@ -1,775 +0,0 @@
-/*
- * Copyright 2022 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 <cmath>
-#include <vector>
-#include <ultrahdr/gainmapmath.h>
-
-namespace android::ultrahdr {
-
-static const std::vector<float> kPqOETF = [] {
- std::vector<float> result;
- for (int idx = 0; idx < kPqOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kPqOETFNumEntries - 1);
- result.push_back(pqOetf(value));
- }
- return result;
-}();
-
-static const std::vector<float> kPqInvOETF = [] {
- std::vector<float> result;
- for (int idx = 0; idx < kPqInvOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kPqInvOETFNumEntries - 1);
- result.push_back(pqInvOetf(value));
- }
- return result;
-}();
-
-static const std::vector<float> kHlgOETF = [] {
- std::vector<float> result;
- for (int idx = 0; idx < kHlgOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kHlgOETFNumEntries - 1);
- result.push_back(hlgOetf(value));
- }
- return result;
-}();
-
-static const std::vector<float> kHlgInvOETF = [] {
- std::vector<float> result;
- for (int idx = 0; idx < kHlgInvOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kHlgInvOETFNumEntries - 1);
- result.push_back(hlgInvOetf(value));
- }
- return result;
-}();
-
-static const std::vector<float> kSrgbInvOETF = [] {
- std::vector<float> result;
- for (int idx = 0; idx < kSrgbInvOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kSrgbInvOETFNumEntries - 1);
- result.push_back(srgbInvOetf(value));
- }
- return result;
-}();
-
-// Use Shepard's method for inverse distance weighting. For more information:
-// en.wikipedia.org/wiki/Inverse_distance_weighting#Shepard's_method
-
-float ShepardsIDW::euclideanDistance(float x1, float x2, float y1, float y2) {
- return sqrt(((y2 - y1) * (y2 - y1)) + (x2 - x1) * (x2 - x1));
-}
-
-void ShepardsIDW::fillShepardsIDW(float *weights, int incR, int incB) {
- for (int y = 0; y < mMapScaleFactor; y++) {
- for (int x = 0; x < mMapScaleFactor; x++) {
- float pos_x = ((float)x) / mMapScaleFactor;
- float pos_y = ((float)y) / mMapScaleFactor;
- int curr_x = floor(pos_x);
- int curr_y = floor(pos_y);
- int next_x = curr_x + incR;
- int next_y = curr_y + incB;
- float e1_distance = euclideanDistance(pos_x, curr_x, pos_y, curr_y);
- int index = y * mMapScaleFactor * 4 + x * 4;
- if (e1_distance == 0) {
- weights[index++] = 1.f;
- weights[index++] = 0.f;
- weights[index++] = 0.f;
- weights[index++] = 0.f;
- } else {
- float e1_weight = 1.f / e1_distance;
-
- float e2_distance = euclideanDistance(pos_x, curr_x, pos_y, next_y);
- float e2_weight = 1.f / e2_distance;
-
- float e3_distance = euclideanDistance(pos_x, next_x, pos_y, curr_y);
- float e3_weight = 1.f / e3_distance;
-
- float e4_distance = euclideanDistance(pos_x, next_x, pos_y, next_y);
- float e4_weight = 1.f / e4_distance;
-
- float total_weight = e1_weight + e2_weight + e3_weight + e4_weight;
-
- weights[index++] = e1_weight / total_weight;
- weights[index++] = e2_weight / total_weight;
- weights[index++] = e3_weight / total_weight;
- weights[index++] = e4_weight / total_weight;
- }
- }
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sRGB transformations
-
-static const float kMaxPixelFloat = 1.0f;
-static float clampPixelFloat(float value) {
- return (value < 0.0f) ? 0.0f : (value > kMaxPixelFloat) ? kMaxPixelFloat : value;
-}
-
-// See IEC 61966-2-1/Amd 1:2003, Equation F.7.
-static const float kSrgbR = 0.2126f, kSrgbG = 0.7152f, kSrgbB = 0.0722f;
-
-float srgbLuminance(Color e) {
- return kSrgbR * e.r + kSrgbG * e.g + kSrgbB * e.b;
-}
-
-// See ITU-R BT.709-6, Section 3.
-// Uses the same coefficients for deriving luma signal as
-// IEC 61966-2-1/Amd 1:2003 states for luminance, so we reuse the luminance
-// function above.
-static const float kSrgbCb = 1.8556f, kSrgbCr = 1.5748f;
-
-Color srgbRgbToYuv(Color e_gamma) {
- float y_gamma = srgbLuminance(e_gamma);
- return {{{ y_gamma,
- (e_gamma.b - y_gamma) / kSrgbCb,
- (e_gamma.r - y_gamma) / kSrgbCr }}};
-}
-
-// See ITU-R BT.709-6, Section 3.
-// Same derivation to BT.2100's YUV->RGB, below. Similar to srgbRgbToYuv, we
-// can reuse the luminance coefficients since they are the same.
-static const float kSrgbGCb = kSrgbB * kSrgbCb / kSrgbG;
-static const float kSrgbGCr = kSrgbR * kSrgbCr / kSrgbG;
-
-Color srgbYuvToRgb(Color e_gamma) {
- return {{{ clampPixelFloat(e_gamma.y + kSrgbCr * e_gamma.v),
- clampPixelFloat(e_gamma.y - kSrgbGCb * e_gamma.u - kSrgbGCr * e_gamma.v),
- clampPixelFloat(e_gamma.y + kSrgbCb * e_gamma.u) }}};
-}
-
-// See IEC 61966-2-1/Amd 1:2003, Equations F.5 and F.6.
-float srgbInvOetf(float e_gamma) {
- if (e_gamma <= 0.04045f) {
- return e_gamma / 12.92f;
- } else {
- return pow((e_gamma + 0.055f) / 1.055f, 2.4);
- }
-}
-
-Color srgbInvOetf(Color e_gamma) {
- return {{{ srgbInvOetf(e_gamma.r),
- srgbInvOetf(e_gamma.g),
- srgbInvOetf(e_gamma.b) }}};
-}
-
-// See IEC 61966-2-1, Equations F.5 and F.6.
-float srgbInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * (kSrgbInvOETFNumEntries - 1) + 0.5);
- //TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kSrgbInvOETFNumEntries - 1);
- return kSrgbInvOETF[value];
-}
-
-Color srgbInvOetfLUT(Color e_gamma) {
- return {{{ srgbInvOetfLUT(e_gamma.r),
- srgbInvOetfLUT(e_gamma.g),
- srgbInvOetfLUT(e_gamma.b) }}};
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Display-P3 transformations
-
-// See SMPTE EG 432-1, Equation 7-8.
-static const float kP3R = 0.20949f, kP3G = 0.72160f, kP3B = 0.06891f;
-
-float p3Luminance(Color e) {
- return kP3R * e.r + kP3G * e.g + kP3B * e.b;
-}
-
-// See ITU-R BT.601-7, Sections 2.5.1 and 2.5.2.
-// Unfortunately, calculation of luma signal differs from calculation of
-// luminance for Display-P3, so we can't reuse p3Luminance here.
-static const float kP3YR = 0.299f, kP3YG = 0.587f, kP3YB = 0.114f;
-static const float kP3Cb = 1.772f, kP3Cr = 1.402f;
-
-Color p3RgbToYuv(Color e_gamma) {
- float y_gamma = kP3YR * e_gamma.r + kP3YG * e_gamma.g + kP3YB * e_gamma.b;
- return {{{ y_gamma,
- (e_gamma.b - y_gamma) / kP3Cb,
- (e_gamma.r - y_gamma) / kP3Cr }}};
-}
-
-// See ITU-R BT.601-7, Sections 2.5.1 and 2.5.2.
-// Same derivation to BT.2100's YUV->RGB, below. Similar to p3RgbToYuv, we must
-// use luma signal coefficients rather than the luminance coefficients.
-static const float kP3GCb = kP3YB * kP3Cb / kP3YG;
-static const float kP3GCr = kP3YR * kP3Cr / kP3YG;
-
-Color p3YuvToRgb(Color e_gamma) {
- return {{{ clampPixelFloat(e_gamma.y + kP3Cr * e_gamma.v),
- clampPixelFloat(e_gamma.y - kP3GCb * e_gamma.u - kP3GCr * e_gamma.v),
- clampPixelFloat(e_gamma.y + kP3Cb * e_gamma.u) }}};
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// BT.2100 transformations - according to ITU-R BT.2100-2
-
-// See ITU-R BT.2100-2, Table 5, HLG Reference OOTF
-static const float kBt2100R = 0.2627f, kBt2100G = 0.6780f, kBt2100B = 0.0593f;
-
-float bt2100Luminance(Color e) {
- return kBt2100R * e.r + kBt2100G * e.g + kBt2100B * e.b;
-}
-
-// See ITU-R BT.2100-2, Table 6, Derivation of colour difference signals.
-// BT.2100 uses the same coefficients for calculating luma signal and luminance,
-// so we reuse the luminance function here.
-static const float kBt2100Cb = 1.8814f, kBt2100Cr = 1.4746f;
-
-Color bt2100RgbToYuv(Color e_gamma) {
- float y_gamma = bt2100Luminance(e_gamma);
- return {{{ y_gamma,
- (e_gamma.b - y_gamma) / kBt2100Cb,
- (e_gamma.r - y_gamma) / kBt2100Cr }}};
-}
-
-// See ITU-R BT.2100-2, Table 6, Derivation of colour difference signals.
-//
-// Similar to bt2100RgbToYuv above, we can reuse the luminance coefficients.
-//
-// Derived by inversing bt2100RgbToYuv. The derivation for R and B are pretty
-// straight forward; we just invert the formulas for U and V above. But deriving
-// the formula for G is a bit more complicated:
-//
-// Start with equation for luminance:
-// Y = kBt2100R * R + kBt2100G * G + kBt2100B * B
-// Solve for G:
-// G = (Y - kBt2100R * R - kBt2100B * B) / kBt2100B
-// Substitute equations for R and B in terms YUV:
-// G = (Y - kBt2100R * (Y + kBt2100Cr * V) - kBt2100B * (Y + kBt2100Cb * U)) / kBt2100B
-// Simplify:
-// G = Y * ((1 - kBt2100R - kBt2100B) / kBt2100G)
-// + U * (kBt2100B * kBt2100Cb / kBt2100G)
-// + V * (kBt2100R * kBt2100Cr / kBt2100G)
-//
-// We then get the following coeficients for calculating G from YUV:
-//
-// Coef for Y = (1 - kBt2100R - kBt2100B) / kBt2100G = 1
-// Coef for U = kBt2100B * kBt2100Cb / kBt2100G = kBt2100GCb = ~0.1645
-// Coef for V = kBt2100R * kBt2100Cr / kBt2100G = kBt2100GCr = ~0.5713
-
-static const float kBt2100GCb = kBt2100B * kBt2100Cb / kBt2100G;
-static const float kBt2100GCr = kBt2100R * kBt2100Cr / kBt2100G;
-
-Color bt2100YuvToRgb(Color e_gamma) {
- return {{{ clampPixelFloat(e_gamma.y + kBt2100Cr * e_gamma.v),
- clampPixelFloat(e_gamma.y - kBt2100GCb * e_gamma.u - kBt2100GCr * e_gamma.v),
- clampPixelFloat(e_gamma.y + kBt2100Cb * e_gamma.u) }}};
-}
-
-// See ITU-R BT.2100-2, Table 5, HLG Reference OETF.
-static const float kHlgA = 0.17883277f, kHlgB = 0.28466892f, kHlgC = 0.55991073;
-
-float hlgOetf(float e) {
- if (e <= 1.0f/12.0f) {
- return sqrt(3.0f * e);
- } else {
- return kHlgA * log(12.0f * e - kHlgB) + kHlgC;
- }
-}
-
-Color hlgOetf(Color e) {
- return {{{ hlgOetf(e.r), hlgOetf(e.g), hlgOetf(e.b) }}};
-}
-
-float hlgOetfLUT(float e) {
- uint32_t value = static_cast<uint32_t>(e * (kHlgOETFNumEntries - 1) + 0.5);
- //TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kHlgOETFNumEntries - 1);
-
- return kHlgOETF[value];
-}
-
-Color hlgOetfLUT(Color e) {
- return {{{ hlgOetfLUT(e.r), hlgOetfLUT(e.g), hlgOetfLUT(e.b) }}};
-}
-
-// See ITU-R BT.2100-2, Table 5, HLG Reference EOTF.
-float hlgInvOetf(float e_gamma) {
- if (e_gamma <= 0.5f) {
- return pow(e_gamma, 2.0f) / 3.0f;
- } else {
- return (exp((e_gamma - kHlgC) / kHlgA) + kHlgB) / 12.0f;
- }
-}
-
-Color hlgInvOetf(Color e_gamma) {
- return {{{ hlgInvOetf(e_gamma.r),
- hlgInvOetf(e_gamma.g),
- hlgInvOetf(e_gamma.b) }}};
-}
-
-float hlgInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * (kHlgInvOETFNumEntries - 1) + 0.5);
- //TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kHlgInvOETFNumEntries - 1);
-
- return kHlgInvOETF[value];
-}
-
-Color hlgInvOetfLUT(Color e_gamma) {
- return {{{ hlgInvOetfLUT(e_gamma.r),
- hlgInvOetfLUT(e_gamma.g),
- hlgInvOetfLUT(e_gamma.b) }}};
-}
-
-// See ITU-R BT.2100-2, Table 4, Reference PQ OETF.
-static const float kPqM1 = 2610.0f / 16384.0f, kPqM2 = 2523.0f / 4096.0f * 128.0f;
-static const float kPqC1 = 3424.0f / 4096.0f, kPqC2 = 2413.0f / 4096.0f * 32.0f,
- kPqC3 = 2392.0f / 4096.0f * 32.0f;
-
-float pqOetf(float e) {
- if (e <= 0.0f) return 0.0f;
- return pow((kPqC1 + kPqC2 * pow(e, kPqM1)) / (1 + kPqC3 * pow(e, kPqM1)),
- kPqM2);
-}
-
-Color pqOetf(Color e) {
- return {{{ pqOetf(e.r), pqOetf(e.g), pqOetf(e.b) }}};
-}
-
-float pqOetfLUT(float e) {
- uint32_t value = static_cast<uint32_t>(e * (kPqOETFNumEntries - 1) + 0.5);
- //TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kPqOETFNumEntries - 1);
-
- return kPqOETF[value];
-}
-
-Color pqOetfLUT(Color e) {
- return {{{ pqOetfLUT(e.r), pqOetfLUT(e.g), pqOetfLUT(e.b) }}};
-}
-
-// Derived from the inverse of the Reference PQ OETF.
-static const float kPqInvA = 128.0f, kPqInvB = 107.0f, kPqInvC = 2413.0f, kPqInvD = 2392.0f,
- kPqInvE = 6.2773946361f, kPqInvF = 0.0126833f;
-
-float pqInvOetf(float e_gamma) {
- // This equation blows up if e_gamma is 0.0, and checking on <= 0.0 doesn't
- // always catch 0.0. So, check on 0.0001, since anything this small will
- // effectively be crushed to zero anyways.
- if (e_gamma <= 0.0001f) return 0.0f;
- return pow((kPqInvA * pow(e_gamma, kPqInvF) - kPqInvB)
- / (kPqInvC - kPqInvD * pow(e_gamma, kPqInvF)),
- kPqInvE);
-}
-
-Color pqInvOetf(Color e_gamma) {
- return {{{ pqInvOetf(e_gamma.r),
- pqInvOetf(e_gamma.g),
- pqInvOetf(e_gamma.b) }}};
-}
-
-float pqInvOetfLUT(float e_gamma) {
- uint32_t value = static_cast<uint32_t>(e_gamma * (kPqInvOETFNumEntries - 1) + 0.5);
- //TODO() : Remove once conversion modules have appropriate clamping in place
- value = CLIP3(value, 0, kPqInvOETFNumEntries - 1);
-
- return kPqInvOETF[value];
-}
-
-Color pqInvOetfLUT(Color e_gamma) {
- return {{{ pqInvOetfLUT(e_gamma.r),
- pqInvOetfLUT(e_gamma.g),
- pqInvOetfLUT(e_gamma.b) }}};
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Color conversions
-
-Color bt709ToP3(Color e) {
- return {{{ 0.82254f * e.r + 0.17755f * e.g + 0.00006f * e.b,
- 0.03312f * e.r + 0.96684f * e.g + -0.00001f * e.b,
- 0.01706f * e.r + 0.07240f * e.g + 0.91049f * e.b }}};
-}
-
-Color bt709ToBt2100(Color e) {
- return {{{ 0.62740f * e.r + 0.32930f * e.g + 0.04332f * e.b,
- 0.06904f * e.r + 0.91958f * e.g + 0.01138f * e.b,
- 0.01636f * e.r + 0.08799f * e.g + 0.89555f * e.b }}};
-}
-
-Color p3ToBt709(Color e) {
- return {{{ 1.22482f * e.r + -0.22490f * e.g + -0.00007f * e.b,
- -0.04196f * e.r + 1.04199f * e.g + 0.00001f * e.b,
- -0.01961f * e.r + -0.07865f * e.g + 1.09831f * e.b }}};
-}
-
-Color p3ToBt2100(Color e) {
- return {{{ 0.75378f * e.r + 0.19862f * e.g + 0.04754f * e.b,
- 0.04576f * e.r + 0.94177f * e.g + 0.01250f * e.b,
- -0.00121f * e.r + 0.01757f * e.g + 0.98359f * e.b }}};
-}
-
-Color bt2100ToBt709(Color e) {
- return {{{ 1.66045f * e.r + -0.58764f * e.g + -0.07286f * e.b,
- -0.12445f * e.r + 1.13282f * e.g + -0.00837f * e.b,
- -0.01811f * e.r + -0.10057f * e.g + 1.11878f * e.b }}};
-}
-
-Color bt2100ToP3(Color e) {
- return {{{ 1.34369f * e.r + -0.28223f * e.g + -0.06135f * e.b,
- -0.06533f * e.r + 1.07580f * e.g + -0.01051f * e.b,
- 0.00283f * e.r + -0.01957f * e.g + 1.01679f * e.b
- }}};
-}
-
-// TODO: confirm we always want to convert like this before calculating
-// luminance.
-ColorTransformFn getHdrConversionFn(ultrahdr_color_gamut sdr_gamut,
- ultrahdr_color_gamut hdr_gamut) {
- switch (sdr_gamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- switch (hdr_gamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- return identityConversion;
- case ULTRAHDR_COLORGAMUT_P3:
- return p3ToBt709;
- case ULTRAHDR_COLORGAMUT_BT2100:
- return bt2100ToBt709;
- case ULTRAHDR_COLORGAMUT_UNSPECIFIED:
- return nullptr;
- }
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- switch (hdr_gamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- return bt709ToP3;
- case ULTRAHDR_COLORGAMUT_P3:
- return identityConversion;
- case ULTRAHDR_COLORGAMUT_BT2100:
- return bt2100ToP3;
- case ULTRAHDR_COLORGAMUT_UNSPECIFIED:
- return nullptr;
- }
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- switch (hdr_gamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- return bt709ToBt2100;
- case ULTRAHDR_COLORGAMUT_P3:
- return p3ToBt2100;
- case ULTRAHDR_COLORGAMUT_BT2100:
- return identityConversion;
- case ULTRAHDR_COLORGAMUT_UNSPECIFIED:
- return nullptr;
- }
- break;
- case ULTRAHDR_COLORGAMUT_UNSPECIFIED:
- return nullptr;
- }
-}
-
-// All of these conversions are derived from the respective input YUV->RGB conversion followed by
-// the RGB->YUV for the receiving encoding. They are consistent with the RGB<->YUV functions in this
-// file, given that we uses BT.709 encoding for sRGB and BT.601 encoding for Display-P3, to match
-// DataSpace.
-
-Color yuv709To601(Color e_gamma) {
- return {{{ 1.0f * e_gamma.y + 0.101579f * e_gamma.u + 0.196076f * e_gamma.v,
- 0.0f * e_gamma.y + 0.989854f * e_gamma.u + -0.110653f * e_gamma.v,
- 0.0f * e_gamma.y + -0.072453f * e_gamma.u + 0.983398f * e_gamma.v }}};
-}
-
-Color yuv709To2100(Color e_gamma) {
- return {{{ 1.0f * e_gamma.y + -0.016969f * e_gamma.u + 0.096312f * e_gamma.v,
- 0.0f * e_gamma.y + 0.995306f * e_gamma.u + -0.051192f * e_gamma.v,
- 0.0f * e_gamma.y + 0.011507f * e_gamma.u + 1.002637f * e_gamma.v }}};
-}
-
-Color yuv601To709(Color e_gamma) {
- return {{{ 1.0f * e_gamma.y + -0.118188f * e_gamma.u + -0.212685f * e_gamma.v,
- 0.0f * e_gamma.y + 1.018640f * e_gamma.u + 0.114618f * e_gamma.v,
- 0.0f * e_gamma.y + 0.075049f * e_gamma.u + 1.025327f * e_gamma.v }}};
-}
-
-Color yuv601To2100(Color e_gamma) {
- return {{{ 1.0f * e_gamma.y + -0.128245f * e_gamma.u + -0.115879f * e_gamma.v,
- 0.0f * e_gamma.y + 1.010016f * e_gamma.u + 0.061592f * e_gamma.v,
- 0.0f * e_gamma.y + 0.086969f * e_gamma.u + 1.029350f * e_gamma.v }}};
-}
-
-Color yuv2100To709(Color e_gamma) {
- return {{{ 1.0f * e_gamma.y + 0.018149f * e_gamma.u + -0.095132f * e_gamma.v,
- 0.0f * e_gamma.y + 1.004123f * e_gamma.u + 0.051267f * e_gamma.v,
- 0.0f * e_gamma.y + -0.011524f * e_gamma.u + 0.996782f * e_gamma.v }}};
-}
-
-Color yuv2100To601(Color e_gamma) {
- return {{{ 1.0f * e_gamma.y + 0.117887f * e_gamma.u + 0.105521f * e_gamma.v,
- 0.0f * e_gamma.y + 0.995211f * e_gamma.u + -0.059549f * e_gamma.v,
- 0.0f * e_gamma.y + -0.084085f * e_gamma.u + 0.976518f * e_gamma.v }}};
-}
-
-void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma,
- ColorTransformFn fn) {
- Color yuv1 = getYuv420Pixel(image, x_chroma * 2, y_chroma * 2 );
- Color yuv2 = getYuv420Pixel(image, x_chroma * 2 + 1, y_chroma * 2 );
- Color yuv3 = getYuv420Pixel(image, x_chroma * 2, y_chroma * 2 + 1);
- Color yuv4 = getYuv420Pixel(image, x_chroma * 2 + 1, y_chroma * 2 + 1);
-
- yuv1 = fn(yuv1);
- yuv2 = fn(yuv2);
- yuv3 = fn(yuv3);
- yuv4 = fn(yuv4);
-
- Color new_uv = (yuv1 + yuv2 + yuv3 + yuv4) / 4.0f;
-
- size_t pixel_y1_idx = x_chroma * 2 + y_chroma * 2 * image->luma_stride;
- size_t pixel_y2_idx = (x_chroma * 2 + 1) + y_chroma * 2 * image->luma_stride;
- size_t pixel_y3_idx = x_chroma * 2 + (y_chroma * 2 + 1) * image->luma_stride;
- size_t pixel_y4_idx = (x_chroma * 2 + 1) + (y_chroma * 2 + 1) * image->luma_stride;
-
- uint8_t& y1_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y1_idx];
- uint8_t& y2_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y2_idx];
- uint8_t& y3_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y3_idx];
- uint8_t& y4_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y4_idx];
-
- size_t pixel_count = image->chroma_stride * image->height / 2;
- size_t pixel_uv_idx = x_chroma + y_chroma * (image->chroma_stride);
-
- uint8_t& u_uint = reinterpret_cast<uint8_t*>(image->chroma_data)[pixel_uv_idx];
- uint8_t& v_uint = reinterpret_cast<uint8_t*>(image->chroma_data)[pixel_count + pixel_uv_idx];
-
- y1_uint = static_cast<uint8_t>(CLIP3((yuv1.y * 255.0f + 0.5f), 0, 255));
- y2_uint = static_cast<uint8_t>(CLIP3((yuv2.y * 255.0f + 0.5f), 0, 255));
- y3_uint = static_cast<uint8_t>(CLIP3((yuv3.y * 255.0f + 0.5f), 0, 255));
- y4_uint = static_cast<uint8_t>(CLIP3((yuv4.y * 255.0f + 0.5f), 0, 255));
-
- u_uint = static_cast<uint8_t>(CLIP3((new_uv.u * 255.0f + 128.0f + 0.5f), 0, 255));
- v_uint = static_cast<uint8_t>(CLIP3((new_uv.v * 255.0f + 128.0f + 0.5f), 0, 255));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Gain map calculations
-uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata) {
- return encodeGain(y_sdr, y_hdr, metadata,
- log2(metadata->minContentBoost), log2(metadata->maxContentBoost));
-}
-
-uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata,
- float log2MinContentBoost, float log2MaxContentBoost) {
- float gain = 1.0f;
- if (y_sdr > 0.0f) {
- gain = y_hdr / y_sdr;
- }
-
- if (gain < metadata->minContentBoost) gain = metadata->minContentBoost;
- if (gain > metadata->maxContentBoost) gain = metadata->maxContentBoost;
-
- return static_cast<uint8_t>((log2(gain) - log2MinContentBoost)
- / (log2MaxContentBoost - log2MinContentBoost)
- * 255.0f);
-}
-
-Color applyGain(Color e, float gain, ultrahdr_metadata_ptr metadata) {
- float logBoost = log2(metadata->minContentBoost) * (1.0f - gain)
- + log2(metadata->maxContentBoost) * gain;
- float gainFactor = exp2(logBoost);
- return e * gainFactor;
-}
-
-Color applyGain(Color e, float gain, ultrahdr_metadata_ptr metadata, float displayBoost) {
- float logBoost = log2(metadata->minContentBoost) * (1.0f - gain)
- + log2(metadata->maxContentBoost) * gain;
- float gainFactor = exp2(logBoost * displayBoost / metadata->maxContentBoost);
- return e * gainFactor;
-}
-
-Color applyGainLUT(Color e, float gain, GainLUT& gainLUT) {
- float gainFactor = gainLUT.getGainFactor(gain);
- return e * gainFactor;
-}
-
-Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) {
- uint8_t* luma_data = reinterpret_cast<uint8_t*>(image->data);
- size_t luma_stride = image->luma_stride;
- uint8_t* chroma_data = reinterpret_cast<uint8_t*>(image->chroma_data);
- size_t chroma_stride = image->chroma_stride;
-
- size_t offset_cr = chroma_stride * (image->height / 2);
- size_t pixel_y_idx = x + y * luma_stride;
- size_t pixel_chroma_idx = x / 2 + (y / 2) * chroma_stride;
-
- uint8_t y_uint = luma_data[pixel_y_idx];
- uint8_t u_uint = chroma_data[pixel_chroma_idx];
- uint8_t v_uint = chroma_data[offset_cr + pixel_chroma_idx];
-
- // 128 bias for UV given we are using jpeglib; see:
- // https://github.com/kornelski/libjpeg/blob/master/structure.doc
- return {{{ static_cast<float>(y_uint) / 255.0f,
- (static_cast<float>(u_uint) - 128.0f) / 255.0f,
- (static_cast<float>(v_uint) - 128.0f) / 255.0f }}};
-}
-
-Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y) {
- uint16_t* luma_data = reinterpret_cast<uint16_t*>(image->data);
- size_t luma_stride = image->luma_stride == 0 ? image->width : image->luma_stride;
- uint16_t* chroma_data = reinterpret_cast<uint16_t*>(image->chroma_data);
- size_t chroma_stride = image->chroma_stride;
-
- size_t pixel_y_idx = y * luma_stride + x;
- size_t pixel_u_idx = (y >> 1) * chroma_stride + (x & ~0x1);
- size_t pixel_v_idx = pixel_u_idx + 1;
-
- uint16_t y_uint = luma_data[pixel_y_idx] >> 6;
- uint16_t u_uint = chroma_data[pixel_u_idx] >> 6;
- uint16_t v_uint = chroma_data[pixel_v_idx] >> 6;
-
- // Conversions include taking narrow-range into account.
- return {{{ (static_cast<float>(y_uint) - 64.0f) / 876.0f,
- (static_cast<float>(u_uint) - 64.0f) / 896.0f - 0.5f,
- (static_cast<float>(v_uint) - 64.0f) / 896.0f - 0.5f }}};
-}
-
-typedef Color (*getPixelFn)(jr_uncompressed_ptr, size_t, size_t);
-
-static Color samplePixels(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y,
- getPixelFn get_pixel_fn) {
- Color e = {{{ 0.0f, 0.0f, 0.0f }}};
- for (size_t dy = 0; dy < map_scale_factor; ++dy) {
- for (size_t dx = 0; dx < map_scale_factor; ++dx) {
- e += get_pixel_fn(image, x * map_scale_factor + dx, y * map_scale_factor + dy);
- }
- }
-
- return e / static_cast<float>(map_scale_factor * map_scale_factor);
-}
-
-Color sampleYuv420(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
- return samplePixels(image, map_scale_factor, x, y, getYuv420Pixel);
-}
-
-Color sampleP010(jr_uncompressed_ptr image, size_t map_scale_factor, size_t x, size_t y) {
- return samplePixels(image, map_scale_factor, x, y, getP010Pixel);
-}
-
-// TODO: do we need something more clever for filtering either the map or images
-// to generate the map?
-
-static size_t clamp(const size_t& val, const size_t& low, const size_t& high) {
- return val < low ? low : (high < val ? high : val);
-}
-
-static float mapUintToFloat(uint8_t map_uint) {
- return static_cast<float>(map_uint) / 255.0f;
-}
-
-static float pythDistance(float x_diff, float y_diff) {
- return sqrt(pow(x_diff, 2.0f) + pow(y_diff, 2.0f));
-}
-
-// TODO: If map_scale_factor is guaranteed to be an integer, then remove the following.
-float sampleMap(jr_uncompressed_ptr map, float map_scale_factor, size_t x, size_t y) {
- float x_map = static_cast<float>(x) / map_scale_factor;
- float y_map = static_cast<float>(y) / map_scale_factor;
-
- size_t x_lower = static_cast<size_t>(floor(x_map));
- size_t x_upper = x_lower + 1;
- size_t y_lower = static_cast<size_t>(floor(y_map));
- size_t y_upper = y_lower + 1;
-
- x_lower = clamp(x_lower, 0, map->width - 1);
- x_upper = clamp(x_upper, 0, map->width - 1);
- y_lower = clamp(y_lower, 0, map->height - 1);
- y_upper = clamp(y_upper, 0, map->height - 1);
-
- // Use Shepard's method for inverse distance weighting. For more information:
- // en.wikipedia.org/wiki/Inverse_distance_weighting#Shepard's_method
-
- float e1 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_lower * map->width]);
- float e1_dist = pythDistance(x_map - static_cast<float>(x_lower),
- y_map - static_cast<float>(y_lower));
- if (e1_dist == 0.0f) return e1;
-
- float e2 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_upper * map->width]);
- float e2_dist = pythDistance(x_map - static_cast<float>(x_lower),
- y_map - static_cast<float>(y_upper));
- if (e2_dist == 0.0f) return e2;
-
- float e3 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_lower * map->width]);
- float e3_dist = pythDistance(x_map - static_cast<float>(x_upper),
- y_map - static_cast<float>(y_lower));
- if (e3_dist == 0.0f) return e3;
-
- float e4 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_upper * map->width]);
- float e4_dist = pythDistance(x_map - static_cast<float>(x_upper),
- y_map - static_cast<float>(y_upper));
- if (e4_dist == 0.0f) return e2;
-
- float e1_weight = 1.0f / e1_dist;
- float e2_weight = 1.0f / e2_dist;
- float e3_weight = 1.0f / e3_dist;
- float e4_weight = 1.0f / e4_dist;
- float total_weight = e1_weight + e2_weight + e3_weight + e4_weight;
-
- return e1 * (e1_weight / total_weight)
- + e2 * (e2_weight / total_weight)
- + e3 * (e3_weight / total_weight)
- + e4 * (e4_weight / total_weight);
-}
-
-float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y,
- ShepardsIDW& weightTables) {
- // TODO: If map_scale_factor is guaranteed to be an integer power of 2, then optimize the
- // following by computing log2(map_scale_factor) once and then using >> log2(map_scale_factor)
- int x_lower = x / map_scale_factor;
- int x_upper = x_lower + 1;
- int y_lower = y / map_scale_factor;
- int y_upper = y_lower + 1;
-
- x_lower = std::min(x_lower, map->width - 1);
- x_upper = std::min(x_upper, map->width - 1);
- y_lower = std::min(y_lower, map->height - 1);
- y_upper = std::min(y_upper, map->height - 1);
-
- float e1 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_lower * map->width]);
- float e2 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_lower + y_upper * map->width]);
- float e3 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_lower * map->width]);
- float e4 = mapUintToFloat(reinterpret_cast<uint8_t*>(map->data)[x_upper + y_upper * map->width]);
-
- // TODO: If map_scale_factor is guaranteed to be an integer power of 2, then optimize the
- // following by using & (map_scale_factor - 1)
- int offset_x = x % map_scale_factor;
- int offset_y = y % map_scale_factor;
-
- float* weights = weightTables.mWeights;
- if (x_lower == x_upper && y_lower == y_upper) weights = weightTables.mWeightsC;
- else if (x_lower == x_upper) weights = weightTables.mWeightsNR;
- else if (y_lower == y_upper) weights = weightTables.mWeightsNB;
- weights += offset_y * map_scale_factor * 4 + offset_x * 4;
-
- return e1 * weights[0] + e2 * weights[1] + e3 * weights[2] + e4 * weights[3];
-}
-
-uint32_t colorToRgba1010102(Color e_gamma) {
- return (0x3ff & static_cast<uint32_t>(e_gamma.r * 1023.0f))
- | ((0x3ff & static_cast<uint32_t>(e_gamma.g * 1023.0f)) << 10)
- | ((0x3ff & static_cast<uint32_t>(e_gamma.b * 1023.0f)) << 20)
- | (0x3 << 30); // Set alpha to 1.0
-}
-
-uint64_t colorToRgbaF16(Color e_gamma) {
- return (uint64_t) floatToHalf(e_gamma.r)
- | (((uint64_t) floatToHalf(e_gamma.g)) << 16)
- | (((uint64_t) floatToHalf(e_gamma.b)) << 32)
- | (((uint64_t) floatToHalf(1.0f)) << 48);
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/icc.cpp b/libs/ultrahdr/icc.cpp
deleted file mode 100644
index e41b645..0000000
--- a/libs/ultrahdr/icc.cpp
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef USE_BIG_ENDIAN
-#define USE_BIG_ENDIAN true
-#endif
-
-#include <ultrahdr/icc.h>
-#include <vector>
-#include <utils/Log.h>
-
-#ifndef FLT_MAX
-#define FLT_MAX 0x1.fffffep127f
-#endif
-
-namespace android::ultrahdr {
-static void Matrix3x3_apply(const Matrix3x3* m, float* x) {
- float y0 = x[0] * m->vals[0][0] + x[1] * m->vals[0][1] + x[2] * m->vals[0][2];
- float y1 = x[0] * m->vals[1][0] + x[1] * m->vals[1][1] + x[2] * m->vals[1][2];
- float y2 = x[0] * m->vals[2][0] + x[1] * m->vals[2][1] + x[2] * m->vals[2][2];
- x[0] = y0;
- x[1] = y1;
- x[2] = y2;
-}
-
-bool Matrix3x3_invert(const Matrix3x3* src, Matrix3x3* dst) {
- double a00 = src->vals[0][0],
- a01 = src->vals[1][0],
- a02 = src->vals[2][0],
- a10 = src->vals[0][1],
- a11 = src->vals[1][1],
- a12 = src->vals[2][1],
- a20 = src->vals[0][2],
- a21 = src->vals[1][2],
- a22 = src->vals[2][2];
-
- double b0 = a00*a11 - a01*a10,
- b1 = a00*a12 - a02*a10,
- b2 = a01*a12 - a02*a11,
- b3 = a20,
- b4 = a21,
- b5 = a22;
-
- double determinant = b0*b5
- - b1*b4
- + b2*b3;
-
- if (determinant == 0) {
- return false;
- }
-
- double invdet = 1.0 / determinant;
- if (invdet > +FLT_MAX || invdet < -FLT_MAX || !isfinitef_((float)invdet)) {
- return false;
- }
-
- b0 *= invdet;
- b1 *= invdet;
- b2 *= invdet;
- b3 *= invdet;
- b4 *= invdet;
- b5 *= invdet;
-
- dst->vals[0][0] = (float)( a11*b5 - a12*b4 );
- dst->vals[1][0] = (float)( a02*b4 - a01*b5 );
- dst->vals[2][0] = (float)( + b2 );
- dst->vals[0][1] = (float)( a12*b3 - a10*b5 );
- dst->vals[1][1] = (float)( a00*b5 - a02*b3 );
- dst->vals[2][1] = (float)( - b1 );
- dst->vals[0][2] = (float)( a10*b4 - a11*b3 );
- dst->vals[1][2] = (float)( a01*b3 - a00*b4 );
- dst->vals[2][2] = (float)( + b0 );
-
- for (int r = 0; r < 3; ++r)
- for (int c = 0; c < 3; ++c) {
- if (!isfinitef_(dst->vals[r][c])) {
- return false;
- }
- }
- return true;
-}
-
-static Matrix3x3 Matrix3x3_concat(const Matrix3x3* A, const Matrix3x3* B) {
- Matrix3x3 m = { { { 0,0,0 },{ 0,0,0 },{ 0,0,0 } } };
- for (int r = 0; r < 3; r++)
- for (int c = 0; c < 3; c++) {
- m.vals[r][c] = A->vals[r][0] * B->vals[0][c]
- + A->vals[r][1] * B->vals[1][c]
- + A->vals[r][2] * B->vals[2][c];
- }
- return m;
-}
-
-static void float_XYZD50_to_grid16_lab(const float* xyz_float, uint8_t* grid16_lab) {
- float v[3] = {
- xyz_float[0] / kD50_x,
- xyz_float[1] / kD50_y,
- xyz_float[2] / kD50_z,
- };
- for (size_t i = 0; i < 3; ++i) {
- v[i] = v[i] > 0.008856f ? cbrtf(v[i]) : v[i] * 7.787f + (16 / 116.0f);
- }
- const float L = v[1] * 116.0f - 16.0f;
- const float a = (v[0] - v[1]) * 500.0f;
- const float b = (v[1] - v[2]) * 200.0f;
- const float Lab_unorm[3] = {
- L * (1 / 100.f),
- (a + 128.0f) * (1 / 255.0f),
- (b + 128.0f) * (1 / 255.0f),
- };
- // This will encode L=1 as 0xFFFF. This matches how skcms will interpret the
- // table, but the spec appears to indicate that the value should be 0xFF00.
- // https://crbug.com/skia/13807
- for (size_t i = 0; i < 3; ++i) {
- reinterpret_cast<uint16_t*>(grid16_lab)[i] =
- Endian_SwapBE16(float_round_to_unorm16(Lab_unorm[i]));
- }
-}
-
-std::string IccHelper::get_desc_string(const ultrahdr_transfer_function tf,
- const ultrahdr_color_gamut gamut) {
- std::string result;
- switch (gamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- result += "sRGB";
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- result += "Display P3";
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- result += "Rec2020";
- break;
- default:
- result += "Unknown";
- break;
- }
- result += " Gamut with ";
- switch (tf) {
- case ULTRAHDR_TF_SRGB:
- result += "sRGB";
- break;
- case ULTRAHDR_TF_LINEAR:
- result += "Linear";
- break;
- case ULTRAHDR_TF_PQ:
- result += "PQ";
- break;
- case ULTRAHDR_TF_HLG:
- result += "HLG";
- break;
- default:
- result += "Unknown";
- break;
- }
- result += " Transfer";
- return result;
-}
-
-sp<DataStruct> IccHelper::write_text_tag(const char* text) {
- uint32_t text_length = strlen(text);
- uint32_t header[] = {
- Endian_SwapBE32(kTAG_TextType), // Type signature
- 0, // Reserved
- Endian_SwapBE32(1), // Number of records
- Endian_SwapBE32(12), // Record size (must be 12)
- Endian_SwapBE32(SetFourByteTag('e', 'n', 'U', 'S')), // English USA
- Endian_SwapBE32(2 * text_length), // Length of string in bytes
- Endian_SwapBE32(28), // Offset of string
- };
-
- uint32_t total_length = text_length * 2 + sizeof(header);
- total_length = (((total_length + 2) >> 2) << 2); // 4 aligned
- sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
-
- if (!dataStruct->write(header, sizeof(header))) {
- ALOGE("write_text_tag(): error in writing data");
- return dataStruct;
- }
-
- for (size_t i = 0; i < text_length; i++) {
- // Convert ASCII to big-endian UTF-16.
- dataStruct->write8(0);
- dataStruct->write8(text[i]);
- }
-
- return dataStruct;
-}
-
-sp<DataStruct> IccHelper::write_xyz_tag(float x, float y, float z) {
- uint32_t data[] = {
- Endian_SwapBE32(kXYZ_PCSSpace),
- 0,
- static_cast<uint32_t>(Endian_SwapBE32(float_round_to_fixed(x))),
- static_cast<uint32_t>(Endian_SwapBE32(float_round_to_fixed(y))),
- static_cast<uint32_t>(Endian_SwapBE32(float_round_to_fixed(z))),
- };
- sp<DataStruct> dataStruct = sp<DataStruct>::make(sizeof(data));
- dataStruct->write(&data, sizeof(data));
- return dataStruct;
-}
-
-sp<DataStruct> IccHelper::write_trc_tag(const int table_entries, const void* table_16) {
- int total_length = 4 + 4 + 4 + table_entries * 2;
- total_length = (((total_length + 2) >> 2) << 2); // 4 aligned
- sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
- dataStruct->write32(Endian_SwapBE32(kTAG_CurveType)); // Type
- dataStruct->write32(0); // Reserved
- dataStruct->write32(Endian_SwapBE32(table_entries)); // Value count
- for (size_t i = 0; i < table_entries; ++i) {
- uint16_t value = reinterpret_cast<const uint16_t*>(table_16)[i];
- dataStruct->write16(value);
- }
- return dataStruct;
-}
-
-sp<DataStruct> IccHelper::write_trc_tag(const TransferFunction& fn) {
- if (fn.a == 1.f && fn.b == 0.f && fn.c == 0.f
- && fn.d == 0.f && fn.e == 0.f && fn.f == 0.f) {
- int total_length = 16;
- sp<DataStruct> dataStruct = new DataStruct(total_length);
- dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType)); // Type
- dataStruct->write32(0); // Reserved
- dataStruct->write32(Endian_SwapBE16(kExponential_ParaCurveType));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.g)));
- return dataStruct;
- }
-
- int total_length = 40;
- sp<DataStruct> dataStruct = new DataStruct(total_length);
- dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType)); // Type
- dataStruct->write32(0); // Reserved
- dataStruct->write32(Endian_SwapBE16(kGABCDEF_ParaCurveType));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.g)));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.a)));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.b)));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.c)));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.d)));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.e)));
- dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.f)));
- return dataStruct;
-}
-
-float IccHelper::compute_tone_map_gain(const ultrahdr_transfer_function tf, float L) {
- if (L <= 0.f) {
- return 1.f;
- }
- if (tf == ULTRAHDR_TF_PQ) {
- // The PQ transfer function will map to the range [0, 1]. Linearly scale
- // it up to the range [0, 10,000/203]. We will then tone map that back
- // down to [0, 1].
- constexpr float kInputMaxLuminance = 10000 / 203.f;
- constexpr float kOutputMaxLuminance = 1.0;
- L *= kInputMaxLuminance;
-
- // Compute the tone map gain which will tone map from 10,000/203 to 1.0.
- constexpr float kToneMapA = kOutputMaxLuminance / (kInputMaxLuminance * kInputMaxLuminance);
- constexpr float kToneMapB = 1.f / kOutputMaxLuminance;
- return kInputMaxLuminance * (1.f + kToneMapA * L) / (1.f + kToneMapB * L);
- }
- if (tf == ULTRAHDR_TF_HLG) {
- // Let Lw be the brightness of the display in nits.
- constexpr float Lw = 203.f;
- const float gamma = 1.2f + 0.42f * std::log(Lw / 1000.f) / std::log(10.f);
- return std::pow(L, gamma - 1.f);
- }
- return 1.f;
-}
-
-sp<DataStruct> IccHelper::write_cicp_tag(uint32_t color_primaries,
- uint32_t transfer_characteristics) {
- int total_length = 12; // 4 + 4 + 1 + 1 + 1 + 1
- sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
- dataStruct->write32(Endian_SwapBE32(kTAG_cicp)); // Type signature
- dataStruct->write32(0); // Reserved
- dataStruct->write8(color_primaries); // Color primaries
- dataStruct->write8(transfer_characteristics); // Transfer characteristics
- dataStruct->write8(0); // RGB matrix
- dataStruct->write8(1); // Full range
- return dataStruct;
-}
-
-void IccHelper::compute_lut_entry(const Matrix3x3& src_to_XYZD50, float rgb[3]) {
- // Compute the matrices to convert from source to Rec2020, and from Rec2020 to XYZD50.
- Matrix3x3 src_to_rec2020;
- const Matrix3x3 rec2020_to_XYZD50 = kRec2020;
- {
- Matrix3x3 XYZD50_to_rec2020;
- Matrix3x3_invert(&rec2020_to_XYZD50, &XYZD50_to_rec2020);
- src_to_rec2020 = Matrix3x3_concat(&XYZD50_to_rec2020, &src_to_XYZD50);
- }
-
- // Convert the source signal to linear.
- for (size_t i = 0; i < kNumChannels; ++i) {
- rgb[i] = pqOetf(rgb[i]);
- }
-
- // Convert source gamut to Rec2020.
- Matrix3x3_apply(&src_to_rec2020, rgb);
-
- // Compute the luminance of the signal.
- float L = bt2100Luminance({{{rgb[0], rgb[1], rgb[2]}}});
-
- // Compute the tone map gain based on the luminance.
- float tone_map_gain = compute_tone_map_gain(ULTRAHDR_TF_PQ, L);
-
- // Apply the tone map gain.
- for (size_t i = 0; i < kNumChannels; ++i) {
- rgb[i] *= tone_map_gain;
- }
-
- // Convert from Rec2020-linear to XYZD50.
- Matrix3x3_apply(&rec2020_to_XYZD50, rgb);
-}
-
-sp<DataStruct> IccHelper::write_clut(const uint8_t* grid_points, const uint8_t* grid_16) {
- uint32_t value_count = kNumChannels;
- for (uint32_t i = 0; i < kNumChannels; ++i) {
- value_count *= grid_points[i];
- }
-
- int total_length = 20 + 2 * value_count;
- total_length = (((total_length + 2) >> 2) << 2); // 4 aligned
- sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
-
- for (size_t i = 0; i < 16; ++i) {
- dataStruct->write8(i < kNumChannels ? grid_points[i] : 0); // Grid size
- }
- dataStruct->write8(2); // Grid byte width (always 16-bit)
- dataStruct->write8(0); // Reserved
- dataStruct->write8(0); // Reserved
- dataStruct->write8(0); // Reserved
-
- for (uint32_t i = 0; i < value_count; ++i) {
- uint16_t value = reinterpret_cast<const uint16_t*>(grid_16)[i];
- dataStruct->write16(value);
- }
-
- return dataStruct;
-}
-
-sp<DataStruct> IccHelper::write_mAB_or_mBA_tag(uint32_t type,
- bool has_a_curves,
- const uint8_t* grid_points,
- const uint8_t* grid_16) {
- const size_t b_curves_offset = 32;
- sp<DataStruct> b_curves_data[kNumChannels];
- sp<DataStruct> a_curves_data[kNumChannels];
- size_t clut_offset = 0;
- sp<DataStruct> clut;
- size_t a_curves_offset = 0;
-
- // The "B" curve is required.
- for (size_t i = 0; i < kNumChannels; ++i) {
- b_curves_data[i] = write_trc_tag(kLinear_TransFun);
- }
-
- // The "A" curve and CLUT are optional.
- if (has_a_curves) {
- clut_offset = b_curves_offset;
- for (size_t i = 0; i < kNumChannels; ++i) {
- clut_offset += b_curves_data[i]->getLength();
- }
- clut = write_clut(grid_points, grid_16);
-
- a_curves_offset = clut_offset + clut->getLength();
- for (size_t i = 0; i < kNumChannels; ++i) {
- a_curves_data[i] = write_trc_tag(kLinear_TransFun);
- }
- }
-
- int total_length = b_curves_offset;
- for (size_t i = 0; i < kNumChannels; ++i) {
- total_length += b_curves_data[i]->getLength();
- }
- if (has_a_curves) {
- total_length += clut->getLength();
- for (size_t i = 0; i < kNumChannels; ++i) {
- total_length += a_curves_data[i]->getLength();
- }
- }
- sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
- dataStruct->write32(Endian_SwapBE32(type)); // Type signature
- dataStruct->write32(0); // Reserved
- dataStruct->write8(kNumChannels); // Input channels
- dataStruct->write8(kNumChannels); // Output channels
- dataStruct->write16(0); // Reserved
- dataStruct->write32(Endian_SwapBE32(b_curves_offset)); // B curve offset
- dataStruct->write32(Endian_SwapBE32(0)); // Matrix offset (ignored)
- dataStruct->write32(Endian_SwapBE32(0)); // M curve offset (ignored)
- dataStruct->write32(Endian_SwapBE32(clut_offset)); // CLUT offset
- dataStruct->write32(Endian_SwapBE32(a_curves_offset)); // A curve offset
- for (size_t i = 0; i < kNumChannels; ++i) {
- if (dataStruct->write(b_curves_data[i]->getData(), b_curves_data[i]->getLength())) {
- return dataStruct;
- }
- }
- if (has_a_curves) {
- dataStruct->write(clut->getData(), clut->getLength());
- for (size_t i = 0; i < kNumChannels; ++i) {
- dataStruct->write(a_curves_data[i]->getData(), a_curves_data[i]->getLength());
- }
- }
- return dataStruct;
-}
-
-sp<DataStruct> IccHelper::writeIccProfile(ultrahdr_transfer_function tf,
- ultrahdr_color_gamut gamut) {
- ICCHeader header;
-
- std::vector<std::pair<uint32_t, sp<DataStruct>>> tags;
-
- // Compute profile description tag
- std::string desc = get_desc_string(tf, gamut);
-
- tags.emplace_back(kTAG_desc, write_text_tag(desc.c_str()));
-
- Matrix3x3 toXYZD50;
- switch (gamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- toXYZD50 = kSRGB;
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- toXYZD50 = kDisplayP3;
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- toXYZD50 = kRec2020;
- break;
- default:
- // Should not fall here.
- return nullptr;
- }
-
- // Compute primaries.
- {
- tags.emplace_back(kTAG_rXYZ,
- write_xyz_tag(toXYZD50.vals[0][0], toXYZD50.vals[1][0], toXYZD50.vals[2][0]));
- tags.emplace_back(kTAG_gXYZ,
- write_xyz_tag(toXYZD50.vals[0][1], toXYZD50.vals[1][1], toXYZD50.vals[2][1]));
- tags.emplace_back(kTAG_bXYZ,
- write_xyz_tag(toXYZD50.vals[0][2], toXYZD50.vals[1][2], toXYZD50.vals[2][2]));
- }
-
- // Compute white point tag (must be D50)
- tags.emplace_back(kTAG_wtpt, write_xyz_tag(kD50_x, kD50_y, kD50_z));
-
- // Compute transfer curves.
- if (tf != ULTRAHDR_TF_PQ) {
- if (tf == ULTRAHDR_TF_HLG) {
- std::vector<uint8_t> trc_table;
- trc_table.resize(kTrcTableSize * 2);
- for (uint32_t i = 0; i < kTrcTableSize; ++i) {
- float x = i / (kTrcTableSize - 1.f);
- float y = hlgOetf(x);
- y *= compute_tone_map_gain(tf, y);
- float_to_table16(y, &trc_table[2 * i]);
- }
-
- tags.emplace_back(kTAG_rTRC,
- write_trc_tag(kTrcTableSize, reinterpret_cast<uint8_t*>(trc_table.data())));
- tags.emplace_back(kTAG_gTRC,
- write_trc_tag(kTrcTableSize, reinterpret_cast<uint8_t*>(trc_table.data())));
- tags.emplace_back(kTAG_bTRC,
- write_trc_tag(kTrcTableSize, reinterpret_cast<uint8_t*>(trc_table.data())));
- } else {
- tags.emplace_back(kTAG_rTRC, write_trc_tag(kSRGB_TransFun));
- tags.emplace_back(kTAG_gTRC, write_trc_tag(kSRGB_TransFun));
- tags.emplace_back(kTAG_bTRC, write_trc_tag(kSRGB_TransFun));
- }
- }
-
- // Compute CICP.
- if (tf == ULTRAHDR_TF_HLG || tf == ULTRAHDR_TF_PQ) {
- // The CICP tag is present in ICC 4.4, so update the header's version.
- header.version = Endian_SwapBE32(0x04400000);
-
- uint32_t color_primaries = 0;
- if (gamut == ULTRAHDR_COLORGAMUT_BT709) {
- color_primaries = kCICPPrimariesSRGB;
- } else if (gamut == ULTRAHDR_COLORGAMUT_P3) {
- color_primaries = kCICPPrimariesP3;
- }
-
- uint32_t transfer_characteristics = 0;
- if (tf == ULTRAHDR_TF_SRGB) {
- transfer_characteristics = kCICPTrfnSRGB;
- } else if (tf == ULTRAHDR_TF_LINEAR) {
- transfer_characteristics = kCICPTrfnLinear;
- } else if (tf == ULTRAHDR_TF_PQ) {
- transfer_characteristics = kCICPTrfnPQ;
- } else if (tf == ULTRAHDR_TF_HLG) {
- transfer_characteristics = kCICPTrfnHLG;
- }
- tags.emplace_back(kTAG_cicp, write_cicp_tag(color_primaries, transfer_characteristics));
- }
-
- // Compute A2B0.
- if (tf == ULTRAHDR_TF_PQ) {
- std::vector<uint8_t> a2b_grid;
- a2b_grid.resize(kGridSize * kGridSize * kGridSize * kNumChannels * 2);
- size_t a2b_grid_index = 0;
- for (uint32_t r_index = 0; r_index < kGridSize; ++r_index) {
- for (uint32_t g_index = 0; g_index < kGridSize; ++g_index) {
- for (uint32_t b_index = 0; b_index < kGridSize; ++b_index) {
- float rgb[3] = {
- r_index / (kGridSize - 1.f),
- g_index / (kGridSize - 1.f),
- b_index / (kGridSize - 1.f),
- };
- compute_lut_entry(toXYZD50, rgb);
- float_XYZD50_to_grid16_lab(rgb, &a2b_grid[a2b_grid_index]);
- a2b_grid_index += 6;
- }
- }
- }
- const uint8_t* grid_16 = reinterpret_cast<const uint8_t*>(a2b_grid.data());
-
- uint8_t grid_points[kNumChannels];
- for (size_t i = 0; i < kNumChannels; ++i) {
- grid_points[i] = kGridSize;
- }
-
- auto a2b_data = write_mAB_or_mBA_tag(kTAG_mABType,
- /* has_a_curves */ true,
- grid_points,
- grid_16);
- tags.emplace_back(kTAG_A2B0, std::move(a2b_data));
- }
-
- // Compute B2A0.
- if (tf == ULTRAHDR_TF_PQ) {
- auto b2a_data = write_mAB_or_mBA_tag(kTAG_mBAType,
- /* has_a_curves */ false,
- /* grid_points */ nullptr,
- /* grid_16 */ nullptr);
- tags.emplace_back(kTAG_B2A0, std::move(b2a_data));
- }
-
- // Compute copyright tag
- tags.emplace_back(kTAG_cprt, write_text_tag("Google Inc. 2022"));
-
- // Compute the size of the profile.
- size_t tag_data_size = 0;
- for (const auto& tag : tags) {
- tag_data_size += tag.second->getLength();
- }
- size_t tag_table_size = kICCTagTableEntrySize * tags.size();
- size_t profile_size = kICCHeaderSize + tag_table_size + tag_data_size;
-
- sp<DataStruct> dataStruct = sp<DataStruct>::make(profile_size + kICCIdentifierSize);
-
- // Write identifier, chunk count, and chunk ID
- if (!dataStruct->write(kICCIdentifier, sizeof(kICCIdentifier)) ||
- !dataStruct->write8(1) || !dataStruct->write8(1)) {
- ALOGE("writeIccProfile(): error in identifier");
- return dataStruct;
- }
-
- // Write the header.
- header.data_color_space = Endian_SwapBE32(Signature_RGB);
- header.pcs = Endian_SwapBE32(tf == ULTRAHDR_TF_PQ ? Signature_Lab : Signature_XYZ);
- header.size = Endian_SwapBE32(profile_size);
- header.tag_count = Endian_SwapBE32(tags.size());
-
- if (!dataStruct->write(&header, sizeof(header))) {
- ALOGE("writeIccProfile(): error in header");
- return dataStruct;
- }
-
- // Write the tag table. Track the offset and size of the previous tag to
- // compute each tag's offset. An empty SkData indicates that the previous
- // tag is to be reused.
- uint32_t last_tag_offset = sizeof(header) + tag_table_size;
- uint32_t last_tag_size = 0;
- for (const auto& tag : tags) {
- last_tag_offset = last_tag_offset + last_tag_size;
- last_tag_size = tag.second->getLength();
- uint32_t tag_table_entry[3] = {
- Endian_SwapBE32(tag.first),
- Endian_SwapBE32(last_tag_offset),
- Endian_SwapBE32(last_tag_size),
- };
- if (!dataStruct->write(tag_table_entry, sizeof(tag_table_entry))) {
- ALOGE("writeIccProfile(): error in writing tag table");
- return dataStruct;
- }
- }
-
- // Write the tags.
- for (const auto& tag : tags) {
- if (!dataStruct->write(tag.second->getData(), tag.second->getLength())) {
- ALOGE("writeIccProfile(): error in writing tags");
- return dataStruct;
- }
- }
-
- return dataStruct;
-}
-
-bool IccHelper::tagsEqualToMatrix(const Matrix3x3& matrix,
- const uint8_t* red_tag,
- const uint8_t* green_tag,
- const uint8_t* blue_tag) {
- sp<DataStruct> red_tag_test = write_xyz_tag(matrix.vals[0][0], matrix.vals[1][0],
- matrix.vals[2][0]);
- sp<DataStruct> green_tag_test = write_xyz_tag(matrix.vals[0][1], matrix.vals[1][1],
- matrix.vals[2][1]);
- sp<DataStruct> blue_tag_test = write_xyz_tag(matrix.vals[0][2], matrix.vals[1][2],
- matrix.vals[2][2]);
- return memcmp(red_tag, red_tag_test->getData(), kColorantTagSize) == 0 &&
- memcmp(green_tag, green_tag_test->getData(), kColorantTagSize) == 0 &&
- memcmp(blue_tag, blue_tag_test->getData(), kColorantTagSize) == 0;
-}
-
-ultrahdr_color_gamut IccHelper::readIccColorGamut(void* icc_data, size_t icc_size) {
- // Each tag table entry consists of 3 fields of 4 bytes each.
- static const size_t kTagTableEntrySize = 12;
-
- if (icc_data == nullptr || icc_size < sizeof(ICCHeader) + kICCIdentifierSize) {
- return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- }
-
- if (memcmp(icc_data, kICCIdentifier, sizeof(kICCIdentifier)) != 0) {
- return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- }
-
- uint8_t* icc_bytes = reinterpret_cast<uint8_t*>(icc_data) + kICCIdentifierSize;
-
- ICCHeader* header = reinterpret_cast<ICCHeader*>(icc_bytes);
-
- // Use 0 to indicate not found, since offsets are always relative to start
- // of ICC data and therefore a tag offset of zero would never be valid.
- size_t red_primary_offset = 0, green_primary_offset = 0, blue_primary_offset = 0;
- size_t red_primary_size = 0, green_primary_size = 0, blue_primary_size = 0;
- for (size_t tag_idx = 0; tag_idx < Endian_SwapBE32(header->tag_count); ++tag_idx) {
- uint32_t* tag_entry_start = reinterpret_cast<uint32_t*>(
- icc_bytes + sizeof(ICCHeader) + tag_idx * kTagTableEntrySize);
- // first 4 bytes are the tag signature, next 4 bytes are the tag offset,
- // last 4 bytes are the tag length in bytes.
- if (red_primary_offset == 0 && *tag_entry_start == Endian_SwapBE32(kTAG_rXYZ)) {
- red_primary_offset = Endian_SwapBE32(*(tag_entry_start+1));
- red_primary_size = Endian_SwapBE32(*(tag_entry_start+2));
- } else if (green_primary_offset == 0 && *tag_entry_start == Endian_SwapBE32(kTAG_gXYZ)) {
- green_primary_offset = Endian_SwapBE32(*(tag_entry_start+1));
- green_primary_size = Endian_SwapBE32(*(tag_entry_start+2));
- } else if (blue_primary_offset == 0 && *tag_entry_start == Endian_SwapBE32(kTAG_bXYZ)) {
- blue_primary_offset = Endian_SwapBE32(*(tag_entry_start+1));
- blue_primary_size = Endian_SwapBE32(*(tag_entry_start+2));
- }
- }
-
- if (red_primary_offset == 0 || red_primary_size != kColorantTagSize ||
- kICCIdentifierSize + red_primary_offset + red_primary_size > icc_size ||
- green_primary_offset == 0 || green_primary_size != kColorantTagSize ||
- kICCIdentifierSize + green_primary_offset + green_primary_size > icc_size ||
- blue_primary_offset == 0 || blue_primary_size != kColorantTagSize ||
- kICCIdentifierSize + blue_primary_offset + blue_primary_size > icc_size) {
- return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- }
-
- uint8_t* red_tag = icc_bytes + red_primary_offset;
- uint8_t* green_tag = icc_bytes + green_primary_offset;
- uint8_t* blue_tag = icc_bytes + blue_primary_offset;
-
- // Serialize tags as we do on encode and compare what we find to that to
- // determine the gamut (since we don't have a need yet for full deserialize).
- if (tagsEqualToMatrix(kSRGB, red_tag, green_tag, blue_tag)) {
- return ULTRAHDR_COLORGAMUT_BT709;
- } else if (tagsEqualToMatrix(kDisplayP3, red_tag, green_tag, blue_tag)) {
- return ULTRAHDR_COLORGAMUT_P3;
- } else if (tagsEqualToMatrix(kRec2020, red_tag, green_tag, blue_tag)) {
- return ULTRAHDR_COLORGAMUT_BT2100;
- }
-
- // Didn't find a match to one of the profiles we write; indicate the gamut
- // is unspecified since we don't understand it.
- return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h
deleted file mode 100644
index 9f1238f..0000000
--- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_RECOVERYMAPMATH_H
-#define ANDROID_ULTRAHDR_RECOVERYMAPMATH_H
-
-#include <cmath>
-#include <stdint.h>
-
-#include <ultrahdr/jpegr.h>
-
-namespace android::ultrahdr {
-
-#define CLIP3(x, min, max) ((x) < (min)) ? (min) : ((x) > (max)) ? (max) : (x)
-
-////////////////////////////////////////////////////////////////////////////////
-// Framework
-
-const float kSdrWhiteNits = 100.0f;
-const float kHlgMaxNits = 1000.0f;
-const float kPqMaxNits = 10000.0f;
-
-struct Color {
- union {
- struct {
- float r;
- float g;
- float b;
- };
- struct {
- float y;
- float u;
- float v;
- };
- };
-};
-
-typedef Color (*ColorTransformFn)(Color);
-typedef float (*ColorCalculationFn)(Color);
-
-// A transfer function mapping encoded values to linear values,
-// represented by this 7-parameter piecewise function:
-//
-// linear = sign(encoded) * (c*|encoded| + f) , 0 <= |encoded| < d
-// = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded|
-//
-// (A simple gamma transfer function sets g to gamma and a to 1.)
-typedef struct TransferFunction {
- float g, a,b,c,d,e,f;
-} TransferFunction;
-
-static constexpr TransferFunction kSRGB_TransFun =
- { 2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0.0f, 0.0f };
-
-static constexpr TransferFunction kLinear_TransFun =
- { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
-
-inline Color operator+=(Color& lhs, const Color& rhs) {
- lhs.r += rhs.r;
- lhs.g += rhs.g;
- lhs.b += rhs.b;
- return lhs;
-}
-inline Color operator-=(Color& lhs, const Color& rhs) {
- lhs.r -= rhs.r;
- lhs.g -= rhs.g;
- lhs.b -= rhs.b;
- return lhs;
-}
-
-inline Color operator+(const Color& lhs, const Color& rhs) {
- Color temp = lhs;
- return temp += rhs;
-}
-inline Color operator-(const Color& lhs, const Color& rhs) {
- Color temp = lhs;
- return temp -= rhs;
-}
-
-inline Color operator+=(Color& lhs, const float rhs) {
- lhs.r += rhs;
- lhs.g += rhs;
- lhs.b += rhs;
- return lhs;
-}
-inline Color operator-=(Color& lhs, const float rhs) {
- lhs.r -= rhs;
- lhs.g -= rhs;
- lhs.b -= rhs;
- return lhs;
-}
-inline Color operator*=(Color& lhs, const float rhs) {
- lhs.r *= rhs;
- lhs.g *= rhs;
- lhs.b *= rhs;
- return lhs;
-}
-inline Color operator/=(Color& lhs, const float rhs) {
- lhs.r /= rhs;
- lhs.g /= rhs;
- lhs.b /= rhs;
- return lhs;
-}
-
-inline Color operator+(const Color& lhs, const float rhs) {
- Color temp = lhs;
- return temp += rhs;
-}
-inline Color operator-(const Color& lhs, const float rhs) {
- Color temp = lhs;
- return temp -= rhs;
-}
-inline Color operator*(const Color& lhs, const float rhs) {
- Color temp = lhs;
- return temp *= rhs;
-}
-inline Color operator/(const Color& lhs, const float rhs) {
- Color temp = lhs;
- return temp /= rhs;
-}
-
-inline uint16_t floatToHalf(float f) {
- // round-to-nearest-even: add last bit after truncated mantissa
- const uint32_t b = *((uint32_t*)&f) + 0x00001000;
-
- const uint32_t e = (b & 0x7F800000) >> 23; // exponent
- const uint32_t m = b & 0x007FFFFF; // mantissa
-
- // sign : normalized : denormalized : saturate
- return (b & 0x80000000) >> 16
- | (e > 112) * ((((e - 112) << 10) & 0x7C00) | m >> 13)
- | ((e < 113) & (e > 101)) * ((((0x007FF000 + m) >> (125 - e)) + 1) >> 1)
- | (e > 143) * 0x7FFF;
-}
-
-constexpr size_t kGainFactorPrecision = 10;
-constexpr size_t kGainFactorNumEntries = 1 << kGainFactorPrecision;
-struct GainLUT {
- GainLUT(ultrahdr_metadata_ptr metadata) {
- for (int idx = 0; idx < kGainFactorNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
- float logBoost = log2(metadata->minContentBoost) * (1.0f - value)
- + log2(metadata->maxContentBoost) * value;
- mGainTable[idx] = exp2(logBoost);
- }
- }
-
- GainLUT(ultrahdr_metadata_ptr metadata, float displayBoost) {
- float boostFactor = displayBoost > 0 ? displayBoost / metadata->maxContentBoost : 1.0f;
- for (int idx = 0; idx < kGainFactorNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
- float logBoost = log2(metadata->minContentBoost) * (1.0f - value)
- + log2(metadata->maxContentBoost) * value;
- mGainTable[idx] = exp2(logBoost * boostFactor);
- }
- }
-
- ~GainLUT() {
- }
-
- float getGainFactor(float gain) {
- uint32_t idx = static_cast<uint32_t>(gain * (kGainFactorNumEntries - 1) + 0.5);
- //TODO() : Remove once conversion modules have appropriate clamping in place
- idx = CLIP3(idx, 0, kGainFactorNumEntries - 1);
- return mGainTable[idx];
- }
-
-private:
- float mGainTable[kGainFactorNumEntries];
-};
-
-struct ShepardsIDW {
- ShepardsIDW(int mapScaleFactor) : mMapScaleFactor{mapScaleFactor} {
- const int size = mMapScaleFactor * mMapScaleFactor * 4;
- mWeights = new float[size];
- mWeightsNR = new float[size];
- mWeightsNB = new float[size];
- mWeightsC = new float[size];
- fillShepardsIDW(mWeights, 1, 1);
- fillShepardsIDW(mWeightsNR, 0, 1);
- fillShepardsIDW(mWeightsNB, 1, 0);
- fillShepardsIDW(mWeightsC, 0, 0);
- }
- ~ShepardsIDW() {
- delete[] mWeights;
- delete[] mWeightsNR;
- delete[] mWeightsNB;
- delete[] mWeightsC;
- }
-
- int mMapScaleFactor;
- // Image :-
- // p00 p01 p02 p03 p04 p05 p06 p07
- // p10 p11 p12 p13 p14 p15 p16 p17
- // p20 p21 p22 p23 p24 p25 p26 p27
- // p30 p31 p32 p33 p34 p35 p36 p37
- // p40 p41 p42 p43 p44 p45 p46 p47
- // p50 p51 p52 p53 p54 p55 p56 p57
- // p60 p61 p62 p63 p64 p65 p66 p67
- // p70 p71 p72 p73 p74 p75 p76 p77
-
- // Gain Map (for 4 scale factor) :-
- // m00 p01
- // m10 m11
-
- // Gain sample of curr 4x4, right 4x4, bottom 4x4, bottom right 4x4 are used during
- // reconstruction. hence table weight size is 4.
- float* mWeights;
- // TODO: check if its ok to mWeights at places
- float* mWeightsNR; // no right
- float* mWeightsNB; // no bottom
- float* mWeightsC; // no right & bottom
-
- float euclideanDistance(float x1, float x2, float y1, float y2);
- void fillShepardsIDW(float *weights, int incR, int incB);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// sRGB transformations
-// NOTE: sRGB has the same color primaries as BT.709, but different transfer
-// function. For this reason, all sRGB transformations here apply to BT.709,
-// except for those concerning transfer functions.
-
-/*
- * Calculate the luminance of a linear RGB sRGB pixel, according to
- * IEC 61966-2-1/Amd 1:2003.
- *
- * [0.0, 1.0] range in and out.
- */
-float srgbLuminance(Color e);
-
-/*
- * Convert from OETF'd srgb RGB to YUV, according to ITU-R BT.709-6.
- *
- * BT.709 YUV<->RGB matrix is used to match expectations for DataSpace.
- */
-Color srgbRgbToYuv(Color e_gamma);
-
-
-/*
- * Convert from OETF'd srgb YUV to RGB, according to ITU-R BT.709-6.
- *
- * BT.709 YUV<->RGB matrix is used to match expectations for DataSpace.
- */
-Color srgbYuvToRgb(Color e_gamma);
-
-/*
- * Convert from srgb to linear, according to IEC 61966-2-1/Amd 1:2003.
- *
- * [0.0, 1.0] range in and out.
- */
-float srgbInvOetf(float e_gamma);
-Color srgbInvOetf(Color e_gamma);
-float srgbInvOetfLUT(float e_gamma);
-Color srgbInvOetfLUT(Color e_gamma);
-
-constexpr size_t kSrgbInvOETFPrecision = 10;
-constexpr size_t kSrgbInvOETFNumEntries = 1 << kSrgbInvOETFPrecision;
-
-////////////////////////////////////////////////////////////////////////////////
-// Display-P3 transformations
-
-/*
- * Calculated the luminance of a linear RGB P3 pixel, according to SMPTE EG 432-1.
- *
- * [0.0, 1.0] range in and out.
- */
-float p3Luminance(Color e);
-
-/*
- * Convert from OETF'd P3 RGB to YUV, according to ITU-R BT.601-7.
- *
- * BT.601 YUV<->RGB matrix is used to match expectations for DataSpace.
- */
-Color p3RgbToYuv(Color e_gamma);
-
-/*
- * Convert from OETF'd P3 YUV to RGB, according to ITU-R BT.601-7.
- *
- * BT.601 YUV<->RGB matrix is used to match expectations for DataSpace.
- */
-Color p3YuvToRgb(Color e_gamma);
-
-
-////////////////////////////////////////////////////////////////////////////////
-// BT.2100 transformations - according to ITU-R BT.2100-2
-
-/*
- * Calculate the luminance of a linear RGB BT.2100 pixel.
- *
- * [0.0, 1.0] range in and out.
- */
-float bt2100Luminance(Color e);
-
-/*
- * Convert from OETF'd BT.2100 RGB to YUV, according to ITU-R BT.2100-2.
- *
- * BT.2100 YUV<->RGB matrix is used to match expectations for DataSpace.
- */
-Color bt2100RgbToYuv(Color e_gamma);
-
-/*
- * Convert from OETF'd BT.2100 YUV to RGB, according to ITU-R BT.2100-2.
- *
- * BT.2100 YUV<->RGB matrix is used to match expectations for DataSpace.
- */
-Color bt2100YuvToRgb(Color e_gamma);
-
-/*
- * Convert from scene luminance to HLG.
- *
- * [0.0, 1.0] range in and out.
- */
-float hlgOetf(float e);
-Color hlgOetf(Color e);
-float hlgOetfLUT(float e);
-Color hlgOetfLUT(Color e);
-
-constexpr size_t kHlgOETFPrecision = 16;
-constexpr size_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
-
-/*
- * Convert from HLG to scene luminance.
- *
- * [0.0, 1.0] range in and out.
- */
-float hlgInvOetf(float e_gamma);
-Color hlgInvOetf(Color e_gamma);
-float hlgInvOetfLUT(float e_gamma);
-Color hlgInvOetfLUT(Color e_gamma);
-
-constexpr size_t kHlgInvOETFPrecision = 12;
-constexpr size_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
-
-/*
- * Convert from scene luminance to PQ.
- *
- * [0.0, 1.0] range in and out.
- */
-float pqOetf(float e);
-Color pqOetf(Color e);
-float pqOetfLUT(float e);
-Color pqOetfLUT(Color e);
-
-constexpr size_t kPqOETFPrecision = 16;
-constexpr size_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
-
-/*
- * Convert from PQ to scene luminance in nits.
- *
- * [0.0, 1.0] range in and out.
- */
-float pqInvOetf(float e_gamma);
-Color pqInvOetf(Color e_gamma);
-float pqInvOetfLUT(float e_gamma);
-Color pqInvOetfLUT(Color e_gamma);
-
-constexpr size_t kPqInvOETFPrecision = 12;
-constexpr size_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Color space conversions
-
-/*
- * Convert between color spaces with linear RGB data, according to ITU-R BT.2407 and EG 432-1.
- *
- * All conversions are derived from multiplying the matrix for XYZ to output RGB color gamut by the
- * matrix for input RGB color gamut to XYZ. The matrix for converting from XYZ to an RGB gamut is
- * always the inverse of the RGB gamut to XYZ matrix.
- */
-Color bt709ToP3(Color e);
-Color bt709ToBt2100(Color e);
-Color p3ToBt709(Color e);
-Color p3ToBt2100(Color e);
-Color bt2100ToBt709(Color e);
-Color bt2100ToP3(Color e);
-
-/*
- * Identity conversion.
- */
-inline Color identityConversion(Color e) { return e; }
-
-/*
- * Get the conversion to apply to the HDR image for gain map generation
- */
-ColorTransformFn getHdrConversionFn(ultrahdr_color_gamut sdr_gamut, ultrahdr_color_gamut hdr_gamut);
-
-/*
- * Convert between YUV encodings, according to ITU-R BT.709-6, ITU-R BT.601-7, and ITU-R BT.2100-2.
- *
- * Bt.709 and Bt.2100 have well-defined YUV encodings; Display-P3's is less well defined, but is
- * treated as Bt.601 by DataSpace, hence we do the same.
- */
-Color yuv709To601(Color e_gamma);
-Color yuv709To2100(Color e_gamma);
-Color yuv601To709(Color e_gamma);
-Color yuv601To2100(Color e_gamma);
-Color yuv2100To709(Color e_gamma);
-Color yuv2100To601(Color e_gamma);
-
-/*
- * Performs a transformation at the chroma x and y coordinates provided on a YUV420 image.
- *
- * Apply the transformation by determining transformed YUV for each of the 4 Y + 1 UV; each Y gets
- * this result, and UV gets the averaged result.
- *
- * x_chroma and y_chroma should be less than or equal to half the image's width and height
- * respecitively, since input is 4:2:0 subsampled.
- */
-void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma,
- ColorTransformFn fn);
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Gain map calculations
-
-/*
- * Calculate the 8-bit unsigned integer gain value for the given SDR and HDR
- * luminances in linear space, and the hdr ratio to encode against.
- *
- * Note: since this library always uses gamma of 1.0, offsetSdr of 0.0, and
- * offsetHdr of 0.0, this function doesn't handle different metadata values for
- * these fields.
- */
-uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata);
-uint8_t encodeGain(float y_sdr, float y_hdr, ultrahdr_metadata_ptr metadata,
- float log2MinContentBoost, float log2MaxContentBoost);
-
-/*
- * Calculates the linear luminance in nits after applying the given gain
- * value, with the given hdr ratio, to the given sdr input in the range [0, 1].
- *
- * Note: similar to encodeGain(), this function only supports gamma 1.0,
- * offsetSdr 0.0, offsetHdr 0.0, hdrCapacityMin 1.0, and hdrCapacityMax equal to
- * gainMapMax, as this library encodes.
- */
-Color applyGain(Color e, float gain, ultrahdr_metadata_ptr metadata);
-Color applyGain(Color e, float gain, ultrahdr_metadata_ptr metadata, float displayBoost);
-Color applyGainLUT(Color e, float gain, GainLUT& gainLUT);
-
-/*
- * Helper for sampling from YUV 420 images.
- */
-Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y);
-
-/*
- * Helper for sampling from P010 images.
- *
- * Expect narrow-range image data for P010.
- */
-Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y);
-
-/*
- * Sample the image at the provided location, with a weighting based on nearby
- * pixels and the map scale factor.
- */
-Color sampleYuv420(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y);
-
-/*
- * Sample the image at the provided location, with a weighting based on nearby
- * pixels and the map scale factor.
- *
- * Expect narrow-range image data for P010.
- */
-Color sampleP010(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y);
-
-/*
- * Sample the gain value for the map from a given x,y coordinate on a scale
- * that is map scale factor larger than the map size.
- */
-float sampleMap(jr_uncompressed_ptr map, float map_scale_factor, size_t x, size_t y);
-float sampleMap(jr_uncompressed_ptr map, size_t map_scale_factor, size_t x, size_t y,
- ShepardsIDW& weightTables);
-
-/*
- * Convert from Color to RGBA1010102.
- *
- * Alpha always set to 1.0.
- */
-uint32_t colorToRgba1010102(Color e_gamma);
-
-/*
- * Convert from Color to F16.
- *
- * Alpha always set to 1.0.
- */
-uint64_t colorToRgbaF16(Color e_gamma);
-
-} // namespace android::ultrahdr
-
-#endif // ANDROID_ULTRAHDR_RECOVERYMAPMATH_H
diff --git a/libs/ultrahdr/include/ultrahdr/icc.h b/libs/ultrahdr/include/ultrahdr/icc.h
deleted file mode 100644
index 971b267..0000000
--- a/libs/ultrahdr/include/ultrahdr/icc.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_ICC_H
-#define ANDROID_ULTRAHDR_ICC_H
-
-#include <ultrahdr/gainmapmath.h>
-#include <ultrahdr/jpegr.h>
-#include <ultrahdr/jpegrutils.h>
-#include <utils/RefBase.h>
-#include <cmath>
-#include <string>
-
-#ifdef USE_BIG_ENDIAN
-#undef USE_BIG_ENDIAN
-#define USE_BIG_ENDIAN true
-#endif
-
-namespace android::ultrahdr {
-
-typedef int32_t Fixed;
-#define Fixed1 (1 << 16)
-#define MaxS32FitsInFloat 2147483520
-#define MinS32FitsInFloat (-MaxS32FitsInFloat)
-#define FixedToFloat(x) ((x) * 1.52587890625e-5f)
-
-typedef struct Matrix3x3 {
- float vals[3][3];
-} Matrix3x3;
-
-// The D50 illuminant.
-constexpr float kD50_x = 0.9642f;
-constexpr float kD50_y = 1.0000f;
-constexpr float kD50_z = 0.8249f;
-
-enum {
- // data_color_space
- Signature_CMYK = 0x434D594B,
- Signature_Gray = 0x47524159,
- Signature_RGB = 0x52474220,
-
- // pcs
- Signature_Lab = 0x4C616220,
- Signature_XYZ = 0x58595A20,
-};
-
-typedef uint32_t FourByteTag;
-static inline constexpr FourByteTag SetFourByteTag(char a, char b, char c, char d) {
- return (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d);
-}
-
-static constexpr char kICCIdentifier[] = "ICC_PROFILE";
-// 12 for the actual identifier, +2 for the chunk count and chunk index which
-// will always follow.
-static constexpr size_t kICCIdentifierSize = 14;
-
-// This is equal to the header size according to the ICC specification (128)
-// plus the size of the tag count (4). We include the tag count since we
-// always require it to be present anyway.
-static constexpr size_t kICCHeaderSize = 132;
-
-// Contains a signature (4), offset (4), and size (4).
-static constexpr size_t kICCTagTableEntrySize = 12;
-
-// size should be 20; 4 bytes for type descriptor, 4 bytes reserved, 12
-// bytes for a single XYZ number type (4 bytes per coordinate).
-static constexpr size_t kColorantTagSize = 20;
-
-static constexpr uint32_t kDisplay_Profile = SetFourByteTag('m', 'n', 't', 'r');
-static constexpr uint32_t kRGB_ColorSpace = SetFourByteTag('R', 'G', 'B', ' ');
-static constexpr uint32_t kXYZ_PCSSpace = SetFourByteTag('X', 'Y', 'Z', ' ');
-static constexpr uint32_t kACSP_Signature = SetFourByteTag('a', 'c', 's', 'p');
-
-static constexpr uint32_t kTAG_desc = SetFourByteTag('d', 'e', 's', 'c');
-static constexpr uint32_t kTAG_TextType = SetFourByteTag('m', 'l', 'u', 'c');
-static constexpr uint32_t kTAG_rXYZ = SetFourByteTag('r', 'X', 'Y', 'Z');
-static constexpr uint32_t kTAG_gXYZ = SetFourByteTag('g', 'X', 'Y', 'Z');
-static constexpr uint32_t kTAG_bXYZ = SetFourByteTag('b', 'X', 'Y', 'Z');
-static constexpr uint32_t kTAG_wtpt = SetFourByteTag('w', 't', 'p', 't');
-static constexpr uint32_t kTAG_rTRC = SetFourByteTag('r', 'T', 'R', 'C');
-static constexpr uint32_t kTAG_gTRC = SetFourByteTag('g', 'T', 'R', 'C');
-static constexpr uint32_t kTAG_bTRC = SetFourByteTag('b', 'T', 'R', 'C');
-static constexpr uint32_t kTAG_cicp = SetFourByteTag('c', 'i', 'c', 'p');
-static constexpr uint32_t kTAG_cprt = SetFourByteTag('c', 'p', 'r', 't');
-static constexpr uint32_t kTAG_A2B0 = SetFourByteTag('A', '2', 'B', '0');
-static constexpr uint32_t kTAG_B2A0 = SetFourByteTag('B', '2', 'A', '0');
-
-static constexpr uint32_t kTAG_CurveType = SetFourByteTag('c', 'u', 'r', 'v');
-static constexpr uint32_t kTAG_mABType = SetFourByteTag('m', 'A', 'B', ' ');
-static constexpr uint32_t kTAG_mBAType = SetFourByteTag('m', 'B', 'A', ' ');
-static constexpr uint32_t kTAG_ParaCurveType = SetFourByteTag('p', 'a', 'r', 'a');
-
-
-static constexpr Matrix3x3 kSRGB = {{
- // ICC fixed-point (16.16) representation, taken from skcms. Please keep them exactly in sync.
- // 0.436065674f, 0.385147095f, 0.143066406f,
- // 0.222488403f, 0.716873169f, 0.060607910f,
- // 0.013916016f, 0.097076416f, 0.714096069f,
- { FixedToFloat(0x6FA2), FixedToFloat(0x6299), FixedToFloat(0x24A0) },
- { FixedToFloat(0x38F5), FixedToFloat(0xB785), FixedToFloat(0x0F84) },
- { FixedToFloat(0x0390), FixedToFloat(0x18DA), FixedToFloat(0xB6CF) },
-}};
-
-static constexpr Matrix3x3 kDisplayP3 = {{
- { 0.515102f, 0.291965f, 0.157153f },
- { 0.241182f, 0.692236f, 0.0665819f },
- { -0.00104941f, 0.0418818f, 0.784378f },
-}};
-
-static constexpr Matrix3x3 kRec2020 = {{
- { 0.673459f, 0.165661f, 0.125100f },
- { 0.279033f, 0.675338f, 0.0456288f },
- { -0.00193139f, 0.0299794f, 0.797162f },
-}};
-
-static constexpr uint32_t kCICPPrimariesSRGB = 1;
-static constexpr uint32_t kCICPPrimariesP3 = 12;
-static constexpr uint32_t kCICPPrimariesRec2020 = 9;
-
-static constexpr uint32_t kCICPTrfnSRGB = 1;
-static constexpr uint32_t kCICPTrfnLinear = 8;
-static constexpr uint32_t kCICPTrfnPQ = 16;
-static constexpr uint32_t kCICPTrfnHLG = 18;
-
-enum ParaCurveType {
- kExponential_ParaCurveType = 0,
- kGAB_ParaCurveType = 1,
- kGABC_ParaCurveType = 2,
- kGABDE_ParaCurveType = 3,
- kGABCDEF_ParaCurveType = 4,
-};
-
-/**
- * Return the closest int for the given float. Returns MaxS32FitsInFloat for NaN.
- */
-static inline int float_saturate2int(float x) {
- x = x < MaxS32FitsInFloat ? x : MaxS32FitsInFloat;
- x = x > MinS32FitsInFloat ? x : MinS32FitsInFloat;
- return (int)x;
-}
-
-static Fixed float_round_to_fixed(float x) {
- return float_saturate2int((float)floor((double)x * Fixed1 + 0.5));
-}
-
-static uint16_t float_round_to_unorm16(float x) {
- x = x * 65535.f + 0.5;
- if (x > 65535) return 65535;
- if (x < 0) return 0;
- return static_cast<uint16_t>(x);
-}
-
-static void float_to_table16(const float f, uint8_t* table_16) {
- *reinterpret_cast<uint16_t*>(table_16) = Endian_SwapBE16(float_round_to_unorm16(f));
-}
-
-static bool isfinitef_(float x) { return 0 == x*0; }
-
-struct ICCHeader {
- // Size of the profile (computed)
- uint32_t size;
- // Preferred CMM type (ignored)
- uint32_t cmm_type = 0;
- // Version 4.3 or 4.4 if CICP is included.
- uint32_t version = Endian_SwapBE32(0x04300000);
- // Display device profile
- uint32_t profile_class = Endian_SwapBE32(kDisplay_Profile);
- // RGB input color space;
- uint32_t data_color_space = Endian_SwapBE32(kRGB_ColorSpace);
- // Profile connection space.
- uint32_t pcs = Endian_SwapBE32(kXYZ_PCSSpace);
- // Date and time (ignored)
- uint8_t creation_date_time[12] = {0};
- // Profile signature
- uint32_t signature = Endian_SwapBE32(kACSP_Signature);
- // Platform target (ignored)
- uint32_t platform = 0;
- // Flags: not embedded, can be used independently
- uint32_t flags = 0x00000000;
- // Device manufacturer (ignored)
- uint32_t device_manufacturer = 0;
- // Device model (ignored)
- uint32_t device_model = 0;
- // Device attributes (ignored)
- uint8_t device_attributes[8] = {0};
- // Relative colorimetric rendering intent
- uint32_t rendering_intent = Endian_SwapBE32(1);
- // D50 standard illuminant (X, Y, Z)
- uint32_t illuminant_X = Endian_SwapBE32(float_round_to_fixed(kD50_x));
- uint32_t illuminant_Y = Endian_SwapBE32(float_round_to_fixed(kD50_y));
- uint32_t illuminant_Z = Endian_SwapBE32(float_round_to_fixed(kD50_z));
- // Profile creator (ignored)
- uint32_t creator = 0;
- // Profile id checksum (ignored)
- uint8_t profile_id[16] = {0};
- // Reserved (ignored)
- uint8_t reserved[28] = {0};
- // Technically not part of header, but required
- uint32_t tag_count = 0;
-};
-
-class IccHelper {
-private:
- static constexpr uint32_t kTrcTableSize = 65;
- static constexpr uint32_t kGridSize = 17;
- static constexpr size_t kNumChannels = 3;
-
- static sp<DataStruct> write_text_tag(const char* text);
- static std::string get_desc_string(const ultrahdr_transfer_function tf,
- const ultrahdr_color_gamut gamut);
- static sp<DataStruct> write_xyz_tag(float x, float y, float z);
- static sp<DataStruct> write_trc_tag(const int table_entries, const void* table_16);
- static sp<DataStruct> write_trc_tag(const TransferFunction& fn);
- static float compute_tone_map_gain(const ultrahdr_transfer_function tf, float L);
- static sp<DataStruct> write_cicp_tag(uint32_t color_primaries,
- uint32_t transfer_characteristics);
- static sp<DataStruct> write_mAB_or_mBA_tag(uint32_t type,
- bool has_a_curves,
- const uint8_t* grid_points,
- const uint8_t* grid_16);
- static void compute_lut_entry(const Matrix3x3& src_to_XYZD50, float rgb[3]);
- static sp<DataStruct> write_clut(const uint8_t* grid_points, const uint8_t* grid_16);
-
- // Checks if a set of xyz tags is equivalent to a 3x3 Matrix. Each input
- // tag buffer assumed to be at least kColorantTagSize in size.
- static bool tagsEqualToMatrix(const Matrix3x3& matrix,
- const uint8_t* red_tag,
- const uint8_t* green_tag,
- const uint8_t* blue_tag);
-
-public:
- // Output includes JPEG embedding identifier and chunk information, but not
- // APPx information.
- static sp<DataStruct> writeIccProfile(const ultrahdr_transfer_function tf,
- const ultrahdr_color_gamut gamut);
- // NOTE: this function is not robust; it can infer gamuts that IccHelper
- // writes out but should not be considered a reference implementation for
- // robust parsing of ICC profiles or their gamuts.
- static ultrahdr_color_gamut readIccColorGamut(void* icc_data, size_t icc_size);
-};
-} // namespace android::ultrahdr
-
-#endif //ANDROID_ULTRAHDR_ICC_H
diff --git a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
deleted file mode 100644
index b86ce5f4..0000000
--- a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_JPEGDECODERHELPER_H
-#define ANDROID_ULTRAHDR_JPEGDECODERHELPER_H
-
-// We must include cstdio before jpeglib.h. It is a requirement of libjpeg.
-#include <cstdio>
-extern "C" {
-#include <jerror.h>
-#include <jpeglib.h>
-}
-#include <utils/Errors.h>
-#include <vector>
-
-// constraint on max width and max height is only due to device alloc constraints
-// Can tune these values basing on the target device
-static const int kMaxWidth = 8192;
-static const int kMaxHeight = 8192;
-
-namespace android::ultrahdr {
-/*
- * Encapsulates a converter from JPEG to raw image (YUV420planer or grey-scale) format.
- * This class is not thread-safe.
- */
-class JpegDecoderHelper {
-public:
- JpegDecoderHelper();
- ~JpegDecoderHelper();
- /*
- * Decompresses JPEG image to raw image (YUV420planer, grey-scale or RGBA) format. After
- * calling this method, call getDecompressedImage() to get the image.
- * Returns false if decompressing the image fails.
- */
- bool decompressImage(const void* image, int length, bool decodeToRGBA = false);
- /*
- * Returns the decompressed raw image buffer pointer. This method must be called only after
- * calling decompressImage().
- */
- void* getDecompressedImagePtr();
- /*
- * Returns the decompressed raw image buffer size. This method must be called only after
- * calling decompressImage().
- */
- size_t getDecompressedImageSize();
- /*
- * Returns the image width in pixels. This method must be called only after calling
- * decompressImage().
- */
- size_t getDecompressedImageWidth();
- /*
- * Returns the image width in pixels. This method must be called only after calling
- * decompressImage().
- */
- size_t getDecompressedImageHeight();
- /*
- * Returns the XMP data from the image.
- */
- void* getXMPPtr();
- /*
- * Returns the decompressed XMP buffer size. This method must be called only after
- * calling decompressImage() or getCompressedImageParameters().
- */
- size_t getXMPSize();
- /*
- * Extracts EXIF package and updates the EXIF position / length without decoding the image.
- */
- bool extractEXIF(const void* image, int length);
- /*
- * Returns the EXIF data from the image.
- * This method must be called after extractEXIF() or decompressImage().
- */
- void* getEXIFPtr();
- /*
- * Returns the decompressed EXIF buffer size. This method must be called only after
- * calling decompressImage(), extractEXIF() or getCompressedImageParameters().
- */
- size_t getEXIFSize();
- /*
- * Returns the position offset of EXIF package
- * (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>),
- * or -1 if no EXIF exists.
- * This method must be called after extractEXIF() or decompressImage().
- */
- int getEXIFPos() { return mExifPos; }
- /*
- * Returns the ICC data from the image.
- */
- void* getICCPtr();
- /*
- * Returns the decompressed ICC buffer size. This method must be called only after
- * calling decompressImage() or getCompressedImageParameters().
- */
- size_t getICCSize();
- /*
- * Decompresses metadata of the image. All vectors are owned by the caller.
- */
- bool getCompressedImageParameters(const void* image, int length, size_t* pWidth,
- size_t* pHeight, std::vector<uint8_t>* iccData,
- std::vector<uint8_t>* exifData);
-
-private:
- bool decode(const void* image, int length, bool decodeToRGBA);
- // Returns false if errors occur.
- bool decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest, bool isSingleChannel);
- bool decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest);
- bool decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest);
- bool decompressSingleChannel(jpeg_decompress_struct* cinfo, const uint8_t* dest);
- // Process 16 lines of Y and 16 lines of U/V each time.
- // We must pass at least 16 scanlines according to libjpeg documentation.
- static const int kCompressBatchSize = 16;
- // The buffer that holds the decompressed result.
- std::vector<JOCTET> mResultBuffer;
- // The buffer that holds XMP Data.
- std::vector<JOCTET> mXMPBuffer;
- // The buffer that holds EXIF Data.
- std::vector<JOCTET> mEXIFBuffer;
- // The buffer that holds ICC Data.
- std::vector<JOCTET> mICCBuffer;
-
- // Resolution of the decompressed image.
- size_t mWidth;
- size_t mHeight;
-
- // Position of EXIF package, default value is -1 which means no EXIF package appears.
- ssize_t mExifPos = -1;
-};
-} /* namespace android::ultrahdr */
-
-#endif // ANDROID_ULTRAHDR_JPEGDECODERHELPER_H
diff --git a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h
deleted file mode 100644
index 9d06415..0000000
--- a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_JPEGENCODERHELPER_H
-#define ANDROID_ULTRAHDR_JPEGENCODERHELPER_H
-
-// We must include cstdio before jpeglib.h. It is a requirement of libjpeg.
-#include <cstdio>
-#include <vector>
-
-extern "C" {
-#include <jerror.h>
-#include <jpeglib.h>
-}
-
-#include <utils/Errors.h>
-
-namespace android::ultrahdr {
-
-#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m))
-
-/*
- * Encapsulates a converter from raw image (YUV420planer or grey-scale) to JPEG format.
- * This class is not thread-safe.
- */
-class JpegEncoderHelper {
-public:
- JpegEncoderHelper();
- ~JpegEncoderHelper();
-
- /*
- * Compresses YUV420Planer image to JPEG format. After calling this method, call
- * getCompressedImage() to get the image. |quality| is the jpeg image quality parameter to use.
- * It ranges from 1 (poorest quality) to 100 (highest quality). |iccBuffer| is the buffer of
- * ICC segment which will be added to the compressed image.
- * Returns false if errors occur during compression.
- */
- bool compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height,
- int lumaStride, int chromaStride, int quality, const void* iccBuffer,
- unsigned int iccSize);
-
- /*
- * Returns the compressed JPEG buffer pointer. This method must be called only after calling
- * compressImage().
- */
- void* getCompressedImagePtr();
-
- /*
- * Returns the compressed JPEG buffer size. This method must be called only after calling
- * compressImage().
- */
- size_t getCompressedImageSize();
-
- /*
- * Process 16 lines of Y and 16 lines of U/V each time.
- * We must pass at least 16 scanlines according to libjpeg documentation.
- */
- static const int kCompressBatchSize = 16;
-
-private:
- // initDestination(), emptyOutputBuffer() and emptyOutputBuffer() are callback functions to be
- // passed into jpeg library.
- static void initDestination(j_compress_ptr cinfo);
- static boolean emptyOutputBuffer(j_compress_ptr cinfo);
- static void terminateDestination(j_compress_ptr cinfo);
- static void outputErrorMessage(j_common_ptr cinfo);
-
- // Returns false if errors occur.
- bool encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height,
- int lumaStride, int chromaStride, int quality, const void* iccBuffer,
- unsigned int iccSize);
- void setJpegDestination(jpeg_compress_struct* cinfo);
- void setJpegCompressStruct(int width, int height, int quality, jpeg_compress_struct* cinfo,
- bool isSingleChannel);
- // Returns false if errors occur.
- bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, const uint8_t* uvBuffer,
- int lumaStride, int chromaStride);
- bool compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, int lumaStride);
-
- // The block size for encoded jpeg image buffer.
- static const int kBlockSize = 16384;
-
- // The buffer that holds the compressed result.
- std::vector<JOCTET> mResultBuffer;
-};
-
-} /* namespace android::ultrahdr */
-
-#endif // ANDROID_ULTRAHDR_JPEGENCODERHELPER_H
diff --git a/libs/ultrahdr/include/ultrahdr/jpegr.h b/libs/ultrahdr/include/ultrahdr/jpegr.h
deleted file mode 100644
index 114c81d..0000000
--- a/libs/ultrahdr/include/ultrahdr/jpegr.h
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_JPEGR_H
-#define ANDROID_ULTRAHDR_JPEGR_H
-
-#include <cstdint>
-#include <vector>
-
-#include "ultrahdr/jpegdecoderhelper.h"
-#include "ultrahdr/jpegencoderhelper.h"
-#include "ultrahdr/jpegrerrorcode.h"
-#include "ultrahdr/ultrahdr.h"
-
-#ifndef FLT_MAX
-#define FLT_MAX 0x1.fffffep127f
-#endif
-
-namespace android::ultrahdr {
-
-// The current JPEGR version that we encode to
-static const char* const kJpegrVersion = "1.0";
-
-// Map is quarter res / sixteenth size
-static const size_t kMapDimensionScaleFactor = 4;
-
-// Gain Map width is (image_width / kMapDimensionScaleFactor). If we were to
-// compress 420 GainMap in jpeg, then we need at least 2 samples. For Grayscale
-// 1 sample is sufficient. We are using 2 here anyways
-static const int kMinWidth = 2 * kMapDimensionScaleFactor;
-static const int kMinHeight = 2 * kMapDimensionScaleFactor;
-
-// Minimum Codec Unit(MCU) for 420 sub-sampling is decided by JPEG encoder by parameter
-// JpegEncoderHelper::kCompressBatchSize.
-// The width and height of image under compression is expected to be a multiple of MCU size.
-// If this criteria is not satisfied, padding is done.
-static const size_t kJpegBlock = JpegEncoderHelper::kCompressBatchSize;
-
-/*
- * Holds information of jpegr image
- */
-struct jpegr_info_struct {
- size_t width;
- size_t height;
- std::vector<uint8_t>* iccData;
- std::vector<uint8_t>* exifData;
-};
-
-/*
- * Holds information for uncompressed image or gain map.
- */
-struct jpegr_uncompressed_struct {
- // Pointer to the data location.
- void* data;
- // Width of the gain map or the luma plane of the image in pixels.
- int width;
- // Height of the gain map or the luma plane of the image in pixels.
- int height;
- // Color gamut.
- ultrahdr_color_gamut colorGamut;
-
- // Values below are optional
- // Pointer to chroma data, if it's NULL, chroma plane is considered to be immediately
- // after the luma plane.
- void* chroma_data = nullptr;
- // Stride of Y plane in number of pixels. 0 indicates the member is uninitialized. If
- // non-zero this value must be larger than or equal to luma width. If stride is
- // uninitialized then it is assumed to be equal to luma width.
- int luma_stride = 0;
- // Stride of UV plane in number of pixels.
- // 1. If this handle points to P010 image then this value must be larger than
- // or equal to luma width.
- // 2. If this handle points to 420 image then this value must be larger than
- // or equal to (luma width / 2).
- // NOTE: if chroma_data is nullptr, chroma_stride is irrelevant. Just as the way,
- // chroma_data is derived from luma ptr, chroma stride is derived from luma stride.
- int chroma_stride = 0;
-};
-
-/*
- * Holds information for compressed image or gain map.
- */
-struct jpegr_compressed_struct {
- // Pointer to the data location.
- void* data;
- // Used data length in bytes.
- int length;
- // Maximum available data length in bytes.
- int maxLength;
- // Color gamut.
- ultrahdr_color_gamut colorGamut;
-};
-
-/*
- * Holds information for EXIF metadata.
- */
-struct jpegr_exif_struct {
- // Pointer to the data location.
- void* data;
- // Data length;
- int length;
-};
-
-typedef struct jpegr_uncompressed_struct* jr_uncompressed_ptr;
-typedef struct jpegr_compressed_struct* jr_compressed_ptr;
-typedef struct jpegr_exif_struct* jr_exif_ptr;
-typedef struct jpegr_info_struct* jr_info_ptr;
-
-class JpegR {
-public:
- /*
- * Experimental only
- *
- * Encode API-0
- * Compress JPEGR image from 10-bit HDR YUV.
- *
- * Tonemap the HDR input to a SDR image, generate gain map from the HDR and SDR images,
- * compress SDR YUV to 8-bit JPEG and append the gain map to the end of the compressed
- * JPEG.
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param hdr_tf transfer function of the HDR image
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the destination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is
- * the highest quality
- * @param exif pointer to the exif metadata.
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf,
- jr_compressed_ptr dest, int quality, jr_exif_ptr exif);
-
- /*
- * Encode API-1
- * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV.
- *
- * Generate gain map from the HDR and SDR inputs, compress SDR YUV to 8-bit JPEG and append
- * the gain map to the end of the compressed JPEG. HDR and SDR inputs must be the same
- * resolution. SDR input is assumed to use the sRGB transfer function.
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format
- * @param hdr_tf transfer function of the HDR image
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the desitination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is
- * the highest quality
- * @param exif pointer to the exif metadata.
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr,
- ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality,
- jr_exif_ptr exif);
-
- /*
- * Encode API-2
- * Compress JPEGR image from 10-bit HDR YUV, 8-bit SDR YUV and compressed 8-bit JPEG.
- *
- * This method requires HAL Hardware JPEG encoder.
- *
- * Generate gain map from the HDR and SDR inputs, append the gain map to the end of the
- * compressed JPEG. Adds an ICC profile if one isn't present in the input JPEG image. HDR and
- * SDR inputs must be the same resolution and color space. SDR image is assumed to use the sRGB
- * transfer function.
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format
- * @param yuv420jpg_image_ptr SDR image compressed in jpeg format
- * Note: the compressed SDR image must be the compressed
- * yuv420_image_ptr image in JPEG format.
- * @param hdr_tf transfer function of the HDR image
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the desitination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr,
- jr_compressed_ptr yuv420jpg_image_ptr, ultrahdr_transfer_function hdr_tf,
- jr_compressed_ptr dest);
-
- /*
- * Encode API-3
- * Compress JPEGR image from 10-bit HDR YUV and 8-bit SDR YUV.
- *
- * This method requires HAL Hardware JPEG encoder.
- *
- * Decode the compressed 8-bit JPEG image to YUV SDR, generate gain map from the HDR input
- * and the decoded SDR result, append the gain map to the end of the compressed JPEG. Adds an
- * ICC profile if one isn't present in the input JPEG image. HDR and SDR inputs must be the same
- * resolution. JPEG image is assumed to use the sRGB transfer function.
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param yuv420jpg_image_ptr SDR image compressed in jpeg format
- * @param hdr_tf transfer function of the HDR image
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the desitination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_compressed_ptr yuv420jpg_image_ptr,
- ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest);
-
- /*
- * Encode API-4
- * Assemble JPEGR image from SDR JPEG and gainmap JPEG.
- *
- * Assemble the primary JPEG image, the gain map and the metadata to JPEG/R format. Adds an ICC
- * profile if one isn't present in the input JPEG image.
- * @param yuv420jpg_image_ptr SDR image compressed in jpeg format
- * @param gainmapjpg_image_ptr gain map image compressed in jpeg format
- * @param metadata metadata to be written in XMP of the primary jpeg
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the desitination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr,
- jr_compressed_ptr gainmapjpg_image_ptr, ultrahdr_metadata_ptr metadata,
- jr_compressed_ptr dest);
-
- /*
- * Decode API
- * Decompress JPEGR image.
- *
- * This method assumes that the JPEGR image contains an ICC profile with primaries that match
- * those of a color gamut that this library is aware of; Bt.709, Display-P3, or Bt.2100. It also
- * assumes the base image uses the sRGB transfer function.
- *
- * This method only supports single gain map metadata values for fields that allow multi-channel
- * metadata values.
- * @param jpegr_image_ptr compressed JPEGR image.
- * @param dest destination of the uncompressed JPEGR image.
- * @param max_display_boost (optional) the maximum available boost supported by a display,
- * the value must be greater than or equal to 1.0.
- * @param exif destination of the decoded EXIF metadata. The default value is NULL where the
- decoder will do nothing about it. If configured not NULL the decoder will write
- EXIF data into this structure. The format is defined in {@code jpegr_exif_struct}
- * @param output_format flag for setting output color format. Its value configures the output
- color format. The default value is {@code JPEGR_OUTPUT_HDR_LINEAR}.
- ----------------------------------------------------------------------
- | output_format | decoded color format to be written |
- ----------------------------------------------------------------------
- | JPEGR_OUTPUT_SDR | RGBA_8888 |
- ----------------------------------------------------------------------
- | JPEGR_OUTPUT_HDR_LINEAR | (default)RGBA_F16 linear |
- ----------------------------------------------------------------------
- | JPEGR_OUTPUT_HDR_PQ | RGBA_1010102 PQ |
- ----------------------------------------------------------------------
- | JPEGR_OUTPUT_HDR_HLG | RGBA_1010102 HLG |
- ----------------------------------------------------------------------
- * @param gainmap_image_ptr destination of the decoded gain map. The default value is NULL
- where the decoder will do nothing about it. If configured not NULL
- the decoder will write the decoded gain_map data into this
- structure. The format is defined in
- {@code jpegr_uncompressed_struct}.
- * @param metadata destination of the decoded metadata. The default value is NULL where the
- decoder will do nothing about it. If configured not NULL the decoder will
- write metadata into this structure. the format of metadata is defined in
- {@code ultrahdr_metadata_struct}.
- * @return NO_ERROR if decoding succeeds, error code if error occurs.
- */
- status_t decodeJPEGR(jr_compressed_ptr jpegr_image_ptr, jr_uncompressed_ptr dest,
- float max_display_boost = FLT_MAX, jr_exif_ptr exif = nullptr,
- ultrahdr_output_format output_format = ULTRAHDR_OUTPUT_HDR_LINEAR,
- jr_uncompressed_ptr gainmap_image_ptr = nullptr,
- ultrahdr_metadata_ptr metadata = nullptr);
-
- /*
- * Gets Info from JPEGR file without decoding it.
- *
- * This method only supports single gain map metadata values for fields that allow multi-channel
- * metadata values.
- *
- * The output is filled jpegr_info structure
- * @param jpegr_image_ptr compressed JPEGR image
- * @param jpeg_image_info_ptr pointer to jpegr info struct. Members of jpegr_info
- * are owned by the caller
- * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise
- */
- status_t getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg_image_info_ptr);
-
-protected:
- /*
- * This method is called in the encoding pipeline. It will take the uncompressed 8-bit and
- * 10-bit yuv images as input, and calculate the uncompressed gain map. The input images
- * must be the same resolution. The SDR input is assumed to use the sRGB transfer function.
- *
- * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param hdr_tf transfer function of the HDR image
- * @param metadata everything but "version" is filled in this struct
- * @param dest location at which gain map image is stored (caller responsible for memory
- of data).
- * @param sdr_is_601 if true, then use BT.601 decoding of YUV regardless of SDR image gamut
- * @return NO_ERROR if calculation succeeds, error code if error occurs.
- */
- status_t generateGainMap(jr_uncompressed_ptr yuv420_image_ptr,
- jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf,
- ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest,
- bool sdr_is_601 = false);
-
- /*
- * This method is called in the decoding pipeline. It will take the uncompressed (decoded)
- * 8-bit yuv image, the uncompressed (decoded) gain map, and extracted JPEG/R metadata as
- * input, and calculate the 10-bit recovered image. The recovered output image is the same
- * color gamut as the SDR image, with HLG transfer function, and is in RGBA1010102 data format.
- * The SDR image is assumed to use the sRGB transfer function. The SDR image is also assumed to
- * be a decoded JPEG for the purpose of YUV interpration.
- *
- * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format
- * @param gainmap_image_ptr pointer to uncompressed gain map image struct.
- * @param metadata JPEG/R metadata extracted from XMP.
- * @param output_format flag for setting output color format. if set to
- * {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image
- * which is SDR. Default value is JPEGR_OUTPUT_HDR_LINEAR.
- * @param max_display_boost the maximum available boost supported by a display
- * @param dest reconstructed HDR image
- * @return NO_ERROR if calculation succeeds, error code if error occurs.
- */
- status_t applyGainMap(jr_uncompressed_ptr yuv420_image_ptr,
- jr_uncompressed_ptr gainmap_image_ptr, ultrahdr_metadata_ptr metadata,
- ultrahdr_output_format output_format, float max_display_boost,
- jr_uncompressed_ptr dest);
-
-private:
- /*
- * This method is called in the encoding pipeline. It will encode the gain map.
- *
- * @param gainmap_image_ptr pointer to uncompressed gain map image struct
- * @param jpeg_enc_obj_ptr helper resource to compress gain map
- * @return NO_ERROR if encoding succeeds, error code if error occurs.
- */
- status_t compressGainMap(jr_uncompressed_ptr gainmap_image_ptr,
- JpegEncoderHelper* jpeg_enc_obj_ptr);
-
- /*
- * This method is called to separate primary image and gain map image from JPEGR
- *
- * @param jpegr_image_ptr pointer to compressed JPEGR image.
- * @param primary_jpg_image_ptr destination of primary image
- * @param gainmap_jpg_image_ptr destination of compressed gain map image
- * @return NO_ERROR if calculation succeeds, error code if error occurs.
- */
- status_t extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr,
- jr_compressed_ptr primary_jpg_image_ptr,
- jr_compressed_ptr gainmap_jpg_image_ptr);
-
- /*
- * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image,
- * the compressed gain map and optionally the exif package as inputs, and generate the XMP
- * metadata, and finally append everything in the order of:
- * SOI, APP2(EXIF) (if EXIF is from outside), APP2(XMP), primary image, gain map
- *
- * Note that in the final JPEG/R output, EXIF package will appear if ONLY ONE of the following
- * conditions is fulfilled:
- * (1) EXIF package is available from outside input. I.e. pExif != nullptr.
- * (2) Input JPEG has EXIF.
- * If both conditions are fulfilled, this method will return ERROR_JPEGR_INVALID_INPUT_TYPE
- *
- * @param primary_jpg_image_ptr destination of primary image
- * @param gainmap_jpg_image_ptr destination of compressed gain map image
- * @param (nullable) pExif EXIF package
- * @param (nullable) pIcc ICC package
- * @param icc_size length in bytes of ICC package
- * @param metadata JPEG/R metadata to encode in XMP of the jpeg
- * @param dest compressed JPEGR image
- * @return NO_ERROR if calculation succeeds, error code if error occurs.
- */
- status_t appendGainMap(jr_compressed_ptr primary_jpg_image_ptr,
- jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif, void* pIcc,
- size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest);
-
- /*
- * This method will tone map a HDR image to an SDR image.
- *
- * @param src pointer to uncompressed HDR image struct. HDR image is expected to be
- * in p010 color format
- * @param dest pointer to store tonemapped SDR image
- */
- status_t toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest);
-
- /*
- * This method will convert a YUV420 image from one YUV encoding to another in-place (eg.
- * Bt.709 to Bt.601 YUV encoding).
- *
- * src_encoding and dest_encoding indicate the encoding via the YUV conversion defined for that
- * gamut. P3 indicates Rec.601, since this is how DataSpace encodes Display-P3 YUV data.
- *
- * @param image the YUV420 image to convert
- * @param src_encoding input YUV encoding
- * @param dest_encoding output YUV encoding
- * @return NO_ERROR if calculation succeeds, error code if error occurs.
- */
- status_t convertYuv(jr_uncompressed_ptr image, ultrahdr_color_gamut src_encoding,
- ultrahdr_color_gamut dest_encoding);
-
- /*
- * This method will check the validity of the input arguments.
- *
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param yuv420_image_ptr pointer to uncompressed SDR image struct. HDR image is expected to
- * be in 420p color format
- * @param hdr_tf transfer function of the HDR image
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the desitination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @return NO_ERROR if the input args are valid, error code is not valid.
- */
- status_t areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr,
- jr_uncompressed_ptr yuv420_image_ptr,
- ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest_ptr);
-
- /*
- * This method will check the validity of the input arguments.
- *
- * @param p010_image_ptr uncompressed HDR image in P010 color format
- * @param yuv420_image_ptr pointer to uncompressed SDR image struct. HDR image is expected to
- * be in 420p color format
- * @param hdr_tf transfer function of the HDR image
- * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength}
- * represents the maximum available size of the destination buffer, and it must be
- * set before calling this method. If the encoded JPEGR size exceeds
- * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}.
- * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is
- * the highest quality
- * @return NO_ERROR if the input args are valid, error code is not valid.
- */
- status_t areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr,
- jr_uncompressed_ptr yuv420_image_ptr,
- ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest,
- int quality);
-};
-} // namespace android::ultrahdr
-
-#endif // ANDROID_ULTRAHDR_JPEGR_H
diff --git a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h
deleted file mode 100644
index 5420e1c..0000000
--- a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_JPEGRERRORCODE_H
-#define ANDROID_ULTRAHDR_JPEGRERRORCODE_H
-
-#include <utils/Errors.h>
-
-namespace android::ultrahdr {
-
-enum {
- // status_t map for errors in the media framework
- // OK or NO_ERROR or 0 represents no error.
-
- // See system/core/include/utils/Errors.h
- // System standard errors from -1 through (possibly) -133
- //
- // Errors with special meanings and side effects.
- // INVALID_OPERATION: Operation attempted in an illegal state (will try to signal to app).
- // DEAD_OBJECT: Signal from CodecBase to MediaCodec that MediaServer has died.
- // NAME_NOT_FOUND: Signal from CodecBase to MediaCodec that the component was not found.
-
- // JPEGR errors
- JPEGR_IO_ERROR_BASE = -10000,
- ERROR_JPEGR_INVALID_INPUT_TYPE = JPEGR_IO_ERROR_BASE,
- ERROR_JPEGR_INVALID_OUTPUT_TYPE = JPEGR_IO_ERROR_BASE - 1,
- ERROR_JPEGR_INVALID_NULL_PTR = JPEGR_IO_ERROR_BASE - 2,
- ERROR_JPEGR_RESOLUTION_MISMATCH = JPEGR_IO_ERROR_BASE - 3,
- ERROR_JPEGR_BUFFER_TOO_SMALL = JPEGR_IO_ERROR_BASE - 4,
- ERROR_JPEGR_INVALID_COLORGAMUT = JPEGR_IO_ERROR_BASE - 5,
- ERROR_JPEGR_INVALID_TRANS_FUNC = JPEGR_IO_ERROR_BASE - 6,
- ERROR_JPEGR_INVALID_METADATA = JPEGR_IO_ERROR_BASE - 7,
- ERROR_JPEGR_UNSUPPORTED_METADATA = JPEGR_IO_ERROR_BASE - 8,
- ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND = JPEGR_IO_ERROR_BASE - 9,
-
- JPEGR_RUNTIME_ERROR_BASE = -20000,
- ERROR_JPEGR_ENCODE_ERROR = JPEGR_RUNTIME_ERROR_BASE - 1,
- ERROR_JPEGR_DECODE_ERROR = JPEGR_RUNTIME_ERROR_BASE - 2,
- ERROR_JPEGR_CALCULATION_ERROR = JPEGR_RUNTIME_ERROR_BASE - 3,
- ERROR_JPEGR_METADATA_ERROR = JPEGR_RUNTIME_ERROR_BASE - 4,
- ERROR_JPEGR_TONEMAP_ERROR = JPEGR_RUNTIME_ERROR_BASE - 5,
-
- ERROR_JPEGR_UNSUPPORTED_FEATURE = -20000,
-};
-
-} // namespace android::ultrahdr
-
-#endif // ANDROID_ULTRAHDR_JPEGRERRORCODE_H
diff --git a/libs/ultrahdr/include/ultrahdr/jpegrutils.h b/libs/ultrahdr/include/ultrahdr/jpegrutils.h
deleted file mode 100644
index 4ab664e..0000000
--- a/libs/ultrahdr/include/ultrahdr/jpegrutils.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_JPEGRUTILS_H
-#define ANDROID_ULTRAHDR_JPEGRUTILS_H
-
-#include <ultrahdr/jpegr.h>
-#include <utils/RefBase.h>
-
-#include <sstream>
-#include <stdint.h>
-#include <string>
-#include <cstdio>
-
-namespace android::ultrahdr {
-
-static constexpr uint32_t EndianSwap32(uint32_t value) {
- return ((value & 0xFF) << 24) |
- ((value & 0xFF00) << 8) |
- ((value & 0xFF0000) >> 8) |
- (value >> 24);
-}
-static inline uint16_t EndianSwap16(uint16_t value) {
- return static_cast<uint16_t>((value >> 8) | ((value & 0xFF) << 8));
-}
-
-#if USE_BIG_ENDIAN
- #define Endian_SwapBE32(n) EndianSwap32(n)
- #define Endian_SwapBE16(n) EndianSwap16(n)
-#else
- #define Endian_SwapBE32(n) (n)
- #define Endian_SwapBE16(n) (n)
-#endif
-
-struct ultrahdr_metadata_struct;
-/*
- * Mutable data structure. Holds information for metadata.
- */
-class DataStruct : public RefBase {
-private:
- void* data;
- int writePos;
- int length;
- ~DataStruct();
-
-public:
- DataStruct(int s);
- void* getData();
- int getLength();
- int getBytesWritten();
- bool write8(uint8_t value);
- bool write16(uint16_t value);
- bool write32(uint32_t value);
- bool write(const void* src, int size);
-};
-
-/*
- * Helper function used for writing data to destination.
- *
- * @param destination destination of the data to be written.
- * @param source source of data being written.
- * @param length length of the data to be written.
- * @param position cursor in desitination where the data is to be written.
- * @return status of succeed or error code.
- */
-status_t Write(jr_compressed_ptr destination, const void* source, size_t length, int &position);
-
-
-/*
- * Parses XMP packet and fills metadata with data from XMP
- *
- * @param xmp_data pointer to XMP packet
- * @param xmp_size size of XMP packet
- * @param metadata place to store HDR metadata values
- * @return true if metadata is successfully retrieved, false otherwise
-*/
-bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_struct* metadata);
-
-/*
- * This method generates XMP metadata for the primary image.
- *
- * below is an example of the XMP metadata that this function generates where
- * secondary_image_length = 1000
- *
- * <x:xmpmeta
- * xmlns:x="adobe:ns:meta/"
- * x:xmptk="Adobe XMP Core 5.1.2">
- * <rdf:RDF
- * xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
- * <rdf:Description
- * xmlns:Container="http://ns.google.com/photos/1.0/container/"
- * xmlns:Item="http://ns.google.com/photos/1.0/container/item/"
- * xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"
- * hdrgm:Version="1">
- * <Container:Directory>
- * <rdf:Seq>
- * <rdf:li
- * rdf:parseType="Resource">
- * <Container:Item
- * Item:Semantic="Primary"
- * Item:Mime="image/jpeg"/>
- * </rdf:li>
- * <rdf:li
- * rdf:parseType="Resource">
- * <Container:Item
- * Item:Semantic="GainMap"
- * Item:Mime="image/jpeg"
- * Item:Length="1000"/>
- * </rdf:li>
- * </rdf:Seq>
- * </Container:Directory>
- * </rdf:Description>
- * </rdf:RDF>
- * </x:xmpmeta>
- *
- * @param secondary_image_length length of secondary image
- * @return XMP metadata in type of string
- */
-std::string generateXmpForPrimaryImage(int secondary_image_length,
- ultrahdr_metadata_struct& metadata);
-
-/*
- * This method generates XMP metadata for the recovery map image.
- *
- * below is an example of the XMP metadata that this function generates where
- * max_content_boost = 8.0
- * min_content_boost = 0.5
- *
- * <x:xmpmeta
- * xmlns:x="adobe:ns:meta/"
- * x:xmptk="Adobe XMP Core 5.1.2">
- * <rdf:RDF
- * xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
- * <rdf:Description
- * xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"
- * hdrgm:Version="1"
- * hdrgm:GainMapMin="-1"
- * hdrgm:GainMapMax="3"
- * hdrgm:Gamma="1"
- * hdrgm:OffsetSDR="0"
- * hdrgm:OffsetHDR="0"
- * hdrgm:HDRCapacityMin="0"
- * hdrgm:HDRCapacityMax="3"
- * hdrgm:BaseRenditionIsHDR="False"/>
- * </rdf:RDF>
- * </x:xmpmeta>
- *
- * @param metadata JPEG/R metadata to encode as XMP
- * @return XMP metadata in type of string
- */
- std::string generateXmpForSecondaryImage(ultrahdr_metadata_struct& metadata);
-} // namespace android::ultrahdr
-
-#endif //ANDROID_ULTRAHDR_JPEGRUTILS_H
diff --git a/libs/ultrahdr/include/ultrahdr/multipictureformat.h b/libs/ultrahdr/include/ultrahdr/multipictureformat.h
deleted file mode 100644
index c5bd09d..0000000
--- a/libs/ultrahdr/include/ultrahdr/multipictureformat.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_MULTIPICTUREFORMAT_H
-#define ANDROID_ULTRAHDR_MULTIPICTUREFORMAT_H
-
-#include <ultrahdr/jpegrutils.h>
-
-#ifdef USE_BIG_ENDIAN
-#undef USE_BIG_ENDIAN
-#define USE_BIG_ENDIAN true
-#endif
-
-namespace android::ultrahdr {
-
-constexpr size_t kNumPictures = 2;
-constexpr size_t kMpEndianSize = 4;
-constexpr uint16_t kTagSerializedCount = 3;
-constexpr uint32_t kTagSize = 12;
-
-constexpr uint16_t kTypeLong = 0x4;
-constexpr uint16_t kTypeUndefined = 0x7;
-
-static constexpr uint8_t kMpfSig[] = {'M', 'P', 'F', '\0'};
-constexpr uint8_t kMpLittleEndian[kMpEndianSize] = {0x49, 0x49, 0x2A, 0x00};
-constexpr uint8_t kMpBigEndian[kMpEndianSize] = {0x4D, 0x4D, 0x00, 0x2A};
-
-constexpr uint16_t kVersionTag = 0xB000;
-constexpr uint16_t kVersionType = kTypeUndefined;
-constexpr uint32_t kVersionCount = 4;
-constexpr size_t kVersionSize = 4;
-constexpr uint8_t kVersionExpected[kVersionSize] = {'0', '1', '0', '0'};
-
-constexpr uint16_t kNumberOfImagesTag = 0xB001;
-constexpr uint16_t kNumberOfImagesType = kTypeLong;
-constexpr uint32_t kNumberOfImagesCount = 1;
-
-constexpr uint16_t kMPEntryTag = 0xB002;
-constexpr uint16_t kMPEntryType = kTypeUndefined;
-constexpr uint32_t kMPEntrySize = 16;
-
-constexpr uint32_t kMPEntryAttributeFormatJpeg = 0x0000000;
-constexpr uint32_t kMPEntryAttributeTypePrimary = 0x030000;
-
-size_t calculateMpfSize();
-sp<DataStruct> generateMpf(int primary_image_size, int primary_image_offset,
- int secondary_image_size, int secondary_image_offset);
-
-} // namespace android::ultrahdr
-
-#endif //ANDROID_ULTRAHDR_MULTIPICTUREFORMAT_H
diff --git a/libs/ultrahdr/include/ultrahdr/ultrahdr.h b/libs/ultrahdr/include/ultrahdr/ultrahdr.h
deleted file mode 100644
index 0252391..0000000
--- a/libs/ultrahdr/include/ultrahdr/ultrahdr.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef ANDROID_ULTRAHDR_ULTRAHDR_H
-#define ANDROID_ULTRAHDR_ULTRAHDR_H
-
-#include <string>
-
-namespace android::ultrahdr {
-// Color gamuts for image data
-typedef enum {
- ULTRAHDR_COLORGAMUT_UNSPECIFIED = -1,
- ULTRAHDR_COLORGAMUT_BT709,
- ULTRAHDR_COLORGAMUT_P3,
- ULTRAHDR_COLORGAMUT_BT2100,
- ULTRAHDR_COLORGAMUT_MAX = ULTRAHDR_COLORGAMUT_BT2100,
-} ultrahdr_color_gamut;
-
-// Transfer functions for image data
-// TODO: TF LINEAR is deprecated, remove this enum and the code surrounding it.
-typedef enum {
- ULTRAHDR_TF_UNSPECIFIED = -1,
- ULTRAHDR_TF_LINEAR = 0,
- ULTRAHDR_TF_HLG = 1,
- ULTRAHDR_TF_PQ = 2,
- ULTRAHDR_TF_SRGB = 3,
- ULTRAHDR_TF_MAX = ULTRAHDR_TF_SRGB,
-} ultrahdr_transfer_function;
-
-// Target output formats for decoder
-typedef enum {
- ULTRAHDR_OUTPUT_UNSPECIFIED = -1,
- ULTRAHDR_OUTPUT_SDR, // SDR in RGBA_8888 color format
- ULTRAHDR_OUTPUT_HDR_LINEAR, // HDR in F16 color format (linear)
- ULTRAHDR_OUTPUT_HDR_PQ, // HDR in RGBA_1010102 color format (PQ transfer function)
- ULTRAHDR_OUTPUT_HDR_HLG, // HDR in RGBA_1010102 color format (HLG transfer function)
- ULTRAHDR_OUTPUT_MAX = ULTRAHDR_OUTPUT_HDR_HLG,
-} ultrahdr_output_format;
-
-/*
- * Holds information for gain map related metadata.
- *
- * Not: all values stored in linear. This differs from the metadata encoding in XMP, where
- * maxContentBoost (aka gainMapMax), minContentBoost (aka gainMapMin), hdrCapacityMin, and
- * hdrCapacityMax are stored in log2 space.
- */
-struct ultrahdr_metadata_struct {
- // Ultra HDR format version
- std::string version;
- // Max Content Boost for the map
- float maxContentBoost;
- // Min Content Boost for the map
- float minContentBoost;
- // Gamma of the map data
- float gamma;
- // Offset for SDR data in map calculations
- float offsetSdr;
- // Offset for HDR data in map calculations
- float offsetHdr;
- // HDR capacity to apply the map at all
- float hdrCapacityMin;
- // HDR capacity to apply the map completely
- float hdrCapacityMax;
-};
-typedef struct ultrahdr_metadata_struct* ultrahdr_metadata_ptr;
-
-} // namespace android::ultrahdr
-
-#endif //ANDROID_ULTRAHDR_ULTRAHDR_H
diff --git a/libs/ultrahdr/jpegdecoderhelper.cpp b/libs/ultrahdr/jpegdecoderhelper.cpp
deleted file mode 100644
index 2e7940c..0000000
--- a/libs/ultrahdr/jpegdecoderhelper.cpp
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright 2022 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 <ultrahdr/jpegdecoderhelper.h>
-
-#include <utils/Log.h>
-
-#include <errno.h>
-#include <setjmp.h>
-#include <string>
-
-using namespace std;
-
-namespace android::ultrahdr {
-
-#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m))
-
-const uint32_t kAPP0Marker = JPEG_APP0; // JFIF
-const uint32_t kAPP1Marker = JPEG_APP0 + 1; // EXIF, XMP
-const uint32_t kAPP2Marker = JPEG_APP0 + 2; // ICC
-
-constexpr uint32_t kICCMarkerHeaderSize = 14;
-constexpr uint8_t kICCSig[] = {
- 'I', 'C', 'C', '_', 'P', 'R', 'O', 'F', 'I', 'L', 'E', '\0',
-};
-constexpr uint8_t kXmpNameSpace[] = {
- 'h', 't', 't', 'p', ':', '/', '/', 'n', 's', '.', 'a', 'd', 'o', 'b', 'e',
- '.', 'c', 'o', 'm', '/', 'x', 'a', 'p', '/', '1', '.', '0', '/', '\0',
-};
-constexpr uint8_t kExifIdCode[] = {
- 'E', 'x', 'i', 'f', '\0', '\0',
-};
-
-struct jpegr_source_mgr : jpeg_source_mgr {
- jpegr_source_mgr(const uint8_t* ptr, int len);
- ~jpegr_source_mgr();
-
- const uint8_t* mBufferPtr;
- size_t mBufferLength;
-};
-
-struct jpegrerror_mgr {
- struct jpeg_error_mgr pub;
- jmp_buf setjmp_buffer;
-};
-
-static void jpegr_init_source(j_decompress_ptr cinfo) {
- jpegr_source_mgr* src = static_cast<jpegr_source_mgr*>(cinfo->src);
- src->next_input_byte = static_cast<const JOCTET*>(src->mBufferPtr);
- src->bytes_in_buffer = src->mBufferLength;
-}
-
-static boolean jpegr_fill_input_buffer(j_decompress_ptr /* cinfo */) {
- ALOGE("%s : should not get here", __func__);
- return FALSE;
-}
-
-static void jpegr_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
- jpegr_source_mgr* src = static_cast<jpegr_source_mgr*>(cinfo->src);
-
- if (num_bytes > static_cast<long>(src->bytes_in_buffer)) {
- ALOGE("jpegr_skip_input_data - num_bytes > (long)src->bytes_in_buffer");
- } else {
- src->next_input_byte += num_bytes;
- src->bytes_in_buffer -= num_bytes;
- }
-}
-
-static void jpegr_term_source(j_decompress_ptr /*cinfo*/) {}
-
-jpegr_source_mgr::jpegr_source_mgr(const uint8_t* ptr, int len)
- : mBufferPtr(ptr), mBufferLength(len) {
- init_source = jpegr_init_source;
- fill_input_buffer = jpegr_fill_input_buffer;
- skip_input_data = jpegr_skip_input_data;
- resync_to_restart = jpeg_resync_to_restart;
- term_source = jpegr_term_source;
-}
-
-jpegr_source_mgr::~jpegr_source_mgr() {}
-
-static void jpegrerror_exit(j_common_ptr cinfo) {
- jpegrerror_mgr* err = reinterpret_cast<jpegrerror_mgr*>(cinfo->err);
- longjmp(err->setjmp_buffer, 1);
-}
-
-JpegDecoderHelper::JpegDecoderHelper() {}
-
-JpegDecoderHelper::~JpegDecoderHelper() {}
-
-bool JpegDecoderHelper::decompressImage(const void* image, int length, bool decodeToRGBA) {
- if (image == nullptr || length <= 0) {
- ALOGE("Image size can not be handled: %d", length);
- return false;
- }
- mResultBuffer.clear();
- mXMPBuffer.clear();
- return decode(image, length, decodeToRGBA);
-}
-
-void* JpegDecoderHelper::getDecompressedImagePtr() {
- return mResultBuffer.data();
-}
-
-size_t JpegDecoderHelper::getDecompressedImageSize() {
- return mResultBuffer.size();
-}
-
-void* JpegDecoderHelper::getXMPPtr() {
- return mXMPBuffer.data();
-}
-
-size_t JpegDecoderHelper::getXMPSize() {
- return mXMPBuffer.size();
-}
-
-void* JpegDecoderHelper::getEXIFPtr() {
- return mEXIFBuffer.data();
-}
-
-size_t JpegDecoderHelper::getEXIFSize() {
- return mEXIFBuffer.size();
-}
-
-void* JpegDecoderHelper::getICCPtr() {
- return mICCBuffer.data();
-}
-
-size_t JpegDecoderHelper::getICCSize() {
- return mICCBuffer.size();
-}
-
-size_t JpegDecoderHelper::getDecompressedImageWidth() {
- return mWidth;
-}
-
-size_t JpegDecoderHelper::getDecompressedImageHeight() {
- return mHeight;
-}
-
-// Here we only handle the first EXIF package, and in theary EXIF (or JFIF) must be the first
-// in the image file.
-// We assume that all packages are starting with two bytes marker (eg FF E1 for EXIF package),
-// two bytes of package length which is stored in marker->original_length, and the real data
-// which is stored in marker->data.
-bool JpegDecoderHelper::extractEXIF(const void* image, int length) {
- jpeg_decompress_struct cinfo;
- jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
- jpegrerror_mgr myerr;
-
- cinfo.err = jpeg_std_error(&myerr.pub);
- myerr.pub.error_exit = jpegrerror_exit;
-
- if (setjmp(myerr.setjmp_buffer)) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
- jpeg_create_decompress(&cinfo);
-
- jpeg_save_markers(&cinfo, kAPP0Marker, 0xFFFF);
- jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
-
- cinfo.src = &mgr;
- jpeg_read_header(&cinfo, TRUE);
-
- size_t pos = 2; // position after SOI
- for (jpeg_marker_struct* marker = cinfo.marker_list;
- marker;
- marker = marker->next) {
-
- pos += 4;
- pos += marker->original_length;
-
- if (marker->marker != kAPP1Marker) {
- continue;
- }
-
- const unsigned int len = marker->data_length;
-
- if (len > sizeof(kExifIdCode) &&
- !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
- mEXIFBuffer.resize(len, 0);
- memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len);
- mExifPos = pos - marker->original_length;
- break;
- }
- }
-
- jpeg_destroy_decompress(&cinfo);
- return true;
-}
-
-bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) {
- bool status = true;
- jpeg_decompress_struct cinfo;
- jpegrerror_mgr myerr;
- cinfo.err = jpeg_std_error(&myerr.pub);
- myerr.pub.error_exit = jpegrerror_exit;
- if (setjmp(myerr.setjmp_buffer)) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
-
- jpeg_create_decompress(&cinfo);
-
- jpeg_save_markers(&cinfo, kAPP0Marker, 0xFFFF);
- jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
- jpeg_save_markers(&cinfo, kAPP2Marker, 0xFFFF);
-
- jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
- cinfo.src = &mgr;
- if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
-
- // Save XMP data, EXIF data, and ICC data.
- // Here we only handle the first XMP / EXIF / ICC package.
- // We assume that all packages are starting with two bytes marker (eg FF E1 for EXIF package),
- // two bytes of package length which is stored in marker->original_length, and the real data
- // which is stored in marker->data.
- bool exifAppears = false;
- bool xmpAppears = false;
- bool iccAppears = false;
- size_t pos = 2; // position after SOI
- for (jpeg_marker_struct* marker = cinfo.marker_list;
- marker && !(exifAppears && xmpAppears && iccAppears);
- marker = marker->next) {
- pos += 4;
- pos += marker->original_length;
- if (marker->marker != kAPP1Marker && marker->marker != kAPP2Marker) {
- continue;
- }
- const unsigned int len = marker->data_length;
- if (!xmpAppears &&
- len > sizeof(kXmpNameSpace) &&
- !memcmp(marker->data, kXmpNameSpace, sizeof(kXmpNameSpace))) {
- mXMPBuffer.resize(len+1, 0);
- memcpy(static_cast<void*>(mXMPBuffer.data()), marker->data, len);
- xmpAppears = true;
- } else if (!exifAppears &&
- len > sizeof(kExifIdCode) &&
- !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
- mEXIFBuffer.resize(len, 0);
- memcpy(static_cast<void*>(mEXIFBuffer.data()), marker->data, len);
- exifAppears = true;
- mExifPos = pos - marker->original_length;
- } else if (!iccAppears &&
- len > sizeof(kICCSig) &&
- !memcmp(marker->data, kICCSig, sizeof(kICCSig))) {
- mICCBuffer.resize(len, 0);
- memcpy(static_cast<void*>(mICCBuffer.data()), marker->data, len);
- iccAppears = true;
- }
- }
-
- mWidth = cinfo.image_width;
- mHeight = cinfo.image_height;
- if (mWidth > kMaxWidth || mHeight > kMaxHeight) {
- status = false;
- goto CleanUp;
- }
-
- if (decodeToRGBA) {
- // The primary image is expected to be yuv420 sampling
- if (cinfo.jpeg_color_space != JCS_YCbCr) {
- status = false;
- ALOGE("%s: decodeToRGBA unexpected jpeg color space ", __func__);
- goto CleanUp;
- }
- if (cinfo.comp_info[0].h_samp_factor != 2 || cinfo.comp_info[0].v_samp_factor != 2 ||
- cinfo.comp_info[1].h_samp_factor != 1 || cinfo.comp_info[1].v_samp_factor != 1 ||
- cinfo.comp_info[2].h_samp_factor != 1 || cinfo.comp_info[2].v_samp_factor != 1) {
- status = false;
- ALOGE("%s: decodeToRGBA unexpected primary image sub-sampling", __func__);
- goto CleanUp;
- }
- // 4 bytes per pixel
- mResultBuffer.resize(cinfo.image_width * cinfo.image_height * 4);
- cinfo.out_color_space = JCS_EXT_RGBA;
- } else {
- if (cinfo.jpeg_color_space == JCS_YCbCr) {
- if (cinfo.comp_info[0].h_samp_factor != 2 || cinfo.comp_info[0].v_samp_factor != 2 ||
- cinfo.comp_info[1].h_samp_factor != 1 || cinfo.comp_info[1].v_samp_factor != 1 ||
- cinfo.comp_info[2].h_samp_factor != 1 || cinfo.comp_info[2].v_samp_factor != 1) {
- status = false;
- ALOGE("%s: decoding to YUV only supports 4:2:0 subsampling", __func__);
- goto CleanUp;
- }
- mResultBuffer.resize(cinfo.image_width * cinfo.image_height * 3 / 2, 0);
- } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
- mResultBuffer.resize(cinfo.image_width * cinfo.image_height, 0);
- } else {
- status = false;
- ALOGE("%s: decodeToYUV unexpected jpeg color space", __func__);
- goto CleanUp;
- }
- cinfo.out_color_space = cinfo.jpeg_color_space;
- cinfo.raw_data_out = TRUE;
- }
-
- cinfo.dct_method = JDCT_ISLOW;
- jpeg_start_decompress(&cinfo);
- if (!decompress(&cinfo, static_cast<const uint8_t*>(mResultBuffer.data()),
- cinfo.jpeg_color_space == JCS_GRAYSCALE)) {
- status = false;
- goto CleanUp;
- }
-
-CleanUp:
- jpeg_finish_decompress(&cinfo);
- jpeg_destroy_decompress(&cinfo);
-
- return status;
-}
-
-bool JpegDecoderHelper::decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest,
- bool isSingleChannel) {
- return isSingleChannel
- ? decompressSingleChannel(cinfo, dest)
- : ((cinfo->out_color_space == JCS_EXT_RGBA) ? decompressRGBA(cinfo, dest)
- : decompressYUV(cinfo, dest));
-}
-
-bool JpegDecoderHelper::getCompressedImageParameters(const void* image, int length, size_t* pWidth,
- size_t* pHeight, std::vector<uint8_t>* iccData,
- std::vector<uint8_t>* exifData) {
- jpeg_decompress_struct cinfo;
- jpegrerror_mgr myerr;
- cinfo.err = jpeg_std_error(&myerr.pub);
- myerr.pub.error_exit = jpegrerror_exit;
- if (setjmp(myerr.setjmp_buffer)) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
- jpeg_create_decompress(&cinfo);
-
- jpeg_save_markers(&cinfo, kAPP1Marker, 0xFFFF);
- jpeg_save_markers(&cinfo, kAPP2Marker, 0xFFFF);
-
- jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
- cinfo.src = &mgr;
- if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
- jpeg_destroy_decompress(&cinfo);
- return false;
- }
-
- if (pWidth != nullptr) {
- *pWidth = cinfo.image_width;
- }
- if (pHeight != nullptr) {
- *pHeight = cinfo.image_height;
- }
-
- if (iccData != nullptr) {
- for (jpeg_marker_struct* marker = cinfo.marker_list; marker; marker = marker->next) {
- if (marker->marker != kAPP2Marker) {
- continue;
- }
- if (marker->data_length <= kICCMarkerHeaderSize ||
- memcmp(marker->data, kICCSig, sizeof(kICCSig)) != 0) {
- continue;
- }
-
- iccData->insert(iccData->end(), marker->data, marker->data + marker->data_length);
- }
- }
-
- if (exifData != nullptr) {
- bool exifAppears = false;
- for (jpeg_marker_struct* marker = cinfo.marker_list; marker && !exifAppears;
- marker = marker->next) {
- if (marker->marker != kAPP1Marker) {
- continue;
- }
-
- const unsigned int len = marker->data_length;
- if (len >= sizeof(kExifIdCode) &&
- !memcmp(marker->data, kExifIdCode, sizeof(kExifIdCode))) {
- exifData->resize(len, 0);
- memcpy(static_cast<void*>(exifData->data()), marker->data, len);
- exifAppears = true;
- }
- }
- }
-
- jpeg_destroy_decompress(&cinfo);
- return true;
-}
-
-bool JpegDecoderHelper::decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
- JSAMPLE* out = (JSAMPLE*)dest;
-
- while (cinfo->output_scanline < cinfo->image_height) {
- if (1 != jpeg_read_scanlines(cinfo, &out, 1)) return false;
- out += cinfo->image_width * 4;
- }
- return true;
-}
-
-bool JpegDecoderHelper::decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
- JSAMPROW y[kCompressBatchSize];
- JSAMPROW cb[kCompressBatchSize / 2];
- JSAMPROW cr[kCompressBatchSize / 2];
- JSAMPARRAY planes[3]{y, cb, cr};
-
- size_t y_plane_size = cinfo->image_width * cinfo->image_height;
- size_t uv_plane_size = y_plane_size / 4;
- uint8_t* y_plane = const_cast<uint8_t*>(dest);
- uint8_t* u_plane = const_cast<uint8_t*>(dest + y_plane_size);
- uint8_t* v_plane = const_cast<uint8_t*>(dest + y_plane_size + uv_plane_size);
- std::unique_ptr<uint8_t[]> empty = std::make_unique<uint8_t[]>(cinfo->image_width);
- memset(empty.get(), 0, cinfo->image_width);
-
- const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize);
- bool is_width_aligned = (aligned_width == cinfo->image_width);
- std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
- uint8_t* y_plane_intrm = nullptr;
- uint8_t* u_plane_intrm = nullptr;
- uint8_t* v_plane_intrm = nullptr;
- JSAMPROW y_intrm[kCompressBatchSize];
- JSAMPROW cb_intrm[kCompressBatchSize / 2];
- JSAMPROW cr_intrm[kCompressBatchSize / 2];
- JSAMPARRAY planes_intrm[3]{y_intrm, cb_intrm, cr_intrm};
- if (!is_width_aligned) {
- size_t mcu_row_size = aligned_width * kCompressBatchSize * 3 / 2;
- buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
- y_plane_intrm = buffer_intrm.get();
- u_plane_intrm = y_plane_intrm + (aligned_width * kCompressBatchSize);
- v_plane_intrm = u_plane_intrm + (aligned_width * kCompressBatchSize) / 4;
- for (int i = 0; i < kCompressBatchSize; ++i) {
- y_intrm[i] = y_plane_intrm + i * aligned_width;
- }
- for (int i = 0; i < kCompressBatchSize / 2; ++i) {
- int offset_intrm = i * (aligned_width / 2);
- cb_intrm[i] = u_plane_intrm + offset_intrm;
- cr_intrm[i] = v_plane_intrm + offset_intrm;
- }
- }
-
- while (cinfo->output_scanline < cinfo->image_height) {
- for (int i = 0; i < kCompressBatchSize; ++i) {
- size_t scanline = cinfo->output_scanline + i;
- if (scanline < cinfo->image_height) {
- y[i] = y_plane + scanline * cinfo->image_width;
- } else {
- y[i] = empty.get();
- }
- }
- // cb, cr only have half scanlines
- for (int i = 0; i < kCompressBatchSize / 2; ++i) {
- size_t scanline = cinfo->output_scanline / 2 + i;
- if (scanline < cinfo->image_height / 2) {
- int offset = scanline * (cinfo->image_width / 2);
- cb[i] = u_plane + offset;
- cr[i] = v_plane + offset;
- } else {
- cb[i] = cr[i] = empty.get();
- }
- }
-
- int processed = jpeg_read_raw_data(cinfo, is_width_aligned ? planes : planes_intrm,
- kCompressBatchSize);
- if (processed != kCompressBatchSize) {
- ALOGE("Number of processed lines does not equal input lines.");
- return false;
- }
- if (!is_width_aligned) {
- for (int i = 0; i < kCompressBatchSize; ++i) {
- memcpy(y[i], y_intrm[i], cinfo->image_width);
- }
- for (int i = 0; i < kCompressBatchSize / 2; ++i) {
- memcpy(cb[i], cb_intrm[i], cinfo->image_width / 2);
- memcpy(cr[i], cr_intrm[i], cinfo->image_width / 2);
- }
- }
- }
- return true;
-}
-
-bool JpegDecoderHelper::decompressSingleChannel(jpeg_decompress_struct* cinfo,
- const uint8_t* dest) {
- JSAMPROW y[kCompressBatchSize];
- JSAMPARRAY planes[1]{y};
-
- uint8_t* y_plane = const_cast<uint8_t*>(dest);
- std::unique_ptr<uint8_t[]> empty = std::make_unique<uint8_t[]>(cinfo->image_width);
- memset(empty.get(), 0, cinfo->image_width);
-
- int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize);
- bool is_width_aligned = (aligned_width == cinfo->image_width);
- std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
- uint8_t* y_plane_intrm = nullptr;
- JSAMPROW y_intrm[kCompressBatchSize];
- JSAMPARRAY planes_intrm[1]{y_intrm};
- if (!is_width_aligned) {
- size_t mcu_row_size = aligned_width * kCompressBatchSize;
- buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
- y_plane_intrm = buffer_intrm.get();
- for (int i = 0; i < kCompressBatchSize; ++i) {
- y_intrm[i] = y_plane_intrm + i * aligned_width;
- }
- }
-
- while (cinfo->output_scanline < cinfo->image_height) {
- for (int i = 0; i < kCompressBatchSize; ++i) {
- size_t scanline = cinfo->output_scanline + i;
- if (scanline < cinfo->image_height) {
- y[i] = y_plane + scanline * cinfo->image_width;
- } else {
- y[i] = empty.get();
- }
- }
-
- int processed = jpeg_read_raw_data(cinfo, is_width_aligned ? planes : planes_intrm,
- kCompressBatchSize);
- if (processed != kCompressBatchSize / 2) {
- ALOGE("Number of processed lines does not equal input lines.");
- return false;
- }
- if (!is_width_aligned) {
- for (int i = 0; i < kCompressBatchSize; ++i) {
- memcpy(y[i], y_intrm[i], cinfo->image_width);
- }
- }
- }
- return true;
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/jpegencoderhelper.cpp b/libs/ultrahdr/jpegencoderhelper.cpp
deleted file mode 100644
index 13ae742..0000000
--- a/libs/ultrahdr/jpegencoderhelper.cpp
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2022 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 <cstring>
-#include <memory>
-#include <vector>
-
-#include <ultrahdr/jpegencoderhelper.h>
-#include <utils/Log.h>
-
-namespace android::ultrahdr {
-
-// The destination manager that can access |mResultBuffer| in JpegEncoderHelper.
-struct destination_mgr {
- struct jpeg_destination_mgr mgr;
- JpegEncoderHelper* encoder;
-};
-
-JpegEncoderHelper::JpegEncoderHelper() {}
-
-JpegEncoderHelper::~JpegEncoderHelper() {}
-
-bool JpegEncoderHelper::compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width,
- int height, int lumaStride, int chromaStride, int quality,
- const void* iccBuffer, unsigned int iccSize) {
- mResultBuffer.clear();
- if (!encode(yBuffer, uvBuffer, width, height, lumaStride, chromaStride, quality, iccBuffer,
- iccSize)) {
- return false;
- }
- ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", (width * height * 12) / 8, width, height,
- mResultBuffer.size());
- return true;
-}
-
-void* JpegEncoderHelper::getCompressedImagePtr() {
- return mResultBuffer.data();
-}
-
-size_t JpegEncoderHelper::getCompressedImageSize() {
- return mResultBuffer.size();
-}
-
-void JpegEncoderHelper::initDestination(j_compress_ptr cinfo) {
- destination_mgr* dest = reinterpret_cast<destination_mgr*>(cinfo->dest);
- std::vector<JOCTET>& buffer = dest->encoder->mResultBuffer;
- buffer.resize(kBlockSize);
- dest->mgr.next_output_byte = &buffer[0];
- dest->mgr.free_in_buffer = buffer.size();
-}
-
-boolean JpegEncoderHelper::emptyOutputBuffer(j_compress_ptr cinfo) {
- destination_mgr* dest = reinterpret_cast<destination_mgr*>(cinfo->dest);
- std::vector<JOCTET>& buffer = dest->encoder->mResultBuffer;
- size_t oldsize = buffer.size();
- buffer.resize(oldsize + kBlockSize);
- dest->mgr.next_output_byte = &buffer[oldsize];
- dest->mgr.free_in_buffer = kBlockSize;
- return true;
-}
-
-void JpegEncoderHelper::terminateDestination(j_compress_ptr cinfo) {
- destination_mgr* dest = reinterpret_cast<destination_mgr*>(cinfo->dest);
- std::vector<JOCTET>& buffer = dest->encoder->mResultBuffer;
- buffer.resize(buffer.size() - dest->mgr.free_in_buffer);
-}
-
-void JpegEncoderHelper::outputErrorMessage(j_common_ptr cinfo) {
- char buffer[JMSG_LENGTH_MAX];
-
- /* Create the message */
- (*cinfo->err->format_message)(cinfo, buffer);
- ALOGE("%s\n", buffer);
-}
-
-bool JpegEncoderHelper::encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width,
- int height, int lumaStride, int chromaStride, int quality,
- const void* iccBuffer, unsigned int iccSize) {
- jpeg_compress_struct cinfo;
- jpeg_error_mgr jerr;
-
- cinfo.err = jpeg_std_error(&jerr);
- cinfo.err->output_message = &outputErrorMessage;
- jpeg_create_compress(&cinfo);
- setJpegDestination(&cinfo);
- setJpegCompressStruct(width, height, quality, &cinfo, uvBuffer == nullptr);
- jpeg_start_compress(&cinfo, TRUE);
- if (iccBuffer != nullptr && iccSize > 0) {
- jpeg_write_marker(&cinfo, JPEG_APP0 + 2, static_cast<const JOCTET*>(iccBuffer), iccSize);
- }
- bool status = cinfo.num_components == 1
- ? compressY(&cinfo, yBuffer, lumaStride)
- : compressYuv(&cinfo, yBuffer, uvBuffer, lumaStride, chromaStride);
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
-
- return status;
-}
-
-void JpegEncoderHelper::setJpegDestination(jpeg_compress_struct* cinfo) {
- destination_mgr* dest = static_cast<struct destination_mgr*>(
- (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT,
- sizeof(destination_mgr)));
- dest->encoder = this;
- dest->mgr.init_destination = &initDestination;
- dest->mgr.empty_output_buffer = &emptyOutputBuffer;
- dest->mgr.term_destination = &terminateDestination;
- cinfo->dest = reinterpret_cast<struct jpeg_destination_mgr*>(dest);
-}
-
-void JpegEncoderHelper::setJpegCompressStruct(int width, int height, int quality,
- jpeg_compress_struct* cinfo, bool isSingleChannel) {
- cinfo->image_width = width;
- cinfo->image_height = height;
- cinfo->input_components = isSingleChannel ? 1 : 3;
- cinfo->in_color_space = isSingleChannel ? JCS_GRAYSCALE : JCS_YCbCr;
- jpeg_set_defaults(cinfo);
- jpeg_set_quality(cinfo, quality, TRUE);
- cinfo->raw_data_in = TRUE;
- cinfo->dct_method = JDCT_ISLOW;
- cinfo->comp_info[0].h_samp_factor = cinfo->in_color_space == JCS_GRAYSCALE ? 1 : 2;
- cinfo->comp_info[0].v_samp_factor = cinfo->in_color_space == JCS_GRAYSCALE ? 1 : 2;
- for (int i = 1; i < cinfo->num_components; i++) {
- cinfo->comp_info[i].h_samp_factor = 1;
- cinfo->comp_info[i].v_samp_factor = 1;
- }
-}
-
-bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer,
- const uint8_t* uvBuffer, int lumaStride, int chromaStride) {
- JSAMPROW y[kCompressBatchSize];
- JSAMPROW cb[kCompressBatchSize / 2];
- JSAMPROW cr[kCompressBatchSize / 2];
- JSAMPARRAY planes[3]{y, cb, cr};
-
- size_t y_plane_size = lumaStride * cinfo->image_height;
- size_t u_plane_size = chromaStride * cinfo->image_height / 2;
- uint8_t* y_plane = const_cast<uint8_t*>(yBuffer);
- uint8_t* u_plane = const_cast<uint8_t*>(uvBuffer);
- uint8_t* v_plane = const_cast<uint8_t*>(u_plane + u_plane_size);
- std::unique_ptr<uint8_t[]> empty = std::make_unique<uint8_t[]>(cinfo->image_width);
- memset(empty.get(), 0, cinfo->image_width);
-
- const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize);
- const bool need_padding = (lumaStride < aligned_width);
- std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
- uint8_t* y_plane_intrm = nullptr;
- uint8_t* u_plane_intrm = nullptr;
- uint8_t* v_plane_intrm = nullptr;
- JSAMPROW y_intrm[kCompressBatchSize];
- JSAMPROW cb_intrm[kCompressBatchSize / 2];
- JSAMPROW cr_intrm[kCompressBatchSize / 2];
- JSAMPARRAY planes_intrm[3]{y_intrm, cb_intrm, cr_intrm};
- if (need_padding) {
- size_t mcu_row_size = aligned_width * kCompressBatchSize * 3 / 2;
- buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
- y_plane_intrm = buffer_intrm.get();
- u_plane_intrm = y_plane_intrm + (aligned_width * kCompressBatchSize);
- v_plane_intrm = u_plane_intrm + (aligned_width * kCompressBatchSize) / 4;
- for (int i = 0; i < kCompressBatchSize; ++i) {
- y_intrm[i] = y_plane_intrm + i * aligned_width;
- memset(y_intrm[i] + cinfo->image_width, 0, aligned_width - cinfo->image_width);
- }
- for (int i = 0; i < kCompressBatchSize / 2; ++i) {
- int offset_intrm = i * (aligned_width / 2);
- cb_intrm[i] = u_plane_intrm + offset_intrm;
- cr_intrm[i] = v_plane_intrm + offset_intrm;
- memset(cb_intrm[i] + cinfo->image_width / 2, 0,
- (aligned_width - cinfo->image_width) / 2);
- memset(cr_intrm[i] + cinfo->image_width / 2, 0,
- (aligned_width - cinfo->image_width) / 2);
- }
- }
-
- while (cinfo->next_scanline < cinfo->image_height) {
- for (int i = 0; i < kCompressBatchSize; ++i) {
- size_t scanline = cinfo->next_scanline + i;
- if (scanline < cinfo->image_height) {
- y[i] = y_plane + scanline * lumaStride;
- } else {
- y[i] = empty.get();
- }
- if (need_padding) {
- memcpy(y_intrm[i], y[i], cinfo->image_width);
- }
- }
- // cb, cr only have half scanlines
- for (int i = 0; i < kCompressBatchSize / 2; ++i) {
- size_t scanline = cinfo->next_scanline / 2 + i;
- if (scanline < cinfo->image_height / 2) {
- int offset = scanline * chromaStride;
- cb[i] = u_plane + offset;
- cr[i] = v_plane + offset;
- } else {
- cb[i] = cr[i] = empty.get();
- }
- if (need_padding) {
- memcpy(cb_intrm[i], cb[i], cinfo->image_width / 2);
- memcpy(cr_intrm[i], cr[i], cinfo->image_width / 2);
- }
- }
- int processed = jpeg_write_raw_data(cinfo, need_padding ? planes_intrm : planes,
- kCompressBatchSize);
- if (processed != kCompressBatchSize) {
- ALOGE("Number of processed lines does not equal input lines.");
- return false;
- }
- }
- return true;
-}
-
-bool JpegEncoderHelper::compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer,
- int lumaStride) {
- JSAMPROW y[kCompressBatchSize];
- JSAMPARRAY planes[1]{y};
-
- uint8_t* y_plane = const_cast<uint8_t*>(yBuffer);
- std::unique_ptr<uint8_t[]> empty = std::make_unique<uint8_t[]>(cinfo->image_width);
- memset(empty.get(), 0, cinfo->image_width);
-
- const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize);
- const bool need_padding = (lumaStride < aligned_width);
- std::unique_ptr<uint8_t[]> buffer_intrm = nullptr;
- uint8_t* y_plane_intrm = nullptr;
- uint8_t* u_plane_intrm = nullptr;
- JSAMPROW y_intrm[kCompressBatchSize];
- JSAMPARRAY planes_intrm[]{y_intrm};
- if (need_padding) {
- size_t mcu_row_size = aligned_width * kCompressBatchSize;
- buffer_intrm = std::make_unique<uint8_t[]>(mcu_row_size);
- y_plane_intrm = buffer_intrm.get();
- for (int i = 0; i < kCompressBatchSize; ++i) {
- y_intrm[i] = y_plane_intrm + i * aligned_width;
- memset(y_intrm[i] + cinfo->image_width, 0, aligned_width - cinfo->image_width);
- }
- }
-
- while (cinfo->next_scanline < cinfo->image_height) {
- for (int i = 0; i < kCompressBatchSize; ++i) {
- size_t scanline = cinfo->next_scanline + i;
- if (scanline < cinfo->image_height) {
- y[i] = y_plane + scanline * lumaStride;
- } else {
- y[i] = empty.get();
- }
- if (need_padding) {
- memcpy(y_intrm[i], y[i], cinfo->image_width);
- }
- }
- int processed = jpeg_write_raw_data(cinfo, need_padding ? planes_intrm : planes,
- kCompressBatchSize);
- if (processed != kCompressBatchSize / 2) {
- ALOGE("Number of processed lines does not equal input lines.");
- return false;
- }
- }
- return true;
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
deleted file mode 100644
index 3d70fce..0000000
--- a/libs/ultrahdr/jpegr.cpp
+++ /dev/null
@@ -1,1503 +0,0 @@
-/*
- * Copyright 2022 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 <cmath>
-#include <condition_variable>
-#include <deque>
-#include <memory>
-#include <mutex>
-#include <thread>
-
-#include <ultrahdr/gainmapmath.h>
-#include <ultrahdr/icc.h>
-#include <ultrahdr/jpegr.h>
-#include <ultrahdr/jpegrutils.h>
-#include <ultrahdr/multipictureformat.h>
-
-#include <image_io/base/data_segment_data_source.h>
-#include <image_io/jpeg/jpeg_info.h>
-#include <image_io/jpeg/jpeg_info_builder.h>
-#include <image_io/jpeg/jpeg_marker.h>
-#include <image_io/jpeg/jpeg_scanner.h>
-
-#include <utils/Log.h>
-
-using namespace std;
-using namespace photos_editing_formats::image_io;
-
-namespace android::ultrahdr {
-
-#define USE_SRGB_INVOETF_LUT 1
-#define USE_HLG_OETF_LUT 1
-#define USE_PQ_OETF_LUT 1
-#define USE_HLG_INVOETF_LUT 1
-#define USE_PQ_INVOETF_LUT 1
-#define USE_APPLY_GAIN_LUT 1
-
-#define JPEGR_CHECK(x) \
- { \
- status_t status = (x); \
- if ((status) != NO_ERROR) { \
- return status; \
- } \
- }
-
-// JPEG compress quality (0 ~ 100) for gain map
-static const int kMapCompressQuality = 85;
-
-#define CONFIG_MULTITHREAD 1
-int GetCPUCoreCount() {
- int cpuCoreCount = 1;
-#if CONFIG_MULTITHREAD
-#if defined(_SC_NPROCESSORS_ONLN)
- cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
-#else
- // _SC_NPROC_ONLN must be defined...
- cpuCoreCount = sysconf(_SC_NPROC_ONLN);
-#endif
-#endif
- return cpuCoreCount;
-}
-
-/*
- * Helper function copies the JPEG image from without EXIF.
- *
- * @param pDest destination of the data to be written.
- * @param pSource source of data being written.
- * @param exif_pos position of the EXIF package, which is aligned with jpegdecoder.getEXIFPos().
- * (4 bytes offset to FF sign, the byte after FF E1 XX XX <this byte>).
- * @param exif_size exif size without the initial 4 bytes, aligned with jpegdecoder.getEXIFSize().
- */
-static void copyJpegWithoutExif(jr_compressed_ptr pDest,
- jr_compressed_ptr pSource,
- size_t exif_pos,
- size_t exif_size) {
- const size_t exif_offset = 4; //exif_pos has 4 bytes offset to the FF sign
- pDest->length = pSource->length - exif_size - exif_offset;
- pDest->data = new uint8_t[pDest->length];
- pDest->maxLength = pDest->length;
- pDest->colorGamut = pSource->colorGamut;
- memcpy(pDest->data, pSource->data, exif_pos - exif_offset);
- memcpy((uint8_t*)pDest->data + exif_pos - exif_offset,
- (uint8_t*)pSource->data + exif_pos + exif_size,
- pSource->length - exif_pos - exif_size);
-}
-
-status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr,
- jr_uncompressed_ptr yuv420_image_ptr,
- ultrahdr_transfer_function hdr_tf,
- jr_compressed_ptr dest_ptr) {
- if (p010_image_ptr == nullptr || p010_image_ptr->data == nullptr) {
- ALOGE("Received nullptr for input p010 image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (p010_image_ptr->width % 2 != 0 || p010_image_ptr->height % 2 != 0) {
- ALOGE("Image dimensions cannot be odd, image dimensions %dx%d", p010_image_ptr->width,
- p010_image_ptr->height);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (p010_image_ptr->width < kMinWidth || p010_image_ptr->height < kMinHeight) {
- ALOGE("Image dimensions cannot be less than %dx%d, image dimensions %dx%d", kMinWidth,
- kMinHeight, p010_image_ptr->width, p010_image_ptr->height);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (p010_image_ptr->width > kMaxWidth || p010_image_ptr->height > kMaxHeight) {
- ALOGE("Image dimensions cannot be larger than %dx%d, image dimensions %dx%d", kMaxWidth,
- kMaxHeight, p010_image_ptr->width, p010_image_ptr->height);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (p010_image_ptr->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED ||
- p010_image_ptr->colorGamut > ULTRAHDR_COLORGAMUT_MAX) {
- ALOGE("Unrecognized p010 color gamut %d", p010_image_ptr->colorGamut);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (p010_image_ptr->luma_stride != 0 && p010_image_ptr->luma_stride < p010_image_ptr->width) {
- ALOGE("Luma stride must not be smaller than width, stride=%d, width=%d",
- p010_image_ptr->luma_stride, p010_image_ptr->width);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (p010_image_ptr->chroma_data != nullptr &&
- p010_image_ptr->chroma_stride < p010_image_ptr->width) {
- ALOGE("Chroma stride must not be smaller than width, stride=%d, width=%d",
- p010_image_ptr->chroma_stride, p010_image_ptr->width);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (dest_ptr == nullptr || dest_ptr->data == nullptr) {
- ALOGE("Received nullptr for destination");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX || hdr_tf == ULTRAHDR_TF_SRGB) {
- ALOGE("Invalid hdr transfer function %d", hdr_tf);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (yuv420_image_ptr == nullptr) {
- return NO_ERROR;
- }
- if (yuv420_image_ptr->data == nullptr) {
- ALOGE("Received nullptr for uncompressed 420 image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (yuv420_image_ptr->luma_stride != 0 &&
- yuv420_image_ptr->luma_stride < yuv420_image_ptr->width) {
- ALOGE("Luma stride must not be smaller than width, stride=%d, width=%d",
- yuv420_image_ptr->luma_stride, yuv420_image_ptr->width);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (yuv420_image_ptr->chroma_data != nullptr &&
- yuv420_image_ptr->chroma_stride < yuv420_image_ptr->width / 2) {
- ALOGE("Chroma stride must not be smaller than (width / 2), stride=%d, width=%d",
- yuv420_image_ptr->chroma_stride, yuv420_image_ptr->width);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (p010_image_ptr->width != yuv420_image_ptr->width ||
- p010_image_ptr->height != yuv420_image_ptr->height) {
- ALOGE("Image resolutions mismatch: P010: %dx%d, YUV420: %dx%d", p010_image_ptr->width,
- p010_image_ptr->height, yuv420_image_ptr->width, yuv420_image_ptr->height);
- return ERROR_JPEGR_RESOLUTION_MISMATCH;
- }
- if (yuv420_image_ptr->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED ||
- yuv420_image_ptr->colorGamut > ULTRAHDR_COLORGAMUT_MAX) {
- ALOGE("Unrecognized 420 color gamut %d", yuv420_image_ptr->colorGamut);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- return NO_ERROR;
-}
-
-status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr,
- jr_uncompressed_ptr yuv420_image_ptr,
- ultrahdr_transfer_function hdr_tf,
- jr_compressed_ptr dest_ptr, int quality) {
- if (quality < 0 || quality > 100) {
- ALOGE("quality factor is out side range [0-100], quality factor : %d", quality);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- return areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest_ptr);
-}
-
-/* Encode API-0 */
-status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf,
- jr_compressed_ptr dest, int quality, jr_exif_ptr exif) {
- // validate input arguments
- if (auto ret = areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest, quality);
- ret != NO_ERROR) {
- return ret;
- }
- if (exif != nullptr && exif->data == nullptr) {
- ALOGE("received nullptr for exif metadata");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
-
- // clean up input structure for later usage
- jpegr_uncompressed_struct p010_image = *p010_image_ptr;
- if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width;
- if (!p010_image.chroma_data) {
- uint16_t* data = reinterpret_cast<uint16_t*>(p010_image.data);
- p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height;
- p010_image.chroma_stride = p010_image.luma_stride;
- }
-
- const int yu420_luma_stride = ALIGNM(p010_image.width, kJpegBlock);
- unique_ptr<uint8_t[]> yuv420_image_data =
- make_unique<uint8_t[]>(yu420_luma_stride * p010_image.height * 3 / 2);
- jpegr_uncompressed_struct yuv420_image = {.data = yuv420_image_data.get(),
- .width = p010_image.width,
- .height = p010_image.height,
- .colorGamut = p010_image.colorGamut,
- .luma_stride = yu420_luma_stride,
- .chroma_data = nullptr,
- .chroma_stride = yu420_luma_stride >> 1};
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data);
- yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height;
-
- // tone map
- JPEGR_CHECK(toneMap(&p010_image, &yuv420_image));
-
- // gain map
- ultrahdr_metadata_struct metadata = {.version = kJpegrVersion};
- jpegr_uncompressed_struct gainmap_image;
- JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image));
- std::unique_ptr<uint8_t[]> map_data;
- map_data.reset(reinterpret_cast<uint8_t*>(gainmap_image.data));
-
- // compress gain map
- JpegEncoderHelper jpeg_enc_obj_gm;
- JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm));
- jpegr_compressed_struct compressed_map = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(),
- .length = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .maxLength = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
-
- sp<DataStruct> icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420_image.colorGamut);
-
- // convert to Bt601 YUV encoding for JPEG encode
- if (yuv420_image.colorGamut != ULTRAHDR_COLORGAMUT_P3) {
- JPEGR_CHECK(convertYuv(&yuv420_image, yuv420_image.colorGamut, ULTRAHDR_COLORGAMUT_P3));
- }
-
- // compress 420 image
- JpegEncoderHelper jpeg_enc_obj_yuv420;
- if (!jpeg_enc_obj_yuv420.compressImage(reinterpret_cast<uint8_t*>(yuv420_image.data),
- reinterpret_cast<uint8_t*>(yuv420_image.chroma_data),
- yuv420_image.width, yuv420_image.height,
- yuv420_image.luma_stride, yuv420_image.chroma_stride,
- quality, icc->getData(), icc->getLength())) {
- return ERROR_JPEGR_ENCODE_ERROR;
- }
- jpegr_compressed_struct jpeg = {.data = jpeg_enc_obj_yuv420.getCompressedImagePtr(),
- .length = static_cast<int>(
- jpeg_enc_obj_yuv420.getCompressedImageSize()),
- .maxLength = static_cast<int>(
- jpeg_enc_obj_yuv420.getCompressedImageSize()),
- .colorGamut = yuv420_image.colorGamut};
-
- // append gain map, no ICC since JPEG encode already did it
- JPEGR_CHECK(appendGainMap(&jpeg, &compressed_map, exif, /* icc */ nullptr, /* icc size */ 0,
- &metadata, dest));
-
- return NO_ERROR;
-}
-
-/* Encode API-1 */
-status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr,
- jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf,
- jr_compressed_ptr dest, int quality, jr_exif_ptr exif) {
- // validate input arguments
- if (yuv420_image_ptr == nullptr) {
- ALOGE("received nullptr for uncompressed 420 image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (exif != nullptr && exif->data == nullptr) {
- ALOGE("received nullptr for exif metadata");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (auto ret = areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest, quality);
- ret != NO_ERROR) {
- return ret;
- }
-
- // clean up input structure for later usage
- jpegr_uncompressed_struct p010_image = *p010_image_ptr;
- if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width;
- if (!p010_image.chroma_data) {
- uint16_t* data = reinterpret_cast<uint16_t*>(p010_image.data);
- p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height;
- p010_image.chroma_stride = p010_image.luma_stride;
- }
- jpegr_uncompressed_struct yuv420_image = *yuv420_image_ptr;
- if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width;
- if (!yuv420_image.chroma_data) {
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data);
- yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height;
- yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1;
- }
-
- // gain map
- ultrahdr_metadata_struct metadata = {.version = kJpegrVersion};
- jpegr_uncompressed_struct gainmap_image;
- JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image));
- std::unique_ptr<uint8_t[]> map_data;
- map_data.reset(reinterpret_cast<uint8_t*>(gainmap_image.data));
-
- // compress gain map
- JpegEncoderHelper jpeg_enc_obj_gm;
- JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm));
- jpegr_compressed_struct compressed_map = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(),
- .length = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .maxLength = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
-
- sp<DataStruct> icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420_image.colorGamut);
-
- jpegr_uncompressed_struct yuv420_bt601_image = yuv420_image;
- unique_ptr<uint8_t[]> yuv_420_bt601_data;
- // Convert to bt601 YUV encoding for JPEG encode
- if (yuv420_image.colorGamut != ULTRAHDR_COLORGAMUT_P3) {
- const int yuv_420_bt601_luma_stride = ALIGNM(yuv420_image.width, kJpegBlock);
- yuv_420_bt601_data =
- make_unique<uint8_t[]>(yuv_420_bt601_luma_stride * yuv420_image.height * 3 / 2);
- yuv420_bt601_image.data = yuv_420_bt601_data.get();
- yuv420_bt601_image.colorGamut = yuv420_image.colorGamut;
- yuv420_bt601_image.luma_stride = yuv_420_bt601_luma_stride;
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_bt601_image.data);
- yuv420_bt601_image.chroma_data = data + yuv_420_bt601_luma_stride * yuv420_image.height;
- yuv420_bt601_image.chroma_stride = yuv_420_bt601_luma_stride >> 1;
-
- {
- // copy luma
- uint8_t* y_dst = reinterpret_cast<uint8_t*>(yuv420_bt601_image.data);
- uint8_t* y_src = reinterpret_cast<uint8_t*>(yuv420_image.data);
- if (yuv420_bt601_image.luma_stride == yuv420_image.luma_stride) {
- memcpy(y_dst, y_src, yuv420_bt601_image.luma_stride * yuv420_image.height);
- } else {
- for (size_t i = 0; i < yuv420_image.height; i++) {
- memcpy(y_dst, y_src, yuv420_image.width);
- if (yuv420_image.width != yuv420_bt601_image.luma_stride) {
- memset(y_dst + yuv420_image.width, 0,
- yuv420_bt601_image.luma_stride - yuv420_image.width);
- }
- y_dst += yuv420_bt601_image.luma_stride;
- y_src += yuv420_image.luma_stride;
- }
- }
- }
-
- if (yuv420_bt601_image.chroma_stride == yuv420_image.chroma_stride) {
- // copy luma
- uint8_t* ch_dst = reinterpret_cast<uint8_t*>(yuv420_bt601_image.chroma_data);
- uint8_t* ch_src = reinterpret_cast<uint8_t*>(yuv420_image.chroma_data);
- memcpy(ch_dst, ch_src, yuv420_bt601_image.chroma_stride * yuv420_image.height);
- } else {
- // copy cb & cr
- uint8_t* cb_dst = reinterpret_cast<uint8_t*>(yuv420_bt601_image.chroma_data);
- uint8_t* cb_src = reinterpret_cast<uint8_t*>(yuv420_image.chroma_data);
- uint8_t* cr_dst = cb_dst + (yuv420_bt601_image.chroma_stride * yuv420_bt601_image.height / 2);
- uint8_t* cr_src = cb_src + (yuv420_image.chroma_stride * yuv420_image.height / 2);
- for (size_t i = 0; i < yuv420_image.height / 2; i++) {
- memcpy(cb_dst, cb_src, yuv420_image.width / 2);
- memcpy(cr_dst, cr_src, yuv420_image.width / 2);
- if (yuv420_bt601_image.width / 2 != yuv420_bt601_image.chroma_stride) {
- memset(cb_dst + yuv420_image.width / 2, 0,
- yuv420_bt601_image.chroma_stride - yuv420_image.width / 2);
- memset(cr_dst + yuv420_image.width / 2, 0,
- yuv420_bt601_image.chroma_stride - yuv420_image.width / 2);
- }
- cb_dst += yuv420_bt601_image.chroma_stride;
- cb_src += yuv420_image.chroma_stride;
- cr_dst += yuv420_bt601_image.chroma_stride;
- cr_src += yuv420_image.chroma_stride;
- }
- }
- JPEGR_CHECK(convertYuv(&yuv420_bt601_image, yuv420_image.colorGamut, ULTRAHDR_COLORGAMUT_P3));
- }
-
- // compress 420 image
- JpegEncoderHelper jpeg_enc_obj_yuv420;
- if (!jpeg_enc_obj_yuv420.compressImage(reinterpret_cast<uint8_t*>(yuv420_bt601_image.data),
- reinterpret_cast<uint8_t*>(yuv420_bt601_image.chroma_data),
- yuv420_bt601_image.width, yuv420_bt601_image.height,
- yuv420_bt601_image.luma_stride,
- yuv420_bt601_image.chroma_stride, quality, icc->getData(),
- icc->getLength())) {
- return ERROR_JPEGR_ENCODE_ERROR;
- }
-
- jpegr_compressed_struct jpeg = {.data = jpeg_enc_obj_yuv420.getCompressedImagePtr(),
- .length = static_cast<int>(
- jpeg_enc_obj_yuv420.getCompressedImageSize()),
- .maxLength = static_cast<int>(
- jpeg_enc_obj_yuv420.getCompressedImageSize()),
- .colorGamut = yuv420_image.colorGamut};
-
- // append gain map, no ICC since JPEG encode already did it
- JPEGR_CHECK(appendGainMap(&jpeg, &compressed_map, exif, /* icc */ nullptr, /* icc size */ 0,
- &metadata, dest));
- return NO_ERROR;
-}
-
-/* Encode API-2 */
-status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr,
- jr_uncompressed_ptr yuv420_image_ptr,
- jr_compressed_ptr yuv420jpg_image_ptr,
- ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest) {
- // validate input arguments
- if (yuv420_image_ptr == nullptr) {
- ALOGE("received nullptr for uncompressed 420 image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (yuv420jpg_image_ptr == nullptr || yuv420jpg_image_ptr->data == nullptr) {
- ALOGE("received nullptr for compressed jpeg image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (auto ret = areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest);
- ret != NO_ERROR) {
- return ret;
- }
-
- // clean up input structure for later usage
- jpegr_uncompressed_struct p010_image = *p010_image_ptr;
- if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width;
- if (!p010_image.chroma_data) {
- uint16_t* data = reinterpret_cast<uint16_t*>(p010_image.data);
- p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height;
- p010_image.chroma_stride = p010_image.luma_stride;
- }
- jpegr_uncompressed_struct yuv420_image = *yuv420_image_ptr;
- if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width;
- if (!yuv420_image.chroma_data) {
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data);
- yuv420_image.chroma_data = data + yuv420_image.luma_stride * p010_image.height;
- yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1;
- }
-
- // gain map
- ultrahdr_metadata_struct metadata = {.version = kJpegrVersion};
- jpegr_uncompressed_struct gainmap_image;
- JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image));
- std::unique_ptr<uint8_t[]> map_data;
- map_data.reset(reinterpret_cast<uint8_t*>(gainmap_image.data));
-
- // compress gain map
- JpegEncoderHelper jpeg_enc_obj_gm;
- JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm));
- jpegr_compressed_struct gainmapjpg_image = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(),
- .length = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .maxLength = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
-
- return encodeJPEGR(yuv420jpg_image_ptr, &gainmapjpg_image, &metadata, dest);
-}
-
-/* Encode API-3 */
-status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr,
- jr_compressed_ptr yuv420jpg_image_ptr,
- ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest) {
- // validate input arguments
- if (yuv420jpg_image_ptr == nullptr || yuv420jpg_image_ptr->data == nullptr) {
- ALOGE("received nullptr for compressed jpeg image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (auto ret = areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest); ret != NO_ERROR) {
- return ret;
- }
-
- // clean up input structure for later usage
- jpegr_uncompressed_struct p010_image = *p010_image_ptr;
- if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width;
- if (!p010_image.chroma_data) {
- uint16_t* data = reinterpret_cast<uint16_t*>(p010_image.data);
- p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height;
- p010_image.chroma_stride = p010_image.luma_stride;
- }
-
- // decode input jpeg, gamut is going to be bt601.
- JpegDecoderHelper jpeg_dec_obj_yuv420;
- if (!jpeg_dec_obj_yuv420.decompressImage(yuv420jpg_image_ptr->data,
- yuv420jpg_image_ptr->length)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
- jpegr_uncompressed_struct yuv420_image{};
- yuv420_image.data = jpeg_dec_obj_yuv420.getDecompressedImagePtr();
- yuv420_image.width = jpeg_dec_obj_yuv420.getDecompressedImageWidth();
- yuv420_image.height = jpeg_dec_obj_yuv420.getDecompressedImageHeight();
- yuv420_image.colorGamut = yuv420jpg_image_ptr->colorGamut;
- if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width;
- if (!yuv420_image.chroma_data) {
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data);
- yuv420_image.chroma_data = data + yuv420_image.luma_stride * p010_image.height;
- yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1;
- }
-
- if (p010_image_ptr->width != yuv420_image.width ||
- p010_image_ptr->height != yuv420_image.height) {
- return ERROR_JPEGR_RESOLUTION_MISMATCH;
- }
-
- // gain map
- ultrahdr_metadata_struct metadata = {.version = kJpegrVersion};
- jpegr_uncompressed_struct gainmap_image;
- JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image,
- true /* sdr_is_601 */));
- std::unique_ptr<uint8_t[]> map_data;
- map_data.reset(reinterpret_cast<uint8_t*>(gainmap_image.data));
-
- // compress gain map
- JpegEncoderHelper jpeg_enc_obj_gm;
- JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm));
- jpegr_compressed_struct gainmapjpg_image = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(),
- .length = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .maxLength = static_cast<int>(
- jpeg_enc_obj_gm.getCompressedImageSize()),
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
-
- return encodeJPEGR(yuv420jpg_image_ptr, &gainmapjpg_image, &metadata, dest);
-}
-
-/* Encode API-4 */
-status_t JpegR::encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr,
- jr_compressed_ptr gainmapjpg_image_ptr, ultrahdr_metadata_ptr metadata,
- jr_compressed_ptr dest) {
- if (yuv420jpg_image_ptr == nullptr || yuv420jpg_image_ptr->data == nullptr) {
- ALOGE("received nullptr for compressed jpeg image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (gainmapjpg_image_ptr == nullptr || gainmapjpg_image_ptr->data == nullptr) {
- ALOGE("received nullptr for compressed gain map");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (dest == nullptr || dest->data == nullptr) {
- ALOGE("received nullptr for destination");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
-
- // We just want to check if ICC is present, so don't do a full decode. Note,
- // this doesn't verify that the ICC is valid.
- JpegDecoderHelper decoder;
- std::vector<uint8_t> icc;
- decoder.getCompressedImageParameters(yuv420jpg_image_ptr->data, yuv420jpg_image_ptr->length,
- /* pWidth */ nullptr, /* pHeight */ nullptr, &icc,
- /* exifData */ nullptr);
-
- // Add ICC if not already present.
- if (icc.size() > 0) {
- JPEGR_CHECK(appendGainMap(yuv420jpg_image_ptr, gainmapjpg_image_ptr, /* exif */ nullptr,
- /* icc */ nullptr, /* icc size */ 0, metadata, dest));
- } else {
- sp<DataStruct> newIcc =
- IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420jpg_image_ptr->colorGamut);
- JPEGR_CHECK(appendGainMap(yuv420jpg_image_ptr, gainmapjpg_image_ptr, /* exif */ nullptr,
- newIcc->getData(), newIcc->getLength(), metadata, dest));
- }
-
- return NO_ERROR;
-}
-
-status_t JpegR::getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg_image_info_ptr) {
- if (jpegr_image_ptr == nullptr || jpegr_image_ptr->data == nullptr) {
- ALOGE("received nullptr for compressed jpegr image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (jpeg_image_info_ptr == nullptr) {
- ALOGE("received nullptr for compressed jpegr info struct");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
-
- jpegr_compressed_struct primary_image, gainmap_image;
- status_t status = extractPrimaryImageAndGainMap(jpegr_image_ptr, &primary_image, &gainmap_image);
- if (status != NO_ERROR && status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) {
- return status;
- }
-
- JpegDecoderHelper jpeg_dec_obj_hdr;
- if (!jpeg_dec_obj_hdr.getCompressedImageParameters(primary_image.data, primary_image.length,
- &jpeg_image_info_ptr->width,
- &jpeg_image_info_ptr->height,
- jpeg_image_info_ptr->iccData,
- jpeg_image_info_ptr->exifData)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
-
- return status;
-}
-
-/* Decode API */
-status_t JpegR::decodeJPEGR(jr_compressed_ptr jpegr_image_ptr, jr_uncompressed_ptr dest,
- float max_display_boost, jr_exif_ptr exif,
- ultrahdr_output_format output_format,
- jr_uncompressed_ptr gainmap_image_ptr, ultrahdr_metadata_ptr metadata) {
- if (jpegr_image_ptr == nullptr || jpegr_image_ptr->data == nullptr) {
- ALOGE("received nullptr for compressed jpegr image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (dest == nullptr || dest->data == nullptr) {
- ALOGE("received nullptr for dest image");
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (max_display_boost < 1.0f) {
- ALOGE("received bad value for max_display_boost %f", max_display_boost);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (exif != nullptr && exif->data == nullptr) {
- ALOGE("received nullptr address for exif data");
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (output_format <= ULTRAHDR_OUTPUT_UNSPECIFIED || output_format > ULTRAHDR_OUTPUT_MAX) {
- ALOGE("received bad value for output format %d", output_format);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
- jpegr_compressed_struct primary_jpeg_image, gainmap_jpeg_image;
- status_t status =
- extractPrimaryImageAndGainMap(jpegr_image_ptr, &primary_jpeg_image, &gainmap_jpeg_image);
- if (status != NO_ERROR) {
- if (output_format != ULTRAHDR_OUTPUT_SDR || status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) {
- ALOGE("received invalid compressed jpegr image");
- return status;
- }
- }
-
- JpegDecoderHelper jpeg_dec_obj_yuv420;
- if (!jpeg_dec_obj_yuv420.decompressImage(primary_jpeg_image.data, primary_jpeg_image.length,
- (output_format == ULTRAHDR_OUTPUT_SDR))) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
-
- if (output_format == ULTRAHDR_OUTPUT_SDR) {
- if ((jpeg_dec_obj_yuv420.getDecompressedImageWidth() *
- jpeg_dec_obj_yuv420.getDecompressedImageHeight() * 4) >
- jpeg_dec_obj_yuv420.getDecompressedImageSize()) {
- return ERROR_JPEGR_CALCULATION_ERROR;
- }
- } else {
- if ((jpeg_dec_obj_yuv420.getDecompressedImageWidth() *
- jpeg_dec_obj_yuv420.getDecompressedImageHeight() * 3 / 2) >
- jpeg_dec_obj_yuv420.getDecompressedImageSize()) {
- return ERROR_JPEGR_CALCULATION_ERROR;
- }
- }
-
- if (exif != nullptr) {
- if (exif->data == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (exif->length < jpeg_dec_obj_yuv420.getEXIFSize()) {
- return ERROR_JPEGR_BUFFER_TOO_SMALL;
- }
- memcpy(exif->data, jpeg_dec_obj_yuv420.getEXIFPtr(), jpeg_dec_obj_yuv420.getEXIFSize());
- exif->length = jpeg_dec_obj_yuv420.getEXIFSize();
- }
-
- if (output_format == ULTRAHDR_OUTPUT_SDR) {
- dest->width = jpeg_dec_obj_yuv420.getDecompressedImageWidth();
- dest->height = jpeg_dec_obj_yuv420.getDecompressedImageHeight();
- memcpy(dest->data, jpeg_dec_obj_yuv420.getDecompressedImagePtr(),
- dest->width * dest->height * 4);
- return NO_ERROR;
- }
-
- JpegDecoderHelper jpeg_dec_obj_gm;
- if (!jpeg_dec_obj_gm.decompressImage(gainmap_jpeg_image.data, gainmap_jpeg_image.length)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
- if ((jpeg_dec_obj_gm.getDecompressedImageWidth() * jpeg_dec_obj_gm.getDecompressedImageHeight()) >
- jpeg_dec_obj_gm.getDecompressedImageSize()) {
- return ERROR_JPEGR_CALCULATION_ERROR;
- }
-
- jpegr_uncompressed_struct gainmap_image;
- gainmap_image.data = jpeg_dec_obj_gm.getDecompressedImagePtr();
- gainmap_image.width = jpeg_dec_obj_gm.getDecompressedImageWidth();
- gainmap_image.height = jpeg_dec_obj_gm.getDecompressedImageHeight();
-
- if (gainmap_image_ptr != nullptr) {
- gainmap_image_ptr->width = gainmap_image.width;
- gainmap_image_ptr->height = gainmap_image.height;
- int size = gainmap_image_ptr->width * gainmap_image_ptr->height;
- gainmap_image_ptr->data = malloc(size);
- memcpy(gainmap_image_ptr->data, gainmap_image.data, size);
- }
-
- ultrahdr_metadata_struct uhdr_metadata;
- if (!getMetadataFromXMP(static_cast<uint8_t*>(jpeg_dec_obj_gm.getXMPPtr()),
- jpeg_dec_obj_gm.getXMPSize(), &uhdr_metadata)) {
- return ERROR_JPEGR_INVALID_METADATA;
- }
-
- if (metadata != nullptr) {
- metadata->version = uhdr_metadata.version;
- metadata->minContentBoost = uhdr_metadata.minContentBoost;
- metadata->maxContentBoost = uhdr_metadata.maxContentBoost;
- metadata->gamma = uhdr_metadata.gamma;
- metadata->offsetSdr = uhdr_metadata.offsetSdr;
- metadata->offsetHdr = uhdr_metadata.offsetHdr;
- metadata->hdrCapacityMin = uhdr_metadata.hdrCapacityMin;
- metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax;
- }
-
- jpegr_uncompressed_struct yuv420_image;
- yuv420_image.data = jpeg_dec_obj_yuv420.getDecompressedImagePtr();
- yuv420_image.width = jpeg_dec_obj_yuv420.getDecompressedImageWidth();
- yuv420_image.height = jpeg_dec_obj_yuv420.getDecompressedImageHeight();
- yuv420_image.colorGamut = IccHelper::readIccColorGamut(jpeg_dec_obj_yuv420.getICCPtr(),
- jpeg_dec_obj_yuv420.getICCSize());
- yuv420_image.luma_stride = yuv420_image.width;
- uint8_t* data = reinterpret_cast<uint8_t*>(yuv420_image.data);
- yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height;
- yuv420_image.chroma_stride = yuv420_image.width >> 1;
-
- JPEGR_CHECK(applyGainMap(&yuv420_image, &gainmap_image, &uhdr_metadata, output_format,
- max_display_boost, dest));
- return NO_ERROR;
-}
-
-status_t JpegR::compressGainMap(jr_uncompressed_ptr gainmap_image_ptr,
- JpegEncoderHelper* jpeg_enc_obj_ptr) {
- if (gainmap_image_ptr == nullptr || jpeg_enc_obj_ptr == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
-
- // Don't need to convert YUV to Bt601 since single channel
- if (!jpeg_enc_obj_ptr->compressImage(reinterpret_cast<uint8_t*>(gainmap_image_ptr->data), nullptr,
- gainmap_image_ptr->width, gainmap_image_ptr->height,
- gainmap_image_ptr->luma_stride, 0, kMapCompressQuality,
- nullptr, 0)) {
- return ERROR_JPEGR_ENCODE_ERROR;
- }
-
- return NO_ERROR;
-}
-
-const int kJobSzInRows = 16;
-static_assert(kJobSzInRows > 0 && kJobSzInRows % kMapDimensionScaleFactor == 0,
- "align job size to kMapDimensionScaleFactor");
-
-class JobQueue {
-public:
- bool dequeueJob(size_t& rowStart, size_t& rowEnd);
- void enqueueJob(size_t rowStart, size_t rowEnd);
- void markQueueForEnd();
- void reset();
-
-private:
- bool mQueuedAllJobs = false;
- std::deque<std::tuple<size_t, size_t>> mJobs;
- std::mutex mMutex;
- std::condition_variable mCv;
-};
-
-bool JobQueue::dequeueJob(size_t& rowStart, size_t& rowEnd) {
- std::unique_lock<std::mutex> lock{mMutex};
- while (true) {
- if (mJobs.empty()) {
- if (mQueuedAllJobs) {
- return false;
- } else {
- mCv.wait_for(lock, std::chrono::milliseconds(100));
- }
- } else {
- auto it = mJobs.begin();
- rowStart = std::get<0>(*it);
- rowEnd = std::get<1>(*it);
- mJobs.erase(it);
- return true;
- }
- }
- return false;
-}
-
-void JobQueue::enqueueJob(size_t rowStart, size_t rowEnd) {
- std::unique_lock<std::mutex> lock{mMutex};
- mJobs.push_back(std::make_tuple(rowStart, rowEnd));
- lock.unlock();
- mCv.notify_one();
-}
-
-void JobQueue::markQueueForEnd() {
- std::unique_lock<std::mutex> lock{mMutex};
- mQueuedAllJobs = true;
- lock.unlock();
- mCv.notify_all();
-}
-
-void JobQueue::reset() {
- std::unique_lock<std::mutex> lock{mMutex};
- mJobs.clear();
- mQueuedAllJobs = false;
-}
-
-status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr,
- jr_uncompressed_ptr p010_image_ptr,
- ultrahdr_transfer_function hdr_tf, ultrahdr_metadata_ptr metadata,
- jr_uncompressed_ptr dest, bool sdr_is_601) {
- if (yuv420_image_ptr == nullptr || p010_image_ptr == nullptr || metadata == nullptr ||
- dest == nullptr || yuv420_image_ptr->data == nullptr ||
- yuv420_image_ptr->chroma_data == nullptr || p010_image_ptr->data == nullptr ||
- p010_image_ptr->chroma_data == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (yuv420_image_ptr->width != p010_image_ptr->width ||
- yuv420_image_ptr->height != p010_image_ptr->height) {
- return ERROR_JPEGR_RESOLUTION_MISMATCH;
- }
- if (yuv420_image_ptr->colorGamut == ULTRAHDR_COLORGAMUT_UNSPECIFIED ||
- p010_image_ptr->colorGamut == ULTRAHDR_COLORGAMUT_UNSPECIFIED) {
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
-
- size_t image_width = yuv420_image_ptr->width;
- size_t image_height = yuv420_image_ptr->height;
- size_t map_width = image_width / kMapDimensionScaleFactor;
- size_t map_height = image_height / kMapDimensionScaleFactor;
-
- dest->data = new uint8_t[map_width * map_height];
- dest->width = map_width;
- dest->height = map_height;
- dest->colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- dest->luma_stride = map_width;
- dest->chroma_data = nullptr;
- dest->chroma_stride = 0;
- std::unique_ptr<uint8_t[]> map_data;
- map_data.reset(reinterpret_cast<uint8_t*>(dest->data));
-
- ColorTransformFn hdrInvOetf = nullptr;
- float hdr_white_nits;
- switch (hdr_tf) {
- case ULTRAHDR_TF_LINEAR:
- hdrInvOetf = identityConversion;
- // Note: this will produce clipping if the input exceeds kHlgMaxNits.
- // TODO: TF LINEAR will be deprecated.
- hdr_white_nits = kHlgMaxNits;
- break;
- case ULTRAHDR_TF_HLG:
-#if USE_HLG_INVOETF_LUT
- hdrInvOetf = hlgInvOetfLUT;
-#else
- hdrInvOetf = hlgInvOetf;
-#endif
- hdr_white_nits = kHlgMaxNits;
- break;
- case ULTRAHDR_TF_PQ:
-#if USE_PQ_INVOETF_LUT
- hdrInvOetf = pqInvOetfLUT;
-#else
- hdrInvOetf = pqInvOetf;
-#endif
- hdr_white_nits = kPqMaxNits;
- break;
- default:
- // Should be impossible to hit after input validation.
- return ERROR_JPEGR_INVALID_TRANS_FUNC;
- }
-
- metadata->maxContentBoost = hdr_white_nits / kSdrWhiteNits;
- metadata->minContentBoost = 1.0f;
- metadata->gamma = 1.0f;
- metadata->offsetSdr = 0.0f;
- metadata->offsetHdr = 0.0f;
- metadata->hdrCapacityMin = 1.0f;
- metadata->hdrCapacityMax = metadata->maxContentBoost;
-
- float log2MinBoost = log2(metadata->minContentBoost);
- float log2MaxBoost = log2(metadata->maxContentBoost);
-
- ColorTransformFn hdrGamutConversionFn =
- getHdrConversionFn(yuv420_image_ptr->colorGamut, p010_image_ptr->colorGamut);
-
- ColorCalculationFn luminanceFn = nullptr;
- ColorTransformFn sdrYuvToRgbFn = nullptr;
- switch (yuv420_image_ptr->colorGamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- luminanceFn = srgbLuminance;
- sdrYuvToRgbFn = srgbYuvToRgb;
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- luminanceFn = p3Luminance;
- sdrYuvToRgbFn = p3YuvToRgb;
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- luminanceFn = bt2100Luminance;
- sdrYuvToRgbFn = bt2100YuvToRgb;
- break;
- case ULTRAHDR_COLORGAMUT_UNSPECIFIED:
- // Should be impossible to hit after input validation.
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
- if (sdr_is_601) {
- sdrYuvToRgbFn = p3YuvToRgb;
- }
-
- ColorTransformFn hdrYuvToRgbFn = nullptr;
- switch (p010_image_ptr->colorGamut) {
- case ULTRAHDR_COLORGAMUT_BT709:
- hdrYuvToRgbFn = srgbYuvToRgb;
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- hdrYuvToRgbFn = p3YuvToRgb;
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- hdrYuvToRgbFn = bt2100YuvToRgb;
- break;
- case ULTRAHDR_COLORGAMUT_UNSPECIFIED:
- // Should be impossible to hit after input validation.
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
-
- std::mutex mutex;
- const int threads = std::clamp(GetCPUCoreCount(), 1, 4);
- size_t rowStep = threads == 1 ? image_height : kJobSzInRows;
- JobQueue jobQueue;
-
- std::function<void()> generateMap = [yuv420_image_ptr, p010_image_ptr, metadata, dest, hdrInvOetf,
- hdrGamutConversionFn, luminanceFn, sdrYuvToRgbFn,
- hdrYuvToRgbFn, hdr_white_nits, log2MinBoost, log2MaxBoost,
- &jobQueue]() -> void {
- size_t rowStart, rowEnd;
- while (jobQueue.dequeueJob(rowStart, rowEnd)) {
- for (size_t y = rowStart; y < rowEnd; ++y) {
- for (size_t x = 0; x < dest->width; ++x) {
- Color sdr_yuv_gamma = sampleYuv420(yuv420_image_ptr, kMapDimensionScaleFactor, x, y);
- Color sdr_rgb_gamma = sdrYuvToRgbFn(sdr_yuv_gamma);
- // We are assuming the SDR input is always sRGB transfer.
-#if USE_SRGB_INVOETF_LUT
- Color sdr_rgb = srgbInvOetfLUT(sdr_rgb_gamma);
-#else
- Color sdr_rgb = srgbInvOetf(sdr_rgb_gamma);
-#endif
- float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits;
-
- Color hdr_yuv_gamma = sampleP010(p010_image_ptr, kMapDimensionScaleFactor, x, y);
- Color hdr_rgb_gamma = hdrYuvToRgbFn(hdr_yuv_gamma);
- Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma);
- hdr_rgb = hdrGamutConversionFn(hdr_rgb);
- float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits;
-
- size_t pixel_idx = x + y * dest->width;
- reinterpret_cast<uint8_t*>(dest->data)[pixel_idx] =
- encodeGain(sdr_y_nits, hdr_y_nits, metadata, log2MinBoost, log2MaxBoost);
- }
- }
- }
- };
-
- // generate map
- std::vector<std::thread> workers;
- for (int th = 0; th < threads - 1; th++) {
- workers.push_back(std::thread(generateMap));
- }
-
- rowStep = (threads == 1 ? image_height : kJobSzInRows) / kMapDimensionScaleFactor;
- for (size_t rowStart = 0; rowStart < map_height;) {
- size_t rowEnd = std::min(rowStart + rowStep, map_height);
- jobQueue.enqueueJob(rowStart, rowEnd);
- rowStart = rowEnd;
- }
- jobQueue.markQueueForEnd();
- generateMap();
- std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
-
- map_data.release();
- return NO_ERROR;
-}
-
-status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr,
- jr_uncompressed_ptr gainmap_image_ptr, ultrahdr_metadata_ptr metadata,
- ultrahdr_output_format output_format, float max_display_boost,
- jr_uncompressed_ptr dest) {
- if (yuv420_image_ptr == nullptr || gainmap_image_ptr == nullptr || metadata == nullptr ||
- dest == nullptr || yuv420_image_ptr->data == nullptr ||
- yuv420_image_ptr->chroma_data == nullptr || gainmap_image_ptr->data == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (metadata->version.compare(kJpegrVersion)) {
- ALOGE("Unsupported metadata version: %s", metadata->version.c_str());
- return ERROR_JPEGR_UNSUPPORTED_METADATA;
- }
- if (metadata->gamma != 1.0f) {
- ALOGE("Unsupported metadata gamma: %f", metadata->gamma);
- return ERROR_JPEGR_UNSUPPORTED_METADATA;
- }
- if (metadata->offsetSdr != 0.0f || metadata->offsetHdr != 0.0f) {
- ALOGE("Unsupported metadata offset sdr, hdr: %f, %f", metadata->offsetSdr, metadata->offsetHdr);
- return ERROR_JPEGR_UNSUPPORTED_METADATA;
- }
- if (metadata->hdrCapacityMin != metadata->minContentBoost ||
- metadata->hdrCapacityMax != metadata->maxContentBoost) {
- ALOGE("Unsupported metadata hdr capacity min, max: %f, %f", metadata->hdrCapacityMin,
- metadata->hdrCapacityMax);
- return ERROR_JPEGR_UNSUPPORTED_METADATA;
- }
-
- // TODO: remove once map scaling factor is computed based on actual map dims
- size_t image_width = yuv420_image_ptr->width;
- size_t image_height = yuv420_image_ptr->height;
- size_t map_width = image_width / kMapDimensionScaleFactor;
- size_t map_height = image_height / kMapDimensionScaleFactor;
- if (map_width != gainmap_image_ptr->width || map_height != gainmap_image_ptr->height) {
- ALOGE("gain map dimensions and primary image dimensions are not to scale, computed gain map "
- "resolution is %dx%d, received gain map resolution is %dx%d",
- (int)map_width, (int)map_height, gainmap_image_ptr->width, gainmap_image_ptr->height);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
- dest->width = yuv420_image_ptr->width;
- dest->height = yuv420_image_ptr->height;
- ShepardsIDW idwTable(kMapDimensionScaleFactor);
- float display_boost = std::min(max_display_boost, metadata->maxContentBoost);
- GainLUT gainLUT(metadata, display_boost);
-
- JobQueue jobQueue;
- std::function<void()> applyRecMap = [yuv420_image_ptr, gainmap_image_ptr, metadata, dest,
- &jobQueue, &idwTable, output_format, &gainLUT,
- display_boost]() -> void {
- size_t width = yuv420_image_ptr->width;
- size_t height = yuv420_image_ptr->height;
-
- size_t rowStart, rowEnd;
- while (jobQueue.dequeueJob(rowStart, rowEnd)) {
- for (size_t y = rowStart; y < rowEnd; ++y) {
- for (size_t x = 0; x < width; ++x) {
- Color yuv_gamma_sdr = getYuv420Pixel(yuv420_image_ptr, x, y);
- // Assuming the sdr image is a decoded JPEG, we should always use Rec.601 YUV coefficients
- Color rgb_gamma_sdr = p3YuvToRgb(yuv_gamma_sdr);
- // We are assuming the SDR base image is always sRGB transfer.
-#if USE_SRGB_INVOETF_LUT
- Color rgb_sdr = srgbInvOetfLUT(rgb_gamma_sdr);
-#else
- Color rgb_sdr = srgbInvOetf(rgb_gamma_sdr);
-#endif
- float gain;
- // TODO: determine map scaling factor based on actual map dims
- size_t map_scale_factor = kMapDimensionScaleFactor;
- // TODO: If map_scale_factor is guaranteed to be an integer, then remove the following.
- // Currently map_scale_factor is of type size_t, but it could be changed to a float
- // later.
- if (map_scale_factor != floorf(map_scale_factor)) {
- gain = sampleMap(gainmap_image_ptr, map_scale_factor, x, y);
- } else {
- gain = sampleMap(gainmap_image_ptr, map_scale_factor, x, y, idwTable);
- }
-
-#if USE_APPLY_GAIN_LUT
- Color rgb_hdr = applyGainLUT(rgb_sdr, gain, gainLUT);
-#else
- Color rgb_hdr = applyGain(rgb_sdr, gain, metadata, display_boost);
-#endif
- rgb_hdr = rgb_hdr / display_boost;
- size_t pixel_idx = x + y * width;
-
- switch (output_format) {
- case ULTRAHDR_OUTPUT_HDR_LINEAR: {
- uint64_t rgba_f16 = colorToRgbaF16(rgb_hdr);
- reinterpret_cast<uint64_t*>(dest->data)[pixel_idx] = rgba_f16;
- break;
- }
- case ULTRAHDR_OUTPUT_HDR_HLG: {
-#if USE_HLG_OETF_LUT
- ColorTransformFn hdrOetf = hlgOetfLUT;
-#else
- ColorTransformFn hdrOetf = hlgOetf;
-#endif
- Color rgb_gamma_hdr = hdrOetf(rgb_hdr);
- uint32_t rgba_1010102 = colorToRgba1010102(rgb_gamma_hdr);
- reinterpret_cast<uint32_t*>(dest->data)[pixel_idx] = rgba_1010102;
- break;
- }
- case ULTRAHDR_OUTPUT_HDR_PQ: {
-#if USE_PQ_OETF_LUT
- ColorTransformFn hdrOetf = pqOetfLUT;
-#else
- ColorTransformFn hdrOetf = pqOetf;
-#endif
- Color rgb_gamma_hdr = hdrOetf(rgb_hdr);
- uint32_t rgba_1010102 = colorToRgba1010102(rgb_gamma_hdr);
- reinterpret_cast<uint32_t*>(dest->data)[pixel_idx] = rgba_1010102;
- break;
- }
- default: {
- }
- // Should be impossible to hit after input validation.
- }
- }
- }
- }
- };
-
- const int threads = std::clamp(GetCPUCoreCount(), 1, 4);
- std::vector<std::thread> workers;
- for (int th = 0; th < threads - 1; th++) {
- workers.push_back(std::thread(applyRecMap));
- }
- const int rowStep = threads == 1 ? yuv420_image_ptr->height : kJobSzInRows;
- for (int rowStart = 0; rowStart < yuv420_image_ptr->height;) {
- int rowEnd = std::min(rowStart + rowStep, yuv420_image_ptr->height);
- jobQueue.enqueueJob(rowStart, rowEnd);
- rowStart = rowEnd;
- }
- jobQueue.markQueueForEnd();
- applyRecMap();
- std::for_each(workers.begin(), workers.end(), [](std::thread& t) { t.join(); });
- return NO_ERROR;
-}
-
-status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr,
- jr_compressed_ptr primary_jpg_image_ptr,
- jr_compressed_ptr gainmap_jpg_image_ptr) {
- if (jpegr_image_ptr == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
-
- MessageHandler msg_handler;
- std::shared_ptr<DataSegment> seg =
- DataSegment::Create(DataRange(0, jpegr_image_ptr->length),
- static_cast<const uint8_t*>(jpegr_image_ptr->data),
- DataSegment::BufferDispositionPolicy::kDontDelete);
- DataSegmentDataSource data_source(seg);
- JpegInfoBuilder jpeg_info_builder;
- jpeg_info_builder.SetImageLimit(2);
- JpegScanner jpeg_scanner(&msg_handler);
- jpeg_scanner.Run(&data_source, &jpeg_info_builder);
- data_source.Reset();
-
- if (jpeg_scanner.HasError()) {
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
- const auto& jpeg_info = jpeg_info_builder.GetInfo();
- const auto& image_ranges = jpeg_info.GetImageRanges();
-
- if (image_ranges.empty()) {
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
- if (primary_jpg_image_ptr != nullptr) {
- primary_jpg_image_ptr->data =
- static_cast<uint8_t*>(jpegr_image_ptr->data) + image_ranges[0].GetBegin();
- primary_jpg_image_ptr->length = image_ranges[0].GetLength();
- }
-
- if (image_ranges.size() == 1) {
- return ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND;
- }
-
- if (gainmap_jpg_image_ptr != nullptr) {
- gainmap_jpg_image_ptr->data =
- static_cast<uint8_t*>(jpegr_image_ptr->data) + image_ranges[1].GetBegin();
- gainmap_jpg_image_ptr->length = image_ranges[1].GetLength();
- }
-
- // TODO: choose primary image and gain map image carefully
- if (image_ranges.size() > 2) {
- ALOGW("Number of jpeg images present %d, primary, gain map images may not be correctly chosen",
- (int)image_ranges.size());
- }
-
- return NO_ERROR;
-}
-
-// JPEG/R structure:
-// SOI (ff d8)
-//
-// (Optional, if EXIF package is from outside (Encode API-0 API-1), or if EXIF package presents
-// in the JPEG input (Encode API-2, API-3, API-4))
-// APP1 (ff e1)
-// 2 bytes of length (2 + length of exif package)
-// EXIF package (this includes the first two bytes representing the package length)
-//
-// (Required, XMP package) APP1 (ff e1)
-// 2 bytes of length (2 + 29 + length of xmp package)
-// name space ("http://ns.adobe.com/xap/1.0/\0")
-// XMP
-//
-// (Required, MPF package) APP2 (ff e2)
-// 2 bytes of length
-// MPF
-//
-// (Required) primary image (without the first two bytes (SOI) and EXIF, may have other packages)
-//
-// SOI (ff d8)
-//
-// (Required, XMP package) APP1 (ff e1)
-// 2 bytes of length (2 + 29 + length of xmp package)
-// name space ("http://ns.adobe.com/xap/1.0/\0")
-// XMP
-//
-// (Required) secondary image (the gain map, without the first two bytes (SOI))
-//
-// Metadata versions we are using:
-// ECMA TR-98 for JFIF marker
-// Exif 2.2 spec for EXIF marker
-// Adobe XMP spec part 3 for XMP marker
-// ICC v4.3 spec for ICC
-status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr,
- jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr pExif,
- void* pIcc, size_t icc_size, ultrahdr_metadata_ptr metadata,
- jr_compressed_ptr dest) {
- if (primary_jpg_image_ptr == nullptr || gainmap_jpg_image_ptr == nullptr || metadata == nullptr ||
- dest == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (metadata->version.compare("1.0")) {
- ALOGE("received bad value for version: %s", metadata->version.c_str());
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (metadata->maxContentBoost < metadata->minContentBoost) {
- ALOGE("received bad value for content boost min %f, max %f", metadata->minContentBoost,
- metadata->maxContentBoost);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (metadata->hdrCapacityMax < metadata->hdrCapacityMin || metadata->hdrCapacityMin < 1.0f) {
- ALOGE("received bad value for hdr capacity min %f, max %f", metadata->hdrCapacityMin,
- metadata->hdrCapacityMax);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (metadata->offsetSdr < 0.0f || metadata->offsetHdr < 0.0f) {
- ALOGE("received bad value for offset sdr %f, hdr %f", metadata->offsetSdr, metadata->offsetHdr);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- if (metadata->gamma <= 0.0f) {
- ALOGE("received bad value for gamma %f", metadata->gamma);
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
-
- const string nameSpace = "http://ns.adobe.com/xap/1.0/";
- const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator
-
- // calculate secondary image length first, because the length will be written into the primary
- // image xmp
- const string xmp_secondary = generateXmpForSecondaryImage(*metadata);
- const int xmp_secondary_length = 2 /* 2 bytes representing the length of the package */
- + nameSpaceLength /* 29 bytes length of name space including \0 */
- + xmp_secondary.size(); /* length of xmp packet */
- const int secondary_image_size = 2 /* 2 bytes length of APP1 sign */
- + xmp_secondary_length + gainmap_jpg_image_ptr->length;
- // primary image
- const string xmp_primary = generateXmpForPrimaryImage(secondary_image_size, *metadata);
- // same as primary
- const int xmp_primary_length = 2 + nameSpaceLength + xmp_primary.size();
-
- // Check if EXIF package presents in the JPEG input.
- // If so, extract and remove the EXIF package.
- JpegDecoderHelper decoder;
- if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) {
- return ERROR_JPEGR_DECODE_ERROR;
- }
- jpegr_exif_struct exif_from_jpg = {.data = nullptr, .length = 0};
- jpegr_compressed_struct new_jpg_image = {.data = nullptr,
- .length = 0,
- .maxLength = 0,
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
- std::unique_ptr<uint8_t[]> dest_data;
- if (decoder.getEXIFPos() >= 0) {
- if (pExif != nullptr) {
- ALOGE("received EXIF from outside while the primary image already contains EXIF");
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- copyJpegWithoutExif(&new_jpg_image,
- primary_jpg_image_ptr,
- decoder.getEXIFPos(),
- decoder.getEXIFSize());
- dest_data.reset(reinterpret_cast<uint8_t*>(new_jpg_image.data));
- exif_from_jpg.data = decoder.getEXIFPtr();
- exif_from_jpg.length = decoder.getEXIFSize();
- pExif = &exif_from_jpg;
- }
-
- jr_compressed_ptr final_primary_jpg_image_ptr =
- new_jpg_image.length == 0 ? primary_jpg_image_ptr : &new_jpg_image;
-
- int pos = 0;
- // Begin primary image
- // Write SOI
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos));
-
- // Write EXIF
- if (pExif != nullptr) {
- const int length = 2 + pExif->length;
- const uint8_t lengthH = ((length >> 8) & 0xff);
- const uint8_t lengthL = (length & 0xff);
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
- JPEGR_CHECK(Write(dest, pExif->data, pExif->length, pos));
- }
-
- // Prepare and write XMP
- {
- const int length = xmp_primary_length;
- const uint8_t lengthH = ((length >> 8) & 0xff);
- const uint8_t lengthL = (length & 0xff);
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
- JPEGR_CHECK(Write(dest, (void*)nameSpace.c_str(), nameSpaceLength, pos));
- JPEGR_CHECK(Write(dest, (void*)xmp_primary.c_str(), xmp_primary.size(), pos));
- }
-
- // Write ICC
- if (pIcc != nullptr && icc_size > 0) {
- const int length = icc_size + 2;
- const uint8_t lengthH = ((length >> 8) & 0xff);
- const uint8_t lengthL = (length & 0xff);
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
- JPEGR_CHECK(Write(dest, pIcc, icc_size, pos));
- }
-
- // Prepare and write MPF
- {
- const int length = 2 + calculateMpfSize();
- const uint8_t lengthH = ((length >> 8) & 0xff);
- const uint8_t lengthL = (length & 0xff);
- int primary_image_size = pos + length + final_primary_jpg_image_ptr->length;
- // between APP2 + package size + signature
- // ff e2 00 58 4d 50 46 00
- // 2 + 2 + 4 = 8 (bytes)
- // and ff d8 sign of the secondary image
- int secondary_image_offset = primary_image_size - pos - 8;
- sp<DataStruct> mpf = generateMpf(primary_image_size, 0, /* primary_image_offset */
- secondary_image_size, secondary_image_offset);
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
- JPEGR_CHECK(Write(dest, (void*)mpf->getData(), mpf->getLength(), pos));
- }
-
- // Write primary image
- JPEGR_CHECK(Write(dest, (uint8_t*)final_primary_jpg_image_ptr->data + 2,
- final_primary_jpg_image_ptr->length - 2, pos));
- // Finish primary image
-
- // Begin secondary image (gain map)
- // Write SOI
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos));
-
- // Prepare and write XMP
- {
- const int length = xmp_secondary_length;
- const uint8_t lengthH = ((length >> 8) & 0xff);
- const uint8_t lengthL = (length & 0xff);
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos));
- JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthH, 1, pos));
- JPEGR_CHECK(Write(dest, &lengthL, 1, pos));
- JPEGR_CHECK(Write(dest, (void*)nameSpace.c_str(), nameSpaceLength, pos));
- JPEGR_CHECK(Write(dest, (void*)xmp_secondary.c_str(), xmp_secondary.size(), pos));
- }
-
- // Write secondary image
- JPEGR_CHECK(Write(dest, (uint8_t*)gainmap_jpg_image_ptr->data + 2,
- gainmap_jpg_image_ptr->length - 2, pos));
-
- // Set back length
- dest->length = pos;
-
- // Done!
- return NO_ERROR;
-}
-
-status_t JpegR::toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest) {
- if (src == nullptr || dest == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (src->width != dest->width || src->height != dest->height) {
- return ERROR_JPEGR_INVALID_INPUT_TYPE;
- }
- uint16_t* src_y_data = reinterpret_cast<uint16_t*>(src->data);
- uint8_t* dst_y_data = reinterpret_cast<uint8_t*>(dest->data);
- for (size_t y = 0; y < src->height; ++y) {
- uint16_t* src_y_row = src_y_data + y * src->luma_stride;
- uint8_t* dst_y_row = dst_y_data + y * dest->luma_stride;
- for (size_t x = 0; x < src->width; ++x) {
- uint16_t y_uint = src_y_row[x] >> 6;
- dst_y_row[x] = static_cast<uint8_t>((y_uint >> 2) & 0xff);
- }
- if (dest->width != dest->luma_stride) {
- memset(dst_y_row + dest->width, 0, dest->luma_stride - dest->width);
- }
- }
- uint16_t* src_uv_data = reinterpret_cast<uint16_t*>(src->chroma_data);
- uint8_t* dst_u_data = reinterpret_cast<uint8_t*>(dest->chroma_data);
- size_t dst_v_offset = (dest->chroma_stride * dest->height / 2);
- uint8_t* dst_v_data = dst_u_data + dst_v_offset;
- for (size_t y = 0; y < src->height / 2; ++y) {
- uint16_t* src_uv_row = src_uv_data + y * src->chroma_stride;
- uint8_t* dst_u_row = dst_u_data + y * dest->chroma_stride;
- uint8_t* dst_v_row = dst_v_data + y * dest->chroma_stride;
- for (size_t x = 0; x < src->width / 2; ++x) {
- uint16_t u_uint = src_uv_row[x << 1] >> 6;
- uint16_t v_uint = src_uv_row[(x << 1) + 1] >> 6;
- dst_u_row[x] = static_cast<uint8_t>((u_uint >> 2) & 0xff);
- dst_v_row[x] = static_cast<uint8_t>((v_uint >> 2) & 0xff);
- }
- if (dest->width / 2 != dest->chroma_stride) {
- memset(dst_u_row + dest->width / 2, 0, dest->chroma_stride - dest->width / 2);
- memset(dst_v_row + dest->width / 2, 0, dest->chroma_stride - dest->width / 2);
- }
- }
- dest->colorGamut = src->colorGamut;
- return NO_ERROR;
-}
-
-status_t JpegR::convertYuv(jr_uncompressed_ptr image, ultrahdr_color_gamut src_encoding,
- ultrahdr_color_gamut dest_encoding) {
- if (image == nullptr) {
- return ERROR_JPEGR_INVALID_NULL_PTR;
- }
- if (src_encoding == ULTRAHDR_COLORGAMUT_UNSPECIFIED ||
- dest_encoding == ULTRAHDR_COLORGAMUT_UNSPECIFIED) {
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
-
- ColorTransformFn conversionFn = nullptr;
- switch (src_encoding) {
- case ULTRAHDR_COLORGAMUT_BT709:
- switch (dest_encoding) {
- case ULTRAHDR_COLORGAMUT_BT709:
- return NO_ERROR;
- case ULTRAHDR_COLORGAMUT_P3:
- conversionFn = yuv709To601;
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- conversionFn = yuv709To2100;
- break;
- default:
- // Should be impossible to hit after input validation
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- switch (dest_encoding) {
- case ULTRAHDR_COLORGAMUT_BT709:
- conversionFn = yuv601To709;
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- return NO_ERROR;
- case ULTRAHDR_COLORGAMUT_BT2100:
- conversionFn = yuv601To2100;
- break;
- default:
- // Should be impossible to hit after input validation
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- switch (dest_encoding) {
- case ULTRAHDR_COLORGAMUT_BT709:
- conversionFn = yuv2100To709;
- break;
- case ULTRAHDR_COLORGAMUT_P3:
- conversionFn = yuv2100To601;
- break;
- case ULTRAHDR_COLORGAMUT_BT2100:
- return NO_ERROR;
- default:
- // Should be impossible to hit after input validation
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
- break;
- default:
- // Should be impossible to hit after input validation
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
-
- if (conversionFn == nullptr) {
- // Should be impossible to hit after input validation
- return ERROR_JPEGR_INVALID_COLORGAMUT;
- }
-
- for (size_t y = 0; y < image->height / 2; ++y) {
- for (size_t x = 0; x < image->width / 2; ++x) {
- transformYuv420(image, x, y, conversionFn);
- }
- }
-
- return NO_ERROR;
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/jpegrutils.cpp b/libs/ultrahdr/jpegrutils.cpp
deleted file mode 100644
index c434eb6..0000000
--- a/libs/ultrahdr/jpegrutils.cpp
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * Copyright 2022 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 <ultrahdr/jpegrutils.h>
-
-#include <algorithm>
-#include <cmath>
-
-#include <image_io/xml/xml_reader.h>
-#include <image_io/xml/xml_writer.h>
-#include <image_io/base/message_handler.h>
-#include <image_io/xml/xml_element_rules.h>
-#include <image_io/xml/xml_handler.h>
-#include <image_io/xml/xml_rule.h>
-#include <utils/Log.h>
-
-using namespace photos_editing_formats::image_io;
-using namespace std;
-
-namespace android::ultrahdr {
-/*
- * Helper function used for generating XMP metadata.
- *
- * @param prefix The prefix part of the name.
- * @param suffix The suffix part of the name.
- * @return A name of the form "prefix:suffix".
- */
-static inline string Name(const string &prefix, const string &suffix) {
- std::stringstream ss;
- ss << prefix << ":" << suffix;
- return ss.str();
-}
-
-DataStruct::DataStruct(int s) {
- data = malloc(s);
- length = s;
- memset(data, 0, s);
- writePos = 0;
-}
-
-DataStruct::~DataStruct() {
- if (data != nullptr) {
- free(data);
- }
-}
-
-void* DataStruct::getData() {
- return data;
-}
-
-int DataStruct::getLength() {
- return length;
-}
-
-int DataStruct::getBytesWritten() {
- return writePos;
-}
-
-bool DataStruct::write8(uint8_t value) {
- uint8_t v = value;
- return write(&v, 1);
-}
-
-bool DataStruct::write16(uint16_t value) {
- uint16_t v = value;
- return write(&v, 2);
-}
-bool DataStruct::write32(uint32_t value) {
- uint32_t v = value;
- return write(&v, 4);
-}
-
-bool DataStruct::write(const void* src, int size) {
- if (writePos + size > length) {
- ALOGE("Writing out of boundary: write position: %d, size: %d, capacity: %d",
- writePos, size, length);
- return false;
- }
- memcpy((uint8_t*) data + writePos, src, size);
- writePos += size;
- return true;
-}
-
-/*
- * Helper function used for writing data to destination.
- */
-status_t Write(jr_compressed_ptr destination, const void* source, size_t length, int &position) {
- if (position + length > destination->maxLength) {
- return ERROR_JPEGR_BUFFER_TOO_SMALL;
- }
-
- memcpy((uint8_t*)destination->data + sizeof(uint8_t) * position, source, length);
- position += length;
- return NO_ERROR;
-}
-
-// Extremely simple XML Handler - just searches for interesting elements
-class XMPXmlHandler : public XmlHandler {
-public:
-
- XMPXmlHandler() : XmlHandler() {
- state = NotStrarted;
- versionFound = false;
- minContentBoostFound = false;
- maxContentBoostFound = false;
- gammaFound = false;
- offsetSdrFound = false;
- offsetHdrFound = false;
- hdrCapacityMinFound = false;
- hdrCapacityMaxFound = false;
- baseRenditionIsHdrFound = false;
- }
-
- enum ParseState {
- NotStrarted,
- Started,
- Done
- };
-
- virtual DataMatchResult StartElement(const XmlTokenContext& context) {
- string val;
- if (context.BuildTokenValue(&val)) {
- if (!val.compare(containerName)) {
- state = Started;
- } else {
- if (state != Done) {
- state = NotStrarted;
- }
- }
- }
- return context.GetResult();
- }
-
- virtual DataMatchResult FinishElement(const XmlTokenContext& context) {
- if (state == Started) {
- state = Done;
- lastAttributeName = "";
- }
- return context.GetResult();
- }
-
- virtual DataMatchResult AttributeName(const XmlTokenContext& context) {
- string val;
- if (state == Started) {
- if (context.BuildTokenValue(&val)) {
- if (!val.compare(versionAttrName)) {
- lastAttributeName = versionAttrName;
- } else if (!val.compare(maxContentBoostAttrName)) {
- lastAttributeName = maxContentBoostAttrName;
- } else if (!val.compare(minContentBoostAttrName)) {
- lastAttributeName = minContentBoostAttrName;
- } else if (!val.compare(gammaAttrName)) {
- lastAttributeName = gammaAttrName;
- } else if (!val.compare(offsetSdrAttrName)) {
- lastAttributeName = offsetSdrAttrName;
- } else if (!val.compare(offsetHdrAttrName)) {
- lastAttributeName = offsetHdrAttrName;
- } else if (!val.compare(hdrCapacityMinAttrName)) {
- lastAttributeName = hdrCapacityMinAttrName;
- } else if (!val.compare(hdrCapacityMaxAttrName)) {
- lastAttributeName = hdrCapacityMaxAttrName;
- } else if (!val.compare(baseRenditionIsHdrAttrName)) {
- lastAttributeName = baseRenditionIsHdrAttrName;
- } else {
- lastAttributeName = "";
- }
- }
- }
- return context.GetResult();
- }
-
- virtual DataMatchResult AttributeValue(const XmlTokenContext& context) {
- string val;
- if (state == Started) {
- if (context.BuildTokenValue(&val, true)) {
- if (!lastAttributeName.compare(versionAttrName)) {
- versionStr = val;
- versionFound = true;
- } else if (!lastAttributeName.compare(maxContentBoostAttrName)) {
- maxContentBoostStr = val;
- maxContentBoostFound = true;
- } else if (!lastAttributeName.compare(minContentBoostAttrName)) {
- minContentBoostStr = val;
- minContentBoostFound = true;
- } else if (!lastAttributeName.compare(gammaAttrName)) {
- gammaStr = val;
- gammaFound = true;
- } else if (!lastAttributeName.compare(offsetSdrAttrName)) {
- offsetSdrStr = val;
- offsetSdrFound = true;
- } else if (!lastAttributeName.compare(offsetHdrAttrName)) {
- offsetHdrStr = val;
- offsetHdrFound = true;
- } else if (!lastAttributeName.compare(hdrCapacityMinAttrName)) {
- hdrCapacityMinStr = val;
- hdrCapacityMinFound = true;
- } else if (!lastAttributeName.compare(hdrCapacityMaxAttrName)) {
- hdrCapacityMaxStr = val;
- hdrCapacityMaxFound = true;
- } else if (!lastAttributeName.compare(baseRenditionIsHdrAttrName)) {
- baseRenditionIsHdrStr = val;
- baseRenditionIsHdrFound = true;
- }
- }
- }
- return context.GetResult();
- }
-
- bool getVersion(string* version, bool* present) {
- if (state == Done) {
- *version = versionStr;
- *present = versionFound;
- return true;
- } else {
- return false;
- }
- }
-
- bool getMaxContentBoost(float* max_content_boost, bool* present) {
- if (state == Done) {
- *present = maxContentBoostFound;
- stringstream ss(maxContentBoostStr);
- float val;
- if (ss >> val) {
- *max_content_boost = exp2(val);
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
- bool getMinContentBoost(float* min_content_boost, bool* present) {
- if (state == Done) {
- *present = minContentBoostFound;
- stringstream ss(minContentBoostStr);
- float val;
- if (ss >> val) {
- *min_content_boost = exp2(val);
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
- bool getGamma(float* gamma, bool* present) {
- if (state == Done) {
- *present = gammaFound;
- stringstream ss(gammaStr);
- float val;
- if (ss >> val) {
- *gamma = val;
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-
- bool getOffsetSdr(float* offset_sdr, bool* present) {
- if (state == Done) {
- *present = offsetSdrFound;
- stringstream ss(offsetSdrStr);
- float val;
- if (ss >> val) {
- *offset_sdr = val;
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-
- bool getOffsetHdr(float* offset_hdr, bool* present) {
- if (state == Done) {
- *present = offsetHdrFound;
- stringstream ss(offsetHdrStr);
- float val;
- if (ss >> val) {
- *offset_hdr = val;
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-
- bool getHdrCapacityMin(float* hdr_capacity_min, bool* present) {
- if (state == Done) {
- *present = hdrCapacityMinFound;
- stringstream ss(hdrCapacityMinStr);
- float val;
- if (ss >> val) {
- *hdr_capacity_min = exp2(val);
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-
- bool getHdrCapacityMax(float* hdr_capacity_max, bool* present) {
- if (state == Done) {
- *present = hdrCapacityMaxFound;
- stringstream ss(hdrCapacityMaxStr);
- float val;
- if (ss >> val) {
- *hdr_capacity_max = exp2(val);
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-
- bool getBaseRenditionIsHdr(bool* base_rendition_is_hdr, bool* present) {
- if (state == Done) {
- *present = baseRenditionIsHdrFound;
- if (!baseRenditionIsHdrStr.compare("False")) {
- *base_rendition_is_hdr = false;
- return true;
- } else if (!baseRenditionIsHdrStr.compare("True")) {
- *base_rendition_is_hdr = true;
- return true;
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
-
-
-
-private:
- static const string containerName;
-
- static const string versionAttrName;
- string versionStr;
- bool versionFound;
- static const string maxContentBoostAttrName;
- string maxContentBoostStr;
- bool maxContentBoostFound;
- static const string minContentBoostAttrName;
- string minContentBoostStr;
- bool minContentBoostFound;
- static const string gammaAttrName;
- string gammaStr;
- bool gammaFound;
- static const string offsetSdrAttrName;
- string offsetSdrStr;
- bool offsetSdrFound;
- static const string offsetHdrAttrName;
- string offsetHdrStr;
- bool offsetHdrFound;
- static const string hdrCapacityMinAttrName;
- string hdrCapacityMinStr;
- bool hdrCapacityMinFound;
- static const string hdrCapacityMaxAttrName;
- string hdrCapacityMaxStr;
- bool hdrCapacityMaxFound;
- static const string baseRenditionIsHdrAttrName;
- string baseRenditionIsHdrStr;
- bool baseRenditionIsHdrFound;
-
- string lastAttributeName;
- ParseState state;
-};
-
-// GContainer XMP constants - URI and namespace prefix
-const string kContainerUri = "http://ns.google.com/photos/1.0/container/";
-const string kContainerPrefix = "Container";
-
-// GContainer XMP constants - element and attribute names
-const string kConDirectory = Name(kContainerPrefix, "Directory");
-const string kConItem = Name(kContainerPrefix, "Item");
-
-// GContainer XMP constants - names for XMP handlers
-const string XMPXmlHandler::containerName = "rdf:Description";
-// Item XMP constants - URI and namespace prefix
-const string kItemUri = "http://ns.google.com/photos/1.0/container/item/";
-const string kItemPrefix = "Item";
-
-// Item XMP constants - element and attribute names
-const string kItemLength = Name(kItemPrefix, "Length");
-const string kItemMime = Name(kItemPrefix, "Mime");
-const string kItemSemantic = Name(kItemPrefix, "Semantic");
-
-// Item XMP constants - element and attribute values
-const string kSemanticPrimary = "Primary";
-const string kSemanticGainMap = "GainMap";
-const string kMimeImageJpeg = "image/jpeg";
-
-// GainMap XMP constants - URI and namespace prefix
-const string kGainMapUri = "http://ns.adobe.com/hdr-gain-map/1.0/";
-const string kGainMapPrefix = "hdrgm";
-
-// GainMap XMP constants - element and attribute names
-const string kMapVersion = Name(kGainMapPrefix, "Version");
-const string kMapGainMapMin = Name(kGainMapPrefix, "GainMapMin");
-const string kMapGainMapMax = Name(kGainMapPrefix, "GainMapMax");
-const string kMapGamma = Name(kGainMapPrefix, "Gamma");
-const string kMapOffsetSdr = Name(kGainMapPrefix, "OffsetSDR");
-const string kMapOffsetHdr = Name(kGainMapPrefix, "OffsetHDR");
-const string kMapHDRCapacityMin = Name(kGainMapPrefix, "HDRCapacityMin");
-const string kMapHDRCapacityMax = Name(kGainMapPrefix, "HDRCapacityMax");
-const string kMapBaseRenditionIsHDR = Name(kGainMapPrefix, "BaseRenditionIsHDR");
-
-// GainMap XMP constants - names for XMP handlers
-const string XMPXmlHandler::versionAttrName = kMapVersion;
-const string XMPXmlHandler::minContentBoostAttrName = kMapGainMapMin;
-const string XMPXmlHandler::maxContentBoostAttrName = kMapGainMapMax;
-const string XMPXmlHandler::gammaAttrName = kMapGamma;
-const string XMPXmlHandler::offsetSdrAttrName = kMapOffsetSdr;
-const string XMPXmlHandler::offsetHdrAttrName = kMapOffsetHdr;
-const string XMPXmlHandler::hdrCapacityMinAttrName = kMapHDRCapacityMin;
-const string XMPXmlHandler::hdrCapacityMaxAttrName = kMapHDRCapacityMax;
-const string XMPXmlHandler::baseRenditionIsHdrAttrName = kMapBaseRenditionIsHDR;
-
-bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_struct* metadata) {
- string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
-
- if (xmp_size < nameSpace.size()+2) {
- // Data too short
- return false;
- }
-
- if (strncmp(reinterpret_cast<char*>(xmp_data), nameSpace.c_str(), nameSpace.size())) {
- // Not correct namespace
- return false;
- }
-
- // Position the pointers to the start of XMP XML portion
- xmp_data += nameSpace.size()+1;
- xmp_size -= nameSpace.size()+1;
- XMPXmlHandler handler;
-
- // We need to remove tail data until the closing tag. Otherwise parser will throw an error.
- while(xmp_data[xmp_size-1]!='>' && xmp_size > 1) {
- xmp_size--;
- }
-
- string str(reinterpret_cast<const char*>(xmp_data), xmp_size);
- MessageHandler msg_handler;
- unique_ptr<XmlRule> rule(new XmlElementRule);
- XmlReader reader(&handler, &msg_handler);
- reader.StartParse(std::move(rule));
- reader.Parse(str);
- reader.FinishParse();
- if (reader.HasErrors()) {
- // Parse error
- return false;
- }
-
- // Apply default values to any not-present fields, except for Version,
- // maxContentBoost, and hdrCapacityMax, which are required. Return false if
- // we encounter a present field that couldn't be parsed, since this
- // indicates it is invalid (eg. string where there should be a float).
- bool present = false;
- if (!handler.getVersion(&metadata->version, &present) || !present) {
- return false;
- }
- if (!handler.getMaxContentBoost(&metadata->maxContentBoost, &present) || !present) {
- return false;
- }
- if (!handler.getHdrCapacityMax(&metadata->hdrCapacityMax, &present) || !present) {
- return false;
- }
- if (!handler.getMinContentBoost(&metadata->minContentBoost, &present)) {
- if (present) return false;
- metadata->minContentBoost = 1.0f;
- }
- if (!handler.getGamma(&metadata->gamma, &present)) {
- if (present) return false;
- metadata->gamma = 1.0f;
- }
- if (!handler.getOffsetSdr(&metadata->offsetSdr, &present)) {
- if (present) return false;
- metadata->offsetSdr = 1.0f / 64.0f;
- }
- if (!handler.getOffsetHdr(&metadata->offsetHdr, &present)) {
- if (present) return false;
- metadata->offsetHdr = 1.0f / 64.0f;
- }
- if (!handler.getHdrCapacityMin(&metadata->hdrCapacityMin, &present)) {
- if (present) return false;
- metadata->hdrCapacityMin = 1.0f;
- }
-
- bool base_rendition_is_hdr;
- if (!handler.getBaseRenditionIsHdr(&base_rendition_is_hdr, &present)) {
- if (present) return false;
- base_rendition_is_hdr = false;
- }
- if (base_rendition_is_hdr) {
- ALOGE("Base rendition of HDR is not supported!");
- return false;
- }
-
- return true;
-}
-
-string generateXmpForPrimaryImage(int secondary_image_length, ultrahdr_metadata_struct& metadata) {
- const vector<string> kConDirSeq({kConDirectory, string("rdf:Seq")});
- const vector<string> kLiItem({string("rdf:li"), kConItem});
-
- std::stringstream ss;
- photos_editing_formats::image_io::XmlWriter writer(ss);
- writer.StartWritingElement("x:xmpmeta");
- writer.WriteXmlns("x", "adobe:ns:meta/");
- writer.WriteAttributeNameAndValue("x:xmptk", "Adobe XMP Core 5.1.2");
- writer.StartWritingElement("rdf:RDF");
- writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
- writer.StartWritingElement("rdf:Description");
- writer.WriteXmlns(kContainerPrefix, kContainerUri);
- writer.WriteXmlns(kItemPrefix, kItemUri);
- writer.WriteXmlns(kGainMapPrefix, kGainMapUri);
- writer.WriteAttributeNameAndValue(kMapVersion, metadata.version);
-
- writer.StartWritingElements(kConDirSeq);
-
- size_t item_depth = writer.StartWritingElement("rdf:li");
- writer.WriteAttributeNameAndValue("rdf:parseType", "Resource");
- writer.StartWritingElement(kConItem);
- writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticPrimary);
- writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg);
- writer.FinishWritingElementsToDepth(item_depth);
-
- writer.StartWritingElement("rdf:li");
- writer.WriteAttributeNameAndValue("rdf:parseType", "Resource");
- writer.StartWritingElement(kConItem);
- writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticGainMap);
- writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg);
- writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length);
-
- writer.FinishWriting();
-
- return ss.str();
-}
-
-string generateXmpForSecondaryImage(ultrahdr_metadata_struct& metadata) {
- const vector<string> kConDirSeq({kConDirectory, string("rdf:Seq")});
-
- std::stringstream ss;
- photos_editing_formats::image_io::XmlWriter writer(ss);
- writer.StartWritingElement("x:xmpmeta");
- writer.WriteXmlns("x", "adobe:ns:meta/");
- writer.WriteAttributeNameAndValue("x:xmptk", "Adobe XMP Core 5.1.2");
- writer.StartWritingElement("rdf:RDF");
- writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
- writer.StartWritingElement("rdf:Description");
- writer.WriteXmlns(kGainMapPrefix, kGainMapUri);
- writer.WriteAttributeNameAndValue(kMapVersion, metadata.version);
- writer.WriteAttributeNameAndValue(kMapGainMapMin, log2(metadata.minContentBoost));
- writer.WriteAttributeNameAndValue(kMapGainMapMax, log2(metadata.maxContentBoost));
- writer.WriteAttributeNameAndValue(kMapGamma, metadata.gamma);
- writer.WriteAttributeNameAndValue(kMapOffsetSdr, metadata.offsetSdr);
- writer.WriteAttributeNameAndValue(kMapOffsetHdr, metadata.offsetHdr);
- writer.WriteAttributeNameAndValue(kMapHDRCapacityMin, log2(metadata.hdrCapacityMin));
- writer.WriteAttributeNameAndValue(kMapHDRCapacityMax, log2(metadata.hdrCapacityMax));
- writer.WriteAttributeNameAndValue(kMapBaseRenditionIsHDR, "False");
- writer.FinishWriting();
-
- return ss.str();
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/multipictureformat.cpp b/libs/ultrahdr/multipictureformat.cpp
deleted file mode 100644
index f1679ef..0000000
--- a/libs/ultrahdr/multipictureformat.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 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 <ultrahdr/multipictureformat.h>
-#include <ultrahdr/jpegrutils.h>
-
-namespace android::ultrahdr {
-size_t calculateMpfSize() {
- return sizeof(kMpfSig) + // Signature
- kMpEndianSize + // Endianness
- sizeof(uint32_t) + // Index IFD Offset
- sizeof(uint16_t) + // Tag count
- kTagSerializedCount * kTagSize + // 3 tags at 12 bytes each
- sizeof(uint32_t) + // Attribute IFD offset
- kNumPictures * kMPEntrySize; // MP Entries for each image
-}
-
-sp<DataStruct> generateMpf(int primary_image_size, int primary_image_offset,
- int secondary_image_size, int secondary_image_offset) {
- size_t mpf_size = calculateMpfSize();
- sp<DataStruct> dataStruct = sp<DataStruct>::make(mpf_size);
-
- dataStruct->write(static_cast<const void*>(kMpfSig), sizeof(kMpfSig));
-#if USE_BIG_ENDIAN
- dataStruct->write(static_cast<const void*>(kMpBigEndian), kMpEndianSize);
-#else
- dataStruct->write(static_cast<const void*>(kMpLittleEndian), kMpEndianSize);
-#endif
-
- // Set the Index IFD offset be the position after the endianness value and this offset.
- constexpr uint32_t indexIfdOffset =
- static_cast<uint16_t>(kMpEndianSize + sizeof(kMpfSig));
- dataStruct->write32(Endian_SwapBE32(indexIfdOffset));
-
- // We will write 3 tags (version, number of images, MP entries).
- dataStruct->write16(Endian_SwapBE16(kTagSerializedCount));
-
- // Write the version tag.
- dataStruct->write16(Endian_SwapBE16(kVersionTag));
- dataStruct->write16(Endian_SwapBE16(kVersionType));
- dataStruct->write32(Endian_SwapBE32(kVersionCount));
- dataStruct->write(kVersionExpected, kVersionSize);
-
- // Write the number of images.
- dataStruct->write16(Endian_SwapBE16(kNumberOfImagesTag));
- dataStruct->write16(Endian_SwapBE16(kNumberOfImagesType));
- dataStruct->write32(Endian_SwapBE32(kNumberOfImagesCount));
- dataStruct->write32(Endian_SwapBE32(kNumPictures));
-
- // Write the MP entries.
- dataStruct->write16(Endian_SwapBE16(kMPEntryTag));
- dataStruct->write16(Endian_SwapBE16(kMPEntryType));
- dataStruct->write32(Endian_SwapBE32(kMPEntrySize * kNumPictures));
- const uint32_t mpEntryOffset =
- static_cast<uint32_t>(dataStruct->getBytesWritten() - // The bytes written so far
- sizeof(kMpfSig) + // Excluding the MPF signature
- sizeof(uint32_t) + // The 4 bytes for this offset
- sizeof(uint32_t)); // The 4 bytes for the attribute IFD offset.
- dataStruct->write32(Endian_SwapBE32(mpEntryOffset));
-
- // Write the attribute IFD offset (zero because we don't write it).
- dataStruct->write32(0);
-
- // Write the MP entries for primary image
- dataStruct->write32(
- Endian_SwapBE32(kMPEntryAttributeFormatJpeg | kMPEntryAttributeTypePrimary));
- dataStruct->write32(Endian_SwapBE32(primary_image_size));
- dataStruct->write32(Endian_SwapBE32(primary_image_offset));
- dataStruct->write16(0);
- dataStruct->write16(0);
-
- // Write the MP entries for secondary image
- dataStruct->write32(Endian_SwapBE32(kMPEntryAttributeFormatJpeg));
- dataStruct->write32(Endian_SwapBE32(secondary_image_size));
- dataStruct->write32(Endian_SwapBE32(secondary_image_offset));
- dataStruct->write16(0);
- dataStruct->write16(0);
-
- return dataStruct;
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/tests/AndroidTest.xml b/libs/ultrahdr/tests/AndroidTest.xml
deleted file mode 100644
index 1754a5c..0000000
--- a/libs/ultrahdr/tests/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Unit test configuration for ultrahdr_unit_test">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push-file" key="ultrahdr_unit_test" value="/data/local/tmp/ultrahdr_unit_test" />
- <option name="push" value="data/*->/data/local/tmp/" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="ultrahdr_unit_test" />
- </test>
-</configuration>
diff --git a/libs/ultrahdr/tests/data/jpeg_image.jpg b/libs/ultrahdr/tests/data/jpeg_image.jpg
deleted file mode 100644
index e285742..0000000
--- a/libs/ultrahdr/tests/data/jpeg_image.jpg
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/minnie-318x240.yu12 b/libs/ultrahdr/tests/data/minnie-318x240.yu12
deleted file mode 100644
index 7b2fc71..0000000
--- a/libs/ultrahdr/tests/data/minnie-318x240.yu12
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/minnie-320x240-y.jpg b/libs/ultrahdr/tests/data/minnie-320x240-y.jpg
deleted file mode 100644
index 20b5a2c..0000000
--- a/libs/ultrahdr/tests/data/minnie-320x240-y.jpg
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg b/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg
deleted file mode 100644
index c7f4538..0000000
--- a/libs/ultrahdr/tests/data/minnie-320x240-yuv-icc.jpg
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/minnie-320x240-yuv.jpg b/libs/ultrahdr/tests/data/minnie-320x240-yuv.jpg
deleted file mode 100644
index 41300f4..0000000
--- a/libs/ultrahdr/tests/data/minnie-320x240-yuv.jpg
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/minnie-320x240.y b/libs/ultrahdr/tests/data/minnie-320x240.y
deleted file mode 100644
index f9d8371..0000000
--- a/libs/ultrahdr/tests/data/minnie-320x240.y
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/minnie-320x240.yu12 b/libs/ultrahdr/tests/data/minnie-320x240.yu12
deleted file mode 100644
index 0d66f53..0000000
--- a/libs/ultrahdr/tests/data/minnie-320x240.yu12
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/raw_p010_image.p010 b/libs/ultrahdr/tests/data/raw_p010_image.p010
deleted file mode 100644
index 01673bf..0000000
--- a/libs/ultrahdr/tests/data/raw_p010_image.p010
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/data/raw_yuv420_image.yuv420 b/libs/ultrahdr/tests/data/raw_yuv420_image.yuv420
deleted file mode 100644
index c043da6..0000000
--- a/libs/ultrahdr/tests/data/raw_yuv420_image.yuv420
+++ /dev/null
Binary files differ
diff --git a/libs/ultrahdr/tests/gainmapmath_test.cpp b/libs/ultrahdr/tests/gainmapmath_test.cpp
deleted file mode 100644
index 7c2d076..0000000
--- a/libs/ultrahdr/tests/gainmapmath_test.cpp
+++ /dev/null
@@ -1,1359 +0,0 @@
-/*
- * Copyright 2022 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 <cmath>
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
-#include <ultrahdr/gainmapmath.h>
-
-namespace android::ultrahdr {
-
-class GainMapMathTest : public testing::Test {
-public:
- GainMapMathTest();
- ~GainMapMathTest();
-
- float ComparisonEpsilon() { return 1e-4f; }
- float LuminanceEpsilon() { return 1e-2f; }
- float YuvConversionEpsilon() { return 1.0f / (255.0f * 2.0f); }
-
- Color Yuv420(uint8_t y, uint8_t u, uint8_t v) {
- return {{{ static_cast<float>(y) / 255.0f,
- (static_cast<float>(u) - 128.0f) / 255.0f,
- (static_cast<float>(v) - 128.0f) / 255.0f }}};
- }
-
- Color P010(uint16_t y, uint16_t u, uint16_t v) {
- return {{{ (static_cast<float>(y) - 64.0f) / 876.0f,
- (static_cast<float>(u) - 64.0f) / 896.0f - 0.5f,
- (static_cast<float>(v) - 64.0f) / 896.0f - 0.5f }}};
- }
-
- float Map(uint8_t e) {
- return static_cast<float>(e) / 255.0f;
- }
-
- Color ColorMin(Color e1, Color e2) {
- return {{{ fmin(e1.r, e2.r), fmin(e1.g, e2.g), fmin(e1.b, e2.b) }}};
- }
-
- Color ColorMax(Color e1, Color e2) {
- return {{{ fmax(e1.r, e2.r), fmax(e1.g, e2.g), fmax(e1.b, e2.b) }}};
- }
-
- Color RgbBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; }
- Color RgbWhite() { return {{{ 1.0f, 1.0f, 1.0f }}}; }
-
- Color RgbRed() { return {{{ 1.0f, 0.0f, 0.0f }}}; }
- Color RgbGreen() { return {{{ 0.0f, 1.0f, 0.0f }}}; }
- Color RgbBlue() { return {{{ 0.0f, 0.0f, 1.0f }}}; }
-
- Color YuvBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; }
- Color YuvWhite() { return {{{ 1.0f, 0.0f, 0.0f }}}; }
-
- Color SrgbYuvRed() { return {{{ 0.2126f, -0.11457f, 0.5f }}}; }
- Color SrgbYuvGreen() { return {{{ 0.7152f, -0.38543f, -0.45415f }}}; }
- Color SrgbYuvBlue() { return {{{ 0.0722f, 0.5f, -0.04585f }}}; }
-
- Color P3YuvRed() { return {{{ 0.299f, -0.16874f, 0.5f }}}; }
- Color P3YuvGreen() { return {{{ 0.587f, -0.33126f, -0.41869f }}}; }
- Color P3YuvBlue() { return {{{ 0.114f, 0.5f, -0.08131f }}}; }
-
- Color Bt2100YuvRed() { return {{{ 0.2627f, -0.13963f, 0.5f }}}; }
- Color Bt2100YuvGreen() { return {{{ 0.6780f, -0.36037f, -0.45979f }}}; }
- Color Bt2100YuvBlue() { return {{{ 0.0593f, 0.5f, -0.04021f }}}; }
-
- float SrgbYuvToLuminance(Color yuv_gamma, ColorCalculationFn luminanceFn) {
- Color rgb_gamma = srgbYuvToRgb(yuv_gamma);
- Color rgb = srgbInvOetf(rgb_gamma);
- float luminance_scaled = luminanceFn(rgb);
- return luminance_scaled * kSdrWhiteNits;
- }
-
- float P3YuvToLuminance(Color yuv_gamma, ColorCalculationFn luminanceFn) {
- Color rgb_gamma = p3YuvToRgb(yuv_gamma);
- Color rgb = srgbInvOetf(rgb_gamma);
- float luminance_scaled = luminanceFn(rgb);
- return luminance_scaled * kSdrWhiteNits;
- }
-
- float Bt2100YuvToLuminance(Color yuv_gamma, ColorTransformFn hdrInvOetf,
- ColorTransformFn gamutConversionFn, ColorCalculationFn luminanceFn,
- float scale_factor) {
- Color rgb_gamma = bt2100YuvToRgb(yuv_gamma);
- Color rgb = hdrInvOetf(rgb_gamma);
- rgb = gamutConversionFn(rgb);
- float luminance_scaled = luminanceFn(rgb);
- return luminance_scaled * scale_factor;
- }
-
- Color Recover(Color yuv_gamma, float gain, ultrahdr_metadata_ptr metadata) {
- Color rgb_gamma = srgbYuvToRgb(yuv_gamma);
- Color rgb = srgbInvOetf(rgb_gamma);
- return applyGain(rgb, gain, metadata);
- }
-
- jpegr_uncompressed_struct Yuv420Image() {
- static uint8_t pixels[] = {
- // Y
- 0x00, 0x10, 0x20, 0x30,
- 0x01, 0x11, 0x21, 0x31,
- 0x02, 0x12, 0x22, 0x32,
- 0x03, 0x13, 0x23, 0x33,
- // U
- 0xA0, 0xA1,
- 0xA2, 0xA3,
- // V
- 0xB0, 0xB1,
- 0xB2, 0xB3,
- };
- return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709, pixels + 16, 4, 2 };
- }
-
- Color (*Yuv420Colors())[4] {
- static Color colors[4][4] = {
- {
- Yuv420(0x00, 0xA0, 0xB0), Yuv420(0x10, 0xA0, 0xB0),
- Yuv420(0x20, 0xA1, 0xB1), Yuv420(0x30, 0xA1, 0xB1),
- }, {
- Yuv420(0x01, 0xA0, 0xB0), Yuv420(0x11, 0xA0, 0xB0),
- Yuv420(0x21, 0xA1, 0xB1), Yuv420(0x31, 0xA1, 0xB1),
- }, {
- Yuv420(0x02, 0xA2, 0xB2), Yuv420(0x12, 0xA2, 0xB2),
- Yuv420(0x22, 0xA3, 0xB3), Yuv420(0x32, 0xA3, 0xB3),
- }, {
- Yuv420(0x03, 0xA2, 0xB2), Yuv420(0x13, 0xA2, 0xB2),
- Yuv420(0x23, 0xA3, 0xB3), Yuv420(0x33, 0xA3, 0xB3),
- },
- };
- return colors;
- }
-
- jpegr_uncompressed_struct P010Image() {
- static uint16_t pixels[] = {
- // Y
- 0x00 << 6, 0x10 << 6, 0x20 << 6, 0x30 << 6,
- 0x01 << 6, 0x11 << 6, 0x21 << 6, 0x31 << 6,
- 0x02 << 6, 0x12 << 6, 0x22 << 6, 0x32 << 6,
- 0x03 << 6, 0x13 << 6, 0x23 << 6, 0x33 << 6,
- // UV
- 0xA0 << 6, 0xB0 << 6, 0xA1 << 6, 0xB1 << 6,
- 0xA2 << 6, 0xB2 << 6, 0xA3 << 6, 0xB3 << 6,
- };
- return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709, pixels + 16, 4, 4 };
- }
-
- Color (*P010Colors())[4] {
- static Color colors[4][4] = {
- {
- P010(0x00, 0xA0, 0xB0), P010(0x10, 0xA0, 0xB0),
- P010(0x20, 0xA1, 0xB1), P010(0x30, 0xA1, 0xB1),
- }, {
- P010(0x01, 0xA0, 0xB0), P010(0x11, 0xA0, 0xB0),
- P010(0x21, 0xA1, 0xB1), P010(0x31, 0xA1, 0xB1),
- }, {
- P010(0x02, 0xA2, 0xB2), P010(0x12, 0xA2, 0xB2),
- P010(0x22, 0xA3, 0xB3), P010(0x32, 0xA3, 0xB3),
- }, {
- P010(0x03, 0xA2, 0xB2), P010(0x13, 0xA2, 0xB2),
- P010(0x23, 0xA3, 0xB3), P010(0x33, 0xA3, 0xB3),
- },
- };
- return colors;
- }
-
- jpegr_uncompressed_struct MapImage() {
- static uint8_t pixels[] = {
- 0x00, 0x10, 0x20, 0x30,
- 0x01, 0x11, 0x21, 0x31,
- 0x02, 0x12, 0x22, 0x32,
- 0x03, 0x13, 0x23, 0x33,
- };
- return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_UNSPECIFIED };
- }
-
- float (*MapValues())[4] {
- static float values[4][4] = {
- {
- Map(0x00), Map(0x10), Map(0x20), Map(0x30),
- }, {
- Map(0x01), Map(0x11), Map(0x21), Map(0x31),
- }, {
- Map(0x02), Map(0x12), Map(0x22), Map(0x32),
- }, {
- Map(0x03), Map(0x13), Map(0x23), Map(0x33),
- },
- };
- return values;
- }
-
-protected:
- virtual void SetUp();
- virtual void TearDown();
-};
-
-GainMapMathTest::GainMapMathTest() {}
-GainMapMathTest::~GainMapMathTest() {}
-
-void GainMapMathTest::SetUp() {}
-void GainMapMathTest::TearDown() {}
-
-#define EXPECT_RGB_EQ(e1, e2) \
- EXPECT_FLOAT_EQ((e1).r, (e2).r); \
- EXPECT_FLOAT_EQ((e1).g, (e2).g); \
- EXPECT_FLOAT_EQ((e1).b, (e2).b)
-
-#define EXPECT_RGB_NEAR(e1, e2) \
- EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon()); \
- EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon()); \
- EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon())
-
-#define EXPECT_RGB_CLOSE(e1, e2) \
- EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon() * 10.0f); \
- EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon() * 10.0f); \
- EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon() * 10.0f)
-
-#define EXPECT_YUV_EQ(e1, e2) \
- EXPECT_FLOAT_EQ((e1).y, (e2).y); \
- EXPECT_FLOAT_EQ((e1).u, (e2).u); \
- EXPECT_FLOAT_EQ((e1).v, (e2).v)
-
-#define EXPECT_YUV_NEAR(e1, e2) \
- EXPECT_NEAR((e1).y, (e2).y, ComparisonEpsilon()); \
- EXPECT_NEAR((e1).u, (e2).u, ComparisonEpsilon()); \
- EXPECT_NEAR((e1).v, (e2).v, ComparisonEpsilon())
-
-#define EXPECT_YUV_BETWEEN(e, min, max) \
- EXPECT_THAT((e).y, testing::AllOf(testing::Ge((min).y), testing::Le((max).y))); \
- EXPECT_THAT((e).u, testing::AllOf(testing::Ge((min).u), testing::Le((max).u))); \
- EXPECT_THAT((e).v, testing::AllOf(testing::Ge((min).v), testing::Le((max).v)))
-
-// TODO: a bunch of these tests can be parameterized.
-
-TEST_F(GainMapMathTest, ColorConstruct) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- EXPECT_FLOAT_EQ(e1.r, 0.1f);
- EXPECT_FLOAT_EQ(e1.g, 0.2f);
- EXPECT_FLOAT_EQ(e1.b, 0.3f);
-
- EXPECT_FLOAT_EQ(e1.y, 0.1f);
- EXPECT_FLOAT_EQ(e1.u, 0.2f);
- EXPECT_FLOAT_EQ(e1.v, 0.3f);
-}
-
-TEST_F(GainMapMathTest, ColorAddColor) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- Color e2 = e1 + e1;
- EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f);
- EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f);
- EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f);
-
- e2 += e1;
- EXPECT_FLOAT_EQ(e2.r, e1.r * 3.0f);
- EXPECT_FLOAT_EQ(e2.g, e1.g * 3.0f);
- EXPECT_FLOAT_EQ(e2.b, e1.b * 3.0f);
-}
-
-TEST_F(GainMapMathTest, ColorAddFloat) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- Color e2 = e1 + 0.1f;
- EXPECT_FLOAT_EQ(e2.r, e1.r + 0.1f);
- EXPECT_FLOAT_EQ(e2.g, e1.g + 0.1f);
- EXPECT_FLOAT_EQ(e2.b, e1.b + 0.1f);
-
- e2 += 0.1f;
- EXPECT_FLOAT_EQ(e2.r, e1.r + 0.2f);
- EXPECT_FLOAT_EQ(e2.g, e1.g + 0.2f);
- EXPECT_FLOAT_EQ(e2.b, e1.b + 0.2f);
-}
-
-TEST_F(GainMapMathTest, ColorSubtractColor) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- Color e2 = e1 - e1;
- EXPECT_FLOAT_EQ(e2.r, 0.0f);
- EXPECT_FLOAT_EQ(e2.g, 0.0f);
- EXPECT_FLOAT_EQ(e2.b, 0.0f);
-
- e2 -= e1;
- EXPECT_FLOAT_EQ(e2.r, -e1.r);
- EXPECT_FLOAT_EQ(e2.g, -e1.g);
- EXPECT_FLOAT_EQ(e2.b, -e1.b);
-}
-
-TEST_F(GainMapMathTest, ColorSubtractFloat) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- Color e2 = e1 - 0.1f;
- EXPECT_FLOAT_EQ(e2.r, e1.r - 0.1f);
- EXPECT_FLOAT_EQ(e2.g, e1.g - 0.1f);
- EXPECT_FLOAT_EQ(e2.b, e1.b - 0.1f);
-
- e2 -= 0.1f;
- EXPECT_FLOAT_EQ(e2.r, e1.r - 0.2f);
- EXPECT_FLOAT_EQ(e2.g, e1.g - 0.2f);
- EXPECT_FLOAT_EQ(e2.b, e1.b - 0.2f);
-}
-
-TEST_F(GainMapMathTest, ColorMultiplyFloat) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- Color e2 = e1 * 2.0f;
- EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f);
- EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f);
- EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f);
-
- e2 *= 2.0f;
- EXPECT_FLOAT_EQ(e2.r, e1.r * 4.0f);
- EXPECT_FLOAT_EQ(e2.g, e1.g * 4.0f);
- EXPECT_FLOAT_EQ(e2.b, e1.b * 4.0f);
-}
-
-TEST_F(GainMapMathTest, ColorDivideFloat) {
- Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
-
- Color e2 = e1 / 2.0f;
- EXPECT_FLOAT_EQ(e2.r, e1.r / 2.0f);
- EXPECT_FLOAT_EQ(e2.g, e1.g / 2.0f);
- EXPECT_FLOAT_EQ(e2.b, e1.b / 2.0f);
-
- e2 /= 2.0f;
- EXPECT_FLOAT_EQ(e2.r, e1.r / 4.0f);
- EXPECT_FLOAT_EQ(e2.g, e1.g / 4.0f);
- EXPECT_FLOAT_EQ(e2.b, e1.b / 4.0f);
-}
-
-TEST_F(GainMapMathTest, SrgbLuminance) {
- EXPECT_FLOAT_EQ(srgbLuminance(RgbBlack()), 0.0f);
- EXPECT_FLOAT_EQ(srgbLuminance(RgbWhite()), 1.0f);
- EXPECT_FLOAT_EQ(srgbLuminance(RgbRed()), 0.2126f);
- EXPECT_FLOAT_EQ(srgbLuminance(RgbGreen()), 0.7152f);
- EXPECT_FLOAT_EQ(srgbLuminance(RgbBlue()), 0.0722f);
-}
-
-TEST_F(GainMapMathTest, SrgbYuvToRgb) {
- Color rgb_black = srgbYuvToRgb(YuvBlack());
- EXPECT_RGB_NEAR(rgb_black, RgbBlack());
-
- Color rgb_white = srgbYuvToRgb(YuvWhite());
- EXPECT_RGB_NEAR(rgb_white, RgbWhite());
-
- Color rgb_r = srgbYuvToRgb(SrgbYuvRed());
- EXPECT_RGB_NEAR(rgb_r, RgbRed());
-
- Color rgb_g = srgbYuvToRgb(SrgbYuvGreen());
- EXPECT_RGB_NEAR(rgb_g, RgbGreen());
-
- Color rgb_b = srgbYuvToRgb(SrgbYuvBlue());
- EXPECT_RGB_NEAR(rgb_b, RgbBlue());
-}
-
-TEST_F(GainMapMathTest, SrgbRgbToYuv) {
- Color yuv_black = srgbRgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv_black, YuvBlack());
-
- Color yuv_white = srgbRgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv_white, YuvWhite());
-
- Color yuv_r = srgbRgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv_r, SrgbYuvRed());
-
- Color yuv_g = srgbRgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv_g, SrgbYuvGreen());
-
- Color yuv_b = srgbRgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv_b, SrgbYuvBlue());
-}
-
-TEST_F(GainMapMathTest, SrgbRgbYuvRoundtrip) {
- Color rgb_black = srgbYuvToRgb(srgbRgbToYuv(RgbBlack()));
- EXPECT_RGB_NEAR(rgb_black, RgbBlack());
-
- Color rgb_white = srgbYuvToRgb(srgbRgbToYuv(RgbWhite()));
- EXPECT_RGB_NEAR(rgb_white, RgbWhite());
-
- Color rgb_r = srgbYuvToRgb(srgbRgbToYuv(RgbRed()));
- EXPECT_RGB_NEAR(rgb_r, RgbRed());
-
- Color rgb_g = srgbYuvToRgb(srgbRgbToYuv(RgbGreen()));
- EXPECT_RGB_NEAR(rgb_g, RgbGreen());
-
- Color rgb_b = srgbYuvToRgb(srgbRgbToYuv(RgbBlue()));
- EXPECT_RGB_NEAR(rgb_b, RgbBlue());
-}
-
-TEST_F(GainMapMathTest, SrgbTransferFunction) {
- EXPECT_FLOAT_EQ(srgbInvOetf(0.0f), 0.0f);
- EXPECT_NEAR(srgbInvOetf(0.02f), 0.00154f, ComparisonEpsilon());
- EXPECT_NEAR(srgbInvOetf(0.04045f), 0.00313f, ComparisonEpsilon());
- EXPECT_NEAR(srgbInvOetf(0.5f), 0.21404f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(srgbInvOetf(1.0f), 1.0f);
-}
-
-TEST_F(GainMapMathTest, P3Luminance) {
- EXPECT_FLOAT_EQ(p3Luminance(RgbBlack()), 0.0f);
- EXPECT_FLOAT_EQ(p3Luminance(RgbWhite()), 1.0f);
- EXPECT_FLOAT_EQ(p3Luminance(RgbRed()), 0.20949f);
- EXPECT_FLOAT_EQ(p3Luminance(RgbGreen()), 0.72160f);
- EXPECT_FLOAT_EQ(p3Luminance(RgbBlue()), 0.06891f);
-}
-
-TEST_F(GainMapMathTest, P3YuvToRgb) {
- Color rgb_black = p3YuvToRgb(YuvBlack());
- EXPECT_RGB_NEAR(rgb_black, RgbBlack());
-
- Color rgb_white = p3YuvToRgb(YuvWhite());
- EXPECT_RGB_NEAR(rgb_white, RgbWhite());
-
- Color rgb_r = p3YuvToRgb(P3YuvRed());
- EXPECT_RGB_NEAR(rgb_r, RgbRed());
-
- Color rgb_g = p3YuvToRgb(P3YuvGreen());
- EXPECT_RGB_NEAR(rgb_g, RgbGreen());
-
- Color rgb_b = p3YuvToRgb(P3YuvBlue());
- EXPECT_RGB_NEAR(rgb_b, RgbBlue());
-}
-
-TEST_F(GainMapMathTest, P3RgbToYuv) {
- Color yuv_black = p3RgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv_black, YuvBlack());
-
- Color yuv_white = p3RgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv_white, YuvWhite());
-
- Color yuv_r = p3RgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv_r, P3YuvRed());
-
- Color yuv_g = p3RgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv_g, P3YuvGreen());
-
- Color yuv_b = p3RgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv_b, P3YuvBlue());
-}
-
-TEST_F(GainMapMathTest, P3RgbYuvRoundtrip) {
- Color rgb_black = p3YuvToRgb(p3RgbToYuv(RgbBlack()));
- EXPECT_RGB_NEAR(rgb_black, RgbBlack());
-
- Color rgb_white = p3YuvToRgb(p3RgbToYuv(RgbWhite()));
- EXPECT_RGB_NEAR(rgb_white, RgbWhite());
-
- Color rgb_r = p3YuvToRgb(p3RgbToYuv(RgbRed()));
- EXPECT_RGB_NEAR(rgb_r, RgbRed());
-
- Color rgb_g = p3YuvToRgb(p3RgbToYuv(RgbGreen()));
- EXPECT_RGB_NEAR(rgb_g, RgbGreen());
-
- Color rgb_b = p3YuvToRgb(p3RgbToYuv(RgbBlue()));
- EXPECT_RGB_NEAR(rgb_b, RgbBlue());
-}
-TEST_F(GainMapMathTest, Bt2100Luminance) {
- EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlack()), 0.0f);
- EXPECT_FLOAT_EQ(bt2100Luminance(RgbWhite()), 1.0f);
- EXPECT_FLOAT_EQ(bt2100Luminance(RgbRed()), 0.2627f);
- EXPECT_FLOAT_EQ(bt2100Luminance(RgbGreen()), 0.6780f);
- EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlue()), 0.0593f);
-}
-
-TEST_F(GainMapMathTest, Bt2100YuvToRgb) {
- Color rgb_black = bt2100YuvToRgb(YuvBlack());
- EXPECT_RGB_NEAR(rgb_black, RgbBlack());
-
- Color rgb_white = bt2100YuvToRgb(YuvWhite());
- EXPECT_RGB_NEAR(rgb_white, RgbWhite());
-
- Color rgb_r = bt2100YuvToRgb(Bt2100YuvRed());
- EXPECT_RGB_NEAR(rgb_r, RgbRed());
-
- Color rgb_g = bt2100YuvToRgb(Bt2100YuvGreen());
- EXPECT_RGB_NEAR(rgb_g, RgbGreen());
-
- Color rgb_b = bt2100YuvToRgb(Bt2100YuvBlue());
- EXPECT_RGB_NEAR(rgb_b, RgbBlue());
-}
-
-TEST_F(GainMapMathTest, Bt2100RgbToYuv) {
- Color yuv_black = bt2100RgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv_black, YuvBlack());
-
- Color yuv_white = bt2100RgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv_white, YuvWhite());
-
- Color yuv_r = bt2100RgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv_r, Bt2100YuvRed());
-
- Color yuv_g = bt2100RgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv_g, Bt2100YuvGreen());
-
- Color yuv_b = bt2100RgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv_b, Bt2100YuvBlue());
-}
-
-TEST_F(GainMapMathTest, Bt2100RgbYuvRoundtrip) {
- Color rgb_black = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlack()));
- EXPECT_RGB_NEAR(rgb_black, RgbBlack());
-
- Color rgb_white = bt2100YuvToRgb(bt2100RgbToYuv(RgbWhite()));
- EXPECT_RGB_NEAR(rgb_white, RgbWhite());
-
- Color rgb_r = bt2100YuvToRgb(bt2100RgbToYuv(RgbRed()));
- EXPECT_RGB_NEAR(rgb_r, RgbRed());
-
- Color rgb_g = bt2100YuvToRgb(bt2100RgbToYuv(RgbGreen()));
- EXPECT_RGB_NEAR(rgb_g, RgbGreen());
-
- Color rgb_b = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlue()));
- EXPECT_RGB_NEAR(rgb_b, RgbBlue());
-}
-
-TEST_F(GainMapMathTest, Bt709ToBt601YuvConversion) {
- Color yuv_black = srgbRgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv709To601(yuv_black), YuvBlack());
-
- Color yuv_white = srgbRgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv709To601(yuv_white), YuvWhite());
-
- Color yuv_r = srgbRgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv709To601(yuv_r), P3YuvRed());
-
- Color yuv_g = srgbRgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv709To601(yuv_g), P3YuvGreen());
-
- Color yuv_b = srgbRgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv709To601(yuv_b), P3YuvBlue());
-}
-
-TEST_F(GainMapMathTest, Bt709ToBt2100YuvConversion) {
- Color yuv_black = srgbRgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv709To2100(yuv_black), YuvBlack());
-
- Color yuv_white = srgbRgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv709To2100(yuv_white), YuvWhite());
-
- Color yuv_r = srgbRgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv709To2100(yuv_r), Bt2100YuvRed());
-
- Color yuv_g = srgbRgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv709To2100(yuv_g), Bt2100YuvGreen());
-
- Color yuv_b = srgbRgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv709To2100(yuv_b), Bt2100YuvBlue());
-}
-
-TEST_F(GainMapMathTest, Bt601ToBt709YuvConversion) {
- Color yuv_black = p3RgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv601To709(yuv_black), YuvBlack());
-
- Color yuv_white = p3RgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv601To709(yuv_white), YuvWhite());
-
- Color yuv_r = p3RgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv601To709(yuv_r), SrgbYuvRed());
-
- Color yuv_g = p3RgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv601To709(yuv_g), SrgbYuvGreen());
-
- Color yuv_b = p3RgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv601To709(yuv_b), SrgbYuvBlue());
-}
-
-TEST_F(GainMapMathTest, Bt601ToBt2100YuvConversion) {
- Color yuv_black = p3RgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv601To2100(yuv_black), YuvBlack());
-
- Color yuv_white = p3RgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv601To2100(yuv_white), YuvWhite());
-
- Color yuv_r = p3RgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv601To2100(yuv_r), Bt2100YuvRed());
-
- Color yuv_g = p3RgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv601To2100(yuv_g), Bt2100YuvGreen());
-
- Color yuv_b = p3RgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv601To2100(yuv_b), Bt2100YuvBlue());
-}
-
-TEST_F(GainMapMathTest, Bt2100ToBt709YuvConversion) {
- Color yuv_black = bt2100RgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv2100To709(yuv_black), YuvBlack());
-
- Color yuv_white = bt2100RgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv2100To709(yuv_white), YuvWhite());
-
- Color yuv_r = bt2100RgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv2100To709(yuv_r), SrgbYuvRed());
-
- Color yuv_g = bt2100RgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv2100To709(yuv_g), SrgbYuvGreen());
-
- Color yuv_b = bt2100RgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv2100To709(yuv_b), SrgbYuvBlue());
-}
-
-TEST_F(GainMapMathTest, Bt2100ToBt601YuvConversion) {
- Color yuv_black = bt2100RgbToYuv(RgbBlack());
- EXPECT_YUV_NEAR(yuv2100To601(yuv_black), YuvBlack());
-
- Color yuv_white = bt2100RgbToYuv(RgbWhite());
- EXPECT_YUV_NEAR(yuv2100To601(yuv_white), YuvWhite());
-
- Color yuv_r = bt2100RgbToYuv(RgbRed());
- EXPECT_YUV_NEAR(yuv2100To601(yuv_r), P3YuvRed());
-
- Color yuv_g = bt2100RgbToYuv(RgbGreen());
- EXPECT_YUV_NEAR(yuv2100To601(yuv_g), P3YuvGreen());
-
- Color yuv_b = bt2100RgbToYuv(RgbBlue());
- EXPECT_YUV_NEAR(yuv2100To601(yuv_b), P3YuvBlue());
-}
-
-TEST_F(GainMapMathTest, TransformYuv420) {
- ColorTransformFn transforms[] = { yuv709To601, yuv709To2100, yuv601To709, yuv601To2100,
- yuv2100To709, yuv2100To601 };
- for (const ColorTransformFn& transform : transforms) {
- jpegr_uncompressed_struct input = Yuv420Image();
-
- size_t out_buf_size = input.width * input.height * 3 / 2;
- std::unique_ptr<uint8_t[]> out_buf = std::make_unique<uint8_t[]>(out_buf_size);
- memcpy(out_buf.get(), input.data, out_buf_size);
- jpegr_uncompressed_struct output = Yuv420Image();
- output.data = out_buf.get();
- output.chroma_data = out_buf.get() + input.width * input.height;
- output.luma_stride = input.width;
- output.chroma_stride = input.width / 2;
-
- transformYuv420(&output, 1, 1, transform);
-
- for (size_t y = 0; y < 4; ++y) {
- for (size_t x = 0; x < 4; ++x) {
- // Skip the last chroma sample, which we modified above
- if (x >= 2 && y >= 2) {
- continue;
- }
-
- // All other pixels should remain unchanged
- EXPECT_YUV_EQ(getYuv420Pixel(&input, x, y), getYuv420Pixel(&output, x, y));
- }
- }
-
- // modified pixels should be updated as intended by the transformYuv420 algorithm
- Color in1 = getYuv420Pixel(&input, 2, 2);
- Color in2 = getYuv420Pixel(&input, 3, 2);
- Color in3 = getYuv420Pixel(&input, 2, 3);
- Color in4 = getYuv420Pixel(&input, 3, 3);
- Color out1 = getYuv420Pixel(&output, 2, 2);
- Color out2 = getYuv420Pixel(&output, 3, 2);
- Color out3 = getYuv420Pixel(&output, 2, 3);
- Color out4 = getYuv420Pixel(&output, 3, 3);
-
- EXPECT_NEAR(transform(in1).y, out1.y, YuvConversionEpsilon());
- EXPECT_NEAR(transform(in2).y, out2.y, YuvConversionEpsilon());
- EXPECT_NEAR(transform(in3).y, out3.y, YuvConversionEpsilon());
- EXPECT_NEAR(transform(in4).y, out4.y, YuvConversionEpsilon());
-
- Color expect_uv = (transform(in1) + transform(in2) + transform(in3) + transform(in4)) / 4.0f;
-
- EXPECT_NEAR(expect_uv.u, out1.u, YuvConversionEpsilon());
- EXPECT_NEAR(expect_uv.u, out2.u, YuvConversionEpsilon());
- EXPECT_NEAR(expect_uv.u, out3.u, YuvConversionEpsilon());
- EXPECT_NEAR(expect_uv.u, out4.u, YuvConversionEpsilon());
-
- EXPECT_NEAR(expect_uv.v, out1.v, YuvConversionEpsilon());
- EXPECT_NEAR(expect_uv.v, out2.v, YuvConversionEpsilon());
- EXPECT_NEAR(expect_uv.v, out3.v, YuvConversionEpsilon());
- EXPECT_NEAR(expect_uv.v, out4.v, YuvConversionEpsilon());
- }
-}
-
-TEST_F(GainMapMathTest, HlgOetf) {
- EXPECT_FLOAT_EQ(hlgOetf(0.0f), 0.0f);
- EXPECT_NEAR(hlgOetf(0.04167f), 0.35357f, ComparisonEpsilon());
- EXPECT_NEAR(hlgOetf(0.08333f), 0.5f, ComparisonEpsilon());
- EXPECT_NEAR(hlgOetf(0.5f), 0.87164f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(hlgOetf(1.0f), 1.0f);
-
- Color e = {{{ 0.04167f, 0.08333f, 0.5f }}};
- Color e_gamma = {{{ 0.35357f, 0.5f, 0.87164f }}};
- EXPECT_RGB_NEAR(hlgOetf(e), e_gamma);
-}
-
-TEST_F(GainMapMathTest, HlgInvOetf) {
- EXPECT_FLOAT_EQ(hlgInvOetf(0.0f), 0.0f);
- EXPECT_NEAR(hlgInvOetf(0.25f), 0.02083f, ComparisonEpsilon());
- EXPECT_NEAR(hlgInvOetf(0.5f), 0.08333f, ComparisonEpsilon());
- EXPECT_NEAR(hlgInvOetf(0.75f), 0.26496f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(hlgInvOetf(1.0f), 1.0f);
-
- Color e_gamma = {{{ 0.25f, 0.5f, 0.75f }}};
- Color e = {{{ 0.02083f, 0.08333f, 0.26496f }}};
- EXPECT_RGB_NEAR(hlgInvOetf(e_gamma), e);
-}
-
-TEST_F(GainMapMathTest, HlgTransferFunctionRoundtrip) {
- EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(0.0f)), 0.0f);
- EXPECT_NEAR(hlgInvOetf(hlgOetf(0.04167f)), 0.04167f, ComparisonEpsilon());
- EXPECT_NEAR(hlgInvOetf(hlgOetf(0.08333f)), 0.08333f, ComparisonEpsilon());
- EXPECT_NEAR(hlgInvOetf(hlgOetf(0.5f)), 0.5f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(1.0f)), 1.0f);
-}
-
-TEST_F(GainMapMathTest, PqOetf) {
- EXPECT_FLOAT_EQ(pqOetf(0.0f), 0.0f);
- EXPECT_NEAR(pqOetf(0.01f), 0.50808f, ComparisonEpsilon());
- EXPECT_NEAR(pqOetf(0.5f), 0.92655f, ComparisonEpsilon());
- EXPECT_NEAR(pqOetf(0.99f), 0.99895f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(pqOetf(1.0f), 1.0f);
-
- Color e = {{{ 0.01f, 0.5f, 0.99f }}};
- Color e_gamma = {{{ 0.50808f, 0.92655f, 0.99895f }}};
- EXPECT_RGB_NEAR(pqOetf(e), e_gamma);
-}
-
-TEST_F(GainMapMathTest, PqInvOetf) {
- EXPECT_FLOAT_EQ(pqInvOetf(0.0f), 0.0f);
- EXPECT_NEAR(pqInvOetf(0.01f), 2.31017e-7f, ComparisonEpsilon());
- EXPECT_NEAR(pqInvOetf(0.5f), 0.00922f, ComparisonEpsilon());
- EXPECT_NEAR(pqInvOetf(0.99f), 0.90903f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(pqInvOetf(1.0f), 1.0f);
-
- Color e_gamma = {{{ 0.01f, 0.5f, 0.99f }}};
- Color e = {{{ 2.31017e-7f, 0.00922f, 0.90903f }}};
- EXPECT_RGB_NEAR(pqInvOetf(e_gamma), e);
-}
-
-TEST_F(GainMapMathTest, PqInvOetfLUT) {
- for (int idx = 0; idx < kPqInvOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kPqInvOETFNumEntries - 1);
- EXPECT_FLOAT_EQ(pqInvOetf(value), pqInvOetfLUT(value));
- }
-}
-
-TEST_F(GainMapMathTest, HlgInvOetfLUT) {
- for (int idx = 0; idx < kHlgInvOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kHlgInvOETFNumEntries - 1);
- EXPECT_FLOAT_EQ(hlgInvOetf(value), hlgInvOetfLUT(value));
- }
-}
-
-TEST_F(GainMapMathTest, pqOetfLUT) {
- for (int idx = 0; idx < kPqOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kPqOETFNumEntries - 1);
- EXPECT_FLOAT_EQ(pqOetf(value), pqOetfLUT(value));
- }
-}
-
-TEST_F(GainMapMathTest, hlgOetfLUT) {
- for (int idx = 0; idx < kHlgOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kHlgOETFNumEntries - 1);
- EXPECT_FLOAT_EQ(hlgOetf(value), hlgOetfLUT(value));
- }
-}
-
-TEST_F(GainMapMathTest, srgbInvOetfLUT) {
- for (int idx = 0; idx < kSrgbInvOETFNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kSrgbInvOETFNumEntries - 1);
- EXPECT_FLOAT_EQ(srgbInvOetf(value), srgbInvOetfLUT(value));
- }
-}
-
-TEST_F(GainMapMathTest, applyGainLUT) {
- for (int boost = 1; boost <= 10; boost++) {
- ultrahdr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
- .minContentBoost = 1.0f / static_cast<float>(boost) };
- GainLUT gainLUT(&metadata);
- GainLUT gainLUTWithBoost(&metadata, metadata.maxContentBoost);
- for (int idx = 0; idx < kGainFactorNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
- EXPECT_RGB_NEAR(applyGain(RgbBlack(), value, &metadata),
- applyGainLUT(RgbBlack(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), value, &metadata),
- applyGainLUT(RgbWhite(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbRed(), value, &metadata),
- applyGainLUT(RgbRed(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbGreen(), value, &metadata),
- applyGainLUT(RgbGreen(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbBlue(), value, &metadata),
- applyGainLUT(RgbBlue(), value, gainLUT));
- EXPECT_RGB_EQ(applyGainLUT(RgbBlack(), value, gainLUT),
- applyGainLUT(RgbBlack(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbWhite(), value, gainLUT),
- applyGainLUT(RgbWhite(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbRed(), value, gainLUT),
- applyGainLUT(RgbRed(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbGreen(), value, gainLUT),
- applyGainLUT(RgbGreen(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbBlue(), value, gainLUT),
- applyGainLUT(RgbBlue(), value, gainLUTWithBoost));
- }
- }
-
- for (int boost = 1; boost <= 10; boost++) {
- ultrahdr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
- .minContentBoost = 1.0f };
- GainLUT gainLUT(&metadata);
- GainLUT gainLUTWithBoost(&metadata, metadata.maxContentBoost);
- for (int idx = 0; idx < kGainFactorNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
- EXPECT_RGB_NEAR(applyGain(RgbBlack(), value, &metadata),
- applyGainLUT(RgbBlack(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), value, &metadata),
- applyGainLUT(RgbWhite(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbRed(), value, &metadata),
- applyGainLUT(RgbRed(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbGreen(), value, &metadata),
- applyGainLUT(RgbGreen(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbBlue(), value, &metadata),
- applyGainLUT(RgbBlue(), value, gainLUT));
- EXPECT_RGB_EQ(applyGainLUT(RgbBlack(), value, gainLUT),
- applyGainLUT(RgbBlack(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbWhite(), value, gainLUT),
- applyGainLUT(RgbWhite(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbRed(), value, gainLUT),
- applyGainLUT(RgbRed(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbGreen(), value, gainLUT),
- applyGainLUT(RgbGreen(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbBlue(), value, gainLUT),
- applyGainLUT(RgbBlue(), value, gainLUTWithBoost));
- }
- }
-
- for (int boost = 1; boost <= 10; boost++) {
- ultrahdr_metadata_struct metadata = { .maxContentBoost = static_cast<float>(boost),
- .minContentBoost = 1.0f / pow(static_cast<float>(boost),
- 1.0f / 3.0f) };
- GainLUT gainLUT(&metadata);
- GainLUT gainLUTWithBoost(&metadata, metadata.maxContentBoost);
- for (int idx = 0; idx < kGainFactorNumEntries; idx++) {
- float value = static_cast<float>(idx) / static_cast<float>(kGainFactorNumEntries - 1);
- EXPECT_RGB_NEAR(applyGain(RgbBlack(), value, &metadata),
- applyGainLUT(RgbBlack(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), value, &metadata),
- applyGainLUT(RgbWhite(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbRed(), value, &metadata),
- applyGainLUT(RgbRed(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbGreen(), value, &metadata),
- applyGainLUT(RgbGreen(), value, gainLUT));
- EXPECT_RGB_NEAR(applyGain(RgbBlue(), value, &metadata),
- applyGainLUT(RgbBlue(), value, gainLUT));
- EXPECT_RGB_EQ(applyGainLUT(RgbBlack(), value, gainLUT),
- applyGainLUT(RgbBlack(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbWhite(), value, gainLUT),
- applyGainLUT(RgbWhite(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbRed(), value, gainLUT),
- applyGainLUT(RgbRed(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbGreen(), value, gainLUT),
- applyGainLUT(RgbGreen(), value, gainLUTWithBoost));
- EXPECT_RGB_EQ(applyGainLUT(RgbBlue(), value, gainLUT),
- applyGainLUT(RgbBlue(), value, gainLUTWithBoost));
- }
- }
-}
-
-TEST_F(GainMapMathTest, PqTransferFunctionRoundtrip) {
- EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(0.0f)), 0.0f);
- EXPECT_NEAR(pqInvOetf(pqOetf(0.01f)), 0.01f, ComparisonEpsilon());
- EXPECT_NEAR(pqInvOetf(pqOetf(0.5f)), 0.5f, ComparisonEpsilon());
- EXPECT_NEAR(pqInvOetf(pqOetf(0.99f)), 0.99f, ComparisonEpsilon());
- EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(1.0f)), 1.0f);
-}
-
-TEST_F(GainMapMathTest, ColorConversionLookup) {
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_UNSPECIFIED),
- nullptr);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_BT709),
- identityConversion);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3),
- p3ToBt709);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_BT2100),
- bt2100ToBt709);
-
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_UNSPECIFIED),
- nullptr);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT709),
- bt709ToP3);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_P3),
- identityConversion);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_P3, ULTRAHDR_COLORGAMUT_BT2100),
- bt2100ToP3);
-
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT2100, ULTRAHDR_COLORGAMUT_UNSPECIFIED),
- nullptr);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT2100, ULTRAHDR_COLORGAMUT_BT709),
- bt709ToBt2100);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT2100, ULTRAHDR_COLORGAMUT_P3),
- p3ToBt2100);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_BT2100, ULTRAHDR_COLORGAMUT_BT2100),
- identityConversion);
-
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_UNSPECIFIED, ULTRAHDR_COLORGAMUT_UNSPECIFIED),
- nullptr);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_UNSPECIFIED, ULTRAHDR_COLORGAMUT_BT709),
- nullptr);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_UNSPECIFIED, ULTRAHDR_COLORGAMUT_P3),
- nullptr);
- EXPECT_EQ(getHdrConversionFn(ULTRAHDR_COLORGAMUT_UNSPECIFIED, ULTRAHDR_COLORGAMUT_BT2100),
- nullptr);
-}
-
-TEST_F(GainMapMathTest, EncodeGain) {
- ultrahdr_metadata_struct metadata = { .maxContentBoost = 4.0f,
- .minContentBoost = 1.0f / 4.0f };
-
- EXPECT_EQ(encodeGain(0.0f, 0.0f, &metadata), 127);
- EXPECT_EQ(encodeGain(0.0f, 1.0f, &metadata), 127);
- EXPECT_EQ(encodeGain(1.0f, 0.0f, &metadata), 0);
- EXPECT_EQ(encodeGain(0.5f, 0.0f, &metadata), 0);
-
- EXPECT_EQ(encodeGain(1.0f, 1.0f, &metadata), 127);
- EXPECT_EQ(encodeGain(1.0f, 4.0f, &metadata), 255);
- EXPECT_EQ(encodeGain(1.0f, 5.0f, &metadata), 255);
- EXPECT_EQ(encodeGain(4.0f, 1.0f, &metadata), 0);
- EXPECT_EQ(encodeGain(4.0f, 0.5f, &metadata), 0);
- EXPECT_EQ(encodeGain(1.0f, 2.0f, &metadata), 191);
- EXPECT_EQ(encodeGain(2.0f, 1.0f, &metadata), 63);
-
- metadata.maxContentBoost = 2.0f;
- metadata.minContentBoost = 1.0f / 2.0f;
-
- EXPECT_EQ(encodeGain(1.0f, 2.0f, &metadata), 255);
- EXPECT_EQ(encodeGain(2.0f, 1.0f, &metadata), 0);
- EXPECT_EQ(encodeGain(1.0f, 1.41421f, &metadata), 191);
- EXPECT_EQ(encodeGain(1.41421f, 1.0f, &metadata), 63);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 1.0f / 8.0f;
-
- EXPECT_EQ(encodeGain(1.0f, 8.0f, &metadata), 255);
- EXPECT_EQ(encodeGain(8.0f, 1.0f, &metadata), 0);
- EXPECT_EQ(encodeGain(1.0f, 2.82843f, &metadata), 191);
- EXPECT_EQ(encodeGain(2.82843f, 1.0f, &metadata), 63);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 1.0f;
-
- EXPECT_EQ(encodeGain(0.0f, 0.0f, &metadata), 0);
- EXPECT_EQ(encodeGain(1.0f, 0.0f, &metadata), 0);
-
- EXPECT_EQ(encodeGain(1.0f, 1.0f, &metadata), 0);
- EXPECT_EQ(encodeGain(1.0f, 8.0f, &metadata), 255);
- EXPECT_EQ(encodeGain(1.0f, 4.0f, &metadata), 170);
- EXPECT_EQ(encodeGain(1.0f, 2.0f, &metadata), 85);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 0.5f;
-
- EXPECT_EQ(encodeGain(0.0f, 0.0f, &metadata), 63);
- EXPECT_EQ(encodeGain(1.0f, 0.0f, &metadata), 0);
-
- EXPECT_EQ(encodeGain(1.0f, 1.0f, &metadata), 63);
- EXPECT_EQ(encodeGain(1.0f, 8.0f, &metadata), 255);
- EXPECT_EQ(encodeGain(1.0f, 4.0f, &metadata), 191);
- EXPECT_EQ(encodeGain(1.0f, 2.0f, &metadata), 127);
- EXPECT_EQ(encodeGain(1.0f, 0.7071f, &metadata), 31);
- EXPECT_EQ(encodeGain(1.0f, 0.5f, &metadata), 0);
-}
-
-TEST_F(GainMapMathTest, ApplyGain) {
- ultrahdr_metadata_struct metadata = { .maxContentBoost = 4.0f,
- .minContentBoost = 1.0f / 4.0f };
- float displayBoost = metadata.maxContentBoost;
-
- EXPECT_RGB_NEAR(applyGain(RgbBlack(), 0.0f, &metadata), RgbBlack());
- EXPECT_RGB_NEAR(applyGain(RgbBlack(), 0.5f, &metadata), RgbBlack());
- EXPECT_RGB_NEAR(applyGain(RgbBlack(), 1.0f, &metadata), RgbBlack());
-
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.0f, &metadata), RgbWhite() / 4.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.25f, &metadata), RgbWhite() / 2.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.5f, &metadata), RgbWhite());
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.75f, &metadata), RgbWhite() * 2.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 1.0f, &metadata), RgbWhite() * 4.0f);
-
- metadata.maxContentBoost = 2.0f;
- metadata.minContentBoost = 1.0f / 2.0f;
-
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.0f, &metadata), RgbWhite() / 2.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.25f, &metadata), RgbWhite() / 1.41421f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.5f, &metadata), RgbWhite());
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.75f, &metadata), RgbWhite() * 1.41421f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 1.0f, &metadata), RgbWhite() * 2.0f);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 1.0f / 8.0f;
-
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.0f, &metadata), RgbWhite() / 8.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.25f, &metadata), RgbWhite() / 2.82843f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.5f, &metadata), RgbWhite());
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.75f, &metadata), RgbWhite() * 2.82843f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 1.0f, &metadata), RgbWhite() * 8.0f);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 1.0f;
-
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.0f, &metadata), RgbWhite());
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 1.0f / 3.0f, &metadata), RgbWhite() * 2.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 2.0f / 3.0f, &metadata), RgbWhite() * 4.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 1.0f, &metadata), RgbWhite() * 8.0f);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 0.5f;
-
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.0f, &metadata), RgbWhite() / 2.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.25f, &metadata), RgbWhite());
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.5f, &metadata), RgbWhite() * 2.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 0.75f, &metadata), RgbWhite() * 4.0f);
- EXPECT_RGB_NEAR(applyGain(RgbWhite(), 1.0f, &metadata), RgbWhite() * 8.0f);
-
- Color e = {{{ 0.0f, 0.5f, 1.0f }}};
- metadata.maxContentBoost = 4.0f;
- metadata.minContentBoost = 1.0f / 4.0f;
-
- EXPECT_RGB_NEAR(applyGain(e, 0.0f, &metadata), e / 4.0f);
- EXPECT_RGB_NEAR(applyGain(e, 0.25f, &metadata), e / 2.0f);
- EXPECT_RGB_NEAR(applyGain(e, 0.5f, &metadata), e);
- EXPECT_RGB_NEAR(applyGain(e, 0.75f, &metadata), e * 2.0f);
- EXPECT_RGB_NEAR(applyGain(e, 1.0f, &metadata), e * 4.0f);
-
- EXPECT_RGB_EQ(applyGain(RgbBlack(), 1.0f, &metadata),
- applyGain(RgbBlack(), 1.0f, &metadata, displayBoost));
- EXPECT_RGB_EQ(applyGain(RgbWhite(), 1.0f, &metadata),
- applyGain(RgbWhite(), 1.0f, &metadata, displayBoost));
- EXPECT_RGB_EQ(applyGain(RgbRed(), 1.0f, &metadata),
- applyGain(RgbRed(), 1.0f, &metadata, displayBoost));
- EXPECT_RGB_EQ(applyGain(RgbGreen(), 1.0f, &metadata),
- applyGain(RgbGreen(), 1.0f, &metadata, displayBoost));
- EXPECT_RGB_EQ(applyGain(RgbBlue(), 1.0f, &metadata),
- applyGain(RgbBlue(), 1.0f, &metadata, displayBoost));
- EXPECT_RGB_EQ(applyGain(e, 1.0f, &metadata),
- applyGain(e, 1.0f, &metadata, displayBoost));
-}
-
-TEST_F(GainMapMathTest, GetYuv420Pixel) {
- jpegr_uncompressed_struct image = Yuv420Image();
- Color (*colors)[4] = Yuv420Colors();
-
- for (size_t y = 0; y < 4; ++y) {
- for (size_t x = 0; x < 4; ++x) {
- EXPECT_YUV_NEAR(getYuv420Pixel(&image, x, y), colors[y][x]);
- }
- }
-}
-
-TEST_F(GainMapMathTest, GetP010Pixel) {
- jpegr_uncompressed_struct image = P010Image();
- Color (*colors)[4] = P010Colors();
-
- for (size_t y = 0; y < 4; ++y) {
- for (size_t x = 0; x < 4; ++x) {
- EXPECT_YUV_NEAR(getP010Pixel(&image, x, y), colors[y][x]);
- }
- }
-}
-
-TEST_F(GainMapMathTest, SampleYuv420) {
- jpegr_uncompressed_struct image = Yuv420Image();
- Color (*colors)[4] = Yuv420Colors();
-
- static const size_t kMapScaleFactor = 2;
- for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) {
- for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) {
- Color min = {{{ 1.0f, 1.0f, 1.0f }}};
- Color max = {{{ -1.0f, -1.0f, -1.0f }}};
-
- for (size_t dy = 0; dy < kMapScaleFactor; ++dy) {
- for (size_t dx = 0; dx < kMapScaleFactor; ++dx) {
- Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx];
- min = ColorMin(min, e);
- max = ColorMax(max, e);
- }
- }
-
- // Instead of reimplementing the sampling algorithm, confirm that the
- // sample output is within the range of the min and max of the nearest
- // points.
- EXPECT_YUV_BETWEEN(sampleYuv420(&image, kMapScaleFactor, x, y), min, max);
- }
- }
-}
-
-TEST_F(GainMapMathTest, SampleP010) {
- jpegr_uncompressed_struct image = P010Image();
- Color (*colors)[4] = P010Colors();
-
- static const size_t kMapScaleFactor = 2;
- for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) {
- for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) {
- Color min = {{{ 1.0f, 1.0f, 1.0f }}};
- Color max = {{{ -1.0f, -1.0f, -1.0f }}};
-
- for (size_t dy = 0; dy < kMapScaleFactor; ++dy) {
- for (size_t dx = 0; dx < kMapScaleFactor; ++dx) {
- Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx];
- min = ColorMin(min, e);
- max = ColorMax(max, e);
- }
- }
-
- // Instead of reimplementing the sampling algorithm, confirm that the
- // sample output is within the range of the min and max of the nearest
- // points.
- EXPECT_YUV_BETWEEN(sampleP010(&image, kMapScaleFactor, x, y), min, max);
- }
- }
-}
-
-TEST_F(GainMapMathTest, SampleMap) {
- jpegr_uncompressed_struct image = MapImage();
- float (*values)[4] = MapValues();
-
- static const size_t kMapScaleFactor = 2;
- ShepardsIDW idwTable(kMapScaleFactor);
- for (size_t y = 0; y < 4 * kMapScaleFactor; ++y) {
- for (size_t x = 0; x < 4 * kMapScaleFactor; ++x) {
- size_t x_base = x / kMapScaleFactor;
- size_t y_base = y / kMapScaleFactor;
-
- float min = 1.0f;
- float max = -1.0f;
-
- min = fmin(min, values[y_base][x_base]);
- max = fmax(max, values[y_base][x_base]);
- if (y_base + 1 < 4) {
- min = fmin(min, values[y_base + 1][x_base]);
- max = fmax(max, values[y_base + 1][x_base]);
- }
- if (x_base + 1 < 4) {
- min = fmin(min, values[y_base][x_base + 1]);
- max = fmax(max, values[y_base][x_base + 1]);
- }
- if (y_base + 1 < 4 && x_base + 1 < 4) {
- min = fmin(min, values[y_base + 1][x_base + 1]);
- max = fmax(max, values[y_base + 1][x_base + 1]);
- }
-
- // Instead of reimplementing the sampling algorithm, confirm that the
- // sample output is within the range of the min and max of the nearest
- // points.
- EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y),
- testing::AllOf(testing::Ge(min), testing::Le(max)));
- EXPECT_EQ(sampleMap(&image, kMapScaleFactor, x, y, idwTable),
- sampleMap(&image, kMapScaleFactor, x, y));
- }
- }
-}
-
-TEST_F(GainMapMathTest, ColorToRgba1010102) {
- EXPECT_EQ(colorToRgba1010102(RgbBlack()), 0x3 << 30);
- EXPECT_EQ(colorToRgba1010102(RgbWhite()), 0xFFFFFFFF);
- EXPECT_EQ(colorToRgba1010102(RgbRed()), 0x3 << 30 | 0x3ff);
- EXPECT_EQ(colorToRgba1010102(RgbGreen()), 0x3 << 30 | 0x3ff << 10);
- EXPECT_EQ(colorToRgba1010102(RgbBlue()), 0x3 << 30 | 0x3ff << 20);
-
- Color e_gamma = {{{ 0.1f, 0.2f, 0.3f }}};
- EXPECT_EQ(colorToRgba1010102(e_gamma),
- 0x3 << 30
- | static_cast<uint32_t>(0.1f * static_cast<float>(0x3ff))
- | static_cast<uint32_t>(0.2f * static_cast<float>(0x3ff)) << 10
- | static_cast<uint32_t>(0.3f * static_cast<float>(0x3ff)) << 20);
-}
-
-TEST_F(GainMapMathTest, ColorToRgbaF16) {
- EXPECT_EQ(colorToRgbaF16(RgbBlack()), ((uint64_t) 0x3C00) << 48);
- EXPECT_EQ(colorToRgbaF16(RgbWhite()), 0x3C003C003C003C00);
- EXPECT_EQ(colorToRgbaF16(RgbRed()), (((uint64_t) 0x3C00) << 48) | ((uint64_t) 0x3C00));
- EXPECT_EQ(colorToRgbaF16(RgbGreen()), (((uint64_t) 0x3C00) << 48) | (((uint64_t) 0x3C00) << 16));
- EXPECT_EQ(colorToRgbaF16(RgbBlue()), (((uint64_t) 0x3C00) << 48) | (((uint64_t) 0x3C00) << 32));
-
- Color e_gamma = {{{ 0.1f, 0.2f, 0.3f }}};
- EXPECT_EQ(colorToRgbaF16(e_gamma), 0x3C0034CD32662E66);
-}
-
-TEST_F(GainMapMathTest, Float32ToFloat16) {
- EXPECT_EQ(floatToHalf(0.1f), 0x2E66);
- EXPECT_EQ(floatToHalf(0.0f), 0x0);
- EXPECT_EQ(floatToHalf(1.0f), 0x3C00);
- EXPECT_EQ(floatToHalf(-1.0f), 0xBC00);
- EXPECT_EQ(floatToHalf(0x1.fffffep127f), 0x7FFF); // float max
- EXPECT_EQ(floatToHalf(-0x1.fffffep127f), 0xFFFF); // float min
- EXPECT_EQ(floatToHalf(0x1.0p-126f), 0x0); // float zero
-}
-
-TEST_F(GainMapMathTest, GenerateMapLuminanceSrgb) {
- EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), srgbLuminance),
- 0.0f);
- EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), srgbLuminance),
- kSdrWhiteNits);
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), srgbLuminance),
- srgbLuminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), srgbLuminance),
- srgbLuminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), srgbLuminance),
- srgbLuminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
-}
-
-TEST_F(GainMapMathTest, GenerateMapLuminanceSrgbP3) {
- EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), p3Luminance),
- 0.0f);
- EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), p3Luminance),
- kSdrWhiteNits);
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), p3Luminance),
- p3Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), p3Luminance),
- p3Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), p3Luminance),
- p3Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
-}
-
-TEST_F(GainMapMathTest, GenerateMapLuminanceSrgbBt2100) {
- EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), bt2100Luminance),
- 0.0f);
- EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), bt2100Luminance),
- kSdrWhiteNits);
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), bt2100Luminance),
- bt2100Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), bt2100Luminance),
- bt2100Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
- EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), bt2100Luminance),
- bt2100Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
-}
-
-TEST_F(GainMapMathTest, GenerateMapLuminanceHlg) {
- EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), hlgInvOetf, identityConversion,
- bt2100Luminance, kHlgMaxNits),
- 0.0f);
- EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), hlgInvOetf, identityConversion,
- bt2100Luminance, kHlgMaxNits),
- kHlgMaxNits);
- EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), hlgInvOetf, identityConversion,
- bt2100Luminance, kHlgMaxNits),
- bt2100Luminance(RgbRed()) * kHlgMaxNits, LuminanceEpsilon());
- EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), hlgInvOetf, identityConversion,
- bt2100Luminance, kHlgMaxNits),
- bt2100Luminance(RgbGreen()) * kHlgMaxNits, LuminanceEpsilon());
- EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), hlgInvOetf, identityConversion,
- bt2100Luminance, kHlgMaxNits),
- bt2100Luminance(RgbBlue()) * kHlgMaxNits, LuminanceEpsilon());
-}
-
-TEST_F(GainMapMathTest, GenerateMapLuminancePq) {
- EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), pqInvOetf, identityConversion,
- bt2100Luminance, kPqMaxNits),
- 0.0f);
- EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), pqInvOetf, identityConversion,
- bt2100Luminance, kPqMaxNits),
- kPqMaxNits);
- EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), pqInvOetf, identityConversion,
- bt2100Luminance, kPqMaxNits),
- bt2100Luminance(RgbRed()) * kPqMaxNits, LuminanceEpsilon());
- EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), pqInvOetf, identityConversion,
- bt2100Luminance, kPqMaxNits),
- bt2100Luminance(RgbGreen()) * kPqMaxNits, LuminanceEpsilon());
- EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), pqInvOetf, identityConversion,
- bt2100Luminance, kPqMaxNits),
- bt2100Luminance(RgbBlue()) * kPqMaxNits, LuminanceEpsilon());
-}
-
-TEST_F(GainMapMathTest, ApplyMap) {
- ultrahdr_metadata_struct metadata = { .maxContentBoost = 8.0f,
- .minContentBoost = 1.0f / 8.0f };
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
- RgbWhite() * 8.0f);
- EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, &metadata),
- RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, &metadata),
- RgbRed() * 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, &metadata),
- RgbGreen() * 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, &metadata),
- RgbBlue() * 8.0f);
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.75f, &metadata),
- RgbWhite() * sqrt(8.0f));
- EXPECT_RGB_EQ(Recover(YuvBlack(), 0.75f, &metadata),
- RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.75f, &metadata),
- RgbRed() * sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.75f, &metadata),
- RgbGreen() * sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.75f, &metadata),
- RgbBlue() * sqrt(8.0f));
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, &metadata),
- RgbWhite());
- EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, &metadata),
- RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, &metadata),
- RgbRed());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, &metadata),
- RgbGreen());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, &metadata),
- RgbBlue());
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.25f, &metadata),
- RgbWhite() / sqrt(8.0f));
- EXPECT_RGB_EQ(Recover(YuvBlack(), 0.25f, &metadata),
- RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.25f, &metadata),
- RgbRed() / sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.25f, &metadata),
- RgbGreen() / sqrt(8.0f));
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.25f, &metadata),
- RgbBlue() / sqrt(8.0f));
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, &metadata),
- RgbWhite() / 8.0f);
- EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, &metadata),
- RgbBlack());
- EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, &metadata),
- RgbRed() / 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, &metadata),
- RgbGreen() / 8.0f);
- EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, &metadata),
- RgbBlue() / 8.0f);
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 1.0f;
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
- RgbWhite() * 8.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 2.0f / 3.0f, &metadata),
- RgbWhite() * 4.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f / 3.0f, &metadata),
- RgbWhite() * 2.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, &metadata),
- RgbWhite());
-
- metadata.maxContentBoost = 8.0f;
- metadata.minContentBoost = 0.5f;;
-
- EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, &metadata),
- RgbWhite() * 8.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.75, &metadata),
- RgbWhite() * 4.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, &metadata),
- RgbWhite() * 2.0f);
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.25f, &metadata),
- RgbWhite());
- EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, &metadata),
- RgbWhite() / 2.0f);
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/tests/icchelper_test.cpp b/libs/ultrahdr/tests/icchelper_test.cpp
deleted file mode 100644
index ff61c08..0000000
--- a/libs/ultrahdr/tests/icchelper_test.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2022 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 <gtest/gtest.h>
-#include <ultrahdr/icc.h>
-#include <ultrahdr/ultrahdr.h>
-#include <utils/Log.h>
-
-namespace android::ultrahdr {
-
-class IccHelperTest : public testing::Test {
-public:
- IccHelperTest();
- ~IccHelperTest();
-protected:
- virtual void SetUp();
- virtual void TearDown();
-};
-
-IccHelperTest::IccHelperTest() {}
-
-IccHelperTest::~IccHelperTest() {}
-
-void IccHelperTest::SetUp() {}
-
-void IccHelperTest::TearDown() {}
-
-TEST_F(IccHelperTest, iccWriteThenRead) {
- sp<DataStruct> iccBt709 = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB,
- ULTRAHDR_COLORGAMUT_BT709);
- ASSERT_NE(iccBt709->getLength(), 0);
- ASSERT_NE(iccBt709->getData(), nullptr);
- EXPECT_EQ(IccHelper::readIccColorGamut(iccBt709->getData(), iccBt709->getLength()),
- ULTRAHDR_COLORGAMUT_BT709);
-
- sp<DataStruct> iccP3 = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, ULTRAHDR_COLORGAMUT_P3);
- ASSERT_NE(iccP3->getLength(), 0);
- ASSERT_NE(iccP3->getData(), nullptr);
- EXPECT_EQ(IccHelper::readIccColorGamut(iccP3->getData(), iccP3->getLength()),
- ULTRAHDR_COLORGAMUT_P3);
-
- sp<DataStruct> iccBt2100 = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB,
- ULTRAHDR_COLORGAMUT_BT2100);
- ASSERT_NE(iccBt2100->getLength(), 0);
- ASSERT_NE(iccBt2100->getData(), nullptr);
- EXPECT_EQ(IccHelper::readIccColorGamut(iccBt2100->getData(), iccBt2100->getLength()),
- ULTRAHDR_COLORGAMUT_BT2100);
-}
-
-TEST_F(IccHelperTest, iccEndianness) {
- sp<DataStruct> icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, ULTRAHDR_COLORGAMUT_BT709);
- size_t profile_size = icc->getLength() - kICCIdentifierSize;
-
- uint8_t* icc_bytes = reinterpret_cast<uint8_t*>(icc->getData()) + kICCIdentifierSize;
- uint32_t encoded_size = static_cast<uint32_t>(icc_bytes[0]) << 24 |
- static_cast<uint32_t>(icc_bytes[1]) << 16 |
- static_cast<uint32_t>(icc_bytes[2]) << 8 |
- static_cast<uint32_t>(icc_bytes[3]);
-
- EXPECT_EQ(static_cast<size_t>(encoded_size), profile_size);
-}
-
-} // namespace android::ultrahdr
-
diff --git a/libs/ultrahdr/tests/jpegdecoderhelper_test.cpp b/libs/ultrahdr/tests/jpegdecoderhelper_test.cpp
deleted file mode 100644
index af0d59e..0000000
--- a/libs/ultrahdr/tests/jpegdecoderhelper_test.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2022 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 <gtest/gtest.h>
-#include <ultrahdr/icc.h>
-#include <ultrahdr/jpegdecoderhelper.h>
-#include <utils/Log.h>
-
-#include <fcntl.h>
-
-namespace android::ultrahdr {
-
-// No ICC or EXIF
-#define YUV_IMAGE "/data/local/tmp/minnie-320x240-yuv.jpg"
-#define YUV_IMAGE_SIZE 20193
-// Has ICC and EXIF
-#define YUV_ICC_IMAGE "/data/local/tmp/minnie-320x240-yuv-icc.jpg"
-#define YUV_ICC_IMAGE_SIZE 34266
-// No ICC or EXIF
-#define GREY_IMAGE "/data/local/tmp/minnie-320x240-y.jpg"
-#define GREY_IMAGE_SIZE 20193
-
-#define IMAGE_WIDTH 320
-#define IMAGE_HEIGHT 240
-
-class JpegDecoderHelperTest : public testing::Test {
-public:
- struct Image {
- std::unique_ptr<uint8_t[]> buffer;
- size_t size;
- };
- JpegDecoderHelperTest();
- ~JpegDecoderHelperTest();
-
-protected:
- virtual void SetUp();
- virtual void TearDown();
-
- Image mYuvImage, mYuvIccImage, mGreyImage;
-};
-
-JpegDecoderHelperTest::JpegDecoderHelperTest() {}
-
-JpegDecoderHelperTest::~JpegDecoderHelperTest() {}
-
-static size_t getFileSize(int fd) {
- struct stat st;
- if (fstat(fd, &st) < 0) {
- ALOGW("%s : fstat failed", __func__);
- return 0;
- }
- return st.st_size; // bytes
-}
-
-static bool loadFile(const char filename[], JpegDecoderHelperTest::Image* result) {
- int fd = open(filename, O_CLOEXEC);
- if (fd < 0) {
- return false;
- }
- int length = getFileSize(fd);
- if (length == 0) {
- close(fd);
- return false;
- }
- result->buffer.reset(new uint8_t[length]);
- if (read(fd, result->buffer.get(), length) != static_cast<ssize_t>(length)) {
- close(fd);
- return false;
- }
- close(fd);
- return true;
-}
-
-void JpegDecoderHelperTest::SetUp() {
- if (!loadFile(YUV_IMAGE, &mYuvImage)) {
- FAIL() << "Load file " << YUV_IMAGE << " failed";
- }
- mYuvImage.size = YUV_IMAGE_SIZE;
- if (!loadFile(YUV_ICC_IMAGE, &mYuvIccImage)) {
- FAIL() << "Load file " << YUV_ICC_IMAGE << " failed";
- }
- mYuvIccImage.size = YUV_ICC_IMAGE_SIZE;
- if (!loadFile(GREY_IMAGE, &mGreyImage)) {
- FAIL() << "Load file " << GREY_IMAGE << " failed";
- }
- mGreyImage.size = GREY_IMAGE_SIZE;
-}
-
-void JpegDecoderHelperTest::TearDown() {}
-
-TEST_F(JpegDecoderHelperTest, decodeYuvImage) {
- JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.decompressImage(mYuvImage.buffer.get(), mYuvImage.size));
- ASSERT_GT(decoder.getDecompressedImageSize(), static_cast<uint32_t>(0));
- EXPECT_EQ(IccHelper::readIccColorGamut(decoder.getICCPtr(), decoder.getICCSize()),
- ULTRAHDR_COLORGAMUT_UNSPECIFIED);
-}
-
-TEST_F(JpegDecoderHelperTest, decodeYuvIccImage) {
- JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.decompressImage(mYuvIccImage.buffer.get(), mYuvIccImage.size));
- ASSERT_GT(decoder.getDecompressedImageSize(), static_cast<uint32_t>(0));
- EXPECT_EQ(IccHelper::readIccColorGamut(decoder.getICCPtr(), decoder.getICCSize()),
- ULTRAHDR_COLORGAMUT_BT709);
-}
-
-TEST_F(JpegDecoderHelperTest, decodeGreyImage) {
- JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.decompressImage(mGreyImage.buffer.get(), mGreyImage.size));
- ASSERT_GT(decoder.getDecompressedImageSize(), static_cast<uint32_t>(0));
-}
-
-TEST_F(JpegDecoderHelperTest, getCompressedImageParameters) {
- size_t width = 0, height = 0;
- std::vector<uint8_t> icc, exif;
-
- JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvImage.buffer.get(), mYuvImage.size, &width,
- &height, &icc, &exif));
-
- EXPECT_EQ(width, IMAGE_WIDTH);
- EXPECT_EQ(height, IMAGE_HEIGHT);
- EXPECT_EQ(icc.size(), 0);
- EXPECT_EQ(exif.size(), 0);
-}
-
-TEST_F(JpegDecoderHelperTest, getCompressedImageParametersIcc) {
- size_t width = 0, height = 0;
- std::vector<uint8_t> icc, exif;
-
- JpegDecoderHelper decoder;
- EXPECT_TRUE(decoder.getCompressedImageParameters(mYuvIccImage.buffer.get(), mYuvIccImage.size,
- &width, &height, &icc, &exif));
-
- EXPECT_EQ(width, IMAGE_WIDTH);
- EXPECT_EQ(height, IMAGE_HEIGHT);
- EXPECT_GT(icc.size(), 0);
- EXPECT_GT(exif.size(), 0);
-
- EXPECT_EQ(IccHelper::readIccColorGamut(icc.data(), icc.size()), ULTRAHDR_COLORGAMUT_BT709);
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
deleted file mode 100644
index af54eb2..0000000
--- a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2022 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 <ultrahdr/jpegencoderhelper.h>
-#include <gtest/gtest.h>
-#include <utils/Log.h>
-
-#include <fcntl.h>
-
-namespace android::ultrahdr {
-
-#define ALIGNED_IMAGE "/data/local/tmp/minnie-320x240.yu12"
-#define ALIGNED_IMAGE_WIDTH 320
-#define ALIGNED_IMAGE_HEIGHT 240
-#define SINGLE_CHANNEL_IMAGE "/data/local/tmp/minnie-320x240.y"
-#define SINGLE_CHANNEL_IMAGE_WIDTH ALIGNED_IMAGE_WIDTH
-#define SINGLE_CHANNEL_IMAGE_HEIGHT ALIGNED_IMAGE_HEIGHT
-#define UNALIGNED_IMAGE "/data/local/tmp/minnie-318x240.yu12"
-#define UNALIGNED_IMAGE_WIDTH 318
-#define UNALIGNED_IMAGE_HEIGHT 240
-#define JPEG_QUALITY 90
-
-class JpegEncoderHelperTest : public testing::Test {
-public:
- struct Image {
- std::unique_ptr<uint8_t[]> buffer;
- size_t width;
- size_t height;
- };
- JpegEncoderHelperTest();
- ~JpegEncoderHelperTest();
-
-protected:
- virtual void SetUp();
- virtual void TearDown();
-
- Image mAlignedImage, mUnalignedImage, mSingleChannelImage;
-};
-
-JpegEncoderHelperTest::JpegEncoderHelperTest() {}
-
-JpegEncoderHelperTest::~JpegEncoderHelperTest() {}
-
-static size_t getFileSize(int fd) {
- struct stat st;
- if (fstat(fd, &st) < 0) {
- ALOGW("%s : fstat failed", __func__);
- return 0;
- }
- return st.st_size; // bytes
-}
-
-static bool loadFile(const char filename[], JpegEncoderHelperTest::Image* result) {
- int fd = open(filename, O_CLOEXEC);
- if (fd < 0) {
- return false;
- }
- int length = getFileSize(fd);
- if (length == 0) {
- close(fd);
- return false;
- }
- result->buffer.reset(new uint8_t[length]);
- if (read(fd, result->buffer.get(), length) != static_cast<ssize_t>(length)) {
- close(fd);
- return false;
- }
- close(fd);
- return true;
-}
-
-void JpegEncoderHelperTest::SetUp() {
- if (!loadFile(ALIGNED_IMAGE, &mAlignedImage)) {
- FAIL() << "Load file " << ALIGNED_IMAGE << " failed";
- }
- mAlignedImage.width = ALIGNED_IMAGE_WIDTH;
- mAlignedImage.height = ALIGNED_IMAGE_HEIGHT;
- if (!loadFile(UNALIGNED_IMAGE, &mUnalignedImage)) {
- FAIL() << "Load file " << UNALIGNED_IMAGE << " failed";
- }
- mUnalignedImage.width = UNALIGNED_IMAGE_WIDTH;
- mUnalignedImage.height = UNALIGNED_IMAGE_HEIGHT;
- if (!loadFile(SINGLE_CHANNEL_IMAGE, &mSingleChannelImage)) {
- FAIL() << "Load file " << SINGLE_CHANNEL_IMAGE << " failed";
- }
- mSingleChannelImage.width = SINGLE_CHANNEL_IMAGE_WIDTH;
- mSingleChannelImage.height = SINGLE_CHANNEL_IMAGE_HEIGHT;
-}
-
-void JpegEncoderHelperTest::TearDown() {}
-
-TEST_F(JpegEncoderHelperTest, encodeAlignedImage) {
- JpegEncoderHelper encoder;
- EXPECT_TRUE(encoder.compressImage(mAlignedImage.buffer.get(),
- mAlignedImage.buffer.get() +
- mAlignedImage.width * mAlignedImage.height,
- mAlignedImage.width, mAlignedImage.height,
- mAlignedImage.width, mAlignedImage.width / 2, JPEG_QUALITY,
- NULL, 0));
- ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
-}
-
-TEST_F(JpegEncoderHelperTest, encodeUnalignedImage) {
- JpegEncoderHelper encoder;
- EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(),
- mUnalignedImage.buffer.get() +
- mUnalignedImage.width * mUnalignedImage.height,
- mUnalignedImage.width, mUnalignedImage.height,
- mUnalignedImage.width, mUnalignedImage.width / 2,
- JPEG_QUALITY, NULL, 0));
- ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
-}
-
-TEST_F(JpegEncoderHelperTest, encodeSingleChannelImage) {
- JpegEncoderHelper encoder;
- EXPECT_TRUE(encoder.compressImage(mSingleChannelImage.buffer.get(), nullptr,
- mSingleChannelImage.width, mSingleChannelImage.height,
- mSingleChannelImage.width, 0, JPEG_QUALITY, NULL, 0));
- ASSERT_GT(encoder.getCompressedImageSize(), static_cast<uint32_t>(0));
-}
-
-} // namespace android::ultrahdr
diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp
deleted file mode 100644
index 5fa758e..0000000
--- a/libs/ultrahdr/tests/jpegr_test.cpp
+++ /dev/null
@@ -1,2035 +0,0 @@
-/*
- * Copyright 2022 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 <sys/time.h>
-#include <fstream>
-#include <iostream>
-
-#include <ultrahdr/gainmapmath.h>
-#include <ultrahdr/jpegr.h>
-#include <ultrahdr/jpegrutils.h>
-
-#include <gtest/gtest.h>
-#include <utils/Log.h>
-
-//#define DUMP_OUTPUT
-
-namespace android::ultrahdr {
-
-// resources used by unit tests
-const char* kYCbCrP010FileName = "/data/local/tmp/raw_p010_image.p010";
-const char* kYCbCr420FileName = "/data/local/tmp/raw_yuv420_image.yuv420";
-const char* kSdrJpgFileName = "/data/local/tmp/jpeg_image.jpg";
-const int kImageWidth = 1280;
-const int kImageHeight = 720;
-const int kQuality = 90;
-
-// Wrapper to describe the input type
-typedef enum {
- YCbCr_p010 = 0,
- YCbCr_420 = 1,
-} UhdrInputFormat;
-
-/**
- * Wrapper class for raw resource
- * Sample usage:
- * UhdrUnCompressedStructWrapper rawImg(width, height, YCbCr_p010);
- * rawImg.setImageColorGamut(colorGamut));
- * rawImg.setImageStride(strideLuma, strideChroma); // optional
- * rawImg.setChromaMode(false); // optional
- * rawImg.allocateMemory();
- * rawImg.loadRawResource(kYCbCrP010FileName);
- */
-class UhdrUnCompressedStructWrapper {
-public:
- UhdrUnCompressedStructWrapper(uint32_t width, uint32_t height, UhdrInputFormat format);
- ~UhdrUnCompressedStructWrapper() = default;
-
- bool setChromaMode(bool isChromaContiguous);
- bool setImageStride(int lumaStride, int chromaStride);
- bool setImageColorGamut(ultrahdr_color_gamut colorGamut);
- bool allocateMemory();
- bool loadRawResource(const char* fileName);
- jr_uncompressed_ptr getImageHandle();
-
-private:
- std::unique_ptr<uint8_t[]> mLumaData;
- std::unique_ptr<uint8_t[]> mChromaData;
- jpegr_uncompressed_struct mImg;
- UhdrInputFormat mFormat;
- bool mIsChromaContiguous;
-};
-
-/**
- * Wrapper class for compressed resource
- * Sample usage:
- * UhdrCompressedStructWrapper jpgImg(width, height);
- * rawImg.allocateMemory();
- */
-class UhdrCompressedStructWrapper {
-public:
- UhdrCompressedStructWrapper(uint32_t width, uint32_t height);
- ~UhdrCompressedStructWrapper() = default;
-
- bool allocateMemory();
- jr_compressed_ptr getImageHandle();
-
-private:
- std::unique_ptr<uint8_t[]> mData;
- jpegr_compressed_struct mImg{};
- uint32_t mWidth;
- uint32_t mHeight;
-};
-
-UhdrUnCompressedStructWrapper::UhdrUnCompressedStructWrapper(uint32_t width, uint32_t height,
- UhdrInputFormat format) {
- mImg.data = nullptr;
- mImg.width = width;
- mImg.height = height;
- mImg.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- mImg.chroma_data = nullptr;
- mImg.luma_stride = 0;
- mImg.chroma_stride = 0;
- mFormat = format;
- mIsChromaContiguous = true;
-}
-
-bool UhdrUnCompressedStructWrapper::setChromaMode(bool isChromaContiguous) {
- if (mLumaData.get() != nullptr) {
- std::cerr << "Object has sailed, no further modifications are allowed" << std::endl;
- return false;
- }
- mIsChromaContiguous = isChromaContiguous;
- return true;
-}
-
-bool UhdrUnCompressedStructWrapper::setImageStride(int lumaStride, int chromaStride) {
- if (mLumaData.get() != nullptr) {
- std::cerr << "Object has sailed, no further modifications are allowed" << std::endl;
- return false;
- }
- if (lumaStride != 0) {
- if (lumaStride < mImg.width) {
- std::cerr << "Bad luma stride received" << std::endl;
- return false;
- }
- mImg.luma_stride = lumaStride;
- }
- if (chromaStride != 0) {
- if (mFormat == YCbCr_p010 && chromaStride < mImg.width) {
- std::cerr << "Bad chroma stride received for format YCbCrP010" << std::endl;
- return false;
- }
- if (mFormat == YCbCr_420 && chromaStride < (mImg.width >> 1)) {
- std::cerr << "Bad chroma stride received for format YCbCr420" << std::endl;
- return false;
- }
- mImg.chroma_stride = chromaStride;
- }
- return true;
-}
-
-bool UhdrUnCompressedStructWrapper::setImageColorGamut(ultrahdr_color_gamut colorGamut) {
- if (mLumaData.get() != nullptr) {
- std::cerr << "Object has sailed, no further modifications are allowed" << std::endl;
- return false;
- }
- mImg.colorGamut = colorGamut;
- return true;
-}
-
-bool UhdrUnCompressedStructWrapper::allocateMemory() {
- if (mImg.width == 0 || (mImg.width % 2 != 0) || mImg.height == 0 || (mImg.height % 2 != 0) ||
- (mFormat != YCbCr_p010 && mFormat != YCbCr_420)) {
- std::cerr << "Object in bad state, mem alloc failed" << std::endl;
- return false;
- }
- int lumaStride = mImg.luma_stride == 0 ? mImg.width : mImg.luma_stride;
- int lumaSize = lumaStride * mImg.height * (mFormat == YCbCr_p010 ? 2 : 1);
- int chromaSize = (mImg.height >> 1) * (mFormat == YCbCr_p010 ? 2 : 1);
- if (mIsChromaContiguous) {
- chromaSize *= lumaStride;
- } else {
- if (mImg.chroma_stride == 0) {
- std::cerr << "Object in bad state, mem alloc failed" << std::endl;
- return false;
- }
- if (mFormat == YCbCr_p010) {
- chromaSize *= mImg.chroma_stride;
- } else {
- chromaSize *= (mImg.chroma_stride * 2);
- }
- }
- if (mIsChromaContiguous) {
- mLumaData = std::make_unique<uint8_t[]>(lumaSize + chromaSize);
- mImg.data = mLumaData.get();
- mImg.chroma_data = nullptr;
- } else {
- mLumaData = std::make_unique<uint8_t[]>(lumaSize);
- mImg.data = mLumaData.get();
- mChromaData = std::make_unique<uint8_t[]>(chromaSize);
- mImg.chroma_data = mChromaData.get();
- }
- return true;
-}
-
-bool UhdrUnCompressedStructWrapper::loadRawResource(const char* fileName) {
- if (!mImg.data) {
- std::cerr << "memory is not allocated, read not possible" << std::endl;
- return false;
- }
- std::ifstream ifd(fileName, std::ios::binary | std::ios::ate);
- if (ifd.good()) {
- int bpp = mFormat == YCbCr_p010 ? 2 : 1;
- int size = ifd.tellg();
- int length = mImg.width * mImg.height * bpp * 3 / 2; // 2x2 subsampling
- if (size < length) {
- std::cerr << "requested to read " << length << " bytes from file : " << fileName
- << ", file contains only " << length << " bytes" << std::endl;
- return false;
- }
- ifd.seekg(0, std::ios::beg);
- int lumaStride = mImg.luma_stride == 0 ? mImg.width : mImg.luma_stride;
- char* mem = static_cast<char*>(mImg.data);
- for (int i = 0; i < mImg.height; i++) {
- ifd.read(mem, mImg.width * bpp);
- mem += lumaStride * bpp;
- }
- if (!mIsChromaContiguous) {
- mem = static_cast<char*>(mImg.chroma_data);
- }
- int chromaStride;
- if (mIsChromaContiguous) {
- chromaStride = mFormat == YCbCr_p010 ? lumaStride : lumaStride / 2;
- } else {
- if (mFormat == YCbCr_p010) {
- chromaStride = mImg.chroma_stride == 0 ? lumaStride : mImg.chroma_stride;
- } else {
- chromaStride = mImg.chroma_stride == 0 ? (lumaStride / 2) : mImg.chroma_stride;
- }
- }
- if (mFormat == YCbCr_p010) {
- for (int i = 0; i < mImg.height / 2; i++) {
- ifd.read(mem, mImg.width * 2);
- mem += chromaStride * 2;
- }
- } else {
- for (int i = 0; i < mImg.height / 2; i++) {
- ifd.read(mem, (mImg.width / 2));
- mem += chromaStride;
- }
- for (int i = 0; i < mImg.height / 2; i++) {
- ifd.read(mem, (mImg.width / 2));
- mem += chromaStride;
- }
- }
- return true;
- }
- std::cerr << "unable to open file : " << fileName << std::endl;
- return false;
-}
-
-jr_uncompressed_ptr UhdrUnCompressedStructWrapper::getImageHandle() {
- return &mImg;
-}
-
-UhdrCompressedStructWrapper::UhdrCompressedStructWrapper(uint32_t width, uint32_t height) {
- mWidth = width;
- mHeight = height;
-}
-
-bool UhdrCompressedStructWrapper::allocateMemory() {
- if (mWidth == 0 || (mWidth % 2 != 0) || mHeight == 0 || (mHeight % 2 != 0)) {
- std::cerr << "Object in bad state, mem alloc failed" << std::endl;
- return false;
- }
- int maxLength = std::max(8 * 1024 /* min size 8kb */, (int)(mWidth * mHeight * 3 * 2));
- mData = std::make_unique<uint8_t[]>(maxLength);
- mImg.data = mData.get();
- mImg.length = 0;
- mImg.maxLength = maxLength;
- return true;
-}
-
-jr_compressed_ptr UhdrCompressedStructWrapper::getImageHandle() {
- return &mImg;
-}
-
-static bool writeFile(const char* filename, void*& result, int length) {
- std::ofstream ofd(filename, std::ios::binary);
- if (ofd.is_open()) {
- ofd.write(static_cast<char*>(result), length);
- return true;
- }
- std::cerr << "unable to write to file : " << filename << std::endl;
- return false;
-}
-
-static bool readFile(const char* fileName, void*& result, int maxLength, int& length) {
- std::ifstream ifd(fileName, std::ios::binary | std::ios::ate);
- if (ifd.good()) {
- length = ifd.tellg();
- if (length > maxLength) {
- std::cerr << "not enough space to read file" << std::endl;
- return false;
- }
- ifd.seekg(0, std::ios::beg);
- ifd.read(static_cast<char*>(result), length);
- return true;
- }
- std::cerr << "unable to read file : " << fileName << std::endl;
- return false;
-}
-
-void decodeJpegRImg(jr_compressed_ptr img, [[maybe_unused]] const char* outFileName) {
- std::vector<uint8_t> iccData(0);
- std::vector<uint8_t> exifData(0);
- jpegr_info_struct info{0, 0, &iccData, &exifData};
- JpegR jpegHdr;
- ASSERT_EQ(OK, jpegHdr.getJPEGRInfo(img, &info));
- ASSERT_EQ(kImageWidth, info.width);
- ASSERT_EQ(kImageHeight, info.height);
- size_t outSize = info.width * info.height * 8;
- std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(outSize);
- jpegr_uncompressed_struct destImage{};
- destImage.data = data.get();
- ASSERT_EQ(OK, jpegHdr.decodeJPEGR(img, &destImage));
- ASSERT_EQ(kImageWidth, destImage.width);
- ASSERT_EQ(kImageHeight, destImage.height);
-#ifdef DUMP_OUTPUT
- if (!writeFile(outFileName, destImage.data, outSize)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-}
-
-// ============================================================================
-// Unit Tests
-// ============================================================================
-
-// Test Encode API-0 invalid arguments
-TEST(JpegRTest, EncodeAPI0WithInvalidArgs) {
- JpegR uHdrLib;
-
- UhdrCompressedStructWrapper jpgImg(16, 16);
- ASSERT_TRUE(jpgImg.allocateMemory());
-
- // test quality factor and transfer function
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), -1, nullptr),
- OK)
- << "fail, API allows bad jpeg quality factor";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), 101, nullptr),
- OK)
- << "fail, API allows bad jpeg quality factor";
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(
- ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1),
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(-10),
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad hdr transfer function";
- }
-
- // test dest
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr, kQuality,
- nullptr),
- OK)
- << "fail, API allows nullptr dest";
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr dest";
- }
-
- // test p010 input
- {
- ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr p010 image";
-
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr p010 image";
- }
-
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED));
- ASSERT_TRUE(rawImg.allocateMemory());
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg2.setImageColorGamut(
- static_cast<ultrahdr_color_gamut>(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1)));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad p010 color gamut";
- }
-
- {
- const int kWidth = 32, kHeight = 32;
- UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- auto rawImgP010 = rawImg.getImageHandle();
-
- rawImgP010->width = kWidth - 1;
- rawImgP010->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight - 1;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = 0;
- rawImgP010->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = 0;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad luma stride";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth + 64;
- rawImgP010->chroma_data = rawImgP010->data;
- rawImgP010->chroma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad chroma stride";
- }
-}
-
-/* Test Encode API-1 invalid arguments */
-TEST(JpegRTest, EncodeAPI1WithInvalidArgs) {
- JpegR uHdrLib;
-
- UhdrCompressedStructWrapper jpgImg(16, 16);
- ASSERT_TRUE(jpgImg.allocateMemory());
-
- // test quality factor and transfer function
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), -1, nullptr),
- OK)
- << "fail, API allows bad jpeg quality factor";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), 101, nullptr),
- OK)
- << "fail, API allows bad jpeg quality factor";
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(
- ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1),
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(-10),
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad hdr transfer function";
- }
-
- // test dest
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr, kQuality,
- nullptr),
- OK)
- << "fail, API allows nullptr dest";
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr dest";
- }
-
- // test p010 input
- {
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr p010 image";
-
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr p010 image";
- }
-
- {
- const int kWidth = 32, kHeight = 32;
- UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- auto rawImgP010 = rawImg.getImageHandle();
- UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
- auto rawImg420 = rawImg2.getImageHandle();
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut =
- static_cast<ultrahdr_color_gamut>(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- rawImgP010->width = kWidth - 1;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight - 1;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = 0;
- rawImgP010->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = 0;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad luma stride";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth + 64;
- rawImgP010->chroma_data = rawImgP010->data;
- rawImgP010->chroma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad chroma stride";
- }
-
- // test 420 input
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), nullptr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr 420 image";
-
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows nullptr 420 image";
- }
- {
- const int kWidth = 32, kHeight = 32;
- UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- auto rawImgP010 = rawImg.getImageHandle();
- UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
- auto rawImg420 = rawImg2.getImageHandle();
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad 420 color gamut";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->colorGamut =
- static_cast<ultrahdr_color_gamut>(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad 420 color gamut";
-
- rawImg420->width = kWidth - 1;
- rawImg420->height = kHeight;
- rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image width for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight - 1;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image height for 420";
-
- rawImg420->width = 0;
- rawImg420->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image width for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = 0;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad image height for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->luma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad luma stride for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->luma_stride = 0;
- rawImg420->chroma_data = rawImgP010->data;
- rawImg420->chroma_stride = kWidth / 2 - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK)
- << "fail, API allows bad chroma stride for 420";
- }
-}
-
-/* Test Encode API-2 invalid arguments */
-TEST(JpegRTest, EncodeAPI2WithInvalidArgs) {
- JpegR uHdrLib;
-
- UhdrCompressedStructWrapper jpgImg(16, 16);
- ASSERT_TRUE(jpgImg.allocateMemory());
-
- // test quality factor and transfer function
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(
- ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1),
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(-10),
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad hdr transfer function";
- }
-
- // test dest
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr),
- OK)
- << "fail, API allows nullptr dest";
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK)
- << "fail, API allows nullptr dest";
- }
-
- // test compressed image
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), nullptr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr for compressed image";
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr for compressed image";
- }
-
- // test p010 input
- {
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, rawImg2.getImageHandle(), jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr p010 image";
-
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr p010 image";
- }
-
- {
- const int kWidth = 32, kHeight = 32;
- UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- auto rawImgP010 = rawImg.getImageHandle();
- UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
- auto rawImg420 = rawImg2.getImageHandle();
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut =
- static_cast<ultrahdr_color_gamut>(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- rawImgP010->width = kWidth - 1;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight - 1;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = 0;
- rawImgP010->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = 0;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad luma stride";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth + 64;
- rawImgP010->chroma_data = rawImgP010->data;
- rawImgP010->chroma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad chroma stride";
- }
-
- // test 420 input
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), nullptr, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr 420 image";
-
- UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(),
- jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr 420 image";
- }
- {
- const int kWidth = 32, kHeight = 32;
- UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- auto rawImgP010 = rawImg.getImageHandle();
- UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg2.allocateMemory());
- auto rawImg420 = rawImg2.getImageHandle();
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad 420 color gamut";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->colorGamut =
- static_cast<ultrahdr_color_gamut>(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad 420 color gamut";
-
- rawImg420->width = kWidth - 1;
- rawImg420->height = kHeight;
- rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image width for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight - 1;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image height for 420";
-
- rawImg420->width = 0;
- rawImg420->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image width for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = 0;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image height for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->luma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad luma stride for 420";
-
- rawImg420->width = kWidth;
- rawImg420->height = kHeight;
- rawImg420->luma_stride = 0;
- rawImg420->chroma_data = rawImgP010->data;
- rawImg420->chroma_stride = kWidth / 2 - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad chroma stride for 420";
- }
-}
-
-/* Test Encode API-3 invalid arguments */
-TEST(JpegRTest, EncodeAPI3WithInvalidArgs) {
- JpegR uHdrLib;
-
- UhdrCompressedStructWrapper jpgImg(16, 16);
- ASSERT_TRUE(jpgImg.allocateMemory());
-
- // test quality factor and transfer function
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(
- ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1),
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad hdr transfer function";
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(),
- static_cast<ultrahdr_transfer_function>(-10),
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad hdr transfer function";
- }
-
- // test dest
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr),
- OK)
- << "fail, API allows nullptr dest";
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK)
- << "fail, API allows nullptr dest";
- }
-
- // test compressed image
- {
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
-
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), nullptr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr for compressed image";
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr for compressed image";
- }
-
- // test p010 input
- {
- ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr p010 image";
-
- UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr p010 image";
- }
-
- {
- const int kWidth = 32, kHeight = 32;
- UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImg.allocateMemory());
- auto rawImgP010 = rawImg.getImageHandle();
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut =
- static_cast<ultrahdr_color_gamut>(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1);
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad p010 color gamut";
-
- rawImgP010->width = kWidth - 1;
- rawImgP010->height = kHeight;
- rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight - 1;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = 0;
- rawImgP010->height = kHeight;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image width";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = 0;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad image height";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad luma stride";
-
- rawImgP010->width = kWidth;
- rawImgP010->height = kHeight;
- rawImgP010->luma_stride = kWidth + 64;
- rawImgP010->chroma_data = rawImgP010->data;
- rawImgP010->chroma_stride = kWidth - 2;
- ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad chroma stride";
- }
-}
-
-/* Test Encode API-4 invalid arguments */
-TEST(JpegRTest, EncodeAPI4WithInvalidArgs) {
- UhdrCompressedStructWrapper jpgImg(16, 16);
- ASSERT_TRUE(jpgImg.allocateMemory());
- UhdrCompressedStructWrapper jpgImg2(16, 16);
- JpegR uHdrLib;
-
- // test dest
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), nullptr, nullptr),
- OK)
- << "fail, API allows nullptr dest";
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), nullptr,
- jpgImg2.getImageHandle()),
- OK)
- << "fail, API allows nullptr dest";
-
- // test primary image
- ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, jpgImg.getImageHandle(), nullptr, jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr primary image";
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg2.getImageHandle(), jpgImg.getImageHandle(), nullptr,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr primary image";
-
- // test gain map
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), nullptr, nullptr, jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr gain map image";
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg2.getImageHandle(), nullptr,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows nullptr gain map image";
-
- // test metadata
- ultrahdr_metadata_struct good_metadata;
- good_metadata.version = "1.0";
- good_metadata.minContentBoost = 1.0f;
- good_metadata.maxContentBoost = 2.0f;
- good_metadata.gamma = 1.0f;
- good_metadata.offsetSdr = 0.0f;
- good_metadata.offsetHdr = 0.0f;
- good_metadata.hdrCapacityMin = 1.0f;
- good_metadata.hdrCapacityMax = 2.0f;
-
- ultrahdr_metadata_struct metadata = good_metadata;
- metadata.version = "1.1";
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata version";
-
- metadata = good_metadata;
- metadata.minContentBoost = 3.0f;
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata content boost";
-
- metadata = good_metadata;
- metadata.gamma = -0.1f;
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata gamma";
-
- metadata = good_metadata;
- metadata.offsetSdr = -0.1f;
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata offset sdr";
-
- metadata = good_metadata;
- metadata.offsetHdr = -0.1f;
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata offset hdr";
-
- metadata = good_metadata;
- metadata.hdrCapacityMax = 0.5f;
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata hdr capacity max";
-
- metadata = good_metadata;
- metadata.hdrCapacityMin = 0.5f;
- ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata,
- jpgImg.getImageHandle()),
- OK)
- << "fail, API allows bad metadata hdr capacity min";
-}
-
-/* Test Decode API invalid arguments */
-TEST(JpegRTest, DecodeAPIWithInvalidArgs) {
- JpegR uHdrLib;
-
- UhdrCompressedStructWrapper jpgImg(16, 16);
- jpegr_uncompressed_struct destImage{};
- size_t outSize = 16 * 16 * 8;
- std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(outSize);
- destImage.data = data.get();
-
- // test jpegr image
- ASSERT_NE(uHdrLib.decodeJPEGR(nullptr, &destImage), OK)
- << "fail, API allows nullptr for jpegr img";
- ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage), OK)
- << "fail, API allows nullptr for jpegr img";
- ASSERT_TRUE(jpgImg.allocateMemory());
-
- // test dest image
- ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), nullptr), OK)
- << "fail, API allows nullptr for dest";
- destImage.data = nullptr;
- ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage), OK)
- << "fail, API allows nullptr for dest";
- destImage.data = data.get();
-
- // test max display boost
- ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage, 0.5), OK)
- << "fail, API allows invalid max display boost";
-
- // test output format
- ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage, FLT_MAX, nullptr,
- static_cast<ultrahdr_output_format>(-1)),
- OK)
- << "fail, API allows invalid output format";
- ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage, FLT_MAX, nullptr,
- static_cast<ultrahdr_output_format>(ULTRAHDR_OUTPUT_MAX + 1)),
- OK)
- << "fail, API allows invalid output format";
-}
-
-TEST(JpegRTest, writeXmpThenRead) {
- ultrahdr_metadata_struct metadata_expected;
- metadata_expected.version = "1.0";
- metadata_expected.maxContentBoost = 1.25f;
- metadata_expected.minContentBoost = 0.75f;
- metadata_expected.gamma = 1.0f;
- metadata_expected.offsetSdr = 0.0f;
- metadata_expected.offsetHdr = 0.0f;
- metadata_expected.hdrCapacityMin = 1.0f;
- metadata_expected.hdrCapacityMax = metadata_expected.maxContentBoost;
- const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0";
- const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator
-
- std::string xmp = generateXmpForSecondaryImage(metadata_expected);
-
- std::vector<uint8_t> xmpData;
- xmpData.reserve(nameSpaceLength + xmp.size());
- xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(nameSpace.c_str()),
- reinterpret_cast<const uint8_t*>(nameSpace.c_str()) + nameSpaceLength);
- xmpData.insert(xmpData.end(), reinterpret_cast<const uint8_t*>(xmp.c_str()),
- reinterpret_cast<const uint8_t*>(xmp.c_str()) + xmp.size());
-
- ultrahdr_metadata_struct metadata_read;
- EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read));
- EXPECT_FLOAT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost);
- EXPECT_FLOAT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost);
- EXPECT_FLOAT_EQ(metadata_expected.gamma, metadata_read.gamma);
- EXPECT_FLOAT_EQ(metadata_expected.offsetSdr, metadata_read.offsetSdr);
- EXPECT_FLOAT_EQ(metadata_expected.offsetHdr, metadata_read.offsetHdr);
- EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMin, metadata_read.hdrCapacityMin);
- EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMax, metadata_read.hdrCapacityMax);
-}
-
-class JpegRAPIEncodeAndDecodeTest
- : public ::testing::TestWithParam<std::tuple<ultrahdr_color_gamut, ultrahdr_color_gamut>> {
-public:
- JpegRAPIEncodeAndDecodeTest()
- : mP010ColorGamut(std::get<0>(GetParam())), mYuv420ColorGamut(std::get<1>(GetParam())){};
-
- const ultrahdr_color_gamut mP010ColorGamut;
- const ultrahdr_color_gamut mYuv420ColorGamut;
-};
-
-/* Test Encode API-0 and Decode */
-TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI0AndDecodeTest) {
- // reference encode
- UhdrUnCompressedStructWrapper rawImg(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg.allocateMemory());
- ASSERT_TRUE(rawImg.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg.allocateMemory());
- JpegR uHdrLib;
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK);
- // encode with luma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 18, 0));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 18, kImageWidth + 28));
- ASSERT_TRUE(rawImg2.setChromaMode(false));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2.setImageStride(0, kImageWidth + 34));
- ASSERT_TRUE(rawImg2.setChromaMode(false));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set but no chroma ptr
- {
- UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2.setImageStride(kImageWidth, kImageWidth + 38));
- ASSERT_TRUE(rawImg2.allocateMemory());
- ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
-
- auto jpg1 = jpgImg.getImageHandle();
-#ifdef DUMP_OUTPUT
- if (!writeFile("encode_api0_output.jpeg", jpg1->data, jpg1->length)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-
- ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api0_output.rgb"));
-}
-
-/* Test Encode API-1 and Decode */
-TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI1AndDecodeTest) {
- UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImgP010.allocateMemory());
- ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName));
- UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg420.allocateMemory());
- ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg.allocateMemory());
- JpegR uHdrLib;
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle(), kQuality, nullptr),
- OK);
- // encode with luma stride set p010
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set p010
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256));
- ASSERT_TRUE(rawImg2P010.setChromaMode(false));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with chroma stride set p010
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64));
- ASSERT_TRUE(rawImg2P010.setChromaMode(false));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set but no chroma ptr p010
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 64, kImageWidth + 256));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma stride set 420
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 14, 0));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set 420
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 46, kImageWidth / 2 + 34));
- ASSERT_TRUE(rawImg2420.setChromaMode(false));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with chroma stride set 420
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth / 2 + 38));
- ASSERT_TRUE(rawImg2420.setChromaMode(false));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set but no chroma ptr 420
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 26, kImageWidth / 2 + 44));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(),
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle(), kQuality, nullptr),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
-
- auto jpg1 = jpgImg.getImageHandle();
-
-#ifdef DUMP_OUTPUT
- if (!writeFile("encode_api1_output.jpeg", jpg1->data, jpg1->length)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-
- ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api1_output.rgb"));
-}
-
-/* Test Encode API-2 and Decode */
-TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI2AndDecodeTest) {
- UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImgP010.allocateMemory());
- ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName));
- UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg420.allocateMemory());
- ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg.allocateMemory());
- UhdrCompressedStructWrapper jpgSdr(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgSdr.allocateMemory());
- auto sdr = jpgSdr.getImageHandle();
- ASSERT_TRUE(readFile(kSdrJpgFileName, sdr->data, sdr->maxLength, sdr->length));
- JpegR uHdrLib;
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK);
- // encode with luma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256));
- ASSERT_TRUE(rawImg2P010.setChromaMode(false));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64));
- ASSERT_TRUE(rawImg2P010.setChromaMode(false));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth + 256));
- ASSERT_TRUE(rawImg2420.setChromaMode(false));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut));
- ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth + 64));
- ASSERT_TRUE(rawImg2420.setChromaMode(false));
- ASSERT_TRUE(rawImg2420.allocateMemory());
- ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
-
- auto jpg1 = jpgImg.getImageHandle();
-
-#ifdef DUMP_OUTPUT
- if (!writeFile("encode_api2_output.jpeg", jpg1->data, jpg1->length)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-
- ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api2_output.rgb"));
-}
-
-/* Test Encode API-3 and Decode */
-TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI3AndDecodeTest) {
- UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImgP010.allocateMemory());
- ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg.allocateMemory());
- UhdrCompressedStructWrapper jpgSdr(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgSdr.allocateMemory());
- auto sdr = jpgSdr.getImageHandle();
- ASSERT_TRUE(readFile(kSdrJpgFileName, sdr->data, sdr->maxLength, sdr->length));
- JpegR uHdrLib;
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg.getImageHandle()),
- OK);
- // encode with luma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256));
- ASSERT_TRUE(rawImg2P010.setChromaMode(false));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with chroma stride set
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64));
- ASSERT_TRUE(rawImg2P010.setChromaMode(false));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
- // encode with luma and chroma stride set and no chroma ptr
- {
- UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut));
- ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 32, kImageWidth + 256));
- ASSERT_TRUE(rawImg2P010.allocateMemory());
- ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName));
- UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight);
- ASSERT_TRUE(jpgImg2.allocateMemory());
- ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr,
- ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- jpgImg2.getImageHandle()),
- OK);
- auto jpg1 = jpgImg.getImageHandle();
- auto jpg2 = jpgImg2.getImageHandle();
- ASSERT_EQ(jpg1->length, jpg2->length);
- ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length));
- }
-
- auto jpg1 = jpgImg.getImageHandle();
-
-#ifdef DUMP_OUTPUT
- if (!writeFile("encode_api3_output.jpeg", jpg1->data, jpg1->length)) {
- std::cerr << "unable to write output file" << std::endl;
- }
-#endif
-
- ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api3_output.rgb"));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- JpegRAPIParameterizedTests, JpegRAPIEncodeAndDecodeTest,
- ::testing::Combine(::testing::Values(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3,
- ULTRAHDR_COLORGAMUT_BT2100),
- ::testing::Values(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3,
- ULTRAHDR_COLORGAMUT_BT2100)));
-
-// ============================================================================
-// Profiling
-// ============================================================================
-
-class Profiler {
-public:
- void timerStart() { gettimeofday(&mStartingTime, nullptr); }
-
- void timerStop() { gettimeofday(&mEndingTime, nullptr); }
-
- int64_t elapsedTime() {
- struct timeval elapsedMicroseconds;
- elapsedMicroseconds.tv_sec = mEndingTime.tv_sec - mStartingTime.tv_sec;
- elapsedMicroseconds.tv_usec = mEndingTime.tv_usec - mStartingTime.tv_usec;
- return elapsedMicroseconds.tv_sec * 1000000 + elapsedMicroseconds.tv_usec;
- }
-
-private:
- struct timeval mStartingTime;
- struct timeval mEndingTime;
-};
-
-class JpegRBenchmark : public JpegR {
-public:
- void BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr p010Image,
- ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr map);
- void BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map,
- ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest);
-
-private:
- const int kProfileCount = 10;
-};
-
-void JpegRBenchmark::BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image,
- jr_uncompressed_ptr p010Image,
- ultrahdr_metadata_ptr metadata,
- jr_uncompressed_ptr map) {
- ASSERT_EQ(yuv420Image->width, p010Image->width);
- ASSERT_EQ(yuv420Image->height, p010Image->height);
- Profiler profileGenerateMap;
- profileGenerateMap.timerStart();
- for (auto i = 0; i < kProfileCount; i++) {
- ASSERT_EQ(OK,
- generateGainMap(yuv420Image, p010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG,
- metadata, map));
- if (i != kProfileCount - 1) delete[] static_cast<uint8_t*>(map->data);
- }
- profileGenerateMap.timerStop();
- ALOGE("Generate Gain Map:- Res = %i x %i, time = %f ms", yuv420Image->width, yuv420Image->height,
- profileGenerateMap.elapsedTime() / (kProfileCount * 1000.f));
-}
-
-void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map,
- ultrahdr_metadata_ptr metadata,
- jr_uncompressed_ptr dest) {
- Profiler profileRecMap;
- profileRecMap.timerStart();
- for (auto i = 0; i < kProfileCount; i++) {
- ASSERT_EQ(OK,
- applyGainMap(yuv420Image, map, metadata, ULTRAHDR_OUTPUT_HDR_HLG,
- metadata->maxContentBoost /* displayBoost */, dest));
- }
- profileRecMap.timerStop();
- ALOGE("Apply Gain Map:- Res = %i x %i, time = %f ms", yuv420Image->width, yuv420Image->height,
- profileRecMap.elapsedTime() / (kProfileCount * 1000.f));
-}
-
-TEST(JpegRTest, ProfileGainMapFuncs) {
- UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010);
- ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100));
- ASSERT_TRUE(rawImgP010.allocateMemory());
- ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName));
- UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420);
- ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709));
- ASSERT_TRUE(rawImg420.allocateMemory());
- ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName));
- ultrahdr_metadata_struct metadata = {.version = "1.0"};
- jpegr_uncompressed_struct map = {.data = NULL,
- .width = 0,
- .height = 0,
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
- {
- auto rawImg = rawImgP010.getImageHandle();
- if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width;
- if (!rawImg->chroma_data) {
- uint16_t* data = reinterpret_cast<uint16_t*>(rawImg->data);
- rawImg->chroma_data = data + rawImg->luma_stride * rawImg->height;
- rawImg->chroma_stride = rawImg->luma_stride;
- }
- }
- {
- auto rawImg = rawImg420.getImageHandle();
- if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width;
- if (!rawImg->chroma_data) {
- uint8_t* data = reinterpret_cast<uint8_t*>(rawImg->data);
- rawImg->chroma_data = data + rawImg->luma_stride * rawImg->height;
- rawImg->chroma_stride = rawImg->luma_stride / 2;
- }
- }
-
- JpegRBenchmark benchmark;
- ASSERT_NO_FATAL_FAILURE(benchmark.BenchmarkGenerateGainMap(rawImg420.getImageHandle(),
- rawImgP010.getImageHandle(), &metadata,
- &map));
-
- const int dstSize = kImageWidth * kImageWidth * 4;
- auto bufferDst = std::make_unique<uint8_t[]>(dstSize);
- jpegr_uncompressed_struct dest = {.data = bufferDst.get(),
- .width = 0,
- .height = 0,
- .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED};
-
- ASSERT_NO_FATAL_FAILURE(
- benchmark.BenchmarkApplyGainMap(rawImg420.getImageHandle(), &map, &metadata, &dest));
-}
-
-} // namespace android::ultrahdr
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 79f22c1..a481c62 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -72,6 +72,9 @@
};
GpuService::~GpuService() {
+ mGpuMem->stop();
+ mGpuWork->stop();
+
mGpuWorkAsyncInitThread->join();
mGpuMemAsyncInitThread->join();
}
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index 141fe02..d0783df 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -61,6 +61,7 @@
return;
}
// Retry until GPU driver loaded or timeout.
+ if (mStop.load()) return;
sleep(1);
}
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
index 9aa74d6..16b201f 100644
--- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -34,6 +34,7 @@
// dumpsys interface
void dump(const Vector<String16>& args, std::string* result);
bool isInitialized() { return mInitialized.load(); }
+ void stop() { mStop.store(true); }
// Traverse the gpu memory total map to feed the callback function.
void traverseGpuMemTotals(const std::function<void(int64_t ts, uint32_t gpuId, uint32_t pid,
@@ -48,6 +49,10 @@
// indicate whether ebpf has been initialized
std::atomic<bool> mInitialized = false;
+
+ // whether initialization should be stopped
+ std::atomic<bool> mStop = false;
+
// bpf map for GPU memory total data
android::bpf::BpfMapRO<uint64_t, uint64_t> mGpuMemTotalMap;
diff --git a/services/gpuservice/gpuwork/GpuWork.cpp b/services/gpuservice/gpuwork/GpuWork.cpp
index fd70323..1a744ab 100644
--- a/services/gpuservice/gpuwork/GpuWork.cpp
+++ b/services/gpuservice/gpuwork/GpuWork.cpp
@@ -243,6 +243,7 @@
return false;
}
// Retry until GPU driver loaded or timeout.
+ if (mStop.load()) return false;
sleep(1);
errno = 0;
}
diff --git a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
index cece999..e70da54 100644
--- a/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
+++ b/services/gpuservice/gpuwork/include/gpuwork/GpuWork.h
@@ -40,6 +40,7 @@
~GpuWork();
void initialize();
+ void stop() { mStop.store(true); }
// Dumps the GPU work information.
void dump(const Vector<String16>& args, std::string* result);
@@ -47,7 +48,7 @@
private:
// Attaches tracepoint |tracepoint_group|/|tracepoint_name| to BPF program at path
// |program_path|. The tracepoint is also enabled.
- static bool attachTracepoint(const char* program_path, const char* tracepoint_group,
+ bool attachTracepoint(const char* program_path, const char* tracepoint_group,
const char* tracepoint_name);
// Native atom puller callback registered in statsd.
@@ -80,6 +81,9 @@
// Indicates whether our eBPF components have been initialized.
std::atomic<bool> mInitialized = false;
+ // Indicates whether eBPF initialization should be stopped.
+ std::atomic<bool> mStop = false;
+
// A thread that periodically checks whether |mGpuWorkMap| is nearly full
// and, if so, clears it.
std::thread mMapClearerThread;
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index ae066c0..41e5247 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -41,7 +41,6 @@
const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
-const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
const bool ENABLE_INPUT_FILTER_RUST = input_flags::enable_input_filter_rust_impl();
int32_t exceptionCodeFromStatusT(status_t status) {
@@ -152,12 +151,10 @@
mTracingStages.emplace_back(
std::make_unique<TracedInputListener>("InputProcessor", *mProcessor));
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- mChoreographer =
- std::make_unique<PointerChoreographer>(*mTracingStages.back(), choreographerPolicy);
- mTracingStages.emplace_back(
- std::make_unique<TracedInputListener>("PointerChoreographer", *mChoreographer));
- }
+ mChoreographer =
+ std::make_unique<PointerChoreographer>(*mTracingStages.back(), choreographerPolicy);
+ mTracingStages.emplace_back(
+ std::make_unique<TracedInputListener>("PointerChoreographer", *mChoreographer));
mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mTracingStages.back());
mTracingStages.emplace_back(
@@ -245,10 +242,8 @@
dump += '\n';
mBlocker->dump(dump);
dump += '\n';
- if (ENABLE_POINTER_CHOREOGRAPHER) {
- mChoreographer->dump(dump);
- dump += '\n';
- }
+ mChoreographer->dump(dump);
+ dump += '\n';
mProcessor->dump(dump);
dump += '\n';
if (ENABLE_INPUT_DEVICE_USAGE_METRICS) {
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 3ca691e..fe70a51 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -123,7 +123,8 @@
{"multi_index", InputLightClass::MULTI_INDEX},
{"multi_intensity", InputLightClass::MULTI_INTENSITY},
{"max_brightness", InputLightClass::MAX_BRIGHTNESS},
- {"kbd_backlight", InputLightClass::KEYBOARD_BACKLIGHT}};
+ {"kbd_backlight", InputLightClass::KEYBOARD_BACKLIGHT},
+ {"mic_mute", InputLightClass::KEYBOARD_MIC_MUTE}};
// Mapping for input multicolor led class node names.
// https://www.kernel.org/doc/html/latest/leds/leds-class-multicolor.html
diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp
index eabf591..27b9d23 100644
--- a/services/inputflinger/reader/controller/PeripheralController.cpp
+++ b/services/inputflinger/reader/controller/PeripheralController.cpp
@@ -505,9 +505,14 @@
// Check the rest of raw light infos
for (const auto& [rawId, rawInfo] : rawInfos) {
- InputDeviceLightType type = keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end()
- ? InputDeviceLightType::KEYBOARD_BACKLIGHT
- : InputDeviceLightType::INPUT;
+ InputDeviceLightType type;
+ if (keyboardBacklightIds.find(rawId) != keyboardBacklightIds.end()) {
+ type = InputDeviceLightType::KEYBOARD_BACKLIGHT;
+ } else if (rawInfo.flags.test(InputLightClass::KEYBOARD_MIC_MUTE)) {
+ type = InputDeviceLightType::KEYBOARD_MIC_MUTE;
+ } else {
+ type = InputDeviceLightType::INPUT;
+ }
// If the node is multi-color led, construct a MULTI_COLOR light
if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) &&
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index a7e0675..39d2f5b 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -177,6 +177,8 @@
MAX_BRIGHTNESS = 0x00000080,
/* The input light has kbd_backlight name */
KEYBOARD_BACKLIGHT = 0x00000100,
+ /* The input light has mic_mute name */
+ KEYBOARD_MIC_MUTE = 0x00000200,
};
enum class InputBatteryClass : uint32_t {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index c8cc5dc..becac5a 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -40,8 +40,6 @@
// The default velocity control parameters that has no effect.
static const VelocityControlParameters FLAT_VELOCITY_CONTROL_PARAMS{};
-static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
-
// --- CursorMotionAccumulator ---
CursorMotionAccumulator::CursorMotionAccumulator() {
@@ -78,22 +76,10 @@
CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig)
- : CursorInputMapper(deviceContext, readerConfig, ENABLE_POINTER_CHOREOGRAPHER) {}
-
-CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext,
- const InputReaderConfiguration& readerConfig,
- bool enablePointerChoreographer)
: InputMapper(deviceContext, readerConfig),
mLastEventTime(std::numeric_limits<nsecs_t>::min()),
- mEnablePointerChoreographer(enablePointerChoreographer),
mEnableNewMousePointerBallistics(input_flags::enable_new_mouse_pointer_ballistics()) {}
-CursorInputMapper::~CursorInputMapper() {
- if (mPointerController != nullptr) {
- mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
- }
-}
-
uint32_t CursorInputMapper::getSources() const {
return mSource;
}
@@ -304,22 +290,6 @@
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
if (mSource == AINPUT_SOURCE_MOUSE) {
- if (!mEnablePointerChoreographer) {
- if (moved || scrolled || buttonsChanged) {
- mPointerController->setPresentation(
- PointerControllerInterface::Presentation::POINTER);
-
- if (moved) {
- mPointerController->move(deltaX, deltaY);
- }
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- }
-
- std::tie(xCursorPosition, yCursorPosition) = mPointerController->getPosition();
-
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
- }
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
} else {
@@ -470,7 +440,6 @@
mYPrecision = 1.0f;
mXScale = 1.0f;
mYScale = 1.0f;
- mPointerController = getContext()->getPointerController(getDeviceId());
break;
case Parameters::Mode::NAVIGATION:
mSource = AINPUT_SOURCE_TRACKBALL;
@@ -490,8 +459,6 @@
if (mParameters.mode == Parameters::Mode::POINTER) {
mParameters.mode = Parameters::Mode::POINTER_RELATIVE;
mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
- // Keep PointerController around in order to preserve the pointer position.
- mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
} else {
ALOGE("Cannot request pointer capture, device is not in MODE_POINTER");
}
@@ -546,32 +513,12 @@
// Only generate events for the associated display.
mDisplayId = assocViewport->displayId;
resolvedViewport = *assocViewport;
- if (!mEnablePointerChoreographer) {
- const bool mismatchedPointerDisplay =
- isPointer && (assocViewport->displayId != mPointerController->getDisplayId());
- if (mismatchedPointerDisplay) {
- // This device's associated display doesn't match PointerController's current
- // display. Do not associate it with any display.
- mDisplayId.reset();
- }
- }
} else if (isPointer) {
// The InputDevice is not associated with a viewport, but it controls the mouse pointer.
- if (mEnablePointerChoreographer) {
- // Always use DISPLAY_ID_NONE for mouse events.
- // PointerChoreographer will make it target the correct the displayId later.
- resolvedViewport = getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
- mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
- } else {
- mDisplayId = mPointerController->getDisplayId();
- if (auto v = config.getDisplayViewportById(*mDisplayId); v) {
- resolvedViewport = *v;
- }
- if (auto bounds = mPointerController->getBounds(); bounds) {
- mBoundsInLogicalDisplay = *bounds;
- isBoundsSet = true;
- }
- }
+ // Always use DISPLAY_ID_NONE for mouse events.
+ // PointerChoreographer will make it target the correct the displayId later.
+ resolvedViewport = getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
+ mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
}
mOrientation = (mParameters.orientationAware && mParameters.hasAssociatedDisplay) ||
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index ca541d9..3daae2f 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -20,14 +20,11 @@
#include "CursorScrollAccumulator.h"
#include "InputMapper.h"
-#include <PointerControllerInterface.h>
#include <input/VelocityControl.h>
#include <ui/Rotation.h>
namespace android {
-class PointerControllerInterface;
-
class CursorButtonAccumulator;
class CursorScrollAccumulator;
@@ -56,7 +53,7 @@
friend std::unique_ptr<T> createInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig,
Args... args);
- virtual ~CursorInputMapper();
+ virtual ~CursorInputMapper() = default;
virtual uint32_t getSources() const override;
virtual void populateDeviceInfo(InputDeviceInfo& deviceInfo) override;
@@ -122,21 +119,14 @@
ui::Rotation mOrientation{ui::ROTATION_0};
FloatRect mBoundsInLogicalDisplay{};
- std::shared_ptr<PointerControllerInterface> mPointerController;
-
int32_t mButtonState;
nsecs_t mDownTime;
nsecs_t mLastEventTime;
- const bool mEnablePointerChoreographer;
const bool mEnableNewMousePointerBallistics;
explicit CursorInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig);
- // Constructor for testing.
- explicit CursorInputMapper(InputDeviceContext& deviceContext,
- const InputReaderConfiguration& readerConfig,
- bool enablePointerChoreographer);
void dumpParameters(std::string& dump);
void configureBasicParams();
void configureOnPointerCapture(const InputReaderConfiguration& config);
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 81449d1..cf07506 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -336,7 +336,6 @@
changes.any(InputReaderConfiguration::Change::DISPLAY_INFO |
InputReaderConfiguration::Change::POINTER_CAPTURE |
InputReaderConfiguration::Change::POINTER_GESTURE_ENABLEMENT |
- InputReaderConfiguration::Change::SHOW_TOUCHES |
InputReaderConfiguration::Change::EXTERNAL_STYLUS_PRESENCE |
InputReaderConfiguration::Change::DEVICE_TYPE)) {
// Configure device sources, display dimensions, orientation and
@@ -1042,32 +1041,6 @@
mOrientedRanges.clear();
}
- // Create and preserve the pointer controller in the following cases:
- const bool isPointerControllerNeeded =
- // - when the device is in pointer mode, to show the mouse cursor;
- (mDeviceMode == DeviceMode::POINTER) ||
- // - when pointer capture is enabled, to preserve the mouse cursor position;
- (mParameters.deviceType == Parameters::DeviceType::POINTER &&
- mConfig.pointerCaptureRequest.isEnable()) ||
- // - when we should be showing touches;
- (mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches) ||
- // - when we should be showing a pointer icon for direct styluses.
- (mDeviceMode == DeviceMode::DIRECT && mConfig.stylusPointerIconEnabled && hasStylus());
- if (isPointerControllerNeeded) {
- if (mPointerController == nullptr) {
- mPointerController = getContext()->getPointerController(getDeviceId());
- }
- if (mConfig.pointerCaptureRequest.isEnable()) {
- mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
- }
- } else {
- if (mPointerController != nullptr && mDeviceMode == DeviceMode::DIRECT &&
- !mConfig.showTouches) {
- mPointerController->clearSpots();
- }
- mPointerController.reset();
- }
-
if ((viewportChanged && !skipViewportUpdate) || deviceModeChanged) {
ALOGI("Device reconfigured: id=%d, name='%s', size %s, orientation %s, mode %s, "
"display id %d",
@@ -1400,7 +1373,6 @@
std::list<NotifyArgs> TouchInputMapper::reset(nsecs_t when) {
std::list<NotifyArgs> out = cancelTouch(when, when);
- updateTouchSpots();
mCursorButtonAccumulator.reset(getDeviceContext());
mCursorScrollAccumulator.reset(getDeviceContext());
@@ -1427,11 +1399,6 @@
mPointerSimple.reset();
resetExternalStylus();
- if (mPointerController != nullptr) {
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- mPointerController->clearSpots();
- }
-
return out += InputMapper::reset(when);
}
@@ -1586,11 +1553,6 @@
uint32_t policyFlags = 0;
bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState;
if (initialDown || buttonsPressed) {
- // If this is a touch screen, hide the pointer on an initial down.
- if (mDeviceMode == DeviceMode::DIRECT) {
- getContext()->fadePointer();
- }
-
if (mParameters.wake) {
policyFlags |= POLICY_FLAG_WAKE;
}
@@ -1658,7 +1620,6 @@
out += dispatchPointerUsage(when, readTime, policyFlags, pointerUsage);
} else {
if (!mCurrentMotionAborted) {
- updateTouchSpots();
out += dispatchButtonRelease(when, readTime, policyFlags);
out += dispatchHoverExit(when, readTime, policyFlags);
out += dispatchTouches(when, readTime, policyFlags);
@@ -1690,28 +1651,6 @@
return out;
}
-void TouchInputMapper::updateTouchSpots() {
- if (!mConfig.showTouches || mPointerController == nullptr) {
- return;
- }
-
- // Update touch spots when this is a touchscreen even when it's not enabled so that we can
- // clear touch spots.
- if (mDeviceMode != DeviceMode::DIRECT &&
- (mDeviceMode != DeviceMode::DISABLED || !isTouchScreen())) {
- return;
- }
-
- mPointerController->setPresentation(PointerControllerInterface::Presentation::SPOT);
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
-
- mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords.cbegin(),
- mCurrentCookedState.cookedPointerData.idToIndex.cbegin(),
- mCurrentCookedState.cookedPointerData.touchingIdBits |
- mCurrentCookedState.cookedPointerData.hoveringIdBits,
- mViewport.displayId);
-}
-
bool TouchInputMapper::isTouchScreen() {
return mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN &&
mParameters.hasAssociatedDisplay;
@@ -2560,54 +2499,6 @@
cancelPreviousGesture = false;
}
- // Update the pointer presentation and spots.
- if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- if (finishPreviousGesture || cancelPreviousGesture) {
- mPointerController->clearSpots();
- }
-
- if (mPointerGesture.currentGestureMode == PointerGesture::Mode::FREEFORM) {
- mPointerController->setSpots(mPointerGesture.currentGestureCoords.cbegin(),
- mPointerGesture.currentGestureIdToIndex.cbegin(),
- mPointerGesture.currentGestureIdBits,
- mPointerController->getDisplayId());
- }
- } else {
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- }
-
- // Show or hide the pointer if needed.
- switch (mPointerGesture.currentGestureMode) {
- case PointerGesture::Mode::NEUTRAL:
- case PointerGesture::Mode::QUIET:
- if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH &&
- mPointerGesture.lastGestureMode == PointerGesture::Mode::FREEFORM) {
- // Remind the user of where the pointer is after finishing a gesture with spots.
- mPointerController->unfade(PointerControllerInterface::Transition::GRADUAL);
- }
- break;
- case PointerGesture::Mode::TAP:
- case PointerGesture::Mode::TAP_DRAG:
- case PointerGesture::Mode::BUTTON_CLICK_OR_DRAG:
- case PointerGesture::Mode::HOVER:
- case PointerGesture::Mode::PRESS:
- case PointerGesture::Mode::SWIPE:
- // Unfade the pointer when the current gesture manipulates the
- // area directly under the pointer.
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- break;
- case PointerGesture::Mode::FREEFORM:
- // Fade the pointer when the current gesture manipulates a different
- // area and there are spots to guide the user experience.
- if (mParameters.gestureMode == Parameters::GestureMode::MULTI_TOUCH) {
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- } else {
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- }
- break;
- }
-
// Send events!
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentCookedState.buttonState;
@@ -2746,7 +2637,6 @@
// the pointer is hovering again even if the user is not currently touching
// the touch pad. This ensures that a view will receive a fresh hover enter
// event after a tap.
- const auto [x, y] = mPointerController->getPosition();
PointerProperties pointerProperties;
pointerProperties.clear();
@@ -2755,16 +2645,12 @@
PointerCoords pointerCoords;
pointerCoords.clear();
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
-
- const int32_t displayId = mPointerController->getDisplayId();
out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(),
- mSource, displayId, policyFlags,
+ mSource, ADISPLAY_ID_NONE, policyFlags,
AMOTION_EVENT_ACTION_HOVER_MOVE, 0, flags, metaState,
buttonState, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
- &pointerCoords, 0, 0, x, y, mPointerGesture.downTime,
+ &pointerCoords, 0, 0, 0.f, 0.f, mPointerGesture.downTime,
/*videoFrames=*/{}));
}
@@ -2810,12 +2696,6 @@
// Reset the current pointer gesture.
mPointerGesture.reset();
mPointerVelocityControl.reset();
-
- // Remove any current spots.
- if (mPointerController != nullptr) {
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- mPointerController->clearSpots();
- }
return out;
}
@@ -2951,8 +2831,6 @@
mPointerVelocityControl.reset();
}
- const auto [x, y] = mPointerController->getPosition();
-
mPointerGesture.currentGestureMode = PointerGesture::Mode::BUTTON_CLICK_OR_DRAG;
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
@@ -2961,8 +2839,6 @@
mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
mPointerGesture.currentGestureProperties[0].toolType = ToolType::FINGER;
mPointerGesture.currentGestureCoords[0].clear();
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
} else if (currentFingerCount == 0) {
// Case 3. No fingers down and button is not pressed. (NEUTRAL)
@@ -2977,9 +2853,8 @@
mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP_DRAG) &&
lastFingerCount == 1) {
if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) {
- const auto [x, y] = mPointerController->getPosition();
- if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
- fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
+ if (fabs(0.f - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
+ fabs(0.f - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
ALOGD_IF(DEBUG_GESTURES, "Gestures: TAP");
mPointerGesture.tapUpTime = when;
@@ -3006,7 +2881,7 @@
tapped = true;
} else {
ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP, deltaX=%f, deltaY=%f",
- x - mPointerGesture.tapX, y - mPointerGesture.tapY);
+ 0.f - mPointerGesture.tapX, 0.f - mPointerGesture.tapY);
}
} else {
if (DEBUG_GESTURES) {
@@ -3038,13 +2913,12 @@
mPointerGesture.currentGestureMode = PointerGesture::Mode::HOVER;
if (mPointerGesture.lastGestureMode == PointerGesture::Mode::TAP) {
if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) {
- const auto [x, y] = mPointerController->getPosition();
- if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
- fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
+ if (fabs(0.f - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop &&
+ fabs(0.f - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) {
mPointerGesture.currentGestureMode = PointerGesture::Mode::TAP_DRAG;
} else {
ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f",
- x - mPointerGesture.tapX, y - mPointerGesture.tapY);
+ 0.f - mPointerGesture.tapX, 0.f - mPointerGesture.tapY);
}
} else {
ALOGD_IF(DEBUG_GESTURES, "Gestures: Not a TAP_DRAG, %0.3fms time since up",
@@ -3074,8 +2948,6 @@
down = false;
}
- const auto [x, y] = mPointerController->getPosition();
-
mPointerGesture.currentGestureIdBits.clear();
mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId);
mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0;
@@ -3083,16 +2955,14 @@
mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId;
mPointerGesture.currentGestureProperties[0].toolType = ToolType::FINGER;
mPointerGesture.currentGestureCoords[0].clear();
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
- mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
down ? 1.0f : 0.0f);
if (lastFingerCount == 0 && currentFingerCount != 0) {
mPointerGesture.resetTap();
mPointerGesture.tapDownTime = when;
- mPointerGesture.tapX = x;
- mPointerGesture.tapY = y;
+ mPointerGesture.tapX = 0.f;
+ mPointerGesture.tapY = 0.f;
}
} else {
// Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM)
@@ -3243,8 +3113,8 @@
mCurrentRawState.rawPointerData
.getCentroidOfTouchingPointers(&mPointerGesture.referenceTouchX,
&mPointerGesture.referenceTouchY);
- std::tie(mPointerGesture.referenceGestureX, mPointerGesture.referenceGestureY) =
- mPointerController->getPosition();
+ mPointerGesture.referenceGestureX = 0.f;
+ mPointerGesture.referenceGestureY = 0.f;
}
// Clear the reference deltas for fingers not yet included in the reference calculation.
@@ -3539,8 +3409,6 @@
rotateDelta(mInputDeviceOrientation, &deltaX, &deltaY);
mPointerVelocityControl.move(when, &deltaX, &deltaY);
-
- mPointerController->move(deltaX, deltaY);
}
std::list<NotifyArgs> TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsecs_t readTime,
@@ -3557,13 +3425,6 @@
float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX();
float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY();
- // Styluses are configured specifically for one display. We only update the
- // PointerController for this stylus if the PointerController is configured for
- // the same display as this stylus,
- if (getAssociatedDisplayId() == mViewport.displayId) {
- mPointerController->setPosition(x, y);
- std::tie(x, y) = mPointerController->getPosition();
- }
mPointerSimple.currentCoords = mCurrentCookedState.cookedPointerData.pointerCoords[index];
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
@@ -3601,12 +3462,9 @@
down = isPointerDown(mCurrentRawState.buttonState);
hovering = !down;
- const auto [x, y] = mPointerController->getPosition();
const uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id];
mPointerSimple.currentCoords =
mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex];
- mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
- mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
hovering ? 0.0f : 1.0f);
mPointerSimple.currentProperties.id = 0;
@@ -3619,8 +3477,7 @@
hovering = false;
}
- const int32_t displayId = mPointerController->getDisplayId();
- return dispatchPointerSimple(when, readTime, policyFlags, down, hovering, displayId);
+ return dispatchPointerSimple(when, readTime, policyFlags, down, hovering, ADISPLAY_ID_NONE);
}
std::list<NotifyArgs> TouchInputMapper::abortPointerMouse(nsecs_t when, nsecs_t readTime,
@@ -3641,17 +3498,6 @@
int32_t metaState = getContext()->getGlobalMetaState();
auto cursorPosition = mPointerSimple.currentCoords.getXYValue();
- if (displayId == mPointerController->getDisplayId()) {
- std::tie(cursorPosition.x, cursorPosition.y) = mPointerController->getPosition();
- if (down || hovering) {
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- mPointerController->clearSpots();
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- }
- }
-
if (mPointerSimple.down && !down) {
mPointerSimple.down = false;
@@ -3787,9 +3633,6 @@
mPointerSimple.lastCursorX, mPointerSimple.lastCursorY,
mPointerSimple.downTime,
/*videoFrames=*/{}));
- if (mPointerController != nullptr) {
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- }
}
mPointerSimple.reset();
return out;
@@ -3841,32 +3684,11 @@
}
const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
- const bool showDirectStylusPointer = mConfig.stylusPointerIconEnabled &&
- mDeviceMode == DeviceMode::DIRECT && isStylusEvent(source, pointerProperties) &&
- mPointerController && displayId != ADISPLAY_ID_NONE &&
- displayId == mPointerController->getDisplayId();
- if (showDirectStylusPointer) {
- switch (action & AMOTION_EVENT_ACTION_MASK) {
- case AMOTION_EVENT_ACTION_HOVER_ENTER:
- case AMOTION_EVENT_ACTION_HOVER_MOVE:
- mPointerController->setPresentation(
- PointerControllerInterface::Presentation::STYLUS_HOVER);
- mPointerController
- ->setPosition(mCurrentCookedState.cookedPointerData.pointerCoords[0].getX(),
- mCurrentCookedState.cookedPointerData.pointerCoords[0]
- .getY());
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
- break;
- case AMOTION_EVENT_ACTION_HOVER_EXIT:
- mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
- break;
- }
- }
float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
if (mDeviceMode == DeviceMode::POINTER) {
- std::tie(xCursorPosition, yCursorPosition) = mPointerController->getPosition();
+ xCursorPosition = yCursorPosition = 0.f;
}
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = getDeviceContext().getVideoFrames();
@@ -4138,7 +3960,7 @@
std::optional<int32_t> TouchInputMapper::getAssociatedDisplayId() {
if (mParameters.hasAssociatedDisplay) {
if (mDeviceMode == DeviceMode::POINTER) {
- return std::make_optional(mPointerController->getDisplayId());
+ return ADISPLAY_ID_NONE;
} else {
return std::make_optional(mViewport.displayId);
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 9b7fe93..6485ab2 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -46,7 +46,6 @@
#include "InputMapper.h"
#include "InputReaderBase.h"
#include "NotifyArgs.h"
-#include "PointerControllerInterface.h"
#include "StylusState.h"
#include "TouchButtonAccumulator.h"
@@ -392,9 +391,6 @@
// The time the primary pointer last went down.
nsecs_t mDownTime{0};
- // The pointer controller, or null if the device is not a pointer.
- std::shared_ptr<PointerControllerInterface> mPointerController;
-
std::vector<VirtualKey> mVirtualKeys;
explicit TouchInputMapper(InputDeviceContext& deviceContext,
@@ -837,9 +833,6 @@
// Returns if this touch device is a touch screen with an associated display.
bool isTouchScreen();
- // Updates touch spots if they are enabled. Should only be used when this device is a
- // touchscreen.
- void updateTouchSpots();
bool isPointInsidePhysicalFrame(int32_t x, int32_t y) const;
const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y);
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index f558ba1..6a38aa7 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -47,8 +47,6 @@
namespace {
-static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
-
/**
* Log details of each gesture output by the gestures library.
* Enable this via "adb shell setprop log.tag.TouchpadInputMapperGestures DEBUG" (requires
@@ -237,20 +235,13 @@
TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig)
- : TouchpadInputMapper(deviceContext, readerConfig, ENABLE_POINTER_CHOREOGRAPHER) {}
-
-TouchpadInputMapper::TouchpadInputMapper(InputDeviceContext& deviceContext,
- const InputReaderConfiguration& readerConfig,
- bool enablePointerChoreographer)
: InputMapper(deviceContext, readerConfig),
mGestureInterpreter(NewGestureInterpreter(), DeleteGestureInterpreter),
- mPointerController(getContext()->getPointerController(getDeviceId())),
mTimerProvider(*getContext()),
mStateConverter(deviceContext, mMotionAccumulator),
mGestureConverter(*getContext(), deviceContext, getDeviceId()),
mCapturedEventConverter(*getContext(), deviceContext, mMotionAccumulator, getDeviceId()),
- mMetricsId(metricsIdFromInputDeviceIdentifier(deviceContext.getDeviceIdentifier())),
- mEnablePointerChoreographer(enablePointerChoreographer) {
+ mMetricsId(metricsIdFromInputDeviceIdentifier(deviceContext.getDeviceIdentifier())) {
RawAbsoluteAxisInfo slotAxisInfo;
deviceContext.getAbsoluteAxisInfo(ABS_MT_SLOT, &slotAxisInfo);
if (!slotAxisInfo.valid || slotAxisInfo.maxValue <= 0) {
@@ -277,10 +268,6 @@
}
TouchpadInputMapper::~TouchpadInputMapper() {
- if (mPointerController != nullptr) {
- mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
- }
-
// The gesture interpreter's destructor will try to free its property and timer providers,
// calling PropertyProvider::freeProperty and TimerProvider::freeTimer using a raw pointers.
// Depending on the declaration order in TouchpadInputMapper.h, those providers may have already
@@ -342,33 +329,12 @@
// Only generate events for the associated display.
mDisplayId = assocViewport->displayId;
resolvedViewport = *assocViewport;
- if (!mEnablePointerChoreographer) {
- const bool mismatchedPointerDisplay =
- (assocViewport->displayId != mPointerController->getDisplayId());
- if (mismatchedPointerDisplay) {
- ALOGW("Touchpad \"%s\" associated viewport display does not match pointer "
- "controller",
- mDeviceContext.getName().c_str());
- mDisplayId.reset();
- }
- }
} else {
// The InputDevice is not associated with a viewport, but it controls the mouse pointer.
- if (mEnablePointerChoreographer) {
- // Always use DISPLAY_ID_NONE for touchpad events.
- // PointerChoreographer will make it target the correct the displayId later.
- resolvedViewport =
- getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
- mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
- } else {
- mDisplayId = mPointerController->getDisplayId();
- if (auto v = config.getDisplayViewportById(*mDisplayId); v) {
- resolvedViewport = *v;
- }
- if (auto bounds = mPointerController->getBounds(); bounds) {
- boundsInLogicalDisplay = *bounds;
- }
- }
+ // Always use DISPLAY_ID_NONE for touchpad events.
+ // PointerChoreographer will make it target the correct the displayId later.
+ resolvedViewport = getContext()->getPolicy()->getPointerViewportForAssociatedDisplay();
+ mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt;
}
mGestureConverter.setDisplayId(mDisplayId);
@@ -422,7 +388,6 @@
// The touchpad is being captured, so we need to tidy up any fake fingers etc. that are
// still being reported for a gesture in progress.
out += reset(when);
- mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
} else {
// We're transitioning from captured to uncaptured.
mCapturedEventConverter.reset();
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index 9f272cf..9f685ec 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -72,10 +72,6 @@
void resetGestureInterpreter(nsecs_t when);
explicit TouchpadInputMapper(InputDeviceContext& deviceContext,
const InputReaderConfiguration& readerConfig);
- // Constructor for testing.
- explicit TouchpadInputMapper(InputDeviceContext& deviceContext,
- const InputReaderConfiguration& readerConfig,
- bool enablePointerChoreographer);
void updatePalmDetectionMetrics();
[[nodiscard]] std::list<NotifyArgs> sendHardwareState(nsecs_t when, nsecs_t readTime,
SelfContainedHardwareState schs);
@@ -83,7 +79,6 @@
std::unique_ptr<gestures::GestureInterpreter, void (*)(gestures::GestureInterpreter*)>
mGestureInterpreter;
- std::shared_ptr<PointerControllerInterface> mPointerController;
PropertyProvider mPropertyProvider;
TimerProvider mTimerProvider;
@@ -111,8 +106,6 @@
// Tracking IDs for touches that have at some point been reported as palms by the touchpad.
std::set<int32_t> mPalmTrackingIds;
- const bool mEnablePointerChoreographer;
-
// The display that events generated by this mapper should target. This can be set to
// ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e.
// std::nullopt), all events will be ignored.
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 39a88e5..ff95857 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -66,7 +66,6 @@
const InputDeviceContext& deviceContext, int32_t deviceId)
: mDeviceId(deviceId),
mReaderContext(readerContext),
- mPointerController(readerContext.getPointerController(deviceId)),
mEnableFlingStop(input_flags::enable_touchpad_fling_stop()) {
deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mXAxisInfo);
deviceContext.getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mYAxisInfo);
@@ -174,7 +173,6 @@
const Gesture& gesture) {
float deltaX = gesture.details.move.dx;
float deltaY = gesture.details.move.dy;
- const auto [oldXCursorPosition, oldYCursorPosition] = mPointerController->getPosition();
if (ENABLE_TOUCHPAD_PALM_REJECTION_V2) {
bool wasHoverCancelled = mIsHoverCancelled;
// Gesture will be cancelled if it started before the user started typing and
@@ -185,8 +183,7 @@
if (!wasHoverCancelled && mIsHoverCancelled) {
// This is the first event of the cancelled gesture, we won't return because we need to
// generate a HOVER_EXIT event
- mPointerController->fade(PointerControllerInterface::Transition::GRADUAL);
- return exitHover(when, readTime, oldXCursorPosition, oldYCursorPosition);
+ return exitHover(when, readTime);
} else if (mIsHoverCancelled) {
return {};
}
@@ -202,30 +199,23 @@
(std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) {
enableTapToClick(when);
}
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- mPointerController->move(deltaX, deltaY);
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
}
std::list<NotifyArgs> out;
const bool down = isPointerDown(mButtonState);
if (!down) {
- out += enterHover(when, readTime, oldXCursorPosition, oldYCursorPosition);
+ out += enterHover(when, readTime);
}
- const auto [newXCursorPosition, newYCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, newXCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, newYCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);
const int32_t action = down ? AMOTION_EVENT_ACTION_MOVE : AMOTION_EVENT_ACTION_HOVER_MOVE;
out.push_back(makeMotionArgs(when, readTime, action, /*actionButton=*/0, mButtonState,
- /*pointerCount=*/1, &coords, newXCursorPosition,
- newYCursorPosition));
+ /*pointerCount=*/1, &coords));
return out;
}
@@ -233,15 +223,8 @@
const Gesture& gesture) {
std::list<NotifyArgs> out = {};
- mPointerController->setPresentation(PointerControllerInterface::Presentation::POINTER);
- mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE);
-
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
-
PointerCoords coords;
coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
@@ -274,16 +257,15 @@
newButtonState |= actionButton;
pressEvents.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS,
actionButton, newButtonState,
- /*pointerCount=*/1, &coords, xCursorPosition,
- yCursorPosition));
+ /*pointerCount=*/1, &coords));
}
}
if (!isPointerDown(mButtonState) && isPointerDown(newButtonState)) {
mDownTime = when;
- out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += exitHover(when, readTime);
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
/* actionButton= */ 0, newButtonState, /* pointerCount= */ 1,
- &coords, xCursorPosition, yCursorPosition));
+ &coords));
}
out.splice(out.end(), pressEvents);
@@ -299,16 +281,15 @@
newButtonState &= ~actionButton;
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
actionButton, newButtonState, /* pointerCount= */ 1,
- &coords, xCursorPosition, yCursorPosition));
+ &coords));
}
}
if (isPointerDown(mButtonState) && !isPointerDown(newButtonState)) {
coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
- newButtonState, /* pointerCount= */ 1, &coords,
- xCursorPosition, yCursorPosition));
+ newButtonState, /* pointerCount= */ 1, &coords));
mButtonState = newButtonState;
- out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += enterHover(when, readTime);
}
mButtonState = newButtonState;
return out;
@@ -316,12 +297,9 @@
std::list<NotifyArgs> GestureConverter::releaseAllButtons(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out;
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
PointerCoords coords;
coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
const bool pointerDown = isPointerDown(mButtonState);
@@ -332,17 +310,15 @@
if (mButtonState & button) {
newButtonState &= ~button;
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
- button, newButtonState, /*pointerCount=*/1, &coords,
- xCursorPosition, yCursorPosition));
+ button, newButtonState, /*pointerCount=*/1, &coords));
}
}
mButtonState = 0;
if (pointerDown) {
coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.0f);
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /*actionButton=*/0,
- mButtonState, /*pointerCount=*/1, &coords, xCursorPosition,
- yCursorPosition));
- out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ mButtonState, /*pointerCount=*/1, &coords));
+ out += enterHover(when, readTime);
}
return out;
}
@@ -351,19 +327,15 @@
const Gesture& gesture) {
std::list<NotifyArgs> out;
PointerCoords& coords = mFakeFingerCoords[0];
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mCurrentClassification != MotionClassification::TWO_FINGER_SWIPE) {
- out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += exitHover(when, readTime);
mCurrentClassification = MotionClassification::TWO_FINGER_SWIPE;
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
mDownTime = when;
NotifyMotionArgs args =
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN, /* actionButton= */ 0,
- mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data(),
- xCursorPosition, yCursorPosition);
+ mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data());
args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
out.push_back(args);
}
@@ -378,8 +350,7 @@
coords.setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, -gesture.details.scroll.dy);
NotifyMotionArgs args =
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0,
- mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data(),
- xCursorPosition, yCursorPosition);
+ mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data());
args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
out.push_back(args);
return out;
@@ -409,28 +380,22 @@
// avoid side effects (e.g. activation of UI elements).
// TODO(b/326056750): add an API for fling stops.
mFlingMayBeInProgress = false;
- const auto [xCursorPosition, yCursorPosition] =
- mPointerController->getPosition();
PointerCoords coords;
coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
std::list<NotifyArgs> out;
mDownTime = when;
mCurrentClassification = MotionClassification::TWO_FINGER_SWIPE;
- out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += exitHover(when, readTime);
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
/*actionButton=*/0, /*buttonState=*/0,
- /*pointerCount=*/1, &coords, xCursorPosition,
- yCursorPosition));
+ /*pointerCount=*/1, &coords));
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_CANCEL,
/*actionButton=*/0, /*buttonState=*/0,
- /*pointerCount=*/1, &coords, xCursorPosition,
- yCursorPosition));
- out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ /*pointerCount=*/1, &coords));
+ out += enterHover(when, readTime);
mCurrentClassification = MotionClassification::NONE;
return out;
} else {
@@ -455,17 +420,15 @@
std::list<NotifyArgs> GestureConverter::endScroll(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out;
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, 0);
NotifyMotionArgs args =
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /* actionButton= */ 0,
- mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data(),
- xCursorPosition, yCursorPosition);
+ mButtonState, /* pointerCount= */ 1, mFakeFingerCoords.data());
args.flags |= AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE;
out.push_back(args);
mCurrentClassification = MotionClassification::NONE;
- out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += enterHover(when, readTime);
return out;
}
@@ -475,26 +438,26 @@
float dx, float dy) {
std::list<NotifyArgs> out = {};
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
// If the user changes the number of fingers mid-way through a swipe (e.g. they start with
// three and then put a fourth finger down), the gesture library will treat it as two
// separate swipes with an appropriate lift event between them, so we don't have to worry
// about the finger count changing mid-swipe.
- out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += exitHover(when, readTime);
mCurrentClassification = MotionClassification::MULTI_FINGER_SWIPE;
mSwipeFingerCount = fingerCount;
constexpr float FAKE_FINGER_SPACING = 100;
- float xCoord = xCursorPosition - FAKE_FINGER_SPACING * (mSwipeFingerCount - 1) / 2;
+ float xCoord = 0.f - FAKE_FINGER_SPACING * (mSwipeFingerCount - 1) / 2;
for (size_t i = 0; i < mSwipeFingerCount; i++) {
PointerCoords& coords = mFakeFingerCoords[i];
coords.clear();
+ // PointerChoreographer will add the cursor position to these pointers.
coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCoord);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 0.f);
coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
xCoord += FAKE_FINGER_SPACING;
}
@@ -504,14 +467,13 @@
fingerCount);
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
/* actionButton= */ 0, mButtonState, /* pointerCount= */ 1,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
for (size_t i = 1; i < mSwipeFingerCount; i++) {
out.push_back(makeMotionArgs(when, readTime,
AMOTION_EVENT_ACTION_POINTER_DOWN |
(i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
/* actionButton= */ 0, mButtonState,
- /* pointerCount= */ i + 1, mFakeFingerCoords.data(),
- xCursorPosition, yCursorPosition));
+ /* pointerCount= */ i + 1, mFakeFingerCoords.data()));
}
}
float rotatedDeltaX = dx, rotatedDeltaY = -dy;
@@ -529,7 +491,7 @@
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, yOffset);
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /* actionButton= */ 0,
mButtonState, /* pointerCount= */ mSwipeFingerCount,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
return out;
}
@@ -539,7 +501,6 @@
if (mCurrentClassification != MotionClassification::MULTI_FINGER_SWIPE) {
return out;
}
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET, 0);
@@ -548,22 +509,20 @@
AMOTION_EVENT_ACTION_POINTER_UP |
((i - 1) << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
/* actionButton= */ 0, mButtonState, /* pointerCount= */ i,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
}
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP,
/* actionButton= */ 0, mButtonState, /* pointerCount= */ 1,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SWIPE_FINGER_COUNT, 0);
mCurrentClassification = MotionClassification::NONE;
- out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += enterHover(when, readTime);
mSwipeFingerCount = 0;
return out;
}
[[nodiscard]] std::list<NotifyArgs> GestureConverter::handlePinch(nsecs_t when, nsecs_t readTime,
const Gesture& gesture) {
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
-
// Pinch gesture phases are reported a little differently from others, in that the same details
// struct is used for all phases of the gesture, just with different zoom_state values. When
// zoom_state is START or END, dz will always be 1, so we don't need to move the pointers in
@@ -575,28 +534,27 @@
gesture.details.pinch.zoom_state);
std::list<NotifyArgs> out;
- out += exitHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += exitHover(when, readTime);
mCurrentClassification = MotionClassification::PINCH;
mPinchFingerSeparation = INITIAL_PINCH_SEPARATION_PX;
+ // PointerChoreographer will add the cursor position to these pointers.
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 1.0);
- mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
- xCursorPosition - mPinchFingerSeparation / 2);
- mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 0.f - mPinchFingerSeparation / 2);
+ mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 0.f);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
- mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X,
- xCursorPosition + mPinchFingerSeparation / 2);
- mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 0.f + mPinchFingerSeparation / 2);
+ mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 0.f);
mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f);
mDownTime = when;
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_DOWN,
/* actionButton= */ 0, mButtonState, /* pointerCount= */ 1,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
out.push_back(makeMotionArgs(when, readTime,
AMOTION_EVENT_ACTION_POINTER_DOWN |
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT,
/* actionButton= */ 0, mButtonState, /* pointerCount= */ 2,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
return out;
}
@@ -605,77 +563,65 @@
}
mPinchFingerSeparation *= gesture.details.pinch.dz;
+ // PointerChoreographer will add the cursor position to these pointers.
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR,
gesture.details.pinch.dz);
- mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
- xCursorPosition - mPinchFingerSeparation / 2);
- mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
- mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X,
- xCursorPosition + mPinchFingerSeparation / 2);
- mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
+ mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 0.f - mPinchFingerSeparation / 2);
+ mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 0.f);
+ mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_X, 0.f + mPinchFingerSeparation / 2);
+ mFakeFingerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_Y, 0.f);
return {makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, /*actionButton=*/0,
- mButtonState, /*pointerCount=*/2, mFakeFingerCoords.data(),
- xCursorPosition, yCursorPosition)};
+ mButtonState, /*pointerCount=*/2, mFakeFingerCoords.data())};
}
std::list<NotifyArgs> GestureConverter::endPinch(nsecs_t when, nsecs_t readTime) {
std::list<NotifyArgs> out;
- const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 1.0);
out.push_back(makeMotionArgs(when, readTime,
AMOTION_EVENT_ACTION_POINTER_UP |
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT,
/*actionButton=*/0, mButtonState, /*pointerCount=*/2,
- mFakeFingerCoords.data(), xCursorPosition, yCursorPosition));
+ mFakeFingerCoords.data()));
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_UP, /*actionButton=*/0,
- mButtonState, /*pointerCount=*/1, mFakeFingerCoords.data(),
- xCursorPosition, yCursorPosition));
+ mButtonState, /*pointerCount=*/1, mFakeFingerCoords.data()));
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_PINCH_SCALE_FACTOR, 0);
mCurrentClassification = MotionClassification::NONE;
- out += enterHover(when, readTime, xCursorPosition, yCursorPosition);
+ out += enterHover(when, readTime);
return out;
}
-std::list<NotifyArgs> GestureConverter::enterHover(nsecs_t when, nsecs_t readTime,
- float xCursorPosition, float yCursorPosition) {
+std::list<NotifyArgs> GestureConverter::enterHover(nsecs_t when, nsecs_t readTime) {
if (!mIsHovering) {
mIsHovering = true;
- return {makeHoverEvent(when, readTime, AMOTION_EVENT_ACTION_HOVER_ENTER, xCursorPosition,
- yCursorPosition)};
+ return {makeHoverEvent(when, readTime, AMOTION_EVENT_ACTION_HOVER_ENTER)};
} else {
return {};
}
}
-std::list<NotifyArgs> GestureConverter::exitHover(nsecs_t when, nsecs_t readTime,
- float xCursorPosition, float yCursorPosition) {
+std::list<NotifyArgs> GestureConverter::exitHover(nsecs_t when, nsecs_t readTime) {
if (mIsHovering) {
mIsHovering = false;
- return {makeHoverEvent(when, readTime, AMOTION_EVENT_ACTION_HOVER_EXIT, xCursorPosition,
- yCursorPosition)};
+ return {makeHoverEvent(when, readTime, AMOTION_EVENT_ACTION_HOVER_EXIT)};
} else {
return {};
}
}
-NotifyMotionArgs GestureConverter::makeHoverEvent(nsecs_t when, nsecs_t readTime, int32_t action,
- float xCursorPosition, float yCursorPosition) {
+NotifyMotionArgs GestureConverter::makeHoverEvent(nsecs_t when, nsecs_t readTime, int32_t action) {
PointerCoords coords;
coords.clear();
- coords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
- coords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
return makeMotionArgs(when, readTime, action, /*actionButton=*/0, mButtonState,
- /*pointerCount=*/1, &coords, xCursorPosition, yCursorPosition);
+ /*pointerCount=*/1, &coords);
}
NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
int32_t actionButton, int32_t buttonState,
uint32_t pointerCount,
- const PointerCoords* pointerCoords,
- float xCursorPosition, float yCursorPosition) {
+ const PointerCoords* pointerCoords) {
return {mReaderContext.getNextId(),
when,
readTime,
@@ -695,8 +641,8 @@
pointerCoords,
/* xPrecision= */ 1.0f,
/* yPrecision= */ 1.0f,
- xCursorPosition,
- yCursorPosition,
+ /* xCursorPosition= */ 0.f,
+ /* yCursorPosition= */ 0.f,
/* downTime= */ mDownTime,
/* videoFrames= */ {}};
}
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index c8f437e..e6ced0f 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -20,7 +20,6 @@
#include <list>
#include <memory>
-#include <PointerControllerInterface.h>
#include <android/input.h>
#include <utils/Timers.h>
@@ -41,8 +40,7 @@
*/
constexpr std::chrono::nanoseconds TAP_ENABLE_DELAY_NANOS = 400ms;
-// Converts Gesture structs from the gestures library into NotifyArgs and the appropriate
-// PointerController calls.
+// Converts Gesture structs from the gestures library into NotifyArgs.
class GestureConverter {
public:
GestureConverter(InputReaderContext& readerContext, const InputDeviceContext& deviceContext,
@@ -85,18 +83,14 @@
const Gesture& gesture);
[[nodiscard]] std::list<NotifyArgs> endPinch(nsecs_t when, nsecs_t readTime);
- [[nodiscard]] std::list<NotifyArgs> enterHover(nsecs_t when, nsecs_t readTime,
- float xCursorPosition, float yCursorPosition);
- [[nodiscard]] std::list<NotifyArgs> exitHover(nsecs_t when, nsecs_t readTime,
- float xCursorPosition, float yCursorPosition);
+ [[nodiscard]] std::list<NotifyArgs> enterHover(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> exitHover(nsecs_t when, nsecs_t readTime);
- NotifyMotionArgs makeHoverEvent(nsecs_t when, nsecs_t readTime, int32_t action,
- float xCursorPosition, float yCursorPosition);
+ NotifyMotionArgs makeHoverEvent(nsecs_t when, nsecs_t readTime, int32_t action);
NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
int32_t actionButton, int32_t buttonState,
- uint32_t pointerCount, const PointerCoords* pointerCoords,
- float xCursorPosition, float yCursorPosition);
+ uint32_t pointerCount, const PointerCoords* pointerCoords);
void enableTapToClick(nsecs_t when);
bool mIsHoverCancelled{false};
@@ -104,7 +98,6 @@
const int32_t mDeviceId;
InputReaderContext& mReaderContext;
- std::shared_ptr<PointerControllerInterface> mPointerController;
const bool mEnableFlingStop;
std::optional<int32_t> mDisplayId;
diff --git a/services/inputflinger/rust/input_filter_thread.rs b/services/inputflinger/rust/input_filter_thread.rs
index 96e5681..34f9b25 100644
--- a/services/inputflinger/rust/input_filter_thread.rs
+++ b/services/inputflinger/rust/input_filter_thread.rs
@@ -309,7 +309,7 @@
let now = clock_gettime(ClockId::CLOCK_MONOTONIC).unwrap().num_milliseconds();
test_thread.request_timeout_at_time((now + 10) * 1000000);
- std::thread::sleep(Duration::from_millis(20));
+ std::thread::sleep(Duration::from_millis(100));
assert!(test_thread_callback.is_notify_timeout_called());
}
diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp
index c44f880..c237fb6 100644
--- a/services/inputflinger/tests/CursorInputMapper_test.cpp
+++ b/services/inputflinger/tests/CursorInputMapper_test.cpp
@@ -29,7 +29,6 @@
#include <linux/input.h>
#include <utils/Timers.h>
-#include "FakePointerController.h"
#include "InputMapperTest.h"
#include "InputReaderBase.h"
#include "InterfaceMocks.h"
@@ -157,12 +156,9 @@
mFakePolicy->addDisplayViewport(createPrimaryViewport(ui::Rotation::Rotation0));
}
- virtual bool isPointerChoreographerEnabled() { return false; }
-
void createMapper() {
createDevice();
- mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration,
- isPointerChoreographerEnabled());
+ mMapper = createInputMapper<CursorInputMapper>(*mDeviceContext, mReaderConfiguration);
}
void setPointerCapture(bool enabled) {
@@ -200,8 +196,6 @@
input_flags::enable_new_mouse_pointer_ballistics(false);
CursorInputMapperUnitTestBase::SetUp();
}
-
- bool isPointerChoreographerEnabled() override { return false; }
};
TEST_F(CursorInputMapperUnitTest, GetSourcesReturnsMouseInPointerMode) {
@@ -325,12 +319,9 @@
// Disable pointer capture. Afterwards, events should be generated the usual way.
setPointerCapture(false);
- const auto expectedCoords = CursorInputMapperUnitTest::isPointerChoreographerEnabled()
- ? WithCoords(0, 0)
- : WithCoords(INITIAL_CURSOR_X + 10.0f, INITIAL_CURSOR_Y + 20.0f);
- const auto expectedCursorPosition = CursorInputMapperUnitTest::isPointerChoreographerEnabled()
- ? WithCursorPosition(INVALID_CURSOR_POSITION, INVALID_CURSOR_POSITION)
- : WithCursorPosition(INITIAL_CURSOR_X + 10.0f, INITIAL_CURSOR_Y + 20.0f);
+ const auto expectedCoords = WithCoords(0, 0);
+ const auto expectedCursorPosition =
+ WithCursorPosition(INVALID_CURSOR_POSITION, INVALID_CURSOR_POSITION);
args.clear();
args += process(EV_REL, REL_X, 10);
args += process(EV_REL, REL_Y, 20);
@@ -342,42 +333,6 @@
WithRelativeMotion(10.0f, 20.0f)))));
}
-TEST_F(CursorInputMapperUnitTest,
- PopulateDeviceInfoReturnsRangeFromPointerControllerInPointerMode) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- mFakePolicy->clearViewports();
- mFakePointerController->clearBounds();
- createMapper();
-
- InputDeviceInfo info;
- mMapper->populateDeviceInfo(info);
-
- // Initially there should not be a valid motion range because there's no viewport or pointer
- // bounds.
- ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
- ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AINPUT_MOTION_RANGE_PRESSURE,
- AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
-
- // When the bounds are set, then there should be a valid motion range.
- mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1);
- mFakePolicy->addDisplayViewport(createPrimaryViewport(ui::Rotation::Rotation0));
- std::list<NotifyArgs> args =
- mMapper->reconfigure(systemTime(), mReaderConfiguration,
- InputReaderConfiguration::Change::DISPLAY_INFO);
- ASSERT_THAT(args, testing::IsEmpty());
-
- InputDeviceInfo info2;
- mMapper->populateDeviceInfo(info2);
-
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE, 1,
- 800 - 1, 0.0f, 0.0f));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE, 2,
- 480 - 1, 0.0f, 0.0f));
- ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE,
- AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
-}
-
TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsScaledRangeInNavigationMode) {
mPropertyMap.addProperty("cursor.mode", "navigation");
createMapper();
@@ -649,334 +604,9 @@
ASSERT_NO_FATAL_FAILURE(testMotionRotation(-1, 1, 1, 1));
}
-TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesOrientationChanges) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- DisplayViewport viewport = createPrimaryViewport(ui::Rotation::Rotation90);
- mFakePointerController->setDisplayViewport(viewport);
- mReaderConfiguration.setDisplayViewports({viewport});
- createMapper();
-
- // Verify that the coordinates are rotated.
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
- WithRelativeMotion(-20.0f, 10.0f)))));
-
- // Enable Pointer Capture.
- setPointerCapture(true);
-
- // Move and verify rotation is not applied.
- args = process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(ACTION_MOVE),
- WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
- WithCoords(10.0f, 20.0f)))));
-}
-
-TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) {
- DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
- DisplayViewport secondaryViewport = createSecondaryViewport();
- mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
- // Set up the secondary display as the display on which the pointer should be shown. The
- // InputDevice is not associated with any display.
- mFakePointerController->setDisplayViewport(secondaryViewport);
- mFakePointerController->setPosition(100, 200);
- createMapper();
-
- // Ensure input events are generated for the secondary display.
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
- WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f)))));
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(110.0f, 220.0f));
-}
-
-TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdWithAssociatedViewport) {
- DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
- DisplayViewport secondaryViewport = createSecondaryViewport();
- mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
- // Set up the secondary display as the display on which the pointer should be shown.
- mFakePointerController->setDisplayViewport(secondaryViewport);
- mFakePointerController->setPosition(100, 200);
- createDevice();
- // Associate the InputDevice with the secondary display.
- ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
- mMapper = createInputMapper<
- CursorInputMapper>(deviceContext, mReaderConfiguration,
- CursorInputMapperUnitTest::isPointerChoreographerEnabled());
-
- // Ensure input events are generated for the secondary display.
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE),
- WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(110.0f, 220.0f)))));
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(110.0f, 220.0f));
-}
-
-TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdIgnoresEventsForMismatchedPointerDisplay) {
- DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
- DisplayViewport secondaryViewport = createSecondaryViewport();
- mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
- // Set up the primary display as the display on which the pointer should be shown.
- mFakePointerController->setDisplayViewport(primaryViewport);
- createDevice();
- // Associate the InputDevice with the secondary display.
- ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
- mMapper = createInputMapper<
- CursorInputMapper>(deviceContext, mReaderConfiguration,
- CursorInputMapperUnitTest::isPointerChoreographerEnabled());
-
- // The mapper should not generate any events because it is associated with a display that is
- // different from the pointer display.
- std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args, testing::IsEmpty());
-}
-
-TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleAllButtons) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
-
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
-
- std::list<NotifyArgs> args;
-
- // press BTN_LEFT, release BTN_LEFT
- args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 1);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f)))));
- args.clear();
-
- args += process(ARBITRARY_TIME, EV_KEY, BTN_LEFT, 0);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(0), WithCoords(100.0f, 200.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithButtonState(0), WithCoords(100.0f, 200.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithButtonState(0), WithCoords(100.0f, 200.0f),
- WithPressure(0.0f)))));
- args.clear();
-
- // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE
- args += process(ARBITRARY_TIME, EV_KEY, BTN_RIGHT, 1);
- args += process(ARBITRARY_TIME, EV_KEY, BTN_MIDDLE, 1);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY |
- AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY |
- AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f)))));
- args.clear();
-
- args += process(ARBITRARY_TIME, EV_KEY, BTN_RIGHT, 0);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithButtonState(AMOTION_EVENT_BUTTON_TERTIARY),
- WithCoords(100.0f, 200.0f), WithPressure(1.0f)))));
- args.clear();
-
- args += process(ARBITRARY_TIME, EV_KEY, BTN_MIDDLE, 0);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(0), WithCoords(100.0f, 200.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithButtonState(0),
- WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(100.0f, 200.0f), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithButtonState(0),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithCoords(100.0f, 200.0f), WithPressure(0.0f)))));
-}
-
-class CursorInputMapperButtonKeyTest
- : public CursorInputMapperUnitTest,
- public testing::WithParamInterface<
- std::tuple<int32_t /*evdevCode*/, int32_t /*expectedButtonState*/,
- int32_t /*expectedKeyCode*/>> {
- virtual bool isPointerChoreographerEnabled() override { return false; }
-};
-
-TEST_P(CursorInputMapperButtonKeyTest, ProcessShouldHandleButtonKey) {
- auto [evdevCode, expectedButtonState, expectedKeyCode] = GetParam();
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
-
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
-
- std::list<NotifyArgs> args;
-
- args += process(ARBITRARY_TIME, EV_KEY, evdevCode, 1);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
- WithKeyCode(expectedKeyCode))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithButtonState(expectedButtonState),
- WithCoords(100.0f, 200.0f), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithButtonState(expectedButtonState),
- WithCoords(100.0f, 200.0f), WithPressure(0.0f)))));
- args.clear();
-
- args += process(ARBITRARY_TIME, EV_KEY, evdevCode, 0);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithButtonState(0), WithCoords(100.0f, 200.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithButtonState(0), WithCoords(100.0f, 200.0f),
- WithPressure(0.0f))),
- VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_UP),
- WithKeyCode(expectedKeyCode)))));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- SideExtraBackAndForward, CursorInputMapperButtonKeyTest,
- testing::Values(std::make_tuple(BTN_SIDE, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK),
- std::make_tuple(BTN_EXTRA, AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD),
- std::make_tuple(BTN_BACK, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK),
- std::make_tuple(BTN_FORWARD, AMOTION_EVENT_BUTTON_FORWARD,
- AKEYCODE_FORWARD)));
-
-TEST_F(CursorInputMapperUnitTest, ProcessShouldMoveThePointerAroundInPointerMode) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
-
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
-
- std::list<NotifyArgs> args;
-
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithCoords(110.0f, 220.0f), WithPressure(0.0f), WithSize(0.0f),
- WithTouchDimensions(0.0f, 0.0f), WithToolDimensions(0.0f, 0.0f),
- WithOrientation(0.0f), WithDistance(0.0f)))));
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(110.0f, 220.0f));
-}
-
-/**
- * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any
- * pointer acceleration or speed processing should not be applied.
- */
-TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- const VelocityControlParameters testParams(/*scale=*/5.f, /*lowThreshold=*/0.f,
- /*highThreshold=*/100.f, /*acceleration=*/10.f);
- mReaderConfiguration.pointerVelocityControlParameters = testParams;
- mFakePolicy->setVelocityControlParams(testParams);
- createMapper();
-
- std::list<NotifyArgs> args;
-
- // Move and verify scale is applied.
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE),
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE)))));
- NotifyMotionArgs motionArgs = std::get<NotifyMotionArgs>(args.front());
- const float relX = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X);
- const float relY = motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y);
- ASSERT_GT(relX, 10);
- ASSERT_GT(relY, 20);
- args.clear();
-
- // Enable Pointer Capture
- setPointerCapture(true);
-
- // Move and verify scale is not applied.
- args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
- args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithSource(AINPUT_SOURCE_MOUSE_RELATIVE),
- WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(10, 20)))));
-}
-
-// TODO(b/311416205): De-duplicate the test cases after the refactoring is complete and the flagging
-// logic can be removed.
-class CursorInputMapperUnitTestWithChoreographer : public CursorInputMapperUnitTestBase {
-protected:
- void SetUp() override {
- input_flags::enable_new_mouse_pointer_ballistics(false);
- CursorInputMapperUnitTestBase::SetUp();
- }
-
- bool isPointerChoreographerEnabled() override { return true; }
-};
-
-TEST_F(CursorInputMapperUnitTestWithChoreographer, PopulateDeviceInfoReturnsRangeFromPolicy) {
+TEST_F(CursorInputMapperUnitTest, PopulateDeviceInfoReturnsRangeFromPolicy) {
mPropertyMap.addProperty("cursor.mode", "pointer");
mFakePolicy->clearViewports();
- mFakePointerController->clearBounds();
createMapper();
InputDeviceInfo info;
@@ -1009,14 +639,12 @@
AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
}
-TEST_F(CursorInputMapperUnitTestWithChoreographer, ConfigureDisplayIdWithAssociatedViewport) {
+TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdWithAssociatedViewport) {
DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
DisplayViewport secondaryViewport = createSecondaryViewport();
mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
// Set up the secondary display as the display on which the pointer should be shown.
// The InputDevice is not associated with any display.
- mFakePointerController->setDisplayViewport(secondaryViewport);
- mFakePointerController->setPosition(100, 200);
createDevice();
ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
@@ -1032,13 +660,12 @@
WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(0.0f, 0.0f)))));
}
-TEST_F(CursorInputMapperUnitTestWithChoreographer,
+TEST_F(CursorInputMapperUnitTest,
ConfigureDisplayIdShouldGenerateEventForMismatchedPointerDisplay) {
DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation90);
DisplayViewport secondaryViewport = createSecondaryViewport();
mReaderConfiguration.setDisplayViewports({primaryViewport, secondaryViewport});
// Set up the primary display as the display on which the pointer should be shown.
- mFakePointerController->setDisplayViewport(primaryViewport);
createDevice();
// Associate the InputDevice with the secondary display.
ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, secondaryViewport);
@@ -1057,13 +684,10 @@
WithDisplayId(SECONDARY_DISPLAY_ID), WithCoords(0.0f, 0.0f)))));
}
-TEST_F(CursorInputMapperUnitTestWithChoreographer, ProcessShouldHandleAllButtonsWithZeroCoords) {
+TEST_F(CursorInputMapperUnitTest, ProcessShouldHandleAllButtonsWithZeroCoords) {
mPropertyMap.addProperty("cursor.mode", "pointer");
createMapper();
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
-
std::list<NotifyArgs> args;
// press BTN_LEFT, release BTN_LEFT
@@ -1147,21 +771,17 @@
WithCoords(0.0f, 0.0f), WithPressure(0.0f)))));
}
-class CursorInputMapperButtonKeyTestWithChoreographer
- : public CursorInputMapperUnitTestWithChoreographer,
+class CursorInputMapperButtonKeyTest
+ : public CursorInputMapperUnitTest,
public testing::WithParamInterface<
std::tuple<int32_t /*evdevCode*/, int32_t /*expectedButtonState*/,
int32_t /*expectedKeyCode*/>> {};
-TEST_P(CursorInputMapperButtonKeyTestWithChoreographer,
- ProcessShouldHandleButtonKeyWithZeroCoords) {
+TEST_P(CursorInputMapperButtonKeyTest, ProcessShouldHandleButtonKeyWithZeroCoords) {
auto [evdevCode, expectedButtonState, expectedKeyCode] = GetParam();
mPropertyMap.addProperty("cursor.mode", "pointer");
createMapper();
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
-
std::list<NotifyArgs> args;
args += process(ARBITRARY_TIME, EV_KEY, evdevCode, 1);
@@ -1195,20 +815,17 @@
}
INSTANTIATE_TEST_SUITE_P(
- SideExtraBackAndForward, CursorInputMapperButtonKeyTestWithChoreographer,
+ SideExtraBackAndForward, CursorInputMapperButtonKeyTest,
testing::Values(std::make_tuple(BTN_SIDE, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK),
std::make_tuple(BTN_EXTRA, AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD),
std::make_tuple(BTN_BACK, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK),
std::make_tuple(BTN_FORWARD, AMOTION_EVENT_BUTTON_FORWARD,
AKEYCODE_FORWARD)));
-TEST_F(CursorInputMapperUnitTestWithChoreographer, ProcessWhenModeIsPointerShouldKeepZeroCoords) {
+TEST_F(CursorInputMapperUnitTest, ProcessWhenModeIsPointerShouldKeepZeroCoords) {
mPropertyMap.addProperty("cursor.mode", "pointer");
createMapper();
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(100, 200);
-
std::list<NotifyArgs> args;
args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
@@ -1223,7 +840,11 @@
WithOrientation(0.0f), WithDistance(0.0f)))));
}
-TEST_F(CursorInputMapperUnitTestWithChoreographer, PointerCaptureDisablesVelocityProcessing) {
+/**
+ * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any
+ * pointer acceleration or speed processing should not be applied.
+ */
+TEST_F(CursorInputMapperUnitTest, PointerCaptureDisablesVelocityProcessing) {
mPropertyMap.addProperty("cursor.mode", "pointer");
const VelocityControlParameters testParams(/*scale=*/5.f, /*lowThreshold=*/0.f,
/*highThreshold=*/100.f, /*acceleration=*/10.f);
@@ -1267,7 +888,7 @@
ASSERT_EQ(20, relY2);
}
-TEST_F(CursorInputMapperUnitTestWithChoreographer, ConfigureDisplayIdNoAssociatedViewport) {
+TEST_F(CursorInputMapperUnitTest, ConfigureDisplayIdNoAssociatedViewport) {
// Set up the default display.
mFakePolicy->clearViewports();
mFakePolicy->addDisplayViewport(createPrimaryViewport(ui::Rotation::Rotation0));
@@ -1279,9 +900,6 @@
createMapper();
- mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
- mFakePointerController->setPosition(100, 200);
-
// Ensure input events are generated without display ID or coords, because they will be decided
// later by PointerChoreographer.
std::list<NotifyArgs> args;
@@ -1302,8 +920,6 @@
input_flags::enable_new_mouse_pointer_ballistics(true);
CursorInputMapperUnitTestBase::SetUp();
}
-
- bool isPointerChoreographerEnabled() override { return true; }
};
TEST_F(CursorInputMapperUnitTestWithNewBallistics, PointerCaptureDisablesVelocityProcessing) {
@@ -1422,14 +1038,11 @@
} // namespace
+// --- BluetoothCursorInputMapperUnitTest ---
+
class BluetoothCursorInputMapperUnitTest : public CursorInputMapperUnitTestBase {
protected:
- void SetUp() override {
- SetUpWithBus(BUS_BLUETOOTH);
-
- mFakePointerController = std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(mFakePointerController);
- }
+ void SetUp() override { SetUpWithBus(BUS_BLUETOOTH); }
};
TEST_F(BluetoothCursorInputMapperUnitTest, TimestampSmoothening) {
@@ -1537,123 +1150,4 @@
argsList.clear();
}
-// --- BluetoothCursorInputMapperUnitTestWithChoreographer ---
-
-class BluetoothCursorInputMapperUnitTestWithChoreographer : public CursorInputMapperUnitTestBase {
-protected:
- void SetUp() override {
- SetUpWithBus(BUS_BLUETOOTH);
-
- mFakePointerController = std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(mFakePointerController);
- }
-
- bool isPointerChoreographerEnabled() override { return true; }
-};
-
-TEST_F(BluetoothCursorInputMapperUnitTestWithChoreographer, TimestampSmoothening) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
- std::list<NotifyArgs> argsList;
-
- nsecs_t kernelEventTime = ARBITRARY_TIME;
- nsecs_t expectedEventTime = ARBITRARY_TIME;
- argsList += process(kernelEventTime, EV_REL, REL_X, 1);
- argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
- argsList.clear();
-
- // Process several events that come in quick succession, according to their timestamps.
- for (int i = 0; i < 3; i++) {
- constexpr static nsecs_t delta = ms2ns(1);
- static_assert(delta < MIN_BLUETOOTH_TIMESTAMP_DELTA);
- kernelEventTime += delta;
- expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
-
- argsList += process(kernelEventTime, EV_REL, REL_X, 1);
- argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
- argsList.clear();
- }
-}
-
-TEST_F(BluetoothCursorInputMapperUnitTestWithChoreographer, TimestampSmootheningIsCapped) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
- std::list<NotifyArgs> argsList;
-
- nsecs_t expectedEventTime = ARBITRARY_TIME;
- argsList += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
- argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
- argsList.clear();
-
- // Process several events with the same timestamp from the kernel.
- // Ensure that we do not generate events too far into the future.
- constexpr static int32_t numEvents =
- MAX_BLUETOOTH_SMOOTHING_DELTA / MIN_BLUETOOTH_TIMESTAMP_DELTA;
- for (int i = 0; i < numEvents; i++) {
- expectedEventTime += MIN_BLUETOOTH_TIMESTAMP_DELTA;
-
- argsList += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
- argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
- argsList.clear();
- }
-
- // By processing more events with the same timestamp, we should not generate events with a
- // timestamp that is more than the specified max time delta from the timestamp at its injection.
- const nsecs_t cappedEventTime = ARBITRARY_TIME + MAX_BLUETOOTH_SMOOTHING_DELTA;
- for (int i = 0; i < 3; i++) {
- argsList += process(ARBITRARY_TIME, EV_REL, REL_X, 1);
- argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(cappedEventTime)))));
- argsList.clear();
- }
-}
-
-TEST_F(BluetoothCursorInputMapperUnitTestWithChoreographer, TimestampSmootheningNotUsed) {
- mPropertyMap.addProperty("cursor.mode", "pointer");
- createMapper();
- std::list<NotifyArgs> argsList;
-
- nsecs_t kernelEventTime = ARBITRARY_TIME;
- nsecs_t expectedEventTime = ARBITRARY_TIME;
- argsList += process(kernelEventTime, EV_REL, REL_X, 1);
- argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
- argsList.clear();
-
- // If the next event has a timestamp that is sufficiently spaced out so that Bluetooth timestamp
- // smoothening is not needed, its timestamp is not affected.
- kernelEventTime += MAX_BLUETOOTH_SMOOTHING_DELTA + ms2ns(1);
- expectedEventTime = kernelEventTime;
-
- argsList += process(kernelEventTime, EV_REL, REL_X, 1);
- argsList += process(kernelEventTime, EV_SYN, SYN_REPORT, 0);
- EXPECT_THAT(argsList,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithEventTime(expectedEventTime)))));
- argsList.clear();
-}
-
} // namespace android
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index 6a009b2..f50f517 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -51,13 +51,11 @@
using testing::ElementsAre;
using testing::VariantWith;
-class GestureConverterTestBase : public testing::Test {
+class GestureConverterTest : public testing::Test {
protected:
static constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000;
static constexpr int32_t EVENTHUB_ID = 1;
static constexpr stime_t ARBITRARY_GESTURE_TIME = 1.2;
- static constexpr float POINTER_X = 500;
- static constexpr float POINTER_Y = 200;
void SetUp() {
mFakeEventHub = std::make_unique<FakeEventHub>();
@@ -68,12 +66,6 @@
mDevice = newDevice();
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, -500, 500, 0, 0, 20);
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 500, 0, 0, 20);
-
- mFakePointerController = std::make_shared<FakePointerController>(
- /*enabled=*/!input_flags::enable_pointer_choreographer());
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(POINTER_X, POINTER_Y);
- mFakePolicy->setPointerController(mFakePointerController);
}
std::shared_ptr<InputDevice> newDevice() {
@@ -96,15 +88,6 @@
std::unique_ptr<TestInputListener> mFakeListener;
std::unique_ptr<InstrumentedInputReader> mReader;
std::shared_ptr<InputDevice> mDevice;
- std::shared_ptr<FakePointerController> mFakePointerController;
-};
-
-class GestureConverterTest : public GestureConverterTestBase {
-protected:
- void SetUp() override {
- input_flags::enable_pointer_choreographer(false);
- GestureConverterTestBase::SetUp();
- }
};
TEST_F(GestureConverterTest, Move) {
@@ -118,31 +101,24 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
WithRelativeMotion(0, 0))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithCoords(POINTER_X - 5, POINTER_Y + 10),
WithRelativeMotion(-5, 10), WithButtonState(0),
WithPressure(0.0f)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
+ WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10));
-
- // The same gesture again should only repeat the HOVER_MOVE and cursor position change, not the
- // HOVER_ENTER.
+ // The same gesture again should only repeat the HOVER_MOVE, not the HOVER_ENTER.
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithCoords(POINTER_X - 10, POINTER_Y + 20),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0),
WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER),
WithButtonState(0), WithPressure(0.0f),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 10, POINTER_Y + 20));
}
TEST_F(GestureConverterTest, Move_Rotated) {
@@ -157,18 +133,15 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
WithRelativeMotion(0, 0))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithCoords(POINTER_X + 10, POINTER_Y + 5),
WithRelativeMotion(10, 5), WithButtonState(0),
WithPressure(0.0f)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
+ WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X + 10, POINTER_Y + 5));
}
TEST_F(GestureConverterTest, ButtonsChange) {
@@ -197,7 +170,7 @@
WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
AMOTION_EVENT_BUTTON_SECONDARY)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
@@ -210,8 +183,8 @@
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY),
- WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER),
+ WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(0, 0),
+ WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
// Finally release the right button
@@ -228,8 +201,7 @@
VariantWith<NotifyMotionArgs>(
WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0),
- WithCoords(POINTER_X, POINTER_Y),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0), WithCoords(0, 0),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
}
@@ -250,8 +222,8 @@
ASSERT_THAT(args.front(),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), WithButtonState(0),
- WithCoords(POINTER_X - 5, POINTER_Y + 10),
- WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))));
+ WithCoords(0, 0), WithToolType(ToolType::FINGER),
+ WithDisplayId(ADISPLAY_ID_DEFAULT))));
}
TEST_F(GestureConverterTest, DragWithButton) {
@@ -274,7 +246,7 @@
WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
@@ -283,14 +255,11 @@
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10),
- WithToolType(ToolType::FINGER),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, 0),
+ WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER),
WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10));
-
// Release the button
Gesture upGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
/* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_LEFT,
@@ -305,8 +274,7 @@
VariantWith<NotifyMotionArgs>(
WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0),
- WithCoords(POINTER_X - 5, POINTER_Y + 10),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0), WithCoords(0, 0),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
}
@@ -323,12 +291,12 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithGestureScrollDistance(0, 0, EPSILON),
WithDownTime(downTime))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(POINTER_X, POINTER_Y - 10),
+ WithCoords(0, -10),
WithGestureScrollDistance(0, 10, EPSILON)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
@@ -341,8 +309,7 @@
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(POINTER_X, POINTER_Y - 15),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, -15),
WithGestureScrollDistance(0, 5, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
WithToolType(ToolType::FINGER),
@@ -355,14 +322,14 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(POINTER_X, POINTER_Y - 15),
+ WithCoords(0, -15),
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(
MotionClassification::TWO_FINGER_SWIPE),
WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -382,12 +349,12 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithGestureScrollDistance(0, 0, EPSILON),
WithDownTime(downTime))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(POINTER_X - 10, POINTER_Y),
+ WithCoords(-10, 0),
WithGestureScrollDistance(0, 10, EPSILON)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
@@ -399,25 +366,25 @@
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(POINTER_X - 15, POINTER_Y),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(-15, 0),
WithGestureScrollDistance(0, 5, EPSILON),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
+
Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
GESTURES_FLING_START);
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(POINTER_X - 15, POINTER_Y),
+ WithCoords(-15, 0),
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(
MotionClassification::TWO_FINGER_SWIPE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -619,7 +586,7 @@
WithPointerCount(1u))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -706,7 +673,7 @@
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
WithGestureOffset(0, 0, EPSILON), WithPointerCount(1u))),
VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)))));
ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithDisplayId(ADISPLAY_ID_DEFAULT))));
}
@@ -828,7 +795,7 @@
WithPointerCount(1u))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -847,14 +814,12 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(POINTER_X - 100, POINTER_Y),
- WithPointerCount(1u))),
+ WithCoords(-100, 0), WithPointerCount(1u))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(
AMOTION_EVENT_ACTION_POINTER_DOWN |
1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCoords(1, POINTER_X + 100, POINTER_Y),
- WithPointerCount(2u)))));
+ WithPointerCoords(1, 100, 0), WithPointerCount(2u)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionClassification(MotionClassification::PINCH),
@@ -870,73 +835,7 @@
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
WithMotionClassification(MotionClassification::PINCH),
WithGesturePinchScaleFactor(0.8f, EPSILON),
- WithPointerCoords(0, POINTER_X - 80, POINTER_Y),
- WithPointerCoords(1, POINTER_X + 80, POINTER_Y), WithPointerCount(2u),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
- GESTURES_ZOOM_END);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTest, Pinch_Outwards) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
- GESTURES_ZOOM_START);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(POINTER_X - 100, POINTER_Y),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCoords(1, POINTER_X + 100, POINTER_Y),
- WithPointerCount(2u)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dz= */ 1.2, GESTURES_ZOOM_UPDATE);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.2f, EPSILON),
- WithPointerCoords(0, POINTER_X - 120, POINTER_Y),
- WithPointerCoords(1, POINTER_X + 120, POINTER_Y),
+ WithPointerCoords(0, -80, 0), WithPointerCoords(1, 80, 0),
WithPointerCount(2u), WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
@@ -958,7 +857,69 @@
WithPointerCount(1u))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
+ WithMotionClassification(MotionClassification::NONE)))));
+ ASSERT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
+ WithDisplayId(ADISPLAY_ID_DEFAULT)))));
+}
+
+TEST_F(GestureConverterTest, Pinch_Outwards) {
+ InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+ GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
+ converter.setDisplayId(ADISPLAY_ID_DEFAULT);
+
+ Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
+ GESTURES_ZOOM_START);
+ std::list<NotifyArgs> args =
+ converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithCoords(-100, 0), WithPointerCount(1u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithPointerCoords(1, 100, 0), WithPointerCount(2u)))));
+ ASSERT_THAT(args,
+ Each(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionClassification(MotionClassification::PINCH),
+ WithGesturePinchScaleFactor(1.0f, EPSILON),
+ WithToolType(ToolType::FINGER),
+ WithDisplayId(ADISPLAY_ID_DEFAULT)))));
+
+ Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
+ /* dz= */ 1.1, GESTURES_ZOOM_UPDATE);
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
+ WithMotionClassification(MotionClassification::PINCH),
+ WithGesturePinchScaleFactor(1.1f, EPSILON),
+ WithPointerCoords(0, -110, 0), WithPointerCoords(1, 110, 0),
+ WithPointerCount(2u), WithToolType(ToolType::FINGER),
+ WithDisplayId(ADISPLAY_ID_DEFAULT)))));
+
+ Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
+ GESTURES_ZOOM_END);
+ args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture);
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ WithMotionClassification(MotionClassification::PINCH),
+ WithGesturePinchScaleFactor(1.0f, EPSILON),
+ WithPointerCount(2u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
+ WithMotionClassification(MotionClassification::PINCH),
+ WithGesturePinchScaleFactor(1.0f, EPSILON),
+ WithPointerCount(1u))),
+ VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -1044,7 +1005,7 @@
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithButtonState(0)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
}
@@ -1061,14 +1022,14 @@
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(POINTER_X, POINTER_Y - 10),
+ WithCoords(0, -10),
WithGestureScrollDistance(0, 0, EPSILON),
WithMotionClassification(
MotionClassification::TWO_FINGER_SWIPE),
WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -1141,7 +1102,7 @@
WithPointerCount(1u))),
VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y),
+ WithCoords(0, 0),
WithMotionClassification(MotionClassification::NONE)))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
@@ -1159,13 +1120,9 @@
converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture);
ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f),
- WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f),
- WithDisplayId(ADISPLAY_ID_DEFAULT)));
-
- ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X, POINTER_Y));
- ASSERT_TRUE(mFakePointerController->isPointerShown());
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithCoords(0, 0),
+ WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER),
+ WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT)));
}
TEST_F(GestureConverterTest, FlingTapDownAfterScrollStopsFling) {
@@ -1195,7 +1152,7 @@
WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
ASSERT_THAT(args,
Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER),
+ AllOf(WithCoords(0, 0), WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT),
WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE)))));
}
@@ -1241,7 +1198,7 @@
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithButtonState(0), WithPressure(0.0f)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
WithRelativeMotion(0.f, 0.f),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
@@ -1278,7 +1235,7 @@
WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
WithPressure(1.0f)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
WithRelativeMotion(0.f, 0.f),
WithToolType(ToolType::FINGER),
WithDisplayId(ADISPLAY_ID_DEFAULT)))));
@@ -1287,6 +1244,7 @@
/* down= */ GESTURES_BUTTON_NONE,
/* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ false);
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonUpGesture);
+
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
@@ -1299,10 +1257,10 @@
AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
WithPressure(0.0f)))));
ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithButtonState(0), WithCoords(POINTER_X, POINTER_Y),
- WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
+ Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0), WithCoords(0, 0),
+ WithRelativeMotion(0.f, 0.f),
+ WithToolType(ToolType::FINGER),
+ WithDisplayId(ADISPLAY_ID_DEFAULT)))));
}
TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled,
@@ -1438,1428 +1396,6 @@
/* down= */ GESTURES_BUTTON_LEFT,
/* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false);
args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonDownGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
- WithButtonState(0), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
- WithRelativeMotion(0.f, 0.f),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture buttonUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_NONE,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonUpGesture);
-
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(0), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithButtonState(0), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithButtonState(0), WithPressure(0.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(POINTER_X, POINTER_Y),
- WithRelativeMotion(0.f, 0.f),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Future taps should be re-enabled
- ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
-}
-
-TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
- // initially disable tap-to-click
- mReader->getContext()->setPreventingTouchpadTaps(true);
-
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- // We don't need to check args here, since it's covered by the Move test.
-
- // Future taps should be re-enabled
- ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
-}
-
-TEST_F_WITH_FLAGS(GestureConverterTest, KeypressCancelsHoverMove,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) {
- const nsecs_t gestureStartTime = 1000;
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- // Start a move gesture at gestureStartTime
- Gesture moveGesture(kGestureMove, gestureStartTime, gestureStartTime, -5, 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(gestureStartTime, READ_TIME, gestureStartTime, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))));
-
- // Key presses with IME connection should cancel ongoing move gesture
- nsecs_t currentTime = gestureStartTime + 100;
- mFakePolicy->setIsInputMethodConnectionActive(true);
- mReader->getContext()->setLastKeyDownTimestamp(currentTime);
- moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10);
- args = converter.handleGesture(currentTime, READ_TIME, gestureStartTime, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT))));
-
- // any updates in existing move gesture should be ignored
- moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10);
- args = converter.handleGesture(currentTime, READ_TIME, gestureStartTime, moveGesture);
- ASSERT_EQ(0u, args.size());
-
- // New gesture should not be affected
- currentTime += 100;
- moveGesture = Gesture(kGestureMove, currentTime, currentTime, -5, 10);
- args = converter.handleGesture(currentTime, READ_TIME, currentTime, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE))));
-}
-
-// TODO(b/311416205): De-duplicate the test cases after the refactoring is complete and the flagging
-// logic can be removed.
-class GestureConverterTestWithChoreographer : public GestureConverterTestBase {
-protected:
- void SetUp() override {
- input_flags::enable_pointer_choreographer(true);
- GestureConverterTestBase::SetUp();
- }
-};
-
-TEST_F(GestureConverterTestWithChoreographer, Move) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithRelativeMotion(0, 0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithRelativeMotion(-5, 10), WithButtonState(0),
- WithPressure(0.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // The same gesture again should only repeat the HOVER_MOVE, not the HOVER_ENTER.
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(0, 0),
- WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER),
- WithButtonState(0), WithPressure(0.0f),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Move_Rotated) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setOrientation(ui::ROTATION_90);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithRelativeMotion(0, 0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
- WithRelativeMotion(10, 5), WithButtonState(0),
- WithPressure(0.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ButtonsChange) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- // Press left and right buttons at once
- Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT,
- /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
- AMOTION_EVENT_BUTTON_SECONDARY))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
- AMOTION_EVENT_BUTTON_SECONDARY)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Then release the left button
- Gesture leftUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_LEFT,
- /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, leftUpGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Finally release the right button
- Gesture rightUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_RIGHT,
- /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, rightUpGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY))),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_UP)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0), WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ButtonDownAfterMoveExitsHover) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
-
- Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /*down=*/GESTURES_BUTTON_LEFT, /*up=*/GESTURES_BUTTON_NONE,
- /*is_tap=*/false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture);
- ASSERT_THAT(args.front(),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), WithButtonState(0),
- WithCoords(0, 0), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, DragWithButton) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- // Press the button
- Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_LEFT, /* up= */ GESTURES_BUTTON_NONE,
- /* is_tap= */ false);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Move
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, 0),
- WithRelativeMotion(-5, 10), WithToolType(ToolType::FINGER),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Release the button
- Gesture upGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_NONE, /* up= */ GESTURES_BUTTON_LEFT,
- /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, upGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY))),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_UP)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0), WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Scroll) {
- const nsecs_t downTime = 12345;
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10);
- std::list<NotifyArgs> args =
- converter.handleGesture(downTime, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(0, 0),
- WithGestureScrollDistance(0, 0, EPSILON),
- WithDownTime(downTime))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(0, -10),
- WithGestureScrollDistance(0, 10, EPSILON)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(0, -15),
- WithGestureScrollDistance(0, 5, EPSILON),
- WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(ToolType::FINGER),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
- GESTURES_FLING_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(0, -15),
- WithGestureScrollDistance(0, 0, EPSILON),
- WithMotionClassification(
- MotionClassification::TWO_FINGER_SWIPE),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Scroll_Rotated) {
- const nsecs_t downTime = 12345;
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setOrientation(ui::ROTATION_90);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10);
- std::list<NotifyArgs> args =
- converter.handleGesture(downTime, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(0, 0),
- WithGestureScrollDistance(0, 0, EPSILON),
- WithDownTime(downTime))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithCoords(-10, 0),
- WithGestureScrollDistance(0, 10, EPSILON)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(-15, 0),
- WithGestureScrollDistance(0, 5, EPSILON),
- WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
- GESTURES_FLING_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(-15, 0),
- WithGestureScrollDistance(0, 0, EPSILON),
- WithMotionClassification(
- MotionClassification::TWO_FINGER_SWIPE))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Scroll_ClearsClassificationAfterGesture) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
- GESTURES_FLING_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::NONE),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Scroll_ClearsScrollDistanceAfterGesture) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
- GESTURES_FLING_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
-
- // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we
- // need to use another gesture type, like pinch.
- Gesture pinchGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, pinchGesture);
- ASSERT_FALSE(args.empty());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), WithGestureScrollDistance(0, 0, EPSILON));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_ClearsClassificationAfterGesture) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0,
- /*dy=*/0);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/-5,
- /*dy=*/10);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionClassification(MotionClassification::NONE))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_ClearsGestureAxesAfterGesture) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/5,
- /*dy=*/5);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
-
- // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we
- // need to use another gesture type, like pinch.
- Gesture pinchGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, pinchGesture);
- ASSERT_FALSE(args.empty());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(0)));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Vertical) {
- // The gestures library will "lock" a swipe into the dimension it starts in. For example, if you
- // start swiping up and then start moving left or right, it'll return gesture events with only Y
- // deltas until you lift your fingers and start swiping again. That's why each of these tests
- // only checks movement in one dimension.
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0,
- /* dy= */ 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_EQ(4u, args.size());
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
- WithGestureSwipeFingerCount(3), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Three fake fingers should be created. We don't actually care where they are, so long as they
- // move appropriately.
- NotifyMotionArgs arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON),
- WithPointerCount(1u)));
- PointerCoords finger0Start = arg.pointerCoords[0];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u)));
- PointerCoords finger1Start = arg.pointerCoords[1];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u)));
- PointerCoords finger2Start = arg.pointerCoords[2];
- args.pop_front();
-
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithGestureOffset(0, -0.01, EPSILON), WithPointerCount(3u)));
- EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX());
- EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX());
- EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX());
- EXPECT_EQ(arg.pointerCoords[0].getY(), finger0Start.getY() - 10);
- EXPECT_EQ(arg.pointerCoords[1].getY(), finger1Start.getY() - 10);
- EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY() - 10);
-
- Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dx= */ 0, /* dy= */ 5);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
- ASSERT_EQ(1u, args.size());
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithGestureOffset(0, -0.005, EPSILON), WithGestureSwipeFingerCount(3),
- WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(3u), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)));
- EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX());
- EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX());
- EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX());
- EXPECT_EQ(arg.pointerCoords[0].getY(), finger0Start.getY() - 15);
- EXPECT_EQ(arg.pointerCoords[1].getY(), finger1Start.getY() - 15);
- EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY() - 15);
-
- Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(3),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(3u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(3),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(3),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ThreeFingerSwipe_Rotated) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setOrientation(ui::ROTATION_90);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0,
- /* dy= */ 10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_EQ(4u, args.size());
- ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithDisplayId(ADISPLAY_ID_DEFAULT))));
-
- // Three fake fingers should be created. We don't actually care where they are, so long as they
- // move appropriately.
- NotifyMotionArgs arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON),
- WithPointerCount(1u)));
- PointerCoords finger0Start = arg.pointerCoords[0];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u)));
- PointerCoords finger1Start = arg.pointerCoords[1];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u)));
- PointerCoords finger2Start = arg.pointerCoords[2];
- args.pop_front();
-
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithGestureOffset(0, -0.01, EPSILON), WithPointerCount(3u)));
- EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() - 10);
- EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() - 10);
- EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() - 10);
- EXPECT_EQ(arg.pointerCoords[0].getY(), finger0Start.getY());
- EXPECT_EQ(arg.pointerCoords[1].getY(), finger1Start.getY());
- EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY());
-
- Gesture continueGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dx= */ 0, /* dy= */ 5);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
- ASSERT_EQ(1u, args.size());
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithGestureOffset(0, -0.005, EPSILON), WithPointerCount(3u),
- WithDisplayId(ADISPLAY_ID_DEFAULT)));
- EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() - 15);
- EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() - 15);
- EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() - 15);
- EXPECT_EQ(arg.pointerCoords[0].getY(), finger0Start.getY());
- EXPECT_EQ(arg.pointerCoords[1].getY(), finger1Start.getY());
- EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY());
-
- Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)))));
- ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithDisplayId(ADISPLAY_ID_DEFAULT))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, FourFingerSwipe_Horizontal) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dx= */ 10, /* dy= */ 0);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_EQ(5u, args.size());
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
- WithGestureSwipeFingerCount(4), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- // Four fake fingers should be created. We don't actually care where they are, so long as they
- // move appropriately.
- NotifyMotionArgs arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON),
- WithPointerCount(1u)));
- PointerCoords finger0Start = arg.pointerCoords[0];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u)));
- PointerCoords finger1Start = arg.pointerCoords[1];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u)));
- PointerCoords finger2Start = arg.pointerCoords[2];
- args.pop_front();
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
- 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON), WithPointerCount(4u)));
- PointerCoords finger3Start = arg.pointerCoords[3];
- args.pop_front();
-
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithGestureOffset(0.01, 0, EPSILON), WithPointerCount(4u)));
- EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() + 10);
- EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() + 10);
- EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() + 10);
- EXPECT_EQ(arg.pointerCoords[3].getX(), finger3Start.getX() + 10);
- EXPECT_EQ(arg.pointerCoords[0].getY(), finger0Start.getY());
- EXPECT_EQ(arg.pointerCoords[1].getY(), finger1Start.getY());
- EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY());
- EXPECT_EQ(arg.pointerCoords[3].getY(), finger3Start.getY());
-
- Gesture continueGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dx= */ 5, /* dy= */ 0);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, continueGesture);
- ASSERT_EQ(1u, args.size());
- arg = std::get<NotifyMotionArgs>(args.front());
- ASSERT_THAT(arg,
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithGestureOffset(0.005, 0, EPSILON), WithGestureSwipeFingerCount(4),
- WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(4u), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)));
- EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() + 15);
- EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() + 15);
- EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() + 15);
- EXPECT_EQ(arg.pointerCoords[3].getX(), finger3Start.getX() + 15);
- EXPECT_EQ(arg.pointerCoords[0].getY(), finger0Start.getY());
- EXPECT_EQ(arg.pointerCoords[1].getY(), finger1Start.getY());
- EXPECT_EQ(arg.pointerCoords[2].getY(), finger2Start.getY());
- EXPECT_EQ(arg.pointerCoords[3].getY(), finger3Start.getY());
-
- Gesture liftGesture(kGestureSwipeLift, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, liftGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(4),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(4u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(4),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(3u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(4),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithGestureOffset(0, 0, EPSILON),
- WithGestureSwipeFingerCount(4),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Pinch_Inwards) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
- GESTURES_ZOOM_START);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(-100, 0), WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCoords(1, 100, 0), WithPointerCount(2u)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dz= */ 0.8, GESTURES_ZOOM_UPDATE);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(0.8f, EPSILON),
- WithPointerCoords(0, -80, 0), WithPointerCoords(1, 80, 0),
- WithPointerCount(2u), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
- GESTURES_ZOOM_END);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Pinch_Outwards) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
- GESTURES_ZOOM_START);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithCoords(-100, 0), WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_DOWN |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithPointerCoords(1, 100, 0), WithPointerCount(2u)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* dz= */ 1.1, GESTURES_ZOOM_UPDATE);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.1f, EPSILON),
- WithPointerCoords(0, -110, 0), WithPointerCoords(1, 110, 0),
- WithPointerCount(2u), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1,
- GESTURES_ZOOM_END);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Pinch_ClearsClassificationAfterGesture) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_START);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /*dz=*/1.2, GESTURES_ZOOM_UPDATE);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture);
-
- Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_END);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture);
-
- Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, moveGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionClassification(MotionClassification::NONE))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Pinch_ClearsScaleFactorAfterGesture) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_START);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /*dz=*/1.2, GESTURES_ZOOM_UPDATE);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, updateGesture);
-
- Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_END);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, endGesture);
-
- // Move gestures don't use the fake finger array, so to test that gesture axes are cleared we
- // need to use another gesture type, like scroll.
- Gesture scrollGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/1,
- /*dy=*/0);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, scrollGesture);
- ASSERT_FALSE(args.empty());
- EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), WithGesturePinchScaleFactor(0, EPSILON));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ResetWithButtonPressed) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /*down=*/GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT,
- /*up=*/GESTURES_BUTTON_NONE, /*is_tap=*/false);
- (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, downGesture);
-
- std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
- WithButtonState(0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithButtonState(0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithButtonState(0)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ResetDuringScroll) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10);
- (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithCoords(0, -10),
- WithGestureScrollDistance(0, 0, EPSILON),
- WithMotionClassification(
- MotionClassification::TWO_FINGER_SWIPE),
- WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ResetDuringThreeFingerSwipe) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0,
- /*dy=*/10);
- (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(3u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithGestureOffset(0, 0, EPSILON),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithGestureOffset(0, 0, EPSILON),
- WithMotionClassification(
- MotionClassification::MULTI_FINGER_SWIPE),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, ResetDuringPinch) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1,
- GESTURES_ZOOM_START);
- (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, startGesture);
-
- std::list<NotifyArgs> args = converter.reset(ARBITRARY_TIME);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(
- AMOTION_EVENT_ACTION_POINTER_UP |
- 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(2u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithMotionClassification(MotionClassification::PINCH),
- WithGesturePinchScaleFactor(1.0f, EPSILON),
- WithPointerCount(1u))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithCoords(0, 0),
- WithMotionClassification(MotionClassification::NONE)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, FlingTapDown) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture);
-
- ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithCoords(0, 0),
- WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER),
- WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT)));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, FlingTapDownAfterScrollStopsFling) {
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- input_flags::enable_touchpad_fling_stop(true);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture scrollGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, scrollGesture);
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1,
- GESTURES_FLING_START);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
-
- Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapDownGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_DOWN)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)),
- VariantWith<NotifyMotionArgs>(
- WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(
- AllOf(WithCoords(0, 0), WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT),
- WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Tap) {
- // Tap should produce button press/release events
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
- // We don't need to check args here, since it's covered by the FlingTapDown test.
-
- Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, tapGesture);
-
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
- WithButtonState(0), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(0), WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithButtonState(0), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithButtonState(0), WithPressure(0.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithRelativeMotion(0.f, 0.f),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F(GestureConverterTestWithChoreographer, Click) {
- // Click should produce button press/release events
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
- // We don't need to check args here, since it's covered by the FlingTapDown test.
-
- Gesture buttonDownGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonDownGesture);
-
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
- WithButtonState(0), WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(0, 0),
- WithRelativeMotion(0.f, 0.f),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-
- Gesture buttonUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_NONE,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonUpGesture);
-
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithPressure(1.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithPressure(0.0f))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithPressure(0.0f)))));
- ASSERT_THAT(args,
- Each(VariantWith<NotifyMotionArgs>(AllOf(WithButtonState(0), WithCoords(0, 0),
- WithRelativeMotion(0.f, 0.f),
- WithToolType(ToolType::FINGER),
- WithDisplayId(ADISPLAY_ID_DEFAULT)))));
-}
-
-TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, TapWithTapToClickDisabled,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION),
- REQUIRES_FLAGS_DISABLED(TOUCHPAD_PALM_REJECTION_V2)) {
- nsecs_t currentTime = ARBITRARY_GESTURE_TIME;
-
- // Tap should be ignored when disabled
- mReader->getContext()->setPreventingTouchpadTaps(true);
-
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture flingGesture(kGestureFling, currentTime, currentTime, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- std::list<NotifyArgs> args =
- converter.handleGesture(currentTime, currentTime, currentTime, flingGesture);
- // We don't need to check args here, since it's covered by the FlingTapDown test.
-
- Gesture tapGesture(kGestureButtonsChange, currentTime, currentTime,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true);
- args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture);
-
- // no events should be generated
- ASSERT_EQ(0u, args.size());
-
- // Future taps should be re-enabled
- ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
-}
-
-TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, TapWithTapToClickDisabledWithDelay,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) {
- nsecs_t currentTime = ARBITRARY_GESTURE_TIME;
-
- // Tap should be ignored when disabled
- mReader->getContext()->setPreventingTouchpadTaps(true);
-
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture flingGesture(kGestureFling, currentTime, currentTime, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- std::list<NotifyArgs> args =
- converter.handleGesture(currentTime, currentTime, currentTime, flingGesture);
- // We don't need to check args here, since it's covered by the FlingTapDown test.
-
- Gesture tapGesture(kGestureButtonsChange, currentTime, currentTime,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true);
- args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture);
-
- // no events should be generated
- ASSERT_EQ(0u, args.size());
-
- // Future taps should be re-enabled
- ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
-
- // taps before the threshold should still be ignored
- currentTime += TAP_ENABLE_DELAY_NANOS.count();
- flingGesture = Gesture(kGestureFling, currentTime, currentTime, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- args = converter.handleGesture(currentTime, currentTime, currentTime, flingGesture);
-
- ASSERT_EQ(1u, args.size());
- ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0)));
-
- tapGesture = Gesture(kGestureButtonsChange, currentTime, currentTime,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true);
- args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture);
-
- // no events should be generated
- ASSERT_EQ(0u, args.size());
-
- // taps after the threshold should be recognised
- currentTime += 1;
- flingGesture = Gesture(kGestureFling, currentTime, currentTime, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- args = converter.handleGesture(currentTime, currentTime, currentTime, flingGesture);
-
- ASSERT_EQ(1u, args.size());
- ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithRelativeMotion(0, 0)));
-
- tapGesture = Gesture(kGestureButtonsChange, currentTime, currentTime,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_LEFT, /* is_tap= */ true);
- args = converter.handleGesture(currentTime, currentTime, currentTime, tapGesture);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT),
- WithButtonState(0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
- WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
- WithButtonState(0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP),
- WithButtonState(0))),
- VariantWith<NotifyMotionArgs>(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithButtonState(0)))));
- ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithRelativeMotion(0.f, 0.f))));
-}
-
-TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, ClickWithTapToClickDisabled,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
- // Click should still produce button press/release events
- mReader->getContext()->setPreventingTouchpadTaps(true);
-
- InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
- GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
- converter.setDisplayId(ADISPLAY_ID_DEFAULT);
-
- Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0,
- /* vy= */ 0, GESTURES_FLING_TAP_DOWN);
- std::list<NotifyArgs> args =
- converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, flingGesture);
- // We don't need to check args here, since it's covered by the FlingTapDown test.
-
- Gesture buttonDownGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
- /* down= */ GESTURES_BUTTON_LEFT,
- /* up= */ GESTURES_BUTTON_NONE, /* is_tap= */ false);
- args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, ARBITRARY_TIME, buttonDownGesture);
ASSERT_THAT(args,
ElementsAre(VariantWith<NotifyMotionArgs>(
@@ -2909,7 +1445,7 @@
ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
}
-TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, MoveEnablesTapToClick,
+TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick,
REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
// initially disable tap-to-click
mReader->getContext()->setPreventingTouchpadTaps(true);
@@ -2927,7 +1463,7 @@
ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
}
-TEST_F_WITH_FLAGS(GestureConverterTestWithChoreographer, KeypressCancelsHoverMove,
+TEST_F_WITH_FLAGS(GestureConverterTest, KeypressCancelsHoverMove,
REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION_V2)) {
const nsecs_t gestureStartTime = 1000;
InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index 2aecab9..ae6c849 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -29,14 +29,8 @@
using testing::Return;
void InputMapperUnitTest::SetUpWithBus(int bus) {
- mFakePointerController = std::make_shared<FakePointerController>();
- mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1);
- mFakePointerController->setPosition(INITIAL_CURSOR_X, INITIAL_CURSOR_Y);
mFakePolicy = sp<FakeInputReaderPolicy>::make();
- EXPECT_CALL(mMockInputReaderContext, getPointerController(DEVICE_ID))
- .WillRepeatedly(Return(mFakePointerController));
-
EXPECT_CALL(mMockInputReaderContext, getPolicy()).WillRepeatedly(Return(mFakePolicy.get()));
EXPECT_CALL(mMockInputReaderContext, getEventHub()).WillRepeatedly(Return(&mMockEventHub));
diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h
index e176a65..509a593 100644
--- a/services/inputflinger/tests/InputMapperTest.h
+++ b/services/inputflinger/tests/InputMapperTest.h
@@ -40,8 +40,6 @@
protected:
static constexpr int32_t EVENTHUB_ID = 1;
static constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000;
- static constexpr float INITIAL_CURSOR_X = 400;
- static constexpr float INITIAL_CURSOR_Y = 240;
virtual void SetUp() override { SetUpWithBus(0); }
virtual void SetUpWithBus(int bus);
@@ -66,7 +64,6 @@
InputDeviceIdentifier mIdentifier;
MockEventHubInterface mMockEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
- std::shared_ptr<FakePointerController> mFakePointerController;
MockInputReaderContext mMockInputReaderContext;
std::unique_ptr<InputDevice> mDevice;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 076e3db..e1b46fa 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -5344,10 +5344,6 @@
}
TEST_F(SingleTouchInputMapperTest, Process_DoesntCheckPhysicalFrameForTouchpads) {
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(fakePointerController);
-
addConfigurationProperty("touch.deviceType", "pointer");
prepareAxes(POSITION);
prepareDisplay(ui::ROTATION_0);
@@ -6192,52 +6188,6 @@
ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mapper.getSources());
}
-TEST_F(SingleTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectStylusPointer) {
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(ui::ROTATION_0);
- prepareButtons();
- prepareAxes(POSITION);
- mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0);
- mFakePolicy->setPointerController(fakePointerController);
- mFakePolicy->setStylusPointerIconEnabled(true);
- SingleTouchInputMapper& mapper = constructAndAddMapper<SingleTouchInputMapper>();
-
- processKey(mapper, BTN_TOOL_PEN, 1);
- processMove(mapper, 100, 200);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithToolType(ToolType::STYLUS),
- WithPointerCoords(0, toDisplayX(100), toDisplayY(200)))));
- ASSERT_TRUE(fakePointerController->isPointerShown());
- ASSERT_NO_FATAL_FAILURE(
- fakePointerController->assertPosition(toDisplayX(100), toDisplayY(200)));
-}
-
-TEST_F(SingleTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirectStylusPointer) {
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(ui::ROTATION_0);
- prepareButtons();
- prepareAxes(POSITION);
- mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0);
- mFakePolicy->setPointerController(fakePointerController);
- mFakePolicy->setStylusPointerIconEnabled(false);
- SingleTouchInputMapper& mapper = constructAndAddMapper<SingleTouchInputMapper>();
-
- processKey(mapper, BTN_TOOL_PEN, 1);
- processMove(mapper, 100, 200);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithToolType(ToolType::STYLUS),
- WithPointerCoords(0, toDisplayX(100), toDisplayY(200)))));
- ASSERT_FALSE(fakePointerController->isPointerShown());
-}
-
TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsChangedToTouchNavigation_updatesDeviceType) {
// Initialize the device without setting device source to touch navigation.
addConfigurationProperty("touch.deviceType", "touchScreen");
@@ -8717,21 +8667,12 @@
}
TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
- // Setup for second display.
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
- fakePointerController->setPosition(100, 200);
- mFakePolicy->setPointerController(fakePointerController);
-
- mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
prepareSecondaryDisplay(ViewportType::EXTERNAL);
prepareDisplay(ui::ROTATION_0);
prepareAxes(POSITION);
MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
- // Check source is mouse that would obtain the PointerController.
ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
NotifyMotionArgs motionArgs;
@@ -8740,7 +8681,7 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action);
- ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
+ ASSERT_EQ(ADISPLAY_ID_NONE, motionArgs.displayId);
}
/**
@@ -8920,97 +8861,6 @@
WithMotionAction(AMOTION_EVENT_ACTION_MOVE)));
}
-TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
- // Setup the first touch screen device.
- prepareAxes(POSITION | ID | SLOT);
- addConfigurationProperty("touch.deviceType", "touchScreen");
- MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
-
- // Create the second touch screen device, and enable multi fingers.
- const std::string USB2 = "USB2";
- const std::string DEVICE_NAME2 = "TOUCHSCREEN2";
- constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
- constexpr int32_t SECOND_EVENTHUB_ID = EVENTHUB_ID + 1;
- std::shared_ptr<InputDevice> device2 =
- newDevice(SECOND_DEVICE_ID, DEVICE_NAME2, USB2, SECOND_EVENTHUB_ID,
- ftl::Flags<InputDeviceClass>(0));
-
- mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
- /*flat=*/0, /*fuzz=*/0);
- mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX,
- /*flat=*/0, /*fuzz=*/0);
- mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX,
- /*flat=*/0, /*fuzz=*/0);
- mFakeEventHub->addAbsoluteAxis(SECOND_EVENTHUB_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX,
- /*flat=*/0, /*fuzz=*/0);
- mFakeEventHub->setAbsoluteAxisValue(SECOND_EVENTHUB_ID, ABS_MT_SLOT, /*value=*/0);
- mFakeEventHub->addConfigurationProperty(SECOND_EVENTHUB_ID, String8("touch.deviceType"),
- String8("touchScreen"));
-
- // Setup the second touch screen device.
- device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID);
- MultiTouchInputMapper& mapper2 = device2->constructAndAddMapper<
- MultiTouchInputMapper>(SECOND_EVENTHUB_ID, mFakePolicy->getReaderConfiguration());
- std::list<NotifyArgs> unused =
- device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- /*changes=*/{});
- unused += device2->reset(ARBITRARY_TIME);
-
- // Setup PointerController.
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(fakePointerController);
-
- // Setup policy for associated displays and show touches.
- const uint8_t hdmi1 = 0;
- const uint8_t hdmi2 = 1;
- mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
- mFakePolicy->addInputPortAssociation(USB2, hdmi2);
- mFakePolicy->setShowTouches(true);
-
- // Create displays.
- prepareDisplay(ui::ROTATION_0, hdmi1);
- prepareSecondaryDisplay(ViewportType::EXTERNAL, hdmi2);
-
- // Default device will reconfigure above, need additional reconfiguration for another device.
- unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::Change::DISPLAY_INFO |
- InputReaderConfiguration::Change::SHOW_TOUCHES);
-
- // Two fingers down at default display.
- int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
- processPosition(mapper, x1, y1);
- processId(mapper, 1);
- processSlot(mapper, 1);
- processPosition(mapper, x2, y2);
- processId(mapper, 2);
- processSync(mapper);
-
- std::map<int32_t, std::vector<int32_t>>::const_iterator iter =
- fakePointerController->getSpots().find(DISPLAY_ID);
- ASSERT_TRUE(iter != fakePointerController->getSpots().end());
- ASSERT_EQ(size_t(2), iter->second.size());
-
- // Two fingers down at second display.
- processPosition(mapper2, x1, y1);
- processId(mapper2, 1);
- processSlot(mapper2, 1);
- processPosition(mapper2, x2, y2);
- processId(mapper2, 2);
- processSync(mapper2);
-
- iter = fakePointerController->getSpots().find(SECONDARY_DISPLAY_ID);
- ASSERT_TRUE(iter != fakePointerController->getSpots().end());
- ASSERT_EQ(size_t(2), iter->second.size());
-
- // Disable the show touches configuration and ensure the spots are cleared.
- mFakePolicy->setShowTouches(false);
- unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
- InputReaderConfiguration::Change::SHOW_TOUCHES);
-
- ASSERT_TRUE(fakePointerController->getSpots().empty());
-}
-
TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) {
prepareAxes(POSITION);
addConfigurationProperty("touch.deviceType", "touchScreen");
@@ -9703,58 +9553,6 @@
WithToolType(ToolType::STYLUS))));
}
-TEST_F(MultiTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectStylusPointer) {
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(ui::ROTATION_0);
- prepareAxes(POSITION | ID | SLOT | TOOL_TYPE | PRESSURE);
- // Add BTN_TOOL_PEN to statically show stylus support, since using ABS_MT_TOOL_TYPE can only
- // indicate stylus presence dynamically.
- mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0);
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(fakePointerController);
- mFakePolicy->setStylusPointerIconEnabled(true);
- MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
-
- processId(mapper, FIRST_TRACKING_ID);
- processPressure(mapper, RAW_PRESSURE_MIN);
- processPosition(mapper, 100, 200);
- processToolType(mapper, MT_TOOL_PEN);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithToolType(ToolType::STYLUS),
- WithPointerCoords(0, toDisplayX(100), toDisplayY(200)))));
- ASSERT_TRUE(fakePointerController->isPointerShown());
- ASSERT_NO_FATAL_FAILURE(
- fakePointerController->assertPosition(toDisplayX(100), toDisplayY(200)));
-}
-
-TEST_F(MultiTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirectStylusPointer) {
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(ui::ROTATION_0);
- prepareAxes(POSITION | ID | SLOT | TOOL_TYPE | PRESSURE);
- // Add BTN_TOOL_PEN to statically show stylus support, since using ABS_MT_TOOL_TYPE can only
- // indicate stylus presence dynamically.
- mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0);
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- mFakePolicy->setPointerController(fakePointerController);
- mFakePolicy->setStylusPointerIconEnabled(false);
- MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
-
- processId(mapper, FIRST_TRACKING_ID);
- processPressure(mapper, RAW_PRESSURE_MIN);
- processPosition(mapper, 100, 200);
- processToolType(mapper, MT_TOOL_PEN);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
- AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER),
- WithToolType(ToolType::STYLUS),
- WithPointerCoords(0, toDisplayX(100), toDisplayY(200)))));
- ASSERT_FALSE(fakePointerController->isPointerShown());
-}
-
// --- MultiTouchInputMapperTest_ExternalDevice ---
class MultiTouchInputMapperTest_ExternalDevice : public MultiTouchInputMapperTest {
@@ -9790,18 +9588,15 @@
ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
}
-TEST_F(MultiTouchInputMapperTest, Process_TouchpadPointer) {
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
- fakePointerController->setPosition(0, 0);
-
+// TODO(b/281840344): Remove the test when the old touchpad stack is removed. It is currently
+// unclear what the behavior of the touchpad logic in TouchInputMapper should do after the
+// PointerChoreographer refactor.
+TEST_F(MultiTouchInputMapperTest, DISABLED_Process_TouchpadPointer) {
// prepare device
prepareDisplay(ui::ROTATION_0);
prepareAxes(POSITION | ID | SLOT);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0);
- mFakePolicy->setPointerController(fakePointerController);
MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
// run uncaptured pointer tests - pushes out generic events
// FINGER 0 DOWN
@@ -9855,13 +9650,9 @@
}
TEST_F(MultiTouchInputMapperTest, Touchpad_GetSources) {
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
-
prepareDisplay(ui::ROTATION_0);
prepareAxes(POSITION | ID | SLOT);
mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0);
- mFakePolicy->setPointerController(fakePointerController);
mFakePolicy->setPointerCapture(/*window=*/nullptr);
MultiTouchInputMapper& mapper = constructAndAddMapper<MultiTouchInputMapper>();
@@ -9925,10 +9716,6 @@
float mPointerXZoomScale;
void preparePointerMode(int xAxisResolution, int yAxisResolution) {
addConfigurationProperty("touch.deviceType", "pointer");
- std::shared_ptr<FakePointerController> fakePointerController =
- std::make_shared<FakePointerController>();
- fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
- fakePointerController->setPosition(0, 0);
prepareDisplay(ui::ROTATION_0);
prepareAxes(POSITION);
@@ -9937,7 +9724,6 @@
// needs to be disabled, and the pointer gesture needs to be enabled.
mFakePolicy->setPointerCapture(/*window=*/nullptr);
mFakePolicy->setPointerGestureEnabled(true);
- mFakePolicy->setPointerController(fakePointerController);
float rawDiagonal = hypotf(RAW_X_MAX - RAW_X_MIN, RAW_Y_MAX - RAW_Y_MIN);
float displayDiagonal = hypotf(DISPLAY_WIDTH, DISPLAY_HEIGHT);
@@ -10443,6 +10229,28 @@
ASSERT_EQ(controller.getLightColor(lights[0].id).value_or(-1), LIGHT_BRIGHTNESS);
}
+TEST_F(LightControllerTest, MonoKeyboardMuteLight) {
+ RawLightInfo infoMono = {.id = 1,
+ .name = "mono_keyboard_mute",
+ .maxBrightness = 255,
+ .flags = InputLightClass::BRIGHTNESS |
+ InputLightClass::KEYBOARD_MIC_MUTE,
+ .path = ""};
+ mFakeEventHub->addRawLightInfo(infoMono.id, std::move(infoMono));
+
+ PeripheralController& controller = addControllerAndConfigure<PeripheralController>();
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ /*changes=*/{});
+
+ InputDeviceInfo info;
+ controller.populateDeviceInfo(&info);
+ std::vector<InputDeviceLightInfo> lights = info.getLights();
+ ASSERT_EQ(1U, lights.size());
+ ASSERT_EQ(InputDeviceLightType::KEYBOARD_MIC_MUTE, lights[0].type);
+ ASSERT_EQ(0U, lights[0].preferredBrightnessLevels.size());
+}
+
TEST_F(LightControllerTest, MonoKeyboardBacklight) {
RawLightInfo infoMono = {.id = 1,
.name = "mono_keyboard_backlight",
diff --git a/services/inputflinger/tests/InputTracingTest.cpp b/services/inputflinger/tests/InputTracingTest.cpp
index ef0eeae..0404d6d 100644
--- a/services/inputflinger/tests/InputTracingTest.cpp
+++ b/services/inputflinger/tests/InputTracingTest.cpp
@@ -644,7 +644,8 @@
waitForTracerIdle();
}
-TEST_F(InputTracingTest, SimultaneousTracingSessions) {
+// TODO(b/336097719): Investigate flakiness and re-enable this test.
+TEST_F(InputTracingTest, DISABLED_SimultaneousTracingSessions) {
auto s1 = std::make_unique<InputTraceSession>(
[](auto& config) { config->set_mode(AndroidInputEventConfig::TRACE_MODE_TRACE_ALL); });
diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
index a92dce5..402654c 100644
--- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp
+++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp
@@ -19,9 +19,7 @@
#include <android-base/logging.h>
#include <gtest/gtest.h>
-#include <com_android_input_flags.h>
#include <thread>
-#include "FakePointerController.h"
#include "InputMapperTest.h"
#include "InterfaceMocks.h"
#include "TestEventMatchers.h"
@@ -44,12 +42,10 @@
constexpr int32_t DISPLAY_HEIGHT = 800;
constexpr std::optional<uint8_t> NO_PORT = std::nullopt; // no physical port is specified
-namespace input_flags = com::android::input::flags;
-
/**
* Unit tests for TouchpadInputMapper.
*/
-class TouchpadInputMapperTestBase : public InputMapperUnitTest {
+class TouchpadInputMapperTest : public InputMapperUnitTest {
protected:
void SetUp() override {
InputMapperUnitTest::SetUp();
@@ -117,18 +113,7 @@
return base::ResultError("Axis not supported", NAME_NOT_FOUND);
});
createDevice();
- mMapper = createInputMapper<TouchpadInputMapper>(*mDeviceContext, mReaderConfiguration,
- isPointerChoreographerEnabled());
- }
-
- virtual bool isPointerChoreographerEnabled() { return false; }
-};
-
-class TouchpadInputMapperTest : public TouchpadInputMapperTestBase {
-protected:
- void SetUp() override {
- input_flags::enable_pointer_choreographer(false);
- TouchpadInputMapperTestBase::SetUp();
+ mMapper = createInputMapper<TouchpadInputMapper>(*mDeviceContext, mReaderConfiguration);
}
};
@@ -139,66 +124,6 @@
* but only after the button is released.
*/
TEST_F(TouchpadInputMapperTest, HoverAndLeftButtonPress) {
- std::list<NotifyArgs> args;
-
- args += process(EV_ABS, ABS_MT_TRACKING_ID, 1);
- args += process(EV_KEY, BTN_TOUCH, 1);
- setScanCodeState(KeyState::DOWN, {BTN_TOOL_FINGER});
- args += process(EV_KEY, BTN_TOOL_FINGER, 1);
- args += process(EV_ABS, ABS_MT_POSITION_X, 50);
- args += process(EV_ABS, ABS_MT_POSITION_Y, 50);
- args += process(EV_ABS, ABS_MT_PRESSURE, 1);
- args += process(EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args, testing::IsEmpty());
-
- // Without this sleep, the test fails.
- // TODO(b/284133337): Figure out whether this can be removed
- std::this_thread::sleep_for(std::chrono::milliseconds(20));
-
- args += process(EV_KEY, BTN_LEFT, 1);
- setScanCodeState(KeyState::DOWN, {BTN_LEFT});
- args += process(EV_SYN, SYN_REPORT, 0);
-
- args += process(EV_KEY, BTN_LEFT, 0);
- setScanCodeState(KeyState::UP, {BTN_LEFT});
- args += process(EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args,
- ElementsAre(VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_ENTER)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_MOVE)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_EXIT)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_DOWN)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_PRESS)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(BUTTON_RELEASE)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(ACTION_UP)),
- VariantWith<NotifyMotionArgs>(WithMotionAction(HOVER_ENTER))));
-
- // Liftoff
- args.clear();
- args += process(EV_ABS, ABS_MT_PRESSURE, 0);
- args += process(EV_ABS, ABS_MT_TRACKING_ID, -1);
- args += process(EV_KEY, BTN_TOUCH, 0);
- setScanCodeState(KeyState::UP, {BTN_TOOL_FINGER});
- args += process(EV_KEY, BTN_TOOL_FINGER, 0);
- args += process(EV_SYN, SYN_REPORT, 0);
- ASSERT_THAT(args, testing::IsEmpty());
-}
-
-class TouchpadInputMapperTestWithChoreographer : public TouchpadInputMapperTestBase {
-protected:
- void SetUp() override { TouchpadInputMapperTestBase::SetUp(); }
-
- bool isPointerChoreographerEnabled() override { return true; }
-};
-
-// TODO(b/311416205): De-duplicate the test cases after the refactoring is complete and the flagging
-// logic can be removed.
-/**
- * Start moving the finger and then click the left touchpad button. Check whether HOVER_EXIT is
- * generated when hovering stops. Currently, it is not.
- * In the current implementation, HOVER_MOVE and ACTION_DOWN events are not sent out right away,
- * but only after the button is released.
- */
-TEST_F(TouchpadInputMapperTestWithChoreographer, HoverAndLeftButtonPress) {
mFakePolicy->setDefaultPointerDisplayId(DISPLAY_ID);
mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
/*isActive=*/true, "local:0", NO_PORT, ViewportType::INTERNAL);
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index dc69b81..8ca796e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -158,6 +158,7 @@
"BackgroundExecutor.cpp",
"Client.cpp",
"ClientCache.cpp",
+ "Display/DisplayModeController.cpp",
"Display/DisplaySnapshot.cpp",
"DisplayDevice.cpp",
"DisplayHardware/AidlComposerHal.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index a52cc87..7fa58df 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -11,6 +11,7 @@
cc_defaults {
name: "libcompositionengine_defaults",
defaults: [
+ "aconfig_lib_cc_static_link.defaults",
"android.hardware.graphics.composer3-ndk_shared",
"android.hardware.power-ndk_shared",
"librenderengine_deps",
diff --git a/services/surfaceflinger/Display/DisplayModeController.cpp b/services/surfaceflinger/Display/DisplayModeController.cpp
new file mode 100644
index 0000000..f093384
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplayModeController.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DisplayModeController"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "Display/DisplayModeController.h"
+#include "Display/DisplaySnapshot.h"
+
+#include <log/log.h>
+
+namespace android::display {
+
+void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
+ DisplayModeId activeModeId,
+ scheduler::RefreshRateSelector::Config config) {
+ const auto& snapshot = snapshotRef.get();
+ const auto displayId = snapshot.displayId();
+
+ mDisplays.emplace_or_replace(displayId, snapshotRef, snapshot.displayModes(), activeModeId,
+ config);
+}
+
+void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
+ const bool ok = mDisplays.erase(displayId);
+ ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
+}
+
+auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) -> RefreshRateSelectorPtr {
+ return mDisplays.get(displayId)
+ .transform([](const Display& display) { return display.selectorPtr; })
+ .value_or(nullptr);
+}
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplayModeController.h b/services/surfaceflinger/Display/DisplayModeController.h
new file mode 100644
index 0000000..b6a6bee
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplayModeController.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2024 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#include <android-base/thread_annotations.h>
+#include <ui/DisplayId.h>
+#include <ui/DisplayMap.h>
+
+#include "Display/DisplaySnapshotRef.h"
+#include "DisplayHardware/DisplayMode.h"
+#include "Scheduler/RefreshRateSelector.h"
+#include "ThreadContext.h"
+
+namespace android::display {
+
+// Selects the DisplayMode of each physical display, in accordance with DisplayManager policy and
+// certain heuristic signals.
+class DisplayModeController {
+public:
+ // The referenced DisplaySnapshot must outlive the registration.
+ void registerDisplay(DisplaySnapshotRef, DisplayModeId, scheduler::RefreshRateSelector::Config)
+ REQUIRES(kMainThreadContext);
+ void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext);
+
+ // TODO(b/241285876): Remove once ownership is no longer shared with DisplayDevice.
+ using RefreshRateSelectorPtr = std::shared_ptr<scheduler::RefreshRateSelector>;
+
+ // Returns `nullptr` if the display is no longer registered (or never was).
+ RefreshRateSelectorPtr selectorPtrFor(PhysicalDisplayId) REQUIRES(kMainThreadContext);
+
+ // Used by tests to inject an existing RefreshRateSelector.
+ // TODO(b/241285876): Remove this.
+ void registerDisplay(PhysicalDisplayId displayId, DisplaySnapshotRef snapshotRef,
+ RefreshRateSelectorPtr selectorPtr) {
+ mDisplays.emplace_or_replace(displayId, snapshotRef, selectorPtr);
+ }
+
+private:
+ struct Display {
+ Display(DisplaySnapshotRef snapshot, RefreshRateSelectorPtr selectorPtr)
+ : snapshot(snapshot), selectorPtr(std::move(selectorPtr)) {}
+
+ Display(DisplaySnapshotRef snapshot, DisplayModes modes, DisplayModeId activeModeId,
+ scheduler::RefreshRateSelector::Config config)
+ : Display(snapshot,
+ std::make_shared<scheduler::RefreshRateSelector>(std::move(modes),
+ activeModeId, config)) {}
+
+ const DisplaySnapshotRef snapshot;
+ const RefreshRateSelectorPtr selectorPtr;
+ };
+
+ ui::PhysicalDisplayMap<PhysicalDisplayId, Display> mDisplays;
+};
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplaySnapshotRef.h b/services/surfaceflinger/Display/DisplaySnapshotRef.h
new file mode 100644
index 0000000..6cc5f7e
--- /dev/null
+++ b/services/surfaceflinger/Display/DisplaySnapshotRef.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 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.
+ */
+
+#pragma once
+
+#include <functional>
+
+namespace android::display {
+
+class DisplaySnapshot;
+
+using DisplaySnapshotRef = std::reference_wrapper<const DisplaySnapshot>;
+
+} // namespace android::display
diff --git a/services/surfaceflinger/Display/PhysicalDisplay.h b/services/surfaceflinger/Display/PhysicalDisplay.h
index ef36234..9b1f1ed 100644
--- a/services/surfaceflinger/Display/PhysicalDisplay.h
+++ b/services/surfaceflinger/Display/PhysicalDisplay.h
@@ -25,6 +25,7 @@
#include <utils/StrongPointer.h>
#include "DisplaySnapshot.h"
+#include "DisplaySnapshotRef.h"
namespace android::display {
@@ -45,8 +46,7 @@
// Transformers for PhysicalDisplays::get.
- using SnapshotRef = std::reference_wrapper<const DisplaySnapshot>;
- SnapshotRef snapshotRef() const { return std::cref(mSnapshot); }
+ DisplaySnapshotRef snapshotRef() const { return std::cref(mSnapshot); }
bool isInternal() const {
return mSnapshot.connectionType() == ui::DisplayConnectionType::Internal;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index edd57cc..fc5089b 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -363,7 +363,6 @@
hardware::graphics::composer::hal::PowerMode initialPowerMode{
hardware::graphics::composer::hal::PowerMode::OFF};
bool isPrimary{false};
- DisplayModeId activeModeId;
// Refer to DisplayDevice::mRequestedRefreshRate, for virtual display only
Fps requestedRefreshRate;
};
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 821ac0c..0dcbb3c 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -153,7 +153,7 @@
out << prefix + (isLastChild ? "└─ " : "├─ ");
if (variant == LayerHierarchy::Variant::Relative) {
out << "(Relative) ";
- } else if (variant == LayerHierarchy::Variant::Mirror) {
+ } else if (LayerHierarchy::isMirror(variant)) {
if (!includeMirroredHierarchy) {
out << "(Mirroring) " << *mLayer << "\n" + prefix + " └─ ...";
return;
@@ -289,6 +289,12 @@
LayerHierarchy* mirror = getHierarchyFromId(mirrorId);
hierarchy->addChild(mirror, LayerHierarchy::Variant::Mirror);
}
+ if (FlagManager::getInstance().detached_mirror()) {
+ if (layer->layerIdToMirror != UNASSIGNED_LAYER_ID) {
+ LayerHierarchy* mirror = getHierarchyFromId(layer->layerIdToMirror);
+ hierarchy->addChild(mirror, LayerHierarchy::Variant::Detached_Mirror);
+ }
+ }
}
void LayerHierarchyBuilder::onLayerDestroyed(RequestedLayerState* layer) {
@@ -325,7 +331,7 @@
LayerHierarchy* hierarchy = getHierarchyFromId(layer->id);
auto it = hierarchy->mChildren.begin();
while (it != hierarchy->mChildren.end()) {
- if (it->second == LayerHierarchy::Variant::Mirror) {
+ if (LayerHierarchy::isMirror(it->second)) {
it = hierarchy->mChildren.erase(it);
} else {
it++;
@@ -335,6 +341,12 @@
for (uint32_t mirrorId : layer->mirrorIds) {
hierarchy->addChild(getHierarchyFromId(mirrorId), LayerHierarchy::Variant::Mirror);
}
+ if (FlagManager::getInstance().detached_mirror()) {
+ if (layer->layerIdToMirror != UNASSIGNED_LAYER_ID) {
+ hierarchy->addChild(getHierarchyFromId(layer->layerIdToMirror),
+ LayerHierarchy::Variant::Detached_Mirror);
+ }
+ }
}
void LayerHierarchyBuilder::doUpdate(
@@ -501,7 +513,7 @@
// stored to reset the id upon destruction.
traversalPath.id = layerId;
traversalPath.variant = variant;
- if (variant == LayerHierarchy::Variant::Mirror) {
+ if (LayerHierarchy::isMirror(variant)) {
traversalPath.mirrorRootIds.emplace_back(mParentPath.id);
} else if (variant == LayerHierarchy::Variant::Relative) {
if (std::find(traversalPath.relativeRootIds.begin(), traversalPath.relativeRootIds.end(),
@@ -516,7 +528,7 @@
LayerHierarchy::ScopedAddToTraversalPath::~ScopedAddToTraversalPath() {
// Reset the traversal id to its original parent state using the state that was saved in
// the constructor.
- if (mTraversalPath.variant == LayerHierarchy::Variant::Mirror) {
+ if (LayerHierarchy::isMirror(mTraversalPath.variant)) {
mTraversalPath.mirrorRootIds.pop_back();
} else if (mTraversalPath.variant == LayerHierarchy::Variant::Relative) {
mTraversalPath.relativeRootIds.pop_back();
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index a1c73c3..f62e758 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -35,6 +35,7 @@
// Detached - child of the parent but currently relative parented to another layer
// Relative - relative child of the parent
// Mirror - mirrored from another layer
+// Detached_Mirror - mirrored from another layer, ignoring local transform
//
// By representing the hierarchy as a graph, we can represent mirrored layer hierarchies without
// cloning the layer requested state. The mirrored hierarchy and its corresponding
@@ -43,13 +44,18 @@
class LayerHierarchy {
public:
enum Variant : uint32_t {
- Attached, // child of the parent
- Detached, // child of the parent but currently relative parented to another layer
- Relative, // relative child of the parent
- Mirror, // mirrored from another layer
+ Attached, // child of the parent
+ Detached, // child of the parent but currently relative parented to another layer
+ Relative, // relative child of the parent
+ Mirror, // mirrored from another layer
+ Detached_Mirror, // mirrored from another layer, ignoring local transform
ftl_first = Attached,
- ftl_last = Mirror,
+ ftl_last = Detached_Mirror,
};
+ static inline bool isMirror(Variant variant) {
+ return ((variant == Mirror) || (variant == Detached_Mirror));
+ }
+
// Represents a unique path to a node.
// The layer hierarchy is represented as a graph. Each node can be visited by multiple parents.
// This allows us to represent mirroring in an efficient way. See the example below:
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 0983e7c..4b0618e 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -72,8 +72,10 @@
// Check if we are mirroring a single layer, and if so add it to the list of children
// to be mirrored.
layer.layerIdToMirror = linkLayer(layer.layerIdToMirror, layer.id);
- if (layer.layerIdToMirror != UNASSIGNED_LAYER_ID) {
- layer.mirrorIds.emplace_back(layer.layerIdToMirror);
+ if (!FlagManager::getInstance().detached_mirror()) {
+ if (layer.layerIdToMirror != UNASSIGNED_LAYER_ID) {
+ layer.mirrorIds.emplace_back(layer.layerIdToMirror);
+ }
}
}
layer.touchCropId = linkLayer(layer.touchCropId, layer.id);
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index ea06cf6..70e3c64 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -127,9 +127,8 @@
pid = state.ownerPid;
changes = RequestedLayerState::Changes::Created;
clientChanges = 0;
- mirrorRootPath = path.variant == LayerHierarchy::Variant::Mirror
- ? path
- : LayerHierarchy::TraversalPath::ROOT;
+ mirrorRootPath =
+ LayerHierarchy::isMirror(path.variant) ? path : LayerHierarchy::TraversalPath::ROOT;
reachablilty = LayerSnapshot::Reachablilty::Unreachable;
frameRateSelectionPriority = state.frameRateSelectionPriority;
layerMetadata = state.metadata;
@@ -472,13 +471,14 @@
geomContentCrop = requested.getBufferCrop();
}
- if (forceUpdate ||
- requested.what &
- (layer_state_t::eFlagsChanged | layer_state_t::eDestinationFrameChanged |
- layer_state_t::ePositionChanged | layer_state_t::eMatrixChanged |
- layer_state_t::eBufferTransformChanged |
- layer_state_t::eTransformToDisplayInverseChanged) ||
- requested.changes.test(RequestedLayerState::Changes::BufferSize) || displayChanges) {
+ if ((forceUpdate ||
+ requested.what &
+ (layer_state_t::eFlagsChanged | layer_state_t::eDestinationFrameChanged |
+ layer_state_t::ePositionChanged | layer_state_t::eMatrixChanged |
+ layer_state_t::eBufferTransformChanged |
+ layer_state_t::eTransformToDisplayInverseChanged) ||
+ requested.changes.test(RequestedLayerState::Changes::BufferSize) || displayChanges) &&
+ !ignoreLocalTransform) {
localTransform = requested.getTransform(displayRotationFlags);
localTransformInverse = localTransform.inverse();
}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 73ee22f..eef8dff 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -80,6 +80,9 @@
ui::Transform localTransformInverse;
gui::WindowInfo inputInfo;
ui::Transform localTransform;
+ // set to true if this snapshot will ignore local transforms. Used when the snapshot
+ // is a mirror root
+ bool ignoreLocalTransform;
gui::DropInputMode dropInputMode;
bool isTrustedOverlay;
gui::GameMode gameMode;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 7daeefe..a2b5329 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -575,9 +575,11 @@
mSnapshots.emplace_back(std::make_unique<LayerSnapshot>(layer, path));
LayerSnapshot* snapshot = mSnapshots.back().get();
snapshot->globalZ = static_cast<size_t>(mSnapshots.size()) - 1;
- if (path.isClone() && path.variant != LayerHierarchy::Variant::Mirror) {
+ if (path.isClone() && !LayerHierarchy::isMirror(path.variant)) {
snapshot->mirrorRootPath = parentSnapshot.mirrorRootPath;
}
+ snapshot->ignoreLocalTransform =
+ path.isClone() && path.variant == LayerHierarchy::Variant::Detached_Mirror;
mPathToSnapshot[path] = snapshot;
mIdToSnapshots.emplace(path.id, snapshot);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e7d2a11..0137a7b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -150,7 +150,7 @@
mWindowType(static_cast<WindowInfo::Type>(
args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))),
mLayerCreationFlags(args.flags),
- mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName)) {
+ mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName, this)) {
ALOGV("Creating Layer %s", getDebugName());
uint32_t layerFlags = 0;
@@ -3218,10 +3218,6 @@
mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(),
mOwnerUid, postTime, getGameMode());
- if (mFlinger->mLegacyFrontEndEnabled) {
- recordLayerHistoryBufferUpdate(getLayerProps(), systemTime());
- }
-
setFrameTimelineVsyncForBufferTransaction(info, postTime);
if (dequeueTime && *dequeueTime != 0) {
@@ -3982,7 +3978,7 @@
}
sp<LayerFE> Layer::copyCompositionEngineLayerFE() const {
- auto result = mFlinger->getFactory().createLayerFE(mName);
+ auto result = mFlinger->getFactory().createLayerFE(mName, this);
result->mSnapshot = std::make_unique<LayerSnapshot>(*mSnapshot);
return result;
}
@@ -3994,7 +3990,7 @@
return layerFE;
}
}
- auto layerFE = mFlinger->getFactory().createLayerFE(mName);
+ auto layerFE = mFlinger->getFactory().createLayerFE(mName, this);
mLayerFEs.emplace_back(path, layerFE);
return layerFE;
}
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index aa6026e..513c943 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -334,7 +334,7 @@
variant);
frontend::LayerSnapshot* childSnapshot = getSnapshot(path, layer);
if (variant == Variant::Attached || variant == Variant::Detached ||
- variant == Variant::Mirror) {
+ frontend::LayerHierarchy::isMirror(variant)) {
mChildToParent[childSnapshot->uniqueSequence] = snapshot->uniqueSequence;
layerProto->add_children(childSnapshot->uniqueSequence);
} else if (variant == Variant::Relative) {
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 21b72472..632f42a 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -181,19 +181,19 @@
bool LayerInfo::hasEnoughDataForHeuristic() const {
// The layer had to publish at least HISTORY_SIZE or HISTORY_DURATION of updates
if (mFrameTimes.size() < 2) {
- ALOGV("fewer than 2 frames recorded: %zu", mFrameTimes.size());
+ ALOGV("%s fewer than 2 frames recorded: %zu", mName.c_str(), mFrameTimes.size());
return false;
}
if (!isFrameTimeValid(mFrameTimes.front())) {
- ALOGV("stale frames still captured");
+ ALOGV("%s stale frames still captured", mName.c_str());
return false;
}
const auto totalDuration = mFrameTimes.back().queueTime - mFrameTimes.front().queueTime;
if (mFrameTimes.size() < HISTORY_SIZE && totalDuration < HISTORY_DURATION.count()) {
- ALOGV("not enough frames captured: %zu | %.2f seconds", mFrameTimes.size(),
- totalDuration / 1e9f);
+ ALOGV("%s not enough frames captured: %zu | %.2f seconds", mName.c_str(),
+ mFrameTimes.size(), totalDuration / 1e9f);
return false;
}
@@ -365,6 +365,8 @@
}
if (frequent.clearHistory) {
+ ATRACE_FORMAT_INSTANT("frequent.clearHistory");
+ ALOGV("%s frequent.clearHistory", mName.c_str());
clearHistory(now);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5263aa8..64d80d9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -229,7 +229,7 @@
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
}
-std::chrono::milliseconds getIdleTimerTimeout(DisplayId displayId) {
+std::chrono::milliseconds getIdleTimerTimeout(PhysicalDisplayId displayId) {
if (const int32_t displayIdleTimerMs =
base::GetIntProperty("debug.sf.set_idle_timer_ms_"s +
std::to_string(displayId.value),
@@ -243,7 +243,7 @@
return std::chrono::milliseconds(millis);
}
-bool getKernelIdleTimerSyspropConfig(DisplayId displayId) {
+bool getKernelIdleTimerSyspropConfig(PhysicalDisplayId displayId) {
const bool displaySupportKernelIdleTimer =
base::GetBoolProperty("debug.sf.support_kernel_idle_timer_"s +
std::to_string(displayId.value),
@@ -532,8 +532,6 @@
mLayerLifecycleManagerEnabled =
base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true);
- mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled ||
- base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false);
// These are set by the HWC implementation to indicate that they will use the workarounds.
mIsHotplugErrViaNegVsync =
@@ -2226,19 +2224,20 @@
void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData& data) {
ATRACE_CALL();
- if (const auto displayId = getHwComposer().toPhysicalDisplayId(data.display); displayId) {
- const char* const whence = __func__;
- static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) {
- const Fps fps = Fps::fromPeriodNsecs(getHwComposer().getComposer()->isVrrSupported()
- ? data.refreshPeriodNanos
- : data.vsyncPeriodNanos);
- ATRACE_FORMAT("%s Fps %d", whence, fps.getIntValue());
- const auto display = getDisplayDeviceLocked(*displayId);
- FTL_FAKE_GUARD(kMainThreadContext,
- display->updateRefreshRateOverlayRate(fps, display->getActiveMode().fps,
- /* setByHwc */ true));
- }));
- }
+ const char* const whence = __func__;
+ static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
+ kMainThreadContext) {
+ if (const auto displayIdOpt = getHwComposer().toPhysicalDisplayId(data.display)) {
+ if (const auto display = getDisplayDeviceLocked(*displayIdOpt)) {
+ const Fps fps = Fps::fromPeriodNsecs(getHwComposer().getComposer()->isVrrSupported()
+ ? data.refreshPeriodNanos
+ : data.vsyncPeriodNanos);
+ ATRACE_FORMAT("%s Fps %d", whence, fps.getIntValue());
+ display->updateRefreshRateOverlayRate(fps, display->getActiveMode().fps,
+ /* setByHwc */ true);
+ }
+ }
+ }));
}
void SurfaceFlinger::configure() {
@@ -2441,86 +2440,84 @@
mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0;
bool newDataLatched = false;
- if (!mLegacyFrontEndEnabled) {
- ATRACE_NAME("DisplayCallbackAndStatsUpdates");
- mustComposite |= applyTransactionsLocked(update.transactions, vsyncId);
- traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
- const nsecs_t latchTime = systemTime();
- bool unused = false;
+ ATRACE_NAME("DisplayCallbackAndStatsUpdates");
+ mustComposite |= applyTransactionsLocked(update.transactions, vsyncId);
+ traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
+ const nsecs_t latchTime = systemTime();
+ bool unused = false;
- for (auto& layer : mLayerLifecycleManager.getLayers()) {
- if (layer->changes.test(frontend::RequestedLayerState::Changes::Created) &&
- layer->bgColorLayer) {
- sp<Layer> bgColorLayer = getFactory().createEffectLayer(
- LayerCreationArgs(this, nullptr, layer->name,
- ISurfaceComposerClient::eFXSurfaceEffect, LayerMetadata(),
- std::make_optional(layer->id), true));
- mLegacyLayers[bgColorLayer->sequence] = bgColorLayer;
- }
- const bool willReleaseBufferOnLatch = layer->willReleaseBufferOnLatch();
+ for (auto& layer : mLayerLifecycleManager.getLayers()) {
+ if (layer->changes.test(frontend::RequestedLayerState::Changes::Created) &&
+ layer->bgColorLayer) {
+ sp<Layer> bgColorLayer = getFactory().createEffectLayer(
+ LayerCreationArgs(this, nullptr, layer->name,
+ ISurfaceComposerClient::eFXSurfaceEffect, LayerMetadata(),
+ std::make_optional(layer->id), true));
+ mLegacyLayers[bgColorLayer->sequence] = bgColorLayer;
+ }
+ const bool willReleaseBufferOnLatch = layer->willReleaseBufferOnLatch();
- auto it = mLegacyLayers.find(layer->id);
- if (it == mLegacyLayers.end() &&
- layer->changes.test(frontend::RequestedLayerState::Changes::Destroyed)) {
- // Layer handle was created and immediately destroyed. It was destroyed before it
- // was added to the map.
- continue;
- }
-
- LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
- "Couldnt find layer object for %s",
- layer->getDebugString().c_str());
- if (!layer->hasReadyFrame() && !willReleaseBufferOnLatch) {
- if (!it->second->hasBuffer()) {
- // The last latch time is used to classify a missed frame as buffer stuffing
- // instead of a missed frame. This is used to identify scenarios where we
- // could not latch a buffer or apply a transaction due to backpressure.
- // We only update the latch time for buffer less layers here, the latch time
- // is updated for buffer layers when the buffer is latched.
- it->second->updateLastLatchTime(latchTime);
- }
- continue;
- }
-
- const bool bgColorOnly =
- !layer->externalTexture && (layer->bgColorLayerId != UNASSIGNED_LAYER_ID);
- if (willReleaseBufferOnLatch) {
- mLayersWithBuffersRemoved.emplace(it->second);
- }
- it->second->latchBufferImpl(unused, latchTime, bgColorOnly);
- newDataLatched = true;
-
- mLayersWithQueuedFrames.emplace(it->second);
- mLayersIdsWithQueuedFrames.emplace(it->second->sequence);
+ auto it = mLegacyLayers.find(layer->id);
+ if (it == mLegacyLayers.end() &&
+ layer->changes.test(frontend::RequestedLayerState::Changes::Destroyed)) {
+ // Layer handle was created and immediately destroyed. It was destroyed before it
+ // was added to the map.
+ continue;
}
- updateLayerHistory(latchTime);
- mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) {
- if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) ==
- mLayersIdsWithQueuedFrames.end())
- return;
- Region visibleReg;
- visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion);
- invalidateLayerStack(snapshot.outputFilter, visibleReg);
- });
-
- for (auto& destroyedLayer : mLayerLifecycleManager.getDestroyedLayers()) {
- mLegacyLayers.erase(destroyedLayer->id);
+ LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mLegacyLayers.end(),
+ "Couldnt find layer object for %s",
+ layer->getDebugString().c_str());
+ if (!layer->hasReadyFrame() && !willReleaseBufferOnLatch) {
+ if (!it->second->hasBuffer()) {
+ // The last latch time is used to classify a missed frame as buffer stuffing
+ // instead of a missed frame. This is used to identify scenarios where we
+ // could not latch a buffer or apply a transaction due to backpressure.
+ // We only update the latch time for buffer less layers here, the latch time
+ // is updated for buffer layers when the buffer is latched.
+ it->second->updateLastLatchTime(latchTime);
+ }
+ continue;
}
- {
- ATRACE_NAME("LLM:commitChanges");
- mLayerLifecycleManager.commitChanges();
+ const bool bgColorOnly =
+ !layer->externalTexture && (layer->bgColorLayerId != UNASSIGNED_LAYER_ID);
+ if (willReleaseBufferOnLatch) {
+ mLayersWithBuffersRemoved.emplace(it->second);
}
+ it->second->latchBufferImpl(unused, latchTime, bgColorOnly);
+ newDataLatched = true;
- // enter boot animation on first buffer latch
- if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
- ALOGI("Enter boot animation");
- mBootStage = BootStage::BOOTANIMATION;
- }
+ mLayersWithQueuedFrames.emplace(it->second);
+ mLayersIdsWithQueuedFrames.emplace(it->second->sequence);
}
+
+ updateLayerHistory(latchTime);
+ mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+ if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) == mLayersIdsWithQueuedFrames.end())
+ return;
+ Region visibleReg;
+ visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion);
+ invalidateLayerStack(snapshot.outputFilter, visibleReg);
+ });
+
+ for (auto& destroyedLayer : mLayerLifecycleManager.getDestroyedLayers()) {
+ mLegacyLayers.erase(destroyedLayer->id);
+ }
+
+ {
+ ATRACE_NAME("LLM:commitChanges");
+ mLayerLifecycleManager.commitChanges();
+ }
+
+ // enter boot animation on first buffer latch
+ if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) {
+ ALOGI("Enter boot animation");
+ mBootStage = BootStage::BOOTANIMATION;
+ }
+
mustComposite |= (getTransactionFlags() & ~eTransactionFlushNeeded) || newDataLatched;
- if (mustComposite && !mLegacyFrontEndEnabled) {
+ if (mustComposite) {
commitTransactions();
}
@@ -2622,12 +2619,7 @@
mScheduler->getPacesetterRefreshRate());
const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
- bool transactionsAreEmpty;
- if (mLegacyFrontEndEnabled) {
- mustComposite |=
- updateLayerSnapshotsLegacy(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
- flushTransactions, transactionsAreEmpty);
- }
+ bool transactionsAreEmpty = false;
if (mLayerLifecycleManagerEnabled) {
mustComposite |=
updateLayerSnapshots(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
@@ -3516,12 +3508,45 @@
for (const auto [hwcDisplayId, connection] : events) {
if (auto info = getHwComposer().onHotplug(hwcDisplayId, connection)) {
const auto displayId = info->id;
- const bool connected = connection == hal::Connection::CONNECTED;
+ const ftl::Concat displayString("display ", displayId.value, "(HAL ID ", hwcDisplayId,
+ ')');
- if (const char* const log =
- processHotplug(displayId, hwcDisplayId, connected, std::move(*info))) {
- ALOGI("%s display %s (HAL ID %" PRIu64 ")", log, to_string(displayId).c_str(),
- hwcDisplayId);
+ if (connection == hal::Connection::CONNECTED) {
+ const auto activeModeIdOpt =
+ processHotplugConnect(displayId, hwcDisplayId, std::move(*info),
+ displayString.c_str());
+ if (!activeModeIdOpt) {
+ if (FlagManager::getInstance().hotplug2()) {
+ mScheduler->dispatchHotplugError(
+ static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN));
+ }
+ getHwComposer().disconnectDisplay(displayId);
+ continue;
+ }
+
+ const auto [kernelIdleTimerController, idleTimerTimeoutMs] =
+ getKernelIdleTimerProperties(displayId);
+
+ using Config = scheduler::RefreshRateSelector::Config;
+ const Config config =
+ {.enableFrameRateOverride = sysprop::enable_frame_rate_override(true)
+ ? Config::FrameRateOverride::Enabled
+ : Config::FrameRateOverride::Disabled,
+ .frameRateMultipleThreshold =
+ base::GetIntProperty("debug.sf.frame_rate_multiple_threshold"s, 0),
+ .legacyIdleTimerTimeout = idleTimerTimeoutMs,
+ .kernelIdleTimerController = kernelIdleTimerController};
+
+ const auto snapshotOpt =
+ mPhysicalDisplays.get(displayId).transform(&PhysicalDisplay::snapshotRef);
+ LOG_ALWAYS_FATAL_IF(!snapshotOpt);
+
+ mDisplayModeController.registerDisplay(*snapshotOpt, *activeModeIdOpt, config);
+ } else {
+ // Unregister before destroying the DisplaySnapshot below.
+ mDisplayModeController.unregisterDisplay(displayId);
+
+ processHotplugDisconnect(displayId, displayString.c_str());
}
}
}
@@ -3529,36 +3554,20 @@
return !events.empty();
}
-const char* SurfaceFlinger::processHotplug(PhysicalDisplayId displayId,
- hal::HWDisplayId hwcDisplayId, bool connected,
- DisplayIdentificationInfo&& info) {
- const auto displayOpt = mPhysicalDisplays.get(displayId);
- if (!connected) {
- LOG_ALWAYS_FATAL_IF(!displayOpt);
- const auto& display = displayOpt->get();
-
- if (const ssize_t index = mCurrentState.displays.indexOfKey(display.token()); index >= 0) {
- mCurrentState.displays.removeItemsAt(index);
- }
-
- mPhysicalDisplays.erase(displayId);
- return "Disconnecting";
- }
-
+std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDisplayId displayId,
+ hal::HWDisplayId hwcDisplayId,
+ DisplayIdentificationInfo&& info,
+ const char* displayString) {
auto [displayModes, activeMode] = loadDisplayModes(displayId);
if (!activeMode) {
- ALOGE("Failed to hotplug display %s", to_string(displayId).c_str());
- if (FlagManager::getInstance().hotplug2()) {
- mScheduler->dispatchHotplugError(
- static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN));
- }
- getHwComposer().disconnectDisplay(displayId);
- return nullptr;
+ ALOGE("Failed to hotplug %s", displayString);
+ return std::nullopt;
}
+ const DisplayModeId activeModeId = activeMode->getId();
ui::ColorModes colorModes = getHwComposer().getColorModes(displayId);
- if (displayOpt) {
+ if (const auto displayOpt = mPhysicalDisplays.get(displayId)) {
const auto& display = displayOpt->get();
const auto& snapshot = display.snapshot();
@@ -3577,7 +3586,8 @@
auto& state = mCurrentState.displays.editValueFor(it->second.token());
state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId.
state.physical->activeMode = std::move(activeMode);
- return "Reconnecting";
+ ALOGI("Reconnecting %s", displayString);
+ return activeModeId;
}
const sp<IBinder> token = sp<BBinder>::make();
@@ -3597,7 +3607,23 @@
state.displayName = std::move(info.name);
mCurrentState.displays.add(token, state);
- return "Connecting";
+ ALOGI("Connecting %s", displayString);
+ return activeModeId;
+}
+
+void SurfaceFlinger::processHotplugDisconnect(PhysicalDisplayId displayId,
+ const char* displayString) {
+ ALOGI("Disconnecting %s", displayString);
+
+ const auto displayOpt = mPhysicalDisplays.get(displayId);
+ LOG_ALWAYS_FATAL_IF(!displayOpt);
+ const auto& display = displayOpt->get();
+
+ if (const ssize_t index = mCurrentState.displays.indexOfKey(display.token()); index >= 0) {
+ mCurrentState.displays.removeItemsAt(index);
+ }
+
+ mPhysicalDisplays.erase(displayId);
}
void SurfaceFlinger::dispatchDisplayModeChangeEvent(PhysicalDisplayId displayId,
@@ -3625,43 +3651,21 @@
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
- if (const auto& physical = state.physical) {
- creationArgs.activeModeId = physical->activeMode->getId();
- const auto [kernelIdleTimerController, idleTimerTimeoutMs] =
- getKernelIdleTimerProperties(compositionDisplay->getId());
+ if (const auto physicalIdOpt = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
+ const auto physicalId = *physicalIdOpt;
- using Config = scheduler::RefreshRateSelector::Config;
- const auto enableFrameRateOverride = sysprop::enable_frame_rate_override(true)
- ? Config::FrameRateOverride::Enabled
- : Config::FrameRateOverride::Disabled;
- const Config config =
- {.enableFrameRateOverride = enableFrameRateOverride,
- .frameRateMultipleThreshold =
- base::GetIntProperty("debug.sf.frame_rate_multiple_threshold"s, 0),
- .legacyIdleTimerTimeout = idleTimerTimeoutMs,
- .kernelIdleTimerController = kernelIdleTimerController};
-
+ creationArgs.isPrimary = physicalId == getPrimaryDisplayIdLocked();
creationArgs.refreshRateSelector =
- mPhysicalDisplays.get(physical->id)
- .transform(&PhysicalDisplay::snapshotRef)
- .transform([&](const display::DisplaySnapshot& snapshot) {
- return std::make_shared<
- scheduler::RefreshRateSelector>(snapshot.displayModes(),
- creationArgs.activeModeId,
- config);
- })
- .value_or(nullptr);
+ FTL_FAKE_GUARD(kMainThreadContext,
+ mDisplayModeController.selectorPtrFor(physicalId));
- creationArgs.isPrimary = physical->id == getPrimaryDisplayIdLocked();
-
- mPhysicalDisplays.get(physical->id)
+ mPhysicalDisplays.get(physicalId)
.transform(&PhysicalDisplay::snapshotRef)
.transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) {
for (const auto mode : snapshot.colorModes()) {
creationArgs.hasWideColorGamut |= ui::isWideColorMode(mode);
creationArgs.hwcColorModes
- .emplace(mode,
- getHwComposer().getRenderIntents(physical->id, mode));
+ .emplace(mode, getHwComposer().getRenderIntents(physicalId, mode));
}
}));
}
@@ -5251,16 +5255,9 @@
nsecs_t now = systemTime();
uint32_t clientStateFlags = 0;
for (auto& resolvedState : states) {
- if (mLegacyFrontEndEnabled) {
- clientStateFlags |=
- setClientStateLocked(frameTimelineInfo, resolvedState, desiredPresentTime,
- isAutoTimestamp, postTime, transactionId);
-
- } else /*mLayerLifecycleManagerEnabled*/ {
- clientStateFlags |= updateLayerCallbacksAndStats(frameTimelineInfo, resolvedState,
- desiredPresentTime, isAutoTimestamp,
- postTime, transactionId);
- }
+ clientStateFlags |=
+ updateLayerCallbacksAndStats(frameTimelineInfo, resolvedState, desiredPresentTime,
+ isAutoTimestamp, postTime, transactionId);
if (!mLayerLifecycleManagerEnabled) {
if ((flags & eAnimation) && resolvedState.state.surface) {
if (const auto layer = LayerHandle::getLayer(resolvedState.state.surface)) {
@@ -5332,7 +5329,7 @@
}
mFrontEndDisplayInfosChanged = mTransactionFlags & eDisplayTransactionNeeded;
- if (mFrontEndDisplayInfosChanged && !mLegacyFrontEndEnabled) {
+ if (mFrontEndDisplayInfosChanged) {
processDisplayChangesLocked();
mFrontEndDisplayInfos.clear();
for (const auto& [_, display] : mDisplays) {
@@ -5975,11 +5972,6 @@
return result;
}
- if (mLegacyFrontEndEnabled) {
- std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
- mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client);
- }
-
setTransactionFlags(eTransactionFlushNeeded);
return NO_ERROR;
}
@@ -6094,9 +6086,7 @@
std::vector<TransactionState> transactions;
transactions.emplace_back(state);
- if (mLegacyFrontEndEnabled) {
- applyTransactions(transactions, VsyncId{0});
- } else {
+ {
Mutex::Autolock lock(mStateLock);
applyAndCommitDisplayTransactionStatesLocked(transactions);
}
@@ -6648,17 +6638,6 @@
}
}
- if (mLegacyFrontEndEnabled) {
- perfetto::protos::LayersProto layersProto;
- for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
- if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) {
- continue;
- }
- layer->writeToProto(layersProto, traceFlags);
- }
- return layersProto;
- }
-
return LayerProtoFromSnapshotGenerator(mLayerSnapshotBuilder, mFrontEndDisplayInfos,
mLegacyLayers, traceFlags)
.generate(mLayerHierarchyBuilder.getHierarchy());
@@ -6907,10 +6886,6 @@
}
result.push_back('\n');
- if (mLegacyFrontEndEnabled) {
- dumpHwcLayersMinidumpLockedLegacy(result);
- }
-
{
DumpArgs plannerArgs;
plannerArgs.add(); // first argument is ignored
@@ -7664,13 +7639,12 @@
}
std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
-SurfaceFlinger::getKernelIdleTimerProperties(DisplayId displayId) {
+SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) {
const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported(
android::Hwc2::Composer::OptionalFeature::KernelIdleTimer);
const auto timeout = getIdleTimerTimeout(displayId);
if (isKernelIdleTimerHwcSupported) {
- if (const auto id = PhysicalDisplayId::tryCast(displayId);
- getHwComposer().hasDisplayIdleTimerCapability(*id)) {
+ if (getHwComposer().hasDisplayIdleTimerCapability(displayId)) {
// In order to decide if we can use the HWC api for idle timer
// we query DisplayCapability::DISPLAY_IDLE_TIMER directly on the composer
// without relying on hasDisplayCapability.
@@ -9236,7 +9210,7 @@
snapshots[i] = std::move(layerFE->mSnapshot);
}
}
- if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
+ if (!mLayerLifecycleManagerEnabled) {
for (auto [layer, layerFE] : layers) {
layer->updateLayerSnapshot(std::move(layerFE->mSnapshot));
}
@@ -9273,7 +9247,7 @@
layers.emplace_back(legacyLayer.get(), layerFE.get());
});
}
- if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
+ if (!mLayerLifecycleManagerEnabled) {
auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) {
if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
if (cursorOnly &&
@@ -9338,7 +9312,7 @@
"Couldnt find layer object for %s",
snapshot->getDebugString().c_str());
Layer* legacyLayer = (it == mLegacyLayers.end()) ? nullptr : it->second.get();
- sp<LayerFE> layerFE = getFactory().createLayerFE(snapshot->name);
+ sp<LayerFE> layerFE = getFactory().createLayerFE(snapshot->name, legacyLayer);
layerFE->mSnapshot = std::make_unique<frontend::LayerSnapshot>(*snapshot);
layers.emplace_back(legacyLayer, std::move(layerFE));
});
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 44fa806..fc50fd9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -65,6 +65,7 @@
#include <ui/FenceResult.h>
#include <common/FlagManager.h>
+#include "Display/DisplayModeController.h"
#include "Display/PhysicalDisplay.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWC2.h"
@@ -707,7 +708,7 @@
// Get the controller and timeout that will help decide how the kernel idle timer will be
// configured and what value to use as the timeout.
std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
- getKernelIdleTimerProperties(DisplayId) REQUIRES(mStateLock);
+ getKernelIdleTimerProperties(PhysicalDisplayId) REQUIRES(mStateLock);
// Updates the kernel idle timer either through HWC or through sysprop
// depending on which controller is provided
void updateKernelIdleTimer(std::chrono::milliseconds timeoutMs, KernelIdleTimerController,
@@ -989,8 +990,7 @@
return getDefaultDisplayDeviceLocked();
}
- using DisplayDeviceAndSnapshot =
- std::pair<sp<DisplayDevice>, display::PhysicalDisplay::SnapshotRef>;
+ using DisplayDeviceAndSnapshot = std::pair<sp<DisplayDevice>, display::DisplaySnapshotRef>;
// Combinator for ftl::Optional<PhysicalDisplay>::and_then.
auto getDisplayDeviceAndSnapshot() REQUIRES(mStateLock) {
@@ -1059,10 +1059,13 @@
bool configureLocked() REQUIRES(mStateLock) REQUIRES(kMainThreadContext)
EXCLUDES(mHotplugMutex);
- // Returns a string describing the hotplug, or nullptr if it was rejected.
- const char* processHotplug(PhysicalDisplayId, hal::HWDisplayId, bool connected,
- DisplayIdentificationInfo&&) REQUIRES(mStateLock)
- REQUIRES(kMainThreadContext);
+ // Returns the active mode ID, or nullopt on hotplug failure.
+ std::optional<DisplayModeId> processHotplugConnect(PhysicalDisplayId, hal::HWDisplayId,
+ DisplayIdentificationInfo&&,
+ const char* displayString)
+ REQUIRES(mStateLock, kMainThreadContext);
+ void processHotplugDisconnect(PhysicalDisplayId, const char* displayString)
+ REQUIRES(mStateLock, kMainThreadContext);
sp<DisplayDevice> setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken,
@@ -1323,6 +1326,8 @@
// reads from ISchedulerCallback::requestDisplayModes may happen concurrently.
std::atomic<PhysicalDisplayId> mActiveDisplayId GUARDED_BY(mStateLock);
+ display::DisplayModeController mDisplayModeController;
+
struct {
DisplayIdGenerator<GpuVirtualDisplayId> gpu;
std::optional<DisplayIdGenerator<HalVirtualDisplayId>> hal;
@@ -1486,7 +1491,6 @@
bool mPowerHintSessionEnabled;
bool mLayerLifecycleManagerEnabled = false;
- bool mLegacyFrontEndEnabled = true;
frontend::LayerLifecycleManager mLayerLifecycleManager GUARDED_BY(kMainThreadContext);
frontend::LayerHierarchyBuilder mLayerHierarchyBuilder GUARDED_BY(kMainThreadContext);
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 50b167d..b1d8ba9 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -85,7 +85,7 @@
return sp<Layer>::make(args);
}
-sp<LayerFE> DefaultFactory::createLayerFE(const std::string& layerName) {
+sp<LayerFE> DefaultFactory::createLayerFE(const std::string& layerName, const Layer* /* owner */) {
return sp<LayerFE>::make(layerName);
}
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 540dec8..7ebf10f 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -41,7 +41,7 @@
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) override;
sp<Layer> createEffectLayer(const LayerCreationArgs& args) override;
- sp<LayerFE> createLayerFE(const std::string& layerName) override;
+ sp<LayerFE> createLayerFE(const std::string& layerName, const Layer* owner) override;
std::unique_ptr<FrameTracer> createFrameTracer() override;
std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index f1fbf01..c7d1fa0 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -85,7 +85,7 @@
virtual sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
virtual sp<Layer> createEffectLayer(const LayerCreationArgs& args) = 0;
- virtual sp<LayerFE> createLayerFE(const std::string& layerName) = 0;
+ virtual sp<LayerFE> createLayerFE(const std::string& layerName, const Layer* owner) = 0;
virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0;
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 929388f..f074b7d 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -143,6 +143,7 @@
DUMP_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed);
DUMP_READ_ONLY_FLAG(deprecate_vsync_sf);
DUMP_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter);
+ DUMP_READ_ONLY_FLAG(detached_mirror);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -236,6 +237,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, "");
FLAG_MANAGER_READ_ONLY_FLAG(deprecate_vsync_sf, "");
FLAG_MANAGER_READ_ONLY_FLAG(allow_n_vsyncs_in_targeter, "");
+FLAG_MANAGER_READ_ONLY_FLAG(detached_mirror, "");
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 4170c8a..0acf754 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -81,6 +81,7 @@
bool latch_unsignaled_with_auto_refresh_changed() const;
bool deprecate_vsync_sf() const;
bool allow_n_vsyncs_in_targeter() const;
+ bool detached_mirror() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index 4a60987..4d3195d 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -32,6 +32,17 @@
}
} # deprecate_vsync_sf
+ flag {
+ name: "detached_mirror"
+ namespace: "window_surfaces"
+ description: "Ignore local transform when mirroring a partial hierarchy"
+ bug: "337845753"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} # deprecate_vsync_sf
+
flag {
name: "frame_rate_category_mrr"
namespace: "core_graphics"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 2b1834d..4b3ad8a 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -154,8 +154,6 @@
switch (layerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply();
- break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
Transaction().setPosition(layerG, 16, 16).setRelativeLayer(layerG, layerR, 1).apply();
break;
@@ -200,13 +198,6 @@
// layerR = 0, layerG = layerR + 3, layerB = 2
switch (layerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setPosition(layerG, 8, 8)
- .setRelativeLayer(layerG, layerR, 3)
- .setPosition(layerB, 16, 16)
- .setLayer(layerB, mLayerZBase + 2)
- .apply();
- break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
Transaction()
.setPosition(layerG, 8, 8)
@@ -413,13 +404,6 @@
switch (layerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setAlpha(layer1, 0.25f)
- .setAlpha(layer2, 0.75f)
- .setPosition(layer2, 16, 0)
- .setLayer(layer2, mLayerZBase + 1)
- .apply();
- break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
Transaction()
.setAlpha(layer1, 0.25f)
diff --git a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h
index 34e4ba5..d4c801f 100644
--- a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h
+++ b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h
@@ -60,7 +60,7 @@
.setNativeWindow(mNativeWindow)
.setPowerMode(hal::PowerMode::ON)
.setRefreshRateSelector(mFlinger.scheduler()->refreshRateSelector())
- .skipRegisterDisplay()
+ .skipSchedulerRegistration()
.inject();
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 7d8a30a..0ddddbd 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -282,7 +282,7 @@
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.setRefreshRateSelector(test->mFlinger.scheduler()->refreshRateSelector())
- .skipRegisterDisplay()
+ .skipSchedulerRegistration()
.inject();
Mock::VerifyAndClear(test->mNativeWindow.get());
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index e8e7667..fd15eef 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -155,6 +155,17 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setPosition(uint32_t id, float x, float y) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::ePositionChanged;
+ transactions.back().states.front().state.x = x;
+ transactions.back().states.front().state.y = y;
+ transactions.back().states.front().layerId = id;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
virtual void mirrorLayer(uint32_t id, uint32_t parentId, uint32_t layerIdToMirror) {
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index e0a3101..088d0d2 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -506,7 +506,7 @@
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
- // layer became inactive, but the vote stays
+ // layer became infrequent, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, summarizeLayerHistory(time).size());
@@ -540,7 +540,7 @@
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
- // layer became inactive, but the vote stays
+ // layer became infrequent, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, summarizeLayerHistory(time).size());
@@ -692,7 +692,7 @@
EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
- // layer became inactive, but the vote stays
+ // layer became infrequent, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, summarizeLayerHistory(time).size());
@@ -729,7 +729,7 @@
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
- // layer became inactive
+ // layer became infrequent
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(1, activeLayerCount());
@@ -770,7 +770,7 @@
EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate);
EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[1].frameRateCategory);
- // layer became inactive, but the vote stays
+ // layer became infrequent, but the vote stays
setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(2, summarizeLayerHistory(time).size());
@@ -1175,7 +1175,7 @@
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
- // layer became inactive
+ // Layer still active due to front buffering, but it's infrequent.
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, summarizeLayerHistory(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index ae9a89c..7c6cff0 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1302,4 +1302,33 @@
EXPECT_EQ(getSnapshot(1221)->inputInfo.canOccludePresentation, true);
}
+TEST_F(LayerSnapshotTest, mirroredHierarchyIgnoresLocalTransform) {
+ SET_FLAG_FOR_TEST(flags::detached_mirror, true);
+ reparentLayer(12, UNASSIGNED_LAYER_ID);
+ setPosition(11, 2, 20);
+ setPosition(111, 20, 200);
+ mirrorLayer(/*layer*/ 14, /*parent*/ 1, /*layerToMirror*/ 11);
+ std::vector<uint32_t> expected = {1, 11, 111, 13, 14, 11, 111, 2};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+
+ // mirror root has no position set
+ EXPECT_EQ(getSnapshot({.id = 11, .mirrorRootIds = 14u})->localTransform.tx(), 0);
+ EXPECT_EQ(getSnapshot({.id = 11, .mirrorRootIds = 14u})->localTransform.ty(), 0);
+ // original root still has a position
+ EXPECT_EQ(getSnapshot({.id = 11})->localTransform.tx(), 2);
+ EXPECT_EQ(getSnapshot({.id = 11})->localTransform.ty(), 20);
+
+ // mirror child still has the correct position
+ EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootIds = 14u})->localTransform.tx(), 20);
+ EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootIds = 14u})->localTransform.ty(), 200);
+ EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootIds = 14u})->geomLayerTransform.tx(), 20);
+ EXPECT_EQ(getSnapshot({.id = 111, .mirrorRootIds = 14u})->geomLayerTransform.ty(), 200);
+
+ // original child still has the correct position including its parent's position
+ EXPECT_EQ(getSnapshot({.id = 111})->localTransform.tx(), 20);
+ EXPECT_EQ(getSnapshot({.id = 111})->localTransform.ty(), 200);
+ EXPECT_EQ(getSnapshot({.id = 111})->geomLayerTransform.tx(), 22);
+ EXPECT_EQ(getSnapshot({.id = 111})->geomLayerTransform.ty(), 220);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_ColorMatrixTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_ColorMatrixTest.cpp
index f127213..5852b1c 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_ColorMatrixTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_ColorMatrixTest.cpp
@@ -28,6 +28,7 @@
class ColorMatrixTest : public CommitAndCompositeTest {};
TEST_F(ColorMatrixTest, colorMatrixChanged) {
+ mFlinger.enableLayerLifecycleManager();
EXPECT_COLOR_MATRIX_CHANGED(true, true);
mFlinger.mutableTransactionFlags() |= eTransactionNeeded;
@@ -45,6 +46,7 @@
}
TEST_F(ColorMatrixTest, colorMatrixChangedAfterDisplayTransaction) {
+ mFlinger.enableLayerLifecycleManager();
EXPECT_COLOR_MATRIX_CHANGED(true, true);
mFlinger.mutableTransactionFlags() |= eTransactionNeeded;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index c0796df..1bae5ff 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -255,10 +255,15 @@
colorModes.push_back(ColorMode::DISPLAY_P3);
}
- mFlinger.mutablePhysicalDisplays().emplace_or_replace(*displayId, displayToken, *displayId,
- *connectionType,
- makeModes(activeMode),
- std::move(colorModes), std::nullopt);
+ const auto it = mFlinger.mutablePhysicalDisplays()
+ .emplace_or_replace(*displayId, displayToken, *displayId,
+ *connectionType, makeModes(activeMode),
+ std::move(colorModes), std::nullopt)
+ .first;
+
+ FTL_FAKE_GUARD(kMainThreadContext,
+ mFlinger.mutableDisplayModeController()
+ .registerDisplay(it->second.snapshot(), activeMode->getId(), {}));
}
state.isSecure = static_cast<bool>(Case::Display::SECURE);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 85b1717..9353467 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -131,7 +131,7 @@
sp<Layer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
- sp<LayerFE> createLayerFE(const std::string& layerName) override {
+ sp<LayerFE> createLayerFE(const std::string& layerName, const Layer* /* owner */) override {
return sp<LayerFE>::make(layerName);
}
@@ -657,6 +657,7 @@
auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; }
+ auto& mutableDisplayModeController() { return mFlinger->mDisplayModeController; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
auto& mutableDisplays() { return mFlinger->mDisplays; }
@@ -691,6 +692,10 @@
return mFlinger->initTransactionTraceWriter();
}
+ // Needed since mLayerLifecycleManagerEnabled is false by default and must
+ // be enabled for tests to go through the new front end path.
+ void enableLayerLifecycleManager() { mFlinger->mLayerLifecycleManagerEnabled = true; }
+
void notifyExpectedPresentIfRequired(PhysicalDisplayId displayId, Period vsyncPeriod,
TimePoint expectedPresentTime, Fps frameInterval,
std::optional<Period> timeoutOpt) {
@@ -967,14 +972,14 @@
auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId) {
mDisplayModes = std::move(modes);
- mCreationArgs.activeModeId = activeModeId;
+ mActiveModeId = activeModeId;
mCreationArgs.refreshRateSelector = nullptr;
return *this;
}
auto& setRefreshRateSelector(RefreshRateSelectorPtr selectorPtr) {
mDisplayModes = selectorPtr->displayModes();
- mCreationArgs.activeModeId = selectorPtr->getActiveMode().modePtr->getId();
+ mActiveModeId = selectorPtr->getActiveMode().modePtr->getId();
mCreationArgs.refreshRateSelector = std::move(selectorPtr);
return *this;
}
@@ -1016,8 +1021,9 @@
return *this;
}
- auto& skipRegisterDisplay() {
- mRegisterDisplay = false;
+ // Used to avoid overwriting mocks injected by TestableSurfaceFlinger::setupMockScheduler.
+ auto& skipSchedulerRegistration() {
+ mSchedulerRegistration = false;
return *this;
}
@@ -1030,12 +1036,24 @@
std::shared_ptr<android::scheduler::VSyncTracker> tracker)
NO_THREAD_SAFETY_ANALYSIS {
const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
auto& modes = mDisplayModes;
- auto& activeModeId = mCreationArgs.activeModeId;
+ auto& activeModeId = mActiveModeId;
+ std::optional<Fps> refreshRateOpt;
- if (displayId && !mCreationArgs.refreshRateSelector) {
- if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) {
+ DisplayDeviceState state;
+ state.isSecure = mCreationArgs.isSecure;
+
+ if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) {
+ LOG_ALWAYS_FATAL_IF(!mConnectionType);
+ LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
+
+ if (mCreationArgs.isPrimary) {
+ mFlinger.mutableActiveDisplayId() = *physicalId;
+ }
+
+ if (!mCreationArgs.refreshRateSelector) {
if (modes.empty()) {
constexpr DisplayModeId kModeId{0};
DisplayModePtr mode =
@@ -1057,48 +1075,38 @@
mCreationArgs.refreshRateSelector =
std::make_shared<scheduler::RefreshRateSelector>(modes, activeModeId);
}
+
+ const auto activeModeOpt = modes.get(activeModeId);
+ LOG_ALWAYS_FATAL_IF(!activeModeOpt);
+ refreshRateOpt = activeModeOpt->get()->getPeakFps();
+
+ state.physical = {.id = *physicalId,
+ .hwcDisplayId = *mHwcDisplayId,
+ .activeMode = activeModeOpt->get()};
+
+ const auto it = mFlinger.mutablePhysicalDisplays()
+ .emplace_or_replace(*physicalId, mDisplayToken, *physicalId,
+ *mConnectionType, std::move(modes),
+ ui::ColorModes(), std::nullopt)
+ .first;
+
+ mFlinger.mutableDisplayModeController()
+ .registerDisplay(*physicalId, it->second.snapshot(),
+ mCreationArgs.refreshRateSelector);
+
+ if (mFlinger.scheduler() && mSchedulerRegistration) {
+ mFlinger.scheduler()->registerDisplay(*physicalId,
+ mCreationArgs.refreshRateSelector,
+ std::move(controller),
+ std::move(tracker));
+ }
}
sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs);
mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display);
- DisplayDeviceState state;
- state.isSecure = mCreationArgs.isSecure;
-
- if (mConnectionType) {
- LOG_ALWAYS_FATAL_IF(!displayId);
- const auto physicalIdOpt = PhysicalDisplayId::tryCast(*displayId);
- LOG_ALWAYS_FATAL_IF(!physicalIdOpt);
- const auto physicalId = *physicalIdOpt;
-
- if (mCreationArgs.isPrimary) {
- mFlinger.mutableActiveDisplayId() = physicalId;
- }
-
- LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
-
- const auto activeMode = modes.get(activeModeId);
- LOG_ALWAYS_FATAL_IF(!activeMode);
- const auto fps = activeMode->get()->getPeakFps();
-
- state.physical = {.id = physicalId,
- .hwcDisplayId = *mHwcDisplayId,
- .activeMode = activeMode->get()};
-
- mFlinger.mutablePhysicalDisplays().emplace_or_replace(physicalId, mDisplayToken,
- physicalId, *mConnectionType,
- std::move(modes),
- ui::ColorModes(),
- std::nullopt);
-
- if (mFlinger.scheduler() && mRegisterDisplay) {
- mFlinger.scheduler()->registerDisplay(physicalId,
- display->holdRefreshRateSelector(),
- std::move(controller),
- std::move(tracker));
- }
-
- display->setActiveMode(activeModeId, fps, fps);
+ if (refreshRateOpt) {
+ display->setActiveMode(activeModeId, *refreshRateOpt, *refreshRateOpt);
}
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
@@ -1112,7 +1120,8 @@
sp<BBinder> mDisplayToken = sp<BBinder>::make();
DisplayDeviceCreationArgs mCreationArgs;
DisplayModes mDisplayModes;
- bool mRegisterDisplay = true;
+ DisplayModeId mActiveModeId;
+ bool mSchedulerRegistration = true;
const std::optional<ui::DisplayConnectionType> mConnectionType;
const std::optional<hal::HWDisplayId> mHwcDisplayId;
};