Add special handling of rectori case for gpu

https://codereview.chromium.org/15080010/



git-svn-id: http://skia.googlecode.com/svn/trunk@9175 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 64893b4..d25709f 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -792,17 +792,9 @@
             return;
         }
         if (width >= 0) {
-            GrVec strokeSize;
-            if (width > 0) {
-                strokeSize.set(width, width);
-                combinedMatrix.mapVectors(&strokeSize, 1);
-                strokeSize.setAbs(strokeSize);
-            } else {
-                strokeSize.set(SK_Scalar1, SK_Scalar1);
-            }
             fAARectRenderer->strokeAARect(this->getGpu(), target,
                                           rect, combinedMatrix, devRect,
-                                          strokeSize, useVertexCoverage);
+                                          width, useVertexCoverage);
         } else {
             // filled AA rect
             fAARectRenderer->fillAARect(this->getGpu(), target,
@@ -1004,6 +996,52 @@
     }
 }
 
+namespace {
+
+// Can 'path' be drawn as a pair of filled nested rectangles?
+static bool is_nested_rects(GrDrawTarget* target,
+                            const SkPath& path,
+                            const SkStrokeRec& stroke,
+                            SkRect rects[2],
+                            bool* useVertexCoverage) {
+    SkASSERT(stroke.isFillStyle());
+
+    if (path.isInverseFillType()) {
+        return false;
+    }
+
+    const GrDrawState& drawState = target->getDrawState();
+
+    // TODO: this restriction could be lifted if we were willing to apply
+    // the matrix to all the points individually rather than just to the rect
+    if (!drawState.getViewMatrix().preservesAxisAlignment()) {
+        return false;
+    }
+
+    *useVertexCoverage = false;
+    if (!target->getDrawState().canTweakAlphaForCoverage()) {
+        if (disable_coverage_aa_for_blend(target)) {
+            return false;
+        } else {
+            *useVertexCoverage = true;
+        }
+    }
+
+    SkPath::Direction dirs[2];
+    if (!path.isNestedRects(rects, dirs)) {
+        return false;
+    }
+
+    if (SkPath::kWinding_FillType == path.getFillType()) {
+        // The two rects need to be wound opposite to each other
+        return dirs[0] != dirs[1];
+    } else {
+        return true;
+    }
+}
+
+};
+
 void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) {
 
     if (path.isEmpty()) {
@@ -1021,9 +1059,28 @@
     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
     GrDrawState::AutoStageDisable atr(fDrawState);
 
+    bool useAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled();
+    if (useAA && stroke.getWidth() < 0 && !path.isConvex()) {
+        // Concave AA paths are expensive - try to avoid them for special cases
+        bool useVertexCoverage;
+        SkRect rects[2];
+
+        if (is_nested_rects(target, path, stroke, rects, &useVertexCoverage)) {
+            GrDrawState::AutoDeviceCoordDraw adcd(target->drawState());
+            if (!adcd.succeeded()) {
+                return;
+            }
+
+            fAARectRenderer->fillAANestedRects(this->getGpu(), target,
+                                               rects,
+                                               adcd.getOriginalMatrix(),
+                                               useVertexCoverage);
+            return;
+        }
+    }
+
     SkRect ovalRect;
     bool isOval = path.isOval(&ovalRect);
-    bool useAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled();
 
     if (!isOval || path.isInverseFillType()
         || !fOvalRenderer->drawOval(target, this, useAA, ovalRect, stroke)) {