Revert "Converts remaining rect ops from GrLegacyMeshDrawOp to GrMeshDrawOp subclasses."

This reverts commit 1ec03f33cf493352174c748662d4a3cca29f78fd.

Revert "Fix logic reversal in NonAAFillRectOp test factory"

This reverts commit 89c1c2552ec5b9ad8949988f7c9532a298b55987.

Reason: Unexpected GM changes.

Bug: skia:
Change-Id: I9edf5f0e4a54b5cad86bd438a505aaaef38563de
Reviewed-on: https://skia-review.googlesource.com/19960
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gm/bigrrectaaeffect.cpp b/gm/bigrrectaaeffect.cpp
index e60cfdf..92c3a24 100644
--- a/gm/bigrrectaaeffect.cpp
+++ b/gm/bigrrectaaeffect.cpp
@@ -13,7 +13,7 @@
 #include "SkRRect.h"
 #include "effects/GrRRectEffect.h"
 #include "ops/GrDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 namespace skiagm {
 
@@ -89,8 +89,8 @@
                     bounds.offset(SkIntToScalar(x), SkIntToScalar(y));
 
                     renderTargetContext->priv().testingOnly_addDrawOp(
-                            GrRectOpFactory::MakeNonAAFill(std::move(grPaint), SkMatrix::I(),
-                                                           bounds, GrAAType::kNone));
+                            GrNonAAFillRectOp::Make(std::move(grPaint), SkMatrix::I(), bounds,
+                                                    nullptr, nullptr, GrAAType::kNone));
                 }
             canvas->restore();
             x = x + fTestOffsetX;
