Fix cubic->quad RR corner regression

https://codereview.chromium.org/29673002/



git-svn-id: http://skia.googlecode.com/svn/trunk/src@11870 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/core/SkCanvas.cpp b/core/SkCanvas.cpp
index 7add524..6036186 100644
--- a/core/SkCanvas.cpp
+++ b/core/SkCanvas.cpp
@@ -1124,7 +1124,7 @@
     doAA &= fAllowSoftClip;
 
     if (fMCRec->fMatrix->rectStaysRect()) {
-        // for these simpler matrices, we can stay a rect ever after applying
+        // for these simpler matrices, we can stay a rect even after applying
         // the matrix. This means we don't have to a) make a path, and b) tell
         // the region code to scan-convert the path, only to discover that it
         // is really just a rect.
@@ -1134,7 +1134,7 @@
         fClipStack.clipDevRect(r, op, doAA);
         return fMCRec->fRasterClip->op(r, op, doAA);
     } else {
-        // since we're rotate or some such thing, we convert the rect to a path
+        // since we're rotated or some such thing, we convert the rect to a path
         // and clip against that, since it can handle any matrix. However, to
         // avoid recursion in the case where we are subclassed (e.g. Pictures)
         // we explicitly call "our" version of clipPath.
diff --git a/core/SkPath.cpp b/core/SkPath.cpp
index 3b3a125..9df6285 100644
--- a/core/SkPath.cpp
+++ b/core/SkPath.cpp
@@ -17,8 +17,6 @@
 
 SK_DEFINE_INST_COUNT(SkPath);
 
-#define SK_IGNORE_QUAD_RR_CORNERS_OPT 1
-
 // This value is just made-up for now. When count is 4, calling memset was much
 // slower than just writing the loop. This seems odd, and hopefully in the
 // future this we appear to have been a fluke...
@@ -966,8 +964,7 @@
 
 static void add_corner_arc(SkPath* path, const SkRect& rect,
                            SkScalar rx, SkScalar ry, int startAngle,
-                           SkPath::Direction dir, bool addArcTo,
-                           bool forceMoveTo = false) {
+                           SkPath::Direction dir, bool forceMoveTo) {
     // These two asserts are not sufficient, since really we want to know
     // that the pair of radii (e.g. left and right, or top and bottom) sum
     // to <= dimension, but we don't have that data here, so we just have
@@ -997,15 +994,7 @@
         sweep = -sweep;
     }
 
-    if (addArcTo) {
-        path->arcTo(r, start, sweep, forceMoveTo);
-    } else {
-        SkPoint pts[kSkBuildQuadArcStorage];
-        int count = build_arc_points(r, start, sweep, pts);
-        for (int i = 1; i < count; i += 2) {
-            path->quadTo(pts[i], pts[i+1]);
-        }
-    }
+    path->arcTo(r, start, sweep, forceMoveTo);
 }
 
 void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[],
@@ -1035,15 +1024,15 @@
         SkAutoPathBoundsUpdate apbu(this, bounds);
 
         if (kCW_Direction == dir) {
-            add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true, true);
-            add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, true);
-            add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY,   0, dir, true);
-            add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY,  90, dir, true);
+            add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true);
+            add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false);
+            add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY,   0, dir, false);
+            add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY,  90, dir, false);
         } else {
-            add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true, true);
-            add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY,  90, dir, true);
-            add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY,   0, dir, true);
-            add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, true);
+            add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true);
+            add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY,  90, dir, false);
+            add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY,   0, dir, false);
+            add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false);
         }
         this->close();
     }
@@ -1113,9 +1102,20 @@
 
     this->incReserve(17);
 #else
-    this->incReserve(13);
+    // Please see SkBuildQuadArc for more information but, we need to pull
+    // the off-curve quadratic points in a little bit to make the round
+    // rects convex.
+    static const SkScalar kOffCurveEpsilon = 0.0001f;
+
+    SkScalar    midPtX = rx * SK_ScalarRoot2Over2;
+    SkScalar    midPtY = ry * SK_ScalarRoot2Over2;
+
+    SkScalar    offPtX = rx * SK_ScalarTanPIOver8 - kOffCurveEpsilon;
+    SkScalar    offPtY = ry * SK_ScalarTanPIOver8 - kOffCurveEpsilon;
+
+    this->incReserve(21);
 #endif
-    this->moveTo(rect.fRight - rx, rect.fTop);
+    this->moveTo(rect.fRight - rx, rect.fTop);                  // top-right
     if (dir == kCCW_Direction) {
         if (!skip_hori) {
             this->lineTo(rect.fLeft + rx, rect.fTop);           // top
@@ -1125,7 +1125,10 @@
                       rect.fLeft, rect.fTop + ry - sy,
                       rect.fLeft, rect.fTop + ry);          // top-left
 #else
-        add_corner_arc(this, rect, rx, ry, 180, dir, false);    // top-left
+        this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon,
+                     rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY);
+        this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY,
+                     rect.fLeft, rect.fTop + ry);
 #endif
         if (!skip_vert) {
             this->lineTo(rect.fLeft, rect.fBottom - ry);        // left
@@ -1135,7 +1138,10 @@
                       rect.fLeft + rx - sx, rect.fBottom,
                       rect.fLeft + rx, rect.fBottom);       // bot-left
 #else
