GrTessellator: fix for three edges becoming collinear after splitting.
In rare cases, a single edge can become collinear with two adjacent neighbour edges after it's split. The solution is to continue to merge until no collinear edges are found. BUG=722000 Change-Id: Ia5dd212b7acfb40ed1d6c74ebfa9e4a4746fe40a Reviewed-on: https://skia-review.googlesource.com/17963 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
parent
506262665c
commit
6eca90fea6
@ -959,20 +959,27 @@ void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparato
|
||||
}
|
||||
|
||||
void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) {
|
||||
if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
|
||||
!edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
|
||||
merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c);
|
||||
} else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
|
||||
!edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
|
||||
merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c);
|
||||
}
|
||||
if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
|
||||
!edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
|
||||
merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c);
|
||||
} else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
|
||||
!edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
|
||||
merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c);
|
||||
for (;;) {
|
||||
if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
|
||||
!edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
|
||||
merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c);
|
||||
} else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
|
||||
!edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
|
||||
merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c);
|
||||
} else if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
|
||||
!edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
|
||||
merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c);
|
||||
} else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
|
||||
!edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
|
||||
merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SkASSERT(!edge->fPrevEdgeAbove || edge->fPrevEdgeAbove->isLeftOf(edge->fTop));
|
||||
SkASSERT(!edge->fPrevEdgeBelow || edge->fPrevEdgeBelow->isLeftOf(edge->fBottom));
|
||||
SkASSERT(!edge->fNextEdgeAbove || edge->fNextEdgeAbove->isRightOf(edge->fTop));
|
||||
SkASSERT(!edge->fNextEdgeBelow || edge->fNextEdgeBelow->isRightOf(edge->fBottom));
|
||||
}
|
||||
|
||||
void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc);
|
||||
|
@ -275,6 +275,45 @@ static SkPath create_path_18() {
|
||||
return path;
|
||||
}
|
||||
|
||||
// Exercises the case where an edge becomes collinear with *two* of its
|
||||
// adjacent neighbour edges after splitting.
|
||||
// This is a reduction from
|
||||
// http://mooooo.ooo/chebyshev-sine-approximation/horner_ulp.svg
|
||||
static SkPath create_path_19() {
|
||||
SkPath path;
|
||||
path.moveTo( 351.99298095703125, 348.23046875);
|
||||
path.lineTo( 351.91876220703125, 347.33984375);
|
||||
path.lineTo( 351.91876220703125, 346.1953125);
|
||||
path.lineTo( 351.90313720703125, 347.734375);
|
||||
path.lineTo( 351.90313720703125, 346.1328125);
|
||||
path.lineTo( 351.87579345703125, 347.93359375);
|
||||
path.lineTo( 351.87579345703125, 345.484375);
|
||||
path.lineTo( 351.86407470703125, 347.7890625);
|
||||
path.lineTo( 351.86407470703125, 346.2109375);
|
||||
path.lineTo( 351.84844970703125, 347.63763427734375);
|
||||
path.lineTo( 351.84454345703125, 344.19232177734375);
|
||||
path.lineTo( 351.78204345703125, 346.9483642578125);
|
||||
path.lineTo( 351.758636474609375, 347.18310546875);
|
||||
path.lineTo( 351.75469970703125, 346.75);
|
||||
path.lineTo( 351.75469970703125, 345.46875);
|
||||
path.lineTo( 352.5546875, 345.46875);
|
||||
path.lineTo( 352.55078125, 347.01953125);
|
||||
path.lineTo( 351.75079345703125, 347.02313232421875);
|
||||
path.lineTo( 351.74688720703125, 346.15203857421875);
|
||||
path.lineTo( 351.74688720703125, 347.646148681640625);
|
||||
path.lineTo( 352.5390625, 346.94140625);
|
||||
path.lineTo( 351.73907470703125, 346.94268798828125);
|
||||
path.lineTo( 351.73516845703125, 344.48565673828125);
|
||||
path.lineTo( 352.484375, 346.73828125);
|
||||
path.lineTo( 351.68438720703125, 346.7401123046875);
|
||||
path.lineTo( 352.4765625, 346.546875);
|
||||
path.lineTo( 351.67657470703125, 346.54937744140625);
|
||||
path.lineTo( 352.47265625, 346.75390625);
|
||||
path.lineTo( 351.67266845703125, 346.756622314453125);
|
||||
path.lineTo( 351.66876220703125, 345.612091064453125);
|
||||
return path;
|
||||
}
|
||||
|
||||
static sk_sp<GrFragmentProcessor> create_linear_gradient_processor(GrContext* ctx) {
|
||||
SkPoint pts[2] = { {0, 0}, {1, 1} };
|
||||
SkColor colors[2] = { SK_ColorGREEN, SK_ColorBLUE };
|
||||
@ -350,5 +389,6 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(TessellatingPathRendererTests, reporter, ctxInfo) {
|
||||
sk_sp<GrFragmentProcessor> fp(create_linear_gradient_processor(ctx));
|
||||
test_path(ctx, rtc.get(), create_path_17(), nonInvertibleMatrix, GrAAType::kCoverage, fp);
|
||||
test_path(ctx, rtc.get(), create_path_18());
|
||||
test_path(ctx, rtc.get(), create_path_19());
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user