diff --git a/gm/constcolorprocessor.cpp b/gm/constcolorprocessor.cpp
index 39926a9..bbfca00 100644
--- a/gm/constcolorprocessor.cpp
+++ b/gm/constcolorprocessor.cpp
@@ -18,7 +18,7 @@
 #include "SkGradientShader.h"
 #include "effects/GrConstColorProcessor.h"
 #include "ops/GrDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 namespace skiagm {
 /**
@@ -110,8 +110,8 @@
 
                     grPaint.addColorFragmentProcessor(std::move(fp));
                     renderTargetContext->priv().testingOnly_addDrawOp(
-                            GrRectOpFactory::MakeNonAAFill(std::move(grPaint), viewMatrix,
-                                                           renderRect, GrAAType::kNone));
+                            GrNonAAFillRectOp::Make(std::move(grPaint), viewMatrix, renderRect,
+                                                    nullptr, nullptr, GrAAType::kNone));
 
                     // Draw labels for the input to the processor and the processor to the right of
                     // the test rect. The input label appears above the processor label.
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index 3124895..23f576b 100644
--- a/gm/rrects.cpp
+++ b/gm/rrects.cpp
@@ -12,7 +12,7 @@
 #include "GrRenderTargetContextPriv.h"
 #include "effects/GrRRectEffect.h"
 #include "ops/GrDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 #endif
 #include "SkRRect.h"
 
@@ -117,9 +117,12 @@
                             bounds.outset(2.f, 2.f);
 
                             renderTargetContext->priv().testingOnly_addDrawOp(
-                                    GrRectOpFactory::MakeNonAAFill(std::move(grPaint),
-                                                                   SkMatrix::I(), bounds,
-                                                                   GrAAType::kNone));
+                                    GrNonAAFillRectOp::Make(std::move(grPaint),
+                                                            SkMatrix::I(),
+                                                            bounds,
+                                                            nullptr,
+                                                            nullptr,
+                                                            GrAAType::kNone));
                         } else {
                             drew = false;
                         }
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index e54404e..d49e059 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -18,7 +18,7 @@
 #include "SkGradientShader.h"
 #include "effects/GrTextureDomain.h"
 #include "ops/GrDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 namespace skiagm {
 /**
@@ -134,8 +134,8 @@
                     const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y);
                     grPaint.addColorFragmentProcessor(std::move(fp));
                     renderTargetContext->priv().testingOnly_addDrawOp(
-                            GrRectOpFactory::MakeNonAAFill(std::move(grPaint), viewMatrix,
-                                                           renderRect, GrAAType::kNone));
+                            GrNonAAFillRectOp::Make(std::move(grPaint), viewMatrix, renderRect,
+                                                    nullptr, nullptr, GrAAType::kNone));
                     x += renderRect.width() + kTestPad;
                 }
                 y += renderRect.height() + kTestPad;
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index c6effed..eb2e422 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -19,7 +19,7 @@
 #include "SkGradientShader.h"
 #include "effects/GrYUVEffect.h"
 #include "ops/GrDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 #define YSIZE 8
 #define USIZE 4
@@ -133,8 +133,8 @@
                     SkMatrix viewMatrix;
                     viewMatrix.setTranslate(x, y);
                     renderTargetContext->priv().testingOnly_addDrawOp(
-                            GrRectOpFactory::MakeNonAAFill(std::move(grPaint), viewMatrix,
-                                                           renderRect, GrAAType::kNone));
+                            GrNonAAFillRectOp::Make(std::move(grPaint), viewMatrix, renderRect,
+                                                    nullptr, nullptr, GrAAType::kNone));
                 }
                 x += renderRect.width() + kTestPad;
             }
@@ -256,8 +256,9 @@
                 SkMatrix viewMatrix;
                 viewMatrix.setTranslate(x, y);
                 grPaint.addColorFragmentProcessor(fp);
-                renderTargetContext->priv().testingOnly_addDrawOp(GrRectOpFactory::MakeNonAAFill(
-                        std::move(grPaint), viewMatrix, renderRect, GrAAType::kNone));
+                renderTargetContext->priv().testingOnly_addDrawOp(
+                        GrNonAAFillRectOp::Make(std::move(grPaint), viewMatrix, renderRect, nullptr,
+                                                nullptr, GrAAType::kNone));
             }
         }
     }
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 2a1ed00..01d0628 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -230,11 +230,13 @@
   "$_src/gpu/ops/GrAAConvexPathRenderer.cpp",
   "$_src/gpu/ops/GrAAConvexPathRenderer.h",
   "$_src/gpu/ops/GrAAFillRectOp.cpp",
+  "$_src/gpu/ops/GrAAFillRectOp.h",
   "$_src/gpu/ops/GrAAHairLinePathRenderer.cpp",
   "$_src/gpu/ops/GrAAHairLinePathRenderer.h",
   "$_src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp",
   "$_src/gpu/ops/GrAALinearizingConvexPathRenderer.h",
   "$_src/gpu/ops/GrAAStrokeRectOp.cpp",
+  "$_src/gpu/ops/GrAAStrokeRectOp.h",
   "$_src/gpu/ops/GrAnalyticRectOp.cpp",
   "$_src/gpu/ops/GrAnalyticRectOp.h",
   "$_src/gpu/ops/GrAtlasTextOp.cpp",
@@ -262,8 +264,10 @@
   "$_src/gpu/ops/GrMeshDrawOp.h",
   "$_src/gpu/ops/GrMSAAPathRenderer.cpp",
   "$_src/gpu/ops/GrMSAAPathRenderer.h",
+  "$_src/gpu/ops/GrNonAAFillRectOp.h",
   "$_src/gpu/ops/GrNonAAFillRectOp.cpp",
   "$_src/gpu/ops/GrNonAAStrokeRectOp.cpp",
+  "$_src/gpu/ops/GrNonAAStrokeRectOp.h",
   "$_src/gpu/ops/GrLatticeOp.cpp",
   "$_src/gpu/ops/GrLatticeOp.h",
   "$_src/gpu/ops/GrOp.cpp",
@@ -271,6 +275,7 @@
   "$_src/gpu/ops/GrOvalOpFactory.cpp",
   "$_src/gpu/ops/GrOvalOpFactory.h",
   "$_src/gpu/ops/GrRectOpFactory.h",
+  "$_src/gpu/ops/GrRectOpFactory.cpp",
   "$_src/gpu/ops/GrRegionOp.cpp",
   "$_src/gpu/ops/GrRegionOp.h",
   "$_src/gpu/ops/GrSemaphoreOp.cpp",
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 7d752b4..0f436f0 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -34,6 +34,7 @@
 #include "ops/GrDrawOp.h"
 #include "ops/GrDrawVerticesOp.h"
 #include "ops/GrLatticeOp.h"
+#include "ops/GrNonAAFillRectOp.h"
 #include "ops/GrOp.h"
 #include "ops/GrOvalOpFactory.h"
 #include "ops/GrRectOpFactory.h"
@@ -284,9 +285,10 @@
 
         // We don't call drawRect() here to avoid the cropping to the, possibly smaller,
         // RenderTargetProxy bounds
-        std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFill(
-                std::move(paint), SkMatrix::I(), SkRect::Make(rtRect), GrAAType::kNone);
-        fRenderTargetContext->addDrawOp(GrNoClip(), std::move(op));
+        fRenderTargetContext->drawNonAAFilledRect(GrNoClip(), std::move(paint), SkMatrix::I(),
+                                                  SkRect::Make(rtRect), nullptr, nullptr, nullptr,
+                                                  GrAAType::kNone);
+
     } else {
         // This path doesn't handle coalescing of full screen clears b.c. it
         // has to clear the entire render target - not just the content area.
@@ -396,9 +398,8 @@
 
         AutoCheckFlush acf(this->drawingManager());
 
-        std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
-                std::move(paint), SkMatrix::I(), localMatrix, r, GrAAType::kNone);
-        this->addDrawOp(clip, std::move(op));
+        this->drawNonAAFilledRect(clip, std::move(paint), SkMatrix::I(), r, nullptr, &localMatrix,
+                                  nullptr, GrAAType::kNone);
     }
 }
 
@@ -407,6 +408,10 @@
            point.fY >= rect.fTop && point.fY <= rect.fBottom;
 }
 
+static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
+    return viewMatrix.preservesRightAngles();
+}
+
 // Attempts to crop a rect and optional local rect to the clip boundaries.
 // Returns false if the draw can be skipped entirely.
 static bool crop_filled_rect(int width, int height, const GrClip& clip,
@@ -474,17 +479,29 @@
         }
     }
     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
-    std::unique_ptr<GrDrawOp> op;
     if (GrAAType::kCoverage == aaType) {
-        op = GrRectOpFactory::MakeAAFill(std::move(paint), viewMatrix, rect, ss);
+        // The fill path can handle rotation but not skew.
+        if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
+            SkRect devBoundRect;
+            viewMatrix.mapRect(&devBoundRect, croppedRect);
+            std::unique_ptr<GrLegacyMeshDrawOp> op =
+                    GrRectOpFactory::MakeAAFill(paint, viewMatrix, rect, croppedRect, devBoundRect);
+            if (op) {
+                GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
+                if (ss) {
+                    pipelineBuilder.setUserStencil(ss);
+                }
+                this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
+                return true;
+            }
+        }
     } else {
-        op = GrRectOpFactory::MakeNonAAFill(std::move(paint), viewMatrix, croppedRect, aaType, ss);
+        this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, nullptr, nullptr,
+                                  ss, aaType);
+        return true;
     }
-    if (!op) {
-        return false;
-    }
-    this->addDrawOp(clip, std::move(op));
-    return true;
+
+    return false;
 }
 
 void GrRenderTargetContext::drawRect(const GrClip& clip,
@@ -574,21 +591,30 @@
                 }
         }
 
-        std::unique_ptr<GrDrawOp> op;
+        bool snapToPixelCenters = false;
+        std::unique_ptr<GrLegacyMeshDrawOp> op;
 
+        GrColor color = paint.getColor();
         GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
         if (GrAAType::kCoverage == aaType) {
             // The stroke path needs the rect to remain axis aligned (no rotation or skew).
             if (viewMatrix.rectStaysRect()) {
-                op = GrRectOpFactory::MakeAAStroke(std::move(paint), viewMatrix, rect, stroke);
+                op = GrRectOpFactory::MakeAAStroke(color, viewMatrix, rect, stroke);
             }
         } else {
-            op = GrRectOpFactory::MakeNonAAStroke(std::move(paint), viewMatrix, rect, stroke,
-                                                  aaType);
+            // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
+            // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
+            // when MSAA is enabled because it can cause ugly artifacts.
+            snapToPixelCenters = stroke.getStyle() == SkStrokeRec::kHairline_Style &&
+                                 GrFSAAType::kUnifiedMSAA != fRenderTargetProxy->fsaaType();
+            op = GrRectOpFactory::MakeNonAAStroke(color, viewMatrix, rect, stroke,
+                                                  snapToPixelCenters);
         }
 
         if (op) {
-            this->addDrawOp(clip, std::move(op));
+            GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
+            pipelineBuilder.setSnapVerticesToPixelCenters(snapToPixelCenters);
+            this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
             return;
         }
     }
@@ -694,9 +720,9 @@
 
     GrPaint paint;
     paint.setXPFactory(GrDisableColorXPFactory::Get());
-    std::unique_ptr<GrDrawOp> op =
-            GrRectOpFactory::MakeNonAAFill(std::move(paint), viewMatrix, rect, aaType, ss);
-    fRenderTargetContext->addDrawOp(clip, std::move(op));
+
+    fRenderTargetContext->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, rect, nullptr,
+                                              nullptr, ss, aaType);
 }
 
 bool GrRenderTargetContextPriv::drawAndStencilRect(const GrClip& clip,
@@ -758,16 +784,16 @@
 
     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
     if (GrAAType::kCoverage != aaType) {
-        std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalRect(
-                std::move(paint), viewMatrix, croppedRect, croppedLocalRect, aaType);
-        this->addDrawOp(clip, std::move(op));
+        this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect,
+                                  &croppedLocalRect, nullptr, nullptr, aaType);
         return;
     }
 
-    std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalRect(
-            std::move(paint), viewMatrix, croppedRect, croppedLocalRect);
-    if (op) {
-        this->addDrawOp(clip, std::move(op));
+    if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
+        std::unique_ptr<GrLegacyMeshDrawOp> op = GrAAFillRectOp::MakeWithLocalRect(
+                paint.getColor(), viewMatrix, croppedRect, croppedLocalRect);
+        GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
+        this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
         return;
     }
 
@@ -814,16 +840,16 @@
 
     GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
     if (GrAAType::kCoverage != aaType) {
-        std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
-                std::move(paint), viewMatrix, localMatrix, croppedRect, aaType);
-        this->addDrawOp(clip, std::move(op));
+        this->drawNonAAFilledRect(clip, std::move(paint), viewMatrix, croppedRect, nullptr,
+                                  &localMatrix, nullptr, aaType);
         return;
     }
 
-    std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalMatrix(
-            std::move(paint), viewMatrix, localMatrix, croppedRect);
-    if (op) {
-        this->addDrawOp(clip, std::move(op));
+    if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
+        std::unique_ptr<GrLegacyMeshDrawOp> op =
+                GrAAFillRectOp::Make(paint.getColor(), viewMatrix, localMatrix, croppedRect);
+        GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
+        this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
         return;
     }
 
@@ -1438,6 +1464,21 @@
     this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
 }
 
+void GrRenderTargetContext::drawNonAAFilledRect(const GrClip& clip,
+                                                GrPaint&& paint,
+                                                const SkMatrix& viewMatrix,
+                                                const SkRect& rect,
+                                                const SkRect* localRect,
+                                                const SkMatrix* localMatrix,
+                                                const GrUserStencilSettings* ss,
+                                                GrAAType hwOrNoneAAType) {
+    SkASSERT(GrAAType::kCoverage != hwOrNoneAAType);
+    SkASSERT(GrAAType::kNone == hwOrNoneAAType || GrFSAAType::kNone != this->fsaaType());
+    std::unique_ptr<GrDrawOp> op = GrNonAAFillRectOp::Make(
+            std::move(paint), viewMatrix, rect, localRect, localMatrix, hwOrNoneAAType, ss);
+    this->addDrawOp(clip, std::move(op));
+}
+
 // Can 'path' be drawn as a pair of filled nested rectangles?
 static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
 
@@ -1511,13 +1552,13 @@
             SkRect rects[2];
 
             if (fills_as_nested_rects(viewMatrix, path, rects)) {
-                std::unique_ptr<GrDrawOp> op =
-                        GrRectOpFactory::MakeAAFillNestedRects(std::move(paint), viewMatrix, rects);
-                if (!op) {
-                    // A null return indicates that there is nothing to draw in this case.
-                    return;
+                std::unique_ptr<GrLegacyMeshDrawOp> op =
+                        GrRectOpFactory::MakeAAFillNestedRects(paint.getColor(), viewMatrix, rects);
+                if (op) {
+                    GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
+                    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
                 }
-                this->addDrawOp(clip, std::move(op));
+                return;
             }
         }
         SkRect ovalRect;
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index c471eac..c794050 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -400,6 +400,15 @@
                         const SkRect& rect,
                         const GrUserStencilSettings* ss);
 
+    void drawNonAAFilledRect(const GrClip&,
+                             GrPaint&&,
+                             const SkMatrix& viewMatrix,
+                             const SkRect& rect,
+                             const SkRect* localRect,
+                             const SkMatrix* localMatrix,
+                             const GrUserStencilSettings* ss,
+                             GrAAType hwOrNoneAAType);
+
     void internalDrawPath(
             const GrClip&, GrPaint&&, GrAA, const SkMatrix&, const SkPath&, const GrStyle&);
 
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index fb66886..141f357 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrSWMaskHelper.h"
+
 #include "GrCaps.h"
 #include "GrContext.h"
 #include "GrContextPriv.h"
@@ -14,9 +15,11 @@
 #include "GrShape.h"
 #include "GrSurfaceContext.h"
 #include "GrTextureProxy.h"
-#include "SkDistanceFieldGen.h"
 #include "ops/GrDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+
+#include "SkDistanceFieldGen.h"
+
+#include "ops/GrNonAAFillRectOp.h"
 
 /*
  * Convert a boolean operation into a transfer mode code
@@ -173,8 +176,7 @@
     paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(
             resourceProvider, std::move(proxy), nullptr, maskMatrix,
             GrSamplerParams::kNone_FilterMode));
-    renderTargetContext->addDrawOp(clip,
-                                   GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
-                                           std::move(paint), SkMatrix::I(), invert, dstRect,
-                                           GrAAType::kNone, &userStencilSettings));
+    renderTargetContext->addDrawOp(
+            clip, GrNonAAFillRectOp::Make(std::move(paint), SkMatrix::I(), dstRect, nullptr,
+                                          &invert, GrAAType::kNone, &userStencilSettings));
 }
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 161b62b..f823e13 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -12,7 +12,7 @@
 #include "GrPipelineBuilder.h"
 #include "GrResourceProvider.h"
 #include "GrSWMaskHelper.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
@@ -76,10 +76,9 @@
                                            const SkMatrix& viewMatrix,
                                            const SkRect& rect,
                                            const SkMatrix& localMatrix) {
-    renderTargetContext->addDrawOp(clip,
-                                   GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
-                                           std::move(paint), viewMatrix, localMatrix, rect,
-                                           GrAAType::kNone, &userStencilSettings));
+    renderTargetContext->addDrawOp(
+            clip, GrNonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, &localMatrix,
+                                          GrAAType::kNone, &userStencilSettings));
 }
 
 void GrSoftwarePathRenderer::DrawAroundInvPath(GrRenderTargetContext* renderTargetContext,
diff --git a/src/gpu/ops/GrAAFillRectOp.cpp b/src/gpu/ops/GrAAFillRectOp.cpp
index 478c109..af5885c 100644
--- a/src/gpu/ops/GrAAFillRectOp.cpp
+++ b/src/gpu/ops/GrAAFillRectOp.cpp
@@ -5,26 +5,21 @@
  * found in the LICENSE file.
  */
 
