Add SkColorSpaceTransferFn to SkColorSpace
authorMatt Sarett <msarett@google.com>
Tue, 11 Oct 2016 20:57:50 +0000 (16:57 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 11 Oct 2016 21:59:09 +0000 (21:59 +0000)
BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3178

Change-Id: I354342d4469cee0e25a7b0d189e925e431da623c
Reviewed-on: https://skia-review.googlesource.com/3178
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>

include/core/SkColorSpace.h
src/core/SkColorSpace.cpp
src/core/SkColorSpacePriv.h
src/core/SkColorSpaceXform.cpp
src/core/SkColorSpace_Base.h
src/core/SkColorSpace_ICC.cpp
tests/ColorSpaceTest.cpp
tests/ColorSpaceXformTest.cpp

index 9b990da..b1daf4f 100644 (file)
@@ -29,6 +29,27 @@ struct SK_API SkColorSpacePrimaries {
     bool toXYZD50(SkMatrix44* toXYZD50) const;
 };
 
+/**
+ *  Contains the coefficients for a common transfer function equation, specified as
+ *  a transformation from a curved space to linear.
+ *
+ *  LinearVal = E*InputVal + F        , for 0.0f <= InputVal <  D
+ *  LinearVal = (A*InputVal + B)^G + C, for D    <= InputVal <= 1.0f
+ *
+ *  Function is undefined if InputVal is not in [ 0.0f, 1.0f ].
+ *  Resulting LinearVals must be in [ 0.0f, 1.0f ].
+ *  Function must be positive and increasing.
+ */
+struct SK_API SkColorSpaceTransferFn {
+    float fG;
+    float fA;
+    float fB;
+    float fC;
+    float fD;
+    float fE;
+    float fF;
+};
+
 class SK_API SkColorSpace : public SkRefCnt {
 public:
 
@@ -68,10 +89,12 @@ public:
     /**
      *  Create an SkColorSpace from a transfer function and a color gamut.
      *
-     *  Transfer function is specified as linear or sRGB.
+     *  Transfer function can be specified as a render target or as the coefficients to an equation.
      *  Gamut is specified using the matrix transformation to XYZ D50.
      */
     static sk_sp<SkColorSpace> NewRGB(RenderTargetGamma gamma, const SkMatrix44& toXYZD50);
+    static sk_sp<SkColorSpace> NewRGB(const SkColorSpaceTransferFn& coeffs,
+                                      const SkMatrix44& toXYZD50);
 
     /**
      *  Create a common, named SkColorSpace.
index 66b980b..6c4b474 100644 (file)
 #include "SkOnce.h"
 #include "SkPoint3.h"
 
-static inline bool is_zero_to_one(float v) {
-    return (0.0f <= v) && (v <= 1.0f);
-}
-
 bool SkColorSpacePrimaries::toXYZD50(SkMatrix44* toXYZ_D50) const {
     if (!is_zero_to_one(fRX) || !is_zero_to_one(fRY) ||
         !is_zero_to_one(fGX) || !is_zero_to_one(fGY) ||
@@ -211,6 +207,37 @@ sk_sp<SkColorSpace> SkColorSpace::NewRGB(RenderTargetGamma gamma, const SkMatrix
     }
 }
 
+sk_sp<SkColorSpace> SkColorSpace::NewRGB(const SkColorSpaceTransferFn& coeffs,
+                                         const SkMatrix44& toXYZD50) {
+    if (!is_valid_transfer_fn(coeffs)) {
+        return nullptr;
+    }
+
+    if (is_almost_srgb(coeffs)) {
+        return SkColorSpace::NewRGB(kSRGB_RenderTargetGamma, toXYZD50);
+    }
+
+    if (is_almost_2dot2(coeffs)) {
+        return SkColorSpace_Base::NewRGB(k2Dot2Curve_SkGammaNamed, toXYZD50);
+    }
+
+    void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
+    sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
+    SkColorSpaceTransferFn* fn = SkTAddOffset<SkColorSpaceTransferFn>(memory, sizeof(SkGammas));
+    *fn = coeffs;
+    gammas->fRedType = SkGammas::Type::kParam_Type;
+    gammas->fGreenType = SkGammas::Type::kParam_Type;
+    gammas->fBlueType = SkGammas::Type::kParam_Type;
+
+    SkGammas::Data data;
+    data.fParamOffset = 0;
+    gammas->fRedData = data;
+    gammas->fGreenData = data;
+    gammas->fBlueData = data;
+    return sk_sp<SkColorSpace>(new SkColorSpace_Base(nullptr, kNonStandard_SkGammaNamed,
+                                                     std::move(gammas), toXYZD50, nullptr));
+}
+
 static SkColorSpace* gAdobeRGB;
 static SkColorSpace* gSRGB;
 static SkColorSpace* gSRGBLinear;
@@ -300,8 +327,12 @@ enum Version {
 
 struct ColorSpaceHeader {
     /**
+     *  It is only valid to set zero or one flags.
+     *  Setting multiple flags is invalid.
+     */
+
+    /**
      *  If kMatrix_Flag is set, we will write 12 floats after the header.
-     *  Should not be set at the same time as the kICC_Flag or kFloatGamma_Flag.
      */
     static constexpr uint8_t kMatrix_Flag     = 1 << 0;
 
@@ -309,7 +340,6 @@ struct ColorSpaceHeader {
      *  If kICC_Flag is set, we will write an ICC profile after the header.
      *  The ICC profile will be written as a uint32 size, followed immediately
      *  by the data (padded to 4 bytes).
-     *  Should not be set at the same time as the kMatrix_Flag or kFloatGamma_Flag.
      */
     static constexpr uint8_t kICC_Flag        = 1 << 1;
 
@@ -317,10 +347,16 @@ struct ColorSpaceHeader {
      *  If kFloatGamma_Flag is set, we will write 15 floats after the header.
      *  The first three are the gamma values, and the next twelve are the
      *  matrix.
-     *  Should not be set at the same time as the kICC_Flag or kMatrix_Flag.
      */
     static constexpr uint8_t kFloatGamma_Flag = 1 << 2;
 
+    /**
+     *  If kTransferFn_Flag is set, we will write 19 floats after the header.
+     *  The first seven represent the transfer fn, and the next twelve are the
+     *  matrix.
+     */
+    static constexpr uint8_t kTransferFn_Flag = 1 << 3;
+
     static ColorSpaceHeader Pack(Version version, uint8_t named, uint8_t gammaNamed, uint8_t flags)
     {
         ColorSpaceHeader header;
@@ -334,7 +370,7 @@ struct ColorSpaceHeader {
         SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed);
         header.fGammaNamed = (uint8_t) gammaNamed;
 
-        SkASSERT(flags <= kFloatGamma_Flag);
+        SkASSERT(flags <= kTransferFn_Flag);
         header.fFlags = flags;
         return header;
     }
@@ -388,26 +424,51 @@ size_t SkColorSpace::writeToMemory(void* memory) const {
                 return sizeof(ColorSpaceHeader) + 12 * sizeof(float);
             }
             default:
-                // Otherwise, write the gamma values and the matrix.
-                if (memory) {
-                    *((ColorSpaceHeader*) memory) =
-                            ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed,
-                                                   ColorSpaceHeader::kFloatGamma_Flag);
-                    memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
-
-                    const SkGammas* gammas = as_CSB(this)->gammas();
-                    SkASSERT(gammas);
-                    SkASSERT(SkGammas::Type::kValue_Type == gammas->fRedType &&
-                             SkGammas::Type::kValue_Type == gammas->fGreenType &&
-                             SkGammas::Type::kValue_Type == gammas->fBlueType);
-                    *(((float*) memory) + 0) = gammas->fRedData.fValue;
-                    *(((float*) memory) + 1) = gammas->fGreenData.fValue;
-                    *(((float*) memory) + 2) = gammas->fBlueData.fValue;
-                    memory = SkTAddOffset<void>(memory, 3 * sizeof(float));
-
-                    as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory);
+                const SkGammas* gammas = as_CSB(this)->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::kFloatGamma_Flag);
+                        memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
+
+                        *(((float*) memory) + 0) = gammas->fRedData.fValue;
+                        *(((float*) memory) + 1) = gammas->fGreenData.fValue;
+                        *(((float*) memory) + 2) = gammas->fBlueData.fValue;
+                        memory = SkTAddOffset<void>(memory, 3 * sizeof(float));
+
+                        as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory);
+                    }
+
+                    return sizeof(ColorSpaceHeader) + 15 * sizeof(float);
+                } else {
+                    SkASSERT(gammas->isParametric(0));
+                    SkASSERT(gammas->isParametric(1));
+                    SkASSERT(gammas->isParametric(2));
+                    SkASSERT(gammas->data(0) == gammas->data(1));
+                    SkASSERT(gammas->data(0) == gammas->data(2));
+
+                    if (memory) {
+                        *((ColorSpaceHeader*) memory) =
+                                ColorSpaceHeader::Pack(k0_Version, 0, as_CSB(this)->fGammaNamed,
+                                                       ColorSpaceHeader::kTransferFn_Flag);
+                        memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
+
+                        *(((float*) memory) + 0) = gammas->params(0).fA;
+                        *(((float*) memory) + 1) = gammas->params(0).fB;
+                        *(((float*) memory) + 2) = gammas->params(0).fC;
+                        *(((float*) memory) + 3) = gammas->params(0).fD;
+                        *(((float*) memory) + 4) = gammas->params(0).fE;
+                        *(((float*) memory) + 5) = gammas->params(0).fF;
+                        *(((float*) memory) + 6) = gammas->params(0).fG;
+                        memory = SkTAddOffset<void>(memory, 7 * sizeof(float));
+
+                        as_CSB(this)->fToXYZD50.as3x4RowMajorf((float*) memory);
+                    }
+
+                    return sizeof(ColorSpaceHeader) + 19 * sizeof(float);
                 }
