From: msarett Date: Tue, 17 May 2016 16:31:20 +0000 (-0700) Subject: Prepare SkColorSpace to be a public API X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~129^2~488 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bb9f77437dad6a127840e6898edb3f811e3e9e94;p=platform%2Fupstream%2FlibSkiaSharp.git Prepare SkColorSpace to be a public API Moves implementation details into SkColorSpacePriv.h BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1985903002 Review-Url: https://codereview.chromium.org/1985903002 --- diff --git a/gm/color4f.cpp b/gm/color4f.cpp index 829434c..ffe9a87 100644 --- a/gm/color4f.cpp +++ b/gm/color4f.cpp @@ -95,6 +95,8 @@ DEF_SIMPLE_GM(color4shader, canvas, 1024, 260) { // red -> blue, green -> red, blue -> green mat.set3x3(0, 1, 0, 0, 0, 1, 1, 0, 0); + float linearGamma[3] = { 1.0f, 1.0f, 1.0f }; + const SkColor4f colors[] { { 1, 1, 0, 0 }, { 1, 0, 1, 0 }, @@ -109,8 +111,7 @@ DEF_SIMPLE_GM(color4shader, canvas, 1024, 260) { sk_sp shaders[] { SkShader::MakeColorShader(c4, nullptr), SkShader::MakeColorShader(c4, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)), - SkShader::MakeColorShader(c4, SkColorSpace::NewRGB(SkColorSpace::SkGammas(1, 1, 1), - mat)), + SkShader::MakeColorShader(c4, SkColorSpace::NewRGB(linearGamma, mat)), }; canvas->save(); diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 4bd87ed..84d2575 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -210,7 +210,7 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { png_fixed_point XYZ[9]; float toXYZD50[9]; png_fixed_point gamma; - SkColorSpace::SkGammas gammas; + float gammas[3]; if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &XYZ[0], &XYZ[1], &XYZ[2], &XYZ[3], &XYZ[4], &XYZ[5], &XYZ[6], &XYZ[7], &XYZ[8])) { @@ -226,17 +226,21 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { float value = png_inverted_fixed_point_to_float(gamma); - gammas = SkColorSpace::SkGammas(value, value, value); + gammas[0] = value; + gammas[1] = value; + gammas[2] = value; } else { // Default to sRGB (gamma = 2.2f) if the image has color space information, // but does not specify gamma. - gammas = SkColorSpace::SkGammas(2.2f, 2.2f, 2.2f); + gammas[0] = 2.2f; + gammas[1] = 2.2f; + gammas[2] = 2.2f; } SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); mat.set3x3ColMajorf(toXYZD50); - return SkColorSpace::NewRGB(std::move(gammas), mat); + return SkColorSpace::NewRGB(gammas, mat); } // Last, check for gamma. @@ -247,9 +251,11 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { // Set the gammas. float value = png_inverted_fixed_point_to_float(gamma); - gammas = SkColorSpace::SkGammas(value, value, value); + gammas[0] = value; + gammas[1] = value; + gammas[2] = value; - return SkColorSpace::NewRGB(std::move(gammas), SkMatrix44::I()); + return SkColorSpace::NewRGB(gammas, SkMatrix44::I()); } #endif // LIBPNG >= 1.6 diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp index cc8d0b0..172082b 100644 --- a/src/core/SkColorSpace.cpp +++ b/src/core/SkColorSpace.cpp @@ -7,31 +7,28 @@ #include "SkAtomics.h" #include "SkColorSpace.h" +#include "SkColorSpacePriv.h" #include "SkOnce.h" static bool color_space_almost_equal(float a, float b) { return SkTAbs(a - b) < 0.01f; } -void SkFloat3::dump() const { - SkDebugf("[%7.4f %7.4f %7.4f]\n", fVec[0], fVec[1], fVec[2]); -} - ////////////////////////////////////////////////////////////////////////////////////////////////// static int32_t gUniqueColorSpaceID; -SkColorSpace::SkColorSpace(SkGammas gammas, const SkMatrix44& toXYZD50, Named named) - : fGammas(std::move(gammas)) +SkColorSpace::SkColorSpace(sk_sp gammas, const SkMatrix44& toXYZD50, Named named) + : fGammas(gammas) , fToXYZD50(toXYZD50) , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) , fNamed(named) {} -SkColorSpace::SkColorSpace(SkColorLookUpTable colorLUT, SkGammas gammas, +SkColorSpace::SkColorSpace(SkColorLookUpTable* colorLUT, sk_sp gammas, const SkMatrix44& toXYZD50) - : fColorLUT(std::move(colorLUT)) - , fGammas(std::move(gammas)) + : fColorLUT(colorLUT) + , fGammas(gammas) , fToXYZD50(toXYZD50) , fUniqueID(sk_atomic_inc(&gUniqueColorSpaceID)) , fNamed(kUnknown_Named) @@ -74,12 +71,22 @@ static bool xyz_almost_equal(const SkMatrix44& toXYZD50, const float* standard) color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f); } -sk_sp SkColorSpace::NewRGB(SkGammas gammas, const SkMatrix44& toXYZD50) { +static SkOnce gStandardGammasOnce; +static SkGammas* gStandardGammas; + +sk_sp SkColorSpace::NewRGB(float gammaVals[3], const SkMatrix44& toXYZD50) { + sk_sp gammas = nullptr; + // Check if we really have sRGB or Adobe RGB - if (color_space_almost_equal(2.2f, gammas.fRed.fValue) && - color_space_almost_equal(2.2f, gammas.fGreen.fValue) && - color_space_almost_equal(2.2f, gammas.fBlue.fValue)) + if (color_space_almost_equal(2.2f, gammaVals[0]) && + color_space_almost_equal(2.2f, gammaVals[1]) && + color_space_almost_equal(2.2f, gammaVals[2])) { + gStandardGammasOnce([] { + gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); + }); + gammas = sk_ref_sp(gStandardGammas); + if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) { return SkColorSpace::NewNamed(kSRGB_Named); } else if (xyz_almost_equal(toXYZD50, gAdobeRGB_toXYZD50)) { @@ -87,7 +94,10 @@ sk_sp SkColorSpace::NewRGB(SkGammas gammas, const SkMatrix44& toXY } } - return sk_sp(new SkColorSpace(std::move(gammas), toXYZD50, kUnknown_Named)); + if (!gammas) { + gammas = sk_ref_sp(new SkGammas(gammaVals[0], gammaVals[1], gammaVals[2])); + } + return sk_sp(new SkColorSpace(gammas, toXYZD50, kUnknown_Named)); } sk_sp SkColorSpace::NewNamed(Named named) { @@ -98,18 +108,26 @@ sk_sp SkColorSpace::NewNamed(Named named) { switch (named) { case kSRGB_Named: { + gStandardGammasOnce([] { + gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); + }); + sRGBOnce([] { SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); srgbToxyzD50.set3x3ColMajorf(gSRGB_toXYZD50); - sRGB = new SkColorSpace(SkGammas(2.2f, 2.2f, 2.2f), srgbToxyzD50, kSRGB_Named); + sRGB = new SkColorSpace(sk_ref_sp(gStandardGammas), srgbToxyzD50, kSRGB_Named); }); return sk_ref_sp(sRGB); } case kAdobeRGB_Named: { + gStandardGammasOnce([] { + gStandardGammas = new SkGammas(2.2f, 2.2f, 2.2f); + }); + adobeRGBOnce([] { SkMatrix44 adobergbToxyzD50(SkMatrix44::kUninitialized_Constructor); adobergbToxyzD50.set3x3ColMajorf(gAdobeRGB_toXYZD50); - adobeRGB = new SkColorSpace(SkGammas(2.2f, 2.2f, 2.2f), adobergbToxyzD50, + adobeRGB = new SkColorSpace(sk_ref_sp(gStandardGammas), adobergbToxyzD50, kAdobeRGB_Named); }); return sk_ref_sp(adobeRGB); @@ -536,7 +554,7 @@ bool load_matrix(SkMatrix44* toXYZ, const uint8_t* src, size_t len) { return true; } -bool SkColorSpace::LoadA2B0(SkColorLookUpTable* colorLUT, SkGammas* gammas, SkMatrix44* toXYZ, +bool SkColorSpace::LoadA2B0(SkColorLookUpTable* colorLUT, sk_sp gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len) { if (len < 32) { SkColorSpacePrintf("A to B tag is too small (%d bytes).", len); @@ -662,47 +680,62 @@ sk_sp SkColorSpace::NewICC(const void* base, size_t len) { // It is not uncommon to see missing or empty gamma tags. This indicates // that we should use unit gamma. - SkGammas gammas; + sk_sp gammas(new SkGammas()); r = ICCTag::Find(tags.get(), tagCount, kTAG_rTRC); g = ICCTag::Find(tags.get(), tagCount, kTAG_gTRC); b = ICCTag::Find(tags.get(), tagCount, kTAG_bTRC); - if (!r || !SkColorSpace::LoadGammas(&gammas.fRed, 1, + if (!r || !SkColorSpace::LoadGammas(&gammas->fRed, 1, r->addr((const uint8_t*) base), r->fLength)) { SkColorSpacePrintf("Failed to read R gamma tag.\n"); } - if (!g || !SkColorSpace::LoadGammas(&gammas.fGreen, 1, + if (!g || !SkColorSpace::LoadGammas(&gammas->fGreen, 1, g->addr((const uint8_t*) base), g->fLength)) { SkColorSpacePrintf("Failed to read G gamma tag.\n"); } - if (!b || !SkColorSpace::LoadGammas(&gammas.fBlue, 1, + if (!b || !SkColorSpace::LoadGammas(&gammas->fBlue, 1, b->addr((const uint8_t*) base), b->fLength)) { SkColorSpacePrintf("Failed to read B gamma tag.\n"); } SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); mat.set3x3ColMajorf(toXYZ); - return SkColorSpace::NewRGB(std::move(gammas), mat); + if (gammas->isValues()) { + // When we have values, take advantage of the NewFromRGB initializer. + // This allows us to check for canonical sRGB and Adobe RGB. + float gammaVals[3]; + gammaVals[0] = gammas->fRed.fValue; + gammaVals[1] = gammas->fGreen.fValue; + gammaVals[2] = gammas->fBlue.fValue; + return SkColorSpace::NewRGB(gammaVals, mat); + } else { + return sk_sp(new SkColorSpace(gammas, mat, kUnknown_Named)); + } } // Recognize color profile specified by A2B0 tag. const ICCTag* a2b0 = ICCTag::Find(tags.get(), tagCount, kTAG_A2B0); if (a2b0) { - SkColorLookUpTable colorLUT; - SkGammas gammas; + SkAutoTDelete colorLUT(new SkColorLookUpTable()); + sk_sp gammas(new SkGammas()); SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor); - if (!SkColorSpace::LoadA2B0(&colorLUT, &gammas, &toXYZ, + if (!SkColorSpace::LoadA2B0(colorLUT, gammas, &toXYZ, a2b0->addr((const uint8_t*) base), a2b0->fLength)) { return_null("Failed to parse A2B0 tag"); } - // If there is no colorLUT, use NewRGB. This allows us to check if the - // profile is sRGB. - if (!colorLUT.fTable) { - return SkColorSpace::NewRGB(std::move(gammas), toXYZ); + if (colorLUT->fTable) { + return sk_sp(new SkColorSpace(colorLUT.release(), gammas, toXYZ)); + } else if (gammas->isValues()) { + // When we have values, take advantage of the NewFromRGB initializer. + // This allows us to check for canonical sRGB and Adobe RGB. + float gammaVals[3]; + gammaVals[0] = gammas->fRed.fValue; + gammaVals[1] = gammas->fGreen.fValue; + gammaVals[2] = gammas->fBlue.fValue; + return SkColorSpace::NewRGB(gammaVals, toXYZ); + } else { + return sk_sp(new SkColorSpace(gammas, toXYZ, kUnknown_Named)); } - - return sk_sp(new SkColorSpace(std::move(colorLUT), std::move(gammas), - toXYZ)); } } diff --git a/src/core/SkColorSpace.h b/src/core/SkColorSpace.h index 52b8973..ccbaa25 100644 --- a/src/core/SkColorSpace.h +++ b/src/core/SkColorSpace.h @@ -21,107 +21,32 @@ // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html // -#include "SkRefCnt.h" #include "SkMatrix44.h" +#include "SkRefCnt.h" +#include "SkTemplates.h" -struct SkFloat3 { - float fVec[3]; - - void dump() const; -}; +struct SkColorLookUpTable; +struct SkGammaCurve; +struct SkGammas; class SkColorSpace : public SkRefCnt { -private: - struct SkGammaCurve { - bool isValue() const { - bool result = (0.0f != fValue); - SkASSERT(!result || (0 == fTableSize)); - return result; - } - - bool isTable() const { - bool result = (0 != fTableSize); - SkASSERT(!result || (0.0f == fValue)); - SkASSERT(!result || fTable); - return result; - } - - bool isParametric() const { return false; } - - // We have three different ways to represent gamma. - // (1) A single value: - float fValue; - - // (2) A lookup table: - uint32_t fTableSize; - std::unique_ptr fTable; - - // (3) Parameters for a curve: - // FIXME (msarett): Handle parametric curves. - - SkGammaCurve() { - memset(this, 0, sizeof(struct SkGammaCurve)); - } - - SkGammaCurve(float value) - : fValue(value) - , fTableSize(0) - , fTable(nullptr) - {} - }; - - struct SkColorLookUpTable { - static const uint8_t kMaxChannels = 16; - - uint8_t fInputChannels; - uint8_t fOutputChannels; - uint8_t fGridPoints[kMaxChannels]; - std::unique_ptr fTable; - - SkColorLookUpTable() { - memset(this, 0, sizeof(struct SkColorLookUpTable)); - } - }; - public: + enum Named { kUnknown_Named, kSRGB_Named, kAdobeRGB_Named, }; - struct SkGammas { - public: - SkGammas(float red, float green, float blue) - : fRed(red) - , fGreen(green) - , fBlue(blue) - {} - - SkGammas() {} - - SkDEBUGCODE(float red() const { return fRed.fValue; }) - SkDEBUGCODE(float green() const { return fGreen.fValue; }) - SkDEBUGCODE(float blue() const { return fBlue.fValue; }) - - private: - SkGammaCurve fRed; - SkGammaCurve fGreen; - SkGammaCurve fBlue; - - friend class SkColorSpace; - }; - /** - * Return a colorspace instance, given a transform from linear_RGB to D50_XYZ - * and the src-gamma, return a ColorSpace + * Given the src gamma and a transform from src gamut to D50_XYZ, return a SkColorSpace. */ - static sk_sp NewRGB(SkGammas gammas, const SkMatrix44& toXYZD50); + static sk_sp NewRGB(float gammas[3], const SkMatrix44& toXYZD50); static sk_sp NewNamed(Named); static sk_sp NewICC(const void*, size_t); - const SkGammas& gammas() const { return fGammas; } + SkGammas* gammas() const { return fGammas.get(); } SkMatrix44 xyz() const { return fToXYZD50; } Named named() const { return fNamed; } uint32_t uniqueID() const { return fUniqueID; } @@ -135,20 +60,19 @@ private: uint32_t outputChannels, const uint8_t* src, size_t len); - static bool LoadA2B0(SkColorLookUpTable* colorLUT, SkGammas* gammas, SkMatrix44* toXYZ, + static bool LoadA2B0(SkColorLookUpTable* colorLUT, sk_sp gammas, SkMatrix44* toXYZ, const uint8_t* src, size_t len); - SkColorSpace(SkGammas gammas, const SkMatrix44& toXYZ, Named); + SkColorSpace(sk_sp gammas, const SkMatrix44& toXYZ, Named); - SkColorSpace(SkColorLookUpTable colorLUT, SkGammas gammas, - const SkMatrix44& toXYZ); + SkColorSpace(SkColorLookUpTable* colorLUT, sk_sp gammas, const SkMatrix44& toXYZ); - const SkColorLookUpTable fColorLUT; - const SkGammas fGammas; - const SkMatrix44 fToXYZD50; + SkAutoTDelete fColorLUT; + sk_sp fGammas; + const SkMatrix44 fToXYZD50; - const uint32_t fUniqueID; - const Named fNamed; + const uint32_t fUniqueID; + const Named fNamed; }; #endif diff --git a/src/core/SkColorSpacePriv.h b/src/core/SkColorSpacePriv.h new file mode 100644 index 0000000..a07640b --- /dev/null +++ b/src/core/SkColorSpacePriv.h @@ -0,0 +1,83 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorSpacePriv_DEFINED +#define SkColorSpacePriv_DEFINED + +struct SkGammaCurve { + bool isValue() const { + bool result = (0.0f != fValue); + SkASSERT(!result || (0 == fTableSize)); + return result; + } + + bool isTable() const { + bool result = (0 != fTableSize); + SkASSERT(!result || (0.0f == fValue)); + SkASSERT(!result || fTable); + return result; + } + + bool isParametric() const { return false; } + + // We have three different ways to represent gamma. + // (1) A single value: + float fValue; + + // (2) A lookup table: + uint32_t fTableSize; + std::unique_ptr fTable; + + // (3) Parameters for a curve: + // FIXME (msarett): Handle parametric curves. + + SkGammaCurve() { + memset(this, 0, sizeof(struct SkGammaCurve)); + } + + SkGammaCurve(float value) + : fValue(value) + , fTableSize(0) + , fTable(nullptr) + {} +}; + +struct SkGammas : public SkRefCnt { +public: + bool isValues() const { + return fRed.isValue() && fGreen.isValue() && fBlue.isValue(); + } + + SkGammaCurve fRed; + SkGammaCurve fGreen; + SkGammaCurve fBlue; + + SkGammas(float red, float green, float blue) + : fRed(red) + , fGreen(green) + , fBlue(blue) + {} + + SkGammas() {} + + friend class SkColorSpace; +}; + +struct SkColorLookUpTable { + static const uint8_t kMaxChannels = 16; + + uint8_t fInputChannels; + uint8_t fOutputChannels; + uint8_t fGridPoints[kMaxChannels]; + std::unique_ptr fTable; + + SkColorLookUpTable() { + memset(this, 0, sizeof(struct SkColorLookUpTable)); + } +}; + +#endif diff --git a/tests/ColorSpaceTest.cpp b/tests/ColorSpaceTest.cpp index 17332d7..698c3e9 100644 --- a/tests/ColorSpaceTest.cpp +++ b/tests/ColorSpaceTest.cpp @@ -8,6 +8,7 @@ #include "Resources.h" #include "SkCodec.h" #include "SkColorSpace.h" +#include "SkColorSpacePriv.h" #include "Test.h" #include "png.h" @@ -19,12 +20,12 @@ static bool almost_equal(float a, float b) { static void test_space(skiatest::Reporter* r, SkColorSpace* space, const float red[], const float green[], const float blue[], const float expectedGammas[]) { -#ifdef SK_DEBUG - const SkColorSpace::SkGammas& gammas = space->gammas(); - REPORTER_ASSERT(r, almost_equal(expectedGammas[0], gammas.red())); - REPORTER_ASSERT(r, almost_equal(expectedGammas[1], gammas.green())); - REPORTER_ASSERT(r, almost_equal(expectedGammas[2], gammas.blue())); -#endif + + SkGammas* gammas = space->gammas(); + REPORTER_ASSERT(r, almost_equal(expectedGammas[0], gammas->fRed.fValue)); + REPORTER_ASSERT(r, almost_equal(expectedGammas[1], gammas->fGreen.fValue)); + REPORTER_ASSERT(r, almost_equal(expectedGammas[2], gammas->fBlue.fValue)); + SkMatrix44 mat = space->xyz(); const float src[] = { @@ -106,16 +107,16 @@ DEF_TEST(ColorSpaceSRGBCompare, r) { // Create an sRGB color space by name sk_sp namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); + // Create an sRGB color space by value SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor); + float sRGBGammas[3] = { 2.2f, 2.2f, 2.2f }; srgbToxyzD50.set3x3ColMajorf(g_sRGB_XYZ); - sk_sp rgbColorSpace = SkColorSpace::NewRGB( - SkColorSpace::SkGammas(2.2f, 2.2f, 2.2f), srgbToxyzD50); + sk_sp rgbColorSpace = SkColorSpace::NewRGB(sRGBGammas, srgbToxyzD50); REPORTER_ASSERT(r, namedColorSpace == namedColorSpace); // Change a single value from the sRGB matrix srgbToxyzD50.set(2, 2, 0.5f); - sk_sp strangeColorSpace = SkColorSpace::NewRGB( - SkColorSpace::SkGammas(2.2f, 2.2f, 2.2f), srgbToxyzD50); + sk_sp strangeColorSpace = SkColorSpace::NewRGB(sRGBGammas, srgbToxyzD50); REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace); }