+#include "GrAAFillRectOp.h"
+
 #include "GrColor.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrMeshDrawOp.h"
 #include "GrOpFlushState.h"
-#include "GrRectOpFactory.h"
 #include "GrResourceKey.h"
 #include "GrResourceProvider.h"
 #include "GrTypes.h"
 #include "SkMatrix.h"
 #include "SkRect.h"
-#include "ops/GrSimpleMeshDrawOpHelper.h"
 
 GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
 
-static inline bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
-    return viewMatrix.preservesRightAngles();
-}
-
-static inline void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx,
-                                 SkScalar dy) {
+static void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx, SkScalar dy) {
     pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
 }
 
@@ -158,34 +153,16 @@
     }
 }
 
-namespace {
-
-class AAFillRectOp final : public GrMeshDrawOp {
-private:
-    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
-
+class AAFillRectOp final : public GrLegacyMeshDrawOp {
 public:
     DEFINE_OP_CLASS_ID
 
-    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
-                                          const SkMatrix& viewMatrix,
-                                          const SkRect& rect,
-                                          const SkRect& devRect,
-                                          const SkMatrix* localMatrix,
-                                          const GrUserStencilSettings* stencil) {
-        SkASSERT(view_matrix_ok_for_aa_fill_rect(viewMatrix));
-        return Helper::FactoryHelper<AAFillRectOp>(std::move(paint), viewMatrix, rect, devRect,
-                                                   localMatrix, stencil);
-    }
-
-    AAFillRectOp(const Helper::MakeArgs& helperArgs,
-                 GrColor color,
+    AAFillRectOp(GrColor color,
                  const SkMatrix& viewMatrix,
                  const SkRect& rect,
                  const SkRect& devRect,
-                 const SkMatrix* localMatrix,
-                 const GrUserStencilSettings* stencil)
-            : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencil) {
+                 const SkMatrix* localMatrix)
+            : INHERITED(ClassID()) {
         if (localMatrix) {
             void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
             new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
@@ -212,29 +189,38 @@
                         info->color(), rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
             info = this->next(info);
         }
+        str.append(DumpPipelineInfo(*this->pipeline()));
         return str;
     }
 
-    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
-    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor color = this->first()->color();
-        bool result = fHelper.xpRequiresDstTexture(
-                caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &color);
-        this->first()->setColor(color);
-        return result;
+    void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
+        GrColor color;
+        if (optimizations.getOverrideColorIfSet(&color)) {
+            this->first()->setColor(color);
+        }
+        fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage();
+        fNeedsLocalCoords = optimizations.readsLocalCoords();
     }
 
 private:
+    void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
+                                    GrProcessorAnalysisCoverage* coverage) const override {
+        color->setToConstant(this->first()->color());
+        *coverage = GrProcessorAnalysisCoverage::kSingleChannel;
+    }
+
     void onPrepareDraws(Target* target) const override {
         using namespace GrDefaultGeoProcFactory;
 
         Color color(Color::kPremulGrColorAttribute_Type);
-        Coverage::Type coverageType = fHelper.compatibleWithAlphaAsCoverage()
-                                              ? Coverage::kSolid_Type
-                                              : Coverage::kAttribute_Type;
-        LocalCoords lc = fHelper.usesLocalCoords() ? LocalCoords::kHasExplicit_Type
-                                                   : LocalCoords::kUnused_Type;
+        Coverage::Type coverageType;
+        if (fCanTweakAlphaForCoverage) {
+            coverageType = Coverage::kSolid_Type;
+        } else {
+            coverageType = Coverage::kAttribute_Type;
+        }
+        LocalCoords lc =
+                fNeedsLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUnused_Type;
         sk_sp<GrGeometryProcessor> gp =
                 GrDefaultGeoProcFactory::Make(color, coverageType, lc, SkMatrix::I());
         if (!gp) {
@@ -259,7 +245,7 @@
         for (int i = 0; i < fRectCnt; i++) {
             intptr_t verts =
                     reinterpret_cast<intptr_t>(vertices) + i * kVertsPerAAFillRect * vertexStride;
-            if (fHelper.usesLocalCoords()) {
+            if (fNeedsLocalCoords) {
                 if (info->hasLocalMatrix()) {
                     localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
                 } else {
@@ -267,19 +253,28 @@
                 }
             }
             generate_aa_fill_rect_geometry(verts, vertexStride, info->color(), info->viewMatrix(),
-                                           info->rect(), info->devRect(),
-                                           fHelper.compatibleWithAlphaAsCoverage(), localMatrix);
+                                           info->rect(), info->devRect(), fCanTweakAlphaForCoverage,
+                                           localMatrix);
             info = this->next(info);
         }
-        helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
+        helper.recordDraw(target, gp.get(), this->pipeline());
     }
 
     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
         AAFillRectOp* that = t->cast<AAFillRectOp>();
-        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
+        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
+                                    that->bounds(), caps)) {
             return false;
         }
 
+        SkASSERT(fNeedsLocalCoords == that->fNeedsLocalCoords);
+
+        // In the event of two ops, one who can tweak, one who cannot, we just fall back to not
+        // tweaking.
+        if (fCanTweakAlphaForCoverage && !that->fCanTweakAlphaForCoverage) {
+            fCanTweakAlphaForCoverage = false;
+        }
+
         fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
         fRectCnt += that->fRectCnt;
         this->joinBounds(*that);
@@ -338,63 +333,55 @@
         return reinterpret_cast<const RectInfo*>(next);
     }
 
+    bool fNeedsLocalCoords;
+    bool fCanTweakAlphaForCoverage;
     SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
-    Helper fHelper;
     int fRectCnt;
 
-    typedef GrMeshDrawOp INHERITED;
+    typedef GrLegacyMeshDrawOp INHERITED;
 };
 
-}  // anonymous namespace
+namespace GrAAFillRectOp {
 
-namespace GrRectOpFactory {
-
-std::unique_ptr<GrDrawOp> MakeAAFill(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                     const SkRect& rect, const GrUserStencilSettings* stencil) {
-    if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
-        return nullptr;
-    }
-    SkRect devRect;
-    if (!viewMatrix.mapRect(&devRect, rect)) {
-        return nullptr;
-    }
-    return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, nullptr, stencil);
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkRect& rect,
+                                         const SkRect& devRect) {
+    return std::unique_ptr<GrLegacyMeshDrawOp>(
+            new AAFillRectOp(color, viewMatrix, rect, devRect, nullptr));
 }
 
-std::unique_ptr<GrDrawOp> MakeAAFillWithDevRect(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                                const SkRect& rect, const SkRect& devRect) {
-    if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
-        return nullptr;
-    }
-    return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, nullptr, nullptr);
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkMatrix& localMatrix,
+                                         const SkRect& rect,
+                                         const SkRect& devRect) {
+    return std::unique_ptr<GrLegacyMeshDrawOp>(
+            new AAFillRectOp(color, viewMatrix, rect, devRect, &localMatrix));
 }
 
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                                    const SkMatrix& localMatrix,
-                                                    const SkRect& rect) {
-    if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
-        return nullptr;
-    }
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkMatrix& localMatrix,
+                                         const SkRect& rect) {
     SkRect devRect;
     viewMatrix.mapRect(&devRect, rect);
-    return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, &localMatrix, nullptr);
+    return Make(color, viewMatrix, localMatrix, rect, devRect);
 }
 
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                                  const SkRect& rect, const SkRect& localRect) {
-    if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
-        return nullptr;
-    }
+std::unique_ptr<GrLegacyMeshDrawOp> MakeWithLocalRect(GrColor color,
+                                                      const SkMatrix& viewMatrix,
+                                                      const SkRect& rect,
+                                                      const SkRect& localRect) {
     SkRect devRect;
     viewMatrix.mapRect(&devRect, rect);
     SkMatrix localMatrix;
     if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
         return nullptr;
     }
-    return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, &localMatrix, nullptr);
+    return Make(color, viewMatrix, localMatrix, rect, devRect);
 }
