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
diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp
index a6058a9..45455b4 100644
--- a/tests/CodecTest.cpp
+++ b/tests/CodecTest.cpp
@@ -10,7 +10,7 @@
 #include "SkBitmap.h"
 #include "SkCodec.h"
 #include "SkCodecImageGenerator.h"
-#include "SkColorSpace_Base.h"
+#include "SkColorSpace_XYZ.h"
 #include "SkData.h"
 #include "SkImageEncoder.h"
 #include "SkFrontBufferedStream.h"
@@ -1192,7 +1192,9 @@
         REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
     }
 
-    infoF16 = infoF16.makeColorSpace(as_CSB(infoF16.colorSpace())->makeLinearGamma());
+    SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(infoF16.colorSpace())->type());
+    SkColorSpace_XYZ* csXYZ = static_cast<SkColorSpace_XYZ*>(infoF16.colorSpace());
+    infoF16 = infoF16.makeColorSpace(csXYZ->makeLinearGamma());
     result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
     REPORTER_ASSERT(r, SkCodec::kSuccess == result);
     result = codec->startScanlineDecode(infoF16);
diff --git a/tests/ColorSpaceTest.cpp b/tests/ColorSpaceTest.cpp
index aa0a33b..04d4010 100644
--- a/tests/ColorSpaceTest.cpp
+++ b/tests/ColorSpaceTest.cpp
@@ -9,6 +9,7 @@
 #include "SkCodec.h"
 #include "SkColorSpace.h"
 #include "SkColorSpace_Base.h"
+#include "SkColorSpace_XYZ.h"
 #include "Test.h"
 
 #include "png.h"
@@ -22,9 +23,11 @@
                        const SkGammaNamed expectedGamma) {
 
     REPORTER_ASSERT(r, nullptr != space);
-    REPORTER_ASSERT(r, expectedGamma == as_CSB(space)->gammaNamed());
+    SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(space)->type());
+    SkColorSpace_XYZ* csXYZ = static_cast<SkColorSpace_XYZ*>(space);
+    REPORTER_ASSERT(r, expectedGamma == csXYZ->gammaNamed());
 
-    const SkMatrix44& mat = as_CSB(space)->toXYZD50();
+    const SkMatrix44& mat = *csXYZ->toXYZD50();
     const float src[] = {
         1, 0, 0, 1,
         0, 1, 0, 1,
@@ -120,8 +123,9 @@
     sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
 
     // Create the linear sRGB color space via the sRGB color space's makeLinearGamma()
-    sk_sp<SkColorSpace> viaSrgbColorSpace =
-        as_CSB(SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named))->makeLinearGamma();
+    auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+    auto srgbXYZ = static_cast<SkColorSpace_XYZ*>(srgb.get());
+    sk_sp<SkColorSpace> viaSrgbColorSpace = srgbXYZ->makeLinearGamma();
     REPORTER_ASSERT(r, namedColorSpace == viaSrgbColorSpace);
 
     // Create a linear sRGB color space by value
@@ -166,8 +170,12 @@
     sk_sp<SkData> newMonitorData = ColorSpaceTest::WriteToICC(monitorSpace.get());
     sk_sp<SkColorSpace> newMonitorSpace = SkColorSpace::NewICC(newMonitorData->data(),
                                                                newMonitorData->size());
-    REPORTER_ASSERT(r, as_CSB(monitorSpace)->toXYZD50() == as_CSB(newMonitorSpace)->toXYZD50());
-    REPORTER_ASSERT(r, as_CSB(monitorSpace)->gammaNamed() == as_CSB(newMonitorSpace)->gammaNamed());
+    SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(monitorSpace)->type());
+    SkColorSpace_XYZ* monitorSpaceXYZ = static_cast<SkColorSpace_XYZ*>(monitorSpace.get());
+    SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(newMonitorSpace)->type());
+    SkColorSpace_XYZ* newMonitorSpaceXYZ = static_cast<SkColorSpace_XYZ*>(newMonitorSpace.get());
+    REPORTER_ASSERT(r, *monitorSpaceXYZ->toXYZD50() == *newMonitorSpaceXYZ->toXYZD50());
+    REPORTER_ASSERT(r, monitorSpaceXYZ->gammaNamed() == newMonitorSpaceXYZ->gammaNamed());
 }
 
 DEF_TEST(ColorSpace_Named, r) {
@@ -184,7 +192,9 @@
         auto cs = SkColorSpace::NewNamed(rec.fNamed);
         REPORTER_ASSERT(r, cs);
         if (cs) {
-            REPORTER_ASSERT(r, rec.fExpectedGamma == as_CSB(cs)->gammaNamed());
+            SkASSERT(SkColorSpace_Base::Type::kXYZ == as_CSB(cs)->type());
+            SkColorSpace_XYZ* csXYZ = static_cast<SkColorSpace_XYZ*>(cs.get());
+            REPORTER_ASSERT(r, rec.fExpectedGamma == csXYZ->gammaNamed());
         }
     }
 