-                return sizeof(ColorSpaceHeader) + 15 * sizeof(float);
         }
     }
 
@@ -501,6 +562,25 @@ sk_sp<SkColorSpace> SkColorSpace::Deserialize(const void* data, size_t length) {
             toXYZ.set3x4RowMajorf((const float*) data);
             return SkColorSpace_Base::NewRGB(gammas, toXYZ);
         }
+        case ColorSpaceHeader::kTransferFn_Flag: {
+            if (length < 19 * sizeof(float)) {
+                return nullptr;
+            }
+
+            SkColorSpaceTransferFn transferFn;
+            transferFn.fA = *(((const float*) data) + 0);
+            transferFn.fB = *(((const float*) data) + 1);
+            transferFn.fC = *(((const float*) data) + 2);
+            transferFn.fD = *(((const float*) data) + 3);
+            transferFn.fE = *(((const float*) data) + 4);
+            transferFn.fF = *(((const float*) data) + 5);
+            transferFn.fG = *(((const float*) data) + 6);
+            data = SkTAddOffset<const void>(data, 7 * sizeof(float));
+
+            SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
+            toXYZ.set3x4RowMajorf((const float*) data);
+            return SkColorSpace::NewRGB(transferFn, toXYZ);
+        }
         default:
             return nullptr;
     }