-
-}  // namespace GrRectOpFactory
+};
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -402,22 +389,21 @@
 
 #include "GrDrawOpTest.h"
 
-GR_DRAW_OP_TEST_DEFINE(AAFillRectOp) {
-    SkMatrix viewMatrix;
-    do {
-        viewMatrix = GrTest::TestMatrixInvertible(random);
-    } while (!view_matrix_ok_for_aa_fill_rect(viewMatrix));
+GR_LEGACY_MESH_DRAW_OP_TEST_DEFINE(AAFillRectOp) {
+    GrColor color = GrRandomColor(random);
+    SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
     SkRect rect = GrTest::TestRect(random);
-    SkRect devRect;
-    viewMatrix.mapRect(&devRect, rect);
-    const SkMatrix* localMatrix = nullptr;
-    SkMatrix m;
-    if (random->nextBool()) {
-        m = GrTest::TestMatrix(random);
-    }
-    const GrUserStencilSettings* stencil =
-            random->nextBool() ? nullptr : GrGetRandomStencil(random, context);
-    return AAFillRectOp::Make(std::move(paint), viewMatrix, rect, devRect, localMatrix, stencil);
+    SkRect devRect = GrTest::TestRect(random);
+    return GrAAFillRectOp::Make(color, viewMatrix, rect, devRect);
+}
+
+GR_LEGACY_MESH_DRAW_OP_TEST_DEFINE(AAFillRectOpLocalMatrix) {
+    GrColor color = GrRandomColor(random);
+    SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
+    SkMatrix localMatrix = GrTest::TestMatrix(random);
+    SkRect rect = GrTest::TestRect(random);
+    SkRect devRect = GrTest::TestRect(random);
+    return GrAAFillRectOp::Make(color, viewMatrix, localMatrix, rect, devRect);
 }
 
 #endif
diff --git a/src/gpu/ops/GrAAFillRectOp.h b/src/gpu/ops/GrAAFillRectOp.h
new file mode 100644
index 0000000..7d97716
--- /dev/null
+++ b/src/gpu/ops/GrAAFillRectOp.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrAAFillRectOp_DEFINED
+#define GrAAFillRectOp_DEFINED
+
+#include "GrColor.h"
+#include "SkRefCnt.h"
+
+class GrLegacyMeshDrawOp;
+class SkMatrix;
+struct SkRect;
+
+namespace GrAAFillRectOp {
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkRect& rect,
+                                         const SkRect& devRect);
+
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkMatrix& localMatrix,
+                                         const SkRect& rect);
+
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkMatrix& localMatrix,
+                                         const SkRect& rect,
+                                         const SkRect& devRect);
+
+std::unique_ptr<GrLegacyMeshDrawOp> MakeWithLocalRect(GrColor color,
+                                                      const SkMatrix& viewMatrix,
+                                                      const SkRect& rect,
+                                                      const SkRect& localRect);
+};
+
+#endif
diff --git a/src/gpu/ops/GrAAStrokeRectOp.cpp b/src/gpu/ops/GrAAStrokeRectOp.cpp
index 82b4ec1..7af6c3e 100644
--- a/src/gpu/ops/GrAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrAAStrokeRectOp.cpp
@@ -5,12 +5,12 @@
  * found in the LICENSE file.
  */
 
+#include "GrAAStrokeRectOp.h"
+
 #include "GrDefaultGeoProcFactory.h"
 #include "GrOpFlushState.h"
-#include "GrRectOpFactory.h"
 #include "GrResourceKey.h"
 #include "GrResourceProvider.h"
-#include "GrSimpleMeshDrawOpHelper.h"
 #include "SkStrokeRec.h"
 
 GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
@@ -110,26 +110,13 @@
                               viewMatrix);
 }
 
-namespace {
-
-class AAStrokeRectOp final : public GrMeshDrawOp {
-private:
-    using Helper = GrSimpleMeshDrawOpHelper;
-
+class AAStrokeRectOp final : public GrLegacyMeshDrawOp {
 public:
     DEFINE_OP_CLASS_ID
 
-    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                          const SkRect& devOutside, const SkRect& devInside) {
-        return Helper::FactoryHelper<AAStrokeRectOp>(std::move(paint), viewMatrix, devOutside,
-                                                     devInside);
-    }
-
-    AAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
-                   const SkRect& devOutside, const SkRect& devInside)
-            : INHERITED(ClassID())
-            , fHelper(helperArgs, GrAAType::kCoverage)
-            , fViewMatrix(viewMatrix) {
+    AAStrokeRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& devOutside,
+                   const SkRect& devInside)
+            : INHERITED(ClassID()), fViewMatrix(viewMatrix) {
         SkASSERT(!devOutside.isEmpty());
         SkASSERT(!devInside.isEmpty());
 
@@ -138,35 +125,30 @@
         fMiterStroke = true;
     }
 
-    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                          const SkRect& rect, const SkStrokeRec& stroke) {
+    static std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
+                                                    const SkRect& rect, const SkStrokeRec& stroke) {
         bool isMiter;
         if (!allowed_stroke(stroke, &isMiter)) {
             return nullptr;
         }
-        return Helper::FactoryHelper<AAStrokeRectOp>(std::move(paint), viewMatrix, rect, stroke,
-                                                     isMiter);
-    }
 
-    AAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix,
-                   const SkRect& rect, const SkStrokeRec& stroke, bool isMiter)
-            : INHERITED(ClassID())
-            , fHelper(helperArgs, GrAAType::kCoverage)
-            , fViewMatrix(viewMatrix) {
-        fMiterStroke = isMiter;
-        RectInfo& info = fRects.push_back();
+        AAStrokeRectOp* op = new AAStrokeRectOp();
+        op->fMiterStroke = isMiter;
+        RectInfo& info = op->fRects.push_back();
         compute_rects(&info.fDevOutside, &info.fDevOutsideAssist, &info.fDevInside,
                       &info.fDegenerate, viewMatrix, rect, stroke.getWidth(), isMiter);
         info.fColor = color;
         if (isMiter) {
-            this->setBounds(info.fDevOutside, HasAABloat::kYes, IsZeroArea::kNo);
+            op->setBounds(info.fDevOutside, HasAABloat::kYes, IsZeroArea::kNo);
         } else {
             // The outer polygon of the bevel stroke is an octagon specified by the points of a
             // pair of overlapping rectangles where one is wide and the other is narrow.
             SkRect bounds = info.fDevOutside;
             bounds.joinPossiblyEmptyRect(info.fDevOutsideAssist);
-            this->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo);
+            op->setBounds(bounds, HasAABloat::kYes, IsZeroArea::kNo);
         }
+        op->fViewMatrix = viewMatrix;
+        return std::unique_ptr<GrLegacyMeshDrawOp>(op);
     }
 
     const char* name() const override { return "AAStrokeRect"; }
@@ -184,18 +166,20 @@
                     info.fDevOutsideAssist.fBottom, info.fDevInside.fLeft, info.fDevInside.fTop,
                     info.fDevInside.fRight, info.fDevInside.fBottom, info.fDegenerate);
         }
+        string.append(DumpPipelineInfo(*this->pipeline()));
         string.append(INHERITED::dumpInfo());
         return string;
     }
 
-    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
-    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
-        return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kSingleChannel,
-                                            &fRects.back().fColor);
-    }
-
 private:
+    AAStrokeRectOp() : INHERITED(ClassID()) {}
+
+    void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
+                                    GrProcessorAnalysisCoverage* coverage) const override {
+        color->setToConstant(fRects[0].fColor);
+        *coverage = GrProcessorAnalysisCoverage::kSingleChannel;
+    }
+    void applyPipelineOptimizations(const PipelineOptimizations&) override;
     void onPrepareDraws(Target*) const override;
 
     static const int kMiterIndexCnt = 3 * 24;
@@ -208,6 +192,8 @@
 
     static const GrBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider, bool miterStroke);
 
+    bool usesLocalCoords() const { return fUsesLocalCoords; }
+    bool canTweakAlphaForCoverage() const { return fCanTweakAlphaForCoverage; }
     const SkMatrix& viewMatrix() const { return fViewMatrix; }
     bool miterStroke() const { return fMiterStroke; }
 
@@ -235,20 +221,29 @@
         bool fDegenerate;
     };
 
-    Helper fHelper;
     SkSTArray<1, RectInfo, true> fRects;
+    bool fUsesLocalCoords;
+    bool fCanTweakAlphaForCoverage;
     SkMatrix fViewMatrix;
     bool fMiterStroke;
 
-    typedef GrMeshDrawOp INHERITED;
+    typedef GrLegacyMeshDrawOp INHERITED;
 };
 
