Fix for out-of-bounds intersection (found by fuzzer).
authorsenorblanco <senorblanco@chromium.org>
Mon, 2 Mar 2015 17:34:13 +0000 (09:34 -0800)
committerCommit bot <commit-bot@chromium.org>
Mon, 2 Mar 2015 17:34:13 +0000 (09:34 -0800)
Sometimes, the intersection returned by check_intersection() is
out-of-bounds for both edges (above both tops or below both bottoms)
due to floating-point inaccuracy. This causes split_edge() to create a
tiny negative-length edge on one side (which would then assert).
Although we could safely remove this assert and allow the negative
length edge to be removed, it's faster/safer to simply avoid its
creation in the first place by adjusting one edge to the other edge's
endpoint.

Added a new unit test to exercise this case.

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

src/gpu/GrTessellatingPathRenderer.cpp
tests/TessellatingPathRendererTests.cpp

index be28a69..a9ae6fa 100644 (file)
@@ -958,13 +958,19 @@ void split_edge(Edge* edge, Vertex* v, Edge** activeEdges, SkChunkAlloc& alloc)
     LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
         edge->fTop->fID, edge->fBottom->fID,
         v->fID, v->fPoint.fX, v->fPoint.fY);
-    Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc);
-    insert_edge_below(newEdge, v);
-    insert_edge_above(newEdge, edge->fBottom);
-    set_bottom(edge, v, activeEdges);
-    cleanup_active_edges(edge, activeEdges, alloc);
-    fix_active_state(newEdge, activeEdges);
-    merge_collinear_edges(newEdge, activeEdges);
+    if (sweep_lt(v->fPoint, edge->fTop->fPoint)) {
+        set_top(edge, v, activeEdges);
+    } else if (sweep_gt(v->fPoint, edge->fBottom->fPoint)) {
+        set_bottom(edge, v, activeEdges);
+    } else {
+        Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc);
+        insert_edge_below(newEdge, v);
+        insert_edge_above(newEdge, edge->fBottom);
+        set_bottom(edge, v, activeEdges);
+        cleanup_active_edges(edge, activeEdges, alloc);
+        fix_active_state(newEdge, activeEdges);
+        merge_collinear_edges(newEdge, activeEdges);
+    }
 }
 
 void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, SkChunkAlloc& alloc) {
index 1625bf2..0635e7f 100644 (file)
@@ -220,6 +220,16 @@ static SkPath create_path_14() {
     return path;
 }
 
+static SkPath create_path_15() {
+    SkPath path;
+    path.moveTo(    0.0f,   0.0f);
+    path.lineTo(10000.0f,   0.0f);
+    path.lineTo(    0.0f,  -1.0f);
+    path.lineTo(10000.0f,   0.000001f);
+    path.lineTo(    0.0f, -30.0f);
+    return path;
+}
+
 static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, const SkPath& path) {
     GrTessellatingPathRenderer tess;
     GrPipelineBuilder pipelineBuilder;
@@ -259,5 +269,6 @@ DEF_GPUTEST(TessellatingPathRendererTests, reporter, factory) {
     test_path(dt, rt, create_path_12());
     test_path(dt, rt, create_path_13());
     test_path(dt, rt, create_path_14());
+    test_path(dt, rt, create_path_15());
 }
 #endif