| Index: src/gpu/GrDrawContext.cpp | 
| diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp | 
| index a86e01e72b385328b069f84f412f43bfcc58e604..8f012cd65840177ecade6979dec9ff584bd31239 100644 | 
| --- a/src/gpu/GrDrawContext.cpp | 
| +++ b/src/gpu/GrDrawContext.cpp | 
| @@ -270,17 +270,70 @@ static bool should_apply_coverage_aa(const GrPaint& paint, GrRenderTarget* rt, | 
| } | 
| } | 
|  | 
| +// Attempts to crop a rect and optional local rect to the clip boundaries. | 
| +// Returns false if the draw can be skipped entirely. | 
| +static bool crop_filled_rect(const GrRenderTarget* rt, const GrClip& clip, | 
| +                             const SkMatrix& viewMatrix, SkRect* rect, | 
| +                             SkRect* localRect = nullptr) { | 
| +    if (!viewMatrix.rectStaysRect()) { | 
| +        return true; | 
| +    } | 
| + | 
| +    SkMatrix inverseViewMatrix; | 
| +    if (!viewMatrix.invert(&inverseViewMatrix)) { | 
| +        return false; | 
| +    } | 
| + | 
| +    SkIRect clipDevBounds; | 
| +    SkRect clipBounds; | 
| +    SkASSERT(inverseViewMatrix.rectStaysRect()); | 
| + | 
| +    clip.getConservativeBounds(rt->width(), rt->height(), &clipDevBounds); | 
| +    inverseViewMatrix.mapRect(&clipBounds, SkRect::Make(clipDevBounds)); | 
| + | 
| +    if (localRect) { | 
| +        if (!rect->intersects(clipBounds)) { | 
| +            return false; | 
| +        } | 
| +        const SkScalar dx = localRect->width() / rect->width(); | 
| +        const SkScalar dy = localRect->height() / rect->height(); | 
| +        if (clipBounds.fLeft > rect->fLeft) { | 
| +            localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx; | 
| +            rect->fLeft = clipBounds.fLeft; | 
| +        } | 
| +        if (clipBounds.fTop > rect->fTop) { | 
| +            localRect->fTop += (clipBounds.fTop - rect->fTop) * dy; | 
| +            rect->fTop = clipBounds.fTop; | 
| +        } | 
| +        if (clipBounds.fRight < rect->fRight) { | 
| +            localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx; | 
| +            rect->fRight = clipBounds.fRight; | 
| +        } | 
| +        if (clipBounds.fBottom < rect->fBottom) { | 
| +            localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy; | 
| +            rect->fBottom = clipBounds.fBottom; | 
| +        } | 
| +        return true; | 
| +    } | 
| + | 
| +    return rect->intersect(clipBounds); | 
| +} | 
| + | 
| bool GrDrawContext::drawFilledRect(const GrClip& clip, | 
| const GrPaint& paint, | 
| const SkMatrix& viewMatrix, | 
| const SkRect& rect, | 
| const GrUserStencilSettings* ss) { | 
| +    SkRect croppedRect = rect; | 
| +    if (!crop_filled_rect(fRenderTarget.get(), clip, viewMatrix, &croppedRect)) { | 
| +        return true; | 
| +    } | 
|  | 
| SkAutoTUnref<GrDrawBatch> batch; | 
| bool useHWAA; | 
|  | 
| if (InstancedRendering* ir = this->getDrawTarget()->instancedRendering()) { | 
| -        batch.reset(ir->recordRect(rect, viewMatrix, paint.getColor(), | 
| +        batch.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), | 
| paint.isAntiAlias(), fInstancedPipelineInfo, | 
| &useHWAA)); | 
| if (batch) { | 
| @@ -297,10 +350,10 @@ bool GrDrawContext::drawFilledRect(const GrClip& clip, | 
| // The fill path can handle rotation but not skew. | 
| if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) { | 
| SkRect devBoundRect; | 
| -            viewMatrix.mapRect(&devBoundRect, rect); | 
| +            viewMatrix.mapRect(&devBoundRect, croppedRect); | 
|  | 
| batch.reset(GrRectBatchFactory::CreateAAFill(paint.getColor(), viewMatrix, | 
| -                                                         rect, devBoundRect)); | 
| +                                                         croppedRect, devBoundRect)); | 
| if (batch) { | 
| GrPipelineBuilder pipelineBuilder(paint, useHWAA); | 
| if (ss) { | 
| @@ -311,7 +364,7 @@ bool GrDrawContext::drawFilledRect(const GrClip& clip, | 
| } | 
| } | 
| } else { | 
| -        this->drawNonAAFilledRect(clip, paint, viewMatrix, rect, nullptr, nullptr, ss); | 
| +        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, nullptr, ss); | 
| return true; | 
| } | 
|  | 
| @@ -522,12 +575,18 @@ void GrDrawContext::fillRectToRect(const GrClip& clip, | 
| SkDEBUGCODE(this->validate();) | 
| GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectToRect"); | 
|  | 
| +    SkRect croppedRect = rectToDraw; | 
| +    SkRect croppedLocalRect = localRect; | 
| +    if (!crop_filled_rect(fRenderTarget.get(), clip, viewMatrix, &croppedRect, &croppedLocalRect)) { | 
| +        return; | 
| +    } | 
| + | 
| AutoCheckFlush acf(fDrawingManager); | 
| SkAutoTUnref<GrDrawBatch> batch; | 
| bool useHWAA; | 
|  | 
| if (InstancedRendering* ir = this->getDrawTarget()->instancedRendering()) { | 
| -        batch.reset(ir->recordRect(rectToDraw, viewMatrix, paint.getColor(), localRect, | 
| +        batch.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), croppedLocalRect, | 
| paint.isAntiAlias(), fInstancedPipelineInfo, &useHWAA)); | 
| if (batch) { | 
| GrPipelineBuilder pipelineBuilder(paint, useHWAA); | 
| @@ -538,15 +597,15 @@ void GrDrawContext::fillRectToRect(const GrClip& clip, | 
|  | 
| if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA) && | 
| view_matrix_ok_for_aa_fill_rect(viewMatrix)) { | 
| -        batch.reset(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), viewMatrix, rectToDraw, | 
| -                                                           localRect)); | 
| +        batch.reset(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), viewMatrix, | 
| +                                                           croppedRect, croppedLocalRect)); | 
| if (batch) { | 
| GrPipelineBuilder pipelineBuilder(paint, useHWAA); | 
| this->drawBatch(pipelineBuilder, clip, batch); | 
| return; | 
| } | 
| } else { | 
| -        this->drawNonAAFilledRect(clip, paint, viewMatrix, rectToDraw, &localRect, | 
| +        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, &croppedLocalRect, | 
| nullptr, nullptr); | 
| } | 
|  | 
| @@ -562,12 +621,17 @@ void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip, | 
| SkDEBUGCODE(this->validate();) | 
| GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectWithLocalMatrix"); | 
|  | 
| +    SkRect croppedRect = rectToDraw; | 
| +    if (!crop_filled_rect(fRenderTarget.get(), clip, viewMatrix, &croppedRect)) { | 
| +        return; | 
| +    } | 
| + | 
| AutoCheckFlush acf(fDrawingManager); | 
| SkAutoTUnref<GrDrawBatch> batch; | 
| bool useHWAA; | 
|  | 
| if (InstancedRendering* ir = this->getDrawTarget()->instancedRendering()) { | 
| -        batch.reset(ir->recordRect(rectToDraw, viewMatrix, paint.getColor(), localMatrix, | 
| +        batch.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), localMatrix, | 
| paint.isAntiAlias(), fInstancedPipelineInfo, &useHWAA)); | 
| if (batch) { | 
| GrPipelineBuilder pipelineBuilder(paint, useHWAA); | 
| @@ -579,11 +643,11 @@ void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip, | 
| if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA) && | 
| view_matrix_ok_for_aa_fill_rect(viewMatrix)) { | 
| batch.reset(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, localMatrix, | 
| -                                              rectToDraw)); | 
| +                                              croppedRect)); | 
| GrPipelineBuilder pipelineBuilder(paint, useHWAA); | 
| this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch); | 
| } else { | 
| -        this->drawNonAAFilledRect(clip, paint, viewMatrix, rectToDraw, nullptr, | 
| +        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, | 
| &localMatrix, nullptr); | 
| } | 
|  | 
|  |