Switch SkPaint's color to SkColor4f

Change-Id: Ic2b83a05739720013a7c30ec014df0747b3f99a5
Reviewed-on: https://skia-review.googlesource.com/149229
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index 46cf308..5590ebb 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -28,6 +28,7 @@
 class GrTextBlob;
 class SkAutoDescriptor;
 class SkColorFilter;
+class SkColorSpace;
 class SkData;
 class SkDescriptor;
 class SkDrawLooper;
@@ -494,7 +495,14 @@
 
         @return  unpremultiplied ARGB
     */
-    SkColor getColor() const { return fColor; }
+    SkColor getColor() const { return fColor4f.toSkColor(); }
+
+    /** Retrieves alpha and RGB, unpmreultiplied, as four floating point values. RGB are
+        are extended sRGB values (sRGB gamut, and encoded with the sRGB transfer function).
+
+        @return  unpremultiplied RGBA
+    */
+    SkColor4f getColor4f() const { return fColor4f; }
 
     /** Sets alpha and RGB used when stroking and filling. The color is a 32-bit value,
         unpremultiplied, packing 8-bit components for alpha, red, blue, and green.
@@ -503,11 +511,21 @@
     */
     void setColor(SkColor color);
 
+    /** Sets alpha and RGB used when stroking and filling. The color is four floating
+        point values, unpremultiplied. The color values are interpreted as being in
+        the colorSpace. If colorSpace is nullptr, then color is assumed to be in the
+        sRGB color space.
+
+        @param color       unpremultiplied RGBA
+        @param colorSpace  SkColorSpace describing the encoding of color
+    */
+    void setColor4f(const SkColor4f& color, SkColorSpace* colorSpace);
+
     /** Retrieves alpha from the color used when stroking and filling.
 
         @return  alpha ranging from zero, fully transparent, to 255, fully opaque
     */
