Begin weaning GrClipMaskManager off of GrDrawTarget (take 2)

GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1754563003

Review URL: https://codereview.chromium.org/1754563003
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index 2511dec..5d26be8 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -12,7 +12,7 @@
 
 #if SK_SUPPORT_GPU
 
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrContext.h"
 #include "GrPathUtils.h"
 #include "GrTest.h"
@@ -226,7 +226,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(
                             BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, klmSigns[c]));
 
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
                 }
                 ++col;
                 if (numCols == col) {
@@ -367,7 +367,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(
                             BezierCubicOrConicTestBatch::Create(gp, geometry, klmEqs, 1.f));
 
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
                 }
                 ++col;
                 if (numCols == col) {
@@ -603,7 +603,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(BezierQuadTestBatch::Create(gp, geometry,
                                                                                 DevToUV));
 
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
                 }
                 ++col;
                 if (numCols == col) {
diff --git a/gm/bigrrectaaeffect.cpp b/gm/bigrrectaaeffect.cpp
index fde6360..3a7a155 100644
--- a/gm/bigrrectaaeffect.cpp
+++ b/gm/bigrrectaaeffect.cpp
@@ -8,7 +8,7 @@
 #include "gm.h"
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrPipelineBuilder.h"
 #include "SkDevice.h"
 #include "SkRRect.h"
@@ -99,7 +99,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(
                             GrRectBatchFactory::CreateNonAAFill(0xff000000, SkMatrix::I(), bounds,
                                                                 nullptr, nullptr));
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
                 }
             canvas->restore();
             x = x + fTestOffsetX;
diff --git a/gm/constcolorprocessor.cpp b/gm/constcolorprocessor.cpp
index a9cd4b5..177a8c9 100644
--- a/gm/constcolorprocessor.cpp
+++ b/gm/constcolorprocessor.cpp
@@ -13,7 +13,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrContext.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrPipelineBuilder.h"
 #include "SkGrPriv.h"
 #include "SkGradientShader.h"
@@ -118,7 +118,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(
                             GrRectBatchFactory::CreateNonAAFill(grPaint.getColor(), viewMatrix,
                                                                 renderRect, nullptr, nullptr));
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
 
                     // 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/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 4071159..57ee307 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -14,7 +14,7 @@
 
 #include "GrContext.h"
 #include "GrDefaultGeoProcFactory.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrPathUtils.h"
 #include "GrTest.h"
 #include "SkColorPriv.h"
@@ -205,7 +205,7 @@
 
                 SkAutoTUnref<GrDrawBatch> batch(ConvexPolyTestBatch::Create(gp, geometry));
 
-                drawContext->internal_drawBatch(pipelineBuilder, batch);
+                drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
 
                 x += SkScalarCeilToScalar(path->getBounds().width() + 10.f);
             }
@@ -252,7 +252,7 @@
 
                 SkAutoTUnref<GrDrawBatch> batch(ConvexPolyTestBatch::Create(gp, geometry));
 
-                drawContext->internal_drawBatch(pipelineBuilder, batch);
+                drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
 
                 x += SkScalarCeilToScalar(rect.width() + 10.f);
             }
diff --git a/gm/rrects.cpp b/gm/rrects.cpp
index 63d6c9e..e698e6b 100644
--- a/gm/rrects.cpp
+++ b/gm/rrects.cpp
@@ -8,7 +8,7 @@
 #include "gm.h"
 #if SK_SUPPORT_GPU
 #include "GrContext.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "batches/GrDrawBatch.h"
 #include "batches/GrRectBatchFactory.h"
 #include "effects/GrRRectEffect.h"
@@ -137,7 +137,8 @@
                             SkAutoTUnref<GrDrawBatch> batch(
                                     GrRectBatchFactory::CreateNonAAFill(0xff000000, SkMatrix::I(),
                                                                         bounds, nullptr, nullptr));
-                            drawContext->internal_drawBatch(pipelineBuilder, batch);
+                            drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder,
+                                                                                 batch);
                         } else {
                             drew = false;
                         }
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index 53316f7..72e40fe 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -12,7 +12,7 @@
 
 #if SK_SUPPORT_GPU
 
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrContext.h"
 #include "SkBitmap.h"
 #include "SkGr.h"
@@ -135,7 +135,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(
                             GrRectBatchFactory::CreateNonAAFill(GrColor_WHITE, viewMatrix,
                                                                 renderRect, nullptr, nullptr));
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
                     x += renderRect.width() + kTestPad;
                 }
                 y += renderRect.height() + kTestPad;
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index bf4094c..4aafb7a 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -13,7 +13,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrContext.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrPipelineBuilder.h"
 #include "SkBitmap.h"
 #include "SkGr.h"
@@ -132,7 +132,7 @@
                     SkAutoTUnref<GrDrawBatch> batch(
                             GrRectBatchFactory::CreateNonAAFill(GrColor_WHITE, viewMatrix,
                                                                 renderRect, nullptr, nullptr));
-                    drawContext->internal_drawBatch(pipelineBuilder, batch);
+                    drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
                 }
                 x += renderRect.width() + kTestPad;
             }
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index c20ef04..fd53da4 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -82,6 +82,7 @@
       '<(skia_src_path)/gpu/GrDefaultGeoProcFactory.cpp',
       '<(skia_src_path)/gpu/GrDefaultGeoProcFactory.h',
       '<(skia_src_path)/gpu/GrDrawContext.cpp',
+      '<(skia_src_path)/gpu/GrDrawContextPriv.h',
       '<(skia_src_path)/gpu/GrPathRenderingDrawContext.cpp',
       '<(skia_src_path)/gpu/GrPathRenderingDrawContext.h',
       '<(skia_src_path)/gpu/GrDrawingManager.cpp',
diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h
index cf6e65c..fd8b970 100644
--- a/include/gpu/GrClip.h
+++ b/include/gpu/GrClip.h
@@ -114,6 +114,13 @@
         }
     }
 
+    void setIRect(const SkIRect& irect) {
+        this->reset();
+        fClipType = kIRect_ClipType;
+        fOrigin.setZero();
+        fClip.fIRect = irect;
+    }
+
     const SkIRect& irect() const {
         SkASSERT(kIRect_ClipType == fClipType);
         return fClip.fIRect;
diff --git a/include/gpu/GrDrawContext.h b/include/gpu/GrDrawContext.h
index bde2f4a..1643cc9 100644
--- a/include/gpu/GrDrawContext.h
+++ b/include/gpu/GrDrawContext.h
@@ -11,6 +11,7 @@
 #include "GrColor.h"
 #include "GrRenderTarget.h"
 #include "SkRefCnt.h"
+#include "SkRegion.h"
 #include "SkSurfaceProps.h"
 #include "../private/GrSingleOwner.h"
 
@@ -19,6 +20,7 @@
 class GrClip;
 class GrContext;
 class GrDrawBatch;
+class GrDrawContextPriv;
 class GrDrawPathBatchBase;
 class GrDrawingManager;
 class GrDrawTarget;
@@ -277,9 +279,9 @@
 
     GrRenderTarget* accessRenderTarget() { return fRenderTarget; }
 
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Functions intended for internal use only.
-    void internal_drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch);
+    // Provides access to functions that aren't part of the public API.
+    GrDrawContextPriv drawContextPriv();
+    const GrDrawContextPriv drawContextPriv() const;
 
 protected:
     GrDrawContext(GrContext*, GrDrawingManager*, GrRenderTarget*,
@@ -295,6 +297,7 @@
 private:
     friend class GrAtlasTextBlob; // for access to drawBatch
     friend class GrDrawingManager; // for ctor
+    friend class GrDrawContextPriv;
 
     bool drawFilledDRRect(const GrClip& clip,
                           const GrPaint& paint,
@@ -302,6 +305,10 @@
                           const SkRRect& origOuter,
                           const SkRRect& origInner);
 
+    GrDrawBatch* getFillRectBatch(const GrPaint& paint,
+                                  const SkMatrix& viewMatrix,
+                                  const SkRect& rect);
+
     void internalDrawPath(const GrClip& clip,
                           const GrPaint& paint,
                           const SkMatrix& viewMatrix,
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 3168424..70c65ed 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -8,7 +8,7 @@
 #include "GrClipMaskManager.h"
 #include "GrCaps.h"
 #include "GrDrawingManager.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrDrawTarget.h"
 #include "GrGpuResourcePriv.h"
 #include "GrPaint.h"
@@ -159,7 +159,8 @@
  * will be used on any element. If so, it returns true to indicate that the
  * entire clip should be rendered in SW and then uploaded en masse to the gpu.
  */
-bool GrClipMaskManager::useSWOnlyPath(const GrPipelineBuilder& pipelineBuilder,
+bool GrClipMaskManager::UseSWOnlyPath(GrContext* context,
+                                      const GrPipelineBuilder& pipelineBuilder,
                                       const GrRenderTarget* rt,
                                       const SkVector& clipToMaskOffset,
                                       const GrReducedClip::ElementList& elements) {
@@ -179,7 +180,7 @@
         bool needsStencil = invert || 
                             SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op;
 
-        if (PathNeedsSWRenderer(this->getContext(), pipelineBuilder.getStencil().isDisabled(),
+        if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled(),
                                 rt, translate, element, nullptr, needsStencil)) {
             return true;
         }
@@ -316,6 +317,42 @@
     }
 }
 
+bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
+                                         GrPipelineBuilder::AutoRestoreStencil* ars,
+                                         const SkIRect& clipScissor,
+                                         const SkRect* devBounds,
+                                         GrAppliedClip* out) {
+    if (kRespectClip_StencilClipMode == fClipMode) {
+        fClipMode = kIgnoreClip_StencilClipMode;
+    }
+
+    GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
+
+    SkIRect clipSpaceRTIBounds = SkIRect::MakeWH(rt->width(), rt->height());
+    SkIRect devBoundsScissor;
+    const SkIRect* scissor = &clipScissor;
+    bool doDevBoundsClip = fDebugClipBatchToBounds && devBounds;
+    if (doDevBoundsClip) {
+        devBounds->roundOut(&devBoundsScissor);
+        if (devBoundsScissor.intersect(clipScissor)) {
+            scissor = &devBoundsScissor;
+        }
+    }
+
+    if (scissor->contains(clipSpaceRTIBounds)) {
+        // This counts as wide open
+        this->setPipelineBuilderStencil(pipelineBuilder, ars);
+        return true;
+    }
+
+    if (clipSpaceRTIBounds.intersect(*scissor)) {
+        out->fScissorState.set(clipSpaceRTIBounds);
+        this->setPipelineBuilderStencil(pipelineBuilder, ars);
+        return true;
+    }
+    return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // sort out what kind of clip mask needs to be created: alpha, stencil,
 // scissor, or entirely software
@@ -439,21 +476,23 @@
             SkIntToScalar(-clipSpaceIBounds.fTop)
         };
 
-        if (this->useSWOnlyPath(pipelineBuilder, rt, clipToMaskOffset, elements)) {
+        if (UseSWOnlyPath(this->getContext(), pipelineBuilder, rt, clipToMaskOffset, elements)) {
             // The clip geometry is complex enough that it will be more efficient to create it
             // entirely in software
-            result.reset(this->createSoftwareClipMask(genID,
-                                                      initialState,
-                                                      elements,
-                                                      clipToMaskOffset,
-                                                      clipSpaceIBounds));
+            result.reset(CreateSoftwareClipMask(this->getContext(),
+                                                genID,
+                                                initialState,
+                                                elements,
+                                                clipToMaskOffset,
+                                                clipSpaceIBounds));
         } else {
-            result.reset(this->createAlphaClipMask(genID,
-                                                   initialState,
-                                                   elements,
-                                                   clipToMaskOffset,
-                                                   clipSpaceIBounds));
-            // If createAlphaClipMask fails it means useSWOnlyPath has a bug
+            result.reset(CreateAlphaClipMask(this->getContext(),
+                                             genID,
+                                             initialState,
+                                             elements,
+                                             clipToMaskOffset,
+                                             clipSpaceIBounds));
+            // If createAlphaClipMask fails it means UseSWOnlyPath has a bug
             SkASSERT(result);
         }
 
@@ -488,93 +527,67 @@
     return true;
 }
 
-namespace {
-////////////////////////////////////////////////////////////////////////////////
-// Set a coverage drawing XPF on the pipelineBuilder for the given op and invertCoverage mode
-void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage,
-                              GrPipelineBuilder* pipelineBuilder) {
-    SkASSERT(op <= SkRegion::kLastOp);
-    pipelineBuilder->setCoverageSetOpXPFactory(op, invertCoverage);
-}
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder,
-                                    const SkMatrix& viewMatrix,
-                                    GrTexture* target,
-                                    const SkClipStack::Element* element,
-                                    GrPathRenderer* pr) {
-
-    GrRenderTarget* rt = target->asRenderTarget();
-    pipelineBuilder->setRenderTarget(rt);
-
-    // The color we use to draw does not matter since we will always be using a GrCoverageSetOpXP
-    // which ignores color.
-    GrColor color = GrColor_WHITE;
+static bool stencil_element(GrDrawContext* dc,
+                            const SkIRect* scissorRect,
+                            const GrStencilSettings& ss,
+                            const SkMatrix& viewMatrix,
+                            const SkClipStack::Element* element) {
 
     // TODO: Draw rrects directly here.
     switch (element->getType()) {
         case Element::kEmpty_Type:
             SkDEBUGFAIL("Should never get here with an empty element.");
             break;
-        case Element::kRect_Type: {
-            // TODO: Do rects directly to the accumulator using a aa-rect GrProcessor that covers
-            // the entire mask bounds and writes 0 outside the rect.
-            if (element->isAA()) {
-                SkRect devRect = element->getRect();
-                viewMatrix.mapRect(&devRect);
-
-                SkAutoTUnref<GrDrawBatch> batch(
-                        GrRectBatchFactory::CreateAAFill(color, viewMatrix, element->getRect(),
-                                                         devRect));
-
-                fDrawTarget->drawBatch(*pipelineBuilder, batch);
-            } else {
-                draw_non_aa_rect(fDrawTarget, *pipelineBuilder, color, viewMatrix,
-                                 element->getRect());
-            }
-            return true;
-        }
+        case Element::kRect_Type:
+            return dc->drawContextPriv().drawAndStencilRect(scissorRect, ss,
+                                                            element->getOp(),
+                                                            element->isInverseFilled(),
+                                                            element->isAA(),
+                                                            viewMatrix, element->getRect());
+            break;
         default: {
             SkPath path;
             element->asPath(&path);
             if (path.isInverseFillType()) {
                 path.toggleInverseFillType();
             }
-            GrStrokeInfo stroke(SkStrokeRec::kFill_InitStyle);
-            if (nullptr == pr) {
-                GrPathRendererChain::DrawType type;
-                type = element->isAA() ? GrPathRendererChain::kColorAntiAlias_DrawType :
-                                         GrPathRendererChain::kColor_DrawType;
 
-                GrPathRenderer::CanDrawPathArgs canDrawArgs;
-                canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
-                canDrawArgs.fViewMatrix = &viewMatrix;
-                canDrawArgs.fPath = &path;
-                canDrawArgs.fStroke = &stroke;
-                canDrawArgs.fAntiAlias = element->isAA();;
-                canDrawArgs.fIsStencilDisabled = pipelineBuilder->getStencil().isDisabled();
-                canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
-
-                pr = this->getContext()->drawingManager()->getPathRenderer(canDrawArgs, false, type);
-            }
-            if (nullptr == pr) {
-                return false;
-            }
-            GrPathRenderer::DrawPathArgs args;
-            args.fTarget = fDrawTarget;
-            args.fResourceProvider = this->getContext()->resourceProvider();
-            args.fPipelineBuilder = pipelineBuilder;
-            args.fColor = color;
-            args.fViewMatrix = &viewMatrix;
-            args.fPath = &path;
-            args.fStroke = &stroke;
-            args.fAntiAlias = element->isAA();
-            pr->drawPath(args);
+            return dc->drawContextPriv().drawAndStencilPath(scissorRect, ss,
+                                                            element->getOp(),
+                                                            element->isInverseFilled(),
+                                                            element->isAA(), viewMatrix, path);
             break;
         }
     }
-    return true;
+
+    return false;
+}
+
+static void draw_element(GrDrawContext* dc,
+                         const GrClip& clip, // TODO: can this just always be WideOpen?
+                         const GrPaint &paint,
+                         const SkMatrix& viewMatrix,
+                         const SkClipStack::Element* element) {
+
+    // TODO: Draw rrects directly here.
+    switch (element->getType()) {
+        case Element::kEmpty_Type:
+            SkDEBUGFAIL("Should never get here with an empty element.");
+            break;
+        case Element::kRect_Type:
+            dc->drawRect(clip, paint, viewMatrix, element->getRect());
+            break;
+        default: {
+            SkPath path;
+            element->asPath(&path);
+            if (path.isInverseFillType()) {
+                path.toggleInverseFillType();
+            }
+
+            dc->drawPath(clip, paint, viewMatrix, path, GrStrokeInfo::FillInfo());
+            break;
+        }
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -588,32 +601,13 @@
     builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16);
 }
 
-GrTexture* GrClipMaskManager::createCachedMask(int width, int height, const GrUniqueKey& key,
-                                               bool renderTarget) {
-    GrSurfaceDesc desc;
-    desc.fWidth = width;
-    desc.fHeight = height;
-    desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
-    if (!renderTarget || this->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
-        desc.fConfig = kAlpha_8_GrPixelConfig;
-    } else {
-        desc.fConfig = kRGBA_8888_GrPixelConfig;
-    }
-
-    GrTexture* texture = this->resourceProvider()->createApproxTexture(desc, 0);
-    if (!texture) {
-        return nullptr;
-    }
-    texture->resourcePriv().setUniqueKey(key);
-    return texture;
-}
-
-GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID,
+GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context,
+                                                  int32_t elementsGenID,
                                                   GrReducedClip::InitialState initialState,
                                                   const GrReducedClip::ElementList& elements,
                                                   const SkVector& clipToMaskOffset,
                                                   const SkIRect& clipSpaceIBounds) {
-    GrResourceProvider* resourceProvider = this->resourceProvider();
+    GrResourceProvider* resourceProvider = context->resourceProvider();
     GrUniqueKey key;
     GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
     if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
@@ -621,15 +615,27 @@
     }
 
     // There's no texture in the cache. Let's try to allocate it then.
