Handle paths that do not report empty, but have no edges.
authorreed <reed@google.com>
Fri, 13 Mar 2015 15:48:26 +0000 (08:48 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 13 Mar 2015 15:48:27 +0000 (08:48 -0700)
patch from issue 999963005 at patchset 1 (http://crrev.com/999963005#ps1)

BUG=skia:3527

Review URL: https://codereview.chromium.org/1008883002

src/core/SkRegion_path.cpp
tests/CanvasTest.cpp
tests/RegionTest.cpp

index e9224d8..5b665d4 100644 (file)
@@ -268,7 +268,7 @@ static unsigned verb_to_max_edges(unsigned verb) {
     return gPathVerbToMaxEdges[verb];
 }
 
-
+// If returns 0, ignore itop and ibot
 static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
     SkPath::Iter    iter(path, true);
     SkPoint         pts[4];
@@ -298,13 +298,24 @@ static int count_path_runtype_values(const SkPath& path, int* itop, int* ibot) {
             }
         }
     }
-    SkASSERT(top <= bot);
+    if (0 == maxEdges) {
+        return 0;   // we have only moves+closes
+    }
 
+    SkASSERT(top <= bot);
     *itop = SkScalarRoundToInt(top);
     *ibot = SkScalarRoundToInt(bot);
     return maxEdges;
 }
 
+static bool check_inverse_on_empty_return(SkRegion* dst, const SkPath& path, const SkRegion& clip) {
+    if (path.isInverseFillType()) {
+        return dst->set(clip);
+    } else {
+        return dst->setEmpty();
+    }
+}
+
 bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
     SkDEBUGCODE(this->validate();)
 
@@ -313,26 +324,24 @@ bool SkRegion::setPath(const SkPath& path, const SkRegion& clip) {
     }
 
     if (path.isEmpty()) {
-        if (path.isInverseFillType()) {
-            return this->set(clip);
-        } else {
-            return this->setEmpty();
-        }
+        return check_inverse_on_empty_return(this, path, clip);
     }
 
     //  compute worst-case rgn-size for the path
     int pathTop, pathBot;
     int pathTransitions = count_path_runtype_values(path, &pathTop, &pathBot);
-    int clipTop, clipBot;
-    int clipTransitions;
+    if (0 == pathTransitions) {
+        return check_inverse_on_empty_return(this, path, clip);
+    }
 
-    clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
+    int clipTop, clipBot;
+    int clipTransitions = clip.count_runtype_values(&clipTop, &clipBot);
 
     int top = SkMax32(pathTop, clipTop);
     int bot = SkMin32(pathBot, clipBot);
-
-    if (top >= bot)
-        return this->setEmpty();
+    if (top >= bot) {
+        return check_inverse_on_empty_return(this, path, clip);
+    }
 
     SkRgnBuilder builder;
 
index 98cfbc1..23d4983 100644 (file)
@@ -747,3 +747,19 @@ DEF_TEST(Canvas_SaveState, reporter) {
     canvas.restore();
     REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
 }
+
+DEF_TEST(Canvas_ClipEmptyPath, reporter) {
+    SkCanvas canvas(10, 10);
+    canvas.save();
+    SkPath path;
+    canvas.clipPath(path);
+    canvas.restore();
+    canvas.save();
+    path.moveTo(5, 5);
+    canvas.clipPath(path);
+    canvas.restore();
+    canvas.save();
+    path.moveTo(7, 7);
+    canvas.clipPath(path);  // should not assert here
+    canvas.restore();
+}
index ae58ae6..acb8180 100644 (file)
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "SkPath.h"
 #include "SkRandom.h"
 #include "SkRegion.h"
 #include "Test.h"
@@ -91,6 +92,13 @@ static void test_empties(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, !empty.contains(empty2));
     REPORTER_ASSERT(reporter, !valid.contains(empty));
     REPORTER_ASSERT(reporter, !empty.contains(valid));
+
+    SkPath emptyPath;
+    emptyPath.moveTo(1, 5);
+    emptyPath.close();
+    SkRegion openClip;
+    openClip.setRect(-16000, -16000, 16000, 16000);
+    empty.setPath(emptyPath, openClip);  // should not assert
 }
 
 enum {