blob: 9340f503921660dcd8574b91b64dec20220652e0 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/dark_mode_color_filter.h"
#include "base/check.h"
#include "base/notreached.h"
#include "third_party/blink/renderer/platform/graphics/dark_mode_lab_color_space.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/effects/SkHighContrastFilter.h"
#include "third_party/skia/include/effects/SkTableColorFilter.h"
namespace blink {
namespace {
// SkColorFilterWrapper implementation.
class SkColorFilterWrapper : public DarkModeColorFilter {
public:
static std::unique_ptr<SkColorFilterWrapper> Create(
sk_sp<SkColorFilter> color_filter) {
return std::unique_ptr<SkColorFilterWrapper>(
new SkColorFilterWrapper(color_filter));
}
static std::unique_ptr<SkColorFilterWrapper> Create(
SkHighContrastConfig::InvertStyle invert_style,
const DarkModeSettings& settings) {
SkHighContrastConfig config;
config.fInvertStyle = invert_style;
config.fGrayscale = settings.grayscale;
config.fContrast = settings.contrast;
return std::unique_ptr<SkColorFilterWrapper>(
new SkColorFilterWrapper(SkHighContrastFilter::Make(config)));
}
SkColor InvertColor(SkColor color) const override {
return filter_->filterColor(color);
}
sk_sp<SkColorFilter> ToSkColorFilter() const override { return filter_; }
private:
explicit SkColorFilterWrapper(sk_sp<SkColorFilter> filter)
: filter_(filter) {}
sk_sp<SkColorFilter> filter_;
};
// LABColorFilter implementation.
class LABColorFilter : public DarkModeColorFilter {
public:
LABColorFilter() : transformer_(lab::DarkModeSRGBLABTransformer()) {
SkHighContrastConfig config;
config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness;
config.fGrayscale = false;
config.fContrast = 0.0;
filter_ = SkHighContrastFilter::Make(config);
}
SkColor InvertColor(SkColor color) const override {
SkV3 rgb = {SkColorGetR(color) / 255.0f, SkColorGetG(color) / 255.0f,
SkColorGetB(color) / 255.0f};
SkV3 lab = transformer_.SRGBToLAB(rgb);
lab.x = std::min(110.0f - lab.x, 100.0f);
rgb = transformer_.LABToSRGB(lab);
SkColor inverted_color = SkColorSetARGB(
SkColorGetA(color), static_cast<unsigned int>(rgb.x * 255 + 0.5),
static_cast<unsigned int>(rgb.y * 255 + 0.5),
static_cast<unsigned int>(rgb.z * 255 + 0.5));
return AdjustGray(inverted_color);
}
sk_sp<SkColorFilter> ToSkColorFilter() const override { return filter_; }
private:
// Further darken dark grays to match the primary surface color recommended by
// the material design guidelines:
// https://material.io/design/color/dark-theme.html#properties
//
// TODO(gilmanmh): Consider adding a more general way to adjust colors after
// applying the main filter.
SkColor AdjustGray(SkColor color) const {
static const uint8_t kBrightnessThreshold = 32;
static const uint8_t kAdjustedBrightness = 18;
uint8_t r = SkColorGetR(color);
uint8_t g = SkColorGetG(color);
uint8_t b = SkColorGetB(color);
if (r == b && r == g && r < kBrightnessThreshold &&
r > kAdjustedBrightness) {
return SkColorSetRGB(kAdjustedBrightness, kAdjustedBrightness,
kAdjustedBrightness);
}
return color;
}
const lab::DarkModeSRGBLABTransformer transformer_;
sk_sp<SkColorFilter> filter_;
};
} // namespace
std::unique_ptr<DarkModeColorFilter> DarkModeColorFilter::FromSettings(
const DarkModeSettings& settings) {
switch (settings.mode) {
case DarkModeInversionAlgorithm::kSimpleInvertForTesting:
uint8_t identity[256], invert[256];
for (int i = 0; i < 256; ++i) {
identity[i] = i;
invert[i] = 255 - i;
}
return SkColorFilterWrapper::Create(
SkTableColorFilter::MakeARGB(identity, invert, invert, invert));
case DarkModeInversionAlgorithm::kInvertBrightness:
return SkColorFilterWrapper::Create(
SkHighContrastConfig::InvertStyle::kInvertBrightness, settings);
case DarkModeInversionAlgorithm::kInvertLightness:
return SkColorFilterWrapper::Create(
SkHighContrastConfig::InvertStyle::kInvertLightness, settings);
case DarkModeInversionAlgorithm::kInvertLightnessLAB:
return std::make_unique<LABColorFilter>();
}
NOTREACHED();
}
DarkModeColorFilter::~DarkModeColorFilter() {}
} // namespace blink