diff --git a/tests/ColorSpaceXformTest.cpp b/tests/ColorSpaceXformTest.cpp
index 6cf0dbe..477e61a 100644
--- a/tests/ColorSpaceXformTest.cpp
+++ b/tests/ColorSpaceXformTest.cpp
@@ -11,6 +11,7 @@
 #include "SkColorPriv.h"
 #include "SkColorSpace.h"
 #include "SkColorSpace_Base.h"
+#include "SkColorSpace_XYZ.h"
 #include "SkColorSpaceXform_Base.h"
 #include "Test.h"
 
@@ -18,11 +19,11 @@
 public:
     static std::unique_ptr<SkColorSpaceXform> CreateIdentityXform(const sk_sp<SkGammas>& gammas) {
         // Logically we can pass any matrix here.  For simplicty, pass I(), i.e. D50 XYZ gamut.
-        sk_sp<SkColorSpace> space(new SkColorSpace_Base(
-                nullptr, kNonStandard_SkGammaNamed, gammas, SkMatrix::I(), nullptr));
+        sk_sp<SkColorSpace> space(new SkColorSpace_XYZ(
+                kNonStandard_SkGammaNamed, gammas, SkMatrix::I(), nullptr));
 
         // Use special testing entry point, so we don't skip the xform, even though src == dst.
-        return SlowIdentityXform(space.get());
+        return SlowIdentityXform(static_cast<SkColorSpace_XYZ*>(space.get()));
     }
 };
 
@@ -175,25 +176,3 @@
     test_identity_xform(r, gammas, true);
 }
 
-DEF_TEST(ColorSpaceXform_applyCLUTMemoryAccess, r) {
-    // buffers larger than 1024 (or 256 in GOOGLE3) will force ColorSpaceXform_Base::apply()
-    // to heap-allocate a buffer that is used for CLUT application, and this test is here to
-    // ensure that it no longer causes potential invalid memory accesses when this happens
-    const size_t len = 2048;
-    SkAutoTMalloc<uint32_t> src(len);
-    SkAutoTMalloc<uint32_t> dst(len);
-    for (uint32_t i = 0; i < len; ++i) {
-        src[i] = i;
-    }
-    // this ICC profile has a CLUT in it
-    const SkString filename(GetResourcePath("icc_profiles/upperRight.icc"));
-    sk_sp<SkData> iccData = SkData::MakeFromFileName(filename.c_str());
-    REPORTER_ASSERT_MESSAGE(r, iccData, "upperRight.icc profile required for test");
-    sk_sp<SkColorSpace> srcSpace = SkColorSpace::NewICC(iccData->bytes(), iccData->size());
-    sk_sp<SkColorSpace> dstSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
-    auto xform = SkColorSpaceXform::New(srcSpace.get(), dstSpace.get());
-    bool result = xform->apply(SkColorSpaceXform::kRGBA_8888_ColorFormat, dst.get(),
-                               SkColorSpaceXform::kRGBA_8888_ColorFormat, src.get(), len,
-                               kUnpremul_SkAlphaType);
-    REPORTER_ASSERT(r, result);
-}
diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp
index 241ddb1..180f2d9 100644
--- a/tests/SurfaceTest.cpp
+++ b/tests/SurfaceTest.cpp
@@ -921,9 +921,10 @@
 
     auto srgbColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
     auto adobeColorSpace = SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named);