-    SkAutoTUnref<GrTexture> texture(this->createCachedMask(
-        clipSpaceIBounds.width(), clipSpaceIBounds.height(), key, true));
+    GrSurfaceDesc desc;
+    desc.fWidth = clipSpaceIBounds.width();
+    desc.fHeight = clipSpaceIBounds.height();
+    desc.fFlags = kRenderTarget_GrSurfaceFlag;
+    if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
+        desc.fConfig = kAlpha_8_GrPixelConfig;
+    } else {
+        desc.fConfig = kRGBA_8888_GrPixelConfig;
+    }
+
+    SkAutoTUnref<GrTexture> texture(resourceProvider->createApproxTexture(desc, 0));
     if (!texture) {
         return nullptr;
     }
 
-    // Set the matrix so that rendered clip elements are transformed to mask space from clip
-    // space.
-    const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY);
+    texture->resourcePriv().setUniqueKey(key);
+
+    SkAutoTUnref<GrDrawContext> dc(context->drawContext(texture->asRenderTarget()));
+    if (!dc) {
+        return nullptr;
+    }
 
     // The texture may be larger than necessary, this rect represents the part of the texture
     // we populate with a rasterization of the clip.
@@ -637,16 +643,18 @@
 
     // The scratch texture that we are drawing into can be substantially larger than the mask. Only
     // clear the part that we care about.
