Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d57794b1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Auto-dark mode prototype"

parents 50621368 9ce2bf7e
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.view;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Matrix;
@@ -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
@@ -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.
     *
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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();
+6 −0
Original line number Diff line number Diff line
@@ -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);
}
@@ -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 },
+1 −0
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ cc_defaults {
        "AnimatorManager.cpp",
        "Caches.cpp",
        "CanvasState.cpp",
        "CanvasTransform.cpp",
        "ClipArea.cpp",
        "DamageAccumulator.cpp",
        "DeferredLayerUpdater.cpp",
+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