blob: 32ff2e410264cbf4c705a2528b048d4ed103e36a [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_provider.h"
#include <map>
#include <set>
#include <utility>
#include "base/functional/bind.h"
#include "base/logging.h"
#include "ui/color/color_mixer.h"
#include "ui/color/color_provider_utils.h"
#include "ui/color/color_recipe.h"
#include "ui/gfx/color_palette.h"
namespace ui {
ColorProvider::ColorProvider() = default;
ColorProvider::ColorProvider(ColorProvider&&) = default;
ColorProvider& ColorProvider::operator=(ColorProvider&&) = default;
ColorProvider::~ColorProvider() = default;
ColorMixer& ColorProvider::AddMixer() {
DCHECK(!color_map_);
mixers_.emplace_after(
first_postprocessing_mixer_,
base::BindRepeating([](const ColorMixer* mixer) { return mixer; },
GetLastNonPostprocessingMixer()),
base::BindRepeating(&ColorProvider::GetLastNonPostprocessingMixer,
base::Unretained(this)));
return *std::next(first_postprocessing_mixer_, 1);
}
ColorMixer& ColorProvider::AddPostprocessingMixer() {
DCHECK(!color_map_);
if (first_postprocessing_mixer_ == mixers_.before_begin()) {
// The first postprocessing mixer points to the last regular mixer.
auto previous_mixer_getter = base::BindRepeating(
&ColorProvider::GetLastNonPostprocessingMixer, base::Unretained(this));
mixers_.emplace_front(previous_mixer_getter, previous_mixer_getter);
first_postprocessing_mixer_ = mixers_.begin();
} else {
// Other postprocessing mixers point to the next postprocessing mixer.
auto previous_mixer_getter =
base::BindRepeating([](const ColorMixer* mixer) { return mixer; },
base::Unretained(&mixers_.front()));
mixers_.emplace_front(previous_mixer_getter, previous_mixer_getter);
}
return mixers_.front();
}
SkColor ColorProvider::GetColor(ColorId id) const {
CHECK(color_map_);
auto i = color_map_->find(id);
return i == color_map_->end() ? gfx::kPlaceholderColor : i->second;
}
void ColorProvider::GenerateColorMap() {
// This should only be called to generate the `color_map_` once.
DCHECK(!color_map_);
if (mixers_.empty())
DVLOG(2) << "ColorProvider::GenerateColorMap: No mixers defined!";
// Iterate over associated mixers and extract the ColorIds defined for this
// provider.
std::set<ColorId> color_ids;
for (const auto& mixer : mixers_) {
const auto mixer_color_ids = mixer.GetDefinedColorIds();
color_ids.insert(mixer_color_ids.begin(), mixer_color_ids.end());
}
// Iterate through all defined ColorIds and seed the `color_map` with the
// computed values. Use a std::map rather than a base::flat_map since it has
// frequent inserts and could grow very large.
std::map<ColorId, SkColor> color_map;
for (const auto& color_id : color_ids) {
SkColor resulting_color = mixers_.front().GetResultColor(color_id);
DVLOG(2) << "GenerateColorMap:"
<< " Color Id: " << ColorIdName(color_id)
<< " Resulting Color: " << SkColorName(resulting_color);
color_map.insert({color_id, resulting_color});
}
// Construct the color_map_.
color_map_ = ColorMap(color_map.begin(), color_map.end());
// Clear away all associated mixers as these are no longer needed.
mixers_.clear();
first_postprocessing_mixer_ = mixers_.before_begin();
}
bool ColorProvider::IsColorMapEmpty() const {
DCHECK(color_map_);
return color_map_->empty();
}
void ColorProvider::SetColorForTesting(ColorId id, SkColor color) {
if (color_map_) {
(*color_map_)[id] = color;
} else {
if (mixers_.empty())
AddMixer();
(*std::next(first_postprocessing_mixer_, 1))[id] = {color};
}
}
const ColorMixer* ColorProvider::GetLastNonPostprocessingMixer() const {
const auto it = std::next(first_postprocessing_mixer_, 1);
return (it == mixers_.cend()) ? nullptr : &(*it);
}
} // namespace ui