-}  // anonymous namespace
+void AAStrokeRectOp::applyPipelineOptimizations(const PipelineOptimizations& optimizations) {
+    optimizations.getOverrideColorIfSet(&fRects[0].fColor);
+
+    fUsesLocalCoords = optimizations.readsLocalCoords();
+    fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage();
+    fCanTweakAlphaForCoverage = optimizations.canTweakAlphaForCoverage();
+}
 
 void AAStrokeRectOp::onPrepareDraws(Target* target) const {
-    sk_sp<GrGeometryProcessor> gp(create_stroke_rect_gp(fHelper.compatibleWithAlphaAsCoverage(),
+    bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
+
+    sk_sp<GrGeometryProcessor> gp(create_stroke_rect_gp(canTweakAlphaForCoverage,
                                                         this->viewMatrix(),
-                                                        fHelper.usesLocalCoords()));
+                                                        this->usesLocalCoords()));
     if (!gp) {
         SkDebugf("Couldn't create GrGeometryProcessor\n");
         return;
@@ -256,7 +251,7 @@
 
     size_t vertexStride = gp->getVertexStride();
 
-    SkASSERT(fHelper.compatibleWithAlphaAsCoverage()
+    SkASSERT(canTweakAlphaForCoverage
                      ? vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)
                      : vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
     int innerVertexNum = 4;
@@ -289,9 +284,9 @@
                                            info.fDevInside,
                                            fMiterStroke,
                                            info.fDegenerate,
-                                           fHelper.compatibleWithAlphaAsCoverage());
+                                           canTweakAlphaForCoverage);
     }
-    helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
+    helper.recordDraw(target, gp.get(), this->pipeline());
 }
 
 const GrBuffer* AAStrokeRectOp::GetIndexBuffer(GrResourceProvider* resourceProvider,
@@ -391,7 +386,8 @@
 bool AAStrokeRectOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
     AAStrokeRectOp* that = t->cast<AAStrokeRectOp>();
 
-    if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
+    if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
+                                that->bounds(), caps)) {
         return false;
     }
 
@@ -401,11 +397,18 @@
     }
 
     // We apply the viewmatrix to the rect points on the cpu.  However, if the pipeline uses
-    // local coords then we won't be able to combine. TODO: Upload local coords as an attribute.
-    if (fHelper.usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
+    // local coords then we won't be able to combine.  We could actually upload the viewmatrix
+    // using vertex attributes in these cases, but haven't investigated that
+    if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
         return false;
     }
 
+    // In the event of two ops, one who can tweak, one who cannot, we just fall back to not
+    // tweaking.
+    if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
+        fCanTweakAlphaForCoverage = false;
+    }
+
     fRects.push_back_n(that->fRects.count(), that->fRects.begin());
     this->joinBounds(*that);
     return true;
@@ -566,35 +569,23 @@
     }
 }
 
-namespace GrRectOpFactory {
+namespace GrAAStrokeRectOp {
 
-std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrPaint&& paint,
-                                                const SkMatrix& viewMatrix,
-                                                const SkRect rects[2]) {
-    SkASSERT(viewMatrix.rectStaysRect());
-    SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty());
-
-    SkRect devOutside, devInside;
-    viewMatrix.mapRect(&devOutside, rects[0]);
-    viewMatrix.mapRect(&devInside, rects[1]);
-    if (devInside.isEmpty()) {
-        if (devOutside.isEmpty()) {
-            return nullptr;
-        }
-        return MakeAAFillWithDevRect(std::move(paint), viewMatrix, rects[0], devOutside);
-    }
-
-    return AAStrokeRectOp::Make(std::move(paint), viewMatrix, devOutside, devInside);
+std::unique_ptr<GrLegacyMeshDrawOp> MakeFillBetweenRects(GrColor color,
+                                                         const SkMatrix& viewMatrix,
+                                                         const SkRect& devOutside,
+                                                         const SkRect& devInside) {
+    return std::unique_ptr<GrLegacyMeshDrawOp>(
+            new AAStrokeRectOp(color, viewMatrix, devOutside, devInside));
 }
 
-std::unique_ptr<GrDrawOp> MakeAAStroke(GrPaint&& paint,
-                                       const SkMatrix& viewMatrix,
-                                       const SkRect& rect,
-                                       const SkStrokeRec& stroke) {
-    return AAStrokeRectOp::Make(std::move(paint), viewMatrix, rect, stroke);
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkRect& rect,
+                                         const SkStrokeRec& stroke) {
+    return AAStrokeRectOp::Make(color, viewMatrix, rect, stroke);
 }
-
-}  // namespace GrRectOpFactory
+}
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -602,7 +593,7 @@
 
 #include "GrDrawOpTest.h"
 
-GR_DRAW_OP_TEST_DEFINE(AAStrokeRectOp) {
+GR_LEGACY_MESH_DRAW_OP_TEST_DEFINE(AAStrokeRectOp) {
     bool miterStroke = random->nextBool();
 
     // Create either a empty rect or a non-empty rect.
@@ -611,12 +602,14 @@
     SkScalar minDim = SkMinScalar(rect.width(), rect.height());
     SkScalar strokeWidth = random->nextUScalar1() * minDim;
 
+    GrColor color = GrRandomColor(random);
+
     SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
     rec.setStrokeStyle(strokeWidth);
     rec.setStrokeParams(SkPaint::kButt_Cap,
                         miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Join, 1.f);
     SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random);
-    return GrRectOpFactory::MakeAAStroke(std::move(paint), matrix, rect, rec);
+    return GrAAStrokeRectOp::Make(color, matrix, rect, rec);
 }
 
 #endif
diff --git a/src/gpu/ops/GrAAStrokeRectOp.h b/src/gpu/ops/GrAAStrokeRectOp.h
new file mode 100644
index 0000000..074f8e0
--- /dev/null
+++ b/src/gpu/ops/GrAAStrokeRectOp.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrAAStrokeRectOp_DEFINED
+#define GrAAStrokeRectOp_DEFINED
+
+#include "GrColor.h"
+#include "SkRefCnt.h"
+
+class GrLegacyMeshDrawOp;
+class SkMatrix;
+struct SkRect;
+class SkStrokeRec;
+
+namespace GrAAStrokeRectOp {
+
+std::unique_ptr<GrLegacyMeshDrawOp> MakeFillBetweenRects(GrColor color,
+                                                         const SkMatrix& viewMatrix,
+                                                         const SkRect& devOutside,
+                                                         const SkRect& devInside);
+
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkRect& rect,
+                                         const SkStrokeRec& stroke);
+}
+
+#endif
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index c712a9c..bc5702b 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrDefaultPathRenderer.h"
+
 #include "GrContext.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrDrawOpTest.h"
@@ -19,8 +20,9 @@
 #include "SkStrokeRec.h"
 #include "SkTLazy.h"
 #include "SkTraceEvent.h"
+
 #include "ops/GrMeshDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 GrDefaultPathRenderer::GrDefaultPathRenderer() {
 }
@@ -520,8 +522,8 @@
                                                                                viewMatrix;
             renderTargetContext->addDrawOp(
                     clip,
-                    GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
-                            std::move(paint), viewM, localMatrix, bounds, aaType, passes[p]));
+                    GrNonAAFillRectOp::Make(std::move(paint), viewM, bounds, nullptr, &localMatrix,
+                                            aaType, passes[p]));
         } else {
             std::unique_ptr<GrLegacyMeshDrawOp> op =
                     DefaultPathOp::Make(paint.getColor(), path, srcSpaceTol, newCoverage,
diff --git a/src/gpu/ops/GrMSAAPathRenderer.cpp b/src/gpu/ops/GrMSAAPathRenderer.cpp
index f49c8cd..ef64ecf 100644
--- a/src/gpu/ops/GrMSAAPathRenderer.cpp
+++ b/src/gpu/ops/GrMSAAPathRenderer.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrMSAAPathRenderer.h"
+
 #include "GrAuditTrail.h"
 #include "GrClip.h"
 #include "GrDefaultGeoProcFactory.h"
@@ -25,7 +26,7 @@
 #include "glsl/GrGLSLUtil.h"
 #include "glsl/GrGLSLVertexShaderBuilder.h"
 #include "ops/GrMeshDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 static const float kTolerance = 0.5f;
 
@@ -666,8 +667,8 @@
                 (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix;
         renderTargetContext->addDrawOp(
                 clip,
-                GrRectOpFactory::MakeNonAAFillWithLocalMatrix(std::move(paint), viewM, localMatrix,
-                                                              bounds, aaType, passes[1]));
+                GrNonAAFillRectOp::Make(std::move(paint), viewM, bounds, nullptr, &localMatrix,
+                                        aaType, passes[1]));
     }
     return true;
 }
diff --git a/src/gpu/ops/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
index c30f4a1..defc790 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ b/src/gpu/ops/GrNonAAFillRectOp.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "GrNonAAFillRectOp.h"
 #include "GrAppliedClip.h"
 #include "GrColor.h"
 #include "GrDefaultGeoProcFactory.h"
@@ -13,7 +14,6 @@
 #include "GrOpFlushState.h"
 #include "GrPrimitiveProcessor.h"
 #include "GrQuad.h"
-#include "GrRectOpFactory.h"
 #include "GrResourceProvider.h"
 #include "GrSimpleMeshDrawOpHelper.h"
 #include "SkMatrixPriv.h"
@@ -358,45 +358,25 @@
 
 }  // anonymous namespace
 
