Move all non-AA fill rect ops off of GrLegacyMeshDrawOp.

This adds perspective to GrNewNonAAFillRectOp, renames it to GrNonAAFillRectOp, and deletes the previous version of that namespace.

Change-Id: I20f35bf019f9c9105e6ec83dda11328451138109
Reviewed-on: https://skia-review.googlesource.com/15634
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gm/bigrrectaaeffect.cpp b/gm/bigrrectaaeffect.cpp
index 786e177..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 {
 
@@ -81,16 +81,16 @@
                 SkASSERT(fp);
                 if (fp) {
                     GrPaint grPaint;
+                    grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f));
                     grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
                     grPaint.addCoverageFragmentProcessor(std::move(fp));
 
                     SkRect bounds = testBounds;
                     bounds.offset(SkIntToScalar(x), SkIntToScalar(y));
 
-                    std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                            0xff000000, SkMatrix::I(), bounds, nullptr, nullptr));
-                    renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                            std::move(grPaint), GrAAType::kNone, std::move(op));
+                    renderTargetContext->priv().testingOnly_addDrawOp(
+                            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 2e0fde2..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 {
 /**
@@ -109,11 +109,9 @@
                     sk_sp<GrFragmentProcessor> fp(GrConstColorProcessor::Make(color, mode));
 
                     grPaint.addColorFragmentProcessor(std::move(fp));
-
-                    std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                            grPaint.getColor(), viewMatrix, renderRect, nullptr, nullptr));
-                    renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                            std::move(grPaint), GrAAType::kNone, std::move(op));
+                    renderTargetContext->priv().testingOnly_addDrawOp(
+                            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/etc1.cpp b/gm/etc1.cpp
index 0c99e50..cc01a0e 100644
--- a/gm/etc1.cpp
+++ b/gm/etc1.cpp
@@ -17,7 +17,7 @@
 #include "GrRenderTargetContextPriv.h"
 #include "GrTextureProxy.h"
 #include "effects/GrSimpleTextureEffect.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 // Basic test of Ganesh's ETC1 support
 class ETC1GM : public skiagm::GM {
@@ -97,10 +97,8 @@
 
         SkRect rect = SkRect::MakeXYWH(kPad, kPad, kTexWidth, kTexHeight);
 
-        std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                GrColor_WHITE, SkMatrix::I(), rect, nullptr, nullptr));
-        renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                std::move(grPaint), GrAAType::kNone, std::move(op));
+        renderTargetContext->priv().testingOnly_addDrawOp(GrNonAAFillRectOp::Make(
+                std::move(grPaint), SkMatrix::I(), rect, nullptr, nullptr, GrAAType::kNone));
     }
 
 private:
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index 8219681..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"
 
@@ -111,14 +111,18 @@
                             GrPaint grPaint;
                             grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
                             grPaint.addCoverageFragmentProcessor(std::move(fp));
+                            grPaint.setColor4f(GrColor4f(0, 0, 0, 1.f));
 
                             SkRect bounds = rrect.getBounds();
                             bounds.outset(2.f, 2.f);
 
-                            std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                                    0xff000000, SkMatrix::I(), bounds, nullptr, nullptr));
-                            renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                                    std::move(grPaint), GrAAType::kNone, std::move(op));
+                            renderTargetContext->priv().testingOnly_addDrawOp(
+                                    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 6a296f4..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 {
 /**
@@ -133,11 +133,9 @@
                     }
                     const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y);
                     grPaint.addColorFragmentProcessor(std::move(fp));
-
-                    std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                            GrColor_WHITE, viewMatrix, renderRect, nullptr, nullptr));
-                    renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                            std::move(grPaint), GrAAType::kNone, std::move(op));
+                    renderTargetContext->priv().testingOnly_addDrawOp(
+                            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 87d76cb..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
@@ -132,10 +132,9 @@
                     grPaint.addColorFragmentProcessor(std::move(fp));
                     SkMatrix viewMatrix;
                     viewMatrix.setTranslate(x, y);
-                    std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                            GrColor_WHITE, viewMatrix, renderRect, nullptr, nullptr));
-                    renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                            std::move(grPaint), GrAAType::kNone, std::move(op));
+                    renderTargetContext->priv().testingOnly_addDrawOp(
+                            GrNonAAFillRectOp::Make(std::move(grPaint), viewMatrix, renderRect,
+                                                    nullptr, nullptr, GrAAType::kNone));
                 }
                 x += renderRect.width() + kTestPad;
             }
@@ -257,10 +256,9 @@
                 SkMatrix viewMatrix;
                 viewMatrix.setTranslate(x, y);
                 grPaint.addColorFragmentProcessor(fp);
-                std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                        GrColor_WHITE, viewMatrix, renderRect, nullptr, nullptr));
-                renderTargetContext->priv().testingOnly_addLegacyMeshDrawOp(
-                        std::move(grPaint), GrAAType::kNone, std::move(op));
+                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 fde979d..b2515f0 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -263,9 +263,6 @@
   "$_src/gpu/ops/GrMSAAPathRenderer.h",
   "$_src/gpu/ops/GrNonAAFillRectOp.h",
   "$_src/gpu/ops/GrNonAAFillRectOp.cpp",
-  "$_src/gpu/ops/GrNewNonAAFillRectOp.h",
-  "$_src/gpu/ops/GrNewNonAAFillRectOp.cpp",
-  "$_src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp",
   "$_src/gpu/ops/GrNonAAStrokeRectOp.cpp",
   "$_src/gpu/ops/GrNonAAStrokeRectOp.h",
   "$_src/gpu/ops/GrLatticeOp.cpp",
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index fc1ab68..12ddb96 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -32,7 +32,7 @@
 #include "ops/GrDrawOp.h"
 #include "ops/GrDrawVerticesOp.h"
 #include "ops/GrLatticeOp.h"
-#include "ops/GrNewNonAAFillRectOp.h"
+#include "ops/GrNonAAFillRectOp.h"
 #include "ops/GrOp.h"
 #include "ops/GrOvalOpFactory.h"
 #include "ops/GrRectOpFactory.h"
@@ -1274,19 +1274,9 @@
                                                 GrAAType hwOrNoneAAType) {
     SkASSERT(GrAAType::kCoverage != hwOrNoneAAType);
     SkASSERT(GrAAType::kNone == hwOrNoneAAType || this->isStencilBufferMultisampled());
-    if (!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective())) {
-        std::unique_ptr<GrDrawOp> op = GrNewNonAAFillRectOp::Make(
-                std::move(paint), viewMatrix, rect, localRect, localMatrix, hwOrNoneAAType, ss);
-        this->addDrawOp(clip, std::move(op));
-        return;
-    }
-    std::unique_ptr<GrLegacyMeshDrawOp> op = GrRectOpFactory::MakeNonAAFill(
-            paint.getColor(), viewMatrix, rect, localRect, localMatrix);
-    GrPipelineBuilder pipelineBuilder(std::move(paint), hwOrNoneAAType);
-    if (ss) {
-        pipelineBuilder.setUserStencil(ss);
-    }
-    this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
+    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?
diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h
index e889317..2acda23 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -107,6 +107,8 @@
                                              const GrUserStencilSettings* = nullptr,
                                              bool snapToCenters = false);
 
+    uint32_t testingOnly_addDrawOp(std::unique_ptr<GrDrawOp>);
+
     bool refsWrappedObjects() const {
         return fRenderTargetContext->fRenderTargetProxy->refsWrappedObjects();
     }
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index 2068734..141f357 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -19,7 +19,7 @@
 
 #include "SkDistanceFieldGen.h"
 
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 /*
  * Convert a boolean operation into a transfer mode code
@@ -173,12 +173,10 @@
     SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX),
                                               SkIntToScalar(-textureOriginInDeviceSpace.fY));
     maskMatrix.preConcat(viewMatrix);
-    std::unique_ptr<GrLegacyMeshDrawOp> op = GrRectOpFactory::MakeNonAAFill(
-            paint.getColor(), SkMatrix::I(), dstRect, nullptr, &invert);
     paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(
             resourceProvider, std::move(proxy), nullptr, maskMatrix,
             GrSamplerParams::kNone_FilterMode));
-    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
-    pipelineBuilder.setUserStencil(&userStencilSettings);
-    renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
+    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 a9613b4..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,12 +76,9 @@
                                            const SkMatrix& viewMatrix,
                                            const SkRect& rect,
                                            const SkMatrix& localMatrix) {
-    std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-            paint.getColor(), viewMatrix, rect, nullptr, &localMatrix));
-
-    GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone);
-    pipelineBuilder.setUserStencil(&userStencilSettings);
-    renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
+    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/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index ef925b6..c683c33 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -22,7 +22,7 @@
 #include "SkTraceEvent.h"
 
 #include "ops/GrMeshDrawOp.h"
-#include "ops/GrRectOpFactory.h"
+#include "ops/GrNonAAFillRectOp.h"
 
 GrDefaultPathRenderer::GrDefaultPathRenderer() {
 }
@@ -523,12 +523,10 @@
             }
             const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
                                                                                viewMatrix;
-            std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                    paint.getColor(), viewM, bounds, nullptr, &localMatrix));
-            GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
-            pipelineBuilder.setUserStencil(passes[p]);
-            renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip,
-                                                     std::move(op));
+            renderTargetContext->addDrawOp(
+                    clip,
+                    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 49f8259..e2f12cf 100644
--- a/src/gpu/ops/GrMSAAPathRenderer.cpp
+++ b/src/gpu/ops/GrMSAAPathRenderer.cpp
@@ -26,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;
 
@@ -668,13 +668,10 @@
         }
         const SkMatrix& viewM =
                 (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : viewMatrix;
-        std::unique_ptr<GrLegacyMeshDrawOp> op(GrRectOpFactory::MakeNonAAFill(
-                paint.getColor(), viewM, bounds, nullptr, &localMatrix));
-
-        GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
-        pipelineBuilder.setUserStencil(passes[1]);
-
-        renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
+        renderTargetContext->addDrawOp(
+                clip,
+                GrNonAAFillRectOp::Make(std::move(paint), viewM, bounds, nullptr, &localMatrix,
+                                        aaType, passes[1]));
     }
     return true;
 }
diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.cpp b/src/gpu/ops/GrNewNonAAFillRectOp.cpp
deleted file mode 100644
index 328f01b..0000000
--- a/src/gpu/ops/GrNewNonAAFillRectOp.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright 2017 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrNewNonAAFillRectOp.h"
-#include "GrAppliedClip.h"
-#include "GrColor.h"
-#include "GrDefaultGeoProcFactory.h"
-#include "GrMeshDrawOp.h"
-#include "GrOpFlushState.h"
-#include "GrPrimitiveProcessor.h"
-#include "GrQuad.h"
-#include "GrResourceProvider.h"
-#include "GrSimpleMeshDrawOpHelper.h"
-#include "SkMatrixPriv.h"
-
-static const int kVertsPerRect = 4;
-static const int kIndicesPerRect = 6;
-
-/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
-    we  have explicit local coords and sometimes not. We *could* always provide explicit local
-    coords and just duplicate the positions when the caller hasn't provided a local coord rect,
-    but we haven't seen a use case which frequently switches between local rect and no local
-    rect draws.
-
-    The vertex attrib order is always pos, color, [local coords].
- */
-static sk_sp<GrGeometryProcessor> make_gp() {
-    using namespace GrDefaultGeoProcFactory;
-    return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type,
-                                         LocalCoords::kHasExplicit_Type, SkMatrix::I());
-}
-
-static void tesselate(intptr_t vertices,
-                      size_t vertexStride,
-                      GrColor color,
-                      const SkMatrix* viewMatrix,
-                      const SkRect& rect,
-                      const GrQuad* localQuad) {
-    SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
-
-    positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
-
-    if (viewMatrix) {
-        SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
-    }
-
-    // Setup local coords
-    // TODO we should only do this if local coords are being read
-    if (localQuad) {
-        static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
-        for (int i = 0; i < kVertsPerRect; i++) {
-            SkPoint* coords =
-                    reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
-            *coords = localQuad->point(i);
-        }
-    }
-
-    static const int kColorOffset = sizeof(SkPoint);
-    GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
-    for (int j = 0; j < 4; ++j) {
-        *vertColor = color;
-        vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
-    }
-}
-
-class NewNonAAFillRectOp final : public GrMeshDrawOp {
-private:
-    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
-
-public:
-    DEFINE_OP_CLASS_ID
-    NewNonAAFillRectOp() = delete;
-
-    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
-                                          const SkRect& rect, const SkRect* localRect,
-                                          const SkMatrix* localMatrix, GrAAType aaType,
-                                          const GrUserStencilSettings* stencilSettings) {
-        SkASSERT(GrAAType::kCoverage != aaType);
-        return Helper::FactoryHelper<NewNonAAFillRectOp>(std::move(paint), viewMatrix, rect,
-                                                         localRect, localMatrix, aaType,
-                                                         stencilSettings);
-    }
-
-    const char* name() const override { return "NonAAFillRectOp"; }
-
-    SkString dumpInfo() const override {
-        SkString str;
-        str.append(GrMeshDrawOp::dumpInfo());
-        str.appendf("# combined: %d\n", fRects.count());
-        for (int i = 0; i < fRects.count(); ++i) {
-            const RectInfo& info = fRects[i];
-            str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
-                        info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
-                        info.fRect.fBottom);
-        }
-        return str;
-    }
-
-    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
-        GrColor* color = &fRects.front().fColor;
-        return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
-    }
-
-    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
-
-    NewNonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix,
-                       const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix,
-                       GrAAType aaType, const GrUserStencilSettings* stencilSettings)
-            : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
-        SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
-        RectInfo& info = fRects.push_back();
-        info.fColor = color;
-        info.fViewMatrix = viewMatrix;
-        info.fRect = rect;
-        if (localRect && localMatrix) {
-            info.fLocalQuad.setFromMappedRect(*localRect, *localMatrix);
-        } else if (localRect) {
-            info.fLocalQuad.set(*localRect);
-        } else if (localMatrix) {
-            info.fLocalQuad.setFromMappedRect(rect, *localMatrix);
-        } else {
-            info.fLocalQuad.set(rect);
-        }
-        this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
-    }
-
-private:
-    void onPrepareDraws(Target* target) const override {
-        sk_sp<GrGeometryProcessor> gp = make_gp();
-        if (!gp) {
-            SkDebugf("Couldn't create GrGeometryProcessor\n");
-            return;
-        }
-        SkASSERT(gp->getVertexStride() ==
-                 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
-
-        size_t vertexStride = gp->getVertexStride();
-        int rectCount = fRects.count();
-
-        sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
-        PatternHelper helper;
-        void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
-                                     indexBuffer.get(), kVertsPerRect, kIndicesPerRect, rectCount);
-        if (!vertices || !indexBuffer) {
-            SkDebugf("Could not allocate vertices\n");
-            return;
-        }
-
-        for (int i = 0; i < rectCount; i++) {
-            intptr_t verts =
-                    reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
-            tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
-                      fRects[i].fRect, &fRects[i].fLocalQuad);
-        }
-        helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
-    }
-
-    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
-        NewNonAAFillRectOp* that = t->cast<NewNonAAFillRectOp>();
-        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
-            return false;
-        }
-        fRects.push_back_n(that->fRects.count(), that->fRects.begin());
-        this->joinBounds(*that);
-        return true;
-    }
-
-    struct RectInfo {
-        GrColor fColor;
-        SkMatrix fViewMatrix;
-        SkRect fRect;
-        GrQuad fLocalQuad;
-    };
-
-    Helper fHelper;
-    SkSTArray<1, RectInfo, true> fRects;
-    typedef GrMeshDrawOp INHERITED;
-};
-
-namespace GrNewNonAAFillRectOp {
-
-std::unique_ptr<GrDrawOp> Make(GrPaint&& paint,
-                               const SkMatrix& viewMatrix,
-                               const SkRect& rect,
-                               const SkRect* localRect,
-                               const SkMatrix* localMatrix,
-                               GrAAType aaType,
-                               const GrUserStencilSettings* stencilSettings) {
-    return NewNonAAFillRectOp::Make(std::move(paint), viewMatrix, rect, localRect, localMatrix,
-                                    aaType, stencilSettings);
-}
-};  // namespace GrNewNonAAFillRectOp
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/ops/GrNewNonAAFillRectOp.h b/src/gpu/ops/GrNewNonAAFillRectOp.h
deleted file mode 100644
index 8f78707..0000000
--- a/src/gpu/ops/GrNewNonAAFillRectOp.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 GrNewNonAAFillRectOp_DEFINED
-#define GrNewNonAAFillRectOp_DEFINED
-
-#include <memory>
-#include "GrColor.h"
-
-class GrDrawOp;
-class GrPaint;
-class SkMatrix;
-struct SkRect;
-struct GrUserStencilSettings;
-enum class GrAAType : unsigned;
-
-namespace GrNewNonAAFillRectOp {
-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/GrNonAAFillRectOp.cpp b/src/gpu/ops/GrNonAAFillRectOp.cpp
index b9c20e1..384856a 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.cpp
+++ b/src/gpu/ops/GrNonAAFillRectOp.cpp
@@ -1,12 +1,12 @@
 /*
- * Copyright 2015 Google Inc.
+ * Copyright 2017 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
 
 #include "GrNonAAFillRectOp.h"
-
+#include "GrAppliedClip.h"
 #include "GrColor.h"
 #include "GrDefaultGeoProcFactory.h"
 #include "GrMeshDrawOp.h"
@@ -14,11 +14,11 @@
 #include "GrPrimitiveProcessor.h"
 #include "GrQuad.h"
 #include "GrResourceProvider.h"
-
+#include "GrSimpleMeshDrawOpHelper.h"
 #include "SkMatrixPriv.h"
 
-static const int kVertsPerInstance = 4;
-static const int kIndicesPerInstance = 6;
+static const int kVertsPerRect = 4;
+static const int kIndicesPerRect = 6;
 
 /** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
     we  have explicit local coords and sometimes not. We *could* always provide explicit local
@@ -34,6 +34,35 @@
                                          LocalCoords::kHasExplicit_Type, SkMatrix::I());
 }
 
+static sk_sp<GrGeometryProcessor> make_perspective_gp(const SkMatrix& viewMatrix,
+                                                      bool hasExplicitLocalCoords,
+                                                      const SkMatrix* localMatrix) {
+    SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
+
+    using namespace GrDefaultGeoProcFactory;
+
+    // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
+    // the local rect on the cpu (in case the localMatrix also has perspective).
+    // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
+    // to generate vertex local coords
+    if (viewMatrix.hasPerspective()) {
+        LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
+                                                       : LocalCoords::kUsePosition_Type,
+                                localMatrix);
+        return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
+                                             Coverage::kSolid_Type, localCoords, viewMatrix);
+    } else if (hasExplicitLocalCoords) {
+        LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
+        return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
+                                             Coverage::kSolid_Type, localCoords, SkMatrix::I());
+    } else {
+        LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
+        return GrDefaultGeoProcFactory::MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type,
+                                                           Coverage::kSolid_Type, localCoords,
+                                                           viewMatrix);
+    }
+}
+
 static void tesselate(intptr_t vertices,
                       size_t vertexStride,
                       GrColor color,
@@ -45,14 +74,14 @@
     positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
 
     if (viewMatrix) {
-        SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerInstance);
+        SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
     }
 
     // Setup local coords
     // TODO we should only do this if local coords are being read
     if (localQuad) {
         static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
-        for (int i = 0; i < kVertsPerInstance; i++) {
+        for (int i = 0; i < kVertsPerRect; i++) {
             SkPoint* coords =
                     reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
             *coords = localQuad->point(i);
@@ -67,13 +96,28 @@
     }
 }
 
-class NonAAFillRectOp final : public GrLegacyMeshDrawOp {
-public:
-    DEFINE_OP_CLASS_ID
+namespace {
 
-    NonAAFillRectOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
-                    const SkRect* localRect, const SkMatrix* localMatrix)
-            : INHERITED(ClassID()) {
+class NonAAFillRectOp final : public GrMeshDrawOp {
+private:
+    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
+
+public:
+    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+                                          const SkRect& rect, const SkRect* localRect,
+                                          const SkMatrix* localMatrix, GrAAType aaType,
+                                          const GrUserStencilSettings* stencilSettings) {
+        SkASSERT(GrAAType::kCoverage != aaType);
+        return Helper::FactoryHelper<NonAAFillRectOp>(std::move(paint), viewMatrix, rect, localRect,
+                                                      localMatrix, aaType, stencilSettings);
+    }
+
+    NonAAFillRectOp() = delete;
+
+    NonAAFillRectOp(const Helper::MakeArgs& args, GrColor color, const SkMatrix& viewMatrix,
+                    const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix,
+                    GrAAType aaType, const GrUserStencilSettings* stencilSettings)
+            : INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
         SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
         RectInfo& info = fRects.push_back();
         info.fColor = color;
@@ -95,7 +139,7 @@
 
     SkString dumpInfo() const override {
         SkString str;
-        str.append(INHERITED::dumpInfo());
+        str.append(GrMeshDrawOp::dumpInfo());
         str.appendf("# combined: %d\n", fRects.count());
         for (int i = 0; i < fRects.count(); ++i) {
             const RectInfo& info = fRects[i];
@@ -103,23 +147,19 @@
                         info.fColor, info.fRect.fLeft, info.fRect.fTop, info.fRect.fRight,
                         info.fRect.fBottom);
         }
-        str.append(DumpPipelineInfo(*this->pipeline()));
         return str;
     }
 
+    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
+        GrColor* color = &fRects.front().fColor;
+        return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
+    }
+
+    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
+
+    DEFINE_OP_CLASS_ID
+
 private:
-    NonAAFillRectOp() : INHERITED(ClassID()) {}
-
-    void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
-                                    GrProcessorAnalysisCoverage* coverage) const override {
-        color->setToConstant(fRects[0].fColor);
-        *coverage = GrProcessorAnalysisCoverage::kNone;
-    }
-
-    void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
-        optimizations.getOverrideColorIfSet(&fRects[0].fColor);
-    }
-
     void onPrepareDraws(Target* target) const override {
         sk_sp<GrGeometryProcessor> gp = make_gp();
         if (!gp) {
@@ -130,34 +170,31 @@
                  sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
 
         size_t vertexStride = gp->getVertexStride();
-        int instanceCount = fRects.count();
+        int rectCount = fRects.count();
 
         sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
         PatternHelper helper;
-        void* vertices =
-                helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(),
-                            kVertsPerInstance, kIndicesPerInstance, instanceCount);
+        void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
+                                     indexBuffer.get(), kVertsPerRect, kIndicesPerRect, rectCount);
         if (!vertices || !indexBuffer) {
             SkDebugf("Could not allocate vertices\n");
             return;
         }
 
-        for (int i = 0; i < instanceCount; i++) {
+        for (int i = 0; i < rectCount; i++) {
             intptr_t verts =
-                    reinterpret_cast<intptr_t>(vertices) + i * kVertsPerInstance * vertexStride;
+                    reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
             tesselate(verts, vertexStride, fRects[i].fColor, &fRects[i].fViewMatrix,
                       fRects[i].fRect, &fRects[i].fLocalQuad);
         }
-        helper.recordDraw(target, gp.get(), this->pipeline());
+        helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
     }
 
     bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
         NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
-        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
-                                    that->bounds(), caps)) {
+        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
             return false;
         }
-
         fRects.push_back_n(that->fRects.count(), that->fRects.begin());
         this->joinBounds(*that);
         return true;
@@ -170,43 +207,173 @@
         GrQuad fLocalQuad;
     };
 
+    Helper fHelper;
     SkSTArray<1, RectInfo, true> fRects;
-
-    typedef GrLegacyMeshDrawOp INHERITED;
+    typedef GrMeshDrawOp INHERITED;
 };
 
+// We handle perspective in the local matrix or viewmatrix with special ops.
+class NonAAFillRectPerspectiveOp final : public GrMeshDrawOp {
+private:
+    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
+
+public:
+    static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix,
+                                          const SkRect& rect, const SkRect* localRect,
+                                          const SkMatrix* localMatrix, GrAAType aaType,
+                                          const GrUserStencilSettings* stencilSettings) {
+        SkASSERT(GrAAType::kCoverage != aaType);
+        return Helper::FactoryHelper<NonAAFillRectPerspectiveOp>(std::move(paint), viewMatrix, rect,
+                                                                 localRect, localMatrix, aaType,
+                                                                 stencilSettings);
+    }
+
+    NonAAFillRectPerspectiveOp() = delete;
+
+    NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, GrColor color,
+                               const SkMatrix& viewMatrix, const SkRect& rect,
+                               const SkRect* localRect, const SkMatrix* localMatrix,
+                               GrAAType aaType, const GrUserStencilSettings* stencilSettings)
+            : INHERITED(ClassID())
+            , fHelper(args, aaType, stencilSettings)
+            , fViewMatrix(viewMatrix) {
+        SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
+        RectInfo& info = fRects.push_back();
+        info.fColor = color;
+        info.fRect = rect;
+        fHasLocalRect = SkToBool(localRect);
+        fHasLocalMatrix = SkToBool(localMatrix);
+        if (fHasLocalMatrix) {
+            fLocalMatrix = *localMatrix;
+        }
+        if (fHasLocalRect) {
+            info.fLocalRect = *localRect;
+        }
+        this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
+    }
+
+    const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
+
+    SkString dumpInfo() const override {
+        SkString str;
+        str.appendf("# combined: %d\n", fRects.count());
+        for (int i = 0; i < fRects.count(); ++i) {
+            const RectInfo& geo = fRects[0];
+            str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
+                        geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight,
+                        geo.fRect.fBottom);
+        }
+        str.append(INHERITED::dumpInfo());
+        return str;
+    }
+
+    bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
+        GrColor* color = &fRects.front().fColor;
+        return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
+    }
+
+    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
+
+    DEFINE_OP_CLASS_ID
+
+private:
+    void onPrepareDraws(Target* target) const override {
+        sk_sp<GrGeometryProcessor> gp = make_perspective_gp(
+                fViewMatrix, fHasLocalRect, fHasLocalMatrix ? &fLocalMatrix : nullptr);
+        if (!gp) {
+            SkDebugf("Couldn't create GrGeometryProcessor\n");
+            return;
+        }
+        SkASSERT(fHasLocalRect
+                         ? gp->getVertexStride() ==
+                                   sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
+                         : gp->getVertexStride() ==
+                                   sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
+
+        size_t vertexStride = gp->getVertexStride();
+        int rectCount = fRects.count();
+
+        sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
+        PatternHelper helper;
+        void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
+                                     indexBuffer.get(), kVertsPerRect, kIndicesPerRect, rectCount);
+        if (!vertices || !indexBuffer) {
+            SkDebugf("Could not allocate vertices\n");
+            return;
+        }
+
+        for (int i = 0; i < rectCount; i++) {
+            const RectInfo& info = fRects[i];
+            intptr_t verts =
+                    reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
+            if (fHasLocalRect) {
+                GrQuad quad(info.fLocalRect);
+                tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad);
+            } else {
+                tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr);
+            }
+        }
+        helper.recordDraw(target, gp.get(), fHelper.makePipeline(target));
+    }
+
+    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
+        NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
+        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
+            return false;
+        }
+
+        // We could combine across perspective vm changes if we really wanted to.
+        if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
+            return false;
+        }
+        if (fHasLocalRect != that->fHasLocalRect) {
+            return false;
+        }
+        if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
+            return false;
+        }
+
+        fRects.push_back_n(that->fRects.count(), that->fRects.begin());
+        this->joinBounds(*that);
+        return true;
+    }
+
+    struct RectInfo {
+        SkRect fRect;
+        GrColor fColor;
+        SkRect fLocalRect;
+    };
+
+    SkSTArray<1, RectInfo, true> fRects;
+    Helper fHelper;
+    bool fHasLocalMatrix;
+    bool fHasLocalRect;
+    SkMatrix fLocalMatrix;
+    SkMatrix fViewMatrix;
+
+    typedef GrMeshDrawOp INHERITED;
+};
+
+}  // anonymous namespace
+
 namespace GrNonAAFillRectOp {
 
-std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
-                                         const SkMatrix& viewMatrix,
-                                         const SkRect& rect,
-                                         const SkRect* localRect,
-                                         const SkMatrix* localMatrix) {
-    return std::unique_ptr<GrLegacyMeshDrawOp>(
-            new NonAAFillRectOp(color, viewMatrix, rect, localRect, 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);
+    } else {
+        return NonAAFillRectPerspectiveOp::Make(std::move(paint), viewMatrix, rect, localRect,
+                                                localMatrix, aaType, stencilSettings);
+    }
 }
-};
+
+};  // namespace GrNonAAFillRectOp
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#if GR_TEST_UTILS
-
-#include "GrDrawOpTest.h"
-
-DRAW_OP_TEST_DEFINE(NonAAFillRectOp) {
-    GrColor color = GrRandomColor(random);
-    SkRect rect = GrTest::TestRect(random);
-    SkRect localRect = GrTest::TestRect(random);
-    SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
-    SkMatrix localMatrix = GrTest::TestMatrix(random);
-
-    bool hasLocalRect = random->nextBool();
-    bool hasLocalMatrix = random->nextBool();
-    return GrNonAAFillRectOp::Make(color,
-                                   viewMatrix,
-                                   rect,
-                                   hasLocalRect ? &localRect : nullptr,
-                                   hasLocalMatrix ? &localMatrix : nullptr);
-}
-
-#endif
diff --git a/src/gpu/ops/GrNonAAFillRectOp.h b/src/gpu/ops/GrNonAAFillRectOp.h
index 8972281..c936f2e 100644
--- a/src/gpu/ops/GrNonAAFillRectOp.h
+++ b/src/gpu/ops/GrNonAAFillRectOp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Google Inc.
+ * Copyright 2017 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
@@ -8,26 +8,24 @@
 #ifndef GrNonAAFillRectOp_DEFINED
 #define GrNonAAFillRectOp_DEFINED
 
+#include <memory>
 #include "GrColor.h"
-#include "SkRefCnt.h"
 
-class GrLegacyMeshDrawOp;
+class GrDrawOp;
+class GrPaint;
 class SkMatrix;
 struct SkRect;
+struct GrUserStencilSettings;
+enum class GrAAType : unsigned;
 
 namespace GrNonAAFillRectOp {
-
-std::unique_ptr<GrLegacyMeshDrawOp> Make(GrColor color,
-                                         const SkMatrix& viewMatrix,
-                                         const SkRect& rect,
-                                         const SkRect* localRect,
-                                         const SkMatrix* localMatrix);
-
-std::unique_ptr<GrLegacyMeshDrawOp> MakeWithPerspective(GrColor color,
-                                                        const SkMatrix& viewMatrix,
-                                                        const SkRect& rect,
-                                                        const SkRect* localRect,
-                                                        const SkMatrix* localMatrix);
+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/GrNonAAFillRectPerspectiveOp.cpp b/src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp
deleted file mode 100644
index 647f69e..0000000
--- a/src/gpu/ops/GrNonAAFillRectPerspectiveOp.cpp
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * 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 "GrNonAAFillRectOp.h"
-
-#include "GrColor.h"
-#include "GrDefaultGeoProcFactory.h"
-#include "GrMeshDrawOp.h"
-#include "GrOpFlushState.h"
-#include "GrPrimitiveProcessor.h"
-#include "GrQuad.h"
-#include "GrResourceProvider.h"
-
-static const int kVertsPerInstance = 4;
-static const int kIndicesPerInstance = 6;
-
-/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
-    we  have explicit local coords and sometimes not. We *could* always provide explicit local
-    coords and just duplicate the positions when the caller hasn't provided a local coord rect,
-    but we haven't seen a use case which frequently switches between local rect and no local
-    rect draws.
-
-    The vertex attrib order is always pos, color, [local coords].
- */
-static sk_sp<GrGeometryProcessor> make_persp_gp(const SkMatrix& viewMatrix,
-                                                bool hasExplicitLocalCoords,
-                                                const SkMatrix* localMatrix) {
-    SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
-
-    using namespace GrDefaultGeoProcFactory;
-
-    // If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
-    // the local rect on the cpu (in case the localMatrix also has perspective).
-    // Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
-    // to generate vertex local coords
-    if (viewMatrix.hasPerspective()) {
-        LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
-                                                       : LocalCoords::kUsePosition_Type,
-                                localMatrix);
-        return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
-                                             Coverage::kSolid_Type, localCoords, viewMatrix);
-    } else if (hasExplicitLocalCoords) {
-        LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
-        return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type,
-                                             Coverage::kSolid_Type, localCoords, SkMatrix::I());
-    } else {
-        LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
-        return GrDefaultGeoProcFactory::MakeForDeviceSpace(Color::kPremulGrColorAttribute_Type,
-                                                           Coverage::kSolid_Type, localCoords,
-                                                           viewMatrix);
-    }
-}
-
-static void tesselate(intptr_t vertices,
-                      size_t vertexStride,
-                      GrColor color,
-                      const SkMatrix* viewMatrix,
-                      const SkRect& rect,
-                      const GrQuad* localQuad) {
-    SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
-
-    positions->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride);
-
-    if (viewMatrix) {
-        viewMatrix->mapPointsWithStride(positions, vertexStride, kVertsPerInstance);
-    }
-
-    // Setup local coords
-    // TODO we should only do this if local coords are being read
-    if (localQuad) {
-        static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
-        for (int i = 0; i < kVertsPerInstance; i++) {
-            SkPoint* coords =
-                    reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
-            *coords = localQuad->point(i);
-        }
-    }
-
-    static const int kColorOffset = sizeof(SkPoint);
-    GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
-    for (int j = 0; j < 4; ++j) {
-        *vertColor = color;
-        vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
-    }
-}
-
-// We handle perspective in the local matrix or viewmatrix with special ops.
-class NonAAFillRectPerspectiveOp final : public GrLegacyMeshDrawOp {
-public:
-    DEFINE_OP_CLASS_ID
-
-    NonAAFillRectPerspectiveOp(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
-                               const SkRect* localRect, const SkMatrix* localMatrix)
-            : INHERITED(ClassID()), fViewMatrix(viewMatrix) {
-        SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
-        RectInfo& info = fRects.push_back();
-        info.fColor = color;
-        info.fRect = rect;
-        fHasLocalRect = SkToBool(localRect);
-        fHasLocalMatrix = SkToBool(localMatrix);
-        if (fHasLocalMatrix) {
-            fLocalMatrix = *localMatrix;
-        }
-        if (fHasLocalRect) {
-            info.fLocalRect = *localRect;
-        }
-        this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
-    }
-
-    const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
-
-    SkString dumpInfo() const override {
-        SkString str;
-        str.appendf("# combined: %d\n", fRects.count());
-        for (int i = 0; i < fRects.count(); ++i) {
-            const RectInfo& geo = fRects[0];
-            str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
-                        geo.fColor, geo.fRect.fLeft, geo.fRect.fTop, geo.fRect.fRight,
-                        geo.fRect.fBottom);
-        }
-        str.append(DumpPipelineInfo(*this->pipeline()));
-        str.append(INHERITED::dumpInfo());
-        return str;
-    }
-
-private:
-    NonAAFillRectPerspectiveOp() : INHERITED(ClassID()) {}
-
-    void getProcessorAnalysisInputs(GrProcessorAnalysisColor* color,
-                                    GrProcessorAnalysisCoverage* coverage) const override {
-        color->setToConstant(fRects[0].fColor);
-        *coverage = GrProcessorAnalysisCoverage::kNone;
-    }
-
-    void applyPipelineOptimizations(const PipelineOptimizations& optimizations) override {
-        optimizations.getOverrideColorIfSet(&fRects[0].fColor);
-    }
-
-    void onPrepareDraws(Target* target) const override {
-        sk_sp<GrGeometryProcessor> gp = make_persp_gp(fViewMatrix,
-                                                      fHasLocalRect,
-                                                      fHasLocalMatrix ? &fLocalMatrix : nullptr);
-        if (!gp) {
-            SkDebugf("Couldn't create GrGeometryProcessor\n");
-            return;
-        }
-        SkASSERT(fHasLocalRect
-                         ? gp->getVertexStride() ==
-                                   sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)
-                         : gp->getVertexStride() ==
-                                   sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
-
-        size_t vertexStride = gp->getVertexStride();
-        int instanceCount = fRects.count();
-
-        sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer());
-        PatternHelper helper;
-        void* vertices =
-                helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(),
-                            kVertsPerInstance, kIndicesPerInstance, instanceCount);
-        if (!vertices || !indexBuffer) {
-            SkDebugf("Could not allocate vertices\n");
-            return;
-        }
-
-        for (int i = 0; i < instanceCount; i++) {
-            const RectInfo& info = fRects[i];
-            intptr_t verts =
-                    reinterpret_cast<intptr_t>(vertices) + i * kVertsPerInstance * vertexStride;
-            if (fHasLocalRect) {
-                GrQuad quad(info.fLocalRect);
-                tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, &quad);
-            } else {
-                tesselate(verts, vertexStride, info.fColor, nullptr, info.fRect, nullptr);
-            }
-        }
-        helper.recordDraw(target, gp.get(), this->pipeline());
-    }
-
-    bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
-        NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
-        if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
-                                    that->bounds(), caps)) {
-            return false;
-        }
-
-        // We could combine across perspective vm changes if we really wanted to.
-        if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
-            return false;
-        }
-        if (fHasLocalRect != that->fHasLocalRect) {
-            return false;
-        }
-        if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
-            return false;
-        }
-
-        fRects.push_back_n(that->fRects.count(), that->fRects.begin());
-        this->joinBounds(*that);
-        return true;
-    }
-
-    struct RectInfo {
-        SkRect fRect;
-        GrColor fColor;
-        SkRect fLocalRect;
-    };
-
-    SkSTArray<1, RectInfo, true> fRects;
-    bool fHasLocalMatrix;
-    bool fHasLocalRect;
-    SkMatrix fLocalMatrix;
-    SkMatrix fViewMatrix;
-
-    typedef GrLegacyMeshDrawOp INHERITED;
-};
-
-namespace GrNonAAFillRectOp {
-
-std::unique_ptr<GrLegacyMeshDrawOp> MakeWithPerspective(GrColor color,
-                                                        const SkMatrix& viewMatrix,
-                                                        const SkRect& rect,
-                                                        const SkRect* localRect,
-                                                        const SkMatrix* localMatrix) {
-    return std::unique_ptr<GrLegacyMeshDrawOp>(
-            new NonAAFillRectPerspectiveOp(color, viewMatrix, rect, localRect, localMatrix));
-}
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#if GR_TEST_UTILS
-
-#include "GrDrawOpTest.h"
-
-DRAW_OP_TEST_DEFINE(NonAAFillRectPerspectiveOp) {
-    GrColor color = GrRandomColor(random);
-    SkRect rect = GrTest::TestRect(random);
-    SkRect localRect = GrTest::TestRect(random);
-    SkMatrix viewMatrix = GrTest::TestMatrix(random);
-    bool hasLocalMatrix = random->nextBool();
-    SkMatrix localMatrix;
-    if (!viewMatrix.hasPerspective()) {
-        localMatrix = GrTest::TestMatrixPerspective(random);
-        hasLocalMatrix = true;
-    }
-
-    bool hasLocalRect = random->nextBool();
-    return GrNonAAFillRectOp::MakeWithPerspective(color, viewMatrix, rect,
-                                                  hasLocalRect ? &localRect : nullptr,
-                                                  hasLocalMatrix ? &localMatrix : nullptr);
-}
-
-#endif
diff --git a/src/gpu/ops/GrRectOpFactory.h b/src/gpu/ops/GrRectOpFactory.h
index fef88e6..f4b1b80 100644
--- a/src/gpu/ops/GrRectOpFactory.h
+++ b/src/gpu/ops/GrRectOpFactory.h
@@ -13,7 +13,6 @@
 #include "GrAnalyticRectOp.h"
 #include "GrColor.h"
 #include "GrMeshDrawOp.h"
-#include "GrNonAAFillRectOp.h"
 #include "GrNonAAStrokeRectOp.h"
 #include "GrPaint.h"
 #include "SkMatrix.h"
@@ -27,19 +26,6 @@
  */
 namespace GrRectOpFactory {
 
-inline std::unique_ptr<GrLegacyMeshDrawOp> MakeNonAAFill(GrColor color,
-                                                         const SkMatrix& viewMatrix,
-                                                         const SkRect& rect,
-                                                         const SkRect* localRect,
-                                                         const SkMatrix* localMatrix) {
-    if (viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective())) {
-        return GrNonAAFillRectOp::MakeWithPerspective(color, viewMatrix, rect, localRect,
-                                                      localMatrix);
-    } else {
-        return GrNonAAFillRectOp::Make(color, viewMatrix, rect, localRect, localMatrix);
-    }
-}
-
 inline std::unique_ptr<GrLegacyMeshDrawOp> MakeAAFill(const GrPaint& paint,
                                                       const SkMatrix& viewMatrix,
                                                       const SkRect& rect,
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
index 9832359..4822850 100644
--- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
@@ -18,7 +18,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) {
@@ -112,9 +112,6 @@
         }
         const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
 
-        std::unique_ptr<GrLegacyMeshDrawOp> coverOp(GrRectOpFactory::MakeNonAAFill(
-                args.fPaint.getColor(), viewM, bounds, nullptr, &invert));
-
         // fake inverse with a stencil and cover
         args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix,
                                                       path.get());
