Keep paint color range/precision into ops and GPs (using GrColor4h)

We still degrade to bytes when creating vertices (tagged TODO4F).

Note: Guarded for Chrome (by making GrColor4h a wrapper around
GrColor).

Bug: skia:
Change-Id: Id8a1d9eec7978d52b059cd9952666bc1217ee073
Reviewed-on: https://skia-review.googlesource.com/c/165527
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/atlastext/SkAtlasTextTarget.cpp b/src/atlastext/SkAtlasTextTarget.cpp
index fcb489e..c2f2d40 100644
--- a/src/atlastext/SkAtlasTextTarget.cpp
+++ b/src/atlastext/SkAtlasTextTarget.cpp
@@ -209,8 +209,10 @@
 }
 
 void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) {
+    // TODO4F: Odd handling of client colors among AtlasTextTarget and AtlasTextRenderer
+    GrColor4h color4f = GrColor4h::FromGrColor(color);
     for (int i = 0; i < fGeoCount; ++i) {
-        fGeoData[i].fColor = color;
+        fGeoData[i].fColor = color4f;
     }
     this->finalize(caps, nullptr /* applied clip */);
 }
@@ -229,10 +231,12 @@
     }
 
     for (int i = 0; i < fGeoCount; ++i) {
+        // TODO4F: Preserve float colors
         GrTextBlob::VertexRegenerator regenerator(
                 resourceProvider, fGeoData[i].fBlob, fGeoData[i].fRun, fGeoData[i].fSubRun,
-                fGeoData[i].fViewMatrix, fGeoData[i].fX, fGeoData[i].fY, fGeoData[i].fColor,
-                &context, glyphCache, atlasManager, &autoGlyphCache);
+                fGeoData[i].fViewMatrix, fGeoData[i].fX, fGeoData[i].fY,
+                fGeoData[i].fColor.toGrColor(), &context, glyphCache, atlasManager,
+                &autoGlyphCache);
         bool done = false;
         while (!done) {
             GrTextBlob::VertexRegenerator::Result result;
diff --git a/src/core/SkColor.cpp b/src/core/SkColor.cpp
index 337dfed..753f928 100644
--- a/src/core/SkColor.cpp
+++ b/src/core/SkColor.cpp
@@ -120,6 +120,18 @@
 }
 
 template <>
