Add blend optimization helpers and use to convert rect draws to clears.

Committed: http://code.google.com/p/skia/source/detail?r=10537

R=robertphillips@google.com, jvanverth@google.com, reed@google.com

Author: bsalomon@google.com

Review URL: https://chromiumcodereview.appspot.com/21877006

git-svn-id: http://skia.googlecode.com/svn/trunk@10562 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 20c633d..20320e8 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -681,9 +681,8 @@
 static bool apply_aa_to_rect(GrDrawTarget* target,
                              const SkRect& rect,
                              SkScalar strokeWidth,
-                             const SkMatrix* matrix,
-                             SkMatrix* combinedMatrix,
-                             SkRect* devRect,
+                             const SkMatrix& combinedMatrix,
+                             SkRect* devBoundRect,
                              bool* useVertexCoverage) {
     // we use a simple coverage ramp to do aa on axis-aligned rects
     // we check if the rect will be axis-aligned, and the rect won't land on
@@ -716,52 +715,32 @@
 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
     if (strokeWidth >= 0) {
 #endif
-        if (!drawState.getViewMatrix().preservesAxisAlignment()) {
+        if (!combinedMatrix.preservesAxisAlignment()) {
             return false;
         }
 
-        if (NULL != matrix && !matrix->preservesAxisAlignment()) {
-            return false;
-        }
 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
     } else {
-        if (!drawState.getViewMatrix().preservesAxisAlignment() &&
-            !drawState.getViewMatrix().preservesRightAngles()) {
-            return false;
-        }
-
-        if (NULL != matrix && !matrix->preservesRightAngles()) {
+        if (!combinedMatrix.preservesRightAngles()) {
             return false;
         }
     }
 #endif
 
-    *combinedMatrix = drawState.getViewMatrix();
-    if (NULL != matrix) {
-        combinedMatrix->preConcat(*matrix);
-
-#if GR_DEBUG
-#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
-        if (strokeWidth >= 0) {
-#endif
-            GrAssert(combinedMatrix->preservesAxisAlignment());
-#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
-        } else {
-            GrAssert(combinedMatrix->preservesRightAngles());
-        }
-#endif
-#endif
-    }
-
-    combinedMatrix->mapRect(devRect, rect);
+    combinedMatrix.mapRect(devBoundRect, rect);
 
     if (strokeWidth < 0) {
-        return !isIRect(*devRect);
+        return !isIRect(*devBoundRect);
     } else {
         return true;
     }
 }
 
+static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
+    return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
+           point.fY >= rect.fTop && point.fY <= rect.fBottom;
+}
+
 void GrContext::drawRect(const GrPaint& paint,
                          const SkRect& rect,
                          SkScalar width,
@@ -771,13 +750,48 @@
     AutoRestoreEffects are;
     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are);
 
-    SkRect devRect;
-    SkMatrix combinedMatrix;
+    SkMatrix combinedMatrix = target->drawState()->getViewMatrix();
+    if (NULL != matrix) {
+        combinedMatrix.preConcat(*matrix);
+    }
+
+    // Check if this is a full RT draw and can be replaced with a clear.
+    SkRect rtRect;
+    target->getDrawState().getRenderTarget()->getBoundsRect(&rtRect);
+    SkRect clipSpaceRTRect = rtRect;
+    bool checkClip = false;
+    if (NULL != this->getClip()) {
+        checkClip = true;
+        clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->fOrigin.fX),
+                               SkIntToScalar(this->getClip()->fOrigin.fY));
+    }
+    // Does the clip contain the entire RT?
+    if (!checkClip || target->getClip()->fClipStack->quickContains(clipSpaceRTRect)) {
+        SkMatrix invM;
+        if (!combinedMatrix.invert(&invM)) {
+            return;
+        }
+        // Does the rect bound the RT?
+        SkPoint srcSpaceRTQuad[4];
+        invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
+        if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
+            rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
+            rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
+            rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
+            // Will it blend?
+            GrColor clearColor;
+            if (paint.isOpaqueAndConstantColor(&clearColor)) {
+                target->clear(NULL, clearColor);
+                return;
+            }
+        }
+    }
+
+    SkRect devBoundRect;
     bool useVertexCoverage;
     bool needAA = paint.isAntiAlias() &&
                   !target->getDrawState().getRenderTarget()->isMultisampled();
-    bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
-                                           &combinedMatrix, &devRect,
+    bool doAA = needAA && apply_aa_to_rect(target, rect, width, combinedMatrix, &devBoundRect,
                                            &useVertexCoverage);
     if (doAA) {
         GrDrawState::AutoViewMatrixRestore avmr;
@@ -786,12 +800,12 @@
         }
         if (width >= 0) {
             fAARectRenderer->strokeAARect(this->getGpu(), target,
-                                          rect, combinedMatrix, devRect,
+                                          rect, combinedMatrix, devBoundRect,
                                           width, useVertexCoverage);
         } else {
             // filled AA rect
             fAARectRenderer->fillAARect(this->getGpu(), target,
-                                        rect, combinedMatrix, devRect,
+                                        rect, combinedMatrix, devBoundRect,
                                         useVertexCoverage);
         }
         return;