-        add_corner_arc(this, rect, rx, ry, 90, dir, false);     // bot-left
+        this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fBottom - ry + offPtY,
+                     rect.fLeft + rx - midPtX, rect.fBottom - ry + midPtY);
+        this->quadTo(rect.fLeft + rx - offPtX, rect.fBottom - kOffCurveEpsilon,
+                     rect.fLeft + rx, rect.fBottom);
 #endif
         if (!skip_hori) {
             this->lineTo(rect.fRight - rx, rect.fBottom);       // bottom
@@ -1145,7 +1151,10 @@
                       rect.fRight, rect.fBottom - ry + sy,
                       rect.fRight, rect.fBottom - ry);      // bot-right
 #else
-        add_corner_arc(this, rect, rx, ry, 0, dir, false);      // bot-right
+        this->quadTo(rect.fRight - rx + offPtX, rect.fBottom - kOffCurveEpsilon,
+                     rect.fRight - rx + midPtX, rect.fBottom - ry + midPtY);
+        this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fBottom - ry + offPtY,
+                     rect.fRight, rect.fBottom - ry);
 #endif
         if (!skip_vert) {
             this->lineTo(rect.fRight, rect.fTop + ry);          // right
@@ -1155,7 +1164,10 @@
                       rect.fRight - rx + sx, rect.fTop,
                       rect.fRight - rx, rect.fTop);         // top-right
 #else
-        add_corner_arc(this, rect, rx, ry, 270, dir, false);    // top-right
+        this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fTop + ry - offPtY,
+                     rect.fRight - rx + midPtX, rect.fTop + ry - midPtY);
+        this->quadTo(rect.fRight - rx + offPtX, rect.fTop + kOffCurveEpsilon,
+                     rect.fRight - rx, rect.fTop);
 #endif
     } else {
 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT
@@ -1163,7 +1175,10 @@
                       rect.fRight, rect.fTop + ry - sy,
                       rect.fRight, rect.fTop + ry);         // top-right
 #else
-        add_corner_arc(this, rect, rx, ry, 270, dir, false);    // top-right
+        this->quadTo(rect.fRight - rx + offPtX, rect.fTop + kOffCurveEpsilon,
+                     rect.fRight - rx + midPtX, rect.fTop + ry - midPtY);
+        this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fTop + ry - offPtY,
+                     rect.fRight, rect.fTop + ry);
 #endif
         if (!skip_vert) {
             this->lineTo(rect.fRight, rect.fBottom - ry);       // right
@@ -1173,7 +1188,10 @@
                       rect.fRight - rx + sx, rect.fBottom,
                       rect.fRight - rx, rect.fBottom);      // bot-right
 #else
-        add_corner_arc(this, rect, rx, ry, 0, dir, false);      // bot-right
+        this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fBottom - ry + offPtY,
+                     rect.fRight - rx + midPtX, rect.fBottom - ry + midPtY);
+        this->quadTo(rect.fRight - rx + offPtX, rect.fBottom - kOffCurveEpsilon,
+                     rect.fRight - rx, rect.fBottom);
 #endif
         if (!skip_hori) {
             this->lineTo(rect.fLeft + rx, rect.fBottom);        // bottom
@@ -1183,7 +1201,10 @@
                       rect.fLeft, rect.fBottom - ry + sy,
                       rect.fLeft, rect.fBottom - ry);       // bot-left
 #else
-        add_corner_arc(this, rect, rx, ry, 90, dir, false);     // bot-left
+        this->quadTo(rect.fLeft + rx - offPtX, rect.fBottom - kOffCurveEpsilon,
+                     rect.fLeft + rx - midPtX, rect.fBottom - ry + midPtY);
+        this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fBottom - ry + offPtY,
+                     rect.fLeft, rect.fBottom - ry);
 #endif
         if (!skip_vert) {
             this->lineTo(rect.fLeft, rect.fTop + ry);           // left
@@ -1193,7 +1214,10 @@
                       rect.fLeft + rx - sx, rect.fTop,
                       rect.fLeft + rx, rect.fTop);          // top-left
 #else
-        add_corner_arc(this, rect, rx, ry, 180, dir, false);    // top-left
+        this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY,
+                     rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY);
+        this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon,
+                     rect.fLeft + rx, rect.fTop);
 #endif
         if (!skip_hori) {
             this->lineTo(rect.fRight - rx, rect.fTop);          // top