Removed degenerate quads from zero radius Chrome-style round rects

https://codereview.appspot.com/6737059/



git-svn-id: http://skia.googlecode.com/svn/trunk@6053 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/bench/PathBench.cpp b/bench/PathBench.cpp
index ac324a9..be16c75 100644
--- a/bench/PathBench.cpp
+++ b/bench/PathBench.cpp
@@ -671,8 +671,10 @@
     typedef SkBenchmark INHERITED;
 };
 
-// Chrome creates its own round rects with each corner possibly being different
-// Note: PathTest::test_arb_round_rect_is_convex performs almost exactly
+// Chrome creates its own round rects with each corner possibly being different.
+// In its "zero radius" incarnation it creates degenerate round rects.
+// Note: PathTest::test_arb_round_rect_is_convex and 
+// test_arb_zero_rad_round_rect_is_rect perform almost exactly
 // the same test (but with no drawing)
 class ArbRoundRectBench : public SkBenchmark {
 protected:
@@ -682,8 +684,12 @@
         N = SkBENCHLOOP(100)
     };
 public:
-    ArbRoundRectBench(void* param) : INHERITED(param) {
-        fName.printf("arbroundrect");
+    ArbRoundRectBench(void* param, bool zeroRad) : INHERITED(param), fZeroRad(zeroRad) {
+        if (zeroRad) {
+            fName.printf("zeroradroundrect");
+        } else {
+            fName.printf("arbroundrect");
+        }
     }
 
 protected:
@@ -728,6 +734,7 @@
         add_corner_arc(path, r, xCorner, yCorner, 0);
         add_corner_arc(path, r, xCorner, yCorner, 90);
         add_corner_arc(path, r, xCorner, yCorner, 180);
+        path->close();
 
 #ifdef SK_REDEFINE_ROOT2OVER2_TO_MAKE_ARCTOS_CONVEX
         SkASSERT(path->isConvex());
@@ -743,24 +750,32 @@
             paint.setColor(0xff000000 | rand.nextU());
             paint.setAntiAlias(true);
 
-            SkScalar radius = rand.nextUScalar1() * 30;
-            if (radius < SK_Scalar1) {
+            SkScalar size = rand.nextUScalar1() * 30;
+            if (size < SK_Scalar1) {
                 continue;
             }
             r.fLeft = rand.nextUScalar1() * 300;
             r.fTop =  rand.nextUScalar1() * 300;
-            r.fRight =  r.fLeft + 2 * radius;
-            r.fBottom = r.fTop + 2 * radius;
+            r.fRight =  r.fLeft + 2 * size;
+            r.fBottom = r.fTop + 2 * size;
 
             SkPath temp;
 
-            make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
+            if (fZeroRad) {
+                make_arb_round_rect(&temp, r, 0, 0);
+
+                SkASSERT(temp.isRect(NULL));
+            } else {
+                make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
+            }
 
             canvas->drawPath(temp, paint);
         }
     }
 
 private:
+    bool fZeroRad;      // should 0 radius rounds rects be tested?
+
     typedef SkBenchmark INHERITED;
 };
 
@@ -863,5 +878,8 @@
 static SkBenchmark* CirclesTest(void* p) { return new CirclesBench(p); }
 static BenchRegistry gRegCirclesTest(CirclesTest);
 
-static SkBenchmark* ArbRoundRectTest(void* p) { return new ArbRoundRectBench(p); }
+static SkBenchmark* ArbRoundRectTest(void* p) { return new ArbRoundRectBench(p, false); }
 static BenchRegistry gRegArbRoundRectTest(ArbRoundRectTest);
+
+static SkBenchmark* ZeroRadRoundRectTest(void* p) { return new ArbRoundRectBench(p, true); }
+static BenchRegistry gRegZeroRadRoundRectTest(ZeroRadRoundRectTest);
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 9723db9..b8df23b 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -1030,6 +1030,15 @@
         // bounding box (and break the circle special case).
         pts[0].set(oval.fRight, oval.centerY());
         return 1;
+    } else if (0 == oval.width() && 0 == oval.height()) {
+        // Chrome will sometimes create 0 radius round rects. Having degenerate
+        // quad segments in the path prevents the path from being recognized as 
+        // a rect.
+        // TODO: optimizing the case where only one of width or height is zero
+        // should also be considered. This case, however, doesn't seem to be
+        // as common as the single point case.
+        pts[0].set(oval.fRight, oval.fTop);
+        return 1;
     }
 
     SkVector start, stop;
diff --git a/tests/PathTest.cpp b/tests/PathTest.cpp
index 819d3b3..cfad5d6 100644
--- a/tests/PathTest.cpp
+++ b/tests/PathTest.cpp
@@ -114,6 +114,7 @@
     add_corner_arc(path, r, xCorner, yCorner, 0);
     add_corner_arc(path, r, xCorner, yCorner, 90);
     add_corner_arc(path, r, xCorner, yCorner, 180);
+    path->close();
 }
 
 // Chrome creates its own round rects with each corner possibly being different.
@@ -126,14 +127,14 @@
 
     for (int i = 0; i < 5000; ++i) {
 
-        SkScalar radius = rand.nextUScalar1() * 30;
-        if (radius < SK_Scalar1) {
+        SkScalar size = rand.nextUScalar1() * 30;
+        if (size < SK_Scalar1) {
             continue;
         }
         r.fLeft = rand.nextUScalar1() * 300;
         r.fTop =  rand.nextUScalar1() * 300;
-        r.fRight =  r.fLeft + 2 * radius;
-        r.fBottom = r.fTop + 2 * radius;
+        r.fRight =  r.fLeft + 2 * size;
+        r.fBottom = r.fTop + 2 * size;
 
         SkPath temp;
 
@@ -145,6 +146,37 @@
     }
 }
 
+// Chrome will sometimes create a 0 radius round rect. The degenerate
+// quads prevent the path from being converted to a rect
+// Note: PathBench::ArbRoundRectBench performs almost exactly
+// the same test (but with drawing)
+static void test_arb_zero_rad_round_rect_is_rect(skiatest::Reporter* reporter) {
+    SkRandom rand;
+    SkRect r;
+
+    for (int i = 0; i < 5000; ++i) {
+
+        SkScalar size = rand.nextUScalar1() * 30;
+        if (size < SK_Scalar1) {
+            continue;
+        }
+        r.fLeft = rand.nextUScalar1() * 300;
+        r.fTop =  rand.nextUScalar1() * 300;
+        r.fRight =  r.fLeft + 2 * size;
+        r.fBottom = r.fTop + 2 * size;
+
+        SkPath temp;
+
+        make_arb_round_rect(&temp, r, 0, 0);
+
+#ifdef SK_REDEFINE_ROOT2OVER2_TO_MAKE_ARCTOS_CONVEX
+        SkRect result;
+        REPORTER_ASSERT(reporter, temp.isRect(&result));
+        REPORTER_ASSERT(reporter, r == result);
+#endif
+    }
+}
+
 static void test_rect_isfinite(skiatest::Reporter* reporter) {
     const SkScalar inf = SK_ScalarInfinity;
     const SkScalar nan = SK_ScalarNaN;
@@ -1685,6 +1717,7 @@
     test_isfinite_after_transform(reporter);
     test_tricky_cubic(reporter);
     test_arb_round_rect_is_convex(reporter);
+    test_arb_zero_rad_round_rect_is_rect(reporter);
 }
 
 #include "TestClassDef.h"