Fix bounds computation in GrAAHairlineRenderer

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

Author: bsalomon@google.com

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

git-svn-id: http://skia.googlecode.com/svn/trunk/src@11054 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/GrAAHairLinePathRenderer.cpp b/gpu/GrAAHairLinePathRenderer.cpp
index 60992fd..5078467 100644
--- a/gpu/GrAAHairLinePathRenderer.cpp
+++ b/gpu/GrAAHairLinePathRenderer.cpp
@@ -589,10 +589,8 @@
     c1.fPos = c;
     c1.fPos -= cbN;
 
-    // This point may not be within 1 pixel of a control point. We update the bounding box to
-    // include it.
     intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos);
-    devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY);
+    devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kVertsPerQuad);
 
     if (toSrc) {
         toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kVertsPerQuad);
@@ -723,8 +721,6 @@
 
     const SkMatrix& viewM = drawState->getViewMatrix();
 
-    *devBounds = path.getBounds();
-    viewM.mapRect(devBounds);
     devBounds->outset(SK_Scalar1, SK_Scalar1);
 
     int vertCnt = kVertsPerLineSeg * lineCnt;
@@ -746,10 +742,14 @@
             toSrc = &ivm;
         }
     }
-
+    devBounds->set(lines.begin(), lines.count());
     for (int i = 0; i < lineCnt; ++i) {
         add_line(&lines[2*i], rtHeight, toSrc, drawState->getCoverage(), &verts);
     }
+    // All the verts computed by add_line are within unit distance of the end points. Add a little
+    // extra to account for vector normalization precision.
+    static const SkScalar kOutset = SK_Scalar1 + SK_Scalar1 / 20;
+    devBounds->outset(kOutset, kOutset);
 
     return true;
 }
@@ -769,13 +769,6 @@
 
     const SkMatrix& viewM = drawState->getViewMatrix();
 
-    // All the vertices that we compute are within 1 of path control points with the exception of
-    // one of the bounding vertices for each quad. The add_quads() function will update the bounds
-    // for each quad added.
-    *devBounds = path.getBounds();
-    viewM.mapRect(devBounds);
-    devBounds->outset(SK_Scalar1, SK_Scalar1);
-
     int vertCnt = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt;
 
     target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(SK_ARRAY_COUNT(gHairlineBezierAttribs));
@@ -798,6 +791,21 @@
         }
     }
 
+    // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding
+    // box to include its vertices.
+    SkPoint seedPts[2];
+    if (quadCnt) {
+        seedPts[0] = quads[0];
+        seedPts[1] = quads[2];
+    } else if (conicCnt) {
+        seedPts[0] = conics[0];
+        seedPts[1] = conics[2];
+    }
+    if (NULL != toDevice) {
+        toDevice->mapPoints(seedPts, 2);
+    }
+    devBounds->set(seedPts[0], seedPts[1]);
+
     int unsubdivQuadCnt = quads.count() / 3;
     for (int i = 0; i < unsubdivQuadCnt; ++i) {
         SkASSERT(qSubdivs[i] >= 0);
@@ -830,7 +838,14 @@
 bool check_bounds(GrDrawState* drawState, const SkRect& devBounds, void* vertices, int vCount)
 {
     SkRect tolDevBounds = devBounds;
-    tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
+    // The bounds ought to be tight, but in perspective the below code runs the verts
+    // through the view matrix to get back to dev coords, which can introduce imprecision.
+    if (drawState->getViewMatrix().hasPerspective()) {
+        tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000);
+    } else {
+        // Non-persp matrices cause this path renderer to draw in device space.
+        SkASSERT(drawState->getViewMatrix().isIdentity());
+    }
     SkRect actualBounds;
 
     VertexType* verts = reinterpret_cast<VertexType*>(vertices);
@@ -880,7 +895,7 @@
     conicCnt = conics.count() / 3;
 
     // do lines first
-    {
+    if (lineCnt) {
         GrDrawTarget::AutoReleaseGeometry arg;
         SkRect devBounds;
 
@@ -926,7 +941,7 @@
     }
 
     // then quadratics/conics
-    {
+    if (quadCnt || conicCnt) {
         GrDrawTarget::AutoReleaseGeometry arg;
         SkRect devBounds;