-    fDrawTarget->clear(&maskSpaceIBounds,
-                       GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
-                       true,
-                       texture->asRenderTarget());
+    dc->clear(&maskSpaceIBounds,
+              GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff : 0x00000000,
+              true);
 
-    // When we use the stencil in the below loop it is important to have this clip installed.
+    // Set the matrix so that rendered clip elements are transformed to mask space from clip
+    // space.
+    const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMaskOffset.fY);
+
+    // It is important that we use maskSpaceIBounds as the stencil rect in the below loop.
     // The second pass that zeros the stencil buffer renders the rect maskSpaceIBounds so the first
     // pass must not set values outside of this bounds or stencil values outside the rect won't be
     // cleared.
-    const GrClip clip(maskSpaceIBounds);
 
     // walk through each clip element and perform its set op
     for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get(); iter.next()) {
@@ -654,68 +662,54 @@
         SkRegion::Op op = element->getOp();
         bool invert = element->isInverseFilled();
         if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
-
-            GrPathRenderer* pr = GetPathRenderer(this->getContext(),
+#ifdef SK_DEBUG
+            GrPathRenderer* pr = GetPathRenderer(context,
                                                  texture, translate, element);
             if (Element::kRect_Type != element->getType() && !pr) {
-                // useSWOnlyPath should now filter out all cases where gpu-side mask merging would
-                // be performed (i.e., pr would be NULL for a non-rect path). See https://bug.skia.org/4519
-                // for rationale and details.
+                // UseSWOnlyPath should now filter out all cases where gpu-side mask merging would
+                // be performed (i.e., pr would be NULL for a non-rect path).
+                // See https://bug.skia.org/4519 for rationale and details.
                 SkASSERT(0);
-                continue;
+            }
+#endif
+
+            // draw directly into the result with the stencil set to make the pixels affected
+            // by the clip shape be non-zero.
+            GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
+                                         kReplace_StencilOp,
+                                         kReplace_StencilOp,
+                                         kAlways_StencilFunc,
+                                         0xffff,
+                                         0xffff,
+                                         0xffff)
+            if (!stencil_element(dc, &maskSpaceIBounds, kStencilInElement,
+                                 translate, element)) {
+                texture->resourcePriv().removeUniqueKey();
+                return nullptr;
             }
 
-            {
-                GrPipelineBuilder pipelineBuilder;
-
-                pipelineBuilder.setClip(clip);
-                pipelineBuilder.setRenderTarget(texture->asRenderTarget());
-                SkASSERT(pipelineBuilder.getStencil().isDisabled());
-
-                // draw directly into the result with the stencil set to make the pixels affected
-                // by the clip shape be non-zero.
-                GR_STATIC_CONST_SAME_STENCIL(kStencilInElement,
-                                             kReplace_StencilOp,
-                                             kReplace_StencilOp,
-                                             kAlways_StencilFunc,
-                                             0xffff,
-                                             0xffff,
-                                             0xffff);
-                pipelineBuilder.setStencil(kStencilInElement);
-                set_coverage_drawing_xpf(op, invert, &pipelineBuilder);
-
-                if (!this->drawElement(&pipelineBuilder, translate, texture, element, pr)) {
-                    texture->resourcePriv().removeUniqueKey();
-                    return nullptr;
-                }
-            }
-
-            {
-                GrPipelineBuilder backgroundPipelineBuilder;
-                backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarget());
-
-                set_coverage_drawing_xpf(op, !invert, &backgroundPipelineBuilder);
-                // Draw to the exterior pixels (those with a zero stencil value).
-                GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
-                                             kZero_StencilOp,
-                                             kZero_StencilOp,
-                                             kEqual_StencilFunc,
-                                             0xffff,
-                                             0x0000,
-                                             0xffff);
-                backgroundPipelineBuilder.setStencil(kDrawOutsideElement);
-
-                // The color passed in here does not matter since the coverageSetOpXP won't read it.
-                draw_non_aa_rect(fDrawTarget, backgroundPipelineBuilder, GrColor_WHITE, translate,
-                                 SkRect::Make(clipSpaceIBounds));
+            // Draw to the exterior pixels (those with a zero stencil value).
+            GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement,
+                                         kZero_StencilOp,
+                                         kZero_StencilOp,
+                                         kEqual_StencilFunc,
+                                         0xffff,
+                                         0x0000,
+                                         0xffff);
+            if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, kDrawOutsideElement,
+                                                          op, !invert, false,
+                                                          translate,
+                                                          SkRect::Make(clipSpaceIBounds))) {
+                texture->resourcePriv().removeUniqueKey();
+                return nullptr;
             }
         } else {
-            GrPipelineBuilder pipelineBuilder;
-
             // all the remaining ops can just be directly draw into the accumulation buffer
-            set_coverage_drawing_xpf(op, false, &pipelineBuilder);
-            // The color passed in here does not matter since the coverageSetOpXP won't read it.
-            this->drawElement(&pipelineBuilder, translate, texture, element);
+            GrPaint paint;
+            paint.setAntiAlias(element->isAA());
+            paint.setCoverageSetOpXPFactory(op, false);
+
+            draw_element(dc, GrClip::WideOpen(), paint, translate, element);
         }
     }
 
