| Index: ui/gfx/color_space.cc
|
| diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc
|
| index 077e92759050d2de9fd69bcbfea80799014a7fd5..62ddbe0679d8e94430fa73e9213fbce48c6e8f26 100644
|
| --- a/ui/gfx/color_space.cc
|
| +++ b/ui/gfx/color_space.cc
|
| @@ -13,6 +13,26 @@
|
|
|
| namespace gfx {
|
|
|
| +namespace {
|
| +
|
| +SkColorSpaceTransferFn InvertTransferFn(SkColorSpaceTransferFn fn) {
|
| + SkColorSpaceTransferFn fn_inv = {0};
|
| + if (fn.fA > 0 && fn.fG > 0) {
|
| + double a_to_the_g = pow(fn.fA, fn.fG);
|
| + fn_inv.fA = 1.f / a_to_the_g;
|
| + fn_inv.fB = -fn.fE / a_to_the_g;
|
| + fn_inv.fG = 1.f / fn.fG;
|
| + }
|
| + fn_inv.fD = fn.fC * fn.fD + fn.fF;
|
| + fn_inv.fE = -fn.fB / fn.fA;
|
| + if (fn.fC != 0) {
|
| + fn_inv.fC = 1.f / fn.fC;
|
| + fn_inv.fF = -fn.fF / fn.fC;
|
| + }
|
| + return fn_inv;
|
| +}
|
| +};
|
| +
|
| ColorSpace::PrimaryID ColorSpace::PrimaryIDFromInt(int primary_id) {
|
| if (primary_id < 0 || primary_id > static_cast<int>(PrimaryID::LAST))
|
| return PrimaryID::UNKNOWN;
|
| @@ -40,9 +60,7 @@ ColorSpace::MatrixID ColorSpace::MatrixIDFromInt(int matrix_id) {
|
| return static_cast<MatrixID>(matrix_id);
|
| }
|
|
|
| -ColorSpace::ColorSpace() {
|
| - memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_));
|
| -}
|
| +ColorSpace::ColorSpace() {}
|
|
|
| ColorSpace::ColorSpace(PrimaryID primaries,
|
| TransferID transfer,
|
| @@ -51,19 +69,13 @@ ColorSpace::ColorSpace(PrimaryID primaries,
|
| : primaries_(primaries),
|
| transfer_(transfer),
|
| matrix_(matrix),
|
| - range_(range) {
|
| - memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_));
|
| - // TODO: Set profile_id_
|
| -}
|
| + range_(range) {}
|
|
|
| ColorSpace::ColorSpace(int primaries, int transfer, int matrix, RangeID range)
|
| : primaries_(PrimaryIDFromInt(primaries)),
|
| transfer_(TransferIDFromInt(transfer)),
|
| matrix_(MatrixIDFromInt(matrix)),
|
| - range_(range) {
|
| - memset(custom_primary_matrix_, 0, sizeof(custom_primary_matrix_));
|
| - // TODO: Set profile_id_
|
| -}
|
| + range_(range) {}
|
|
|
| ColorSpace::ColorSpace(const ColorSpace& other)
|
| : primaries_(other.primaries_),
|
| @@ -71,19 +83,23 @@ ColorSpace::ColorSpace(const ColorSpace& other)
|
| matrix_(other.matrix_),
|
| range_(other.range_),
|
| icc_profile_id_(other.icc_profile_id_),
|
| - sk_color_space_(other.sk_color_space_) {
|
| - memcpy(custom_primary_matrix_, other.custom_primary_matrix_,
|
| - sizeof(custom_primary_matrix_));
|
| + icc_profile_sk_color_space_(other.icc_profile_sk_color_space_) {
|
| + if (transfer_ == TransferID::CUSTOM) {
|
| + memcpy(custom_transfer_params_, other.custom_transfer_params_,
|
| + sizeof(custom_transfer_params_));
|
| + }
|
| + if (primaries_ == PrimaryID::CUSTOM) {
|
| + memcpy(custom_primary_matrix_, other.custom_primary_matrix_,
|
| + sizeof(custom_primary_matrix_));
|
| + }
|
| }
|
|
|
| ColorSpace::~ColorSpace() = default;
|
|
|
| // static
|
| ColorSpace ColorSpace::CreateSRGB() {
|
| - ColorSpace result(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB,
|
| + return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB,
|
| RangeID::FULL);
|
| - result.sk_color_space_ = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
|
| - return result;
|
| }
|
|
|
| // static
|
| @@ -124,6 +140,10 @@ bool ColorSpace::operator==(const ColorSpace& other) const {
|
| memcmp(custom_primary_matrix_, other.custom_primary_matrix_,
|
| sizeof(custom_primary_matrix_)))
|
| return false;
|
| + if (transfer_ == TransferID::CUSTOM &&
|
| + memcmp(custom_transfer_params_, other.custom_transfer_params_,
|
| + sizeof(custom_transfer_params_)))
|
| + return false;
|
| return true;
|
| }
|
|
|
| @@ -163,9 +183,70 @@ bool ColorSpace::operator<(const ColorSpace& other) const {
|
| if (primary_result > 0)
|
| return false;
|
| }
|
| + if (transfer_ == TransferID::CUSTOM) {
|
| + int transfer_result =
|
| + memcmp(custom_transfer_params_, other.custom_transfer_params_,
|
| + sizeof(custom_transfer_params_));
|
| + if (transfer_result < 0)
|
| + return true;
|
| + if (transfer_result > 0)
|
| + return false;
|
| + }
|
| return false;
|
| }
|
|
|
| +sk_sp<SkColorSpace> ColorSpace::ToSkColorSpace() const {
|
| + // If we got a specific SkColorSpace from the ICCProfile that this color space
|
| + // was created from, use that.
|
| + if (icc_profile_sk_color_space_)
|
| + return icc_profile_sk_color_space_;
|
| +
|
| + // Unspecified color spaces correspond to the null SkColorSpace.
|
| + if (primaries_ == PrimaryID::UNSPECIFIED ||
|
| + transfer_ == TransferID::UNSPECIFIED) {
|
| + return nullptr;
|
| + }
|
| +
|
| + // Handle only full-range RGB spaces.
|
| + if (matrix_ != MatrixID::RGB) {
|
| + DLOG(ERROR) << "Not creating non-RGB SkColorSpace";
|
| + return nullptr;
|
| + }
|
| + if (range_ != RangeID::FULL) {
|
| + DLOG(ERROR) << "Not creating non-full-range SkColorSpace";
|
| + return nullptr;
|
| + }
|
| +
|
| + // Use the named SRGB and linear-SRGB instead of the generic constructors.
|
| + if (primaries_ == PrimaryID::BT709) {
|
| + if (transfer_ == TransferID::IEC61966_2_1)
|
| + return SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
|
| + if (transfer_ == TransferID::LINEAR || transfer_ == TransferID::LINEAR_HDR)
|
| + return SkColorSpace::MakeNamed(SkColorSpace::kSRGBLinear_Named);
|
| + }
|
| +
|
| + SkMatrix44 to_xyz_d50;
|
| + GetPrimaryMatrix(&to_xyz_d50);
|
| +
|
| + // Use the named sRGB and linear transfer functions.
|
| + if (transfer_ == TransferID::IEC61966_2_1) {
|
| + return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
|
| + to_xyz_d50);
|
| + }
|
| + if (transfer_ == TransferID::LINEAR || transfer_ == TransferID::LINEAR_HDR) {
|
| + return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
|
| + to_xyz_d50);
|
| + }
|
| +
|
| + // Use the parametric transfer function if no other option is available.
|
| + SkColorSpaceTransferFn fn;
|
| + if (!GetTransferFunction(&fn)) {
|
| + DLOG(ERROR) << "Failed to parameterize transfer function for SkColorSpace";
|
| + return nullptr;
|
| + }
|
| + return SkColorSpace::MakeRGB(fn, to_xyz_d50);
|
| +}
|
| +
|
| ColorSpace ColorSpace::FromSkColorSpace(
|
| const sk_sp<SkColorSpace>& sk_color_space) {
|
| if (!sk_color_space)
|
| @@ -181,4 +262,222 @@ ColorSpace ColorSpace::FromSkColorSpace(
|
| return icc_profile.GetColorSpace();
|
| }
|
|
|
| +void ColorSpace::GetPrimaryMatrix(SkMatrix44* to_XYZD50) const {
|
| + SkColorSpacePrimaries primaries = {0};
|
| + switch (primaries_) {
|
| + case ColorSpace::PrimaryID::CUSTOM:
|
| + to_XYZD50->set3x3RowMajorf(custom_primary_matrix_);
|
| + return;
|
| +
|
| + case ColorSpace::PrimaryID::RESERVED0:
|
| + case ColorSpace::PrimaryID::RESERVED:
|
| + case ColorSpace::PrimaryID::UNSPECIFIED:
|
| + case ColorSpace::PrimaryID::UNKNOWN:
|
| + case ColorSpace::PrimaryID::BT709:
|
| + // BT709 is our default case. Put it after the switch just
|
| + // in case we somehow get an id which is not listed in the switch.
|
| + // (We don't want to use "default", because we want the compiler
|
| + // to tell us if we forgot some enum values.)
|
| + primaries.fRX = 0.640f;
|
| + primaries.fRY = 0.330f;
|
| + primaries.fGX = 0.300f;
|
| + primaries.fGY = 0.600f;
|
| + primaries.fBX = 0.150f;
|
| + primaries.fBY = 0.060f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::BT470M:
|
| + primaries.fRX = 0.67f;
|
| + primaries.fRY = 0.33f;
|
| + primaries.fGX = 0.21f;
|
| + primaries.fGY = 0.71f;
|
| + primaries.fBX = 0.14f;
|
| + primaries.fBY = 0.08f;
|
| + primaries.fWX = 0.31f;
|
| + primaries.fWY = 0.316f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::BT470BG:
|
| + primaries.fRX = 0.64f;
|
| + primaries.fRY = 0.33f;
|
| + primaries.fGX = 0.29f;
|
| + primaries.fGY = 0.60f;
|
| + primaries.fBX = 0.15f;
|
| + primaries.fBY = 0.06f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTE170M:
|
| + case ColorSpace::PrimaryID::SMPTE240M:
|
| + primaries.fRX = 0.630f;
|
| + primaries.fRY = 0.340f;
|
| + primaries.fGX = 0.310f;
|
| + primaries.fGY = 0.595f;
|
| + primaries.fBX = 0.155f;
|
| + primaries.fBY = 0.070f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::FILM:
|
| + primaries.fRX = 0.681f;
|
| + primaries.fRY = 0.319f;
|
| + primaries.fGX = 0.243f;
|
| + primaries.fGY = 0.692f;
|
| + primaries.fBX = 0.145f;
|
| + primaries.fBY = 0.049f;
|
| + primaries.fWX = 0.310f;
|
| + primaries.fWY = 0.136f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::BT2020:
|
| + primaries.fRX = 0.708f;
|
| + primaries.fRY = 0.292f;
|
| + primaries.fGX = 0.170f;
|
| + primaries.fGY = 0.797f;
|
| + primaries.fBX = 0.131f;
|
| + primaries.fBY = 0.046f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTEST428_1:
|
| + primaries.fRX = 1.0f;
|
| + primaries.fRY = 0.0f;
|
| + primaries.fGX = 0.0f;
|
| + primaries.fGY = 1.0f;
|
| + primaries.fBX = 0.0f;
|
| + primaries.fBY = 0.0f;
|
| + primaries.fWX = 1.0f / 3.0f;
|
| + primaries.fWY = 1.0f / 3.0f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTEST431_2:
|
| + primaries.fRX = 0.680f;
|
| + primaries.fRY = 0.320f;
|
| + primaries.fGX = 0.265f;
|
| + primaries.fGY = 0.690f;
|
| + primaries.fBX = 0.150f;
|
| + primaries.fBY = 0.060f;
|
| + primaries.fWX = 0.314f;
|
| + primaries.fWY = 0.351f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::SMPTEST432_1:
|
| + primaries.fRX = 0.680f;
|
| + primaries.fRY = 0.320f;
|
| + primaries.fGX = 0.265f;
|
| + primaries.fGY = 0.690f;
|
| + primaries.fBX = 0.150f;
|
| + primaries.fBY = 0.060f;
|
| + primaries.fWX = 0.3127f;
|
| + primaries.fWY = 0.3290f;
|
| + break;
|
| +
|
| + case ColorSpace::PrimaryID::XYZ_D50:
|
| + primaries.fRX = 1.0f;
|
| + primaries.fRY = 0.0f;
|
| + primaries.fGX = 0.0f;
|
| + primaries.fGY = 1.0f;
|
| + primaries.fBX = 0.0f;
|
| + primaries.fBY = 0.0f;
|
| + primaries.fWX = 0.34567f;
|
| + primaries.fWY = 0.35850f;
|
| + break;
|
| + }
|
| + primaries.toXYZD50(to_XYZD50);
|
| +}
|
| +
|
| +bool ColorSpace::GetTransferFunction(SkColorSpaceTransferFn* fn) const {
|
| + // Default to F(x) = pow(x, 1)
|
| + fn->fA = 1;
|
| + fn->fB = 0;
|
| + fn->fC = 1;
|
| + fn->fD = 0;
|
| + fn->fE = 0;
|
| + fn->fF = 0;
|
| + fn->fG = 1;
|
| +
|
| + switch (transfer_) {
|
| + case ColorSpace::TransferID::CUSTOM:
|
| + fn->fA = custom_transfer_params_[0];
|
| + fn->fB = custom_transfer_params_[1];
|
| + fn->fC = custom_transfer_params_[2];
|
| + fn->fD = custom_transfer_params_[3];
|
| + fn->fE = custom_transfer_params_[4];
|
| + fn->fF = custom_transfer_params_[5];
|
| + fn->fG = custom_transfer_params_[6];
|
| + return true;
|
| + case ColorSpace::TransferID::LINEAR:
|
| + case ColorSpace::TransferID::LINEAR_HDR:
|
| + return true;
|
| + case ColorSpace::TransferID::GAMMA22:
|
| + fn->fG = 2.2f;
|
| + return true;
|
| + case ColorSpace::TransferID::GAMMA24:
|
| + fn->fG = 2.4f;
|
| + return true;
|
| + case ColorSpace::TransferID::GAMMA28:
|
| + fn->fG = 2.8f;
|
| + return true;
|
| + case ColorSpace::TransferID::RESERVED0:
|
| + case ColorSpace::TransferID::RESERVED:
|
| + case ColorSpace::TransferID::UNSPECIFIED:
|
| + case ColorSpace::TransferID::UNKNOWN:
|
| + // All unknown values default to BT709
|
| + case ColorSpace::TransferID::BT709:
|
| + case ColorSpace::TransferID::SMPTE170M:
|
| + case ColorSpace::TransferID::BT2020_10:
|
| + case ColorSpace::TransferID::BT2020_12:
|
| + fn->fA = 0.909672431050f;
|
| + fn->fB = 0.090327568950f;
|
| + fn->fC = 0.222222222222f;
|
| + fn->fD = 0.081242862158f;
|
| + fn->fG = 2.222222222222f;
|
| + return true;
|
| + case ColorSpace::TransferID::SMPTE240M:
|
| + fn->fA = 0.899626676224f;
|
| + fn->fB = 0.100373323776f;
|
| + fn->fC = 0.250000000000f;
|
| + fn->fD = 0.091286342118f;
|
| + fn->fG = 2.222222222222f;
|
| + return true;
|
| + case ColorSpace::TransferID::IEC61966_2_1:
|
| + fn->fA = 0.947867345704f;
|
| + fn->fB = 0.052132654296f;
|
| + fn->fC = 0.077399380805f;
|
| + fn->fD = 0.040449937172f;
|
| + fn->fG = 2.400000000000f;
|
| + return true;
|
| + case ColorSpace::TransferID::SMPTEST428_1:
|
| + fn->fA = 0.225615407568f;
|
| + fn->fE = -1.091041666667f;
|
| + fn->fG = 2.600000000000f;
|
| + return true;
|
| + case ColorSpace::TransferID::IEC61966_2_4:
|
| + // This could potentially be represented the same as IEC61966_2_1, but
|
| + // it handles negative values differently.
|
| + break;
|
| + case ColorSpace::TransferID::ARIB_STD_B67:
|
| + case ColorSpace::TransferID::BT1361_ECG:
|
| + case ColorSpace::TransferID::LOG:
|
| + case ColorSpace::TransferID::LOG_SQRT:
|
| + case ColorSpace::TransferID::SMPTEST2084:
|
| + case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
|
| + break;
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +bool ColorSpace::GetInverseTransferFunction(SkColorSpaceTransferFn* fn) const {
|
| + if (!GetTransferFunction(fn))
|
| + return false;
|
| + *fn = InvertTransferFn(*fn);
|
| + return true;
|
| +}
|
| +
|
| } // namespace gfx
|
|
|