Loading core/java/android/view/RenderNode.java +25 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Matrix; Loading @@ -29,6 +30,9 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * <p>A display list records a series of graphics related operations and can replay * them later. Display lists are usually built by recording operations on a Loading Loading @@ -449,6 +453,25 @@ public class RenderNode { return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering); } /** @hide */ @IntDef({USAGE_BACKGROUND}) @Retention(RetentionPolicy.SOURCE) public @interface UsageHint {} /** The default usage hint */ public static final int USAGE_UNKNOWN = 0; /** Usage is background content */ public static final int USAGE_BACKGROUND = 1; /** * Provides a hint on what this RenderNode's display list content contains. This hint is used * for automatic content transforms to improve accessibility or similar. */ public void setUsageHint(@UsageHint int usageHint) { nSetUsageHint(mNativeRenderNode, usageHint); } /** * Indicates whether the content of this display list overlaps. * Loading Loading @@ -948,6 +971,8 @@ public class RenderNode { private static native boolean nSetHasOverlappingRendering(long renderNode, boolean hasOverlappingRendering); @CriticalNative private static native void nSetUsageHint(long renderNode, int usageHint); @CriticalNative private static native boolean nSetElevation(long renderNode, float lift); @CriticalNative private static native boolean nSetTranslationX(long renderNode, float translationX); Loading core/java/android/view/View.java +1 −0 Original line number Diff line number Diff line Loading @@ -20442,6 +20442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { if (renderNode == null) { renderNode = RenderNode.create(drawable.getClass().getName(), this); renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); } final Rect bounds = drawable.getBounds(); core/jni/android_view_RenderNode.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,11 @@ static jboolean android_view_RenderNode_setHasOverlappingRendering(jlong renderN RenderNode::GENERIC); } static void android_view_RenderNode_setUsageHint(jlong renderNodePtr, jint usageHint) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->setUsageHint(static_cast<UsageHint>(usageHint)); } static jboolean android_view_RenderNode_setElevation(jlong renderNodePtr, float elevation) { return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z); } Loading Loading @@ -614,6 +619,7 @@ static const JNINativeMethod gMethods[] = { { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha }, { "nSetHasOverlappingRendering", "(JZ)Z", (void*) android_view_RenderNode_setHasOverlappingRendering }, { "nSetUsageHint", "(JI)V", (void*) android_view_RenderNode_setUsageHint }, { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation }, { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX }, { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY }, Loading libs/hwui/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,7 @@ cc_defaults { "AnimatorManager.cpp", "Caches.cpp", "CanvasState.cpp", "CanvasTransform.cpp", "ClipArea.cpp", "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", Loading libs/hwui/CanvasTransform.cpp 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 "CanvasTransform.h" #include "Properties.h" #include <SkColorFilter.h> #include <SkPaint.h> #include <log/log.h> namespace android::uirenderer { static SkColor makeLight(SkColor color) { SkScalar hsv[3]; SkColorToHSV(color, hsv); if (hsv[1] > .2f) return color; // hsv[1] *= .85f; // hsv[2] = std::min(1.0f, std::max(hsv[2], 1 - hsv[2]) * 1.3f); hsv[2] = std::max(hsv[2], 1.1f - hsv[2]); return SkHSVToColor(SkColorGetA(color), hsv); } static SkColor makeDark(SkColor color) { SkScalar hsv[3]; SkColorToHSV(color, hsv); if (hsv[1] > .2f) return color; // hsv[1] *= .85f; // hsv[2] = std::max(0.0f, std::min(hsv[2], 1 - hsv[2]) * .7f); hsv[2] = std::min(hsv[2], 1.1f - hsv[2]); return SkHSVToColor(SkColorGetA(color), hsv); } static SkColor transformColor(ColorTransform transform, SkColor color) { switch (transform) { case ColorTransform::Light: return makeLight(color); case ColorTransform::Dark: return makeDark(color); default: return color; } } static void applyColorTransform(ColorTransform transform, SkPaint& paint) { if (transform == ColorTransform::None) return; SkColor newColor = transformColor(transform, paint.getColor()); paint.setColor(newColor); if (paint.getColorFilter()) { SkBlendMode mode; SkColor color; // TODO: LRU this or something to avoid spamming new color mode filters if (paint.getColorFilter()->asColorMode(&color, &mode)) { color = transformColor(transform, color); paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); } } } class ColorFilterCanvas : public SkPaintFilterCanvas { public: ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas) : SkPaintFilterCanvas(canvas), mTransform(transform) {} bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override { if (*paint) { applyColorTransform(mTransform, *(paint->writable())); } return true; } private: ColorTransform mTransform; }; std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) { switch (transform) { case ColorTransform::Light: return std::make_unique<ColorFilterCanvas>(ColorTransform::Light, inCanvas); case ColorTransform::Dark: return std::make_unique<ColorFilterCanvas>(ColorTransform::Dark, inCanvas); default: return nullptr; } } std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) { if (Properties::forceDarkMode) { switch (usageHint) { case UsageHint::Unknown: return makeTransformCanvas(inCanvas, ColorTransform::Light); case UsageHint::Background: return makeTransformCanvas(inCanvas, ColorTransform::Dark); } } return nullptr; } }; // namespace android::uirenderer No newline at end of file Loading
core/java/android/view/RenderNode.java +25 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.view; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Matrix; Loading @@ -29,6 +30,9 @@ import dalvik.annotation.optimization.FastNative; import libcore.util.NativeAllocationRegistry; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * <p>A display list records a series of graphics related operations and can replay * them later. Display lists are usually built by recording operations on a Loading Loading @@ -449,6 +453,25 @@ public class RenderNode { return nSetHasOverlappingRendering(mNativeRenderNode, hasOverlappingRendering); } /** @hide */ @IntDef({USAGE_BACKGROUND}) @Retention(RetentionPolicy.SOURCE) public @interface UsageHint {} /** The default usage hint */ public static final int USAGE_UNKNOWN = 0; /** Usage is background content */ public static final int USAGE_BACKGROUND = 1; /** * Provides a hint on what this RenderNode's display list content contains. This hint is used * for automatic content transforms to improve accessibility or similar. */ public void setUsageHint(@UsageHint int usageHint) { nSetUsageHint(mNativeRenderNode, usageHint); } /** * Indicates whether the content of this display list overlaps. * Loading Loading @@ -948,6 +971,8 @@ public class RenderNode { private static native boolean nSetHasOverlappingRendering(long renderNode, boolean hasOverlappingRendering); @CriticalNative private static native void nSetUsageHint(long renderNode, int usageHint); @CriticalNative private static native boolean nSetElevation(long renderNode, float lift); @CriticalNative private static native boolean nSetTranslationX(long renderNode, float translationX); Loading
core/java/android/view/View.java +1 −0 Original line number Diff line number Diff line Loading @@ -20442,6 +20442,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { if (renderNode == null) { renderNode = RenderNode.create(drawable.getClass().getName(), this); renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); } final Rect bounds = drawable.getBounds();
core/jni/android_view_RenderNode.cpp +6 −0 Original line number Diff line number Diff line Loading @@ -222,6 +222,11 @@ static jboolean android_view_RenderNode_setHasOverlappingRendering(jlong renderN RenderNode::GENERIC); } static void android_view_RenderNode_setUsageHint(jlong renderNodePtr, jint usageHint) { RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderNode->setUsageHint(static_cast<UsageHint>(usageHint)); } static jboolean android_view_RenderNode_setElevation(jlong renderNodePtr, float elevation) { return SET_AND_DIRTY(setElevation, elevation, RenderNode::Z); } Loading Loading @@ -614,6 +619,7 @@ static const JNINativeMethod gMethods[] = { { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha }, { "nSetHasOverlappingRendering", "(JZ)Z", (void*) android_view_RenderNode_setHasOverlappingRendering }, { "nSetUsageHint", "(JI)V", (void*) android_view_RenderNode_setUsageHint }, { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation }, { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX }, { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY }, Loading
libs/hwui/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -198,6 +198,7 @@ cc_defaults { "AnimatorManager.cpp", "Caches.cpp", "CanvasState.cpp", "CanvasTransform.cpp", "ClipArea.cpp", "DamageAccumulator.cpp", "DeferredLayerUpdater.cpp", Loading
libs/hwui/CanvasTransform.cpp 0 → 100644 +113 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 "CanvasTransform.h" #include "Properties.h" #include <SkColorFilter.h> #include <SkPaint.h> #include <log/log.h> namespace android::uirenderer { static SkColor makeLight(SkColor color) { SkScalar hsv[3]; SkColorToHSV(color, hsv); if (hsv[1] > .2f) return color; // hsv[1] *= .85f; // hsv[2] = std::min(1.0f, std::max(hsv[2], 1 - hsv[2]) * 1.3f); hsv[2] = std::max(hsv[2], 1.1f - hsv[2]); return SkHSVToColor(SkColorGetA(color), hsv); } static SkColor makeDark(SkColor color) { SkScalar hsv[3]; SkColorToHSV(color, hsv); if (hsv[1] > .2f) return color; // hsv[1] *= .85f; // hsv[2] = std::max(0.0f, std::min(hsv[2], 1 - hsv[2]) * .7f); hsv[2] = std::min(hsv[2], 1.1f - hsv[2]); return SkHSVToColor(SkColorGetA(color), hsv); } static SkColor transformColor(ColorTransform transform, SkColor color) { switch (transform) { case ColorTransform::Light: return makeLight(color); case ColorTransform::Dark: return makeDark(color); default: return color; } } static void applyColorTransform(ColorTransform transform, SkPaint& paint) { if (transform == ColorTransform::None) return; SkColor newColor = transformColor(transform, paint.getColor()); paint.setColor(newColor); if (paint.getColorFilter()) { SkBlendMode mode; SkColor color; // TODO: LRU this or something to avoid spamming new color mode filters if (paint.getColorFilter()->asColorMode(&color, &mode)) { color = transformColor(transform, color); paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode)); } } } class ColorFilterCanvas : public SkPaintFilterCanvas { public: ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas) : SkPaintFilterCanvas(canvas), mTransform(transform) {} bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override { if (*paint) { applyColorTransform(mTransform, *(paint->writable())); } return true; } private: ColorTransform mTransform; }; std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) { switch (transform) { case ColorTransform::Light: return std::make_unique<ColorFilterCanvas>(ColorTransform::Light, inCanvas); case ColorTransform::Dark: return std::make_unique<ColorFilterCanvas>(ColorTransform::Dark, inCanvas); default: return nullptr; } } std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) { if (Properties::forceDarkMode) { switch (usageHint) { case UsageHint::Unknown: return makeTransformCanvas(inCanvas, ColorTransform::Light); case UsageHint::Background: return makeTransformCanvas(inCanvas, ColorTransform::Dark); } } return nullptr; } }; // namespace android::uirenderer No newline at end of file