+uint32_t SkColor4f::toBytes_RGBA() const {
+    return Sk4f_toL32(Sk4f::Load(this->vec()));
+}
+
+template <>
+SkColor4f SkColor4f::FromBytes_RGBA(uint32_t c) {
+    SkColor4f color;
+    Sk4f_fromL32(c).store(&color);
+    return color;
+}
+
+template <>
 SkPMColor4f SkPMColor4f::FromPMColor(SkPMColor c) {
     SkPMColor4f color;
     swizzle_rb_if_bgra(Sk4f_fromL32(c)).store(&color);
diff --git a/src/core/SkGlyphRunPainter.cpp b/src/core/SkGlyphRunPainter.cpp
index 0ffdd80..c7985f7 100644
--- a/src/core/SkGlyphRunPainter.cpp
+++ b/src/core/SkGlyphRunPainter.cpp
@@ -270,7 +270,7 @@
 
 #if SK_SUPPORT_GPU
 // -- GrTextContext --------------------------------------------------------------------------------
-GrColor generate_filtered_color(const SkPaint& paint, const GrColorSpaceInfo& colorSpaceInfo) {
+GrColor4h generate_filtered_color(const SkPaint& paint, const GrColorSpaceInfo& colorSpaceInfo) {
     SkColor4f filteredColor = paint.getColor4f();
     if (auto* xform = colorSpaceInfo.colorSpaceXformFromSRGB()) {
         filteredColor = xform->apply(filteredColor);
@@ -279,7 +279,7 @@
         filteredColor = paint.getColorFilter()->filterColor4f(filteredColor,
                                                               colorSpaceInfo.colorSpace());
     }
-    return filteredColor.premul().toBytes_RGBA();
+    return GrColor4h::FromFloats(filteredColor.premul().vec());
 }
 
 void GrTextContext::drawGlyphRunList(
@@ -290,7 +290,7 @@
 
     // Get the first paint to use as the key paint.
     const SkPaint& listPaint = glyphRunList.paint();
-    GrColor filteredColor = generate_filtered_color(listPaint, target->colorSpaceInfo());
+    GrColor4h filteredColor = generate_filtered_color(listPaint, target->colorSpaceInfo());
 
     // If we have been abandoned, then don't draw
     if (context->abandoned()) {
@@ -379,7 +379,7 @@
                                 const sk_sp<GrTextStrike>& strike,
                                 const SkGlyph& skGlyph, GrGlyph::MaskStyle maskStyle,
                                 SkScalar sx, SkScalar sy,
-                                GrColor color, SkGlyphCache* skGlyphCache,
+                                GrColor4h color, SkGlyphCache* skGlyphCache,
                                 SkScalar textRatio, bool needsTransform) {
     GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(),
                                          skGlyph.getSubXFixed(),
@@ -407,7 +407,7 @@
                                            GrGlyphCache* glyphCache,
                                            const GrShaderCaps& shaderCaps,
                                            const SkPaint& paint,
-                                           GrColor filteredColor,
+                                           GrColor4h filteredColor,
                                            SkScalerContextFlags scalerContextFlags,
                                            const SkMatrix& viewMatrix,
                                            const SkSurfaceProps& props,
@@ -441,7 +441,7 @@
         const SkSurfaceProps& fProps;
         const SkScalerContextFlags fScalerContextFlags;
         GrGlyphCache* const fGlyphCache;
-        const GrColor fFilteredColor;
+        GrColor4h fFilteredColor;
     };
 
     SkPoint origin = glyphRunList.origin();
@@ -603,7 +603,7 @@
 
     size_t textLen = (int)strlen(text);
 
-    GrColor filteredColor = generate_filtered_color(skPaint, rtc->colorSpaceInfo());
+    GrColor4h filteredColor = generate_filtered_color(skPaint, rtc->colorSpaceInfo());
 
     auto origin = SkPoint::Make(x, y);
     SkGlyphRunBuilder builder;
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 5dfff7e..fc54933 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -39,7 +39,7 @@
 public:
     static sk_sp<GrGeometryProcessor> Make(const GrShaderCaps* shaderCaps,
                                            uint32_t gpTypeFlags,
-                                           GrColor color,
+                                           GrColor4h color,
                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
                                            const SkMatrix& viewMatrix,
                                            const SkMatrix& localMatrix,
@@ -54,7 +54,7 @@
 
     const char* name() const override { return "DefaultGeometryProcessor"; }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     bool hasVertexColor() const { return fInColor.isInitialized(); }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
@@ -68,7 +68,7 @@
     class GLSLProcessor : public GrGLSLGeometryProcessor {
     public:
         GLSLProcessor()
-            : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL), fCoverage(0xff) {}
+            : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor4h_ILLEGAL), fCoverage(0xff) {}
 
         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
@@ -229,9 +229,9 @@
                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
             }
 
-            if (dgp.color() != fColor && !dgp.hasVertexColor()) {
+            if (!dgp.hasVertexColor() && dgp.color() != fColor) {
                 float c[4];
-                GrColorToRGBAFloat(dgp.color(), c);
+                dgp.color().toFloats(c);
                 pdman.set4fv(fColorUniform, 1, c);
                 fColor = dgp.color();
             }
@@ -281,7 +281,7 @@
 
     private:
         SkMatrix fViewMatrix;
-        GrColor fColor;
+        GrColor4h fColor;
         uint8_t fCoverage;
         UniformHandle fViewMatrixUniform;
         UniformHandle fColorUniform;
@@ -303,7 +303,7 @@
 private:
     DefaultGeoProc(const GrShaderCaps* shaderCaps,
                    uint32_t gpTypeFlags,
-                   GrColor color,
+                   GrColor4h color,
                    sk_sp<GrColorSpaceXform> colorSpaceXform,
                    const SkMatrix& viewMatrix,
                    const SkMatrix& localMatrix,
@@ -370,7 +370,7 @@
     Attribute fInCoverage;
     Attribute fInBoneIndices;
     Attribute fInBoneWeights;
-    GrColor fColor;
+    GrColor4h fColor;
     SkMatrix fViewMatrix;
     SkMatrix fLocalMatrix;
     uint8_t fCoverage;
@@ -417,7 +417,7 @@
 
     return DefaultGeoProc::Make(d->caps()->shaderCaps(),
                                 flags,
-                                GrRandomColor(d->fRandom),
+                                GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
                                 GrTest::TestColorXform(d->fRandom),
                                 GrTest::TestMatrix(d->fRandom),
                                 GrTest::TestMatrix(d->fRandom),
@@ -445,7 +445,7 @@
     uint8_t inCoverage = coverage.fCoverage;
     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
 
-    GrColor inColor = color.fColor;
+    GrColor4h inColor = color.fColor;
     return DefaultGeoProc::Make(shaderCaps,
                                 flags,
                                 inColor,
@@ -499,7 +499,7 @@
     uint8_t inCoverage = coverage.fCoverage;
     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
 
-    GrColor inColor = color.fColor;
+    GrColor4h inColor = color.fColor;
     return DefaultGeoProc::Make(shaderCaps,
                                 flags,
                                 inColor,
diff --git a/src/gpu/GrDefaultGeoProcFactory.h b/src/gpu/GrDefaultGeoProcFactory.h
index b5aef98..935aa8b 100644
--- a/src/gpu/GrDefaultGeoProcFactory.h
+++ b/src/gpu/GrDefaultGeoProcFactory.h
@@ -70,19 +70,19 @@
             kPremulGrColorAttribute_Type,
             kUnpremulSkColorAttribute_Type,
         };
-        explicit Color(GrColor color)
+        explicit Color(GrColor4h color)
                 : fType(kPremulGrColorUniform_Type)
                 , fColor(color)
                 , fColorSpaceXform(nullptr) {}
         Color(Type type)
                 : fType(type)
-                , fColor(GrColor_ILLEGAL)
+                , fColor(GrColor4h_ILLEGAL)
                 , fColorSpaceXform(nullptr) {
             SkASSERT(type != kPremulGrColorUniform_Type);
         }
 
         Type fType;
-        GrColor fColor;
+        GrColor4h fColor;
 
         // This only applies to SkColor. Any GrColors are assumed to have been color converted
         // during paint conversion.
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
index 0b4354c..7f4f8c1 100644
--- a/src/gpu/GrPathProcessor.cpp
+++ b/src/gpu/GrPathProcessor.cpp
@@ -18,7 +18,7 @@
 
 class GrGLPathProcessor : public GrGLSLPrimitiveProcessor {
 public:
-    GrGLPathProcessor() : fColor(GrColor_ILLEGAL) {}
+    GrGLPathProcessor() : fColor(GrColor4h_ILLEGAL) {}
 
     static void GenKey(const GrPathProcessor& pathProc,
                        const GrShaderCaps&,
@@ -77,7 +77,7 @@
         const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
         if (pathProc.color() != fColor) {
             float c[4];
-            GrColorToRGBAFloat(pathProc.color(), c);
+            pathProc.color().toFloats(c);
             pd.set4fv(fColorUniform, 1, c);
             fColor = pathProc.color();
         }
@@ -110,12 +110,12 @@
     SkTArray<TransformVarying, true> fInstalledTransforms;
 
     UniformHandle fColorUniform;
-    GrColor fColor;
+    GrColor4h fColor;
 
     typedef GrGLSLPrimitiveProcessor INHERITED;
 };
 
-GrPathProcessor::GrPathProcessor(GrColor color,
+GrPathProcessor::GrPathProcessor(GrColor4h color,
                                  const SkMatrix& viewMatrix,
                                  const SkMatrix& localMatrix)
         : INHERITED(kGrPathProcessor_ClassID)
diff --git a/src/gpu/GrPathProcessor.h b/src/gpu/GrPathProcessor.h
index 6893e88..0ce3155 100644
--- a/src/gpu/GrPathProcessor.h
+++ b/src/gpu/GrPathProcessor.h
@@ -16,7 +16,7 @@
  */
 class GrPathProcessor : public GrPrimitiveProcessor {
 public:
-    static GrPathProcessor* Create(GrColor color,
+    static GrPathProcessor* Create(GrColor4h color,
                                    const SkMatrix& viewMatrix = SkMatrix::I(),
                                    const SkMatrix& localMatrix = SkMatrix::I()) {
         return new GrPathProcessor(color, viewMatrix, localMatrix);
@@ -24,7 +24,7 @@
 
     const char* name() const override { return "PathProcessor"; }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
@@ -50,9 +50,9 @@
         return kBogus;
     }
 
-    GrPathProcessor(GrColor, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
+    GrPathProcessor(GrColor4h, const SkMatrix& viewMatrix, const SkMatrix& localMatrix);
 
-    GrColor fColor;
+    GrColor4h fColor;
     const SkMatrix fViewMatrix;
     const SkMatrix fLocalMatrix;
 
diff --git a/src/gpu/GrProcessorAnalysis.cpp b/src/gpu/GrProcessorAnalysis.cpp
index 6c4ffbd..8162131 100644
--- a/src/gpu/GrProcessorAnalysis.cpp
+++ b/src/gpu/GrProcessorAnalysis.cpp
@@ -17,9 +17,9 @@
     fIsOpaque = input.isOpaque();
     fUsesLocalCoords = false;
     fProcessorsToEliminate = 0;
-    GrColor color;
+    GrColor4h color;
     if ((fKnowOutputColor = input.isConstant(&color))) {
-        fLastKnownOutputColor = SkPMColor4f::FromBytes_RGBA(color);
+        color.toFloats(fLastKnownOutputColor.vec());
     }
     for (int i = 0; i < cnt; ++i) {
         if (fUsesLocalCoords && !fKnowOutputColor && !fCompatibleWithCoverageAsAlpha &&
diff --git a/src/gpu/GrProcessorAnalysis.h b/src/gpu/GrProcessorAnalysis.h
index 6767941..f1a8798 100644
--- a/src/gpu/GrProcessorAnalysis.h
+++ b/src/gpu/GrProcessorAnalysis.h
@@ -23,13 +23,14 @@
     };
 
     constexpr GrProcessorAnalysisColor(Opaque opaque = Opaque::kNo)
-            : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0), fColor(0) {}
+            : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0)
+            , fColor(GrColor4h_TRANSPARENT) {}
 
-    GrProcessorAnalysisColor(GrColor color) { this->setToConstant(color); }
+    GrProcessorAnalysisColor(GrColor4h color) { this->setToConstant(color); }
 
-    void setToConstant(GrColor color) {
+    void setToConstant(GrColor4h color) {
         fColor = color;
-        if (GrColorIsOpaque(color)) {
+        if (color.isOpaque()) {
             fFlags = kColorIsKnown_Flag | kIsOpaque_Flag;
         } else {
             fFlags = kColorIsKnown_Flag;
@@ -42,7 +43,17 @@
 
     bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); }
 
-    bool isConstant(GrColor* color = nullptr) const {
+    bool isConstant(GrColor* color) const {
+        if (kColorIsKnown_Flag & fFlags) {
+            if (color) {
+                *color = fColor.toGrColor();
+            }
+            return true;
+        }
+        return false;
+    }
+
+    bool isConstant(GrColor4h* color = nullptr) const {
         if (kColorIsKnown_Flag & fFlags) {
             if (color) {
                 *color = fColor;
@@ -79,7 +90,7 @@
         kIsOpaque_Flag = 0x2,
     };
     uint32_t fFlags;
-    GrColor fColor;
+    GrColor4h fColor;
 };
 
 enum class GrProcessorAnalysisCoverage { kNone, kSingleChannel, kLCD };
@@ -122,16 +133,16 @@
      * there are only N processors) sees its expected input. If this returns 0 then there are no
      * processors to eliminate.
      */
-    int initialProcessorsToEliminate(GrColor* newPipelineInputColor) const {
+    int initialProcessorsToEliminate(SkPMColor4f* newPipelineInputColor) const {
         if (fProcessorsToEliminate > 0) {
-            *newPipelineInputColor = fLastKnownOutputColor.toBytes_RGBA();
+            *newPipelineInputColor = fLastKnownOutputColor;
         }
         return fProcessorsToEliminate;
     }
 
-    int initialProcessorsToEliminate(SkPMColor4f* newPipelineInputColor) const {
+    int initialProcessorsToEliminate(GrColor4h* newPipelineInputColor) const {
         if (fProcessorsToEliminate > 0) {
-            *newPipelineInputColor = fLastKnownOutputColor;
+            *newPipelineInputColor = GrColor4h::FromFloats(fLastKnownOutputColor.vec());
         }
         return fProcessorsToEliminate;
     }
@@ -141,7 +152,7 @@
      */
     GrProcessorAnalysisColor outputColor() const {
         if (fKnowOutputColor) {
-            return fLastKnownOutputColor.toBytes_RGBA();
+            return GrColor4h::FromFloats(fLastKnownOutputColor.vec());
         }
         return fIsOpaque ? GrProcessorAnalysisColor::Opaque::kYes
                          : GrProcessorAnalysisColor::Opaque::kNo;
diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp
index e4da038..176e2c3 100644
--- a/src/gpu/GrProcessorSet.cpp
+++ b/src/gpu/GrProcessorSet.cpp
@@ -159,7 +159,8 @@
 GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor& colorInput,
                                                   const GrProcessorAnalysisCoverage coverageInput,
                                                   const GrAppliedClip* clip, bool isMixedSamples,
-                                                  const GrCaps& caps, GrColor* overrideInputColor) {
+                                                  const GrCaps& caps,
+                                                  GrColor4h* overrideInputColor) {
     SkASSERT(!this->isFinalized());
     SkASSERT(!fFragmentProcessorOffset);
 
diff --git a/src/gpu/GrProcessorSet.h b/src/gpu/GrProcessorSet.h
index 5dd1c48..dc1010e 100644
--- a/src/gpu/GrProcessorSet.h
+++ b/src/gpu/GrProcessorSet.h
@@ -141,7 +141,7 @@
      */
     Analysis finalize(const GrProcessorAnalysisColor& colorInput,
                       const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip*,
-                      bool isMixedSamples, const GrCaps&, GrColor* inputColorOverride);
+                      bool isMixedSamples, const GrCaps&, GrColor4h* inputColorOverride);
 
     bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); }
 
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
index 3787971..ca671e2 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp
@@ -120,7 +120,7 @@
         : GrDrawOp(ClassID())
         , fViewMatrixIfUsingLocalCoords(has_coord_transforms(paint) ? m : SkMatrix::I())
         , fDraws(m, shape, strokeDevWidth, shapeConservativeIBounds, maskDevIBounds, maskVisibility,
-                 paint.getColor())
+                 GrColor4h::FromFloats(paint.getColor4f().vec()))
         , fProcessors(std::move(paint)) {  // Paint must be moved after fetching its color above.
     SkDEBUGCODE(fBaseInstance = -1);
     // FIXME: intersect with clip bounds to (hopefully) improve batching.
@@ -139,7 +139,7 @@
                                         float strokeDevWidth,
                                         const SkIRect& shapeConservativeIBounds,
                                         const SkIRect& maskDevIBounds, Visibility maskVisibility,
-                                        GrColor color)
+                                        GrColor4h color)
         : fMatrix(m)
         , fShape(shape)
         , fStrokeDevWidth(strokeDevWidth)
@@ -196,8 +196,11 @@
 
         draw->fShape = GrShape(path, GrStyle(hairlineStroke, nullptr));
         draw->fStrokeDevWidth = 1;
+
+        // TODO4F: Preserve float colors
         // fShapeConservativeIBounds already accounted for this possibility of inflating the stroke.
-        draw->fColor = GrColorMul(draw->fColor, coverageAsAlpha);
+        draw->fColor = GrColor4h::FromGrColor(
+                GrColorMul(draw->fColor.toGrColor(), coverageAsAlpha));
     }
 
     return RequiresDstTexture(analysis.requiresDstTexture());
@@ -322,8 +325,9 @@
             if (auto proxy = draw.fCachedAtlasProxy.get()) {
                 SkASSERT(!cacheEntry->currFlushAtlas());
                 this->recordInstance(proxy, resources->nextPathInstanceIdx());
+                // TODO4F: Preserve float colors
                 resources->appendDrawPathInstance().set(*cacheEntry, draw.fCachedMaskShift,
-                                                        draw.fColor);
+                                                        draw.fColor.toGrColor());
                 continue;
             }
 
@@ -331,8 +335,9 @@
             // drawn more than once during the same flush, with a compatible matrix?)
             if (auto atlas = cacheEntry->currFlushAtlas()) {
                 this->recordInstance(atlas->textureProxy(), resources->nextPathInstanceIdx());
+                // TODO4F: Preserve float colors
                 resources->appendDrawPathInstance().set(
-                        *cacheEntry, draw.fCachedMaskShift, draw.fColor,
+                        *cacheEntry, draw.fCachedMaskShift, draw.fColor.toGrColor(),
                         cacheEntry->hasCachedAtlas() ? DoEvenOddFill::kNo : doEvenOddFill);
                 continue;
             }
@@ -348,8 +353,9 @@
                         atlas->getOrAssignUniqueKey(onFlushRP), newOffset,
                         atlas->refOrMakeCachedAtlasInfo(onFlushRP->contextUniqueID()));
                 this->recordInstance(atlas->textureProxy(), resources->nextPathInstanceIdx());
+                // TODO4F: Preserve float colors
                 resources->appendDrawPathInstance().set(*cacheEntry, draw.fCachedMaskShift,
-                                                        draw.fColor);
+                                                        draw.fColor.toGrColor());
                 // Remember this atlas in case we encounter the path again during the same flush.
                 cacheEntry->setCurrFlushAtlas(atlas);
                 continue;
@@ -368,8 +374,9 @@
                     draw.fMaskDevIBounds, draw.fMatrix, draw.fShape, draw.fStrokeDevWidth,
                     &devBounds, &devBounds45, &devIBounds, &devToAtlasOffset)) {
             this->recordInstance(atlas->textureProxy(), resources->nextPathInstanceIdx());
+            // TODO4F: Preserve float colors
             resources->appendDrawPathInstance().set(devBounds, devBounds45, devToAtlasOffset,
-                                                    draw.fColor, doEvenOddFill);
+                                                    draw.fColor.toGrColor(), doEvenOddFill);
 
             // If we have a spot in the path cache, try to make a note of where this mask is so we
             // can reuse it in the future.
diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h
index 1d17a9f..dbb8dad 100644
--- a/src/gpu/ccpr/GrCCDrawPathsOp.h
+++ b/src/gpu/ccpr/GrCCDrawPathsOp.h
@@ -93,7 +93,7 @@
     struct SingleDraw {
         SingleDraw(const SkMatrix&, const GrShape&, float strokeDevWidth,
                    const SkIRect& shapeConservativeIBounds, const SkIRect& maskDevIBounds,
-                   Visibility maskVisibility, GrColor);
+                   Visibility maskVisibility, GrColor4h);
         ~SingleDraw();
 
         SkMatrix fMatrix;
@@ -102,7 +102,7 @@
         const SkIRect fShapeConservativeIBounds;
         SkIRect fMaskDevIBounds;
         Visibility fMaskVisibility;
-        GrColor fColor;
+        GrColor4h fColor;
 
         sk_sp<GrCCPathCacheEntry> fCacheEntry;
         sk_sp<GrTextureProxy> fCachedAtlasProxy;
diff --git a/src/gpu/ccpr/GrCCPathCache.h b/src/gpu/ccpr/GrCCPathCache.h
index 742e7b1..c0e3cef 100644
--- a/src/gpu/ccpr/GrCCPathCache.h
+++ b/src/gpu/ccpr/GrCCPathCache.h
@@ -192,7 +192,7 @@
 
     friend class GrCCPathCache;
     friend void GrCCPathProcessor::Instance::set(const GrCCPathCacheEntry&, const SkIVector&,
-                                                 uint32_t, DoEvenOddFill);  // To access data.
+                                                 GrColor, DoEvenOddFill);  // To access data.
 };
 
 inline void GrCCPathProcessor::Instance::set(const GrCCPathCacheEntry& entry,
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index e6d6413..31cffb6 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -38,7 +38,7 @@
 
         if (ce.color() != fColor) {
             float c[4];
-            GrColorToRGBAFloat(ce.color(), c);
+            ce.color().toFloats(c);
             pdman.set4fv(fColorUniform, 1, c);
             fColor = ce.color();
         }
@@ -52,7 +52,7 @@
 
 private:
     SkMatrix fViewMatrix;
-    GrColor fColor;
+    GrColor4h fColor;
     uint8_t fCoverageScale;
     GrClipEdgeType fEdgeType;
     UniformHandle fColorUniform;
@@ -63,7 +63,7 @@
 };
 
 GrGLConicEffect::GrGLConicEffect(const GrGeometryProcessor& processor)
-    : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL), fCoverageScale(0xff) {
+    : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor4h_ILLEGAL), fCoverageScale(0xff) {
     const GrConicEffect& ce = processor.cast<GrConicEffect>();
     fEdgeType = ce.getEdgeType();
 }
@@ -232,7 +232,7 @@
     return new GrGLConicEffect(*this);
 }
 
-GrConicEffect::GrConicEffect(GrColor color, const SkMatrix& viewMatrix, uint8_t coverage,
+GrConicEffect::GrConicEffect(GrColor4h color, const SkMatrix& viewMatrix, uint8_t coverage,
                              GrClipEdgeType edgeType, const SkMatrix& localMatrix,
                              bool usesLocalCoords)
     : INHERITED(kGrConicEffect_ClassID)
@@ -256,9 +256,9 @@
         GrClipEdgeType edgeType =
                 static_cast<GrClipEdgeType>(
                         d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
-        gp = GrConicEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom),
-                                 edgeType, *d->caps(), GrTest::TestMatrix(d->fRandom),
-                                 d->fRandom->nextBool());
+        gp = GrConicEffect::Make(GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
+                                 GrTest::TestMatrix(d->fRandom), edgeType, *d->caps(),
+                                 GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool());
     } while (nullptr == gp);
     return gp;
 }
