Hide GrPaint copy constructor and add GrPaint::Clone and remove MoveOrNew and MoveOrCopy.

Also makes paint clones use cloned fragment processors.

Change-Id: I60efcfc6a46a4f8430a72f4d1ec79c7d99fbe593
Reviewed-on: https://skia-review.googlesource.com/33084
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gm/texdata.cpp b/gm/texdata.cpp
index 42723e4..4f0a0b1 100644
--- a/gm/texdata.cpp
+++ b/gm/texdata.cpp
@@ -119,7 +119,7 @@
         }
         paint.addColorTextureProcessor(tContext->asTextureProxyRef(), nullptr, vm);
 
-        renderTargetContext->drawRect(clip, GrPaint(paint), GrAA::kNo, vm,
+        renderTargetContext->drawRect(clip, GrPaint::Clone(paint), GrAA::kNo, vm,
                                       SkRect::MakeWH(2 * S, 2 * S));
 
         // now update the lower right of the texture in first pass
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index d9182d2..139a2cc 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -11,6 +11,24 @@
 #include "effects/GrPorterDuffXferProcessor.h"
 #include "effects/GrSimpleTextureEffect.h"
 
+GrPaint::GrPaint(const GrPaint& that)
+        : fXPFactory(that.fXPFactory)
+        , fColorFragmentProcessors(that.fColorFragmentProcessors.count())
+        , fCoverageFragmentProcessors(that.fCoverageFragmentProcessors.count())
+        , fDisableOutputConversionToSRGB(that.fDisableOutputConversionToSRGB)
+        , fAllowSRGBInputs(that.fAllowSRGBInputs)
+        , fTrivial(that.fTrivial)
+        , fColor(that.fColor) {
+    for (int i = 0; i < that.fColorFragmentProcessors.count(); ++i) {
+        fColorFragmentProcessors.push_back(that.fColorFragmentProcessors[i]->clone());
+        SkASSERT(fColorFragmentProcessors[i]);
+    }
+    for (int i = 0; i < that.fCoverageFragmentProcessors.count(); ++i) {
+        fCoverageFragmentProcessors.push_back(that.fCoverageFragmentProcessors[i]->clone());
+        SkASSERT(fCoverageFragmentProcessors[i]);
+    }
+}
+
 void GrPaint::setPorterDuffXPFactory(SkBlendMode mode) {
     this->setXPFactory(GrPorterDuffXPFactory::Get(mode));
 }
diff --git a/src/gpu/GrPaint.h b/src/gpu/GrPaint.h
index 0d8beb4..1ab01f3 100644
--- a/src/gpu/GrPaint.h
+++ b/src/gpu/GrPaint.h
@@ -41,9 +41,10 @@
 class GrPaint {
 public:
     GrPaint() = default;
-    explicit GrPaint(const GrPaint&) = default;
     ~GrPaint() = default;
 
+    static GrPaint Clone(const GrPaint& src) { return GrPaint(src); }
+
     /**
      * The initial color of the drawn primitive. Defaults to solid white.
      */
@@ -148,24 +149,9 @@
     bool isTrivial() const { return fTrivial; }
 
 private:
-    template <bool> class MoveOrImpl;
-
-public:
-    /**
-     * A temporary instance of this class can be used to select between moving an existing paint or
-     * a temporary copy of an existing paint into a call site. MoveOrClone(paint, false) is a rvalue
-     * reference to paint while MoveOrClone(paint, true) is a rvalue reference to a copy of paint.
-     */
-    using MoveOrClone = MoveOrImpl<true>;
-
-    /**
-     * A temporary instance of this class can be used to select between moving an existing or a
-     * newly default constructed paint into a call site. MoveOrNew(paint, false) is a rvalue
-     * reference to paint while MoveOrNew(paint, true) is a rvalue reference to a default paint.
-     */
-    using MoveOrNew = MoveOrImpl<false>;
-
-private:
+    // Since paint copying is expensive if there are fragment processors, we require going through
+    // the Clone() method.
+    GrPaint(const GrPaint&);
     GrPaint& operator=(const GrPaint&) = delete;
 
     friend class GrProcessorSet;
@@ -179,29 +165,4 @@
     GrColor4f fColor = GrColor4f::OpaqueWhite();
 };
 
-/** This is the implementation of MoveOrCopy and MoveOrNew. */
-template <bool COPY_IF_NEW>
-class GrPaint::MoveOrImpl {
-public:
-    MoveOrImpl(GrPaint& paint, bool newPaint) {
-        if (newPaint) {
-            if (COPY_IF_NEW) {
-                fStorage.init(paint);
-            } else {
-                fStorage.init();
-            };
-            fPaint = fStorage.get();
-        } else {
-            fPaint = &paint;
-        }
-    }
-
-    operator GrPaint&&() && { return std::move(*fPaint); }
-    GrPaint& paint() { return *fPaint; }
-
-private:
-    SkTLazy<GrPaint> fStorage;
-    GrPaint* fPaint;
-};
-
 #endif
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index f479a48..8858bf9 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -98,20 +98,20 @@
     if (devClipBounds.fTop < devPathBounds.fTop) {
         rect.iset(devClipBounds.fLeft, devClipBounds.fTop,
                   devClipBounds.fRight, devPathBounds.fTop);
-        DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(),
-                      rect, invert);
+        DrawNonAARect(renderTargetContext, GrPaint::Clone(paint), userStencilSettings, clip,
+                      SkMatrix::I(), rect, invert);
     }
     if (devClipBounds.fLeft < devPathBounds.fLeft) {
         rect.iset(devClipBounds.fLeft, devPathBounds.fTop,
                   devPathBounds.fLeft, devPathBounds.fBottom);
-        DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(),
-                      rect, invert);
+        DrawNonAARect(renderTargetContext, GrPaint::Clone(paint), userStencilSettings, clip,
+                      SkMatrix::I(), rect, invert);
     }
     if (devClipBounds.fRight > devPathBounds.fRight) {
         rect.iset(devPathBounds.fRight, devPathBounds.fTop,
                   devClipBounds.fRight, devPathBounds.fBottom);
-        DrawNonAARect(renderTargetContext, GrPaint(paint), userStencilSettings, clip, SkMatrix::I(),
-                      rect, invert);
+        DrawNonAARect(renderTargetContext, GrPaint::Clone(paint), userStencilSettings, clip,
+                      SkMatrix::I(), rect, invert);
     }
     if (devClipBounds.fBottom > devPathBounds.fBottom) {
         rect.iset(devClipBounds.fLeft, devPathBounds.fBottom,
@@ -222,7 +222,7 @@
         }
     }
     if (inverseFilled) {
-        DrawAroundInvPath(args.fRenderTargetContext, GrPaint(args.fPaint),
+        DrawAroundInvPath(args.fRenderTargetContext, GrPaint::Clone(args.fPaint),
                           *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, devClipBounds,
                           unclippedDevShapeBounds);
     }
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index fb72085..4a436aa 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -593,13 +593,16 @@
                             std::move(paint), viewM, localMatrix, bounds, aaType, passes[p]));
         } else {
             bool stencilPass = stencilOnly || passCount > 1;
-            GrPaint::MoveOrNew passPaint(paint, stencilPass);
+            std::unique_ptr<GrDrawOp> op;
             if (stencilPass) {
-                passPaint.paint().setXPFactory(GrDisableColorXPFactory::Get());
+                GrPaint stencilPaint;
+                stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
+                op = DefaultPathOp::Make(std::move(stencilPaint), path, srcSpaceTol, newCoverage,
+                                         viewMatrix, isHairline, aaType, devBounds, passes[p]);
+            } else {
+                op = DefaultPathOp::Make(std::move(paint), path, srcSpaceTol, newCoverage,
+                                         viewMatrix, isHairline, aaType, devBounds, passes[p]);
             }
-            std::unique_ptr<GrDrawOp> op =
-                    DefaultPathOp::Make(std::move(passPaint), path, srcSpaceTol, newCoverage,
-                                        viewMatrix, isHairline, aaType, devBounds, passes[p]);
             renderTargetContext->addDrawOp(clip, std::move(op));
         }
     }