index e7c8aaa..7303873 100644 (file)
@@ -7,6 +7,80 @@
 
 #define SkColorSpacePrintf(...)
 
-inline bool color_space_almost_equal(float a, float b) {
+static inline bool color_space_almost_equal(float a, float b) {
     return SkTAbs(a - b) < 0.01f;
 }
+
+static inline bool is_zero_to_one(float v) {
+    return (0.0f <= v) && (v <= 1.0f);
+}
+
+static inline bool is_valid_transfer_fn(const SkColorSpaceTransferFn& coeffs) {
+    if (SkScalarIsNaN(coeffs.fA) || SkScalarIsNaN(coeffs.fB) ||
+        SkScalarIsNaN(coeffs.fC) || SkScalarIsNaN(coeffs.fD) ||
+        SkScalarIsNaN(coeffs.fE) || SkScalarIsNaN(coeffs.fF) ||
+        SkScalarIsNaN(coeffs.fG))
+    {
+        return false;
+    }
+
+    if (!is_zero_to_one(coeffs.fD)) {
+        return false;
+    }
+
+    if (coeffs.fD == 0.0f) {
+        // Y = (aX + b)^g + c  for always
+        if (0.0f == coeffs.fA || 0.0f == coeffs.fG) {
+            SkColorSpacePrintf("A or G is zero, constant transfer function "
+                               "is nonsense");
+            return false;
+        }
+    }
+
+    if (coeffs.fD == 1.0f) {
+        // Y = eX + f          for always
+        if (0.0f == coeffs.fE) {
+            SkColorSpacePrintf("E is zero, constant transfer function is "
+                               "nonsense");
+            return false;
+        }
+    }
+
+    if ((0.0f == coeffs.fA || 0.0f == coeffs.fG) && 0.0f == coeffs.fE) {
+        SkColorSpacePrintf("A or G, and E are zero, constant transfer function "
+                           "is nonsense");
+        return false;
+    }
+
+    if (coeffs.fE < 0.0f) {
+        SkColorSpacePrintf("Transfer function must be increasing");
+        return false;
+    }
+
+    if (coeffs.fA < 0.0f || coeffs.fG < 0.0f) {
+        SkColorSpacePrintf("Transfer function must be positive or increasing");
+        return false;
+    }
+
+    return true;
+}
+
+static inline bool is_almost_srgb(const SkColorSpaceTransferFn& coeffs) {
+    return color_space_almost_equal(0.9479f, coeffs.fA) &&
+           color_space_almost_equal(0.0521f, coeffs.fB) &&
+           color_space_almost_equal(0.0000f, coeffs.fC) &&
+           color_space_almost_equal(0.0405f, coeffs.fD) &&
+           color_space_almost_equal(0.0774f, coeffs.fE) &&
+           color_space_almost_equal(0.0000f, coeffs.fF) &&
+           color_space_almost_equal(2.4000f, coeffs.fG);
+}
+
+static inline bool is_almost_2dot2(const SkColorSpaceTransferFn& coeffs) {
+    return color_space_almost_equal(1.0f, coeffs.fA) &&
+           color_space_almost_equal(0.0f, coeffs.fB) &&
+           color_space_almost_equal(0.0f, coeffs.fC) &&
+           color_space_almost_equal(0.0f, coeffs.fD) &&
+           color_space_almost_equal(0.0f, coeffs.fE) &&
+           color_space_almost_equal(0.0f, coeffs.fF) &&
+           color_space_almost_equal(2.2f, coeffs.fG);
+}
index 5abc476..b71ee4a 100644 (file)
@@ -303,7 +303,7 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage,
                     outGammaTables[i] = &gammaTableStorage[i * gammaTableSize];
                 } else {
                     SkASSERT(gammas->isParametric(i));
-                    const SkGammas::Params& params = gammas->params(i);
+                    const SkColorSpaceTransferFn& params = gammas->params(i);
                     (*fns.fBuildFromParam)(&gammaTableStorage[i * gammaTableSize], params.fG,
                                            params.fA, params.fB, params.fC, params.fD, params.fE,
                                            params.fF);
index 07fa383..f0e26be 100644 (file)
@@ -42,19 +42,6 @@ struct SkGammas : SkRefCnt {
         }
     };
 