@@ -291,7 +291,7 @@
 
         if (qe.color() != fColor) {
             float c[4];
-            GrColorToRGBAFloat(qe.color(), c);
+            qe.color().toFloats(c);
             pdman.set4fv(fColorUniform, 1, c);
             fColor = qe.color();
         }
@@ -305,7 +305,7 @@
 
 private:
     SkMatrix fViewMatrix;
-    GrColor fColor;
+    GrColor4h fColor;
     uint8_t fCoverageScale;
     GrClipEdgeType fEdgeType;
     UniformHandle fColorUniform;
@@ -316,7 +316,7 @@
 };
 
 GrGLQuadEffect::GrGLQuadEffect(const GrGeometryProcessor& processor)
-    : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL), fCoverageScale(0xff) {
+    : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor4h_ILLEGAL), fCoverageScale(0xff) {
     const GrQuadEffect& ce = processor.cast<GrQuadEffect>();
     fEdgeType = ce.getEdgeType();
 }
@@ -434,7 +434,7 @@
     return new GrGLQuadEffect(*this);
 }
 
-GrQuadEffect::GrQuadEffect(GrColor color, const SkMatrix& viewMatrix, uint8_t coverage,
+GrQuadEffect::GrQuadEffect(GrColor4h color, const SkMatrix& viewMatrix, uint8_t coverage,
                            GrClipEdgeType edgeType, const SkMatrix& localMatrix,
                            bool usesLocalCoords)
     : INHERITED(kGrQuadEffect_ClassID)
@@ -457,9 +457,9 @@
     do {
         GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(
                 d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
-        gp = GrQuadEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom), edgeType,
-                                *d->caps(), GrTest::TestMatrix(d->fRandom),
-                                d->fRandom->nextBool());
+        gp = GrQuadEffect::Make(GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
+                                GrTest::TestMatrix(d->fRandom), edgeType, *d->caps(),
+                                GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool());
     } while (nullptr == gp);
     return gp;
 }
@@ -499,7 +499,7 @@
 
         if (ce.color() != fColor) {
             float c[4];
-            GrColorToRGBAFloat(ce.color(), c);
+            ce.color().toFloats(c);
             pdman.set4fv(fColorUniform, 1, c);
             fColor = ce.color();
         }
@@ -510,7 +510,7 @@
 private:
     SkMatrix fViewMatrix;
     SkMatrix fDevKLMMatrix;
-    GrColor fColor;
+    GrColor4h fColor;
     GrClipEdgeType fEdgeType;
     UniformHandle fColorUniform;
     UniformHandle fViewMatrixUniform;
@@ -522,7 +522,7 @@
 GrGLCubicEffect::GrGLCubicEffect(const GrGeometryProcessor& processor)
     : fViewMatrix(SkMatrix::InvalidMatrix())
     , fDevKLMMatrix(SkMatrix::InvalidMatrix())
-    , fColor(GrColor_ILLEGAL) {
+    , fColor(GrColor4h_ILLEGAL) {
     const GrCubicEffect& ce = processor.cast<GrCubicEffect>();
     fEdgeType = ce.getEdgeType();
 }
@@ -661,7 +661,7 @@
     return new GrGLCubicEffect(*this);
 }
 
-GrCubicEffect::GrCubicEffect(GrColor color, const SkMatrix& viewMatrix, const SkMatrix&
+GrCubicEffect::GrCubicEffect(GrColor4h color, const SkMatrix& viewMatrix, const SkMatrix&
                              devKLMMatrix, GrClipEdgeType edgeType)
     : INHERITED(kGrCubicEffect_ClassID)
     , fColor(color)
@@ -682,9 +682,9 @@
         GrClipEdgeType edgeType =
                 static_cast<GrClipEdgeType>(
                         d->fRandom->nextULessThan(kGrClipEdgeTypeCnt));
-        gp = GrCubicEffect::Make(GrRandomColor(d->fRandom), GrTest::TestMatrix(d->fRandom),
-                                 GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool(), edgeType,
-                                 *d->caps());
+        gp = GrCubicEffect::Make(GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
+                                 GrTest::TestMatrix(d->fRandom), GrTest::TestMatrix(d->fRandom),
+                                 d->fRandom->nextBool(), edgeType, *d->caps());
     } while (nullptr == gp);
     return gp;
 }
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index b8742e8..de5283c 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -57,7 +57,7 @@
 
 class GrConicEffect : public GrGeometryProcessor {
 public:
-    static sk_sp<GrGeometryProcessor> Make(GrColor color,
+    static sk_sp<GrGeometryProcessor> Make(GrColor4h color,
                                            const SkMatrix& viewMatrix,
                                            const GrClipEdgeType edgeType,
                                            const GrCaps& caps,
@@ -98,7 +98,7 @@
     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
     inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
     bool usesLocalCoords() const { return fUsesLocalCoords; }
@@ -109,12 +109,12 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    GrConicEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
+    GrConicEffect(GrColor4h, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
                   const SkMatrix& localMatrix, bool usesLocalCoords);
 
     const Attribute& onVertexAttribute(int i) const override { return kAttributes[i]; }
 
-    GrColor             fColor;
+    GrColor4h           fColor;
     SkMatrix            fViewMatrix;
     SkMatrix            fLocalMatrix;
     bool                fUsesLocalCoords;
@@ -143,7 +143,7 @@
 
 class GrQuadEffect : public GrGeometryProcessor {
 public:
-    static sk_sp<GrGeometryProcessor> Make(GrColor color,
+    static sk_sp<GrGeometryProcessor> Make(GrColor4h color,
                                            const SkMatrix& viewMatrix,
                                            const GrClipEdgeType edgeType,
                                            const GrCaps& caps,
@@ -184,7 +184,7 @@
     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
     inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
     bool usesLocalCoords() const { return fUsesLocalCoords; }
@@ -195,12 +195,12 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    GrQuadEffect(GrColor, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
+    GrQuadEffect(GrColor4h, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType,
                  const SkMatrix& localMatrix, bool usesLocalCoords);
 
     const Attribute& onVertexAttribute(int i) const override { return kAttributes[i]; }
 
-    GrColor fColor;
+    GrColor4h fColor;
     SkMatrix fViewMatrix;
     SkMatrix fLocalMatrix;
     bool fUsesLocalCoords;
@@ -232,7 +232,7 @@
 
 class GrCubicEffect : public GrGeometryProcessor {
 public:
-    static sk_sp<GrGeometryProcessor> Make(GrColor color,
+    static sk_sp<GrGeometryProcessor> Make(GrColor4h color,
                                            const SkMatrix& viewMatrix,
                                            const SkMatrix& klm,
                                            bool flipKL,
@@ -276,8 +276,8 @@
     inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); }
     inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); }
     inline GrClipEdgeType getEdgeType() const { return fEdgeType; }
-    GrColor color() const { return fColor; }
-    bool colorIgnored() const { return GrColor_ILLEGAL == fColor; }
+    GrColor4h color() const { return fColor; }
+    bool colorIgnored() const { return GrColor4h_ILLEGAL == fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     const SkMatrix& devKLMMatrix() const { return fDevKLMMatrix; }
 
@@ -286,12 +286,12 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    GrCubicEffect(GrColor, const SkMatrix& viewMatrix, const SkMatrix& devKLMMatrix,
+    GrCubicEffect(GrColor4h, const SkMatrix& viewMatrix, const SkMatrix& devKLMMatrix,
                   GrClipEdgeType);
 
     const Attribute& onVertexAttribute(int) const override { return kInPosition; }
 
-    GrColor fColor;
+    GrColor4h fColor;
     SkMatrix fViewMatrix;
     SkMatrix fDevKLMMatrix;
     GrClipEdgeType fEdgeType;
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 667f13b..018ec85 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -20,7 +20,7 @@
 
 class GrGLBitmapTextGeoProc : public GrGLSLGeometryProcessor {
 public:
-    GrGLBitmapTextGeoProc() : fColor(GrColor_ILLEGAL), fAtlasSize({0,0}) {}
+    GrGLBitmapTextGeoProc() : fColor(GrColor4h_ILLEGAL), fAtlasSize({0,0}) {}
 
     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
         const GrBitmapTextGeoProc& btgp = args.fGP.cast<GrBitmapTextGeoProc>();
@@ -83,7 +83,7 @@
         const GrBitmapTextGeoProc& btgp = gp.cast<GrBitmapTextGeoProc>();
         if (btgp.color() != fColor && !btgp.hasVertexColor()) {
             float c[4];
-            GrColorToRGBAFloat(btgp.color(), c);
+            btgp.color().toFloats(c);
             pdman.set4fv(fColorUniform, 1, c);
             fColor = btgp.color();
         }
@@ -110,7 +110,7 @@
     }
 
 private:
-    GrColor       fColor;
+    GrColor4h     fColor;
     UniformHandle fColorUniform;
 
     SkISize       fAtlasSize;
@@ -122,7 +122,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrBitmapTextGeoProc::GrBitmapTextGeoProc(const GrShaderCaps& caps,
-                                         GrColor color,
+                                         GrColor4h color,
                                          const sk_sp<GrTextureProxy>* proxies,
                                          int numActiveProxies,
                                          const GrSamplerState& params, GrMaskFormat format,
@@ -232,8 +232,9 @@
             break;
     }
 
-    return GrBitmapTextGeoProc::Make(*d->caps()->shaderCaps(), GrRandomColor(d->fRandom), proxies,
-                                     1, samplerState, format, GrTest::TestMatrix(d->fRandom),
-                                     d->fRandom->nextBool());
+    return GrBitmapTextGeoProc::Make(*d->caps()->shaderCaps(),
+                                     GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
+                                     proxies, 1, samplerState, format,
+                                     GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool());
 }
 #endif
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index 5f671b2..21ddc7e 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -23,7 +23,7 @@
 public:
     static constexpr int kMaxTextures = 4;
 
-    static sk_sp<GrGeometryProcessor> Make(const GrShaderCaps& caps, GrColor color,
+    static sk_sp<GrGeometryProcessor> Make(const GrShaderCaps& caps, GrColor4h color,
                                            const sk_sp<GrTextureProxy>* proxies,
                                            int numActiveProxies,
                                            const GrSamplerState& p, GrMaskFormat format,
@@ -41,7 +41,7 @@
     const Attribute& inColor() const { return fInColor; }
     const Attribute& inTextureCoords() const { return fInTextureCoords; }
     GrMaskFormat maskFormat() const { return fMaskFormat; }
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     bool hasVertexColor() const { return fInColor.isInitialized(); }
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
     bool usesW() const { return fUsesW; }
@@ -54,14 +54,14 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override;
 
 private:
-    GrBitmapTextGeoProc(const GrShaderCaps&, GrColor, const sk_sp<GrTextureProxy>* proxies,
+    GrBitmapTextGeoProc(const GrShaderCaps&, GrColor4h, const sk_sp<GrTextureProxy>* proxies,
                         int numProxies, const GrSamplerState& params, GrMaskFormat format,
                         const SkMatrix& localMatrix, bool usesW);
 
     const Attribute& onVertexAttribute(int i) const override;
     const TextureSampler& onTextureSampler(int i) const override { return fTextureSamplers[i]; }
 
-    GrColor          fColor;
+    GrColor4h        fColor;
     SkMatrix         fLocalMatrix;
     bool             fUsesW;
     SkISize          fAtlasSize;  // size for all textures used with fTextureSamplers[].
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp
index 68b8b8e..6896526 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -765,7 +765,7 @@
                                                      stencilSettings);
     }
 
-    AAConvexPathOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    AAConvexPathOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                    const SkPath& path, const GrUserStencilSettings* stencilSettings)
             : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
         fPaths.emplace_back(PathData{viewMatrix, path, color});
@@ -843,7 +843,8 @@
                 return;
             }
 
-            extract_lines_only_verts(tess, verts, vertexStride, args.fColor, idxs,
+            // TODO4F: Preserve float colors
+            extract_lines_only_verts(tess, verts, vertexStride, args.fColor.toGrColor(), idxs,
                                      fHelper.compatibleWithAlphaAsCoverage());
 
             GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
@@ -929,7 +930,8 @@
             }
 
             SkSTArray<kPreallocDrawCnt, Draw, true> draws;
-            create_vertices(segments, fanPt, args.fColor, &draws, verts, idxs);
+            // TODO4F: Preserve float colors
+            create_vertices(segments, fanPt, args.fColor.toGrColor(), &draws, verts, idxs);
 
             GrMesh* meshes = target->allocMeshes(draws.count());
             for (int j = 0; j < draws.count(); ++j) {
@@ -967,7 +969,7 @@
     struct PathData {
         SkMatrix fViewMatrix;
         SkPath fPath;
-        GrColor fColor;
+        GrColor4h fColor;
     };
 
     Helper fHelper;
diff --git a/src/gpu/ops/GrAAFillRectOp.cpp b/src/gpu/ops/GrAAFillRectOp.cpp
index f1987a7..b77f09e 100644
--- a/src/gpu/ops/GrAAFillRectOp.cpp
+++ b/src/gpu/ops/GrAAFillRectOp.cpp
@@ -185,7 +185,7 @@
     }
 
     AAFillRectOp(const Helper::MakeArgs& helperArgs,
-                 GrColor color,
+                 GrColor4h color,
                  const SkMatrix& viewMatrix,
                  const SkRect& rect,
                  const SkRect& devRect,
@@ -219,7 +219,8 @@
         for (int i = 0; i < fRectCnt; ++i) {
             const SkRect& rect = info->rect();
             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
-                        info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
+                        info->color().toGrColor(), rect.fLeft, rect.fTop, rect.fRight,
+                        rect.fBottom);
             info = this->next(info);
         }
         str += fHelper.dumpInfo();
@@ -230,7 +231,7 @@
     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor color = this->first()->color();
+        GrColor4h color = this->first()->color();
         auto result = fHelper.xpRequiresDstTexture(
                 caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &color);
         this->first()->setColor(color);
@@ -285,8 +286,9 @@
                     localMatrix = &SkMatrix::I();
                 }
             }
-            generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), info->viewMatrix(),
-                                           info->rect(), info->devRect(),
+            // TODO4F: Preserve float colors
+            generate_aa_fill_rect_geometry(verts, vertexStride, info->color().toGrColor(),
+                                           info->viewMatrix(), info->rect(), info->devRect(),
                                            fHelper.compatibleWithAlphaAsCoverage(), localMatrix);
             info = this->next(info);
         }
@@ -307,21 +309,21 @@
 
     struct RectInfo {
     public:
-        RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
+        RectInfo(GrColor4h color, const SkMatrix& viewMatrix, const SkRect& rect,
                  const SkRect& devRect)
                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
         bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
-        GrColor color() const { return fColor; }
+        GrColor4h color() const { return fColor; }
         const SkMatrix& viewMatrix() const { return fViewMatrix; }
         const SkRect& rect() const { return fRect; }
         const SkRect& devRect() const { return fDevRect; }
 
-        void setColor(GrColor color) { fColor = color; }
+        void setColor(GrColor4h color) { fColor = color; }
 
     protected:
         enum class HasLocalMatrix : uint32_t { kNo, kYes };
 
-        RectInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
+        RectInfo(GrColor4h color, const SkMatrix& viewMatrix, const SkRect& rect,
                  const SkRect& devRect, HasLocalMatrix hasLM)
                 : fHasLocalMatrix(hasLM)
                 , fColor(color)
@@ -330,7 +332,7 @@
                 , fDevRect(devRect) {}
 
         HasLocalMatrix fHasLocalMatrix;
-        GrColor fColor;
+        GrColor4h fColor;
         SkMatrix fViewMatrix;
         SkRect fRect;
         SkRect fDevRect;
@@ -338,7 +340,7 @@
 
     struct RectWithLocalMatrixInfo : public RectInfo {
     public:
-        RectWithLocalMatrixInfo(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
+        RectWithLocalMatrixInfo(GrColor4h color, const SkMatrix& viewMatrix, const SkRect& rect,
                                 const SkRect& devRect, const SkMatrix& localMatrix)
                 : RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
                 , fLocalMatrix(localMatrix) {}
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index c59d53f..3bfc055 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -803,7 +803,7 @@
     }
 
     AAHairlineOp(const Helper::MakeArgs& helperArgs,
-                 GrColor color,
+                 GrColor4h color,
                  uint8_t coverage,
                  const SkMatrix& viewMatrix,
                  const SkPath& path,
@@ -828,8 +828,8 @@
 
     SkString dumpInfo() const override {
         SkString string;
-        string.appendf("Color: 0x%08x Coverage: 0x%02x, Count: %d\n", fColor, fCoverage,
-                       fPaths.count());
+        string.appendf("Color: 0x%08x Coverage: 0x%02x, Count: %d\n", fColor.toGrColor(),
+                       fCoverage, fPaths.count());
         string += INHERITED::dumpInfo();
         string += fHelper.dumpInfo();
         return string;
@@ -885,7 +885,7 @@
         return CombineResult::kMerged;
     }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     uint8_t coverage() const { return fCoverage; }
     const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
 
@@ -898,7 +898,7 @@
 
     SkSTArray<1, PathData, true> fPaths;
     Helper fHelper;
-    GrColor fColor;
+    GrColor4h fColor;
     uint8_t fCoverage;
 
     typedef GrMeshDrawOp INHERITED;
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
index 1ecceb1..51a1b87 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -157,7 +157,7 @@
     }
 
     AAFlatteningConvexPathOp(const Helper::MakeArgs& helperArgs,
-                             GrColor color,
+                             GrColor4h color,
                              const SkMatrix& viewMatrix,
                              const SkPath& path,
                              SkScalar strokeWidth,
@@ -195,7 +195,8 @@
             string.appendf(
                     "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
                     "MiterLimit: %.2f\n",
-                    path.fColor, path.fStrokeWidth, path.fStyle, path.fJoin, path.fMiterLimit);
+                    path.fColor.toGrColor(), path.fStrokeWidth, path.fStyle, path.fJoin,
+                    path.fMiterLimit);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -304,8 +305,9 @@
                 indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
             }
 
-            extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride, args.fColor,
-                          vertexCount, indices + indexCount,
+            // TODO4F: Preserve float colors
+            extract_verts(tess, vertices + vertexStride * vertexCount, vertexStride,
+                          args.fColor.toGrColor(), vertexCount, indices + indexCount,
                           fHelper.compatibleWithAlphaAsCoverage());
             vertexCount += currentVertices;
             indexCount += currentIndices;
@@ -331,7 +333,7 @@
     const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
 
     struct PathData {
-        GrColor fColor;
+        GrColor4h fColor;
         SkMatrix fViewMatrix;
         SkPath fPath;
         SkScalar fStrokeWidth;
diff --git a/src/gpu/ops/GrAAStrokeRectOp.cpp b/src/gpu/ops/GrAAStrokeRectOp.cpp
index 625635e..92f0c62 100644
--- a/src/gpu/ops/GrAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrAAStrokeRectOp.cpp
@@ -133,7 +133,7 @@
                                                      devOutside, devInside);
     }
 
-    AAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    AAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                    const SkRect& devOutside, const SkRect& devInside)
             : INHERITED(ClassID())
             , fHelper(helperArgs, GrAAType::kCoverage)
@@ -159,7 +159,7 @@
                                                      stroke, isMiter);
     }
 