@@ -138,11 +135,10 @@
             if (GrAAType::kMixedSamples == coverAAType) {
                 coverAAType = GrAAType::kNone;
             }
-            GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), coverAAType);
-            pipelineBuilder.setUserStencil(&kInvertedCoverPass);
-
-            args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip,
-                                                           std::move(coverOp));
+            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 29ea29f..ee89ff3 100644
--- a/tests/ProcessorTest.cpp
+++ b/tests/ProcessorTest.cpp
@@ -9,6 +9,7 @@
 #include "Test.h"
 
 #if SK_SUPPORT_GPU
+#include <random>
 #include "GrClip.h"
 #include "GrContext.h"
 #include "GrGpuResource.h"
@@ -20,7 +21,6 @@
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "ops/GrNonAAFillRectOp.h"
 #include "ops/GrTestMeshDrawOp.h"
-#include <random>
 
 namespace {
 class TestOp : public GrTestMeshDrawOp {
@@ -266,11 +266,11 @@
                                    nullptr, SkMatrix::I());
     paint.addColorFragmentProcessor(std::move(fp));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    GrPipelineBuilder pb(std::move(paint), GrAAType::kNone);
-    auto op =
-            GrNonAAFillRectOp::Make(GrColor_WHITE, SkMatrix::I(),
-                                    SkRect::MakeWH(rtc->width(), rtc->height()), nullptr, nullptr);
-    rtc->addLegacyMeshDrawOp(std::move(pb), GrNoClip(), std::move(op));
+
+    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));
 }
 
 #include "SkCommandLineFlags.h"
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index cd21e83..73ceab4 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -254,8 +254,9 @@
     if (fRenderTargetContext->drawingManager()->wasAbandoned()) {
         return SK_InvalidUniqueID;
     }
