1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/platform/graphics/dark_mode_color_classifier.h"
6
7 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
8
9 namespace blink {
10 namespace {
11
12 class SimpleColorClassifier : public DarkModeColorClassifier {
13 public:
NeverInvert()14 static std::unique_ptr<SimpleColorClassifier> NeverInvert() {
15 return std::unique_ptr<SimpleColorClassifier>(
16 new SimpleColorClassifier(DarkModeClassification::kDoNotApplyFilter));
17 }
18
AlwaysInvert()19 static std::unique_ptr<SimpleColorClassifier> AlwaysInvert() {
20 return std::unique_ptr<SimpleColorClassifier>(
21 new SimpleColorClassifier(DarkModeClassification::kApplyFilter));
22 }
23
ShouldInvertColor(const Color & color)24 DarkModeClassification ShouldInvertColor(const Color& color) override {
25 return value_;
26 }
27
28 private:
SimpleColorClassifier(DarkModeClassification value)29 SimpleColorClassifier(DarkModeClassification value) : value_(value) {}
30
31 DarkModeClassification value_;
32 };
33
34 class InvertLowBrightnessColorsClassifier : public DarkModeColorClassifier {
35 public:
InvertLowBrightnessColorsClassifier(int brightness_threshold)36 InvertLowBrightnessColorsClassifier(int brightness_threshold)
37 : brightness_threshold_(brightness_threshold) {
38 DCHECK_GT(brightness_threshold_, 0);
39 DCHECK_LT(brightness_threshold_, 256);
40 }
41
ShouldInvertColor(const Color & color)42 DarkModeClassification ShouldInvertColor(const Color& color) override {
43 if (CalculateColorBrightness(color) < brightness_threshold_)
44 return DarkModeClassification::kApplyFilter;
45 return DarkModeClassification::kDoNotApplyFilter;
46 }
47
48 private:
49 int brightness_threshold_;
50 };
51
52 class InvertHighBrightnessColorsClassifier : public DarkModeColorClassifier {
53 public:
InvertHighBrightnessColorsClassifier(int brightness_threshold)54 InvertHighBrightnessColorsClassifier(int brightness_threshold)
55 : brightness_threshold_(brightness_threshold) {
56 DCHECK_GT(brightness_threshold_, 0);
57 DCHECK_LT(brightness_threshold_, 256);
58 }
59
ShouldInvertColor(const Color & color)60 DarkModeClassification ShouldInvertColor(const Color& color) override {
61 if (CalculateColorBrightness(color) > brightness_threshold_)
62 return DarkModeClassification::kApplyFilter;
63 return DarkModeClassification::kDoNotApplyFilter;
64 }
65
66 private:
67 int brightness_threshold_;
68 };
69
70 } // namespace
71
72 // Based on this algorithm suggested by the W3:
73 // https://www.w3.org/TR/AERT/#color-contrast
74 //
75 // We don't use HSL or HSV here because perceived brightness is a function of
76 // hue as well as lightness/value.
CalculateColorBrightness(const Color & color)77 int DarkModeColorClassifier::CalculateColorBrightness(const Color& color) {
78 int weighted_red = color.Red() * 299;
79 int weighted_green = color.Green() * 587;
80 int weighted_blue = color.Blue() * 114;
81 return (weighted_red + weighted_green + weighted_blue) / 1000;
82 }
83
84 std::unique_ptr<DarkModeColorClassifier>
MakeTextColorClassifier(const DarkModeSettings & settings)85 DarkModeColorClassifier::MakeTextColorClassifier(
86 const DarkModeSettings& settings) {
87 DCHECK_LE(settings.text_brightness_threshold, 256);
88 DCHECK_GE(settings.text_brightness_threshold, 0);
89
90 // The value should be between 0 and 256, but check for values outside that
91 // range here to preserve correct behavior in non-debug builds.
92 if (settings.text_brightness_threshold >= 256)
93 return SimpleColorClassifier::AlwaysInvert();
94 if (settings.text_brightness_threshold <= 0)
95 return SimpleColorClassifier::NeverInvert();
96
97 return std::make_unique<InvertLowBrightnessColorsClassifier>(
98 settings.text_brightness_threshold);
99 }
100
101 std::unique_ptr<DarkModeColorClassifier>
MakeBackgroundColorClassifier(const DarkModeSettings & settings)102 DarkModeColorClassifier::MakeBackgroundColorClassifier(
103 const DarkModeSettings& settings) {
104 DCHECK_LE(settings.background_brightness_threshold, 256);
105 DCHECK_GE(settings.background_brightness_threshold, 0);
106
107 // The value should be between 0 and 256, but check for values outside that
108 // range here to preserve correct behavior in non-debug builds.
109 if (settings.background_brightness_threshold >= 256)
110 return SimpleColorClassifier::NeverInvert();
111 if (settings.background_brightness_threshold <= 0)
112 return SimpleColorClassifier::AlwaysInvert();
113
114 return std::make_unique<InvertHighBrightnessColorsClassifier>(
115 settings.background_brightness_threshold);
116 }
117
~DarkModeColorClassifier()118 DarkModeColorClassifier::~DarkModeColorClassifier() {}
119
120 } // namespace blink
121