diff options
author | raftias <raftias@google.com> | 2016-10-18 10:02:51 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-10-18 10:02:52 -0700 |
commit | 9488833428e83c93a7e6002f4d056084fb57112f (patch) | |
tree | 725cd5f30d3b685b3e7d18eb68a551d9b76ad5df /src/core/SkColorSpace.cpp | |
parent | b9eb887f8baa3dcf89b0106a799aff03b5c1cbba (diff) |
Refactored SkColorSpace and added in a Lab PCS GM
The refactoring breaks off A2B0 tag support into a separate
subclass of SkColorSpace_Base, while keeping the current
(besides CLUT) functionality in a XYZTRC subclass.
ICC profile loading is now aware of this and creates the A2B0
subclass when SkColorSpace::NewICC() is called on a profile
in need of the A2B0 functionality.
The LabPCSDemo GM loads a .icc profile containing a LAB PCS and
then runs a Lab->XYZ conversion on an image using it so we can
display it and test out the A2B0 SkColorSpace functionality,
sans a/b/m-curves, as well as the Lab->XYZ conversion code.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2389983002
Review-Url: https://codereview.chromium.org/2389983002
Diffstat (limited to 'src/core/SkColorSpace.cpp')
-rw-r--r-- | src/core/SkColorSpace.cpp | 136 |
1 files changed, 43 insertions, 93 deletions
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index b956c7fe3e..e90254c969 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -7,8 +7,8 @@ #include "SkColorSpace.h" #include "SkColorSpace_Base.h" +#include "SkColorSpace_XYZ.h" #include "SkColorSpacePriv.h" -#include "SkColorSpaceXform_Base.h" #include "SkOnce.h" #include "SkPoint3.h" @@ -83,23 +83,8 @@ bool SkColorSpacePrimaries::toXYZD50(SkMatrix44* toXYZ_D50) const { /////////////////////////////////////////////////////////////////////////////////////////////////// -SkColorSpace_Base::SkColorSpace_Base(SkGammaNamed gammaNamed, const SkMatrix44& toXYZD50) - : fGammaNamed(gammaNamed) - , fGammas(nullptr) - , fProfileData(nullptr) - , fToXYZD50(toXYZD50) - , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) -{} - -SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkColorLookUpTable> colorLUT, SkGammaNamed gammaNamed, - sk_sp<SkGammas> gammas, const SkMatrix44& toXYZD50, - sk_sp<SkData> profileData) - : fColorLUT(std::move(colorLUT)) - , fGammaNamed(gammaNamed) - , fGammas(std::move(gammas)) - , fProfileData(std::move(profileData)) - , fToXYZD50(toXYZD50) - , fFromXYZD50(SkMatrix44::kUninitialized_Constructor) +SkColorSpace_Base::SkColorSpace_Base(sk_sp<SkData> profileData) + : fProfileData(std::move(profileData)) {} static constexpr float gSRGB_toXYZD50[] { @@ -163,8 +148,8 @@ sk_sp<SkColorSpace> SkColorSpace::NewRGB(const float values[3], const SkMatrix44 gammas->fRedData.fValue = values[0]; gammas->fGreenData.fValue = values[1]; gammas->fBlueData.fValue = values[2]; - return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, kNonStandard_SkGammaNamed, gammas, - toXYZD50, nullptr)); + return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(kNonStandard_SkGammaNamed, + gammas, toXYZD50, nullptr)); } return SkColorSpace_Base::NewRGB(gammaNamed, toXYZD50); @@ -194,7 +179,7 @@ sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(SkGammaNamed gammaNamed, const SkM break; } - return sk_sp<SkColorSpace>(new SkColorSpace_Base(gammaNamed, toXYZD50)); + return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(gammaNamed, toXYZD50)); } sk_sp<SkColorSpace> SkColorSpace::NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50) { @@ -235,8 +220,8 @@ sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkColorSpaceTransferFn& coeffs, gammas->fRedData = data; gammas->fGreenData = data; gammas->fBlueData = data; - return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, kNonStandard_SkGammaNamed, - std::move(gammas), toXYZD50, nullptr)); + return sk_sp<SkColorSpace>(new SkColorSpace_XYZ(kNonStandard_SkGammaNamed, + std::move(gammas), toXYZD50, nullptr)); } static SkColorSpace* gAdobeRGB; @@ -256,7 +241,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { // Force the mutable type mask to be computed. This avoids races. (void)srgbToxyzD50.getType(); - gSRGB = new SkColorSpace_Base(kSRGB_SkGammaNamed, srgbToxyzD50); + gSRGB = new SkColorSpace_XYZ(kSRGB_SkGammaNamed, srgbToxyzD50); }); return sk_ref_sp<SkColorSpace>(gSRGB); } @@ -267,7 +252,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { // Force the mutable type mask to be computed. This avoids races. (void)adobergbToxyzD50.getType(); - gAdobeRGB = new SkColorSpace_Base(k2Dot2Curve_SkGammaNamed, adobergbToxyzD50); + gAdobeRGB = new SkColorSpace_XYZ(k2Dot2Curve_SkGammaNamed, adobergbToxyzD50); }); return sk_ref_sp<SkColorSpace>(gAdobeRGB); } @@ -278,7 +263,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { // Force the mutable type mask to be computed. This avoids races. (void)srgbToxyzD50.getType(); - gSRGBLinear = new SkColorSpace_Base(kLinear_SkGammaNamed, srgbToxyzD50); + gSRGBLinear = new SkColorSpace_XYZ(kLinear_SkGammaNamed, srgbToxyzD50); }); return sk_ref_sp<SkColorSpace>(gSRGBLinear); } @@ -288,53 +273,14 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) { return nullptr; } -sk_sp<SkColorSpace> SkColorSpace_Base::makeLinearGamma() { - if (this->gammaIsLinear()) { - return sk_ref_sp(this); - } - return SkColorSpace_Base::NewRGB(kLinear_SkGammaNamed, as_CSB(this)->fToXYZD50); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// bool SkColorSpace::gammaCloseToSRGB() const { - return kSRGB_SkGammaNamed == as_CSB(this)->fGammaNamed || - k2Dot2Curve_SkGammaNamed == as_CSB(this)->fGammaNamed; + return as_CSB(this)->onGammaCloseToSRGB(); } bool SkColorSpace::gammaIsLinear() const { - return kLinear_SkGammaNamed == as_CSB(this)->fGammaNamed; -} - -const SkMatrix44& SkColorSpace_Base::fromXYZD50() const { - fFromXYZOnce([this] { - if (!fToXYZD50.invert(&fFromXYZD50)) { - // If a client gives us a dst gamut with a transform that we can't invert, we will - // simply give them back a transform to sRGB gamut. - SkDEBUGFAIL("Non-invertible XYZ matrix, defaulting to sRGB"); - SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); - srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50); - srgbToxyzD50.invert(&fFromXYZD50); - } - }); - return fFromXYZD50; -} - -void SkColorSpace_Base::toDstGammaTables(const uint8_t* tables[3], sk_sp<SkData>* storage, - int numTables) const { - fToDstGammaOnce([this, numTables] { - const bool gammasAreMatching = numTables <= 1; - fDstStorage = - SkData::MakeUninitialized(numTables * SkColorSpaceXform_Base::kDstGammaTableSize); - SkColorSpaceXform_Base::BuildDstGammaTables(fToDstGammaTables, - (uint8_t*) fDstStorage->writable_data(), this, - gammasAreMatching); - }); - - *storage = fDstStorage; - tables[0] = fToDstGammaTables[0]; - tables[1] = fToDstGammaTables[1]; - tables[2] = fToDstGammaTables[2]; + return as_CSB(this)->onGammaIsLinear(); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -403,51 +349,52 @@ size_t SkColorSpace::writeToMemory(void* memory) const { // Start by trying the serialization fast path. If we haven't saved ICC profile data, // we must have a profile that we can serialize easily. if (!as_CSB(this)->fProfileData) { + // Profile data is mandatory for A2B0 color spaces. + SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(this)->type()); + const SkColorSpace_XYZ* thisXYZ = static_cast<const SkColorSpace_XYZ*>(this); // If we have a named profile, only write the enum. + const SkGammaNamed gammaNamed = thisXYZ->gammaNamed(); if (this == gSRGB) { if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, kSRGB_Named, - as_CSB(this)->fGammaNamed, 0); + ColorSpaceHeader::Pack(k0_Version, kSRGB_Named, gammaNamed, 0); } return sizeof(ColorSpaceHeader); } else if (this == gAdobeRGB) { if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, kAdobeRGB_Named, - as_CSB(this)->fGammaNamed, 0); + ColorSpaceHeader::Pack(k0_Version, kAdobeRGB_Named, gammaNamed, 0); } return sizeof(ColorSpaceHeader); } else if (this == gSRGBLinear) { if (memory) { - *((ColorSpaceHeader*)memory) = - ColorSpaceHeader::Pack(k0_Version, kSRGBLinear_Named, - as_CSB(this)->fGammaNamed, 0); + *((ColorSpaceHeader*) memory) = + ColorSpaceHeader::Pack(k0_Version, kSRGBLinear_Named, gammaNamed, 0); } return sizeof(ColorSpaceHeader); } // If we have a named gamma, write the enum and the matrix. - switch (as_CSB(this)->fGammaNamed) { + switch (gammaNamed) { case kSRGB_SkGammaNamed: case k2Dot2Curve_SkGammaNamed: case kLinear_SkGammaNamed: { if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, + ColorSpaceHeader::Pack(k0_Version, 0, gammaNamed, ColorSpaceHeader::kMatrix_Flag); memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader)); - as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + thisXYZ->toXYZD50()->as3x4RowMajorf((float*) memory); } return sizeof(ColorSpaceHeader) + 12 * sizeof(float); } default: - const SkGammas* gammas = as_CSB(this)->gammas(); + const SkGammas* gammas = thisXYZ->gammas(); SkASSERT(gammas); if (gammas->isValue(0) && gammas->isValue(1) && gammas->isValue(2)) { if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, + ColorSpaceHeader::Pack(k0_Version, 0, thisXYZ->fGammaNamed, ColorSpaceHeader::kFloatGamma_Flag); memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader)); @@ -456,7 +403,7 @@ size_t SkColorSpace::writeToMemory(void* memory) const { *(((float*) memory) + 2) = gammas->fBlueData.fValue; memory = SkTAddOffset<void>(memory, 3 * sizeof(float)); - as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + thisXYZ->fToXYZD50.as3x4RowMajorf((float*) memory); } return sizeof(ColorSpaceHeader) + 15 * sizeof(float); @@ -469,7 +416,7 @@ size_t SkColorSpace::writeToMemory(void* memory) const { if (memory) { *((ColorSpaceHeader*) memory) = - ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed, + ColorSpaceHeader::Pack(k0_Version, 0, thisXYZ->fGammaNamed, ColorSpaceHeader::kTransferFn_Flag); memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader)); @@ -482,7 +429,7 @@ size_t SkColorSpace::writeToMemory(void* memory) const { *(((float*) memory) + 6) = gammas->params(0).fG; memory = SkTAddOffset<void>(memory, 7 * sizeof(float)); - as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory); + thisXYZ->fToXYZD50.as3x4RowMajorf((float*) memory); } return sizeof(ColorSpaceHeader) + 19 * sizeof(float); @@ -624,23 +571,26 @@ bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) { return false; } - // It's important to check fProfileData before named gammas. Some profiles may have named - // gammas, but also include other wacky features that cause us to save the data. - switch (as_CSB(src)->fGammaNamed) { + // profiles are mandatory for A2B0 color spaces + SkASSERT(as_CSB(src)->type() == SkColorSpace_Base::Type::kXYZ); + const SkColorSpace_XYZ* srcXYZ = static_cast<const SkColorSpace_XYZ*>(src); + const SkColorSpace_XYZ* dstXYZ = static_cast<const SkColorSpace_XYZ*>(dst); + + switch (srcXYZ->gammaNamed()) { case kSRGB_SkGammaNamed: case k2Dot2Curve_SkGammaNamed: case kLinear_SkGammaNamed: - return (as_CSB(src)->fGammaNamed == as_CSB(dst)->fGammaNamed) && - (as_CSB(src)->fToXYZD50 == as_CSB(dst)->fToXYZD50); + return (srcXYZ->gammaNamed() == dstXYZ->gammaNamed()) && + (*srcXYZ->toXYZD50() == *dstXYZ->toXYZD50()); default: - if (as_CSB(src)->fGammaNamed != as_CSB(dst)->fGammaNamed) { + if (srcXYZ->gammaNamed() != dstXYZ->gammaNamed()) { return false; } - // It is unlikely that we will reach this case. - sk_sp<SkData> srcData = src->serialize(); - sk_sp<SkData> dstData = dst->serialize(); - return srcData->size() == dstData->size() && - 0 == memcmp(srcData->data(), dstData->data(), srcData->size()); + sk_sp<SkData> serializedSrcData = src->serialize(); + sk_sp<SkData> serializedDstData = dst->serialize(); + return serializedSrcData->size() == serializedDstData->size() && + 0 == memcmp(serializedSrcData->data(), serializedDstData->data(), + serializedSrcData->size()); } } |