aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/gpu/GrTessellator.cpp36
-rw-r--r--tests/TessellatingPathRendererTests.cpp25
2 files changed, 43 insertions, 18 deletions
diff --git a/src/gpu/GrTessellator.cpp b/src/gpu/GrTessellator.cpp
index 4d3c1eb0ee..a4797665dd 100644
--- a/src/gpu/GrTessellator.cpp
+++ b/src/gpu/GrTessellator.cpp
@@ -1131,17 +1131,6 @@ void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c,
mesh->remove(src);
}
-bool out_of_range_and_collinear(const SkPoint& p, Edge* edge, Comparator& c) {
- if (c.sweep_lt(p, edge->fTop->fPoint) &&
- !Line(p, edge->fBottom->fPoint).dist(edge->fTop->fPoint)) {
- return true;
- } else if (c.sweep_lt(edge->fBottom->fPoint, p) &&
- !Line(edge->fTop->fPoint, p).dist(edge->fBottom->fPoint)) {
- return true;
- }
- return false;
-}
-
Vertex* create_sorted_vertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
Vertex* reference, Comparator& c, SkArenaAlloc& alloc) {
Vertex* prevV = reference;
@@ -1174,6 +1163,15 @@ Vertex* create_sorted_vertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
return v;
}
+// If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary
+// sort criterion, it may not be possible to split correctly, since there is no point which is
+// below the top and above the bottom. This function detects that case.
+bool nearly_flat(Comparator& c, Edge* edge) {
+ SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint;
+ float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY;
+ return fabs(primaryDiff) < std::numeric_limits<float>::epsilon();
+}
+
bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
if (!edge || !other) {
@@ -1182,12 +1180,6 @@ bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vert
SkPoint p;
uint8_t alpha;
if (edge->intersect(*other, &p, &alpha) && p.isFinite()) {
- // Ignore any out-of-range intersections which are also collinear,
- // since the resulting edges would cancel each other out by merging.
- if (out_of_range_and_collinear(p, edge, c) ||
- out_of_range_and_collinear(p, other, c)) {
- return false;
- }
Vertex* v;
LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Vertex* top = *current;
@@ -1196,7 +1188,15 @@ bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vert
while (top && c.sweep_lt(p, top->fPoint)) {
top = top->fPrev;
}
- if (p == edge->fTop->fPoint) {
+ if (c.sweep_lt(p, edge->fTop->fPoint) && !nearly_flat(c, edge)) {
+ v = edge->fTop;
+ } else if (c.sweep_lt(edge->fBottom->fPoint, p) && !nearly_flat(c, edge)) {
+ v = edge->fBottom;
+ } else if (c.sweep_lt(p, other->fTop->fPoint) && !nearly_flat(c, other)) {
+ v = other->fTop;
+ } else if (c.sweep_lt(other->fBottom->fPoint, p) && !nearly_flat(c, other)) {
+ v = other->fBottom;
+ } else if (p == edge->fTop->fPoint) {
v = edge->fTop;
} else if (p == edge->fBottom->fPoint) {
v = edge->fBottom;
diff --git a/tests/TessellatingPathRendererTests.cpp b/tests/TessellatingPathRendererTests.cpp
index 00f43985dd..086d2e546c 100644
--- a/tests/TessellatingPathRendererTests.cpp
+++ b/tests/TessellatingPathRendererTests.cpp
@@ -502,6 +502,29 @@ static SkPath create_path_33() {
return path;
}
+// From crbug.com/844873. Hangs repeatedly splitting alternate vertices.
+static SkPath create_path_34() {
+ SkPath path;
+ path.moveTo(10, -1e+20f);
+ path.lineTo(11, 25000);
+ path.lineTo(10, 25000);
+ path.lineTo(11, 25010);
+ return path;
+}
+
+// Reduction from circular_arcs_stroke_and_fill_round GM which
+// repeatedly splits on the opposite edge from case 34 above.
+static SkPath create_path_35() {
+ SkPath path;
+ path.moveTo( 16.25, 26.495191574096679688);
+ path.lineTo(32.420825958251953125, 37.377376556396484375);
+ path.lineTo(25.176382064819335938, 39.31851959228515625);
+ path.moveTo( 20, 20);
+ path.lineTo(28.847436904907226562, 37.940830230712890625);
+ path.lineTo(25.17638397216796875, 39.31851959228515625);
+ return path;
+}
+
static std::unique_ptr<GrFragmentProcessor> create_linear_gradient_processor(GrContext* ctx) {
SkPoint pts[2] = { {0, 0}, {1, 1} };
@@ -595,5 +618,7 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(TessellatingPathRendererTests, reporter, ctxInfo) {
test_path(ctx, rtc.get(), create_path_31(), SkMatrix(), GrAAType::kCoverage);
test_path(ctx, rtc.get(), create_path_32());
test_path(ctx, rtc.get(), create_path_33());
+ test_path(ctx, rtc.get(), create_path_34());
+ test_path(ctx, rtc.get(), create_path_35());
}
#endif