blob: 0864052a9cf185e6cacd345f2578bd1ba1dae958 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/color/color_transform.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_provider_utils.h"
namespace ui {
ColorTransform::ColorTransform(Callback callback)
: callback_(std::move(callback)) {}
ColorTransform::ColorTransform(SkColor color) {
const auto generator = [](SkColor color, SkColor input_color,
const ColorMixer& mixer) {
DVLOG(2) << "ColorTransform From Color:"
<< " Input Color:" << SkColorName(input_color)
<< " Color: " << SkColorName(color)
<< " Result Color: " << SkColorName(color);
return color;
};
callback_ = base::BindRepeating(generator, color);
}
ColorTransform::ColorTransform(ColorId id) {
const auto generator = [](ColorId id, SkColor input_color,
const ColorMixer& mixer) {
SkColor result_color = mixer.GetResultColor(id);
DVLOG(2) << "ColorTransform FromMixer:"
<< " Input Color:" << SkColorName(input_color)
<< " Color Id: " << ColorIdName(id)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
callback_ = base::BindRepeating(generator, id);
}
ColorTransform::ColorTransform(const ColorTransform&) = default;
ColorTransform& ColorTransform::operator=(const ColorTransform&) = default;
ColorTransform::~ColorTransform() = default;
SkColor ColorTransform::Run(SkColor input_color,
const ColorMixer& mixer) const {
return callback_.Run(input_color, mixer);
}
ColorTransform AlphaBlend(ColorTransform foreground_transform,
ColorTransform background_transform,
SkAlpha alpha) {
const auto generator = [](ColorTransform foreground_transform,
ColorTransform background_transform, SkAlpha alpha,
SkColor input_color, const ColorMixer& mixer) {
const SkColor foreground_color =
foreground_transform.Run(input_color, mixer);
const SkColor background_color =
background_transform.Run(input_color, mixer);
const SkColor result_color =
color_utils::AlphaBlend(foreground_color, background_color, alpha);
DVLOG(2) << "ColorTransform AlphaBlend:"
<< " Input Color: " << SkColorName(input_color)
<< " FG Transform: " << SkColorName(foreground_color)
<< " BG Transform: " << SkColorName(background_color)
<< " Alpha: " << base::NumberToString(alpha)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(foreground_transform),
std::move(background_transform), alpha);
}
ColorTransform BlendForMinContrast(
ColorTransform foreground_transform,
ColorTransform background_transform,
std::optional<ColorTransform> high_contrast_foreground_transform,
float contrast_ratio) {
const auto generator =
[](ColorTransform foreground_transform,
ColorTransform background_transform,
std::optional<ColorTransform> high_contrast_foreground_transform,
float contrast_ratio, SkColor input_color, const ColorMixer& mixer) {
const SkColor foreground_color =
foreground_transform.Run(input_color, mixer);
const SkColor background_color =
background_transform.Run(input_color, mixer);
const std::optional<SkColor> high_contrast_foreground =
high_contrast_foreground_transform.has_value()
? std::make_optional(
high_contrast_foreground_transform.value().Run(
input_color, mixer))
: std::nullopt;
const SkColor result_color =
color_utils::BlendForMinContrast(foreground_color, background_color,
high_contrast_foreground,
contrast_ratio)
.color;
DVLOG(2) << "ColorTransform BlendForMinContrast:"
<< " FG Transform Color: " << SkColorName(foreground_color)
<< " BG Transform Color: " << SkColorName(background_color)
<< " High Contrast Foreground: "
<< (high_contrast_foreground.has_value()
? SkColorName(high_contrast_foreground.value())
: "<none>")
<< " Contrast Ratio: " << base::NumberToString(contrast_ratio)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(foreground_transform),
std::move(background_transform),
std::move(high_contrast_foreground_transform),
contrast_ratio);
}
ColorTransform BlendForMinContrastWithSelf(ColorTransform transform,
float contrast_ratio) {
return BlendForMinContrast(transform, transform, std::nullopt,
contrast_ratio);
}
ColorTransform BlendTowardMaxContrast(ColorTransform transform, SkAlpha alpha) {
const auto generator = [](ColorTransform transform, SkAlpha alpha,
SkColor input_color, const ColorMixer& mixer) {
const SkColor transform_color = transform.Run(input_color, mixer);
const SkColor result_color =
color_utils::BlendTowardMaxContrast(transform_color, alpha);
DVLOG(2) << "ColorTransform BlendTowardMaxContrast:"
<< " Input Color:" << SkColorName(input_color)
<< " Transform Color: " << SkColorName(transform_color)
<< " Alpha: " << base::NumberToString(alpha)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(transform), alpha);
}
ColorTransform ContrastInvert(ColorTransform transform) {
const auto generator = [](ColorTransform transform, SkColor input_color,
const ColorMixer& mixer) {
const SkColor foreground = transform.Run(input_color, mixer);
const SkColor far_endpoint =
color_utils::GetColorWithMaxContrast(foreground);
const SkColor near_endpoint =
color_utils::GetEndpointColorWithMinContrast(foreground);
const float contrast_ratio =
color_utils::GetContrastRatio(foreground, far_endpoint);
const SkColor result_color =
color_utils::BlendForMinContrast(foreground, near_endpoint,
std::nullopt, contrast_ratio)
.color;
DVLOG(2) << "ColorTransform ContrastInvert:"
<< " Input Color: " << SkColorName(input_color)
<< " Foreground: " << SkColorName(foreground)
<< " Far End: " << SkColorName(far_endpoint)
<< " Near End: " << SkColorName(near_endpoint)
<< " Contrast Ratio: " << base::NumberToString(contrast_ratio)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(transform));
}
ColorTransform DeriveDefaultIconColor(ColorTransform transform) {
const auto generator = [](ColorTransform transform, SkColor input_color,
const ColorMixer& mixer) {
const SkColor transform_color = transform.Run(input_color, mixer);
const SkColor result_color =
color_utils::DeriveDefaultIconColor(transform_color);
DVLOG(2) << "ColorTransform DeriveDefaultIconColor:"
<< " Input Color: " << SkColorName(input_color)
<< " Transform Color: " << SkColorName(transform_color)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(transform));
}
ColorTransform FromTransformInput() {
const auto generator = [](SkColor input_color, const ColorMixer& mixer) {
DVLOG(2) << "ColorTransform FromTransformInput: "
<< " Input/Result Color: " << SkColorName(input_color);
return input_color;
};
return base::BindRepeating(generator);
}
ColorTransform GetColorWithMaxContrast(ColorTransform transform) {
const auto generator = [](ColorTransform transform, SkColor input_color,
const ColorMixer& mixer) {
const SkColor transform_color = transform.Run(input_color, mixer);
const SkColor result_color =
color_utils::GetColorWithMaxContrast(transform_color);
DVLOG(2) << "ColorTransform GetColorWithMaxContrast:"
<< " Input Color: " << SkColorName(input_color)
<< " Transform Color: " << SkColorName(transform_color)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(transform));
}
ColorTransform GetEndpointColorWithMinContrast(ColorTransform transform) {
const auto generator = [](ColorTransform transform, SkColor input_color,
const ColorMixer& mixer) {
const SkColor transform_color = transform.Run(input_color, mixer);
const SkColor result_color =
color_utils::GetEndpointColorWithMinContrast(transform_color);
DVLOG(2) << "ColorTransform GetEndPointColorWithMinContrast:"
<< " Input Color: " << SkColorName(input_color)
<< " Transform Color: " << SkColorName(transform_color)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(transform));
}
ColorTransform GetResultingPaintColor(ColorTransform foreground_transform,
ColorTransform background_transform) {
const auto generator = [](ColorTransform foreground_transform,
ColorTransform background_transform,
SkColor input_color, const ColorMixer& mixer) {
const SkColor foreground_color =
foreground_transform.Run(input_color, mixer);
const SkColor background_color =
background_transform.Run(input_color, mixer);
const SkColor result_color =
color_utils::GetResultingPaintColor(foreground_color, background_color);
DVLOG(2) << "ColorTransform GetResultingPaintColor:"
<< " Input Color: " << SkColorName(input_color)
<< " FG Transform Color: " << SkColorName(foreground_color)
<< " BG Transform Color: " << SkColorName(background_color)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(foreground_transform),
std::move(background_transform));
}
ColorTransform SelectBasedOnDarkInput(
ColorTransform input_transform,
ColorTransform output_transform_for_dark_input,
ColorTransform output_transform_for_light_input) {
const auto generator = [](ColorTransform input_transform,
ColorTransform output_transform_for_dark_input,
ColorTransform output_transform_for_light_input,
SkColor input_color, const ColorMixer& mixer) {
const SkColor color = input_transform.Run(input_color, mixer);
const auto& output_transform = color_utils::IsDark(color)
? output_transform_for_dark_input
: output_transform_for_light_input;
const SkColor result_color = output_transform.Run(input_color, mixer);
DVLOG(2) << "ColorTransform SelectBasedOnDarkInput:"
<< " Input Color: " << SkColorName(input_color)
<< " Input Transform: " << SkColorName(color)
<< " IsDark: " << (color_utils::IsDark(color) ? "true" : "false")
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(input_transform),
std::move(output_transform_for_dark_input),
std::move(output_transform_for_light_input));
}
ColorTransform SetAlpha(ColorTransform transform, SkAlpha alpha) {
const auto generator = [](ColorTransform transform, SkAlpha alpha,
SkColor input_color, const ColorMixer& mixer) {
const SkColor transform_color = transform.Run(input_color, mixer);
const SkColor result_color = SkColorSetA(transform_color, alpha);
DVLOG(2) << "ColorTransform SetAlpha:"
<< " Input Color: " << SkColorName(input_color)
<< " Transform Color: " << SkColorName(transform_color)
<< " Alpha: " << base::NumberToString(alpha)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(transform), alpha);
}
ColorTransform PickGoogleColor(ColorTransform foreground_transform,
ColorTransform background_transform,
float min_contrast,
float max_contrast) {
const auto generator =
[](ColorTransform foreground_transform,
ColorTransform background_transform, float min_contrast,
float max_contrast, SkColor input_color, const ColorMixer& mixer) {
const SkColor foreground_color =
foreground_transform.Run(input_color, mixer);
const SkColor background_color =
background_transform.Run(input_color, mixer);
const SkColor result_color = color_utils::PickGoogleColor(
foreground_color, background_color, min_contrast, max_contrast);
DVLOG(2) << "ColorTransform PickGoogleColor:"
<< " Input Color: " << SkColorName(input_color)
<< " Foreground Color: " << SkColorName(foreground_color)
<< " Background Color: " << SkColorName(background_color)
<< " Min Contrast: " << base::NumberToString(min_contrast)
<< " Max Contrast: " << base::NumberToString(max_contrast)
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(foreground_transform),
std::move(background_transform), min_contrast,
max_contrast);
}
ColorTransform PickGoogleColorTwoBackgrounds(
ColorTransform foreground_transform,
ColorTransform background_a_transform,
ColorTransform background_b_transform,
float min_contrast,
float max_contrast_against_nearer) {
const auto generator = [](ui::ColorTransform foreground_transform,
ui::ColorTransform background_a_transform,
ui::ColorTransform background_b_transform,
float min_contrast,
float max_contrast_against_nearer,
SkColor input_color, const ui::ColorMixer& mixer) {
const SkColor foreground_color =
foreground_transform.Run(input_color, mixer);
const SkColor background_a_color =
background_a_transform.Run(input_color, mixer);
const SkColor background_b_color =
background_b_transform.Run(input_color, mixer);
const SkColor result_color = color_utils::PickGoogleColorTwoBackgrounds(
foreground_color, background_a_color, background_b_color, min_contrast,
max_contrast_against_nearer);
DVLOG(2) << "ColorTransform PickGoogleColor:"
<< " Foreground Color: " << ui::SkColorName(foreground_color)
<< " Background Color A: " << ui::SkColorName(background_a_color)
<< " Background Color B: " << ui::SkColorName(background_b_color)
<< " Min Contrast: " << base::NumberToString(min_contrast)
<< " Max Contrast Against Nearer: "
<< base::NumberToString(max_contrast_against_nearer)
<< " Result Color: " << ui::SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(foreground_transform),
std::move(background_a_transform),
std::move(background_b_transform), min_contrast,
max_contrast_against_nearer);
}
ColorTransform HSLShift(ColorTransform color, color_utils::HSL hsl) {
const auto generator = [](ColorTransform transform, color_utils::HSL hsl,
SkColor input_color, const ColorMixer& mixer) {
const SkColor transform_color = transform.Run(input_color, mixer);
const SkColor result_color = color_utils::HSLShift(transform_color, hsl);
DVLOG(2) << "ColorTransform HSLShift:"
<< " Input Color: " << SkColorName(input_color)
<< " Transform Color: " << SkColorName(transform_color)
<< " HSL: {" << base::NumberToString(hsl.h) << ", "
<< base::NumberToString(hsl.s) << ", "
<< base::NumberToString(hsl.l) << "}"
<< " Result Color: " << SkColorName(result_color);
return result_color;
};
return base::BindRepeating(generator, std::move(color), hsl);
}
} // namespace ui