Fix for out-of-bounds intersection (found by fuzzer).

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
This commit is contained in:
senorblanco 2015-03-02 09:34:13 -08:00 committed by Commit bot
parent b3310c2221
commit a2b6d28755
2 changed files with 24 additions and 7 deletions

View File

@ -958,6 +958,11 @@ void split_edge(Edge* edge, Vertex* v, Edge** activeEdges, SkChunkAlloc& alloc)
LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n", LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID, edge->fBottom->fID,
v->fID, v->fPoint.fX, v->fPoint.fY); v->fID, v->fPoint.fX, v->fPoint.fY);
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); Edge* newEdge = ALLOC_NEW(Edge, (v, edge->fBottom, edge->fWinding), alloc);
insert_edge_below(newEdge, v); insert_edge_below(newEdge, v);
insert_edge_above(newEdge, edge->fBottom); insert_edge_above(newEdge, edge->fBottom);
@ -966,6 +971,7 @@ void split_edge(Edge* edge, Vertex* v, Edge** activeEdges, SkChunkAlloc& alloc)
fix_active_state(newEdge, activeEdges); fix_active_state(newEdge, activeEdges);
merge_collinear_edges(newEdge, activeEdges); merge_collinear_edges(newEdge, activeEdges);
} }
}
void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, SkChunkAlloc& alloc) { void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, SkChunkAlloc& alloc) {
LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY, LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY,

View File

@ -220,6 +220,16 @@ static SkPath create_path_14() {
return path; 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) { static void test_path(GrDrawTarget* dt, GrRenderTarget* rt, const SkPath& path) {
GrTessellatingPathRenderer tess; GrTessellatingPathRenderer tess;
GrPipelineBuilder pipelineBuilder; GrPipelineBuilder pipelineBuilder;
@ -259,5 +269,6 @@ DEF_GPUTEST(TessellatingPathRendererTests, reporter, factory) {
test_path(dt, rt, create_path_12()); test_path(dt, rt, create_path_12());
test_path(dt, rt, create_path_13()); test_path(dt, rt, create_path_13());
test_path(dt, rt, create_path_14()); test_path(dt, rt, create_path_14());
test_path(dt, rt, create_path_15());
} }
#endif #endif