-namespace GrRectOpFactory {
+namespace GrNonAAFillRectOp {
 
-std::unique_ptr<GrDrawOp> MakeNonAAFill(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                        const SkRect& rect, GrAAType aaType,
-                                        const GrUserStencilSettings* stencilSettings) {
-    if (viewMatrix.hasPerspective()) {
-        return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, nullptr,
-                                                nullptr, aaType, stencilSettings);
-    } else {
-        return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, nullptr, aaType,
-                                     stencilSettings);
-    }
-}
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(
-        GrPaint&& paint, const SkMatrix& viewMatrix, const SkMatrix& localMatrix,
-        const SkRect& rect, GrAAType aaType, const GrUserStencilSettings* stencilSettings) {
-    if (viewMatrix.hasPerspective() || localMatrix.hasPerspective()) {
-        return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, nullptr,
-                                                &localMatrix, aaType, stencilSettings);
-    } else {
-        return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, nullptr, &localMatrix,
+std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
+                               const SkMatrix& viewMatrix,
+                               const SkRect& rect,
+                               const SkRect* localRect,
+                               const SkMatrix* localMatrix,
+                               GrAAType aaType,
+                               const GrUserStencilSettings* stencilSettings) {
+    if (!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective())) {
+        return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, localRect, localMatrix,
                                      aaType, stencilSettings);
-    }
-}
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                                     const SkRect& rect, const SkRect& localRect,
-                                                     GrAAType aaType) {
-    if (viewMatrix.hasPerspective()) {
-        return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, &localRect,
-                                                nullptr, aaType, nullptr);
     } else {
-        return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, &localRect, nullptr,
-                                     aaType, nullptr);
+        return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, localRect,
+                                                localMatrix, aaType, stencilSettings);
     }
 }
 
-}  // namespace GrRectOpFactory
+};  // namespace GrNonAAFillRectOp
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -405,17 +385,14 @@
     SkRect localRect = GrTest::TestRect(random);
     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
     SkMatrix localMatrix = GrTest::TestMatrix(random);
+    bool hasLocalRect = random->nextBool();
+    bool hasLocalMatrix = random->nextBool();
     const GrUserStencilSettings* stencil = GrGetRandomStencil(random, context);
     GrAAType aaType = GrAAType::kNone;
     if (fsaaType == GrFSAAType::kUnifiedMSAA) {
         aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
     }
-    const SkRect* lr = random->nextBool() ? &localRect : nullptr;
-    const SkMatrix* lm = random->nextBool() ? &localMatrix : nullptr;
-    if (viewMatrix.hasPerspective() || (lm && lm->hasPerspective())) {
-        return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, lr, lm, aaType,
-                                                stencil);
-    } else {
-        return NonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, lr, lm, aaType, stencil);
-    }
+    return GrNonAAFillRectOp::Make(std::move(paint), viewMatrix, rect,
+                                   hasLocalRect ? &localRect : nullptr,
+                                   hasLocalMatrix ? &localMatrix : nullptr, aaType, stencil);
 }
diff --git a/src/gpu/ops/GrNonAAFillRectOp.h b/src/gpu/ops/GrNonAAFillRectOp.h
new file mode 100644
index 0000000..70dd8fd
--- /dev/null
+++ b/src/gpu/ops/GrNonAAFillRectOp.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrNonAAFillRectOp_DEFINED
+#define GrNonAAFillRectOp_DEFINED
+
+#include <memory>
+#include "GrColor.h"
+#include "GrDrawOp.h"
+
+class GrPaint;
+class SkMatrix;
+struct SkRect;
+struct GrUserStencilSettings;
+enum class GrAAType : unsigned;
+
+namespace GrNonAAFillRectOp {
+std::unique_ptr<GrDrawOp> Make(GrPaint&&,
+                               const SkMatrix& viewMatrix,
+                               const SkRect& rect,
+                               const SkRect* localRect,
+                               const SkMatrix* localMatrix,
+                               GrAAType,
+                               const GrUserStencilSettings* = nullptr);
+};
+
+#endif
diff --git a/src/gpu/ops/GrNonAAStrokeRectOp.cpp b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
index 4177b65..94dc373 100644
--- a/src/gpu/ops/GrNonAAStrokeRectOp.cpp
+++ b/src/gpu/ops/GrNonAAStrokeRectOp.cpp
@@ -5,15 +5,15 @@
  * found in the LICENSE file.
  */
 
+#include "GrNonAAStrokeRectOp.h"
+
 #include "GrColor.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrDrawOpTest.h"
 #include "GrMeshDrawOp.h"
 #include "GrOpFlushState.h"
-#include "GrRectOpFactory.h"
-#include "GrSimpleMeshDrawOpHelper.h"
-#include "SkRandom.h"
 #include "SkStrokeRec.h"