-    // Contains the parameters for a parametric curve.
-    struct Params {
-        //     Y = (aX + b)^g + c  for X >= d
-        //     Y = eX + f          otherwise
-        float                    fG;
-        float                    fA;
-        float                    fB;
-        float                    fC;
-        float                    fD;
-        float                    fE;
-        float                    fF;
-    };
-
     // Contains the actual gamma curve information.  Should be interpreted
     // based on the type of the gamma curve.
     union Data {
@@ -72,8 +59,9 @@ struct SkGammas : SkRefCnt {
         Table                    fTable;
         size_t                   fParamOffset;
 
-        const Params& params(const SkGammas* base) const {
-            return *SkTAddOffset<const Params>(base, sizeof(SkGammas) + fParamOffset);
+        const SkColorSpaceTransferFn& params(const SkGammas* base) const {
+            return *SkTAddOffset<const SkColorSpaceTransferFn>(
+                    base, sizeof(SkGammas) + fParamOffset);
         }
     };
 
@@ -112,7 +100,7 @@ struct SkGammas : SkRefCnt {
         return this->data(i).fTable.table(this);
     }
 
-    const Params& params(int i) const {
+    const SkColorSpaceTransferFn& params(int i) const {
         SkASSERT(isParametric(i));
         return this->data(i).params(this);
     }
index 4ef9f2b..b33e6b5 100644 (file)
@@ -274,8 +274,8 @@ static float read_big_endian_16_dot_16(const uint8_t buf[4]) {
  *
  *  @return            kNone_Type on failure, otherwise the type of the gamma tag.
  */
-static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* outParams,
-                                      size_t* outTagBytes, const uint8_t* src, size_t len) {
+static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkColorSpaceTransferFn* outParams,
+                                  size_t* outTagBytes, const uint8_t* src, size_t len) {
     if (len < 12) {
         SkColorSpacePrintf("gamma tag is too small (%d bytes)", len);
         return SkGammas::Type::kNone_Type;
@@ -478,56 +478,29 @@ static SkGammas::Type parse_gamma(SkGammas::Data* outData, SkGammas::Params* out
                     return SkGammas::Type::kNone_Type;
             }
 
-            // Recognize and simplify a very common parametric representation of sRGB gamma.
-            if (color_space_almost_equal(0.9479f, a) &&
-                    color_space_almost_equal(0.0521f, b) &&
-                    color_space_almost_equal(0.0000f, c) &&
-                    color_space_almost_equal(0.0405f, d) &&
-                    color_space_almost_equal(0.0774f, e) &&
-                    color_space_almost_equal(0.0000f, f) &&
-                    color_space_almost_equal(2.4000f, g)) {
-                outData->fNamed = kSRGB_SkGammaNamed;
-                return SkGammas::Type::kNamed_Type;
-            }
+            outParams->fG = g;
+            outParams->fA = a;
+            outParams->fB = b;
+            outParams->fC = c;
+            outParams->fD = d;
+            outParams->fE = e;
+            outParams->fF = f;
 
-            // Fail on invalid gammas.
-            if (SkScalarIsNaN(d)) {
+            if (!is_valid_transfer_fn(*outParams)) {
                 return SkGammas::Type::kNone_Type;
             }
 
-            if (d <= 0.0f) {
-                // Y = (aX + b)^g + c  for always
-                if (0.0f == a || 0.0f == g) {
-                    SkColorSpacePrintf("A or G is zero, constant gamma function "
-                                       "is nonsense");
-                    return SkGammas::Type::kNone_Type;
-                }
-            }
-
-            if (d >= 1.0f) {
-                // Y = eX + f          for always
-                if (0.0f == e) {
-                    SkColorSpacePrintf("E is zero, constant gamma function is "
-                                       "nonsense");
-                    return SkGammas::Type::kNone_Type;
-                }
+            if (is_almost_srgb(*outParams)) {
+                outData->fNamed = kSRGB_SkGammaNamed;
+                return SkGammas::Type::kNamed_Type;
             }
 
-            if ((0.0f == a || 0.0f == g) && 0.0f == e) {
-                SkColorSpacePrintf("A or G, and E are zero, constant gamma function "
-                                   "is nonsense");
-                return SkGammas::Type::kNone_Type;
+            if (is_almost_2dot2(*outParams)) {
+                outData->fNamed = k2Dot2Curve_SkGammaNamed;
+                return SkGammas::Type::kNamed_Type;
             }
 
             *outTagBytes = tagBytes;
-
-            outParams->fG = g;
-            outParams->fA = a;
-            outParams->fB = b;
-            outParams->fC = c;
-            outParams->fD = d;
-            outParams->fE = e;
-            outParams->fF = f;
             return SkGammas::Type::kParam_Type;
         }
         default:
@@ -547,7 +520,7 @@ static size_t gamma_alloc_size(SkGammas::Type type, const SkGammas::Data& data)
         case SkGammas::Type::kTable_Type:
             return sizeof(float) * data.fTable.fSize;
         case SkGammas::Type::kParam_Type:
-            return sizeof(SkGammas::Params);
+            return sizeof(SkColorSpaceTransferFn);
         default:
             SkASSERT(false);
             return 0;
@@ -584,7 +557,7 @@ static void handle_invalid_gamma(SkGammas::Type* type, SkGammas::Data* data) {
  *  @return       Additional bytes of memory that are being used by this gamma curve.
  */
 static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
-                        SkGammas::Data* data, const SkGammas::Params& params,
+                        SkGammas::Data* data, const SkColorSpaceTransferFn& params,
                         const uint8_t* src) {
     void* storage = SkTAddOffset<void>(memory, offset + sizeof(SkGammas));
 
@@ -606,8 +579,8 @@ static size_t load_gammas(void* memory, size_t offset, SkGammas::Type type,
         }
         case SkGammas::Type::kParam_Type:
             data->fTable.fOffset = offset;
-            memcpy(storage, &params, sizeof(SkGammas::Params));
-            return sizeof(SkGammas::Params);
+            memcpy(storage, &params, sizeof(SkColorSpaceTransferFn));
+            return sizeof(SkColorSpaceTransferFn);
         default:
             SkASSERT(false);
             return 0;
@@ -785,7 +758,7 @@ static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkGammaNamed* gammaNa
         size_t tagLen = len - offsetToMCurves;
 
         SkGammas::Data rData;
-        SkGammas::Params rParams;
+        SkColorSpaceTransferFn rParams;
 
         // On an invalid first gamma, tagBytes remains set as zero.  This causes the two
         // subsequent to be treated as identical (which is what we want).
@@ -820,17 +793,17 @@ static bool load_a2b0(sk_sp<SkColorLookUpTable>* colorLUT, SkGammaNamed* gammaNa
             const uint8_t* gTagPtr = rTagPtr + alignedTagBytes;
             tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
             SkGammas::Data gData;
-            SkGammas::Params gParams;
+            SkColorSpaceTransferFn gParams;
             tagBytes = 0;
             SkGammas::Type gType = parse_gamma(&gData, &gParams, &tagBytes, gTagPtr,
-                                                       tagLen);
+                                               tagLen);
             handle_invalid_gamma(&gType, &gData);
 
             alignedTagBytes = SkAlign4(tagBytes);
             const uint8_t* bTagPtr = gTagPtr + alignedTagBytes;
             tagLen = tagLen > alignedTagBytes ? tagLen - alignedTagBytes : 0;
             SkGammas::Data bData;
-            SkGammas::Params bParams;
+            SkColorSpaceTransferFn bParams;
             SkGammas::Type bType = parse_gamma(&bData, &bParams, &tagBytes, bTagPtr,
                                                        tagLen);
             handle_invalid_gamma(&bType, &bData);
@@ -993,7 +966,7 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) {
                 if (r && g && b) {
                     if (tag_equals(r, g, base) && tag_equals(g, b, base)) {
                         SkGammas::Data data;
-                        SkGammas::Params params;
+                        SkColorSpaceTransferFn params;
                         SkGammas::Type type =
                                 parse_gamma(&data, &params, &tagBytes, r->addr(base), r->fLength);
                         handle_invalid_gamma(&type, &data);
@@ -1019,19 +992,19 @@ sk_sp<SkColorSpace> SkColorSpace::NewICC(const void* input, size_t len) {
                         }
                     } else {
                         SkGammas::Data rData;
-                        SkGammas::Params rParams;
+                        SkColorSpaceTransferFn rParams;
                         SkGammas::Type rType =
                                 parse_gamma(&rData, &rParams, &tagBytes, r->addr(base), r->fLength);
                         handle_invalid_gamma(&rType, &rData);
 
                         SkGammas::Data gData;
-                        SkGammas::Params gParams;
+                        SkColorSpaceTransferFn gParams;
                         SkGammas::Type gType =
                                 parse_gamma(&gData, &gParams, &tagBytes, g->addr(base), g->fLength);
                         handle_invalid_gamma(&gType, &gData);
 
                         SkGammas::Data bData;
-                        SkGammas::Params bParams;
+                        SkColorSpaceTransferFn bParams;
                         SkGammas::Type bType =
                                 parse_gamma(&bData, &bParams, &tagBytes, b->addr(base), b->fLength);
                         handle_invalid_gamma(&bType, &bData);
index a4eab92..fabeeb8 100644 (file)
@@ -229,6 +229,16 @@ DEF_TEST(ColorSpace_Serialize, r) {
     const float gammas[] = { 1.1f, 1.2f, 1.7f, };
     SkMatrix44 toXYZ(SkMatrix44::kIdentity_Constructor);
     test_serialize(r, SkColorSpace_Base::NewRGB(gammas, toXYZ).get(), false);
+
+    SkColorSpaceTransferFn fn;
+    fn.fA = 1.0f;
+    fn.fB = 0.0f;
+    fn.fC = 0.0f;
+    fn.fD = 0.5f;
+    fn.fE = 1.0f;
+    fn.fF = 0.0f;
+    fn.fG = 1.0f;
+    test_serialize(r, SkColorSpace::NewRGB(fn, toXYZ).get(), false);
 }
 
 DEF_TEST(ColorSpace_Equals, r) {
@@ -250,6 +260,16 @@ DEF_TEST(ColorSpace_Equals, r) {
     sk_sp<SkColorSpace> rgb2 = SkColorSpace_Base::NewRGB(gammas2, toXYZ);
     sk_sp<SkColorSpace> rgb3 = SkColorSpace_Base::NewRGB(gammas1, toXYZ);
 
+    SkColorSpaceTransferFn fn;
+    fn.fA = 1.0f;
+    fn.fB = 0.0f;
+    fn.fC = 0.0f;
+    fn.fD = 0.5f;
+    fn.fE = 1.0f;
+    fn.fF = 0.0f;
+    fn.fG = 1.0f;
+    sk_sp<SkColorSpace> rgb4 = SkColorSpace::NewRGB(fn, toXYZ);
+
     REPORTER_ASSERT(r, SkColorSpace::Equals(nullptr, nullptr));
     REPORTER_ASSERT(r, SkColorSpace::Equals(srgb.get(), srgb.get()));
     REPORTER_ASSERT(r, SkColorSpace::Equals(adobe.get(), adobe.get()));
@@ -259,6 +279,7 @@ DEF_TEST(ColorSpace_Equals, r) {
     REPORTER_ASSERT(r, SkColorSpace::Equals(upperRight.get(), upperRight.get()));
     REPORTER_ASSERT(r, SkColorSpace::Equals(rgb1.get(), rgb1.get()));
     REPORTER_ASSERT(r, SkColorSpace::Equals(rgb1.get(), rgb3.get()));
+    REPORTER_ASSERT(r, SkColorSpace::Equals(rgb4.get(), rgb4.get()));
 
     REPORTER_ASSERT(r, !SkColorSpace::Equals(nullptr, srgb.get()));
     REPORTER_ASSERT(r, !SkColorSpace::Equals(srgb.get(), nullptr));
@@ -270,6 +291,7 @@ DEF_TEST(ColorSpace_Equals, r) {
     REPORTER_ASSERT(r, !SkColorSpace::Equals(z30.get(), upperRight.get()));
     REPORTER_ASSERT(r, !SkColorSpace::Equals(upperRight.get(), adobe.get()));
     REPORTER_ASSERT(r, !SkColorSpace::Equals(rgb1.get(), rgb2.get()));
+    REPORTER_ASSERT(r, !SkColorSpace::Equals(rgb1.get(), rgb4.get()));
 }
 
 DEF_TEST(ColorSpace_Primaries, r) {
index f792c6a..0885d58 100644 (file)
@@ -86,12 +86,13 @@ DEF_TEST(ColorSpaceXform_TableGamma, r) {
 
 DEF_TEST(ColorSpaceXform_ParametricGamma, r) {
     // Parametric gamma curves
-    void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkGammas::Params));
+    void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(SkColorSpaceTransferFn));
     sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
     gammas->fRedType = gammas->fGreenType = gammas->fBlueType = SkGammas::Type::kParam_Type;
     gammas->fRedData.fParamOffset = gammas->fGreenData.fParamOffset =
             gammas->fBlueData.fParamOffset = 0;
-    SkGammas::Params* params = SkTAddOffset<SkGammas::Params>(memory, sizeof(SkGammas));
+    SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>
+            (memory, sizeof(SkGammas));
 
     // Interval, switch xforms at 0.0031308f
     params->fD = 0.04045f;
@@ -129,7 +130,7 @@ DEF_TEST(ColorSpaceXform_NamedGamma, r) {
 DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) {
     constexpr size_t tableSize = 10;
     void* memory = sk_malloc_throw(sizeof(SkGammas) + sizeof(float) * tableSize +
-                                   sizeof(SkGammas::Params));
+                                   sizeof(SkColorSpaceTransferFn));
     sk_sp<SkGammas> gammas = sk_sp<SkGammas>(new (memory) SkGammas());
 
     float* table = SkTAddOffset<float>(memory, sizeof(SkGammas));
@@ -144,8 +145,8 @@ DEF_TEST(ColorSpaceXform_NonMatchingGamma, r) {
     table[8] = 0.85f;
     table[9] = 1.00f;
 
-    SkGammas::Params* params = SkTAddOffset<SkGammas::Params>(memory, sizeof(SkGammas) +
-                                                              sizeof(float) * tableSize);
+    SkColorSpaceTransferFn* params = SkTAddOffset<SkColorSpaceTransferFn>(memory,
+            sizeof(SkGammas) + sizeof(float) * tableSize);
     params->fA = 1.0f / 1.055f;
     params->fB = 0.055f / 1.055f;
     params->fC = 0.0f;