| Index: src/gpu/GrClipMaskManager.cpp | 
| diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp | 
| index ff00a94f5aaebee244e3269da47199ff454a05c7..caf0cbdff9194c0b18029027200db1ef2b3286ef 100644 | 
| --- a/src/gpu/GrClipMaskManager.cpp | 
| +++ b/src/gpu/GrClipMaskManager.cpp | 
| @@ -99,21 +99,14 @@ static bool path_needs_SW_renderer(GrContext* context, | 
| // Determines whether it is possible to draw the element to both the stencil buffer and the | 
| // alpha mask simultaneously. If so and the element is a path a compatible path renderer is | 
| // also returned. | 
| -static bool can_stencil_and_draw_element(GrContext* context, | 
| +static GrPathRenderer* get_path_renderer(GrContext* context, | 
| GrPipelineBuilder* pipelineBuilder, | 
| -                                         GrTexture* texture, | 
| const SkMatrix& viewMatrix, | 
| -                                         const SkClipStack::Element* element, | 
| -                                         GrPathRenderer** pr) { | 
| -    pipelineBuilder->setRenderTarget(texture->asRenderTarget()); | 
| - | 
| +                                         const SkClipStack::Element* element) { | 
| +    GrPathRenderer* pr; | 
| static const bool kNeedsStencil = true; | 
| -    return !path_needs_SW_renderer(context, | 
| -                                   *pipelineBuilder, | 
| -                                   viewMatrix, | 
| -                                   element, | 
| -                                   pr, | 
| -                                   kNeedsStencil); | 
| +    path_needs_SW_renderer(context, *pipelineBuilder, viewMatrix, element, &pr, kNeedsStencil); | 
| +    return pr; | 
| } | 
|  | 
| GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) | 
| @@ -121,8 +114,17 @@ GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) | 
| , fClipMode(kIgnoreClip_StencilClipMode) { | 
| } | 
|  | 
| -GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().context(); } | 
| +GrContext* GrClipMaskManager::getContext() { | 
| +    return fDrawTarget->cmmAccess().context(); | 
| +} | 
|  | 
| +const GrCaps* GrClipMaskManager::caps() const { | 
| +    return fDrawTarget->caps(); | 
| +} | 
| + | 
| +GrResourceProvider* GrClipMaskManager::resourceProvider() { | 
| +    return fDrawTarget->cmmAccess().resourceProvider(); | 
| +} | 
| /* | 
| * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 
| * will be used on any element. If so, it returns true to indicate that the | 
| @@ -482,48 +484,6 @@ bool GrClipMaskManager::drawElement(GrPipelineBuilder* pipelineBuilder, | 
| return true; | 
| } | 
|  | 
| -void GrClipMaskManager::mergeMask(GrPipelineBuilder* pipelineBuilder, | 
| -                                  GrTexture* dstMask, | 
| -                                  GrTexture* srcMask, | 
| -                                  SkRegion::Op op, | 
| -                                  const SkIRect& dstBound, | 
| -                                  const SkIRect& srcBound) { | 
| -    pipelineBuilder->setRenderTarget(dstMask->asRenderTarget()); | 
| - | 
| -    // We want to invert the coverage here | 
| -    set_coverage_drawing_xpf(op, false, pipelineBuilder); | 
| - | 
| -    SkMatrix sampleM; | 
| -    sampleM.setIDiv(srcMask->width(), srcMask->height()); | 
| - | 
| -    pipelineBuilder->addCoverageFragmentProcessor( | 
| -        GrTextureDomainEffect::Create(srcMask, | 
| -                                      sampleM, | 
| -                                      GrTextureDomain::MakeTexelDomain(srcMask, srcBound), | 
| -                                      GrTextureDomain::kDecal_Mode, | 
| -                                      GrTextureParams::kNone_FilterMode))->unref(); | 
| - | 
| -    // The color passed in here does not matter since the coverageSetOpXP won't read it. | 
| -    fDrawTarget->drawNonAARect(*pipelineBuilder, | 
| -                               GrColor_WHITE, | 
| -                               SkMatrix::I(), | 
| -                               SkRect::Make(dstBound)); | 
| -} | 
| - | 
| -GrTexture* GrClipMaskManager::createTempMask(int width, int height) { | 
| -    GrSurfaceDesc desc; | 
| -    desc.fFlags = kRenderTarget_GrSurfaceFlag; | 
| -    desc.fWidth = width; | 
| -    desc.fHeight = height; | 
| -    if (this->getContext()->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 
| -        desc.fConfig = kAlpha_8_GrPixelConfig; | 
| -    } else { | 
| -        desc.fConfig = kRGBA_8888_GrPixelConfig; | 
| -    } | 
| - | 
| -    return this->getContext()->textureProvider()->createApproxTexture(desc); | 
| -} | 
| - | 
| //////////////////////////////////////////////////////////////////////////////// | 
| // Create a 8-bit clip mask in alpha | 
|  | 
| @@ -541,13 +501,13 @@ GrTexture* GrClipMaskManager::createCachedMask(int width, int height, const GrUn | 
| desc.fWidth = width; | 
| desc.fHeight = height; | 
| desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; | 
| -    if (!renderTarget || fDrawTarget->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 
| +    if (!renderTarget || this->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 
| desc.fConfig = kAlpha_8_GrPixelConfig; | 
| } else { | 
| desc.fConfig = kRGBA_8888_GrPixelConfig; | 
| } | 
|  | 
| -    GrTexture* texture = fDrawTarget->cmmAccess().resourceProvider()->createApproxTexture(desc, 0); | 
| +    GrTexture* texture = this->resourceProvider()->createApproxTexture(desc, 0); | 
| if (!texture) { | 
| return nullptr; | 
| } | 
| @@ -560,17 +520,16 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, | 
| const GrReducedClip::ElementList& elements, | 
| const SkVector& clipToMaskOffset, | 
| const SkIRect& clipSpaceIBounds) { | 
| -    GrResourceProvider* resourceProvider = fDrawTarget->cmmAccess().resourceProvider(); | 
| +    GrResourceProvider* resourceProvider = this->resourceProvider(); | 
| GrUniqueKey key; | 
| GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 
| if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) { | 
| return texture; | 
| } | 
|  | 
| +    // 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)); | 
| - | 
| -    // There's no texture in the cache. Let's try to allocate it then. | 
| if (!texture) { | 
| return nullptr; | 
| } | 
| @@ -594,8 +553,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, | 
| // 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. | 
| -    GrClip clip(maskSpaceIBounds); | 
| -    SkAutoTUnref<GrTexture> temp; | 
| +    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()) { | 
| @@ -606,78 +564,36 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, | 
| GrPipelineBuilder pipelineBuilder; | 
|  | 
| pipelineBuilder.setClip(clip); | 
| -            GrPathRenderer* pr = nullptr; | 
| -            bool useTemp = !can_stencil_and_draw_element(this->getContext(), &pipelineBuilder, | 
| -                                                         texture, translate, element, &pr); | 
| - | 
| -            // useSWOnlyPath should now filter out all cases where gpu-side mask merging is | 
| -            // performed. See skbug.com/4519 for rationale and details. | 
| -            SkASSERT(!useTemp); | 
| - | 
| -            GrTexture* dst; | 
| -            // This is the bounds of the clip element in the space of the alpha-mask. The temporary | 
| -            // mask buffer can be substantially larger than the actually clip stack element. We | 
| -            // touch the minimum number of pixels necessary and use decal mode to combine it with | 
| -            // the accumulator. | 
| -            SkIRect maskSpaceElementIBounds; | 
| - | 
| -            if (useTemp) { | 
| -                if (invert) { | 
| -                    maskSpaceElementIBounds = maskSpaceIBounds; | 
| -                } else { | 
| -                    SkRect elementBounds = element->getBounds(); | 
| -                    elementBounds.offset(clipToMaskOffset); | 
| -                    elementBounds.roundOut(&maskSpaceElementIBounds); | 
| -                } | 
| - | 
| -                if (!temp) { | 
| -                    temp.reset(this->createTempMask(maskSpaceIBounds.fRight, | 
| -                                                    maskSpaceIBounds.fBottom)); | 
| -                    if (!temp) { | 
| -                        texture->resourcePriv().removeUniqueKey(); | 
| -                        return nullptr; | 
| -                    } | 
| -                } | 
| -                dst = temp; | 
| -                // clear the temp target and set blend to replace | 
| -                fDrawTarget->clear(&maskSpaceElementIBounds, | 
| -                                   invert ? 0xffffffff : 0x00000000, | 
| -                                   true, | 
| -                                   dst->asRenderTarget()); | 
| -                set_coverage_drawing_xpf(SkRegion::kReplace_Op, invert, &pipelineBuilder); | 
| -            } else { | 
| -                // draw directly into the result with the stencil set to make the pixels affected | 
| -                // by the clip shape be non-zero. | 
| -                dst = texture; | 
| -                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); | 
| +            pipelineBuilder.setRenderTarget(texture->asRenderTarget()); | 
| + | 
| +            GrPathRenderer* pr = get_path_renderer(this->getContext(), &pipelineBuilder, | 
| +                                                   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 skbug.com/4519 | 
| +                // for rationale and details. | 
| +                SkASSERT(0); | 
| +                continue; | 
| } | 
|  | 
| -            if (!this->drawElement(&pipelineBuilder, translate, dst, element, pr)) { | 
| +            // 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; | 
| } | 
|  | 
| -            if (useTemp) { | 
| -                GrPipelineBuilder backgroundPipelineBuilder; | 
| -                backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarget()); | 
| - | 
| -                // Now draw into the accumulator using the real operation and the temp buffer as a | 
| -                // texture | 
| -                this->mergeMask(&backgroundPipelineBuilder, | 
| -                                texture, | 
| -                                temp, | 
| -                                op, | 
| -                                maskSpaceIBounds, | 
| -                                maskSpaceElementIBounds); | 
| -            } else { | 
| +            { | 
| GrPipelineBuilder backgroundPipelineBuilder; | 
| backgroundPipelineBuilder.setRenderTarget(texture->asRenderTarget()); | 
|  | 
| @@ -720,8 +636,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt, | 
| const SkIPoint& clipSpaceToStencilOffset) { | 
| SkASSERT(rt); | 
|  | 
| -    GrStencilAttachment* stencilAttachment = | 
| -        fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); | 
| +    GrStencilAttachment* stencilAttachment = this->resourceProvider()->attachStencilAttachment(rt); | 
| if (nullptr == stencilAttachment) { | 
| return false; | 
| } | 
| @@ -977,14 +892,13 @@ void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipel | 
|  | 
| int stencilBits = 0; | 
| GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); | 
| -    GrStencilAttachment* stencilAttachment = | 
| -        fDrawTarget->cmmAccess().resourceProvider()->attachStencilAttachment(rt); | 
| +    GrStencilAttachment* stencilAttachment = this->resourceProvider()->attachStencilAttachment(rt); | 
| if (stencilAttachment) { | 
| stencilBits = stencilAttachment->bits(); | 
| } | 
|  | 
| -    SkASSERT(fDrawTarget->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp()); | 
| -    SkASSERT(fDrawTarget->caps()->twoSidedStencilSupport() || !settings.isTwoSided()); | 
| +    SkASSERT(this->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp()); | 
| +    SkASSERT(this->caps()->twoSidedStencilSupport() || !settings.isTwoSided()); | 
| this->adjustStencilParams(&settings, fClipMode, stencilBits); | 
| ars->set(&pipelineBuilder); | 
| ars->setStencil(settings); | 
| @@ -1005,7 +919,7 @@ void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings, | 
| unsigned int userBits = clipBit - 1; | 
|  | 
| GrStencilSettings::Face face = GrStencilSettings::kFront_Face; | 
| -    bool twoSided = fDrawTarget->caps()->twoSidedStencilSupport(); | 
| +    bool twoSided = this->caps()->twoSidedStencilSupport(); | 
|  | 
| bool finished = false; | 
| while (!finished) { | 
| @@ -1077,7 +991,7 @@ GrTexture* GrClipMaskManager::createSoftwareClipMask(int32_t elementsGenID, | 
| const SkIRect& clipSpaceIBounds) { | 
| GrUniqueKey key; | 
| GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 
| -    GrResourceProvider* resourceProvider = fDrawTarget->cmmAccess().resourceProvider(); | 
| +    GrResourceProvider* resourceProvider = this->resourceProvider(); | 
| if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)) { | 
| return texture; | 
| } | 
|  |