-    uint8_t getAlpha() const { return SkToU8(SkColorGetA(fColor)); }
+    uint8_t getAlpha() const { return sk_float_round2int(fColor4f.fA * 255); }
 
     /** Replaces alpha, leaving RGB
         unchanged. An out of range value triggers an assert in the debug
@@ -1469,7 +1487,7 @@
     SkScalar        fTextSize;
     SkScalar        fTextScaleX;
     SkScalar        fTextSkewX;
-    SkColor         fColor;
+    SkColor4f       fColor4f;
     SkScalar        fWidth;
     SkScalar        fMiterLimit;
     uint32_t        fBlendMode; // just need 5-6 bits
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 511999a..b870235 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -266,7 +266,7 @@
 
     // Only SKPs within the min/current picture version range (inclusive) can be read.
     static const uint32_t     MIN_PICTURE_VERSION = 56;     // august 2017
-    static const uint32_t CURRENT_PICTURE_VERSION = 64;
+    static const uint32_t CURRENT_PICTURE_VERSION = 65;
 
     static_assert(MIN_PICTURE_VERSION <= 62, "Remove kFontAxes_bad from SkFontDescriptor.cpp");
 
diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp
index 848106a..c85e8d0 100644
--- a/src/atlastext/SkAtlasTextTarget.cpp
+++ b/src/atlastext/SkAtlasTextTarget.cpp
@@ -105,7 +105,7 @@
 
     void makeGrPaint(GrMaskFormat, const SkPaint& skPaint, const SkMatrix&,
                      GrPaint* grPaint) override {
-        grPaint->setColor4f(SkColorToPremulGrColor4fLegacy(skPaint.getColor()));
+        grPaint->setColor4f(SkColor4fToPremulGrColor4fLegacy(skPaint.getColor4f()));
     }
 
     GrContext* getContext() override {
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 13c1e06..ee002e1 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -290,7 +290,7 @@
 
 // -- GrTextContext --------------------------------------------------------------------------------
 GrColor generate_filtered_color(const SkPaint& paint, const GrColorSpaceInfo& colorSpaceInfo) {
-    GrColor4f filteredColor = SkColorToUnpremulGrColor4f(paint.getColor(), colorSpaceInfo);
+    GrColor4f filteredColor = SkColor4fToUnpremulGrColor4f(paint.getColor4f(), colorSpaceInfo);
     if (paint.getColorFilter() != nullptr) {
         filteredColor = GrColor4f::FromSkColor4f(
                 paint.getColorFilter()->filterColor4f(filteredColor.toSkColor4f(),
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 15aa44e..43c568b 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -8,6 +8,8 @@
 #include "SkPaint.h"
 
 #include "SkColorFilter.h"
+#include "SkColorSpacePriv.h"
+#include "SkColorSpaceXformSteps.h"
 #include "SkData.h"
 #include "SkDraw.h"
 #include "SkFontDescriptor.h"
@@ -52,7 +54,7 @@
     fTextSize   = SkPaintDefaults_TextSize;
     fTextScaleX = SK_Scalar1;
     fTextSkewX  = 0;
-    fColor      = SK_ColorBLACK;
+    fColor4f    = { 0, 0, 0, 1 }; // opaque black
     fWidth      = 0;
     fMiterLimit = SkPaintDefaults_MiterLimit;
     fBlendMode  = (unsigned)SkBlendMode::kSrcOver;
@@ -80,7 +82,7 @@
     , COPY(fTextSize)
     , COPY(fTextScaleX)
     , COPY(fTextSkewX)
-    , COPY(fColor)
+    , COPY(fColor4f)
     , COPY(fWidth)
     , COPY(fMiterLimit)
     , COPY(fBlendMode)
@@ -100,7 +102,7 @@
     MOVE(fTextSize);
     MOVE(fTextScaleX);
     MOVE(fTextSkewX);
-    MOVE(fColor);
+    MOVE(fColor4f);
     MOVE(fWidth);
     MOVE(fMiterLimit);
     MOVE(fBlendMode);
@@ -126,7 +128,7 @@
     ASSIGN(fTextSize);
     ASSIGN(fTextScaleX);
     ASSIGN(fTextSkewX);
-    ASSIGN(fColor);
+    ASSIGN(fColor4f);
     ASSIGN(fWidth);
     ASSIGN(fMiterLimit);
     ASSIGN(fBlendMode);
@@ -152,7 +154,7 @@
     MOVE(fTextSize);
     MOVE(fTextScaleX);
     MOVE(fTextSkewX);
-    MOVE(fColor);
+    MOVE(fColor4f);
     MOVE(fWidth);
     MOVE(fMiterLimit);
     MOVE(fBlendMode);
@@ -174,7 +176,7 @@
         && EQUAL(fTextSize)
         && EQUAL(fTextScaleX)
         && EQUAL(fTextSkewX)
-        && EQUAL(fColor)
+        && EQUAL(fColor4f)
         && EQUAL(fWidth)
         && EQUAL(fMiterLimit)
         && EQUAL(fBlendMode)
@@ -257,12 +259,18 @@
 }
 
 void SkPaint::setColor(SkColor color) {
-    fColor = color;
+    fColor4f = SkColor4f::FromColor(color);
+}
+
+void SkPaint::setColor4f(const SkColor4f& color, SkColorSpace* colorSpace) {
+    SkColorSpaceXformSteps steps{colorSpace,          kUnpremul_SkAlphaType,
+                                 sk_srgb_singleton(), kUnpremul_SkAlphaType};
+    fColor4f = color;
+    steps.apply(fColor4f.vec());
 }
 
 void SkPaint::setAlpha(U8CPU a) {
-    this->setColor(SkColorSetARGB(a, SkColorGetR(fColor),
-                                  SkColorGetG(fColor), SkColorGetB(fColor)));
+    fColor4f.fA = a * (1.0f / 255);
 }
 
 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) {
@@ -1196,7 +1204,7 @@
     buffer.writeScalar(paint.getTextSkewX());
     buffer.writeScalar(paint.getStrokeWidth());
     buffer.writeScalar(paint.getStrokeMiter());
-    buffer.writeColor(paint.getColor());
+    buffer.writeColor4f(paint.getColor4f());
 
     buffer.writeUInt(pack_paint_flags(paint.getFlags(), paint.getHinting(), paint.getTextAlign(),
                                       paint.getFilterQuality(), flatFlags));
@@ -1225,7 +1233,13 @@
     paint->setTextSkewX(buffer.readScalar());
     paint->setStrokeWidth(buffer.readScalar());
     paint->setStrokeMiter(buffer.readScalar());
-    paint->setColor(buffer.readColor());
+    if (buffer.isVersionLT(SkReadBuffer::kFloat4PaintColor_Version)) {
+        paint->setColor(buffer.readColor());
+    } else {
+        SkColor4f color;
+        buffer.readColor4f(&color);
+        paint->setColor4f(color, sk_srgb_singleton());
+    }
 
     unsigned flatFlags = unpack_paint_flags(paint, buffer.readUInt());
 
@@ -1494,9 +1508,9 @@
 }
 
 uint32_t SkPaint::getHash() const {
-    // We're going to hash 7 pointers and 7 32-bit values, finishing up with fBitfields,
-    // so fBitfields should be 7 pointers and 6 32-bit values from the start.
-    static_assert(offsetof(SkPaint, fBitfields) == 7 * sizeof(void*) + 7 * sizeof(uint32_t),
+    // We're going to hash 7 pointers and 11 32-bit values, finishing up with fBitfields,
+    // so fBitfields should be 7 pointers and 10 32-bit values from the start.
+    static_assert(offsetof(SkPaint, fBitfields) == 7 * sizeof(void*) + 10 * sizeof(uint32_t),
                   "SkPaint_notPackedTightly");
     return SkOpts::hash(reinterpret_cast<const uint32_t*>(this),
                         offsetof(SkPaint, fBitfields) + sizeof(fBitfields));
diff --git a/src/core/SkReadBuffer.h b/src/core/SkReadBuffer.h
index 4a0a263..c539d16 100644
--- a/src/core/SkReadBuffer.h
+++ b/src/core/SkReadBuffer.h
@@ -80,6 +80,7 @@
         kDontNegateImageSize_Version       = 62,
         kStoreImageBounds_Version          = 63,
         kRemoveOccluderFromBlurMaskFilter  = 64,
+        kFloat4PaintColor_Version          = 65,
     };
 
     /**
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 47ee36a..a29e4ec 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -134,7 +134,7 @@
         color = paintColorXform ? SkColorToUnpremulGrColor(paint.getColor())
                                 : SkColorToPremulGrColor(paint.getColor());
     } else {
-        color = SkColorAlphaToGrColor(paint.getColor());
+        color = GrColorPackA4(paint.getAlpha());
     }
     rtc->drawTexture(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, constraint, ctm,
                      std::move(textureXform), std::move(paintColorXform));
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 0cc2f20..b79f01f 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -257,15 +257,15 @@
 
 GrColor4f SkColorToPremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
     // We want to premultiply after color space conversion, so this is easy:
-    return SkColorToUnpremulGrColor4f(c, colorSpaceInfo).premul();
+    return SkColor4fToUnpremulGrColor4f(SkColor4f::FromColor(c), colorSpaceInfo).premul();
 }
 
-GrColor4f SkColorToPremulGrColor4fLegacy(SkColor c) {
-    return GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c)).premul();
+GrColor4f SkColor4fToPremulGrColor4fLegacy(SkColor4f c) {
+    return GrColor4f::FromSkColor4f(c).premul();
 }
 
-GrColor4f SkColorToUnpremulGrColor4f(SkColor c, const GrColorSpaceInfo& colorSpaceInfo) {
-    GrColor4f color = GrColor4f::FromGrColor(SkColorToUnpremulGrColor(c));
+GrColor4f SkColor4fToUnpremulGrColor4f(SkColor4f c, const GrColorSpaceInfo& colorSpaceInfo) {
+    GrColor4f color = GrColor4f::FromSkColor4f(c);
     if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) {
         color = xform->apply(color);
     }
@@ -367,7 +367,7 @@
                                            SkBlendMode* primColorMode,
                                            GrPaint* grPaint) {
     // Convert SkPaint color to 4f format in the destination color space
-    GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo);
+    GrColor4f origColor = SkColor4fToUnpremulGrColor4f(skPaint.getColor4f(), colorSpaceInfo);
 
     const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
 
@@ -409,7 +409,7 @@
             }
 
             // We can ignore origColor here - alpha is unchanged by gamma
-            GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
+            GrColor paintAlpha = GrColorPackA4(skPaint.getAlpha());
             if (GrColor_WHITE != paintAlpha) {
                 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
                 // color channels. It's value should be treated as the same in ANY color space.
@@ -437,7 +437,7 @@
             grPaint->setColor4f(origColor.opaque());
 
             // We can ignore origColor here - alpha is unchanged by gamma
-            GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor());
+            GrColor paintAlpha = GrColorPackA4(skPaint.getAlpha());
             if (GrColor_WHITE != paintAlpha) {
                 // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all
                 // color channels. It's value should be treated as the same in ANY color space.
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index ec9f30a..1501f90 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -58,16 +58,11 @@
     return GrColorPackRGBA(r, g, b, a);
 }
 
-/** Transform an SkColor (sRGB bytes) to GrColor4f for the specified color space info. */
+/** Transform an SkColor (sRGB bytes) or SkColor4f (sRGB floats) to GrColor4f
+    for the specified color space info. */
 GrColor4f SkColorToPremulGrColor4f(SkColor, const GrColorSpaceInfo&);
-GrColor4f SkColorToPremulGrColor4fLegacy(SkColor);
-GrColor4f SkColorToUnpremulGrColor4f(SkColor, const GrColorSpaceInfo&);
-
-/** Replicates the SkColor's alpha to all four channels of the GrColor. */
-static inline GrColor SkColorAlphaToGrColor(SkColor c) {
-    U8CPU a = SkColorGetA(c);
-    return GrColorPackRGBA(a, a, a, a);
-}
+GrColor4f SkColor4fToPremulGrColor4fLegacy(SkColor4f);
+GrColor4f SkColor4fToUnpremulGrColor4f(SkColor4f, const GrColorSpaceInfo&);
 
 //////////////////////////////////////////////////////////////////////////////