-    AAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    AAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                    const SkRect& rect, const SkStrokeRec& stroke, bool isMiter)
             : INHERITED(ClassID())
             , fHelper(helperArgs, GrAAType::kCoverage)
@@ -193,7 +193,7 @@
                     "Color: 0x%08x, ORect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
                     "AssistORect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
                     "IRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], Degen: %d",
-                    info.fColor, info.fDevOutside.fLeft, info.fDevOutside.fTop,
+                    info.fColor.toGrColor(), info.fDevOutside.fLeft, info.fDevOutside.fTop,
                     info.fDevOutside.fRight, info.fDevOutside.fBottom, info.fDevOutsideAssist.fLeft,
                     info.fDevOutsideAssist.fTop, info.fDevOutsideAssist.fRight,
                     info.fDevOutsideAssist.fBottom, info.fDevInside.fLeft, info.fDevInside.fTop,
@@ -244,7 +244,7 @@
 
     // TODO support AA rotated stroke rects by copying around view matrices
     struct RectInfo {
-        GrColor fColor;
+        GrColor4h fColor;
         SkRect fDevOutside;
         SkRect fDevOutsideAssist;
         SkRect fDevInside;
@@ -299,7 +299,7 @@
                                            vertexStride,
                                            outerVertexNum,
                                            innerVertexNum,
-                                           info.fColor,
+                                           info.fColor.toGrColor(), // TODO4F
                                            info.fDevOutside,
                                            info.fDevOutsideAssist,
                                            info.fDevInside,
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index 7c14c6c..7c3a834 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -123,7 +123,7 @@
     for (int i = 0; i < fGeoCount; ++i) {
         str.appendf("%d: Color: 0x%08x Trans: %.2f,%.2f Runs: %d\n",
                     i,
-                    fGeoData[i].fColor,
+                    fGeoData[i].fColor.toGrColor(),
                     fGeoData[i].fX,
                     fGeoData[i].fY,
                     fGeoData[i].fBlob->runCount());
@@ -346,9 +346,10 @@
     for (int i = 0; i < fGeoCount; i++) {
         const Geometry& args = fGeoData[i];
         Blob* blob = args.fBlob;
+        // TODO4F: Preserve float colors
         GrTextBlob::VertexRegenerator regenerator(
                 resourceProvider, blob, args.fRun, args.fSubRun, args.fViewMatrix, args.fX, args.fY,
-                args.fColor, target->deferredUploadTarget(), glyphCache, atlasManager,
+                args.fColor.toGrColor(), target->deferredUploadTarget(), glyphCache, atlasManager,
                 &autoGlyphCache);
         bool done = false;
         while (!done) {
diff --git a/src/gpu/ops/GrAtlasTextOp.h b/src/gpu/ops/GrAtlasTextOp.h
index df2f11c..9fabe91 100644
--- a/src/gpu/ops/GrAtlasTextOp.h
+++ b/src/gpu/ops/GrAtlasTextOp.h
@@ -31,14 +31,14 @@
 
     typedef GrTextBlob Blob;
     struct Geometry {
-        SkMatrix fViewMatrix;
-        SkIRect  fClipRect;
-        Blob*    fBlob;
-        SkScalar fX;
-        SkScalar fY;
-        uint16_t fRun;
-        uint16_t fSubRun;
-        GrColor  fColor;
+        SkMatrix  fViewMatrix;
+        SkIRect   fClipRect;
+        Blob*     fBlob;
+        SkScalar  fX;
+        SkScalar  fY;
+        uint16_t  fRun;
+        uint16_t  fSubRun;
+        GrColor4h fColor;
     };
 
     static std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrContext* context,
@@ -145,7 +145,7 @@
 
     inline void flush(GrMeshDrawOp::Target* target, FlushInfo* flushInfo) const;
 
-    GrColor color() const { SkASSERT(fGeoCount > 0); return fGeoData[0].fColor; }
+    GrColor4h color() const { SkASSERT(fGeoCount > 0); return fGeoData[0].fColor; }
     bool usesLocalCoords() const { return fUsesLocalCoords; }
     int numGlyphs() const { return fNumGlyphs; }
 
diff --git a/src/gpu/ops/GrDashOp.cpp b/src/gpu/ops/GrDashOp.cpp
index 2a36607..d1b4f28 100644
--- a/src/gpu/ops/GrDashOp.cpp
+++ b/src/gpu/ops/GrDashOp.cpp
@@ -244,7 +244,7 @@
  * Bounding geometry is rendered and the effect computes coverage based on the fragment's
  * position relative to the dashed line.
  */
-static sk_sp<GrGeometryProcessor> make_dash_gp(GrColor,
+static sk_sp<GrGeometryProcessor> make_dash_gp(GrColor4h,
                                                AAMode aaMode,
                                                DashCap cap,
                                                const SkMatrix& localMatrix,
@@ -332,7 +332,7 @@
     DashOp(GrPaint&& paint, const LineData& geometry, SkPaint::Cap cap, AAMode aaMode,
            bool fullDash, const GrUserStencilSettings* stencilSettings)
             : INHERITED(ClassID())
-            , fColor(paint.getColor())
+            , fColor(GrColor4h::FromFloats(paint.getColor4f().vec()))
             , fFullDash(fullDash)
             , fCap(cap)
             , fAAMode(aaMode)
@@ -734,7 +734,7 @@
         return CombineResult::kMerged;
     }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fLines[0].fViewMatrix; }
     AAMode aaMode() const { return fAAMode; }
     bool fullDash() const { return fFullDash; }
@@ -744,7 +744,7 @@
     static const int kIndicesPerDash = 6;
 
     SkSTArray<1, LineData, true> fLines;
-    GrColor fColor;
+    GrColor4h fColor;
     bool fDisallowCombineOnTouchOrOverlap : 1;
     bool fUsesLocalCoords : 1;
     bool fFullDash : 1;
@@ -834,7 +834,7 @@
 public:
     typedef SkPathEffect::DashInfo DashInfo;
 
-    static sk_sp<GrGeometryProcessor> Make(GrColor,
+    static sk_sp<GrGeometryProcessor> Make(GrColor4h,
                                            AAMode aaMode,
                                            const SkMatrix& localMatrix,
                                            bool usesLocalCoords);
@@ -843,7 +843,7 @@
 
     AAMode aaMode() const { return fAAMode; }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
 
     const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
@@ -854,14 +854,14 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    DashingCircleEffect(GrColor, AAMode aaMode, const SkMatrix& localMatrix,
+    DashingCircleEffect(GrColor4h, AAMode aaMode, const SkMatrix& localMatrix,
                         bool usesLocalCoords);
 
     const Attribute& onVertexAttribute(int i) const override {
         return IthAttribute(i, kInPosition, kInDashParams, kInCircleParams);
     }
 
-    GrColor             fColor;
+    GrColor4h           fColor;
     SkMatrix            fLocalMatrix;
     bool                fUsesLocalCoords;
     AAMode              fAAMode;
@@ -899,7 +899,7 @@
 private:
     UniformHandle fParamUniform;
     UniformHandle fColorUniform;
-    GrColor       fColor;
+    GrColor4h     fColor;
     SkScalar      fPrevRadius;
     SkScalar      fPrevCenterX;
     SkScalar      fPrevIntervalLength;
@@ -907,7 +907,7 @@
 };
 
 GLDashingCircleEffect::GLDashingCircleEffect() {
-    fColor = GrColor_ILLEGAL;
+    fColor = GrColor4h_ILLEGAL;
     fPrevRadius = SK_ScalarMin;
     fPrevCenterX = SK_ScalarMin;
     fPrevIntervalLength = SK_ScalarMax;
@@ -971,7 +971,7 @@
     const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>();
     if (dce.color() != fColor) {
         float c[4];
-        GrColorToRGBAFloat(dce.color(), c);
+        dce.color().toFloats(c);
         pdman.set4fv(fColorUniform, 1, c);
         fColor = dce.color();
     }
@@ -990,7 +990,7 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-sk_sp<GrGeometryProcessor> DashingCircleEffect::Make(GrColor color,
+sk_sp<GrGeometryProcessor> DashingCircleEffect::Make(GrColor4h color,
                                                      AAMode aaMode,
                                                      const SkMatrix& localMatrix,
                                                      bool usesLocalCoords) {
@@ -1007,7 +1007,7 @@
     return new GLDashingCircleEffect();
 }
 
-DashingCircleEffect::DashingCircleEffect(GrColor color,
+DashingCircleEffect::DashingCircleEffect(GrColor4h color,
                                          AAMode aaMode,
                                          const SkMatrix& localMatrix,
                                          bool usesLocalCoords)
@@ -1024,9 +1024,9 @@
 #if GR_TEST_UTILS
 sk_sp<GrGeometryProcessor> DashingCircleEffect::TestCreate(GrProcessorTestData* d) {
     AAMode aaMode = static_cast<AAMode>(d->fRandom->nextULessThan(GrDashOp::kAAModeCnt));
-    return DashingCircleEffect::Make(GrRandomColor(d->fRandom),
-                                    aaMode, GrTest::TestMatrix(d->fRandom),
-                                    d->fRandom->nextBool());
+    return DashingCircleEffect::Make(GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
+                                     aaMode, GrTest::TestMatrix(d->fRandom),
+                                     d->fRandom->nextBool());
 }
 #endif
 
@@ -1047,7 +1047,7 @@
 public:
     typedef SkPathEffect::DashInfo DashInfo;
 
-    static sk_sp<GrGeometryProcessor> Make(GrColor,
+    static sk_sp<GrGeometryProcessor> Make(GrColor4h,
                                            AAMode aaMode,
                                            const SkMatrix& localMatrix,
                                            bool usesLocalCoords);
@@ -1056,7 +1056,7 @@
 
     AAMode aaMode() const { return fAAMode; }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
 
      const SkMatrix& localMatrix() const { return fLocalMatrix; }
 
@@ -1067,14 +1067,14 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    DashingLineEffect(GrColor, AAMode aaMode, const SkMatrix& localMatrix,
+    DashingLineEffect(GrColor4h, AAMode aaMode, const SkMatrix& localMatrix,
                       bool usesLocalCoords);
 
     const Attribute& onVertexAttribute(int i) const override {
         return IthAttribute(i, kInPosition, kInDashParams, kInRectParams);
     }
 
-    GrColor             fColor;
+    GrColor4h           fColor;
     SkMatrix            fLocalMatrix;
     bool                fUsesLocalCoords;
     AAMode              fAAMode;
@@ -1112,12 +1112,12 @@
                  FPCoordTransformIter&& iter) override;
 
 private:
-    GrColor       fColor;
+    GrColor4h     fColor;
     UniformHandle fColorUniform;
     typedef GrGLSLGeometryProcessor INHERITED;
 };
 
-GLDashingLineEffect::GLDashingLineEffect() : fColor(GrColor_ILLEGAL) {}
+GLDashingLineEffect::GLDashingLineEffect() : fColor(GrColor4h_ILLEGAL) {}
 
 void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
     const DashingLineEffect& de = args.fGP.cast<DashingLineEffect>();
@@ -1197,7 +1197,7 @@
     const DashingLineEffect& de = processor.cast<DashingLineEffect>();
     if (de.color() != fColor) {
         float c[4];
-        GrColorToRGBAFloat(de.color(), c);
+        de.color().toFloats(c);
         pdman.set4fv(fColorUniform, 1, c);
         fColor = de.color();
     }
@@ -1216,7 +1216,7 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-sk_sp<GrGeometryProcessor> DashingLineEffect::Make(GrColor color,
+sk_sp<GrGeometryProcessor> DashingLineEffect::Make(GrColor4h color,
                                                    AAMode aaMode,
                                                    const SkMatrix& localMatrix,
                                                    bool usesLocalCoords) {
@@ -1233,7 +1233,7 @@
     return new GLDashingLineEffect();
 }
 
-DashingLineEffect::DashingLineEffect(GrColor color,
+DashingLineEffect::DashingLineEffect(GrColor4h color,
                                      AAMode aaMode,
                                      const SkMatrix& localMatrix,
                                      bool usesLocalCoords)
@@ -1250,7 +1250,7 @@
 #if GR_TEST_UTILS
 sk_sp<GrGeometryProcessor> DashingLineEffect::TestCreate(GrProcessorTestData* d) {
     AAMode aaMode = static_cast<AAMode>(d->fRandom->nextULessThan(GrDashOp::kAAModeCnt));
-    return DashingLineEffect::Make(GrRandomColor(d->fRandom),
+    return DashingLineEffect::Make(GrColor4h::FromGrColor(GrRandomColor(d->fRandom)),
                                    aaMode, GrTest::TestMatrix(d->fRandom),
                                    d->fRandom->nextBool());
 }
@@ -1258,7 +1258,7 @@
 #endif
 //////////////////////////////////////////////////////////////////////////////
 
-static sk_sp<GrGeometryProcessor> make_dash_gp(GrColor color,
+static sk_sp<GrGeometryProcessor> make_dash_gp(GrColor4h color,
                                                AAMode aaMode,
                                                DashCap cap,
                                                const SkMatrix& viewMatrix,
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index 0bff89c..f542961 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -363,7 +363,7 @@
 
     SkString dumpInfo() const override {
         SkString string;
-        string.appendf("Color: 0x%08x Count: %d\n", fColor, fPaths.count());
+        string.appendf("Color: 0x%08x Count: %d\n", fColor.toGrColor(), fPaths.count());
         for (const auto& path : fPaths) {
             string.appendf("Tolerance: %.2f\n", path.fTolerance);
         }
@@ -372,7 +372,7 @@
         return string;
     }
 
-    DefaultPathOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkPath& path,
+    DefaultPathOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkPath& path,
                   SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline,
                   GrAAType aaType, const SkRect& devBounds,
                   const GrUserStencilSettings* stencilSettings)
@@ -465,7 +465,7 @@
         return CombineResult::kMerged;
     }
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     uint8_t coverage() const { return fCoverage; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     bool isHairline() const { return fIsHairline; }
@@ -477,7 +477,7 @@
 
     SkSTArray<1, PathData, true> fPaths;
     Helper fHelper;
-    GrColor fColor;
+    GrColor4h fColor;
     uint8_t fCoverage;
     SkMatrix fViewMatrix;
     bool fIsHairline;
diff --git a/src/gpu/ops/GrDrawAtlasOp.cpp b/src/gpu/ops/GrDrawAtlasOp.cpp
index c4b44aa..691299a 100644
--- a/src/gpu/ops/GrDrawAtlasOp.cpp
+++ b/src/gpu/ops/GrDrawAtlasOp.cpp
@@ -15,7 +15,7 @@
 
 static sk_sp<GrGeometryProcessor> make_gp(const GrShaderCaps* shaderCaps,
                                           bool hasColors,
-                                          GrColor color,
+                                          GrColor4h color,
                                           const SkMatrix& viewMatrix) {
     using namespace GrDefaultGeoProcFactory;
     Color gpColor(color);
@@ -27,7 +27,7 @@
                                          LocalCoords::kHasExplicit_Type, viewMatrix);
 }
 
-GrDrawAtlasOp::GrDrawAtlasOp(const Helper::MakeArgs& helperArgs, GrColor color,
+GrDrawAtlasOp::GrDrawAtlasOp(const Helper::MakeArgs& helperArgs, GrColor4h color,
                              const SkMatrix& viewMatrix, GrAAType aaType, int spriteCount,
                              const SkRSXform* xforms, const SkRect* rects, const SkColor* colors)
         : INHERITED(ClassID()), fHelper(helperArgs, aaType), fColor(color) {
@@ -55,7 +55,8 @@
     uint8_t* currVertex = installedGeo.fVerts.begin();
 
     SkRect bounds = SkRectPriv::MakeLargestInverted();
-    int paintAlpha = GrColorUnpackA(installedGeo.fColor);
+    // TODO4F: Preserve float colors
+    int paintAlpha = GrColorUnpackA(installedGeo.fColor.toGrColor());
     for (int spriteIndex = 0; spriteIndex < spriteCount; ++spriteIndex) {
         // Transform rect
         SkPoint strip[4];
@@ -111,7 +112,7 @@
 SkString GrDrawAtlasOp::dumpInfo() const {
     SkString string;
     for (const auto& geo : fGeoData) {
-        string.appendf("Color: 0x%08x, Quads: %d\n", geo.fColor, geo.fVerts.count() / 4);
+        string.appendf("Color: 0x%08x, Quads: %d\n", geo.fColor.toGrColor(), geo.fVerts.count()/4);
     }
     string += fHelper.dumpInfo();
     string += INHERITED::dumpInfo();
diff --git a/src/gpu/ops/GrDrawAtlasOp.h b/src/gpu/ops/GrDrawAtlasOp.h
index fdb3476..97fb169 100644
--- a/src/gpu/ops/GrDrawAtlasOp.h
+++ b/src/gpu/ops/GrDrawAtlasOp.h
@@ -32,7 +32,7 @@
                                                     spriteCount, xforms, rects, colors);
     }
 
-    GrDrawAtlasOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    GrDrawAtlasOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                   GrAAType, int spriteCount, const SkRSXform* xforms, const SkRect* rects,
                   const SkColor* colors);
 
@@ -51,7 +51,7 @@
 private:
     void onPrepareDraws(Target*) override;
 
-    GrColor color() const { return fColor; }
+    GrColor4h color() const { return fColor; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     bool hasColors() const { return fHasColors; }
     int quadCount() const { return fQuadCount; }
@@ -59,14 +59,14 @@
     CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
 
     struct Geometry {
-        GrColor fColor;
+        GrColor4h fColor;
         SkTArray<uint8_t, true> fVerts;
     };
 
     SkSTArray<1, Geometry, true> fGeoData;
     Helper fHelper;
     SkMatrix fViewMatrix;
-    GrColor fColor;
+    GrColor4h fColor;
     int fQuadCount;
     bool fHasColors;
 
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp
index cc8a86d..4e75b57 100644
--- a/src/gpu/ops/GrDrawPathOp.cpp
+++ b/src/gpu/ops/GrDrawPathOp.cpp
@@ -16,7 +16,7 @@
                                    GrPathRendering::FillType fill, GrAAType aaType)
         : INHERITED(classID)
         , fViewMatrix(viewMatrix)
-        , fInputColor(paint.getColor())
+        , fInputColor(GrColor4h::FromFloats(paint.getColor4f().vec()))
         , fFillType(fill)
         , fAAType(aaType)
         , fProcessorSet(std::move(paint)) {}
diff --git a/src/gpu/ops/GrDrawPathOp.h b/src/gpu/ops/GrDrawPathOp.h
index cdd955e..8395118 100644
--- a/src/gpu/ops/GrDrawPathOp.h
+++ b/src/gpu/ops/GrDrawPathOp.h
@@ -40,7 +40,7 @@
 
 protected:
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
-    GrColor color() const { return fInputColor; }
+    GrColor4h color() const { return fInputColor; }
     GrPathRendering::FillType fillType() const { return fFillType; }
     const GrProcessorSet& processors() const { return fProcessorSet; }
     GrProcessorSet detachProcessors() { return std::move(fProcessorSet); }
@@ -61,7 +61,7 @@
     void onPrepare(GrOpFlushState*) final {}
 
     SkMatrix fViewMatrix;
-    GrColor fInputColor;
+    GrColor4h fInputColor;
     GrProcessorSet::Analysis fAnalysis;
     GrPathRendering::FillType fFillType;
     GrAAType fAAType;
diff --git a/src/gpu/ops/GrDrawVerticesOp.cpp b/src/gpu/ops/GrDrawVerticesOp.cpp
index da8eb3a..10ff9da 100644
--- a/src/gpu/ops/GrDrawVerticesOp.cpp
+++ b/src/gpu/ops/GrDrawVerticesOp.cpp
@@ -29,7 +29,7 @@
                                                    std::move(colorSpaceXform), viewMatrix);
 }
 
-GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor color,
+GrDrawVerticesOp::GrDrawVerticesOp(const Helper::MakeArgs& helperArgs, GrColor4h color,
                                    sk_sp<SkVertices> vertices, const SkVertices::Bone bones[],
                                    int boneCount, GrPrimitiveType primitiveType, GrAAType aaType,
                                    sk_sp<GrColorSpaceXform> colorSpaceXform,
@@ -426,6 +426,9 @@
             }
             size_t boneWeightOffset = offset;
 
+            // TODO4F: Preserve float colors
+            GrColor color = mesh.fColor.toGrColor();
+
             for (int j = 0; j < vertexCount; ++j) {
                 if (this->hasMultipleViewMatrices()) {
                     mesh.fViewMatrix.mapPoints(((SkPoint*)verts), &positions[j], 1);
@@ -436,7 +439,7 @@
                     if (mesh.hasPerVertexColors()) {
                         *(uint32_t*)((intptr_t)verts + kColorOffset) = colors[j];
                     } else {
-                        *(uint32_t*)((intptr_t)verts + kColorOffset) = mesh.fColor;
+                        *(uint32_t*)((intptr_t)verts + kColorOffset) = color;
                     }
                 }
                 if (hasLocalCoordsAttribute) {
diff --git a/src/gpu/ops/GrDrawVerticesOp.h b/src/gpu/ops/GrDrawVerticesOp.h
index 79a8309..17ea563 100644
--- a/src/gpu/ops/GrDrawVerticesOp.h
+++ b/src/gpu/ops/GrDrawVerticesOp.h
@@ -45,7 +45,7 @@
                                           sk_sp<GrColorSpaceXform>,
                                           GrPrimitiveType* overridePrimType = nullptr);
 
-    GrDrawVerticesOp(const Helper::MakeArgs&, GrColor, sk_sp<SkVertices>,
+    GrDrawVerticesOp(const Helper::MakeArgs&, GrColor4h, sk_sp<SkVertices>,
                      const SkVertices::Bone bones[], int boneCount, GrPrimitiveType, GrAAType,
                      sk_sp<GrColorSpaceXform>, const SkMatrix& viewMatrix);
 
@@ -101,7 +101,7 @@
     CombineResult onCombineIfPossible(GrOp* t, const GrCaps&) override;
 
     struct Mesh {
-        GrColor fColor;  // Used if this->hasPerVertexColors() is false.
+        GrColor4h fColor;  // Used if this->hasPerVertexColors() is false.
         sk_sp<SkVertices> fVertices;
         SkMatrix fViewMatrix;
         bool fIgnoreTexCoords;
diff --git a/src/gpu/ops/GrLatticeOp.cpp b/src/gpu/ops/GrLatticeOp.cpp
index 79a9062..d997b48 100644
--- a/src/gpu/ops/GrLatticeOp.cpp
+++ b/src/gpu/ops/GrLatticeOp.cpp
@@ -151,7 +151,7 @@
                                                      std::move(iter), dst);
     }
 
-    NonAALatticeOp(Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    NonAALatticeOp(Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                    sk_sp<GrTextureProxy> proxy, sk_sp<GrColorSpaceXform> colorSpaceXform,
                    GrSamplerState::Filter filter, std::unique_ptr<SkLatticeIter> iter,
                    const SkRect& dst)
@@ -182,8 +182,8 @@
 
         for (int i = 0; i < fPatches.count(); ++i) {
             str.appendf("%d: Color: 0x%08x Dst [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
-                        fPatches[i].fColor, fPatches[i].fDst.fLeft, fPatches[i].fDst.fTop,
-                        fPatches[i].fDst.fRight, fPatches[i].fDst.fBottom);
+                        fPatches[i].fColor.toGrColor(), fPatches[i].fDst.fLeft,
+                        fPatches[i].fDst.fTop, fPatches[i].fDst.fRight, fPatches[i].fDst.fBottom);
         }
 
         str += fHelper.dumpInfo();
@@ -194,7 +194,7 @@
     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        auto opaque = GrColorIsOpaque(fPatches[0].fColor) && GrPixelConfigIsOpaque(fProxy->config())
+        auto opaque = fPatches[0].fColor.isOpaque() && GrPixelConfigIsOpaque(fProxy->config())
                               ? GrProcessorAnalysisColor::Opaque::kYes
                               : GrProcessorAnalysisColor::Opaque::kNo;
         auto analysisColor = GrProcessorAnalysisColor(opaque);
@@ -238,6 +238,8 @@
         intptr_t verts = reinterpret_cast<intptr_t>(vertices);
         for (int i = 0; i < patchCnt; i++) {
             const Patch& patch = fPatches[i];
+            // TODO4F: Preserve float colors
+            GrColor patchColor = patch.fColor.toGrColor();
 
             // Apply the view matrix here if it is scale-translate.  Otherwise, we need to
             // wait until we've created the dst rects.
@@ -273,7 +275,7 @@
                 }
 
                 for (int j = 0; j < kVertsPerRect; ++j) {
-                    vertices[j].fColor = patch.fColor;
+                    vertices[j].fColor = patchColor;
                 }
                 verts += kVertsPerRect * kVertexStide;
             }
@@ -313,7 +315,7 @@
         SkMatrix fViewMatrix;
         std::unique_ptr<SkLatticeIter> fIter;
         SkRect fDst;
-        GrColor fColor;
+        GrColor4h fColor;
     };
 
     Helper fHelper;
diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
index b8b4a73..ae28114 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ b/src/gpu/ops/GrNonAAFillRectOp.cpp
@@ -125,7 +125,7 @@
 
     NonAAFillRectOp() = delete;
 
-    NonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix,
+    NonAAFillRectOp(const Helper::MakeArgs& args, GrColor4h color, const SkMatrix& viewMatrix,
                     const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix,
                     GrAAType aaType, const GrUserStencilSettings* stencilSettings)
             : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
@@ -160,8 +160,8 @@
         for (int i = 0; i < fRects.count(); ++i) {
             const RectInfo& info = fRects[i];
             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
-                        info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
-                        info.fRect.fBottom);
+                        info.fColor.toGrColor(), info.fRect.fLeft, info.fRect.fTop,
+                        info.fRect.fRight, info.fRect.fBottom);
         }
         str += fHelper.dumpInfo();
         str += INHERITED::dumpInfo();
@@ -169,7 +169,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fRects.front().fColor;
+        GrColor4h* color = &fRects.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
     }
 
@@ -203,7 +203,8 @@
         for (int i = 0; i < rectCount; i++) {
             intptr_t verts =
                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * kVertexStride;
-            tesselate(verts, kVertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
+            // TODO4F: Preserve float colors
+            tesselate(verts, kVertexStride, fRects[i].fColor.toGrColor(), &fRects[i].fViewMatrix,
                       fRects[i].fRect, &fRects[i].fLocalQuad);
         }
         auto pipe = fHelper.makePipeline(target);
@@ -220,7 +221,7 @@
     }
 
     struct RectInfo {
-        GrColor fColor;
+        GrColor4h fColor;
         SkMatrix fViewMatrix;
         SkRect fRect;
         GrQuad fLocalQuad;
@@ -254,7 +255,7 @@
 
     NonAAFillRectPerspectiveOp() = delete;
 
-    NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, GrColor color,
+    NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, GrColor4h color,
                                const SkMatrix& viewMatrix, const SkRect& rect,
                                const SkRect* localRect, const SkMatrix* localMatrix,
                                GrAAType aaType, const GrUserStencilSettings* stencilSettings)
@@ -288,8 +289,8 @@
         for (int i = 0; i < fRects.count(); ++i) {
             const RectInfo& geo = fRects[i];
             str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
-                        geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight,
-                        geo.fRect.fBottom);
+                        geo.fColor.toGrColor(), geo.fRect.fLeft, geo.fRect.fTop,
+                        geo.fRect.fRight, geo.fRect.fBottom);
         }
         str += fHelper.dumpInfo();
         str += INHERITED::dumpInfo();
@@ -297,7 +298,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fRects.front().fColor;
+        GrColor4h* color = &fRects.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
     }
 
@@ -334,13 +335,15 @@
 
         for (int i = 0; i < rectCount; i++) {
             const RectInfo& info = fRects[i];
+            // TODO4F: Preserve float colors
+            GrColor color = info.fColor.toGrColor();
             intptr_t verts =
                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
             if (fHasLocalRect) {
                 GrQuad quad(info.fLocalRect);
-                tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad);
+                tesselate(verts, vertexStride, color, nullptr, info.fRect, &quad);
             } else {
-                tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr);
+                tesselate(verts, vertexStride, color, nullptr, info.fRect, nullptr);
             }
         }
         auto pipe = fHelper.makePipeline(target);
@@ -370,7 +373,7 @@
 
     struct RectInfo {
         SkRect fRect;
-        GrColor fColor;
+        GrColor4h fColor;
         SkRect fLocalRect;
     };
 
diff --git a/src/gpu/ops/GrNonAAStrokeRectOp.cpp b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
index e7b2b17..7ace398 100644
--- a/src/gpu/ops/GrNonAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
@@ -72,7 +72,8 @@
         string.appendf(
                 "Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
                 "StrokeWidth: %.2f\n",
-                fColor, fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom, fStrokeWidth);
+                fColor.toGrColor(), fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
+                fStrokeWidth);
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
         return string;