@@ -1081,14 +1075,15 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID,
+GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
+                                                     int32_t elementsGenID,
                                                      GrReducedClip::InitialState initialState,
                                                      const GrReducedClip::ElementList& elements,
                                                      const SkVector& clipToMaskOffset,
                                                      const SkIRect& clipSpaceIBounds) {
     GrUniqueKey key;
     GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key);
-    GrResourceProvider* resourceProvider = this->resourceProvider();
+    GrResourceProvider* resourceProvider = context->resourceProvider();
     if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) {
         return texture;
     }
@@ -1097,7 +1092,7 @@
     // the top left corner of the resulting rect to the top left of the texture.
     SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpaceIBounds.height());
 
-    GrSWMaskHelper helper(this->getContext());
+    GrSWMaskHelper helper(context);
 
     // Set the matrix so that rendered clip elements are transformed to mask space from clip
     // space.
@@ -1141,11 +1136,17 @@
     }
 
     // Allocate clip mask texture
-    GrTexture* result = this->createCachedMask(clipSpaceIBounds.width(), clipSpaceIBounds.height(),
-                                               key, false);
-    if (nullptr == result) {
+    GrSurfaceDesc desc;
+    desc.fWidth = clipSpaceIBounds.width();
+    desc.fHeight = clipSpaceIBounds.height();
+    desc.fConfig = kAlpha_8_GrPixelConfig;
+
+    GrTexture* result = context->resourceProvider()->createApproxTexture(desc, 0);
+    if (!result) {
         return nullptr;
     }
+    result->resourcePriv().setUniqueKey(key);
+
     helper.toTexture(result);
 
     return result;
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 6b9b727..3635454 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -69,6 +69,12 @@
                        const SkRect* devBounds,
                        GrAppliedClip*);
 
+    bool setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
+                          GrPipelineBuilder::AutoRestoreStencil* ars,
+                          const SkIRect& scissor,    
+                          const SkRect* devBounds,
+                          GrAppliedClip* out);
+
     void adjustPathStencilParams(const GrStencilAttachment*, GrStencilSettings*);
 
 private:
@@ -123,32 +129,26 @@
 
     // Creates an alpha mask of the clip. The mask is a rasterization of elements through the
     // rect specified by clipSpaceIBounds.
-    GrTexture* createAlphaClipMask(int32_t elementsGenID,
-                                   GrReducedClip::InitialState initialState,
-                                   const GrReducedClip::ElementList& elements,
-                                   const SkVector& clipToMaskOffset,
-                                   const SkIRect& clipSpaceIBounds);
+    static GrTexture* CreateAlphaClipMask(GrContext*,
+                                          int32_t elementsGenID,
+                                          GrReducedClip::InitialState initialState,
+                                          const GrReducedClip::ElementList& elements,
+                                          const SkVector& clipToMaskOffset,
+                                          const SkIRect& clipSpaceIBounds);
 
     // Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture.