-    SkMatrix44 srgbMatrix = as_CSB(srgbColorSpace)->toXYZD50();
+    const SkMatrix44* srgbMatrix = as_CSB(srgbColorSpace)->toXYZD50();
+    SkASSERT(srgbMatrix);
     const float oddGamma[] = { 2.4f, 2.4f, 2.4f };
-    auto oddColorSpace = SkColorSpace::NewRGB(oddGamma, srgbMatrix);
+    auto oddColorSpace = SkColorSpace::NewRGB(oddGamma, *srgbMatrix);
     auto linearColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
 
     const struct {
diff --git a/tests/TestConfigParsing.cpp b/tests/TestConfigParsing.cpp
index 412be73..ec6d721 100644
--- a/tests/TestConfigParsing.cpp
+++ b/tests/TestConfigParsing.cpp
@@ -126,22 +126,28 @@
     REPORTER_ASSERT(reporter, configs[25]->asConfigGpu()->getColorType() == kRGBA_F16_SkColorType);
     REPORTER_ASSERT(reporter, configs[25]->asConfigGpu()->getColorSpace());
     REPORTER_ASSERT(reporter, configs[25]->asConfigGpu()->getColorSpace()->gammaIsLinear());
-    REPORTER_ASSERT(reporter, as_CSB(configs[25]->asConfigGpu()->getColorSpace())->toXYZD50() ==
-                              as_CSB(srgbColorSpace)->toXYZD50());
+    const SkMatrix44* srgbXYZ = as_CSB(srgbColorSpace)->toXYZD50();
+    SkASSERT(srgbXYZ);
+    const SkMatrix44* config25XYZ =
+            as_CSB(configs[25]->asConfigGpu()->getColorSpace())->toXYZD50();
+    SkASSERT(config25XYZ);
+    REPORTER_ASSERT(reporter, *config25XYZ == *srgbXYZ);
     REPORTER_ASSERT(reporter, configs[26]->asConfigGpu()->getColorType() == kRGBA_8888_SkColorType);
     REPORTER_ASSERT(reporter, configs[26]->asConfigGpu()->getColorSpace() == srgbColorSpace.get());
     REPORTER_ASSERT(reporter, configs[41]->asConfigGpu()->getColorType() == kRGBA_F16_SkColorType);
     REPORTER_ASSERT(reporter, configs[41]->asConfigGpu()->getColorSpace());
     REPORTER_ASSERT(reporter, configs[41]->asConfigGpu()->getColorSpace()->gammaIsLinear());
-    REPORTER_ASSERT(reporter, as_CSB(configs[41]->asConfigGpu()->getColorSpace())->toXYZD50() !=
-                              as_CSB(srgbColorSpace)->toXYZD50());
+    const SkMatrix44* config41XYZ =
+            as_CSB(configs[41]->asConfigGpu()->getColorSpace())->toXYZD50();
+    SkASSERT(config41XYZ);
+    REPORTER_ASSERT(reporter, *config41XYZ != *srgbXYZ);
+    REPORTER_ASSERT(reporter, configs[33]->asConfigGpu()->getContextType() ==
+                              GrContextFactory::kGL_ContextType);
     REPORTER_ASSERT(reporter, configs[42]->asConfigGpu()->getColorType() == kRGBA_F16_SkColorType);
     REPORTER_ASSERT(reporter, configs[42]->asConfigGpu()->getColorSpace());
     REPORTER_ASSERT(reporter, configs[42]->asConfigGpu()->getColorSpace()->gammaIsLinear());
-    REPORTER_ASSERT(reporter, as_CSB(configs[42]->asConfigGpu()->getColorSpace())->toXYZD50() !=
-                    as_CSB(srgbColorSpace)->toXYZD50());
-    REPORTER_ASSERT(reporter, configs[33]->asConfigGpu()->getContextType() ==
-                              GrContextFactory::kGL_ContextType);
+    REPORTER_ASSERT(reporter, *as_CSB(configs[42]->asConfigGpu()->getColorSpace())->toXYZD50() !=
+                    *as_CSB(srgbColorSpace)->toXYZD50());
     REPORTER_ASSERT(reporter, configs[33]->asConfigGpu()->getUseInstanced());
     REPORTER_ASSERT(reporter, configs[34]->asConfigGpu()->getContextType() ==
                               GrContextFactory::kGL_ContextType);