@@ -99,7 +100,7 @@
                                                         stroke, aaType);
     }
 
-    NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor color, Helper::Flags flags,
+    NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor4h color, Helper::Flags flags,
                       const SkMatrix& viewMatrix, const SkRect& rect, const SkStrokeRec& stroke,
                       GrAAType aaType)
             : INHERITED(ClassID()), fHelper(helperArgs, aaType, flags) {
@@ -198,7 +199,7 @@
     // TODO: override onCombineIfPossible
 
     Helper fHelper;
-    GrColor fColor;
+    GrColor4h fColor;
     SkMatrix fViewMatrix;
     SkRect fRect;
     SkScalar fStrokeWidth;
diff --git a/src/gpu/ops/GrOvalOpFactory.cpp b/src/gpu/ops/GrOvalOpFactory.cpp
index 6df0cb4..8826d60 100644
--- a/src/gpu/ops/GrOvalOpFactory.cpp
+++ b/src/gpu/ops/GrOvalOpFactory.cpp
@@ -957,7 +957,7 @@
                                                radius, style, arcParams);
     }
 
-    CircleOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    CircleOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
              SkPoint center, SkScalar radius, const GrStyle& style, const ArcParams* arcParams)
             : GrMeshDrawOp(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
         const SkStrokeRec& stroke = style.strokeRec();
@@ -1147,9 +1147,10 @@
             string.appendf(
                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
                     "InnerRad: %.2f, OuterRad: %.2f\n",
-                    fCircles[i].fColor, fCircles[i].fDevBounds.fLeft, fCircles[i].fDevBounds.fTop,
-                    fCircles[i].fDevBounds.fRight, fCircles[i].fDevBounds.fBottom,
-                    fCircles[i].fInnerRadius, fCircles[i].fOuterRadius);
+                    fCircles[i].fColor.toGrColor(), fCircles[i].fDevBounds.fLeft,
+                    fCircles[i].fDevBounds.fTop, fCircles[i].fDevBounds.fRight,
+                    fCircles[i].fDevBounds.fBottom, fCircles[i].fInnerRadius,
+                    fCircles[i].fOuterRadius);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -1157,7 +1158,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fCircles.front().fColor;
+        GrColor4h* color = &fCircles.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
                                             color);
     }
