diff options
author | 2023-05-02 15:18:00 -0700 | |
---|---|---|
committer | 2023-05-03 15:10:05 -0700 | |
commit | f0ea9e19acef673dab3d03a66b7d87ed16326506 (patch) | |
tree | b24845897b310d4b5f47ae13de9122a79d38264d | |
parent | de6f249944479beba30e79639626f98cc5189a59 (diff) |
Update ColorFilter API to be backed by mutable native objects
Move the native ColorFilter implementation off of Skia's
SkColorFilter and instead have a mutable intermediate object
that can be inspected.
Bug: 264559422
Test: re-ran CtsUiRenderingTestCases
Change-Id: I9ec056084f00e72632c86bdf88376b1307e8ef74
-rw-r--r-- | graphics/java/android/graphics/ColorFilter.java | 13 | ||||
-rw-r--r-- | graphics/java/android/graphics/ColorMatrixColorFilter.java | 6 | ||||
-rw-r--r-- | graphics/java/android/graphics/LightingColorFilter.java | 8 | ||||
-rw-r--r-- | libs/hwui/ColorFilter.h | 94 | ||||
-rw-r--r-- | libs/hwui/SkiaWrapper.h | 56 | ||||
-rw-r--r-- | libs/hwui/jni/AnimatedImageDrawable.cpp | 16 | ||||
-rw-r--r-- | libs/hwui/jni/ColorFilter.cpp | 75 | ||||
-rw-r--r-- | libs/hwui/jni/Paint.cpp | 49 | ||||
-rw-r--r-- | libs/hwui/jni/RenderEffect.cpp | 12 | ||||
-rw-r--r-- | libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp | 11 |
10 files changed, 263 insertions, 77 deletions
diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java index 8fd6f7f609c6..7050325997b6 100644 --- a/graphics/java/android/graphics/ColorFilter.java +++ b/graphics/java/android/graphics/ColorFilter.java @@ -41,21 +41,11 @@ public class ColorFilter { * Current native SkColorFilter instance. */ private long mNativeInstance; - // Runnable to do immediate destruction - private Runnable mCleaner; long createNativeInstance() { return 0; } - synchronized final void discardNativeInstance() { - if (mNativeInstance != 0) { - mCleaner.run(); - mCleaner = null; - mNativeInstance = 0; - } - } - /** @hide */ public synchronized final long getNativeInstance() { if (mNativeInstance == 0) { @@ -65,8 +55,7 @@ public class ColorFilter { // Note: we must check for null here, since it's possible for createNativeInstance() // to return nullptr if the native SkColorFilter would be a no-op at draw time. // See native implementations of subclass create methods for more info. - mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation( - this, mNativeInstance); + NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeInstance); } } return mNativeInstance; diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java index 90ff1899f34d..bfdf3187c575 100644 --- a/graphics/java/android/graphics/ColorMatrixColorFilter.java +++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java @@ -81,12 +81,12 @@ public class ColorMatrixColorFilter extends ColorFilter { */ @UnsupportedAppUsage public void setColorMatrix(@Nullable ColorMatrix matrix) { - discardNativeInstance(); if (matrix == null) { mMatrix.reset(); } else { mMatrix.set(matrix); } + nativeSetColorMatrix(getNativeInstance(), mMatrix.getArray()); } /** @@ -111,7 +111,6 @@ public class ColorMatrixColorFilter extends ColorFilter { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setColorMatrixArray(@Nullable float[] array) { // called '...Array' so that passing null isn't ambiguous - discardNativeInstance(); if (array == null) { mMatrix.reset(); } else { @@ -120,6 +119,7 @@ public class ColorMatrixColorFilter extends ColorFilter { } mMatrix.set(array); } + nativeSetColorMatrix(getNativeInstance(), mMatrix.getArray()); } @Override @@ -128,4 +128,6 @@ public class ColorMatrixColorFilter extends ColorFilter { } private static native long nativeColorMatrixFilter(float[] array); + + private static native void nativeSetColorMatrix(long colorMatrixColorFilter, float[] array); } diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java index df91c5d492bd..0aa6f1282c1a 100644 --- a/graphics/java/android/graphics/LightingColorFilter.java +++ b/graphics/java/android/graphics/LightingColorFilter.java @@ -78,7 +78,7 @@ public class LightingColorFilter extends ColorFilter { public void setColorMultiply(@ColorInt int mul) { if (mMul != mul) { mMul = mul; - discardNativeInstance(); + native_SetLightingFilterMul(getNativeInstance(), mul); } } @@ -104,7 +104,7 @@ public class LightingColorFilter extends ColorFilter { public void setColorAdd(@ColorInt int add) { if (mAdd != add) { mAdd = add; - discardNativeInstance(); + native_SetLightingFilterAdd(getNativeInstance(), add); } } @@ -114,4 +114,8 @@ public class LightingColorFilter extends ColorFilter { } private static native long native_CreateLightingFilter(int mul, int add); + + private static native void native_SetLightingFilterAdd(long lightingFilter, int add); + + private static native void native_SetLightingFilterMul(long lightingFilter, int mul); } diff --git a/libs/hwui/ColorFilter.h b/libs/hwui/ColorFilter.h new file mode 100644 index 000000000000..1a5b938d6eed --- /dev/null +++ b/libs/hwui/ColorFilter.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +#ifndef COLORFILTER_H_ +#define COLORFILTER_H_ + +#include <stdint.h> + +#include <memory> + +#include "GraphicsJNI.h" +#include "SkColorFilter.h" +#include "SkiaWrapper.h" + +namespace android { +namespace uirenderer { + +class ColorFilter : public SkiaWrapper<SkColorFilter> { +public: + static ColorFilter* fromJava(jlong handle) { return reinterpret_cast<ColorFilter*>(handle); } + +protected: + ColorFilter() = default; +}; + +class BlendModeColorFilter : public ColorFilter { +public: + BlendModeColorFilter(SkColor color, SkBlendMode mode) : mColor(color), mMode(mode) {} + +private: + sk_sp<SkColorFilter> createInstance() override { return SkColorFilters::Blend(mColor, mMode); } + +private: + const SkColor mColor; + const SkBlendMode mMode; +}; + +class LightingFilter : public ColorFilter { +public: + LightingFilter(SkColor mul, SkColor add) : mMul(mul), mAdd(add) {} + + void setMul(SkColor mul) { + mMul = mul; + discardInstance(); + } + + void setAdd(SkColor add) { + mAdd = add; + discardInstance(); + } + +private: + sk_sp<SkColorFilter> createInstance() override { return SkColorFilters::Lighting(mMul, mAdd); } + +private: + SkColor mMul; + SkColor mAdd; +}; + +class ColorMatrixColorFilter : public ColorFilter { +public: + ColorMatrixColorFilter(std::vector<float>&& matrix) : mMatrix(std::move(matrix)) {} + + void setMatrix(std::vector<float>&& matrix) { + mMatrix = std::move(matrix); + discardInstance(); + } + +private: + sk_sp<SkColorFilter> createInstance() override { + return SkColorFilters::Matrix(mMatrix.data()); + } + +private: + std::vector<float> mMatrix; +}; + +} // namespace uirenderer +} // namespace android + +#endif // COLORFILTER_H_ diff --git a/libs/hwui/SkiaWrapper.h b/libs/hwui/SkiaWrapper.h new file mode 100644 index 000000000000..bd0e35aadbb4 --- /dev/null +++ b/libs/hwui/SkiaWrapper.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#ifndef SKIA_WRAPPER_H_ +#define SKIA_WRAPPER_H_ + +#include <SkRefCnt.h> +#include <utils/RefBase.h> + +namespace android::uirenderer { + +template <typename T> +class SkiaWrapper : public VirtualLightRefBase { +public: + sk_sp<T> getInstance() { + if (mInstance != nullptr && shouldDiscardInstance()) { + mInstance = nullptr; + } + + if (mInstance == nullptr) { + mInstance = createInstance(); + mGenerationId++; + } + return mInstance; + } + + virtual bool shouldDiscardInstance() const { return false; } + + void discardInstance() { mInstance = nullptr; } + + [[nodiscard]] int32_t getGenerationId() const { return mGenerationId; } + +protected: + virtual sk_sp<T> createInstance() = 0; + +private: + sk_sp<T> mInstance = nullptr; + int32_t mGenerationId = 0; +}; + +} // namespace android::uirenderer + +#endif // SKIA_WRAPPER_H_ diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp index a7f5aa83e624..90b1da846205 100644 --- a/libs/hwui/jni/AnimatedImageDrawable.cpp +++ b/libs/hwui/jni/AnimatedImageDrawable.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -#include "GraphicsJNI.h" -#include "ImageDecoder.h" -#include "Utils.h" - #include <SkAndroidCodec.h> #include <SkAnimatedImage.h> #include <SkColorFilter.h> @@ -27,10 +23,15 @@ #include <SkRect.h> #include <SkRefCnt.h> #include <hwui/AnimatedImageDrawable.h> -#include <hwui/ImageDecoder.h> #include <hwui/Canvas.h> +#include <hwui/ImageDecoder.h> #include <utils/Looper.h> +#include "ColorFilter.h" +#include "GraphicsJNI.h" +#include "ImageDecoder.h" +#include "Utils.h" + using namespace android; static jclass gAnimatedImageDrawableClass; @@ -145,8 +146,9 @@ static jlong AnimatedImageDrawable_nGetAlpha(JNIEnv* env, jobject /*clazz*/, jlo static void AnimatedImageDrawable_nSetColorFilter(JNIEnv* env, jobject /*clazz*/, jlong nativePtr, jlong nativeFilter) { auto* drawable = reinterpret_cast<AnimatedImageDrawable*>(nativePtr); - auto* filter = reinterpret_cast<SkColorFilter*>(nativeFilter); - drawable->setStagingColorFilter(sk_ref_sp(filter)); + auto filter = uirenderer::ColorFilter::fromJava(nativeFilter); + auto skColorFilter = filter != nullptr ? filter->getInstance() : sk_sp<SkColorFilter>(); + drawable->setStagingColorFilter(skColorFilter); } static jboolean AnimatedImageDrawable_nIsRunning(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) { diff --git a/libs/hwui/jni/ColorFilter.cpp b/libs/hwui/jni/ColorFilter.cpp index 4bd7ef47b871..0b95148d3c82 100644 --- a/libs/hwui/jni/ColorFilter.cpp +++ b/libs/hwui/jni/ColorFilter.cpp @@ -15,20 +15,21 @@ ** limitations under the License. */ -#include "GraphicsJNI.h" +#include "ColorFilter.h" +#include "GraphicsJNI.h" #include "SkBlendMode.h" -#include "SkColorFilter.h" -#include "SkColorMatrixFilter.h" namespace android { using namespace uirenderer; -class SkColorFilterGlue { +class ColorFilterGlue { public: - static void SafeUnref(SkColorFilter* filter) { - SkSafeUnref(filter); + static void SafeUnref(ColorFilter* filter) { + if (filter) { + filter->decStrong(nullptr); + } } static jlong GetNativeFinalizer(JNIEnv*, jobject) { @@ -36,41 +37,75 @@ public: } static jlong CreateBlendModeFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) { - SkBlendMode mode = static_cast<SkBlendMode>(modeHandle); - return reinterpret_cast<jlong>(SkColorFilters::Blend(srcColor, mode).release()); + auto mode = static_cast<SkBlendMode>(modeHandle); + auto* blendModeFilter = new BlendModeColorFilter(srcColor, mode); + blendModeFilter->incStrong(nullptr); + return static_cast<jlong>(reinterpret_cast<uintptr_t>(blendModeFilter)); } static jlong CreateLightingFilter(JNIEnv* env, jobject, jint mul, jint add) { - return reinterpret_cast<jlong>(SkColorMatrixFilter::MakeLightingFilter(mul, add).release()); + auto* lightingFilter = new LightingFilter(mul, add); + lightingFilter->incStrong(nullptr); + return static_cast<jlong>(reinterpret_cast<uintptr_t>(lightingFilter)); } - static jlong CreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) { - float matrix[20]; - env->GetFloatArrayRegion(jarray, 0, 20, matrix); + static void SetLightingFilterMul(JNIEnv* env, jobject, jlong lightingFilterPtr, jint mul) { + auto* filter = reinterpret_cast<LightingFilter*>(lightingFilterPtr); + if (filter) { + filter->setMul(mul); + } + } + + static void SetLightingFilterAdd(JNIEnv* env, jobject, jlong lightingFilterPtr, jint add) { + auto* filter = reinterpret_cast<LightingFilter*>(lightingFilterPtr); + if (filter) { + filter->setAdd(add); + } + } + + static std::vector<float> getMatrixFromJFloatArray(JNIEnv* env, jfloatArray jarray) { + std::vector<float> matrix(20); + // float matrix[20]; + env->GetFloatArrayRegion(jarray, 0, 20, matrix.data()); // java biases the translates by 255, so undo that before calling skia matrix[ 4] *= (1.0f/255); matrix[ 9] *= (1.0f/255); matrix[14] *= (1.0f/255); matrix[19] *= (1.0f/255); - return reinterpret_cast<jlong>(SkColorFilters::Matrix(matrix).release()); + return matrix; + } + + static jlong CreateColorMatrixFilter(JNIEnv* env, jobject, jfloatArray jarray) { + std::vector<float> matrix = getMatrixFromJFloatArray(env, jarray); + auto* colorMatrixColorFilter = new ColorMatrixColorFilter(std::move(matrix)); + colorMatrixColorFilter->incStrong(nullptr); + return static_cast<jlong>(reinterpret_cast<uintptr_t>(colorMatrixColorFilter)); + } + + static void SetColorMatrix(JNIEnv* env, jobject, jlong colorMatrixColorFilterPtr, + jfloatArray jarray) { + auto* filter = reinterpret_cast<ColorMatrixColorFilter*>(colorMatrixColorFilterPtr); + if (filter) { + filter->setMatrix(getMatrixFromJFloatArray(env, jarray)); + } } }; static const JNINativeMethod colorfilter_methods[] = { - {"nativeGetFinalizer", "()J", (void*) SkColorFilterGlue::GetNativeFinalizer } -}; + {"nativeGetFinalizer", "()J", (void*)ColorFilterGlue::GetNativeFinalizer}}; static const JNINativeMethod blendmode_methods[] = { - { "native_CreateBlendModeFilter", "(II)J", (void*) SkColorFilterGlue::CreateBlendModeFilter }, + {"native_CreateBlendModeFilter", "(II)J", (void*)ColorFilterGlue::CreateBlendModeFilter}, }; static const JNINativeMethod lighting_methods[] = { - { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter }, -}; + {"native_CreateLightingFilter", "(II)J", (void*)ColorFilterGlue::CreateLightingFilter}, + {"native_SetLightingFilterAdd", "(JI)V", (void*)ColorFilterGlue::SetLightingFilterAdd}, + {"native_SetLightingFilterMul", "(JI)V", (void*)ColorFilterGlue::SetLightingFilterMul}}; static const JNINativeMethod colormatrix_methods[] = { - { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter }, -}; + {"nativeColorMatrixFilter", "([F)J", (void*)ColorFilterGlue::CreateColorMatrixFilter}, + {"nativeSetColorMatrix", "(J[F)V", (void*)ColorFilterGlue::SetColorMatrix}}; int register_android_graphics_ColorFilter(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods, diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp index 13357fa25e8c..ace896d573e1 100644 --- a/libs/hwui/jni/Paint.cpp +++ b/libs/hwui/jni/Paint.cpp @@ -18,27 +18,6 @@ #undef LOG_TAG #define LOG_TAG "Paint" -#include <utils/Log.h> - -#include "GraphicsJNI.h" -#include <nativehelper/ScopedStringChars.h> -#include <nativehelper/ScopedUtfChars.h> -#include <nativehelper/ScopedPrimitiveArray.h> - -#include "SkColorFilter.h" -#include "SkColorSpace.h" -#include "SkFont.h" -#include "SkFontMetrics.h" -#include "SkFontTypes.h" -#include "SkMaskFilter.h" -#include "SkPath.h" -#include "SkPathEffect.h" -#include "SkPathUtils.h" -#include "SkShader.h" -#include "SkBlendMode.h" -#include "unicode/uloc.h" -#include "utils/Blur.h" - #include <hwui/BlurDrawLooper.h> #include <hwui/MinikinSkia.h> #include <hwui/MinikinUtils.h> @@ -48,13 +27,33 @@ #include <minikin/LocaleList.h> #include <minikin/Measurement.h> #include <minikin/MinikinPaint.h> +#include <nativehelper/ScopedPrimitiveArray.h> +#include <nativehelper/ScopedStringChars.h> +#include <nativehelper/ScopedUtfChars.h> #include <unicode/utf16.h> +#include <utils/Log.h> #include <cassert> #include <cstring> #include <memory> #include <vector> +#include "ColorFilter.h" +#include "GraphicsJNI.h" +#include "SkBlendMode.h" +#include "SkColorFilter.h" +#include "SkColorSpace.h" +#include "SkFont.h" +#include "SkFontMetrics.h" +#include "SkFontTypes.h" +#include "SkMaskFilter.h" +#include "SkPath.h" +#include "SkPathEffect.h" +#include "SkPathUtils.h" +#include "SkShader.h" +#include "unicode/uloc.h" +#include "utils/Blur.h" + namespace android { static void getPosTextPath(const SkFont& font, const uint16_t glyphs[], int count, @@ -821,9 +820,11 @@ namespace PaintGlue { static jlong setColorFilter(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong filterHandle) { Paint* obj = reinterpret_cast<Paint *>(objHandle); - SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(filterHandle); - obj->setColorFilter(sk_ref_sp(filter)); - return reinterpret_cast<jlong>(obj->getColorFilter()); + auto colorFilter = uirenderer::ColorFilter::fromJava(filterHandle); + auto skColorFilter = + colorFilter != nullptr ? colorFilter->getInstance() : sk_sp<SkColorFilter>(); + obj->setColorFilter(skColorFilter); + return filterHandle; } static void setXfermode(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle, jint xfermodeHandle) { diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp index f3db1705e694..dcd3fa4932fc 100644 --- a/libs/hwui/jni/RenderEffect.cpp +++ b/libs/hwui/jni/RenderEffect.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ #include "Bitmap.h" +#include "ColorFilter.h" #include "GraphicsJNI.h" #include "SkBlendMode.h" #include "SkImageFilter.h" #include "SkImageFilters.h" #include "graphics_jni_helpers.h" #include "utils/Blur.h" -#include <utils/Log.h> using namespace android::uirenderer; @@ -76,11 +76,13 @@ static jlong createColorFilterEffect( jlong colorFilterHandle, jlong inputFilterHandle ) { - auto* colorFilter = reinterpret_cast<const SkColorFilter*>(colorFilterHandle); + auto colorFilter = android::uirenderer::ColorFilter::fromJava(colorFilterHandle); + auto skColorFilter = + colorFilter != nullptr ? colorFilter->getInstance() : sk_sp<SkColorFilter>(); auto* inputFilter = reinterpret_cast<const SkImageFilter*>(inputFilterHandle); - sk_sp<SkImageFilter> colorFilterImageFilter = SkImageFilters::ColorFilter( - sk_ref_sp(colorFilter), sk_ref_sp(inputFilter), nullptr); - return reinterpret_cast<jlong>(colorFilterImageFilter.release()); + sk_sp<SkImageFilter> colorFilterImageFilter = + SkImageFilters::ColorFilter(skColorFilter, sk_ref_sp(inputFilter), nullptr); + return reinterpret_cast<jlong>(colorFilterImageFilter.release()); } static jlong createBlendModeEffect( diff --git a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp index 9cffceb308c8..ade48f26937f 100644 --- a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp +++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp @@ -14,13 +14,13 @@ * limitations under the License. */ -#include "GraphicsJNI.h" +#include <hwui/Paint.h> +#include "ColorFilter.h" +#include "GraphicsJNI.h" #include "PathParser.h" #include "VectorDrawable.h" -#include <hwui/Paint.h> - namespace android { using namespace uirenderer; using namespace uirenderer::VectorDrawable; @@ -108,8 +108,9 @@ static jint draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr, Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); SkRect rect; GraphicsJNI::jrect_to_rect(env, jrect, &rect); - SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr); - return tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache); + auto colorFilter = ColorFilter::fromJava(colorFilterPtr); + auto skColorFilter = colorFilter != nullptr ? colorFilter->getInstance() : nullptr; + return tree->draw(canvas, skColorFilter.get(), rect, needsMirroring, canReuseCache); } /** |