-    GrTexture* createSoftwareClipMask(int32_t elementsGenID,
-                                      GrReducedClip::InitialState initialState,
-                                      const GrReducedClip::ElementList& elements,
-                                      const SkVector& clipToMaskOffset,
-                                      const SkIRect& clipSpaceIBounds);
+    static GrTexture* CreateSoftwareClipMask(GrContext*,
+                                             int32_t elementsGenID,
+                                             GrReducedClip::InitialState initialState,
+                                             const GrReducedClip::ElementList& elements,
+                                             const SkVector& clipToMaskOffset,
+                                             const SkIRect& clipSpaceIBounds);
 
-   bool useSWOnlyPath(const GrPipelineBuilder&,
-                      const GrRenderTarget* rt,
-                      const SkVector& clipToMaskOffset,
-                      const GrReducedClip::ElementList& elements);
-
-    // Draws a clip element into the target alpha mask. The caller should have already setup the
-    // desired blend operation. Optionally if the caller already selected a path renderer it can
-    // be passed. Otherwise the function will select one if the element is a path.
-    bool drawElement(GrPipelineBuilder*,
-                     const SkMatrix& viewMatrix,
-                     GrTexture* target,
-                     const SkClipStack::Element*,
-                     GrPathRenderer* pr = nullptr);
+   static bool UseSWOnlyPath(GrContext*,
+                             const GrPipelineBuilder&,
+                             const GrRenderTarget* rt,
+                             const SkVector& clipToMaskOffset,
+                             const GrReducedClip::ElementList& elements);
 
     /**
      * Called prior to return control back the GrGpu in setupClipping. It updates the
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index 628b4b2..43ef760 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -9,6 +9,7 @@
 #include "GrBatchTest.h"
 #include "GrColor.h"
 #include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrDrawingManager.h"
 #include "GrOvalRenderer.h"
 #include "GrPathRenderer.h"
@@ -33,8 +34,11 @@
 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext())
 #define ASSERT_SINGLE_OWNER \
     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
+#define ASSERT_SINGLE_OWNER_PRIV \
+    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fDrawContext->fSingleOwner);)
 #define RETURN_IF_ABANDONED        if (fDrawingManager->abandoned()) { return; }
 #define RETURN_FALSE_IF_ABANDONED  if (fDrawingManager->abandoned()) { return false; }
+#define RETURN_FALSE_IF_ABANDONED_PRIV  if (fDrawContext->fDrawingManager->abandoned()) { return false; }
 #define RETURN_NULL_IF_ABANDONED   if (fDrawingManager->abandoned()) { return nullptr; }
 
 class AutoCheckFlush {
@@ -250,6 +254,28 @@
     return paint.isAntiAlias() && !rt->isUnifiedMultisampled();
 }
 
+GrDrawBatch* GrDrawContext::getFillRectBatch(const GrPaint& paint,
+                                             const SkMatrix& viewMatrix,
+                                             const SkRect& rect) {
+
+    GrDrawBatch* batch = nullptr;
+    if (should_apply_coverage_aa(paint, fRenderTarget)) {
+        // The fill path can handle rotation but not skew.
+        if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
+            SkRect devBoundRect;
+            viewMatrix.mapRect(&devBoundRect, rect);
+            batch = GrRectBatchFactory::CreateAAFill(paint.getColor(), viewMatrix,
+                                                     rect, devBoundRect);
+        }
+    } else {
+        // filled BW rect
+        batch = GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rect,
+                                                    nullptr, nullptr);        
+    }
+
+    return batch;
+}
+
 void GrDrawContext::drawRect(const GrClip& clip,
                              const GrPaint& paint,
                              const SkMatrix& viewMatrix,
@@ -303,35 +329,28 @@
 
     bool snapToPixelCenters = false;
     SkAutoTUnref<GrDrawBatch> batch;
-    if (should_apply_coverage_aa(paint, fRenderTarget)) {
-        if (width >= 0) {
+    if (width < 0) {
+        batch.reset(this->getFillRectBatch(paint, viewMatrix, rect));
+    } else {
+        GrColor color = paint.getColor();
+
+        if (should_apply_coverage_aa(paint, fRenderTarget)) {
             // The stroke path needs the rect to remain axis aligned (no rotation or skew).
             if (viewMatrix.rectStaysRect()) {
-                batch.reset(GrRectBatchFactory::CreateAAStroke(paint.getColor(), viewMatrix, rect,
+                batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect,
                                                                *strokeInfo));
             }
         } else {
-            // The fill path can handle rotation but not skew.
-            if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
-                SkRect devBoundRect;
-                viewMatrix.mapRect(&devBoundRect, rect);
-                batch.reset(GrRectBatchFactory::CreateAAFill(paint.getColor(), viewMatrix, rect,
-                                                             devBoundRect));
-            }
-        }
-    } else if (width >= 0) {
-        // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
-        snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled());
-        batch.reset(GrRectBatchFactory::CreateNonAAStroke(paint.getColor(), viewMatrix, rect,
-                                                          width, snapToPixelCenters));
+            // Non-AA hairlines are snapped to pixel centers to make which pixels are hit
+            // deterministic
+            snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled());
+            batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect,
+                                                              width, snapToPixelCenters));
 
-        // 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.
-    } else {
-        // filled BW rect
-        batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rect,
-                                                        nullptr, nullptr));
+            // 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 (batch) {
@@ -353,6 +372,39 @@
                            strokeInfo ? *strokeInfo : GrStrokeInfo::FillInfo());
 }
 
+bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
+                                           const GrStencilSettings& ss,
+                                           SkRegion::Op op,
+                                           bool invert,
+                                           bool doAA,
+                                           const SkMatrix& viewMatrix,
+                                           const SkRect& rect) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_FALSE_IF_ABANDONED_PRIV
+    SkDEBUGCODE(fDrawContext->validate();)
+    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::stencilRect");
+
+    AutoCheckFlush acf(fDrawContext->fDrawingManager);
+
+    GrPaint paint;
+    paint.setAntiAlias(doAA);
+    paint.setCoverageSetOpXPFactory(op, invert);
+
+    SkAutoTUnref<GrDrawBatch> batch(fDrawContext->getFillRectBatch(paint, viewMatrix, rect));
+    if (batch) {
+        GrPipelineBuilder pipelineBuilder(paint, fDrawContext->fRenderTarget, GrClip::WideOpen());
+        pipelineBuilder.setStencil(ss);
+
+        fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, batch, scissorRect);
+        return true;
+    }
+
+    SkPath path;
+    path.setIsVolatile(true);
+    path.addRect(rect);
+    return this->drawAndStencilPath(scissorRect, ss, op, invert, doAA, viewMatrix, path);
+}
+
 void GrDrawContext::fillRectToRect(const GrClip& clip,
                                    const GrPaint& paint,
                                    const SkMatrix& viewMatrix,
@@ -801,6 +853,80 @@
     this->internalDrawPath(clip, paint, viewMatrix, path, strokeInfo);
 }
 
+bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
+                                           const GrStencilSettings& ss,
+                                           SkRegion::Op op,
+                                           bool invert,
+                                           bool doAA,
+                                           const SkMatrix& viewMatrix,
+                                           const SkPath& path) {
+    ASSERT_SINGLE_OWNER_PRIV
+    RETURN_FALSE_IF_ABANDONED_PRIV
+    SkDEBUGCODE(fDrawContext->validate();)
+    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPath");
+
+    if (path.isEmpty() && path.isInverseFillType()) {
+        this->drawAndStencilRect(scissorRect, ss, op, invert, false, SkMatrix::I(), 
+                                 SkRect::MakeIWH(fDrawContext->fRenderTarget->width(), 
+                                                 fDrawContext->fRenderTarget->height()));
+        return true;
+    }
+
+    AutoCheckFlush acf(fDrawContext->fDrawingManager);
+
+    // An Assumption here is that path renderer would use some form of tweaking
+    // the src color (either the input alpha or in the frag shader) to implement
+    // aa. If we have some future driver-mojo path AA that can do the right
+    // thing WRT to the blend then we'll need some query on the PR.
+    bool useCoverageAA = doAA && !fDrawContext->fRenderTarget->isUnifiedMultisampled();
+    bool isStencilDisabled = true;
+    bool isStencilBufferMSAA = fDrawContext->fRenderTarget->isStencilBufferMultisampled();
+
+    const GrPathRendererChain::DrawType type =
+        useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
+                      : GrPathRendererChain::kColor_DrawType;
+
+    GrPathRenderer::CanDrawPathArgs canDrawArgs;
+    canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps();
+    canDrawArgs.fViewMatrix = &viewMatrix;
+    canDrawArgs.fPath = &path;
+    canDrawArgs.fStroke = &GrStrokeInfo::FillInfo();
+    canDrawArgs.fAntiAlias = useCoverageAA;
+    canDrawArgs.fIsStencilDisabled = isStencilDisabled;
+    canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
+
+    // Don't allow the SW renderer
+    GrPathRenderer* pr = fDrawContext->fDrawingManager->getPathRenderer(canDrawArgs, false, type);
+    if (!pr) {
+        return false;
+    }
+
+    GrPaint paint;
+    paint.setCoverageSetOpXPFactory(op, invert);
+
+    // TODO: it is unfortunate that we have to convert this to a GrClip to
+    // call drawPath.
+    GrClip clip;
+    if (scissorRect) {
+        clip.setIRect(*scissorRect);
+    }
+
+    GrPipelineBuilder pipelineBuilder(paint, fDrawContext->fRenderTarget, clip);
+    pipelineBuilder.setStencil(ss);
+
+    GrPathRenderer::DrawPathArgs args;
+    args.fTarget = fDrawContext->getDrawTarget();
+    args.fResourceProvider = fDrawContext->fDrawingManager->getContext()->resourceProvider();
+    args.fPipelineBuilder = &pipelineBuilder;
+    args.fColor = GrColor_WHITE;
+    args.fViewMatrix = &viewMatrix;
+    args.fPath = &path;
+    args.fStroke = &GrStrokeInfo::FillInfo();
+    args.fAntiAlias = useCoverageAA;
+    pr->drawPath(args);
+    return true;
+}
+
 void GrDrawContext::internalDrawPath(const GrClip& clip,
                                      const GrPaint& paint,
                                      const SkMatrix& viewMatrix,
diff --git a/src/gpu/GrDrawContextPriv.h b/src/gpu/GrDrawContextPriv.h
new file mode 100644
index 0000000..935b631
--- /dev/null
+++ b/src/gpu/GrDrawContextPriv.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDrawContextPriv_DEFINED
+#define GrDrawContextPriv_DEFINED
+
+#include "GrDrawContext.h"
+
+class GrStencilSettings;
+
+/** Class that adds methods to GrDrawContext that are only intended for use internal to Skia.
+    This class is purely a privileged window into GrDrawContext. It should never have additional
+    data members or virtual methods. */
+class GrDrawContextPriv {
+public:
+    bool drawAndStencilRect(const SkIRect* scissorRect,
+                            const GrStencilSettings&,
+                            SkRegion::Op op,
+                            bool invert,
+                            bool doAA,
+                            const SkMatrix& viewMatrix,
+                            const SkRect&);
+
+    bool drawAndStencilPath(const SkIRect* scissorRect,
+                            const GrStencilSettings&,
+                            SkRegion::Op op,
+                            bool invert,
+                            bool doAA,
+                            const SkMatrix& viewMatrix,
+                            const SkPath&);
+
+    void testingOnly_drawBatch(const GrPipelineBuilder& pipelineBuilder,
+                               GrDrawBatch* batch);
+
+private:
+    explicit GrDrawContextPriv(GrDrawContext* drawContext) : fDrawContext(drawContext) {}
+    GrDrawContextPriv(const GrRenderTargetPriv&) {} // unimpl
+    GrDrawContextPriv& operator=(const GrRenderTargetPriv&); // unimpl
+
+    // No taking addresses of this type.
+    const GrDrawContextPriv* operator&() const;
+    GrDrawContextPriv* operator&();
+
+    GrDrawContext* fDrawContext;
+        
+    friend class GrDrawContext; // to construct/copy this type.
+};
+
+inline GrDrawContextPriv GrDrawContext::drawContextPriv() { return GrDrawContextPriv(this); }
+
+inline const GrDrawContextPriv GrDrawContext::drawContextPriv () const {
+    return GrDrawContextPriv(const_cast<GrDrawContext*>(this));
+}
+
+#endif
+
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 173617e..fc8c71b 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -221,13 +221,25 @@
     fBatches.reset();
 }
 