@@ -1216,7 +1217,8 @@
         for (const auto& circle : fCircles) {
             SkScalar innerRadius = circle.fInnerRadius;
             SkScalar outerRadius = circle.fOuterRadius;
-            GrColor color = circle.fColor;
+            // TODO4F: Preserve float colors
+            GrColor color = circle.fColor.toGrColor();
             const SkRect& bounds = circle.fDevBounds;
 
             CircleVertex* v0 = reinterpret_cast<CircleVertex*>(vertices + 0 * vertexStride);
@@ -1526,7 +1528,7 @@
     }
 
     struct Circle {
-        GrColor fColor;
+        GrColor4h fColor;
         SkScalar fInnerRadius;
         SkScalar fOuterRadius;
         SkScalar fClipPlane[3];
@@ -1575,7 +1577,7 @@
                                                             onAngle, offAngle, phaseAngle);
     }
 
-    ButtCapDashedCircleOp(const Helper::MakeArgs& helperArgs, GrColor color,
+    ButtCapDashedCircleOp(const Helper::MakeArgs& helperArgs, GrColor4h color,
                           const SkMatrix& viewMatrix, SkPoint center, SkScalar radius,
                           SkScalar strokeWidth, SkScalar startAngle, SkScalar onAngle,
                           SkScalar offAngle, SkScalar phaseAngle)
@@ -1660,10 +1662,11 @@
                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
                     "InnerRad: %.2f, OuterRad: %.2f, OnAngle: %.2f, TotalAngle: %.2f, "
                     "Phase: %.2f\n",
-                    fCircles[i].fColor, fCircles[i].fDevBounds.fLeft, fCircles[i].fDevBounds.fTop,
-                    fCircles[i].fDevBounds.fRight, fCircles[i].fDevBounds.fBottom,
-                    fCircles[i].fInnerRadius, fCircles[i].fOuterRadius, fCircles[i].fOnAngle,
-                    fCircles[i].fTotalAngle, fCircles[i].fPhaseAngle);
+                    fCircles[i].fColor.toGrColor(), fCircles[i].fDevBounds.fLeft,
+                    fCircles[i].fDevBounds.fTop, fCircles[i].fDevBounds.fRight,
+                    fCircles[i].fDevBounds.fBottom, fCircles[i].fInnerRadius,
+                    fCircles[i].fOuterRadius, fCircles[i].fOnAngle, fCircles[i].fTotalAngle,
+                    fCircles[i].fPhaseAngle);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -1671,7 +1674,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fCircles.front().fColor;
+        GrColor4h* color = &fCircles.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
                                             color);
     }