+#include "SkRandom.h"
 
 /*  create a triangle strip that strokes the specified rect. There are 8
     unique vertices, but we repeat the last 2 to close up. Alternatively we
@@ -46,12 +46,7 @@
            (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_ScalarSqrt2);
 }
 
-namespace {
-
-class NonAAStrokeRectOp final : public GrMeshDrawOp {
-private:
-    using Helper = GrSimpleMeshDrawOpHelper;
-
+class NonAAStrokeRectOp final : public GrLegacyMeshDrawOp {
 public:
     DEFINE_OP_CLASS_ID
 
@@ -63,44 +58,31 @@
                 "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);
+        string.append(DumpPipelineInfo(*this->pipeline()));
         string.append(INHERITED::dumpInfo());
         return string;
     }
 
-    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                          const SkRect& rect, const SkStrokeRec& stroke,
-                                          GrAAType aaType) {
+    static std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix,
+                                                    const SkRect& rect, const SkStrokeRec& stroke,
+                                                    bool snapToPixelCenters) {
         if (!allowed_stroke(stroke)) {
             return nullptr;
         }
-        Helper::Flags flags = Helper::Flags::kNone;
-        // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
-        // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
-        // when MSAA is enabled because it can cause ugly artifacts.
-        if (stroke.getStyle() == SkStrokeRec::kHairline_Style && aaType != GrAAType::kMSAA) {
-            flags |= Helper::Flags::kSnapVerticesToPixelCenters;
-        }
-        return Helper::FactoryHelper<NonAAStrokeRectOp>(std::move(paint), flags, viewMatrix, rect,
-                                                        stroke, aaType);
-    }
-
-    NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, GrColor color, Helper::Flags flags,
-                      const SkMatrix& viewMatrix, const SkRect& rect, const SkStrokeRec& stroke,
-                      GrAAType aaType)
-            : INHERITED(ClassID()), fHelper(helperArgs, aaType, flags) {
-        fColor = color;
-        fViewMatrix = viewMatrix;
-        fRect = rect;
+        NonAAStrokeRectOp* op = new NonAAStrokeRectOp();
+        op->fColor = color;
+        op->fViewMatrix = viewMatrix;
+        op->fRect = rect;
         // Sort the rect for hairlines
-        fRect.sort();
-        fStrokeWidth = stroke.getWidth();
+        op->fRect.sort();
+        op->fStrokeWidth = stroke.getWidth();
 
-        SkScalar rad = SkScalarHalf(fStrokeWidth);
+        SkScalar rad = SkScalarHalf(op->fStrokeWidth);
         SkRect bounds = rect;
         bounds.outset(rad, rad);
 
         // If our caller snaps to pixel centers then we have to round out the bounds
-        if (flags & Helper::Flags::kSnapVerticesToPixelCenters) {
+        if (snapToPixelCenters) {
             viewMatrix.mapRect(&bounds);
             // We want to be consistent with how we snap non-aa lines. To match what we do in
             // GrGLSLVertexShaderBuilder, we first floor all the vertex values and then add half a
@@ -110,27 +92,28 @@
                        SkScalarFloorToScalar(bounds.fRight),
                        SkScalarFloorToScalar(bounds.fBottom));
             bounds.offset(0.5f, 0.5f);
-            this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
+            op->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
         } else {
-            this->setTransformedBounds(bounds, fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
+            op->setTransformedBounds(bounds, op->fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
         }
-    }
-
-    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
-    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
-        bool result = fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone,
-                                                   &fColor);
-        return result;
+        return std::unique_ptr<GrLegacyMeshDrawOp>(op);
     }
 
 private:
+    NonAAStrokeRectOp() : INHERITED(ClassID()) {}
+
+    void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
+                                    GrProcessorAnalysisCoverage* coverage) const override {
+        color->setToConstant(fColor);
+        *coverage = GrProcessorAnalysisCoverage::kNone;
+    }
+
     void onPrepareDraws(Target* target) const override {
         sk_sp<GrGeometryProcessor> gp;
         {
             using namespace GrDefaultGeoProcFactory;
             Color color(fColor);
-            LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
+            LocalCoords::Type localCoordsType = fNeedsLocalCoords
                                                         ? LocalCoords::kUsePosition_Type
                                                         : LocalCoords::kUnused_Type;
             gp = GrDefaultGeoProcFactory::Make(color, Coverage::kSolid_Type, localCoordsType,
@@ -176,7 +159,12 @@
         GrMesh mesh(primType);
         mesh.setNonIndexedNonInstanced(vertexCount);
         mesh.setVertexData(vertexBuffer, firstVertex);
-        target->draw(gp.get(), fHelper.makePipeline(target), mesh);
+        target->draw(gp.get(), this->pipeline(), mesh);
+    }
+
+    void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
+        optimizations.getOverrideColorIfSet(&fColor);
+        fNeedsLocalCoords = optimizations.readsLocalCoords();
     }
 
     bool onCombineIfPossible(GrOp* t, const GrCaps&) override {
@@ -185,46 +173,42 @@
         return false;
     }
 
-    Helper fHelper;
     GrColor fColor;
     SkMatrix fViewMatrix;
     SkRect fRect;
     SkScalar fStrokeWidth;
+    bool fNeedsLocalCoords;
 
     const static int kVertsPerHairlineRect = 5;
     const static int kVertsPerStrokeRect = 10;
 
-    typedef GrMeshDrawOp INHERITED;
+    typedef GrLegacyMeshDrawOp INHERITED;
 };
 
-}  // anonymous namespace
+namespace GrNonAAStrokeRectOp {
 
-namespace GrRectOpFactory {
-std::unique_ptr<GrDrawOp> MakeNonAAStroke(GrPaint&& paint,
-                                          const SkMatrix& viewMatrix,
-                                          const SkRect& rect,
-                                          const SkStrokeRec& stroke,
-                                          GrAAType aaType) {
-    return NonAAStrokeRectOp::Make(std::move(paint), viewMatrix, rect, stroke, aaType);
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkRect& rect,
+                                         const SkStrokeRec& stroke,
+                                         bool snapToPixelCenters) {
+    return NonAAStrokeRectOp::Make(color, viewMatrix, rect, stroke, snapToPixelCenters);
 }
-}  // namespace GrRectOpFactory
+}
 
 #if GR_TEST_UTILS
 
-GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
+GR_LEGACY_MESH_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
     SkMatrix viewMatrix = GrTest::TestMatrix(random);
+    GrColor color = GrRandomColor(random);
     SkRect rect = GrTest::TestRect(random);
     SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f;
-    SkPaint strokePaint;
-    strokePaint.setStrokeWidth(strokeWidth);
-    strokePaint.setStyle(SkPaint::kStroke_Style);
-    strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
-    SkStrokeRec strokeRec(strokePaint);
-    GrAAType aaType = GrAAType::kNone;
-    if (fsaaType == GrFSAAType::kUnifiedMSAA) {
-        aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
-    }
-    return NonAAStrokeRectOp::Make(std::move(paint), viewMatrix, rect, strokeRec, aaType);
+    SkPaint paint;
+    paint.setStrokeWidth(strokeWidth);
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setStrokeJoin(SkPaint::kMiter_Join);
+    SkStrokeRec strokeRec(paint);
+    return GrNonAAStrokeRectOp::Make(color, viewMatrix, rect, strokeRec, random->nextBool());
 }
 
 #endif
diff --git a/src/gpu/ops/GrNonAAStrokeRectOp.h b/src/gpu/ops/GrNonAAStrokeRectOp.h
new file mode 100644
index 0000000..4071cfd
--- /dev/null
+++ b/src/gpu/ops/GrNonAAStrokeRectOp.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrNonAAStrokeRectOp_DEFINED
+#define GrNonAAStrokeRectOp_DEFINED
+
+#include "GrColor.h"
+#include "SkRefCnt.h"
+
+class GrLegacyMeshDrawOp;
+struct SkRect;
+class SkStrokeRec;
+class SkMatrix;
+
+namespace GrNonAAStrokeRectOp {
+
+std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
+                                         const SkMatrix& viewMatrix,
+                                         const SkRect& rect,
+                                         const SkStrokeRec&,
+                                         bool snapToPixelCenters);
+}
+
+#endif
diff --git a/src/gpu/ops/GrRectOpFactory.cpp b/src/gpu/ops/GrRectOpFactory.cpp
new file mode 100644
index 0000000..45e2053
--- /dev/null
+++ b/src/gpu/ops/GrRectOpFactory.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrRectOpFactory.h"
+
+#include "GrAAStrokeRectOp.h"
+#include "GrMeshDrawOp.h"
+#include "SkStrokeRec.h"
+
+namespace GrRectOpFactory {
+
+std::unique_ptr<GrLegacyMeshDrawOp> MakeAAFillNestedRects(GrColor color,
+                                                          const SkMatrix& viewMatrix,
+                                                          const SkRect rects[2]) {
+    SkASSERT(viewMatrix.rectStaysRect());
+    SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty());
+
+    SkRect devOutside, devInside;
+    viewMatrix.mapRect(&devOutside, rects[0]);
+    viewMatrix.mapRect(&devInside, rects[1]);
+    if (devInside.isEmpty()) {
+        if (devOutside.isEmpty()) {
+            return nullptr;
+        }
+        return GrAAFillRectOp::Make(color, viewMatrix, devOutside, devOutside);
+    }
+
+    return GrAAStrokeRectOp::MakeFillBetweenRects(color, viewMatrix, devOutside, devInside);
+}
+};
diff --git a/src/gpu/ops/GrRectOpFactory.h b/src/gpu/ops/GrRectOpFactory.h
index cf3da2f..58927ef 100644
--- a/src/gpu/ops/GrRectOpFactory.h
+++ b/src/gpu/ops/GrRectOpFactory.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Google Inc.
+ * Copyright 2015 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
@@ -8,66 +8,58 @@
 #ifndef GrRectOpFactory_DEFINED
 #define GrRectOpFactory_DEFINED
 
-#include <memory>
-#include "GrTypes.h"
+#include "GrAAFillRectOp.h"
+#include "GrAAStrokeRectOp.h"
+#include "GrAnalyticRectOp.h"
+#include "GrColor.h"
+#include "GrMeshDrawOp.h"
+#include "GrNonAAStrokeRectOp.h"
+#include "GrPaint.h"
+#include "SkMatrix.h"
+#include "SkRefCnt.h"
 
-enum class GrAAType : unsigned;
-class GrDrawOp;
-class GrPaint;
-struct GrUserStencilSettings;
-class SkMatrix;
 struct SkRect;
 class SkStrokeRec;
 
 /**
- * A set of factory functions for drawing rectangles including fills, strokes, coverage-antialiased,
- * and non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp
- * factories, the GrPaint is only consumed by these methods if a valid op is returned. If null is
- * returned then the paint is unmodified and may still be used.
+ * A factory for returning GrDrawOps which can draw rectangles.
  */
 namespace GrRectOpFactory {
-/** AA Fill */
 
-std::unique_ptr<GrDrawOp> MakeAAFill(GrPaint&&, const SkMatrix&, const SkRect&,
-                                     const GrUserStencilSettings* = nullptr);
+inline std::unique_ptr<GrLegacyMeshDrawOp> MakeAAFill(const GrPaint& paint,
+                                                      const SkMatrix& viewMatrix,
+                                                      const SkRect& rect,
+                                                      const SkRect& croppedRect,
+                                                      const SkRect& devRect) {
+    return GrAAFillRectOp::Make(paint.getColor(), viewMatrix, croppedRect, devRect);
+}
 
-// Using this method to supply a device rect simply saves recalculation if the device rect is known.
-std::unique_ptr<GrDrawOp> MakeAAFillWithDevRect(GrPaint&&, const SkMatrix& viewMatrix,
-                                                const SkRect& rect, const SkRect& devRect);
+inline std::unique_ptr<GrLegacyMeshDrawOp> MakeAAFill(GrColor color,
+                                                      const SkMatrix& viewMatrix,
+                                                      const SkMatrix& localMatrix,
+                                                      const SkRect& rect,
+                                                      const SkRect& devRect) {
+    return GrAAFillRectOp::Make(color, viewMatrix, localMatrix, rect, devRect);
+}
 
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrPaint&&, const SkMatrix& viewMatrix,
-                                                    const SkMatrix& localMatrix, const SkRect&);
+inline std::unique_ptr<GrLegacyMeshDrawOp> MakeNonAAStroke(GrColor color,
+                                                           const SkMatrix& viewMatrix,
+                                                           const SkRect& rect,
+                                                           const SkStrokeRec& strokeRec,
+                                                           bool snapToPixelCenters) {
+    return GrNonAAStrokeRectOp::Make(color, viewMatrix, rect, strokeRec, snapToPixelCenters);
+}
 
-std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrPaint&&, const SkMatrix&, const SkRect& rect,
-                                                  const SkRect& localRect);
+inline std::unique_ptr<GrLegacyMeshDrawOp> MakeAAStroke(GrColor color,
+                                                        const SkMatrix& viewMatrix,
+                                                        const SkRect& rect,
+                                                        const SkStrokeRec& stroke) {
+    return GrAAStrokeRectOp::Make(color, viewMatrix, rect, stroke);
+}
 
-/** Non-AA Fill - GrAAType must be either kNone or kMSAA. */
-
-std::unique_ptr<GrDrawOp> MakeNonAAFill(GrPaint&&, const SkMatrix& viewMatrix, const SkRect& rect,
-                                        GrAAType, const GrUserStencilSettings* = nullptr);
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(GrPaint&&, const SkMatrix& viewMatrix,
-                                                       const SkMatrix& localMatrix, const SkRect&,
-                                                       GrAAType,
-                                                       const GrUserStencilSettings* = nullptr);
-
-std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrPaint&&, const SkMatrix&, const SkRect& rect,
-                                                     const SkRect& localRect, GrAAType);
-
-/** AA Stroke */
-
-std::unique_ptr<GrDrawOp> MakeAAStroke(GrPaint&&, const SkMatrix&, const SkRect&,
-                                       const SkStrokeRec&);
-
-// rects[0] == outer rectangle, rects[1] == inner rectangle. Null return means there is nothing to
-// draw rather than failure.
-std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrPaint&&, const SkMatrix&, const SkRect rects[2]);
-
-/** Non-AA Stroke - GrAAType must be either kNone or kMSAA. */
-
-std::unique_ptr<GrDrawOp> MakeNonAAStroke(GrPaint&&, const SkMatrix&, const SkRect&,
-                                          const SkStrokeRec&, GrAAType);
-
-}  // namespace GrRectOpFactory
+// First rect is outer; second rect is inner
+std::unique_ptr<GrLegacyMeshDrawOp> MakeAAFillNestedRects(GrColor, const SkMatrix& viewMatrix,
+                                                          const SkRect rects[2]);
+};
 
 #endif
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index 903859c..dcd8dd8 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -35,26 +35,19 @@
     template <typename Op, typename... OpArgs>
     static std::unique_ptr<GrDrawOp> FactoryHelper(GrPaint&& paint, OpArgs... opArgs);
 
