Introduce SkRGBA4f, templated on SkAlphaType

Most functionality is shared, but this lets us get type safety.
SkColor4f = SkRGBA4f<kUnpremul>
SkPMColor4f = SkRGBA4f<kPremul>

Change-Id: I27408565dc92e722f42a185cecbf7af15d1dde3f
Reviewed-on: https://skia-review.googlesource.com/156243
Commit-Queue: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Auto-Submit: Mike Klein <mtklein@google.com>
diff --git a/include/core/SkColor.h b/include/core/SkColor.h
index caf30ac..334bb43 100644
--- a/include/core/SkColor.h
+++ b/include/core/SkColor.h
@@ -18,6 +18,7 @@
 #ifndef SkColor_DEFINED
 #define SkColor_DEFINED
 
+#include "SkImageInfo.h"
 #include "SkScalar.h"
 #include "SkTypes.h"
 
@@ -229,93 +230,37 @@
 
 struct SkPM4f;
 
-/** \struct SkColor4f
-    Each component is stored as a 32-bit single precision floating point float value.
-    All values are allowed, but only the range from zero to one is meaningful.
+template <SkAlphaType kAT>
+struct SK_API SkRGBA4f {
+    float fR;
+    float fG;
+    float fB;
+    float fA;
 
-    Each component is independent of the others; fA alpha is not premultiplied
-    with fG green, fB blue, or fR red.
-
-    Values smaller than zero or larger than one are allowed. Values out of range
-    may be used with SkBlendMode so that the final component is in range.
-*/
-struct SK_API SkColor4f {
-    float fR; //!< red component
-    float fG; //!< green component
-    float fB; //!< blue component
-    float fA; //!< alpha component
-
-    /** Compares SkColor4f with other, and returns true if all components are equivalent.
-
-        @param other  SkColor4f to compare
-        @return       true if SkColor4f equals other
-    */
-    bool operator==(const SkColor4f& other) const {
+    bool operator==(const SkRGBA4f& other) const {
         return fA == other.fA && fR == other.fR && fG == other.fG && fB == other.fB;
     }
-
-    /** Compares SkColor4f with other, and returns true if all components are not
-        equivalent.
-
-        @param other  SkColor4f to compare
-        @return       true if SkColor4f is not equal to other
-    */
-    bool operator!=(const SkColor4f& other) const {
+    bool operator!=(const SkRGBA4f& other) const {
         return !(*this == other);
     }
 
-    /** Returns SkColor4f components as a read-only array.
-
-        @return  components as read-only array
-    */
     const float* vec() const { return &fR; }
+          float* vec()       { return &fR; }
 
-    /** Returns SkColor4f components as a read-only array.
+    static SkRGBA4f Pin(float r, float g, float b, float a);  // impl. depends on kAT
+    SkRGBA4f pin() const { return Pin(fR, fG, fB, fA); }
 
-        @return  components as read-only array
-    */
-    float* vec() { return &fR; }
+    static SkRGBA4f FromColor(SkColor);  // impl. depends on kAT
+    SkColor toSkColor() const;  // impl. depends on kAT
 
-    /** Constructs and returns SkColor4f with each component pinned from zero to one.
-
-        @param r  red component
-        @param g  green component
-        @param b  blue component
-        @param a  alpha component
-        @return   SkColor4f with valid components
-    */
-    static SkColor4f Pin(float r, float g, float b, float a);
-
-    /** Converts to closest SkColor4f.
-
-        @param SkColor  color with alpha, red, blue, and green components
-        @return         SkColor4f equivalent
-    */
-    static SkColor4f FromColor(SkColor);
-
-    /** Converts to closest SkColor.
-
-        @return  closest color
-    */
-    SkColor toSkColor() const;
-
-    /** Returns SkColor4f with all components in the range from zero to one.
-
-        @return  SkColor4f with valid components
-    */
-    SkColor4f pin() const {
-        return Pin(fR, fG, fB, fA);
-    }
-
-    /** Returns SkColor4f with all components premultiplied by alpha.
-
-        @return  premultiplied color
-    */
-    SkColor4f premul() const {
+    SkRGBA4f<kPremul_SkAlphaType> premul() const {
+        static_assert(kAT == kUnpremul_SkAlphaType, "");
         return { fR * fA, fG * fA, fB * fA, fA };
     }
 
-    SkColor4f unpremul() const {
+    SkRGBA4f<kUnpremul_SkAlphaType> unpremul() const {
+        static_assert(kAT == kPremul_SkAlphaType, "");
+
         if (fA == 0.0f) {
             return { 0, 0, 0, 0 };
         } else {
@@ -324,11 +269,16 @@
         }
     }
 
-    /** Internal use only.
+    template <SkAlphaType dstAT>
+    SkRGBA4f<dstAT> as() const {
+        static_assert(kAT != dstAT, "");
+        return { fR, fG, fB, fA };
+    }
 
-        @return  premultiplied color
-    */
-    SkPM4f toPM4f() const;
+    // TODO: remove?
+    SkPM4f toPM4f() const;  // impl. depends on kAT
 };
 
+using SkColor4f = SkRGBA4f<kUnpremul_SkAlphaType>;
+
 #endif
diff --git a/include/private/GrColor.h b/include/private/GrColor.h
index 5dacbcc..947cfa9 100644
--- a/include/private/GrColor.h
+++ b/include/private/GrColor.h
@@ -192,7 +192,8 @@
         return result;
     }
 
-    static GrColor4f FromSkColor4f(const SkColor4f& color) {
+    template <SkAlphaType kAT>
+    static GrColor4f FromRGBA4f(const SkRGBA4f<kAT>& color) {
         return GrColor4f(color.fR, color.fG, color.fB, color.fA);
     }
 
@@ -226,8 +227,9 @@
                 static_cast<unsigned>(SkTPin(fRGBA[3], 0.0f,1.0f) * 255 + 0.5f));
     }
 
-    SkColor4f toSkColor4f() const {
-        return SkColor4f { fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3] };
+    template <SkAlphaType kAT>
+    SkRGBA4f<kAT> asRGBA4f() const {
+        return SkRGBA4f<kAT> { fRGBA[0], fRGBA[1], fRGBA[2], fRGBA[3] };
     }
 
     GrColor4f opaque() const {
diff --git a/src/core/SkBlendMode.cpp b/src/core/SkBlendMode.cpp
index ad7e535..56f57f4 100644
--- a/src/core/SkBlendMode.cpp
+++ b/src/core/SkBlendMode.cpp
@@ -121,7 +121,7 @@
     p->append(stage);
 }
 
-SkColor4f SkBlendMode_Apply(SkBlendMode mode, const SkColor4f& src, const SkColor4f& dst) {
+SkPMColor4f SkBlendMode_Apply(SkBlendMode mode, const SkPMColor4f& src, const SkPMColor4f& dst) {
     // special-case simple/common modes...
     switch (mode) {
         case SkBlendMode::kClear:   return { 0, 0, 0, 0 };
@@ -136,7 +136,7 @@
     }
 
     SkRasterPipeline_<256> p;
-    SkColor4f              src_storage = src,
+    SkPMColor4f            src_storage = src,
                            dst_storage = dst,
                            res_storage;
     SkJumper_MemoryCtx src_ctx = { &src_storage, 0 },
diff --git a/src/core/SkBlendModePriv.h b/src/core/SkBlendModePriv.h
index 7b7b300..3b5652d 100644
--- a/src/core/SkBlendModePriv.h
+++ b/src/core/SkBlendModePriv.h
@@ -9,9 +9,10 @@
 #define SkBlendModePriv_DEFINED
 
 #include "SkBlendMode.h"
+#include "SkColor.h"
+#include "SkPM4f.h"
 
 class SkRasterPipeline;
-struct SkColor4f;
 
 bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode);
 
@@ -39,7 +40,7 @@
 
 bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst);
 
-SkColor4f SkBlendMode_Apply(SkBlendMode, const SkColor4f& src, const SkColor4f& dst);
+SkPMColor4f SkBlendMode_Apply(SkBlendMode, const SkPMColor4f& src, const SkPMColor4f& dst);
 
 #if SK_SUPPORT_GPU
 #include "GrXferProcessor.h"
diff --git a/src/core/SkColor.cpp b/src/core/SkColor.cpp
index 19dd2c1..45982fb 100644
--- a/src/core/SkColor.cpp
+++ b/src/core/SkColor.cpp
@@ -135,23 +135,27 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-SkColor4f SkColor4f::FromColor(SkColor bgra) {
+template <>
+SK_API SkColor4f SkColor4f::FromColor(SkColor bgra) {
     SkColor4f rgba;
     swizzle_rb(Sk4f_fromL32(bgra)).store(rgba.vec());
     return rgba;
 }
 
-SkColor SkColor4f::toSkColor() const {
+template <>
+SK_API SkColor SkColor4f::toSkColor() const {
     return Sk4f_toL32(swizzle_rb(Sk4f::Load(this->vec())));
 }
 
-SkColor4f SkColor4f::Pin(float r, float g, float b, float a) {
+template <>
+SK_API SkColor4f SkColor4f::Pin(float r, float g, float b, float a) {
     SkColor4f c4;
     Sk4f::Min(Sk4f::Max(Sk4f(r, g, b, a), Sk4f(0)), Sk4f(1)).store(c4.vec());
     return c4;
 }
 
-SkPM4f SkColor4f::toPM4f() const {
+template <>
+SK_API SkPM4f SkColor4f::toPM4f() const {
     auto rgba = Sk4f::Load(this->vec());
     return SkPM4f::From4f(rgba * Sk4f(rgba[3], rgba[3], rgba[3], 1));
 }
diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp
index 3e8c6e9..2356c4d 100644
--- a/src/core/SkColorFilter.cpp
+++ b/src/core/SkColorFilter.cpp
@@ -9,6 +9,7 @@
 #include "SkColorFilter.h"
 #include "SkColorSpaceXformer.h"
 #include "SkNx.h"
+#include "SkPM4f.h"
 #include "SkRasterPipeline.h"
 #include "SkReadBuffer.h"
 #include "SkRefCnt.h"
@@ -64,12 +65,12 @@
 
 #include "SkRasterPipeline.h"
 SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c, SkColorSpace* colorSpace) const {
-    SkColor4f dst, src = c.premul();
+    SkPMColor4f dst, src = c.premul();
 
     SkSTArenaAlloc<128> alloc;
     SkRasterPipeline    pipeline(&alloc);
 
-    pipeline.append_constant_color(&alloc, src);
+    pipeline.append_constant_color(&alloc, src.vec());
     this->onAppendStages(&pipeline, colorSpace, &alloc, c.fA == 1);
     SkJumper_MemoryCtx dstPtr = { &dst, 0 };
     pipeline.append(SkRasterPipeline::store_f32, &dstPtr);
diff --git a/src/core/SkDraw_vertices.cpp b/src/core/SkDraw_vertices.cpp
index 939d616..b9bc2e6 100644
--- a/src/core/SkDraw_vertices.cpp
+++ b/src/core/SkDraw_vertices.cpp
@@ -10,6 +10,7 @@
 #include "SkComposeShader.h"
 #include "SkDraw.h"
 #include "SkNx.h"
+#include "SkPM4f.h"
 #include "SkRasterClip.h"
 #include "SkScan.h"
 #include "SkShaderBase.h"
@@ -97,7 +98,7 @@
 };
 
 static bool SK_WARN_UNUSED_RESULT
-update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkColor4f colors[],
+update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkPMColor4f colors[],
                        int index0, int index1, int index2, Matrix43* result) {
     SkMatrix m, im;
     m.reset();
@@ -135,9 +136,9 @@
 // - convert colors into dst colorspace before interpolation (matches gradients)
 // - apply per-color alpha before interpolation (matches old version of vertices)
 //
-static SkColor4f* convert_colors(const SkColor src[], int count, SkColorSpace* deviceCS,
+static SkPMColor4f* convert_colors(const SkColor src[], int count, SkColorSpace* deviceCS,
                                  SkArenaAlloc* alloc) {
-    SkColor4f* dst = alloc->makeArray<SkColor4f>(count);
+    SkPMColor4f* dst = alloc->makeArray<SkPMColor4f>(count);
     if (!deviceCS) {
         for (int i = 0; i < count; ++i) {
             dst[i] = SkColor4f::FromColor(src[i]).premul();
@@ -268,7 +269,7 @@
     VertState::Proc vertProc = state.chooseProc(vmode);
 
     if (colors || textures) {
-        SkColor4f*  dstColors = nullptr;
+        SkPMColor4f*  dstColors = nullptr;
         Matrix43*   matrix43 = nullptr;
 
         if (colors) {
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 698f345..5bbcf2b 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -288,9 +288,8 @@
 GrColor generate_filtered_color(const SkPaint& paint, const GrColorSpaceInfo& colorSpaceInfo) {
     GrColor4f filteredColor = SkColor4fToUnpremulGrColor4f(paint.getColor4f(), colorSpaceInfo);
     if (paint.getColorFilter() != nullptr) {
-        filteredColor = GrColor4f::FromSkColor4f(
-                paint.getColorFilter()->filterColor4f(filteredColor.toSkColor4f(),
-                                                      colorSpaceInfo.colorSpace()));
+        filteredColor = GrColor4f::FromRGBA4f(paint.getColorFilter()->filterColor4f(
+                filteredColor.asRGBA4f<kUnpremul_SkAlphaType>(),colorSpaceInfo.colorSpace()));
     }
     return filteredColor.premul().toGrColor();
 }
diff --git a/src/core/SkPM4f.h b/src/core/SkPM4f.h
index f2720a0..ff6741e 100644
--- a/src/core/SkPM4f.h
+++ b/src/core/SkPM4f.h
@@ -74,4 +74,6 @@
     SkColor4f unpremul() const;
 };
 
+using SkPMColor4f = SkRGBA4f<kPremul_SkAlphaType>;
+
 #endif
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 44792fb..4ac6f09 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -18,6 +18,7 @@
 #include "SkMask.h"
 #include "SkNx.h"
 #include "SkPixmapPriv.h"
+#include "SkPM4f.h"
 #include "SkReadPixelsRec.h"
 #include "SkSurface.h"
 #include "SkTemplates.h"
@@ -314,7 +315,7 @@
     }
 
     if (pm.colorType() == kRGBA_F32_SkColorType) {
-        const SkColor4f rgba = color.premul();
+        const SkPMColor4f rgba = color.premul();
         for (int y = 0; y < pm.height(); ++y) {
             auto row = (float*)pm.writable_addr(0, y);
             for (int x = 0; x < pm.width(); ++x) {
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index 6d3f7a5..ce22a66 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -55,8 +55,8 @@
         case SkBlendMode::kDst:
             return dst;
         default: {
-            SkColor4f pmS = src.premul();
-            SkColor4f pmD = dst.premul();
+            SkPMColor4f pmS = src.premul();
+            SkPMColor4f pmD = dst.premul();
             return SkBlendMode_Apply(mode, pmS, pmD).unpremul();
         }
     }
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index b79f01f..358a932 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -261,11 +261,11 @@
 }
 
 GrColor4f SkColor4fToPremulGrColor4fLegacy(SkColor4f c) {
-    return GrColor4f::FromSkColor4f(c).premul();
+    return GrColor4f::FromRGBA4f(c.premul());
 }
 
 GrColor4f SkColor4fToUnpremulGrColor4f(SkColor4f c, const GrColorSpaceInfo& colorSpaceInfo) {
-    GrColor4f color = GrColor4f::FromSkColor4f(c);
+    GrColor4f color = GrColor4f::FromRGBA4f(c);
     if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) {
         color = xform->apply(color);
     }
@@ -455,8 +455,8 @@
     SkColorFilter* colorFilter = skPaint.getColorFilter();
     if (colorFilter) {
         if (applyColorFilterToPaintColor) {
-            grPaint->setColor4f(GrColor4f::FromSkColor4f(
-                    colorFilter->filterColor4f(origColor.toSkColor4f(),
+            grPaint->setColor4f(GrColor4f::FromRGBA4f(
+                    colorFilter->filterColor4f(origColor.asRGBA4f<kUnpremul_SkAlphaType>(),
                                                colorSpaceInfo.colorSpace())).premul());
         } else {
             auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo);
diff --git a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
index b5e3d13..9014114 100644
--- a/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrXfermodeFragmentProcessor.cpp
@@ -151,10 +151,10 @@
         input = input.opaque();
         GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input);
         GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
-        SkColor4f src = srcColor.toSkColor4f();
-        SkColor4f dst = dstColor.toSkColor4f();
-        SkColor4f res = SkBlendMode_Apply(fMode, src, dst);
-        return GrColor4f::FromSkColor4f(res).mulByScalar(alpha);
+        SkPMColor4f src = srcColor.asRGBA4f<kPremul_SkAlphaType>();
+        SkPMColor4f dst = dstColor.asRGBA4f<kPremul_SkAlphaType>();
+        SkPMColor4f res = SkBlendMode_Apply(fMode, src, dst);
+        return GrColor4f::FromRGBA4f(res).mulByScalar(alpha);
     }
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
@@ -406,16 +406,16 @@
     GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override {
         GrColor4f childColor =
                 ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite());
-        SkColor4f src, dst;
+        SkPMColor4f src, dst;
         if (kSrc_Child == fChild) {
-            src = childColor.toSkColor4f();
-            dst = inputColor.toSkColor4f();
+            src = childColor.asRGBA4f<kPremul_SkAlphaType>();
+            dst = inputColor.asRGBA4f<kPremul_SkAlphaType>();
         } else {
-            src = inputColor.toSkColor4f();
-            dst = childColor.toSkColor4f();
+            src = inputColor.asRGBA4f<kPremul_SkAlphaType>();
+            dst = childColor.asRGBA4f<kPremul_SkAlphaType>();
         }
-        SkColor4f res = SkBlendMode_Apply(fMode, src, dst);
-        return GrColor4f::FromSkColor4f(res);
+        SkPMColor4f res = SkBlendMode_Apply(fMode, src, dst);
+        return GrColor4f::FromRGBA4f(res);
     }
 
 private:
diff --git a/src/gpu/gradients/GrGradientShader.cpp b/src/gpu/gradients/GrGradientShader.cpp
index 4dbadef..12b9270 100644
--- a/src/gpu/gradients/GrGradientShader.cpp
+++ b/src/gpu/gradients/GrGradientShader.cpp
@@ -120,7 +120,7 @@
     SkColor4fXformer xformedColors(shader.fOrigColors4f, shader.fColorCount,
             shader.fColorSpace.get(), args.fDstColorSpaceInfo->colorSpace());
     for (int i = 0; i < shader.fColorCount; i++) {
-        colors[i] = GrColor4f::FromSkColor4f(xformedColors.fColors[i]);
+        colors[i] = GrColor4f::FromRGBA4f(xformedColors.fColors[i]);
         if (inputPremul) {
             colors[i] = colors[i].premul();
         }
diff --git a/src/shaders/SkColorShader.cpp b/src/shaders/SkColorShader.cpp
index 8e5feb0..e3eb6da 100644
--- a/src/shaders/SkColorShader.cpp
+++ b/src/shaders/SkColorShader.cpp
@@ -214,7 +214,7 @@
             fColorSpace.get(),                     kUnpremul_SkAlphaType,
             args.fDstColorSpaceInfo->colorSpace(), kUnpremul_SkAlphaType);
 
-    GrColor4f color = GrColor4f::FromSkColor4f(fColor4);
+    GrColor4f color = GrColor4f::FromRGBA4f(fColor4);
     if (xform) {
         color = xform->apply(color);
     }
diff --git a/src/utils/SkPatchUtils.cpp b/src/utils/SkPatchUtils.cpp
index f3e3b76..f38e561 100644
--- a/src/utils/SkPatchUtils.cpp
+++ b/src/utils/SkPatchUtils.cpp
@@ -11,6 +11,7 @@
 #include "SkColorData.h"
 #include "SkColorSpacePriv.h"
 #include "SkGeometry.h"
+#include "SkPM4f.h"
 #include "SkTo.h"
 
 namespace {
@@ -217,7 +218,7 @@
 
 #include "SkColorSpaceXform.h"
 
-static void skcolor_to_float(SkColor4f dst[], const SkColor src[], int count, SkColorSpace* dstCS,
+static void skcolor_to_float(SkPMColor4f dst[], const SkColor src[], int count, SkColorSpace* dstCS,
                              bool doPremul) {
     // Source is always sRGB SkColor.
     auto srcCS = sk_srgb_singleton();
@@ -228,17 +229,20 @@
                                             count, op));
 }
 
-static void float_to_skcolor(SkColor dst[], const SkColor4f src[], int count, SkColorSpace* srcCS) {
+static void float_to_skcolor(SkColor dst[], const SkPMColor4f src[], int count,
+                             SkColorSpace* srcCS) {
     // Destination is always sRGB SkColor.
+    // src colors are actually unpremul
     auto dstCS = sk_srgb_singleton();
     SkAssertResult(SkColorSpaceXform::Apply(dstCS, SkColorSpaceXform::kBGRA_8888_ColorFormat, dst,
                                             srcCS, SkColorSpaceXform::kRGBA_F32_ColorFormat,  src,
                                             count, SkColorSpaceXform::kPreserve_AlphaOp));
 }
 
-static void unpremul(SkColor4f array[], int count) {
+static void unpremul(SkPMColor4f array[], int count) {
+    // Technically, SkPMColor4f to SkColor4f, in-place
     for (int i = 0; i < count; ++i) {
-        array[i] = array[i].unpremul();
+        array[i] = array[i].unpremul().as<kPremul_SkAlphaType>();
     }
 }
 
@@ -286,8 +290,8 @@
     }
 
     SkSTArenaAlloc<2048> alloc;
-    SkColor4f* cornerColors = srcColors ? alloc.makeArray<SkColor4f>(4) : nullptr;
-    SkColor4f* tmpColors = srcColors ? alloc.makeArray<SkColor4f>(vertexCount) : nullptr;
+    SkPMColor4f* cornerColors = srcColors ? alloc.makeArray<SkPMColor4f>(4) : nullptr;
+    SkPMColor4f* tmpColors = srcColors ? alloc.makeArray<SkPMColor4f>(vertexCount) : nullptr;
 
     SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vertexCount, indexCount, flags);
     SkPoint* pos = builder.positions();