-void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder, GrDrawBatch* batch) {
+void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
+                             GrDrawBatch* batch,
+                             const SkIRect* scissorRect) {
     // Setup clip
     GrPipelineBuilder::AutoRestoreStencil ars;
     GrAppliedClip clip;
-    if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
-        return;
+
+    if (scissorRect) {
+        SkASSERT(GrClip::kWideOpen_ClipType == pipelineBuilder.clip().clipType());
+        if (!fClipMaskManager->setupScissorClip(pipelineBuilder, &ars, *scissorRect,
+                                                &batch->bounds(), &clip)) {
+            return;
+        }
+    } else {
+        if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
+            return;
+        }
     }
+
     GrPipelineBuilder::AutoRestoreFragmentProcessorState arfps;
     if (clip.clipCoverageFragmentProcessor()) {
         arfps.set(&pipelineBuilder);
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index a850efd..8b30ab9 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -101,7 +101,7 @@
      */
     const GrCaps* caps() const { return fGpu->caps(); }
 
-    void drawBatch(const GrPipelineBuilder&, GrDrawBatch*);
+    void drawBatch(const GrPipelineBuilder&, GrDrawBatch*, const SkIRect* scissorRect = nullptr);
 
     /**
      * Draws path into the stencil buffer. The fill must be either even/odd or
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index f5fe9f8..f66ced3 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -155,14 +155,6 @@
     }
 
     /**
-     * Sets a GrXPFactory that will ignore src color and perform a set operation between the draws
-     * output coverage and the destination. This is useful to render coverage masks as CSG.
-     */
-    void setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage = false) {
-        fXPFactory.reset(GrCoverageSetOpXPFactory::Create(regionOp, invertCoverage));
-    }
-
-    /**
      * Sets a GrXPFactory that disables color writes to the destination. This is useful when
      * rendering to the stencil buffer.
      */