@@ -1734,12 +1737,15 @@
                 totalAngle = -totalAngle;
             }
 
+            // TODO4F: Preserve float colors
+            GrColor color = circle.fColor.toGrColor();
+
             // The bounding geometry for the circle is composed of an outer bounding octagon and
             // an inner bounded octagon.
 
             // Initializes the attributes that are the same at each vertex. Also applies reflection.
             auto init_const_attrs_and_reflect = [&](CircleVertex* v) {
-                v->fColor = circle.fColor;
+                v->fColor = color;
                 v->fOuterRadius = circle.fOuterRadius;
                 v->fInnerRadius = normInnerRadius;
                 v->fOnAngle = circle.fOnAngle;
@@ -1835,7 +1841,7 @@
     }
 
     struct Circle {
-        GrColor fColor;
+        GrColor4h fColor;
         SkScalar fOuterRadius;
         SkScalar fInnerRadius;
         SkScalar fOnAngle;
@@ -1937,7 +1943,7 @@
                                                 params, stroke);
     }
 
-    EllipseOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    EllipseOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
               const DeviceSpaceParams& params, const SkStrokeRec& stroke)
             : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
         SkStrokeRec::Style style = stroke.getStyle();
@@ -1973,9 +1979,9 @@
             string.appendf(
                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
                     "XRad: %.2f, YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f\n",
-                    geo.fColor, geo.fDevBounds.fLeft, geo.fDevBounds.fTop, geo.fDevBounds.fRight,
-                    geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius,
-                    geo.fInnerYRadius);
+                    geo.fColor.toGrColor(), geo.fDevBounds.fLeft, geo.fDevBounds.fTop,
+                    geo.fDevBounds.fRight, geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius,
+                    geo.fInnerXRadius, geo.fInnerYRadius);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -1983,7 +1989,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fEllipses.front().fColor;
+        GrColor4h* color = &fEllipses.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
                                             color);
     }
@@ -2008,7 +2014,8 @@
         }
 
         for (const auto& ellipse : fEllipses) {
-            GrColor color = ellipse.fColor;
+            // TODO4F: Preserve float colors
+            GrColor color = ellipse.fColor.toGrColor();
             SkScalar xRadius = ellipse.fXRadius;
             SkScalar yRadius = ellipse.fYRadius;
 
@@ -2079,7 +2086,7 @@
     }
 
     struct Ellipse {
-        GrColor fColor;
+        GrColor4h fColor;
         SkScalar fXRadius;
         SkScalar fYRadius;
         SkScalar fInnerXRadius;
@@ -2174,7 +2181,7 @@
         return Helper::FactoryHelper<DIEllipseOp>(context, std::move(paint), params, viewMatrix);
     }
 
-    DIEllipseOp(Helper::MakeArgs& helperArgs, GrColor color, const DeviceSpaceParams& params,
+    DIEllipseOp(Helper::MakeArgs& helperArgs, GrColor4h color, const DeviceSpaceParams& params,
                 const SkMatrix& viewMatrix)
             : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
         // This expands the outer rect so that after CTM we end up with a half-pixel border
@@ -2209,9 +2216,9 @@
                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], XRad: %.2f, "
                     "YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f, GeoDX: %.2f, "
                     "GeoDY: %.2f\n",
-                    geo.fColor, geo.fBounds.fLeft, geo.fBounds.fTop, geo.fBounds.fRight,
-                    geo.fBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius,
-                    geo.fInnerYRadius, geo.fGeoDx, geo.fGeoDy);
+                    geo.fColor.toGrColor(), geo.fBounds.fLeft, geo.fBounds.fTop,
+                    geo.fBounds.fRight, geo.fBounds.fBottom, geo.fXRadius, geo.fYRadius,
+                    geo.fInnerXRadius, geo.fInnerYRadius, geo.fGeoDx, geo.fGeoDy);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -2219,7 +2226,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fEllipses.front().fColor;
+        GrColor4h* color = &fEllipses.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
                                             color);
     }
@@ -2240,7 +2247,8 @@
         }
 
         for (const auto& ellipse : fEllipses) {
-            GrColor color = ellipse.fColor;
+            // TODO4F: Preserve float colors
+            GrColor color = ellipse.fColor.toGrColor();
             SkScalar xRadius = ellipse.fXRadius;
             SkScalar yRadius = ellipse.fYRadius;
 
@@ -2314,7 +2322,7 @@
 
     struct Ellipse {
         SkMatrix fViewMatrix;
-        GrColor fColor;
+        GrColor4h fColor;
         SkScalar fXRadius;
         SkScalar fYRadius;
         SkScalar fInnerXRadius;
@@ -2477,7 +2485,7 @@
                                                       devRect, devRadius,
                                                       devStrokeWidth, strokeOnly);
     }
-    CircularRRectOp(Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    CircularRRectOp(Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                     const SkRect& devRect, float devRadius, float devStrokeWidth, bool strokeOnly)
             : INHERITED(ClassID())
             , fViewMatrixIfUsingLocalCoords(viewMatrix)
@@ -2540,9 +2548,10 @@
             string.appendf(
                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f],"
                     "InnerRad: %.2f, OuterRad: %.2f\n",
-                    fRRects[i].fColor, fRRects[i].fDevBounds.fLeft, fRRects[i].fDevBounds.fTop,
-                    fRRects[i].fDevBounds.fRight, fRRects[i].fDevBounds.fBottom,
-                    fRRects[i].fInnerRadius, fRRects[i].fOuterRadius);
+                    fRRects[i].fColor.toGrColor(), fRRects[i].fDevBounds.fLeft,
+                    fRRects[i].fDevBounds.fTop, fRRects[i].fDevBounds.fRight,
+                    fRRects[i].fDevBounds.fBottom, fRRects[i].fInnerRadius,
+                    fRRects[i].fOuterRadius);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -2550,7 +2559,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fRRects.front().fColor;
+        GrColor4h* color = &fRRects.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
                                             color);
     }
@@ -2666,7 +2675,8 @@
 
         int currStartVertex = 0;
         for (const auto& rrect : fRRects) {
-            GrColor color = rrect.fColor;
+            // TODO4F: Preserve float colors
+            GrColor color = rrect.fColor.toGrColor();
             SkScalar outerRadius = rrect.fOuterRadius;
             const SkRect& bounds = rrect.fDevBounds;
 
@@ -2725,7 +2735,7 @@
                 SkScalar maxOffset = -rrect.fInnerRadius / overstrokeOuterRadius;
 
                 FillInOverstrokeVerts(&verts, bounds, outerRadius, overstrokeOuterRadius, maxOffset,
-                                      overstrokeOuterRadius, 0.0f, rrect.fColor);
+                                      overstrokeOuterRadius, 0.0f, color);
             }
 
             const uint16_t* primIndices = rrect_type_to_indices(rrect.fType);
@@ -2770,7 +2780,7 @@
     }
 
     struct RRect {
-        GrColor fColor;
+        GrColor4h fColor;
         SkScalar fInnerRadius;
         SkScalar fOuterRadius;
         SkRect fDevBounds;
@@ -2861,7 +2871,7 @@
                                                         strokeOnly);
     }
 
-    EllipticalRRectOp(Helper::MakeArgs helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    EllipticalRRectOp(Helper::MakeArgs helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
                       const SkRect& devRect, float devXRadius, float devYRadius,
                       SkVector devStrokeHalfWidths, bool strokeOnly)
             : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage) {
@@ -2904,9 +2914,9 @@
             string.appendf(
                     "Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
                     "XRad: %.2f, YRad: %.2f, InnerXRad: %.2f, InnerYRad: %.2f\n",
-                    geo.fColor, geo.fDevBounds.fLeft, geo.fDevBounds.fTop, geo.fDevBounds.fRight,
-                    geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius, geo.fInnerXRadius,
-                    geo.fInnerYRadius);
+                    geo.fColor.toGrColor(), geo.fDevBounds.fLeft, geo.fDevBounds.fTop,
+                    geo.fDevBounds.fRight, geo.fDevBounds.fBottom, geo.fXRadius, geo.fYRadius,
+                    geo.fInnerXRadius, geo.fInnerYRadius);
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -2914,7 +2924,7 @@
     }
 
     RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fRRects.front().fColor;
+        GrColor4h* color = &fRRects.front().fColor;
         return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
                                             color);
     }
@@ -2948,7 +2958,8 @@
         }
 
         for (const auto& rrect : fRRects) {
-            GrColor color = rrect.fColor;
+            // TODO4F: Preserve float colors
+            GrColor color = rrect.fColor.toGrColor();
             // Compute the reciprocals of the radii here to save time in the shader
             SkScalar xRadRecip = SkScalarInvert(rrect.fXRadius);
             SkScalar yRadRecip = SkScalarInvert(rrect.fYRadius);
@@ -3032,7 +3043,7 @@
     }
 
     struct RRect {
-        GrColor fColor;
+        GrColor4h fColor;
         SkScalar fXRadius;
         SkScalar fYRadius;
         SkScalar fInnerXRadius;
diff --git a/src/gpu/ops/GrRegionOp.cpp b/src/gpu/ops/GrRegionOp.cpp
index 0ba2a27..6ec230f 100644
--- a/src/gpu/ops/GrRegionOp.cpp
+++ b/src/gpu/ops/GrRegionOp.cpp
@@ -70,7 +70,7 @@
                                                aaType, stencilSettings);
     }
 
-    RegionOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
+    RegionOp(const Helper::MakeArgs& helperArgs, GrColor4h color, const SkMatrix& viewMatrix,
              const SkRegion& region, GrAAType aaType, const GrUserStencilSettings* stencilSettings)
             : INHERITED(ClassID())
             , fHelper(helperArgs, aaType, stencilSettings)