-    enum class Flags : uint32_t {
-        kNone = 0x0,
-        kSnapVerticesToPixelCenters = 0x1,
-    };
-    GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags);
-
-    GrSimpleMeshDrawOpHelper(const MakeArgs& args, GrAAType aaType, Flags flags = Flags::kNone)
+    GrSimpleMeshDrawOpHelper(const MakeArgs& args, GrAAType aaType,
+                             GrUserStencilSettings* stencilSettings = nullptr)
             : fProcessors(args.fProcessorSet)
             , fPipelineFlags(args.fSRGBFlags)
             , fAAType((int)aaType)
             , fRequiresDstTexture(false)
             , fUsesLocalCoords(false)
             , fCompatibleWithAlphaAsCoveage(false) {
+        SkASSERT(!stencilSettings);
         SkDEBUGCODE(fDidAnalysis = false);
         if (GrAATypeIsHW(aaType)) {
             fPipelineFlags |= GrPipeline::kHWAntialias_Flag;
         }
-        if (flags & Flags::kSnapVerticesToPixelCenters) {
-            fPipelineFlags |= GrPipeline::kSnapVerticesToPixelCenters_Flag;
-        }
     }
 
     ~GrSimpleMeshDrawOpHelper() {
@@ -174,7 +167,6 @@
 class GrSimpleMeshDrawOpHelperWithStencil : private GrSimpleMeshDrawOpHelper {
 public:
     using MakeArgs = GrSimpleMeshDrawOpHelper::MakeArgs;
-    using Flags = GrSimpleMeshDrawOpHelper::Flags;
 
     // using declarations can't be templated, so this is a pass through function instead.
     template <typename Op, typename... OpArgs>
@@ -184,9 +176,8 @@
     }
 
     GrSimpleMeshDrawOpHelperWithStencil(const MakeArgs& args, GrAAType aaType,
-                                        const GrUserStencilSettings* stencilSettings,
-                                        Flags flags = Flags::kNone)
-            : INHERITED(args, aaType, flags)
+                                         const GrUserStencilSettings* stencilSettings)
+            : INHERITED(args, aaType)
             , fStencilSettings(stencilSettings ? stencilSettings
                                                : &GrUserStencilSettings::kUnused) {}
 
@@ -200,7 +191,6 @@
 
     using GrSimpleMeshDrawOpHelper::xpRequiresDstTexture;
     using GrSimpleMeshDrawOpHelper::usesLocalCoords;
-    using GrSimpleMeshDrawOpHelper::compatibleWithAlphaAsCoverage;
 
     bool isCompatible(const GrSimpleMeshDrawOpHelperWithStencil& that, const GrCaps& caps,
                       const SkRect& aBounds, const SkRect& bBounds) const {
@@ -237,6 +227,4 @@
     }
 }
 
-GR_MAKE_BITFIELD_CLASS_OPS(GrSimpleMeshDrawOpHelper::Flags)
-
 #endif
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
index a613841..46e9fa7 100644
--- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
@@ -17,7 +17,7 @@
 #include "GrResourceProvider.h"
 #include "GrStencilPathOp.h"
 #include "GrStyle.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
                                                       const GrCaps& caps) {
@@ -134,10 +134,10 @@
             if (GrAAType::kMixedSamples == coverAAType) {
                 coverAAType = GrAAType::kNone;
             }
-            args.fRenderTargetContext->addDrawOp(*args.fClip,
-                                                 GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
-                                                         std::move(args.fPaint), viewM, invert,
-                                                         bounds, coverAAType, &kInvertedCoverPass));
+            args.fRenderTargetContext->addDrawOp(
+                    *args.fClip,
+                    GrNonAAFillRectOp::Make(std::move(args.fPaint), viewM, bounds, nullptr, &invert,
+                                            coverAAType, &kInvertedCoverPass));
         }
     } else {
         std::unique_ptr<GrDrawOp> op =
diff --git a/tests/ProcessorTest.cpp b/tests/ProcessorTest.cpp
index 7f9dff7..528dd61 100644
--- a/tests/ProcessorTest.cpp
+++ b/tests/ProcessorTest.cpp
@@ -19,7 +19,7 @@
 #include "GrResourceProvider.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 #include "ops/GrTestMeshDrawOp.h"
 
 namespace {
@@ -270,9 +270,9 @@
     paint.addColorFragmentProcessor(std::move(fp));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
-    auto op = GrRectOpFactory::MakeNonAAFill(std::move(paint), SkMatrix::I(),
-                                             SkRect::MakeWH(rtc->width(), rtc->height()),
-                                             GrAAType::kNone);
+    auto op = GrNonAAFillRectOp::Make(std::move(paint), SkMatrix::I(),
+                                      SkRect::MakeWH(rtc->width(), rtc->height()), nullptr, nullptr,
+                                      GrAAType::kNone);
     rtc->addDrawOp(GrNoClip(), std::move(op));
 }
 
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index 1eb9860..0486787 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -472,24 +472,25 @@
 #define DRAW_OP_TEST_ENTRY(Op) Op##__Test
 
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(AAConvexPathOp);
+LEGACY_MESH_DRAW_OP_TEST_EXTERN(AAFillRectOp);
+LEGACY_MESH_DRAW_OP_TEST_EXTERN(AAFillRectOpLocalMatrix);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(AAFlatteningConvexPathOp)
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(AAHairlineOp);
+LEGACY_MESH_DRAW_OP_TEST_EXTERN(AAStrokeRectOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(AnalyticRectOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(DashOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(DefaultPathOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(GrDrawAtlasOp);
+LEGACY_MESH_DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(SmallPathOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(TesselatingPathOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(TextBlobOp);
 LEGACY_MESH_DRAW_OP_TEST_EXTERN(VerticesOp);
 
-DRAW_OP_TEST_EXTERN(AAFillRectOp)
-DRAW_OP_TEST_EXTERN(AAStrokeRectOp);
 DRAW_OP_TEST_EXTERN(CircleOp)
 DRAW_OP_TEST_EXTERN(DIEllipseOp);
 DRAW_OP_TEST_EXTERN(EllipseOp);
 DRAW_OP_TEST_EXTERN(NonAAFillRectOp)
-DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp);
 DRAW_OP_TEST_EXTERN(RRectOp);
 
 void GrDrawRandomOp(SkRandom* random, GrRenderTargetContext* renderTargetContext, GrPaint&& paint) {
@@ -497,12 +498,16 @@
     using MakeTestLegacyMeshDrawOpFn = std::unique_ptr<GrLegacyMeshDrawOp>(SkRandom*, GrContext*);
     static constexpr MakeTestLegacyMeshDrawOpFn* gLegacyFactories[] = {
         DRAW_OP_TEST_ENTRY(AAConvexPathOp),
+        DRAW_OP_TEST_ENTRY(AAFillRectOp),
+        DRAW_OP_TEST_ENTRY(AAFillRectOpLocalMatrix),
         DRAW_OP_TEST_ENTRY(AAFlatteningConvexPathOp),
         DRAW_OP_TEST_ENTRY(AAHairlineOp),
+        DRAW_OP_TEST_ENTRY(AAStrokeRectOp),
         DRAW_OP_TEST_ENTRY(AnalyticRectOp),
         DRAW_OP_TEST_ENTRY(DashOp),
         DRAW_OP_TEST_ENTRY(DefaultPathOp),
         DRAW_OP_TEST_ENTRY(GrDrawAtlasOp),
+        DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp),
         DRAW_OP_TEST_ENTRY(SmallPathOp),
         DRAW_OP_TEST_ENTRY(TesselatingPathOp),
         DRAW_OP_TEST_ENTRY(TextBlobOp),
@@ -511,13 +516,10 @@
 
     using MakeDrawOpFn = std::unique_ptr<GrDrawOp>(GrPaint&&, SkRandom*, GrContext*, GrFSAAType);
     static constexpr MakeDrawOpFn* gFactories[] = {
-        DRAW_OP_TEST_ENTRY(AAFillRectOp),
-        DRAW_OP_TEST_ENTRY(AAStrokeRectOp),
         DRAW_OP_TEST_ENTRY(CircleOp),
         DRAW_OP_TEST_ENTRY(DIEllipseOp),
         DRAW_OP_TEST_ENTRY(EllipseOp),
         DRAW_OP_TEST_ENTRY(NonAAFillRectOp),
-        DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp),
         DRAW_OP_TEST_ENTRY(RRectOp),
     };