diff --git a/src/gpu/GrTest.cpp b/src/gpu/GrTest.cpp
index 9a37f2b..56037d1 100644
--- a/src/gpu/GrTest.cpp
+++ b/src/gpu/GrTest.cpp
@@ -9,7 +9,7 @@
 
 #include "GrBatchAtlas.h"
 #include "GrContextOptions.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrDrawingManager.h"
 #include "GrGpuResourceCacheAccess.h"
 #include "GrResourceCache.h"
@@ -258,17 +258,17 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #define ASSERT_SINGLE_OWNER \
-    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
-#define RETURN_IF_ABANDONED        if (fDrawingManager->abandoned()) { return; }
+    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fDrawContext->fSingleOwner);)
+#define RETURN_IF_ABANDONED        if (fDrawContext->fDrawingManager->abandoned()) { return; }
 
-void GrDrawContext::internal_drawBatch(const GrPipelineBuilder& pipelineBuilder,
-                                       GrDrawBatch* batch) {
+void GrDrawContextPriv::testingOnly_drawBatch(const GrPipelineBuilder& pipelineBuilder,
+                                              GrDrawBatch* batch) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
-    SkDEBUGCODE(this->validate();)
-    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::internal_drawBatch");
+    SkDEBUGCODE(fDrawContext->validate();)
+    GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::testingOnly_drawBatch");
 
-    this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
+    fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, batch);
 }
 
 #undef ASSERT_SINGLE_OWNER
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 7440608..6b8efeb 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -15,7 +15,7 @@
 #include "GrAutoLocaleSetter.h"
 #include "GrBatchTest.h"
 #include "GrContextFactory.h"
-#include "GrDrawContext.h"
+#include "GrDrawContextPriv.h"
 #include "GrDrawingManager.h"
 #include "GrInvariantOutput.h"
 #include "GrPipeline.h"
@@ -361,7 +361,7 @@
             return false;
         }
 
-        drawContext->internal_drawBatch(pipelineBuilder, batch);
+        drawContext->drawContextPriv().testingOnly_drawBatch(pipelineBuilder, batch);
     }
     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
     drawingManager->flush();
@@ -398,7 +398,7 @@
                 return false;
             }
 
-            drawContext->internal_drawBatch(builder, batch);
+            drawContext->drawContextPriv().testingOnly_drawBatch(builder, batch);
             drawingManager->flush();
         }
     }