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 |