-    SkDEBUGCODE(fRenderTargetContext->validate();) GR_AUDIT_TRAIL_AUTO_FRAME(
-            fRenderTargetContext->fAuditTrail, "GrRenderTargetContext::testingOnly_addMeshDrawOp");
+    SkDEBUGCODE(fRenderTargetContext->validate());
+    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
+                              "GrRenderTargetContext::testingOnly_addLegacyMeshDrawOp");
 
     GrPipelineBuilder pipelineBuilder(std::move(paint), aaType);
     if (uss) {
@@ -267,6 +268,17 @@
                                                      std::move(op));
 }
 
+uint32_t GrRenderTargetContextPriv::testingOnly_addDrawOp(std::unique_ptr<GrDrawOp> op) {
+    ASSERT_SINGLE_OWNER
+    if (fRenderTargetContext->drawingManager()->wasAbandoned()) {
+        return SK_InvalidUniqueID;
+    }
+    SkDEBUGCODE(fRenderTargetContext->validate());
+    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
+                              "GrRenderTargetContext::testingOnly_addDrawOp");
+    return fRenderTargetContext->addDrawOp(GrNoClip(), std::move(op));
+}
+
 #undef ASSERT_SINGLE_OWNER
 
 ///////////////////////////////////////////////////////////////////////////////