diff --git a/src/gpu/ops/GrMSAAPathRenderer.cpp b/src/gpu/ops/GrMSAAPathRenderer.cpp
index 425e675..072692a 100644
--- a/src/gpu/ops/GrMSAAPathRenderer.cpp
+++ b/src/gpu/ops/GrMSAAPathRenderer.cpp
@@ -639,12 +639,15 @@
         bool firstPassIsStencil = stencilOnly || passes[1];
         // If we have a cover pass then we ignore the paint in the first pass and apply it in the
         // second.
-        GrPaint::MoveOrNew firstPassPaint(paint, firstPassIsStencil);
+        std::unique_ptr<GrDrawOp> op;
         if (firstPassIsStencil) {
-            firstPassPaint.paint().setXPFactory(GrDisableColorXPFactory::Get());
+            GrPaint stencilPaint;
+            stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
+            op = MSAAPathOp::Make(std::move(stencilPaint), path, aaType, viewMatrix, devBounds,
+                                  passes[0]);
+        } else {
+            op = MSAAPathOp::Make(std::move(paint), path, aaType, viewMatrix, devBounds, passes[0]);
         }
-        std::unique_ptr<GrDrawOp> op = MSAAPathOp::Make(std::move(firstPassPaint), path, aaType,
-                                                        viewMatrix, devBounds, passes[0]);
         if (!op) {
             return false;
         }
diff --git a/tests/SRGBMipMapTest.cpp b/tests/SRGBMipMapTest.cpp
index 11fedca..a661d50 100644
--- a/tests/SRGBMipMapTest.cpp
+++ b/tests/SRGBMipMapTest.cpp
@@ -151,13 +151,13 @@
 
     // 1) Draw texture to S32 surface (should generate/use sRGB mips)
     paint.setGammaCorrect(true);
-    s32RenderTargetContext->drawRect(noClip, GrPaint(paint), GrAA::kNo, SkMatrix::I(), rect);
+    s32RenderTargetContext->drawRect(noClip, GrPaint::Clone(paint), GrAA::kNo, SkMatrix::I(), rect);
     read_and_check_pixels(reporter, s32RenderTargetContext.get(), expectedSRGB, iiSRGBA, error,
                           "first render of sRGB");
 
     // 2) Draw texture to L32 surface (should generate/use linear mips)
     paint.setGammaCorrect(false);
-    l32RenderTargetContext->drawRect(noClip, GrPaint(paint), GrAA::kNo, SkMatrix::I(), rect);
+    l32RenderTargetContext->drawRect(noClip, GrPaint::Clone(paint), GrAA::kNo, SkMatrix::I(), rect);
 
     // Right now, this test only runs on GL (because Vulkan doesn't support legacy mip-mapping
     // skbug.com/5048). On GL, we may not have sRGB decode support. In that case, rendering sRGB