@@ -94,7 +94,7 @@
         str.appendf("# combined: %d\n", fRegions.count());
         for (int i = 0; i < fRegions.count(); ++i) {
             const RegionInfo& info = fRegions[i];
-            str.appendf("%d: Color: 0x%08x, Region with %d rects\n", i, info.fColor,
+            str.appendf("%d: Color: 0x%08x, Region with %d rects\n", i, info.fColor.toGrColor(),
                         info.fRegion.computeRegionComplexity());
         }
         str += fHelper.dumpInfo();
@@ -139,7 +139,9 @@
 
         intptr_t verts = reinterpret_cast<intptr_t>(vertices);
         for (int i = 0; i < numRegions; i++) {
-            tesselate_region(verts, kVertexStride, fRegions[i].fColor, fRegions[i].fRegion);
+            // TODO4F: Preserve float colors
+            tesselate_region(verts, kVertexStride, fRegions[i].fColor.toGrColor(),
+                             fRegions[i].fRegion);
             int numRectsInRegion = fRegions[i].fRegion.computeRegionComplexity();
             verts += numRectsInRegion * kVertsPerInstance * kVertexStride;
         }
@@ -162,7 +164,7 @@
     }
 
     struct RegionInfo {
-        GrColor fColor;
+        GrColor4h fColor;
         SkRegion fRegion;
     };
 
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
index f1692e6..f542608 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.cpp
@@ -76,7 +76,7 @@
                                : GrProcessorAnalysisCoverage::kNone;
         }
         bool isMixedSamples = this->aaType() == GrAAType::kMixedSamples;
-        GrColor overrideColor;
+        GrColor4h overrideColor;
         analysis = fProcessors->finalize(*geometryColor, coverage, clip, isMixedSamples, caps,
                                          &overrideColor);
         if (analysis.inputColorIsOverridden()) {
@@ -94,7 +94,7 @@
 
 GrDrawOp::RequiresDstTexture GrSimpleMeshDrawOpHelper::xpRequiresDstTexture(
         const GrCaps& caps, const GrAppliedClip* clip, GrProcessorAnalysisCoverage geometryCoverage,
-        GrColor* geometryColor) {
+        GrColor4h* geometryColor) {
     GrProcessorAnalysisColor color = *geometryColor;
     auto result = this->xpRequiresDstTexture(caps, clip, geometryCoverage, &color);
     color.isConstant(geometryColor);
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index cd72786..bb7bbe9 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -77,7 +77,7 @@
      */
     GrDrawOp::RequiresDstTexture xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*,
                                                       GrProcessorAnalysisCoverage geometryCoverage,
-                                                      GrColor* geometryColor);
+                                                      GrColor4h* geometryColor);
 
     bool usesLocalCoords() const {
         SkASSERT(fDidAnalysis);
@@ -182,7 +182,7 @@
     GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
 
     MakeArgs makeArgs;
-    GrColor color = paint.getColor();
+    GrColor4h color = GrColor4h::FromFloats(paint.getColor4f().vec());
 
     if (paint.isTrivial()) {
         makeArgs.fProcessorSet = nullptr;
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index f87b030..68256ff 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -242,7 +242,7 @@
                                                   stencilSettings);
     }
 
-    SmallPathOp(Helper::MakeArgs helperArgs, GrColor color, const GrShape& shape,
+    SmallPathOp(Helper::MakeArgs helperArgs, GrColor4h color, const GrShape& shape,
                 const SkMatrix& viewMatrix, GrDrawOpAtlas* atlas, ShapeCache* shapeCache,
                 ShapeDataList* shapeList, bool gammaCorrect,
                 const GrUserStencilSettings* stencilSettings)
@@ -284,7 +284,7 @@
     SkString dumpInfo() const override {
         SkString string;
         for (const auto& geo : fShapes) {
-            string.appendf("Color: 0x%08x\n", geo.fColor);
+            string.appendf("Color: 0x%08x\n", geo.fColor.toGrColor());
         }
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
@@ -491,8 +491,9 @@
             auto uploadTarget = target->deferredUploadTarget();
             fAtlas->setLastUseToken(shapeData->fID, uploadTarget->tokenTracker()->nextDrawToken());
 
+            // TODO4F: Preserve float colors
             this->writePathVertices(
-                    fAtlas, offset, args.fColor, kVertexStride, args.fViewMatrix, shapeData);
+                    fAtlas, offset, args.fColor.toGrColor(), kVertexStride, args.fViewMatrix, shapeData);
             offset += kVerticesPerQuad * kVertexStride;
             flushInfo.fInstancesToFlush++;
         }
@@ -845,7 +846,7 @@
         }
     }
 
-    GrColor color() const { return fShapes[0].fColor; }
+    GrColor4h color() const { return fShapes[0].fColor; }
     bool usesDistanceField() const { return fUsesDistanceField; }
 
     CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
@@ -887,9 +888,9 @@
     bool fUsesDistanceField;
 
     struct Entry {
-        GrColor  fColor;
-        GrShape  fShape;
-        SkMatrix fViewMatrix;
+        GrColor4h fColor;
+        GrShape   fShape;
+        SkMatrix  fViewMatrix;
     };
 
     SkSTArray<1, Entry> fShapes;
diff --git a/src/gpu/ops/GrTessellatingPathRenderer.cpp b/src/gpu/ops/GrTessellatingPathRenderer.cpp
index 9235cce..f725675 100644
--- a/src/gpu/ops/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/ops/GrTessellatingPathRenderer.cpp
@@ -190,14 +190,14 @@
 
     SkString dumpInfo() const override {
         SkString string;
-        string.appendf("Color 0x%08x, aa: %d\n", fColor, fAntiAlias);
+        string.appendf("Color 0x%08x, aa: %d\n", fColor.toGrColor(), fAntiAlias);
         string += fHelper.dumpInfo();
         string += INHERITED::dumpInfo();
         return string;
     }
 
     TessellatingPathOp(Helper::MakeArgs helperArgs,
-                       GrColor color,
+                       GrColor4h color,
                        const GrShape& shape,
                        const SkMatrix& viewMatrix,
                        const SkIRect& devClipBounds,
@@ -300,8 +300,10 @@
         SkScalar tol = GrPathUtils::kDefaultTolerance;
         bool isLinear;
         DynamicVertexAllocator allocator(vertexStride, target);
+        // TODO4F: Preserve float colors
         int count =
-                GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator, true, fColor,
+                GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator, true,
+                                               fColor.toGrColor(),
                                                fHelper.compatibleWithAlphaAsCoverage(), &isLinear);
         if (count == 0) {
             return;
@@ -367,7 +369,7 @@
     }
 
     Helper fHelper;
-    GrColor                 fColor;
+    GrColor4h               fColor;
     GrShape                 fShape;
     SkMatrix                fViewMatrix;
     SkIRect                 fDevClipBounds;
diff --git a/src/gpu/text/GrTextBlob.cpp b/src/gpu/text/GrTextBlob.cpp
index d96e046..17daa5b 100644
--- a/src/gpu/text/GrTextBlob.cpp
+++ b/src/gpu/text/GrTextBlob.cpp
@@ -79,9 +79,11 @@
 
 void GrTextBlob::appendGlyph(int runIndex,
                              const SkRect& positions,
-                             GrColor color,
+                             GrColor4h color4f,
                              const sk_sp<GrTextStrike>& strike,
                              GrGlyph* glyph, bool preTransformed) {
+    // TODO4F: Preserve float colors
+    GrColor color = color4f.toGrColor();
 
     Run& run = fRuns[runIndex];
     GrMaskFormat format = glyph->fMaskFormat;
@@ -235,7 +237,7 @@
 inline std::unique_ptr<GrAtlasTextOp> GrTextBlob::makeOp(
         const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun,
         const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
-        const SkPaint& paint, GrColor filteredColor, const SkSurfaceProps& props,
+        const SkPaint& paint, GrColor4h filteredColor, const SkSurfaceProps& props,
         const GrDistanceFieldAdjustTable* distanceAdjustTable, GrTextTarget* target) {
     GrMaskFormat format = info.maskFormat();
 
@@ -258,8 +260,7 @@
     geometry.fBlob = SkRef(this);
     geometry.fRun = run;
     geometry.fSubRun = subRun;
-    geometry.fColor =
-            info.maskFormat() == kARGB_GrMaskFormat ? GrColor_WHITE : filteredColor;
+    geometry.fColor = info.maskFormat() == kARGB_GrMaskFormat ? GrColor4h_WHITE : filteredColor;
     geometry.fX = x;
     geometry.fY = y;
     op->init();
@@ -288,7 +289,7 @@
 
 void GrTextBlob::flush(GrTextTarget* target, const SkSurfaceProps& props,
                        const GrDistanceFieldAdjustTable* distanceAdjustTable,
-                       const SkPaint& paint, GrColor filteredColor, const GrClip& clip,
+                       const SkPaint& paint, GrColor4h filteredColor, const GrClip& clip,
                        const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
 
     // GrTextBlob::makeOp only takes uint16_t values for run and subRun indices.
@@ -439,7 +440,7 @@
 
 std::unique_ptr<GrDrawOp> GrTextBlob::test_makeOp(
         int glyphCount, uint16_t run, uint16_t subRun, const SkMatrix& viewMatrix,
-        SkScalar x, SkScalar y, const SkPaint& paint, GrColor filteredColor,
+        SkScalar x, SkScalar y, const SkPaint& paint, GrColor4h filteredColor,
         const SkSurfaceProps& props, const GrDistanceFieldAdjustTable* distanceAdjustTable,
         GrTextTarget* target) {
     const GrTextBlob::Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun];
diff --git a/src/gpu/text/GrTextBlob.h b/src/gpu/text/GrTextBlob.h
index 234039f..8451d48 100644
--- a/src/gpu/text/GrTextBlob.h
+++ b/src/gpu/text/GrTextBlob.h
@@ -176,7 +176,7 @@
     // as a path.
     void appendGlyph(int runIndex,
                      const SkRect& positions,
-                     GrColor color,
+                     GrColor4h color,
                      const sk_sp<GrTextStrike>& strike,
                      GrGlyph* glyph, bool preTransformed);
 
@@ -201,7 +201,7 @@
 
     void flush(GrTextTarget*, const SkSurfaceProps& props,
                const GrDistanceFieldAdjustTable* distanceAdjustTable,
-               const SkPaint& paint, GrColor filteredColor, const GrClip& clip,
+               const SkPaint& paint, GrColor4h filteredColor, const GrClip& clip,
                const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
 
     void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex,
@@ -276,7 +276,7 @@
     // Internal test methods
     std::unique_ptr<GrDrawOp> test_makeOp(int glyphCount, uint16_t run, uint16_t subRun,
                                           const SkMatrix& viewMatrix, SkScalar x, SkScalar y,
-                                          const SkPaint& paint, GrColor filteredColor,
+                                          const SkPaint& paint, GrColor4h filteredColor,
                                           const SkSurfaceProps&, const GrDistanceFieldAdjustTable*,
                                           GrTextTarget*);
 
@@ -513,7 +513,7 @@
     inline std::unique_ptr<GrAtlasTextOp> makeOp(
             const Run::SubRunInfo& info, int glyphCount, uint16_t run, uint16_t subRun,
             const SkMatrix& viewMatrix, SkScalar x, SkScalar y, const SkIRect& clipRect,
-            const SkPaint& paint, GrColor filteredColor, const SkSurfaceProps&,
+            const SkPaint& paint, GrColor4h filteredColor, const SkSurfaceProps&,
             const GrDistanceFieldAdjustTable*, GrTextTarget*);
 
     struct StrokeInfo {
diff --git a/src/gpu/text/GrTextContext.h b/src/gpu/text/GrTextContext.h
index cfc94f5..fb6de70 100644
--- a/src/gpu/text/GrTextContext.h
+++ b/src/gpu/text/GrTextContext.h
@@ -80,7 +80,7 @@
                             GrGlyphCache*,
                             const GrShaderCaps&,
                             const SkPaint&,
-                            GrColor filteredColor,
+                            GrColor4h filteredColor,
                             SkScalerContextFlags scalerContextFlags,
                             const SkMatrix& viewMatrix,
                             const SkSurfaceProps&,
@@ -90,7 +90,7 @@
     static void AppendGlyph(GrTextBlob*, int runIndex,
                             const sk_sp<GrTextStrike>&, const SkGlyph&,
                             GrGlyph::MaskStyle maskStyle, SkScalar sx, SkScalar sy,
-                            GrColor color, SkGlyphCache*, SkScalar textRatio,
+                            GrColor4h color, SkGlyphCache*, SkScalar textRatio,
                             bool needsTransform);