blob: a5b8e14ed903fbbf5322ea7275c31249e39969f7 [file] [log] [blame]
// Copyright 2020 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 "ui/gfx/display_color_spaces.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
namespace gfx {
namespace {
const ContentColorUsage kAllColorUsages[] = {
ContentColorUsage::kSRGB,
ContentColorUsage::kWideColorGamut,
ContentColorUsage::kHDR,
};
gfx::BufferFormat DefaultBufferFormat() {
// ChromeOS expects the default buffer format be BGRA_8888 in several places.
// https://crbug.com/1057501, https://crbug.com/1073237
#if BUILDFLAG(IS_CHROMEOS_ASH)
return gfx::BufferFormat::BGRA_8888;
#else
return gfx::BufferFormat::RGBA_8888;
#endif
}
size_t GetIndex(ContentColorUsage color_usage, bool needs_alpha) {
switch (color_usage) {
case ContentColorUsage::kSRGB:
return 0 + needs_alpha;
case ContentColorUsage::kWideColorGamut:
return 2 + needs_alpha;
case ContentColorUsage::kHDR:
return 4 + needs_alpha;
}
}
} // namespace
DisplayColorSpaces::DisplayColorSpaces() {
for (auto& color_space : color_spaces_)
color_space = gfx::ColorSpace::CreateSRGB();
for (auto& buffer_format : buffer_formats_)
buffer_format = DefaultBufferFormat();
}
DisplayColorSpaces::DisplayColorSpaces(const gfx::DisplayColorSpaces&) =
default;
DisplayColorSpaces& DisplayColorSpaces::operator=(
const gfx::DisplayColorSpaces&) = default;
DisplayColorSpaces::DisplayColorSpaces(const gfx::ColorSpace& c)
: DisplayColorSpaces() {
if (!c.IsValid())
return;
for (auto& color_space : color_spaces_)
color_space = c;
}
DisplayColorSpaces::DisplayColorSpaces(const ColorSpace& c, BufferFormat f) {
for (auto& color_space : color_spaces_)
color_space = c.IsValid() ? c : gfx::ColorSpace::CreateSRGB();
for (auto& buffer_format : buffer_formats_)
buffer_format = f;
}
void DisplayColorSpaces::SetOutputBufferFormats(
gfx::BufferFormat buffer_format_no_alpha,
gfx::BufferFormat buffer_format_needs_alpha) {
for (const auto& color_usage : kAllColorUsages) {
size_t i_no_alpha = GetIndex(color_usage, false);
size_t i_needs_alpha = GetIndex(color_usage, true);
buffer_formats_[i_no_alpha] = buffer_format_no_alpha;
buffer_formats_[i_needs_alpha] = buffer_format_needs_alpha;
}
}
void DisplayColorSpaces::SetOutputColorSpaceAndBufferFormat(
ContentColorUsage color_usage,
bool needs_alpha,
const gfx::ColorSpace& color_space,
gfx::BufferFormat buffer_format) {
size_t i = GetIndex(color_usage, needs_alpha);
color_spaces_[i] = color_space;
buffer_formats_[i] = buffer_format;
}
ColorSpace DisplayColorSpaces::GetOutputColorSpace(
ContentColorUsage color_usage,
bool needs_alpha) const {
return color_spaces_[GetIndex(color_usage, needs_alpha)];
}
BufferFormat DisplayColorSpaces::GetOutputBufferFormat(
ContentColorUsage color_usage,
bool needs_alpha) const {
return buffer_formats_[GetIndex(color_usage, needs_alpha)];
}
gfx::ColorSpace DisplayColorSpaces::GetRasterColorSpace() const {
return GetOutputColorSpace(ContentColorUsage::kHDR, false /* needs_alpha */);
}
gfx::ColorSpace DisplayColorSpaces::GetCompositingColorSpace(
bool needs_alpha,
ContentColorUsage color_usage) const {
gfx::ColorSpace result = GetOutputColorSpace(color_usage, needs_alpha);
if (!result.IsSuitableForBlending())
result = gfx::ColorSpace::CreateExtendedSRGB();
return result;
}
bool DisplayColorSpaces::SupportsHDR() const {
return GetOutputColorSpace(ContentColorUsage::kHDR, false).IsHDR() ||
GetOutputColorSpace(ContentColorUsage::kHDR, true).IsHDR();
}
ColorSpace DisplayColorSpaces::GetScreenInfoColorSpace() const {
return GetOutputColorSpace(ContentColorUsage::kHDR, false /* needs_alpha */);
}
void DisplayColorSpaces::ToStrings(
std::vector<std::string>* out_names,
std::vector<gfx::ColorSpace>* out_color_spaces,
std::vector<gfx::BufferFormat>* out_buffer_formats) const {
// The names of the configurations.
const char* config_names[kConfigCount] = {
"sRGB/no-alpha", "sRGB/alpha", "WCG/no-alpha",
"WCG/alpha", "HDR/no-alpha", "HDR/alpha",
};
// Names for special configuration subsets (e.g, all sRGB, all WCG, etc).
constexpr size_t kSpecialConfigCount = 5;
const char* special_config_names[kSpecialConfigCount] = {
"sRGB", "WCG", "SDR", "HDR", "all",
};
const size_t special_config_indices[kSpecialConfigCount][2] = {
{0, 2}, {2, 4}, {0, 4}, {4, 6}, {0, 6},
};
// We don't want to take up 6 lines (one for each config) if we don't need to.
// To avoid this, build up half-open intervals [i, j) which have the same
// color space and buffer formats, and group them together. The above "special
// configs" give groups that have a common name.
size_t i = 0;
size_t j = 0;
while (i != kConfigCount) {
// Keep growing the interval [i, j) until entry j is different, or past the
// end.
if (color_spaces_[i] == color_spaces_[j] &&
buffer_formats_[i] == buffer_formats_[j] && j != kConfigCount) {
j += 1;
continue;
}
// Populate the name for the group from the "special config" names.
std::string name;
for (size_t k = 0; k < kSpecialConfigCount; ++k) {
if (i == special_config_indices[k][0] &&
j == special_config_indices[k][1]) {
name = special_config_names[k];
break;
}
}
// If that didn't work, just list the configs.
if (name.empty()) {
for (size_t k = i; k < j; ++k) {
name += std::string(config_names[k]);
if (k != j - 1)
name += ",";
}
}
// Add an entry, and continue with the interval [j, j).
out_names->push_back(name);
out_buffer_formats->push_back(buffer_formats_[i]);
out_color_spaces->push_back(color_spaces_[i]);
i = j;
};
}
bool DisplayColorSpaces::operator==(const DisplayColorSpaces& other) const {
for (size_t i = 0; i < kConfigCount; ++i) {
if (color_spaces_[i] != other.color_spaces_[i])
return false;
if (buffer_formats_[i] != other.buffer_formats_[i])
return false;
}
if (sdr_white_level_ != other.sdr_white_level_)
return false;
return true;
}
bool DisplayColorSpaces::operator!=(const DisplayColorSpaces& other) const {
return !(*this == other);
}
} // namespace gfx