blob: 1b15dbd526cca98931aee971a90be6592a0b262f [file] [log] [blame]
John Reck9ce2bf72018-07-02 18:33:32 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "CanvasTransform.h"
John Reck339cf9b2018-07-18 16:32:27 -070018#include "utils/Color.h"
John Reck9ce2bf72018-07-02 18:33:32 -070019#include "Properties.h"
20
John Reck339cf9b2018-07-18 16:32:27 -070021#include <ui/ColorSpace.h>
John Reck9ce2bf72018-07-02 18:33:32 -070022#include <SkColorFilter.h>
23#include <SkPaint.h>
John Reck339cf9b2018-07-18 16:32:27 -070024
25#include <algorithm>
26#include <cmath>
John Reck9ce2bf72018-07-02 18:33:32 -070027
28namespace android::uirenderer {
29
30static SkColor makeLight(SkColor color) {
John Reck339cf9b2018-07-18 16:32:27 -070031 Lab lab = sRGBToLab(color);
32 float invertedL = std::min(110 - lab.L, 100.0f);
33 if (invertedL > lab.L) {
34 lab.L = invertedL;
35 return LabToSRGB(lab, SkColorGetA(color));
36 } else {
37 return color;
38 }
John Reck9ce2bf72018-07-02 18:33:32 -070039}
40
41static SkColor makeDark(SkColor color) {
John Reck339cf9b2018-07-18 16:32:27 -070042 Lab lab = sRGBToLab(color);
43 float invertedL = std::min(110 - lab.L, 100.0f);
44 if (invertedL < lab.L) {
45 lab.L = invertedL;
46 return LabToSRGB(lab, SkColorGetA(color));
47 } else {
48 return color;
49 }
John Reck9ce2bf72018-07-02 18:33:32 -070050}
51
52static SkColor transformColor(ColorTransform transform, SkColor color) {
53 switch (transform) {
54 case ColorTransform::Light:
55 return makeLight(color);
56 case ColorTransform::Dark:
57 return makeDark(color);
58 default:
59 return color;
60 }
61}
62
63static void applyColorTransform(ColorTransform transform, SkPaint& paint) {
64 if (transform == ColorTransform::None) return;
65
66 SkColor newColor = transformColor(transform, paint.getColor());
67 paint.setColor(newColor);
68
69 if (paint.getColorFilter()) {
70 SkBlendMode mode;
71 SkColor color;
72 // TODO: LRU this or something to avoid spamming new color mode filters
73 if (paint.getColorFilter()->asColorMode(&color, &mode)) {
74 color = transformColor(transform, color);
75 paint.setColorFilter(SkColorFilter::MakeModeFilter(color, mode));
76 }
77 }
78}
79
80class ColorFilterCanvas : public SkPaintFilterCanvas {
81public:
82 ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas)
83 : SkPaintFilterCanvas(canvas), mTransform(transform) {}
84
85 bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override {
86 if (*paint) {
87 applyColorTransform(mTransform, *(paint->writable()));
88 }
89 return true;
90 }
91
92private:
93 ColorTransform mTransform;
94};
95
96std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) {
97 switch (transform) {
98 case ColorTransform::Light:
99 return std::make_unique<ColorFilterCanvas>(ColorTransform::Light, inCanvas);
100 case ColorTransform::Dark:
101 return std::make_unique<ColorFilterCanvas>(ColorTransform::Dark, inCanvas);
102 default:
103 return nullptr;
104 }
105}
106
107std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) {
108 if (Properties::forceDarkMode) {
109 switch (usageHint) {
110 case UsageHint::Unknown:
111 return makeTransformCanvas(inCanvas, ColorTransform::Light);
112 case UsageHint::Background:
113 return makeTransformCanvas(inCanvas, ColorTransform::Dark);
114 }
115 }
116 return nullptr;
117}
118
119}; // namespace android::uirenderer