Revert "Make ICCProfile no longer store a ColorSpace directly"
This reverts commit ac3c37d52e71853c54921c488cc52b7a9ebfb2fb.
Reason for revert: crbug.com/780848, crbug.com/780415
Original change's description:
> Make ICCProfile no longer store a ColorSpace directly
>
> Make ICCProfile store the primaries and transfer function that it
> read or computed directly, rather than storing a ColorSpace object.
> Construct the ColorSpace object when requested, rather than storing it.
>
> Store an approximate (or guessed) primary matrix and transfer function
> for ICC_BASED ColorSpace objects. When computing the parametric
> approximation of an ICC_BASED ColorSpace object, use these values
> directly, rather than having to look them up from original ICCProfile.
>
> Bug: 766736
> Change-Id: I21d6dfaa38706f814f6c9dd54517806e99366113
> Reviewed-on: https://chromium-review.googlesource.com/745311
> Reviewed-by: Fredrik Hubinette <[email protected]>
> Commit-Queue: ccameron <[email protected]>
> Cr-Commit-Position: refs/heads/master@{#512958}
[email protected],[email protected]
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: 766736
Change-Id: Ie36929800ab8f748cfc331b1a6ccda328c6559f8
Reviewed-on: https://chromium-review.googlesource.com/752061
Reviewed-by: ccameron <[email protected]>
Commit-Queue: ccameron <[email protected]>
Cr-Commit-Position: refs/heads/master@{#513624}
diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc
index ca60dae..14588f40 100644
--- a/ui/gfx/color_space.cc
+++ b/ui/gfx/color_space.cc
@@ -51,11 +51,11 @@
range_(other.range_),
icc_profile_id_(other.icc_profile_id_),
icc_profile_sk_color_space_(other.icc_profile_sk_color_space_) {
- if (transfer_ == TransferID::CUSTOM || transfer_ == TransferID::ICC_BASED) {
+ if (transfer_ == TransferID::CUSTOM) {
memcpy(custom_transfer_params_, other.custom_transfer_params_,
sizeof(custom_transfer_params_));
}
- if (primaries_ == PrimaryID::CUSTOM || primaries_ == PrimaryID::ICC_BASED) {
+ if (primaries_ == PrimaryID::CUSTOM) {
memcpy(custom_primary_matrix_, other.custom_primary_matrix_,
sizeof(custom_primary_matrix_));
}
@@ -96,18 +96,13 @@
ColorSpace result(ColorSpace::PrimaryID::CUSTOM,
ColorSpace::TransferID::CUSTOM, ColorSpace::MatrixID::RGB,
ColorSpace::RangeID::FULL);
- result.SetCustomPrimaries(to_XYZD50);
- result.SetCustomTransferFunction(fn);
- return result;
-}
-
-void ColorSpace::SetCustomPrimaries(const SkMatrix44& to_XYZD50) {
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
- custom_primary_matrix_[3 * row + col] = to_XYZD50.get(row, col);
+ result.custom_primary_matrix_[3 * row + col] = to_XYZD50.get(row, col);
}
}
- primaries_ = PrimaryID::CUSTOM;
+ result.SetCustomTransferFunction(fn);
+ return result;
}
void ColorSpace::SetCustomTransferFunction(const SkColorSpaceTransferFn& fn) {
@@ -173,13 +168,13 @@
if (primaries_ != other.primaries_ || transfer_ != other.transfer_ ||
matrix_ != other.matrix_ || range_ != other.range_)
return false;
- if (primaries_ == PrimaryID::CUSTOM || primaries_ == PrimaryID::ICC_BASED) {
+ if (primaries_ == PrimaryID::CUSTOM) {
if (memcmp(custom_primary_matrix_, other.custom_primary_matrix_,
sizeof(custom_primary_matrix_))) {
return false;
}
}
- if (transfer_ == TransferID::CUSTOM || transfer_ == TransferID::ICC_BASED) {
+ if (transfer_ == TransferID::CUSTOM) {
if (memcmp(custom_transfer_params_, other.custom_transfer_params_,
sizeof(custom_transfer_params_))) {
return false;
@@ -207,25 +202,27 @@
transfer_ == TransferID::IEC61966_2_4;
}
+bool ColorSpace::IsParametric() const {
+ return primaries_ != PrimaryID::ICC_BASED &&
+ transfer_ != TransferID::ICC_BASED;
+}
+
ColorSpace ColorSpace::GetParametricApproximation() const {
- ColorSpace result = *this;
- // The parametric approximation will not equal the original color space only
- // when the primaries or transfer function of the original color space are not
- // parametric (that is, they require the original ICC profile to represent
- // them).
- if (result.primaries_ == PrimaryID::ICC_BASED ||
- result.transfer_ == TransferID::ICC_BASED) {
- // Ensure that the result not reference the original ICC profile anymore,
- // because ICC profile represents a different space from the returned
- // approximation.
- result.icc_profile_id_ = 0;
- result.icc_profile_sk_color_space_ = nullptr;
- if (result.primaries_ == PrimaryID::ICC_BASED)
- result.primaries_ = PrimaryID::CUSTOM;
- if (result.transfer_ == TransferID::ICC_BASED)
- result.transfer_ = TransferID::CUSTOM;
+ // If this is parametric already, return it directly.
+ if (IsParametric())
+ return *this;
+
+ // Query the ICC profile, if available, for the parametric approximation.
+ ICCProfile icc_profile;
+ if (icc_profile_id_ && GetICCProfile(&icc_profile)) {
+ return icc_profile.GetParametricColorSpace();
+ } else {
+ DLOG(ERROR)
+ << "Unable to acquire ICC profile for parametric approximation.";
}
- return result;
+
+ // Fall back to sRGB if the ICC profile is no longer cached.
+ return CreateSRGB();
}
bool ColorSpace::operator!=(const ColorSpace& other) const {
@@ -249,7 +246,7 @@
return true;
if (range_ > other.range_)
return false;
- if (primaries_ == PrimaryID::CUSTOM || primaries_ == PrimaryID::ICC_BASED) {
+ if (primaries_ == PrimaryID::CUSTOM) {
int primary_result =
memcmp(custom_primary_matrix_, other.custom_primary_matrix_,
sizeof(custom_primary_matrix_));
@@ -258,7 +255,7 @@
if (primary_result > 0)
return false;
}
- if (transfer_ == TransferID::CUSTOM || transfer_ == TransferID::ICC_BASED) {
+ if (transfer_ == TransferID::CUSTOM) {
int transfer_result =
memcmp(custom_transfer_params_, other.custom_transfer_params_,
sizeof(custom_transfer_params_));
@@ -275,14 +272,14 @@
(static_cast<size_t>(transfer_) << 8) |
(static_cast<size_t>(matrix_) << 16) |
(static_cast<size_t>(range_) << 24);
- if (primaries_ == PrimaryID::CUSTOM || primaries_ == PrimaryID::ICC_BASED) {
+ if (primaries_ == PrimaryID::CUSTOM) {
const uint32_t* params =
reinterpret_cast<const uint32_t*>(custom_primary_matrix_);
result ^= params[0];
result ^= params[4];
result ^= params[8];
}
- if (transfer_ == TransferID::CUSTOM || transfer_ == TransferID::ICC_BASED) {
+ if (transfer_ == TransferID::CUSTOM) {
const uint32_t* params =
reinterpret_cast<const uint32_t*>(custom_transfer_params_);
result ^= params[3];
@@ -317,17 +314,16 @@
PRINT_ENUM_CASE(PrimaryID, APPLE_GENERIC_RGB)
PRINT_ENUM_CASE(PrimaryID, WIDE_GAMUT_COLOR_SPIN)
PRINT_ENUM_CASE(PrimaryID, ICC_BASED)
- PRINT_ENUM_CASE(PrimaryID, CUSTOM)
- }
- if (primaries_ == PrimaryID::ICC_BASED || primaries_ == PrimaryID::CUSTOM) {
- ss << ":[";
- for (size_t i = 0; i < 3; ++i) {
+ case PrimaryID::CUSTOM:
ss << "[";
- for (size_t j = 0; j < 3; ++j)
- ss << custom_primary_matrix_[3 * i + j] << ",";
- ss << "],";
- }
- ss << "]";
+ for (size_t i = 0; i < 3; ++i) {
+ ss << "[";
+ for (size_t j = 0; j < 3; ++j)
+ ss << custom_primary_matrix_[3 * i + j] << ",";
+ ss << "],";
+ }
+ ss << "]";
+ break;
}
ss << ", transfer:";
switch (transfer_) {
@@ -354,13 +350,13 @@
PRINT_ENUM_CASE(TransferID, IEC61966_2_1_HDR)
PRINT_ENUM_CASE(TransferID, LINEAR_HDR)
PRINT_ENUM_CASE(TransferID, ICC_BASED)
- PRINT_ENUM_CASE(TransferID, CUSTOM)
- }
- if (transfer_ == TransferID::ICC_BASED || transfer_ == TransferID::CUSTOM) {
- SkColorSpaceTransferFn fn;
- GetTransferFunction(&fn);
- ss << ":(" << fn.fC << "*x + " << fn.fF << " if x < " << fn.fD << " else (";
- ss << fn.fA << "*x + " << fn.fB << ")**" << fn.fG << " + " << fn.fE << ")";
+ case TransferID::CUSTOM: {
+ SkColorSpaceTransferFn fn;
+ GetTransferFunction(&fn);
+ ss << fn.fC << "*x + " << fn.fF << " if x < " << fn.fD << " else (";
+ ss << fn.fA << "*x + " << fn.fB << ")**" << fn.fG << " + " << fn.fE;
+ break;
+ }
}
ss << ", matrix:";
switch (matrix_) {
@@ -400,15 +396,15 @@
}
ColorSpace ColorSpace::GetRasterColorSpace() const {
+ // Rasterization can only be done into parametric color spaces.
+ if (!IsParametric())
+ return GetParametricApproximation();
// Rasterization doesn't support more than 8 bit unorm values. If the output
// space has an extended range, use Display P3 for the rasterization space,
// to get a somewhat wider color gamut.
if (HasExtendedSkTransferFn())
return CreateDisplayP3D65();
-
- // Rasterization can only be done into parametric color spaces. Return the
- // parametric approximation.
- return GetParametricApproximation();
+ return *this;
}
ColorSpace ColorSpace::GetBlendingColorSpace() const {
@@ -420,6 +416,11 @@
}
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 (!IsValid())
return nullptr;
@@ -434,11 +435,6 @@
return nullptr;
}
- // 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_;
-
// Use the named SRGB and linear-SRGB instead of the generic constructors.
if (primaries_ == PrimaryID::BT709) {
if (transfer_ == TransferID::IEC61966_2_1)
@@ -516,14 +512,10 @@
}
// If this was created from an ICC profile, retrieve that exact profile.
+ ICCProfile result;
if (ICCProfile::FromId(icc_profile_id_, icc_profile))
return true;
- if (primaries_ == PrimaryID::ICC_BASED ||
- transfer_ == TransferID::ICC_BASED) {
- return false;
- }
-
// Otherwise, construct an ICC profile based on the best approximated
// primaries and matrix.
SkMatrix44 to_XYZD50_matrix;
@@ -588,11 +580,11 @@
SkColorSpacePrimaries primaries = {0};
switch (primaries_) {
case ColorSpace::PrimaryID::CUSTOM:
- case ColorSpace::PrimaryID::ICC_BASED:
to_XYZD50->set3x3RowMajorf(custom_primary_matrix_);
return;
case ColorSpace::PrimaryID::INVALID:
+ case ColorSpace::PrimaryID::ICC_BASED:
to_XYZD50->setIdentity();
return;
@@ -759,7 +751,6 @@
switch (transfer_) {
case ColorSpace::TransferID::CUSTOM:
- case ColorSpace::TransferID::ICC_BASED:
fn->fA = custom_transfer_params_[0];
fn->fB = custom_transfer_params_[1];
fn->fC = custom_transfer_params_[2];
@@ -827,6 +818,7 @@
case ColorSpace::TransferID::SMPTEST2084:
case ColorSpace::TransferID::SMPTEST2084_NON_HDR:
case ColorSpace::TransferID::INVALID:
+ case ColorSpace::TransferID::ICC_BASED:
break;
}
diff --git a/ui/gfx/color_space.h b/ui/gfx/color_space.h
index a4757ef3..8a514de2 100644
--- a/ui/gfx/color_space.h
+++ b/ui/gfx/color_space.h
@@ -53,8 +53,7 @@
CUSTOM,
// For color spaces defined by an ICC profile which cannot be represented
// parametrically. Any ColorTransform using this color space will use the
- // ICC profile directly to compute a transform LUT. A parametric
- // approximation of these primaries is stored in |custom_primary_matrix_|.
+ // ICC profile directly to compute a transform LUT.
ICC_BASED,
LAST = ICC_BASED,
};
@@ -90,8 +89,7 @@
LINEAR_HDR,
// A parametric transfer function defined by |custom_transfer_params_|.
CUSTOM,
- // See PrimaryID::ICC_BASED. A parametric approximation of the transfer
- // function is stored in |custom_transfer_params_|.
+ // See PrimaryID::ICC_BASED.
ICC_BASED,
LAST = ICC_BASED,
};
@@ -173,6 +171,9 @@
// Returns true if the encoded values can be outside of the 0.0-1.0 range.
bool FullRangeEncodedValues() const;
+ // Returns true if this color space can be represented parametrically.
+ bool IsParametric() const;
+
// Return a parametric approximation of this color space (if it is not already
// parametric).
ColorSpace GetParametricApproximation() const;
@@ -207,7 +208,6 @@
void GetRangeAdjustMatrix(SkMatrix44* matrix) const;
private:
- void SetCustomPrimaries(const SkMatrix44& to_XYZD50);
void SetCustomTransferFunction(const SkColorSpaceTransferFn& fn);
// Returns true if the transfer function is defined by an
@@ -219,12 +219,12 @@
MatrixID matrix_ = MatrixID::INVALID;
RangeID range_ = RangeID::INVALID;
- // Only used if primaries_ is PrimaryID::CUSTOM or PrimaryID::ICC_BASED.
+ // Only used if primaries_ is PrimaryID::CUSTOM.
float custom_primary_matrix_[9] = {0, 0, 0, 0, 0, 0, 0, 0};
- // Only used if transfer_ is TransferID::CUSTOM or PrimaryID::ICC_BASED.
- // This array consists of the A through G entries of the
- // SkColorSpaceTransferFn structure in alphabetical order.
+ // Only used if transfer_ is TransferID::CUSTOM. This array consists of the A
+ // through G entries of the SkColorSpaceTransferFn structure in alphabetical
+ // order.
float custom_transfer_params_[7] = {0, 0, 0, 0, 0, 0, 0};
// This is used to look up the ICCProfile from which this ColorSpace was
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index ab9a4bbf..906aded 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -252,9 +252,8 @@
const float kEpsilon = 2.5f / 255.f;
ICCProfile icc_profile = ICCProfileForTestingNoAnalyticTrFn();
ColorSpace icc_space = icc_profile.GetColorSpace();
- ColorSpace colorspin = ICCProfileForTestingColorSpin()
- .GetColorSpace()
- .GetParametricApproximation();
+ ColorSpace colorspin =
+ ICCProfileForTestingColorSpin().GetParametricColorSpace();
ColorTransform::TriStim input_value(0.25f, 0.5f, 0.75f);
ColorTransform::TriStim transformed_value = input_value;
diff --git a/ui/gfx/icc_profile.cc b/ui/gfx/icc_profile.cc
index f26a8181..75fdec5 100644
--- a/ui/gfx/icc_profile.cc
+++ b/ui/gfx/icc_profile.cc
@@ -54,6 +54,17 @@
if (!icc_profile->id_)
icc_profile->id_ = next_unused_id_++;
+ // Ensure that GetColorSpace() point back to this ICCProfile.
+ gfx::ColorSpace& color_space = icc_profile->color_space_;
+ color_space.icc_profile_id_ = icc_profile->id_;
+
+ // Ensure that the GetParametricColorSpace() point back to this ICCProfile
+ // only if the parametric version is accurate.
+ if (color_space.primaries_ != ColorSpace::PrimaryID::ICC_BASED &&
+ color_space.transfer_ != ColorSpace::TransferID::ICC_BASED) {
+ icc_profile->parametric_color_space_.icc_profile_id_ = icc_profile->id_;
+ }
+
Entry entry;
entry.icc_profile = *icc_profile;
id_to_icc_profile_mru_.Put(icc_profile->id_, entry);
@@ -190,69 +201,76 @@
} // namespace
-ICCProfile::AnalyzeResult ICCProfile::Initialize() {
- // Start out with no parametric data.
- primaries_ = gfx::ColorSpace::PrimaryID::INVALID;
- transfer_ = gfx::ColorSpace::TransferID::INVALID;
+// static
+ICCProfile::AnalyzeResult ICCProfile::ExtractColorSpaces(
+ const std::vector<char>& data,
+ gfx::ColorSpace* parametric_color_space,
+ float* parametric_tr_fn_max_error,
+ sk_sp<SkColorSpace>* useable_sk_color_space) {
+ // Initialize the output parameters as invalid.
+ *parametric_color_space = gfx::ColorSpace();
+ *parametric_tr_fn_max_error = 0;
+ *useable_sk_color_space = nullptr;
// Parse the profile and attempt to create a SkColorSpaceXform out of it.
sk_sp<SkColorSpace> sk_srgb_color_space = SkColorSpace::MakeSRGB();
- sk_sp<SkICC> sk_icc = SkICC::Make(data_.data(), data_.size());
+ sk_sp<SkICC> sk_icc = SkICC::Make(data.data(), data.size());
if (!sk_icc) {
DLOG(ERROR) << "Failed to parse ICC profile to SkICC.";
return kICCFailedToParse;
}
- sk_color_space_ = SkColorSpace::MakeICC(data_.data(), data_.size());
- if (!sk_color_space_) {
+ sk_sp<SkColorSpace> sk_icc_color_space =
+ SkColorSpace::MakeICC(data.data(), data.size());
+ if (!sk_icc_color_space) {
DLOG(ERROR) << "Failed to parse ICC profile to SkColorSpace.";
return kICCFailedToExtractSkColorSpace;
}
-
- // If our SkColorSpace representation is sRGB then return that.
- if (SkColorSpace::Equals(sk_srgb_color_space.get(), sk_color_space_.get())) {
- primaries_ = gfx::ColorSpace::PrimaryID::BT709;
- transfer_ = gfx::ColorSpace::TransferID::IEC61966_2_1;
- return kICCExtractedSRGBColorSpace;
- }
-
std::unique_ptr<SkColorSpaceXform> sk_color_space_xform =
- SkColorSpaceXform::New(sk_srgb_color_space.get(), sk_color_space_.get());
+ SkColorSpaceXform::New(sk_srgb_color_space.get(),
+ sk_icc_color_space.get());
if (!sk_color_space_xform) {
DLOG(ERROR) << "Parsed ICC profile but can't create SkColorSpaceXform.";
return kICCFailedToCreateXform;
}
- // Because this SkColorSpace can be used to construct a transform, we can use
- // it to create a LUT based color transform, at the very least. If we fail to
- // get any better approximation, we'll use sRGB as our approximation.
- primaries_ = ColorSpace::PrimaryID::ICC_BASED;
- transfer_ = ColorSpace::TransferID::ICC_BASED;
- ColorSpace::CreateSRGB().GetPrimaryMatrix(&to_XYZD50_);
- ColorSpace::CreateSRGB().GetTransferFunction(&transfer_fn_);
+ // Because this SkColorSpace can be used to construct a transform, mark it
+ // as "useable". Mark the "best approximation" as sRGB to start.
+ *useable_sk_color_space = sk_icc_color_space;
+ *parametric_color_space = ColorSpace::CreateSRGB();
- // A primary matrix is required for our parametric representations. Use it if
- // it exists.
+ // If our SkColorSpace representation is sRGB then return that.
+ if (SkColorSpace::Equals(sk_srgb_color_space.get(),
+ sk_icc_color_space.get())) {
+ return kICCExtractedSRGBColorSpace;
+ }
+
+ // A primary matrix is required for our parametric approximation.
SkMatrix44 to_XYZD50_matrix;
if (!sk_icc->toXYZD50(&to_XYZD50_matrix)) {
DLOG(ERROR) << "Failed to extract ICC profile primary matrix.";
return kICCFailedToExtractMatrix;
}
- primaries_ = ColorSpace::PrimaryID::CUSTOM;
- to_XYZD50_ = to_XYZD50_matrix;
- // Try to directly extract a numerical transfer function. Use it if it
- // exists.
+ // Try to directly extract a numerical transfer function.
SkColorSpaceTransferFn exact_tr_fn;
if (sk_icc->isNumericalTransferFn(&exact_tr_fn)) {
- transfer_ = ColorSpace::TransferID::CUSTOM;
- transfer_fn_ = exact_tr_fn;
+ *parametric_color_space =
+ gfx::ColorSpace::CreateCustom(to_XYZD50_matrix, exact_tr_fn);
return kICCExtractedMatrixAndAnalyticTrFn;
}
+ // If we fail to get a transfer function, use the sRGB transfer function,
+ // and return false to indicate that the gfx::ColorSpace isn't accurate, but
+ // we can construct accurate LUT transforms using the underlying
+ // SkColorSpace.
+ *parametric_color_space = gfx::ColorSpace::CreateCustom(
+ to_XYZD50_matrix, ColorSpace::TransferID::IEC61966_2_1);
+
// Attempt to fit a parametric transfer function to the table data in the
// profile.
SkColorSpaceTransferFn approx_tr_fn;
- if (!SkApproximateTransferFn(sk_icc, &transfer_fn_error_, &approx_tr_fn)) {
+ if (!SkApproximateTransferFn(sk_icc, parametric_tr_fn_max_error,
+ &approx_tr_fn)) {
DLOG(ERROR) << "Failed approximate transfer function.";
return kICCFailedToConvergeToApproximateTrFn;
}
@@ -260,16 +278,16 @@
// If this converged, but has too high error, use the sRGB transfer function
// from above.
const float kMaxError = 2.f / 256.f;
- if (transfer_fn_error_ >= kMaxError) {
+ if (*parametric_tr_fn_max_error >= kMaxError) {
DLOG(ERROR) << "Failed to accurately approximate transfer function, error: "
- << 256.f * transfer_fn_error_ << "/256";
+ << 256.f * (*parametric_tr_fn_max_error) << "/256";
return kICCFailedToApproximateTrFnAccurately;
};
// If the error is sufficiently low, declare that the approximation is
// accurate.
- transfer_ = ColorSpace::TransferID::CUSTOM;
- transfer_fn_ = approx_tr_fn;
+ *parametric_color_space =
+ gfx::ColorSpace::CreateCustom(to_XYZD50_matrix, approx_tr_fn);
return kICCExtractedMatrixAndApproximatedTrFn;
}
@@ -328,28 +346,14 @@
return data_;
}
-ColorSpace ICCProfile::GetColorSpace() const {
+const ColorSpace& ICCProfile::GetColorSpace() const {
g_cache.Get().TouchEntry(*this);
+ return color_space_;
+}
- ColorSpace color_space;
- if (!IsValid())
- return color_space;
- color_space.icc_profile_id_ = id_;
- color_space.icc_profile_sk_color_space_ = sk_color_space_;
- DCHECK(color_space.icc_profile_sk_color_space_);
- color_space.matrix_ = ColorSpace::MatrixID::RGB;
- color_space.range_ = ColorSpace::RangeID::FULL;
- if (primaries_ == ColorSpace::PrimaryID::CUSTOM ||
- primaries_ == ColorSpace::PrimaryID::ICC_BASED) {
- color_space.SetCustomPrimaries(to_XYZD50_);
- }
- color_space.primaries_ = primaries_;
- if (transfer_ == ColorSpace::TransferID::CUSTOM ||
- transfer_ == ColorSpace::TransferID::ICC_BASED) {
- color_space.SetCustomTransferFunction(transfer_fn_);
- }
- color_space.transfer_ = transfer_;
- return color_space;
+const ColorSpace& ICCProfile::GetParametricColorSpace() const {
+ g_cache.Get().TouchEntry(*this);
+ return parametric_color_space_;
}
// static
@@ -372,7 +376,34 @@
return;
// Parse the ICC profile
- analyze_result_ = Initialize();
+ sk_sp<SkColorSpace> useable_sk_color_space;
+ analyze_result_ =
+ ExtractColorSpaces(data_, ¶metric_color_space_,
+ ¶metric_tr_fn_error_, &useable_sk_color_space);
+ switch (analyze_result_) {
+ case kICCExtractedSRGBColorSpace:
+ case kICCExtractedMatrixAndAnalyticTrFn:
+ case kICCExtractedMatrixAndApproximatedTrFn:
+ // Successfully and accurately extracted color space.
+ color_space_ = parametric_color_space_;
+ break;
+ case kICCFailedToExtractRawTrFn:
+ case kICCFailedToExtractMatrix:
+ case kICCFailedToConvergeToApproximateTrFn:
+ case kICCFailedToApproximateTrFnAccurately:
+ // Successfully but extracted a color space, but it isn't accurate enough.
+ color_space_ = ColorSpace(ColorSpace::PrimaryID::ICC_BASED,
+ ColorSpace::TransferID::ICC_BASED);
+ color_space_.icc_profile_sk_color_space_ = useable_sk_color_space;
+ break;
+ case kICCFailedToParse:
+ case kICCFailedToExtractSkColorSpace:
+ case kICCFailedToCreateXform:
+ // Can't even use this color space as a LUT.
+ DCHECK(!parametric_color_space_.IsValid());
+ color_space_ = parametric_color_space_;
+ break;
+ }
// Add to the cache.
g_cache.Get().InsertAndSetIdIfNeeded(this);
@@ -398,7 +429,7 @@
if (nonlinear_fit_converged) {
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Blink.ColorSpace.Destination.NonlinearFitError",
- static_cast<int>(transfer_fn_error_ * 255), 0, 127, 16);
+ static_cast<int>(parametric_tr_fn_error_ * 255), 0, 127, 16);
}
}
diff --git a/ui/gfx/icc_profile.h b/ui/gfx/icc_profile.h
index 3c00e76..bfbdc4e 100644
--- a/ui/gfx/icc_profile.h
+++ b/ui/gfx/icc_profile.h
@@ -52,7 +52,12 @@
// Return a ColorSpace that references this ICCProfile. ColorTransforms
// created using this ColorSpace will match this ICCProfile precisely.
- ColorSpace GetColorSpace() const;
+ const ColorSpace& GetColorSpace() const;
+
+ // Return a ColorSpace that is the best parametric approximation of this
+ // ICCProfile. The resulting ColorSpace will reference this ICCProfile only
+ // if the parametric approximation is almost exact.
+ const ColorSpace& GetParametricColorSpace() const;
const std::vector<char>& GetData() const;
@@ -98,7 +103,12 @@
size_t size,
uint64_t id);
- AnalyzeResult Initialize();
+ static AnalyzeResult ExtractColorSpaces(
+ const std::vector<char>& data,
+ gfx::ColorSpace* parametric_color_space,
+ float* parametric_tr_fn_max_error,
+ sk_sp<SkColorSpace>* useable_sk_color_space);
+
void ComputeColorSpaceAndCache();
// This globally identifies this ICC profile. It is used to look up this ICC
@@ -110,21 +120,18 @@
// The result of attepting to extract a color space from the color profile.
AnalyzeResult analyze_result_ = kICCFailedToParse;
- // Results of Skia parsing the ICC profile data.
- sk_sp<SkColorSpace> sk_color_space_;
+ // |color_space| always links back to this ICC profile, and its SkColorSpace
+ // is always equal to the SkColorSpace created from this ICCProfile.
+ gfx::ColorSpace color_space_;
- // The best-fit parametric primaries.
- gfx::ColorSpace::PrimaryID primaries_;
- SkMatrix44 to_XYZD50_;
-
- // The best-fit parametric transfer function.
- gfx::ColorSpace::TransferID transfer_;
- SkColorSpaceTransferFn transfer_fn_;
+ // |parametric_color_space_| will only link back to this ICC profile if it
+ // is accurate, and its SkColorSpace will always be parametrically created.
+ gfx::ColorSpace parametric_color_space_;
// The L-infinity error of the parametric color space fit. This is undefined
// unless |analyze_result_| is kICCFailedToApproximateTrFnAccurately or
// kICCExtractedMatrixAndApproximatedTrFn.
- float transfer_fn_error_ = 0;
+ float parametric_tr_fn_error_ = -1;
FRIEND_TEST_ALL_PREFIXES(SimpleColorSpace, BT709toSRGBICC);
FRIEND_TEST_ALL_PREFIXES(SimpleColorSpace, GetColorSpace);
diff --git a/ui/gfx/icc_profile_unittest.cc b/ui/gfx/icc_profile_unittest.cc
index 186fceb..d9a008d 100644
--- a/ui/gfx/icc_profile_unittest.cc
+++ b/ui/gfx/icc_profile_unittest.cc
@@ -32,12 +32,8 @@
EXPECT_EQ(icc_profile.GetColorSpace().ToSkColorSpace().get(),
sk_color_space.get());
// The parametric generating code should recognize that this is SRGB.
- EXPECT_EQ(icc_profile.GetColorSpace().GetParametricApproximation(),
- ColorSpace::CreateSRGB());
- EXPECT_EQ(icc_profile.GetColorSpace()
- .GetParametricApproximation()
- .ToSkColorSpace()
- .get(),
+ EXPECT_EQ(icc_profile.GetParametricColorSpace(), ColorSpace::CreateSRGB());
+ EXPECT_EQ(icc_profile.GetParametricColorSpace().ToSkColorSpace().get(),
sk_color_space.get());
// The generated color space should recognize that this is SRGB.
EXPECT_EQ(color_space.ToSkColorSpace().get(), sk_color_space.get());
@@ -82,8 +78,7 @@
// This ICC profile has three transfer functions that differ enough that the
// parametric color space is considered inaccurate.
ICCProfile multi_tr_fn = ICCProfileForTestingNoAnalyticTrFn();
- EXPECT_NE(multi_tr_fn.GetColorSpace(),
- multi_tr_fn.GetColorSpace().GetParametricApproximation());
+ EXPECT_NE(multi_tr_fn.GetColorSpace(), multi_tr_fn.GetParametricColorSpace());
ICCProfile multi_tr_fn_color_space;
EXPECT_TRUE(
@@ -91,40 +86,35 @@
EXPECT_EQ(multi_tr_fn_color_space, multi_tr_fn);
ICCProfile multi_tr_fn_parametric_color_space;
- EXPECT_TRUE(
- multi_tr_fn.GetColorSpace().GetParametricApproximation().GetICCProfile(
- &multi_tr_fn_parametric_color_space));
+ EXPECT_TRUE(multi_tr_fn.GetParametricColorSpace().GetICCProfile(
+ &multi_tr_fn_parametric_color_space));
EXPECT_NE(multi_tr_fn_parametric_color_space, multi_tr_fn);
// This ICC profile has a transfer function with T(1) that is greater than 1
// in the approximation, but is still close enough to be considered accurate.
ICCProfile overshoot = ICCProfileForTestingOvershoot();
- EXPECT_EQ(overshoot.GetColorSpace(),
- overshoot.GetColorSpace().GetParametricApproximation());
+ EXPECT_EQ(overshoot.GetColorSpace(), overshoot.GetParametricColorSpace());
ICCProfile overshoot_color_space;
EXPECT_TRUE(overshoot.GetColorSpace().GetICCProfile(&overshoot_color_space));
EXPECT_EQ(overshoot_color_space, overshoot);
ICCProfile overshoot_parametric_color_space;
- EXPECT_TRUE(
- overshoot.GetColorSpace().GetParametricApproximation().GetICCProfile(
- &overshoot_parametric_color_space));
+ EXPECT_TRUE(overshoot.GetParametricColorSpace().GetICCProfile(
+ &overshoot_parametric_color_space));
EXPECT_EQ(overshoot_parametric_color_space, overshoot);
// This ICC profile is precisely represented by the parametric color space.
ICCProfile accurate = ICCProfileForTestingAdobeRGB();
- EXPECT_EQ(accurate.GetColorSpace(),
- accurate.GetColorSpace().GetParametricApproximation());
+ EXPECT_EQ(accurate.GetColorSpace(), accurate.GetParametricColorSpace());
ICCProfile accurate_color_space;
EXPECT_TRUE(accurate.GetColorSpace().GetICCProfile(&accurate_color_space));
EXPECT_EQ(accurate_color_space, accurate);
ICCProfile accurate_parametric_color_space;
- EXPECT_TRUE(
- accurate.GetColorSpace().GetParametricApproximation().GetICCProfile(
- &accurate_parametric_color_space));
+ EXPECT_TRUE(accurate.GetParametricColorSpace().GetICCProfile(
+ &accurate_parametric_color_space));
EXPECT_EQ(accurate_parametric_color_space, accurate);
// This ICC profile has only an A2B representation. We cannot create an
@@ -146,15 +136,12 @@
ICCProfile::FromData(bad_data.data(), bad_data.size());
EXPECT_FALSE(garbage_profile.IsValid());
EXPECT_FALSE(garbage_profile.GetColorSpace().IsValid());
- EXPECT_FALSE(
- garbage_profile.GetColorSpace().GetParametricApproximation().IsValid());
+ EXPECT_FALSE(garbage_profile.GetParametricColorSpace().IsValid());
ICCProfile default_ctor_profile;
EXPECT_FALSE(default_ctor_profile.IsValid());
EXPECT_FALSE(default_ctor_profile.GetColorSpace().IsValid());
- EXPECT_FALSE(default_ctor_profile.GetColorSpace()
- .GetParametricApproximation()
- .IsValid());
+ EXPECT_FALSE(default_ctor_profile.GetParametricColorSpace().IsValid());
}
TEST(ICCProfile, GenericRGB) {