1 | /* |
2 | * Copyright 2015 Google Inc. |
3 | * |
4 | * Use of this source code is governed by a BSD-style license that can be |
5 | * found in the LICENSE file. |
6 | */ |
7 | |
8 | #include "src/gpu/GrTriangulator.h" |
9 | |
10 | #include "src/gpu/GrEagerVertexAllocator.h" |
11 | #include "src/gpu/GrVertexWriter.h" |
12 | #include "src/gpu/geometry/GrPathUtils.h" |
13 | |
14 | #include "include/core/SkPath.h" |
15 | #include "src/core/SkArenaAlloc.h" |
16 | #include "src/core/SkGeometry.h" |
17 | #include "src/core/SkPointPriv.h" |
18 | |
19 | #include <algorithm> |
20 | #include <cstdio> |
21 | #include <queue> |
22 | #include <unordered_map> |
23 | #include <utility> |
24 | |
25 | /* |
26 | * There are six stages to the basic algorithm: |
27 | * |
28 | * 1) Linearize the path contours into piecewise linear segments (path_to_contours()). |
29 | * 2) Build a mesh of edges connecting the vertices (build_edges()). |
30 | * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()). |
31 | * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()). |
32 | * 5) Tessellate the simplified mesh into monotone polygons (tessellate()). |
33 | * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()). |
34 | * |
35 | * For screenspace antialiasing, the algorithm is modified as follows: |
36 | * |
37 | * Run steps 1-5 above to produce polygons. |
38 | * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()). |
39 | * 5c) Simplify boundaries to remove "pointy" vertices that cause inversions (simplify_boundary()). |
40 | * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find |
41 | * new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a new |
42 | * antialiased mesh from those vertices (stroke_boundary()). |
43 | * Run steps 3-6 above on the new mesh, and produce antialiased triangles. |
44 | * |
45 | * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list |
46 | * of vertices (and the necessity of inserting new vertices on intersection). |
47 | * |
48 | * Stages (4) and (5) use an active edge list -- a list of all edges for which the |
49 | * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted |
50 | * left-to-right based on the point where both edges are active (when both top vertices |
51 | * have been seen, so the "lower" top vertex of the two). If the top vertices are equal |
52 | * (shared), it's sorted based on the last point where both edges are active, so the |
53 | * "upper" bottom vertex. |
54 | * |
55 | * The most complex step is the simplification (4). It's based on the Bentley-Ottman |
56 | * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are |
57 | * not exact and may violate the mesh topology or active edge list ordering. We |
58 | * accommodate this by adjusting the topology of the mesh and AEL to match the intersection |
59 | * points. This occurs in two ways: |
60 | * |
61 | * A) Intersections may cause a shortened edge to no longer be ordered with respect to its |
62 | * neighbouring edges at the top or bottom vertex. This is handled by merging the |
63 | * edges (merge_collinear_edges()). |
64 | * B) Intersections may cause an edge to violate the left-to-right ordering of the |
65 | * active edge list. This is handled by detecting potential violations and rewinding |
66 | * the active edge list to the vertex before they occur (rewind() during merging, |
67 | * rewind_if_necessary() during splitting). |
68 | * |
69 | * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and |
70 | * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it |
71 | * currently uses a linked list for the active edge list, rather than a 2-3 tree as the |
72 | * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also |
73 | * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N) |
74 | * insertions and removals was greater than the cost of infrequent O(N) lookups with the |
75 | * linked list implementation. With the latter, all removals are O(1), and most insertions |
76 | * are O(1), since we know the adjacent edge in the active edge list based on the topology. |
77 | * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less |
78 | * frequent. There may be other data structures worth investigating, however. |
79 | * |
80 | * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the |
81 | * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y |
82 | * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall, |
83 | * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so |
84 | * that the "left" and "right" orientation in the code remains correct (edges to the left are |
85 | * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90 |
86 | * degrees counterclockwise, rather that transposing. |
87 | */ |
88 | |
89 | #define LOGGING_ENABLED 0 |
90 | |
91 | #if LOGGING_ENABLED |
92 | #define TESS_LOG printf |
93 | #else |
94 | #define TESS_LOG(...) |
95 | #endif |
96 | |
97 | namespace { |
98 | |
99 | using GrTriangulator::Mode; |
100 | |
101 | const int kArenaChunkSize = 16 * 1024; |
102 | const float kCosMiterAngle = 0.97f; // Corresponds to an angle of ~14 degrees. |
103 | |
104 | struct Vertex; |
105 | struct Edge; |
106 | struct Event; |
107 | struct Poly; |
108 | |
109 | template <class T, T* T::*Prev, T* T::*Next> |
110 | void list_insert(T* t, T* prev, T* next, T** head, T** tail) { |
111 | t->*Prev = prev; |
112 | t->*Next = next; |
113 | if (prev) { |
114 | prev->*Next = t; |
115 | } else if (head) { |
116 | *head = t; |
117 | } |
118 | if (next) { |
119 | next->*Prev = t; |
120 | } else if (tail) { |
121 | *tail = t; |
122 | } |
123 | } |
124 | |
125 | template <class T, T* T::*Prev, T* T::*Next> |
126 | void list_remove(T* t, T** head, T** tail) { |
127 | if (t->*Prev) { |
128 | t->*Prev->*Next = t->*Next; |
129 | } else if (head) { |
130 | *head = t->*Next; |
131 | } |
132 | if (t->*Next) { |
133 | t->*Next->*Prev = t->*Prev; |
134 | } else if (tail) { |
135 | *tail = t->*Prev; |
136 | } |
137 | t->*Prev = t->*Next = nullptr; |
138 | } |
139 | |
140 | /** |
141 | * Vertices are used in three ways: first, the path contours are converted into a |
142 | * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices |
143 | * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing |
144 | * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid |
145 | * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of |
146 | * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since |
147 | * an individual Vertex from the path mesh may belong to multiple |
148 | * MonotonePolys, so the original Vertices cannot be re-used. |
149 | */ |
150 | |
151 | struct Vertex { |
152 | Vertex(const SkPoint& point, uint8_t alpha) |
153 | : fPoint(point), fPrev(nullptr), fNext(nullptr) |
154 | , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) |
155 | , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) |
156 | , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr) |
157 | , fPartner(nullptr) |
158 | , fAlpha(alpha) |
159 | , fSynthetic(false) |
160 | #if LOGGING_ENABLED |
161 | , fID (-1.0f) |
162 | #endif |
163 | {} |
164 | SkPoint fPoint; // Vertex position |
165 | Vertex* fPrev; // Linked list of contours, then Y-sorted vertices. |
166 | Vertex* fNext; // " |
167 | Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. |
168 | Edge* fLastEdgeAbove; // " |
169 | Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. |
170 | Edge* fLastEdgeBelow; // " |
171 | Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex. |
172 | Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex. |
173 | Vertex* fPartner; // Corresponding inner or outer vertex (for AA). |
174 | uint8_t fAlpha; |
175 | bool fSynthetic; // Is this a synthetic vertex? |
176 | #if LOGGING_ENABLED |
177 | float fID; // Identifier used for logging. |
178 | #endif |
179 | }; |
180 | |
181 | /***************************************************************************************/ |
182 | |
183 | typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); |
184 | |
185 | bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) { |
186 | return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY); |
187 | } |
188 | |
189 | bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) { |
190 | return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX); |
191 | } |
192 | |
193 | struct Comparator { |
194 | enum class Direction { kVertical, kHorizontal }; |
195 | Comparator(Direction direction) : fDirection(direction) {} |
196 | bool sweep_lt(const SkPoint& a, const SkPoint& b) const { |
197 | return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b); |
198 | } |
199 | Direction fDirection; |
200 | }; |
201 | |
202 | inline void* emit_vertex(Vertex* v, bool emitCoverage, void* data) { |
203 | GrVertexWriter verts{data}; |
204 | verts.write(v->fPoint); |
205 | |
206 | if (emitCoverage) { |
207 | verts.write(GrNormalizeByteToFloat(v->fAlpha)); |
208 | } |
209 | |
210 | return verts.fPtr; |
211 | } |
212 | |
213 | void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, bool emitCoverage, void* data) { |
214 | TESS_LOG("emit_triangle %g (%g, %g) %d\n" , v0->fID, v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha); |
215 | TESS_LOG(" %g (%g, %g) %d\n" , v1->fID, v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha); |
216 | TESS_LOG(" %g (%g, %g) %d\n" , v2->fID, v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha); |
217 | #if TESSELLATOR_WIREFRAME |
218 | data = emit_vertex(v0, emitCoverage, data); |
219 | data = emit_vertex(v1, emitCoverage, data); |
220 | data = emit_vertex(v1, emitCoverage, data); |
221 | data = emit_vertex(v2, emitCoverage, data); |
222 | data = emit_vertex(v2, emitCoverage, data); |
223 | data = emit_vertex(v0, emitCoverage, data); |
224 | #else |
225 | data = emit_vertex(v0, emitCoverage, data); |
226 | data = emit_vertex(v1, emitCoverage, data); |
227 | data = emit_vertex(v2, emitCoverage, data); |
228 | #endif |
229 | return data; |
230 | } |
231 | |
232 | struct VertexList { |
233 | VertexList() : fHead(nullptr), fTail(nullptr) {} |
234 | VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {} |
235 | Vertex* fHead; |
236 | Vertex* fTail; |
237 | void insert(Vertex* v, Vertex* prev, Vertex* next) { |
238 | list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail); |
239 | } |
240 | void append(Vertex* v) { |
241 | insert(v, fTail, nullptr); |
242 | } |
243 | void append(const VertexList& list) { |
244 | if (!list.fHead) { |
245 | return; |
246 | } |
247 | if (fTail) { |
248 | fTail->fNext = list.fHead; |
249 | list.fHead->fPrev = fTail; |
250 | } else { |
251 | fHead = list.fHead; |
252 | } |
253 | fTail = list.fTail; |
254 | } |
255 | void prepend(Vertex* v) { |
256 | insert(v, nullptr, fHead); |
257 | } |
258 | void remove(Vertex* v) { |
259 | list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail); |
260 | } |
261 | void close() { |
262 | if (fHead && fTail) { |
263 | fTail->fNext = fHead; |
264 | fHead->fPrev = fTail; |
265 | } |
266 | } |
267 | }; |
268 | |
269 | // Round to nearest quarter-pixel. This is used for screenspace tessellation. |
270 | |
271 | inline void round(SkPoint* p) { |
272 | p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); |
273 | p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); |
274 | } |
275 | |
276 | inline SkScalar double_to_clamped_scalar(double d) { |
277 | return SkDoubleToScalar(std::min((double) SK_ScalarMax, std::max(d, (double) -SK_ScalarMax))); |
278 | } |
279 | |
280 | // A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line. |
281 | struct Line { |
282 | Line(double a, double b, double c) : fA(a), fB(b), fC(c) {} |
283 | Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {} |
284 | Line(const SkPoint& p, const SkPoint& q) |
285 | : fA(static_cast<double>(q.fY) - p.fY) // a = dY |
286 | , fB(static_cast<double>(p.fX) - q.fX) // b = -dX |
287 | , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p) |
288 | static_cast<double>(p.fX) * q.fY) {} |
289 | double dist(const SkPoint& p) const { |
290 | return fA * p.fX + fB * p.fY + fC; |
291 | } |
292 | Line operator*(double v) const { |
293 | return Line(fA * v, fB * v, fC * v); |
294 | } |
295 | double magSq() const { |
296 | return fA * fA + fB * fB; |
297 | } |
298 | void normalize() { |
299 | double len = sqrt(this->magSq()); |
300 | if (len == 0.0) { |
301 | return; |
302 | } |
303 | double scale = 1.0f / len; |
304 | fA *= scale; |
305 | fB *= scale; |
306 | fC *= scale; |
307 | } |
308 | bool nearParallel(const Line& o) const { |
309 | return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001; |
310 | } |
311 | |
312 | // Compute the intersection of two (infinite) Lines. |
313 | bool intersect(const Line& other, SkPoint* point) const { |
314 | double denom = fA * other.fB - fB * other.fA; |
315 | if (denom == 0.0) { |
316 | return false; |
317 | } |
318 | double scale = 1.0 / denom; |
319 | point->fX = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale); |
320 | point->fY = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale); |
321 | round(point); |
322 | return point->isFinite(); |
323 | } |
324 | double fA, fB, fC; |
325 | }; |
326 | |
327 | /** |
328 | * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and |
329 | * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf(). |
330 | * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating |
331 | * point). For speed, that case is only tested by the callers that require it (e.g., |
332 | * rewind_if_necessary()). Edges also handle checking for intersection with other edges. |
333 | * Currently, this converts the edges to the parametric form, in order to avoid doing a division |
334 | * until an intersection has been confirmed. This is slightly slower in the "found" case, but |
335 | * a lot faster in the "not found" case. |
336 | * |
337 | * The coefficients of the line equation stored in double precision to avoid catastrphic |
338 | * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is |
339 | * correct in float, since it's a polynomial of degree 2. The intersect() function, being |
340 | * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its |
341 | * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of |
342 | * this file). |
343 | */ |
344 | |
345 | struct Edge { |
346 | enum class Type { kInner, kOuter, kConnector }; |
347 | Edge(Vertex* top, Vertex* bottom, int winding, Type type) |
348 | : fWinding(winding) |
349 | , fTop(top) |
350 | , fBottom(bottom) |
351 | , fType(type) |
352 | , fLeft(nullptr) |
353 | , fRight(nullptr) |
354 | , fPrevEdgeAbove(nullptr) |
355 | , fNextEdgeAbove(nullptr) |
356 | , fPrevEdgeBelow(nullptr) |
357 | , fNextEdgeBelow(nullptr) |
358 | , fLeftPoly(nullptr) |
359 | , fRightPoly(nullptr) |
360 | , fLeftPolyPrev(nullptr) |
361 | , fLeftPolyNext(nullptr) |
362 | , fRightPolyPrev(nullptr) |
363 | , fRightPolyNext(nullptr) |
364 | , fUsedInLeftPoly(false) |
365 | , fUsedInRightPoly(false) |
366 | , fLine(top, bottom) { |
367 | } |
368 | int fWinding; // 1 == edge goes downward; -1 = edge goes upward. |
369 | Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). |
370 | Vertex* fBottom; // The bottom vertex in vertex-sort-order. |
371 | Type fType; |
372 | Edge* fLeft; // The linked list of edges in the active edge list. |
373 | Edge* fRight; // " |
374 | Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". |
375 | Edge* fNextEdgeAbove; // " |
376 | Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below". |
377 | Edge* fNextEdgeBelow; // " |
378 | Poly* fLeftPoly; // The Poly to the left of this edge, if any. |
379 | Poly* fRightPoly; // The Poly to the right of this edge, if any. |
380 | Edge* fLeftPolyPrev; |
381 | Edge* fLeftPolyNext; |
382 | Edge* fRightPolyPrev; |
383 | Edge* fRightPolyNext; |
384 | bool fUsedInLeftPoly; |
385 | bool fUsedInRightPoly; |
386 | Line fLine; |
387 | double dist(const SkPoint& p) const { |
388 | return fLine.dist(p); |
389 | } |
390 | bool isRightOf(Vertex* v) const { |
391 | return fLine.dist(v->fPoint) < 0.0; |
392 | } |
393 | bool isLeftOf(Vertex* v) const { |
394 | return fLine.dist(v->fPoint) > 0.0; |
395 | } |
396 | void recompute() { |
397 | fLine = Line(fTop, fBottom); |
398 | } |
399 | bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const { |
400 | TESS_LOG("intersecting %g -> %g with %g -> %g\n" , |
401 | fTop->fID, fBottom->fID, other.fTop->fID, other.fBottom->fID); |
402 | if (fTop == other.fTop || fBottom == other.fBottom) { |
403 | return false; |
404 | } |
405 | double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA; |
406 | if (denom == 0.0) { |
407 | return false; |
408 | } |
409 | double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX; |
410 | double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY; |
411 | double sNumer = dy * other.fLine.fB + dx * other.fLine.fA; |
412 | double tNumer = dy * fLine.fB + dx * fLine.fA; |
413 | // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. |
414 | // This saves us doing the divide below unless absolutely necessary. |
415 | if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom) |
416 | : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) { |
417 | return false; |
418 | } |
419 | double s = sNumer / denom; |
420 | SkASSERT(s >= 0.0 && s <= 1.0); |
421 | p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB); |
422 | p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA); |
423 | if (alpha) { |
424 | if (fType == Type::kConnector) { |
425 | *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha; |
426 | } else if (other.fType == Type::kConnector) { |
427 | double t = tNumer / denom; |
428 | *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha; |
429 | } else if (fType == Type::kOuter && other.fType == Type::kOuter) { |
430 | *alpha = 0; |
431 | } else { |
432 | *alpha = 255; |
433 | } |
434 | } |
435 | return true; |
436 | } |
437 | }; |
438 | |
439 | struct SSEdge; |
440 | |
441 | struct SSVertex { |
442 | SSVertex(Vertex* v) : fVertex(v), fPrev(nullptr), fNext(nullptr) {} |
443 | Vertex* fVertex; |
444 | SSEdge* fPrev; |
445 | SSEdge* fNext; |
446 | }; |
447 | |
448 | struct SSEdge { |
449 | SSEdge(Edge* edge, SSVertex* prev, SSVertex* next) |
450 | : fEdge(edge), fEvent(nullptr), fPrev(prev), fNext(next) { |
451 | } |
452 | Edge* fEdge; |
453 | Event* fEvent; |
454 | SSVertex* fPrev; |
455 | SSVertex* fNext; |
456 | }; |
457 | |
458 | typedef std::unordered_map<Vertex*, SSVertex*> SSVertexMap; |
459 | typedef std::vector<SSEdge*> SSEdgeList; |
460 | |
461 | struct EdgeList { |
462 | EdgeList() : fHead(nullptr), fTail(nullptr) {} |
463 | Edge* fHead; |
464 | Edge* fTail; |
465 | void insert(Edge* edge, Edge* prev, Edge* next) { |
466 | list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail); |
467 | } |
468 | void append(Edge* e) { |
469 | insert(e, fTail, nullptr); |
470 | } |
471 | void remove(Edge* edge) { |
472 | list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail); |
473 | } |
474 | void removeAll() { |
475 | while (fHead) { |
476 | this->remove(fHead); |
477 | } |
478 | } |
479 | void close() { |
480 | if (fHead && fTail) { |
481 | fTail->fRight = fHead; |
482 | fHead->fLeft = fTail; |
483 | } |
484 | } |
485 | bool contains(Edge* edge) const { |
486 | return edge->fLeft || edge->fRight || fHead == edge; |
487 | } |
488 | }; |
489 | |
490 | struct EventList; |
491 | |
492 | struct Event { |
493 | Event(SSEdge* edge, const SkPoint& point, uint8_t alpha) |
494 | : fEdge(edge), fPoint(point), fAlpha(alpha) { |
495 | } |
496 | SSEdge* fEdge; |
497 | SkPoint fPoint; |
498 | uint8_t fAlpha; |
499 | void apply(VertexList* mesh, Comparator& c, EventList* events, SkArenaAlloc& alloc); |
500 | }; |
501 | |
502 | struct EventComparator { |
503 | enum class Op { kLessThan, kGreaterThan }; |
504 | EventComparator(Op op) : fOp(op) {} |
505 | bool operator() (Event* const &e1, Event* const &e2) { |
506 | return fOp == Op::kLessThan ? e1->fAlpha < e2->fAlpha |
507 | : e1->fAlpha > e2->fAlpha; |
508 | } |
509 | Op fOp; |
510 | }; |
511 | |
512 | typedef std::priority_queue<Event*, std::vector<Event*>, EventComparator> EventPQ; |
513 | |
514 | struct EventList : EventPQ { |
515 | EventList(EventComparator comparison) : EventPQ(comparison) { |
516 | } |
517 | }; |
518 | |
519 | void create_event(SSEdge* e, EventList* events, SkArenaAlloc& alloc) { |
520 | Vertex* prev = e->fPrev->fVertex; |
521 | Vertex* next = e->fNext->fVertex; |
522 | if (prev == next || !prev->fPartner || !next->fPartner) { |
523 | return; |
524 | } |
525 | Edge bisector1(prev, prev->fPartner, 1, Edge::Type::kConnector); |
526 | Edge bisector2(next, next->fPartner, 1, Edge::Type::kConnector); |
527 | SkPoint p; |
528 | uint8_t alpha; |
529 | if (bisector1.intersect(bisector2, &p, &alpha)) { |
530 | TESS_LOG("found edge event for %g, %g (original %g -> %g), " |
531 | "will collapse to %g,%g alpha %d\n" , |
532 | prev->fID, next->fID, e->fEdge->fTop->fID, e->fEdge->fBottom->fID, p.fX, p.fY, |
533 | alpha); |
534 | e->fEvent = alloc.make<Event>(e, p, alpha); |
535 | events->push(e->fEvent); |
536 | } |
537 | } |
538 | |
539 | void create_event(SSEdge* edge, Vertex* v, SSEdge* other, Vertex* dest, EventList* events, |
540 | Comparator& c, SkArenaAlloc& alloc) { |
541 | if (!v->fPartner) { |
542 | return; |
543 | } |
544 | Vertex* top = edge->fEdge->fTop; |
545 | Vertex* bottom = edge->fEdge->fBottom; |
546 | if (!top || !bottom ) { |
547 | return; |
548 | } |
549 | Line line = edge->fEdge->fLine; |
550 | line.fC = -(dest->fPoint.fX * line.fA + dest->fPoint.fY * line.fB); |
551 | Edge bisector(v, v->fPartner, 1, Edge::Type::kConnector); |
552 | SkPoint p; |
553 | uint8_t alpha = dest->fAlpha; |
554 | if (line.intersect(bisector.fLine, &p) && !c.sweep_lt(p, top->fPoint) && |
555 | c.sweep_lt(p, bottom->fPoint)) { |
556 | TESS_LOG("found p edge event for %g, %g (original %g -> %g), " |
557 | "will collapse to %g,%g alpha %d\n" , |
558 | dest->fID, v->fID, top->fID, bottom->fID, p.fX, p.fY, alpha); |
559 | edge->fEvent = alloc.make<Event>(edge, p, alpha); |
560 | events->push(edge->fEvent); |
561 | } |
562 | } |
563 | |
564 | /***************************************************************************************/ |
565 | |
566 | struct Poly { |
567 | Poly(Vertex* v, int winding) |
568 | : fFirstVertex(v) |
569 | , fWinding(winding) |
570 | , fHead(nullptr) |
571 | , fTail(nullptr) |
572 | , fNext(nullptr) |
573 | , fPartner(nullptr) |
574 | , fCount(0) |
575 | { |
576 | #if LOGGING_ENABLED |
577 | static int gID = 0; |
578 | fID = gID++; |
579 | TESS_LOG("*** created Poly %d\n" , fID); |
580 | #endif |
581 | } |
582 | typedef enum { kLeft_Side, kRight_Side } Side; |
583 | struct MonotonePoly { |
584 | MonotonePoly(Edge* edge, Side side, int winding) |
585 | : fSide(side) |
586 | , fFirstEdge(nullptr) |
587 | , fLastEdge(nullptr) |
588 | , fPrev(nullptr) |
589 | , fNext(nullptr) |
590 | , fWinding(winding) { |
591 | this->addEdge(edge); |
592 | } |
593 | Side fSide; |
594 | Edge* fFirstEdge; |
595 | Edge* fLastEdge; |
596 | MonotonePoly* fPrev; |
597 | MonotonePoly* fNext; |
598 | int fWinding; |
599 | void addEdge(Edge* edge) { |
600 | if (fSide == kRight_Side) { |
601 | SkASSERT(!edge->fUsedInRightPoly); |
602 | list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>( |
603 | edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge); |
604 | edge->fUsedInRightPoly = true; |
605 | } else { |
606 | SkASSERT(!edge->fUsedInLeftPoly); |
607 | list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>( |
608 | edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge); |
609 | edge->fUsedInLeftPoly = true; |
610 | } |
611 | } |
612 | |
613 | void* emit(bool emitCoverage, void* data) { |
614 | Edge* e = fFirstEdge; |
615 | VertexList vertices; |
616 | vertices.append(e->fTop); |
617 | int count = 1; |
618 | while (e != nullptr) { |
619 | if (kRight_Side == fSide) { |
620 | vertices.append(e->fBottom); |
621 | e = e->fRightPolyNext; |
622 | } else { |
623 | vertices.prepend(e->fBottom); |
624 | e = e->fLeftPolyNext; |
625 | } |
626 | count++; |
627 | } |
628 | Vertex* first = vertices.fHead; |
629 | Vertex* v = first->fNext; |
630 | while (v != vertices.fTail) { |
631 | SkASSERT(v && v->fPrev && v->fNext); |
632 | Vertex* prev = v->fPrev; |
633 | Vertex* curr = v; |
634 | Vertex* next = v->fNext; |
635 | if (count == 3) { |
636 | return this->emitTriangle(prev, curr, next, emitCoverage, data); |
637 | } |
638 | double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX; |
639 | double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY; |
640 | double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX; |
641 | double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY; |
642 | if (ax * by - ay * bx >= 0.0) { |
643 | data = this->emitTriangle(prev, curr, next, emitCoverage, data); |
644 | v->fPrev->fNext = v->fNext; |
645 | v->fNext->fPrev = v->fPrev; |
646 | count--; |
647 | if (v->fPrev == first) { |
648 | v = v->fNext; |
649 | } else { |
650 | v = v->fPrev; |
651 | } |
652 | } else { |
653 | v = v->fNext; |
654 | } |
655 | } |
656 | return data; |
657 | } |
658 | void* emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, bool emitCoverage, |
659 | void* data) const { |
660 | if (fWinding < 0) { |
661 | // Ensure our triangles always wind in the same direction as if the path had been |
662 | // triangulated as a simple fan (a la red book). |
663 | std::swap(prev, next); |
664 | } |
665 | return emit_triangle(next, curr, prev, emitCoverage, data); |
666 | } |
667 | }; |
668 | Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) { |
669 | TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n" , |
670 | e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right" ); |
671 | Poly* partner = fPartner; |
672 | Poly* poly = this; |
673 | if (side == kRight_Side) { |
674 | if (e->fUsedInRightPoly) { |
675 | return this; |
676 | } |
677 | } else { |
678 | if (e->fUsedInLeftPoly) { |
679 | return this; |
680 | } |
681 | } |
682 | if (partner) { |
683 | fPartner = partner->fPartner = nullptr; |
684 | } |
685 | if (!fTail) { |
686 | fHead = fTail = alloc.make<MonotonePoly>(e, side, fWinding); |
687 | fCount += 2; |
688 | } else if (e->fBottom == fTail->fLastEdge->fBottom) { |
689 | return poly; |
690 | } else if (side == fTail->fSide) { |
691 | fTail->addEdge(e); |
692 | fCount++; |
693 | } else { |
694 | e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner); |
695 | fTail->addEdge(e); |
696 | fCount++; |
697 | if (partner) { |
698 | partner->addEdge(e, side, alloc); |
699 | poly = partner; |
700 | } else { |
701 | MonotonePoly* m = alloc.make<MonotonePoly>(e, side, fWinding); |
702 | m->fPrev = fTail; |
703 | fTail->fNext = m; |
704 | fTail = m; |
705 | } |
706 | } |
707 | return poly; |
708 | } |
709 | void* emit(bool emitCoverage, void *data) { |
710 | if (fCount < 3) { |
711 | return data; |
712 | } |
713 | TESS_LOG("emit() %d, size %d\n" , fID, fCount); |
714 | for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) { |
715 | data = m->emit(emitCoverage, data); |
716 | } |
717 | return data; |
718 | } |
719 | Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; } |
720 | Vertex* fFirstVertex; |
721 | int fWinding; |
722 | MonotonePoly* fHead; |
723 | MonotonePoly* fTail; |
724 | Poly* fNext; |
725 | Poly* fPartner; |
726 | int fCount; |
727 | #if LOGGING_ENABLED |
728 | int fID; |
729 | #endif |
730 | }; |
731 | |
732 | /***************************************************************************************/ |
733 | |
734 | bool coincident(const SkPoint& a, const SkPoint& b) { |
735 | return a == b; |
736 | } |
737 | |
738 | Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) { |
739 | Poly* poly = alloc.make<Poly>(v, winding); |
740 | poly->fNext = *head; |
741 | *head = poly; |
742 | return poly; |
743 | } |
744 | |
745 | void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) { |
746 | Vertex* v = alloc.make<Vertex>(p, 255); |
747 | #if LOGGING_ENABLED |
748 | static float gID = 0.0f; |
749 | v->fID = gID++; |
750 | #endif |
751 | contour->append(v); |
752 | } |
753 | |
754 | SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) { |
755 | SkQuadCoeff quad(pts); |
756 | SkPoint p0 = to_point(quad.eval(t - 0.5f * u)); |
757 | SkPoint mid = to_point(quad.eval(t)); |
758 | SkPoint p1 = to_point(quad.eval(t + 0.5f * u)); |
759 | if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) { |
760 | return 0; |
761 | } |
762 | return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1); |
763 | } |
764 | |
765 | void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour, |
766 | SkArenaAlloc& alloc) { |
767 | SkQuadCoeff quad(pts); |
768 | Sk2s aa = quad.fA * quad.fA; |
769 | SkScalar denom = 2.0f * (aa[0] + aa[1]); |
770 | Sk2s ab = quad.fA * quad.fB; |
771 | SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f; |
772 | int nPoints = 1; |
773 | SkScalar u = 1.0f; |
774 | // Test possible subdivision values only at the point of maximum curvature. |
775 | // If it passes the flatness metric there, it'll pass everywhere. |
776 | while (nPoints < GrPathUtils::kMaxPointsPerCurve) { |
777 | u = 1.0f / nPoints; |
778 | if (quad_error_at(pts, t, u) < toleranceSqd) { |
779 | break; |
780 | } |
781 | nPoints++; |
782 | } |
783 | for (int j = 1; j <= nPoints; j++) { |
784 | append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc); |
785 | } |
786 | } |
787 | |
788 | void generate_cubic_points(const SkPoint& p0, |
789 | const SkPoint& p1, |
790 | const SkPoint& p2, |
791 | const SkPoint& p3, |
792 | SkScalar tolSqd, |
793 | VertexList* contour, |
794 | int pointsLeft, |
795 | SkArenaAlloc& alloc) { |
796 | SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3); |
797 | SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3); |
798 | if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || |
799 | !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) { |
800 | append_point_to_contour(p3, contour, alloc); |
801 | return; |
802 | } |
803 | const SkPoint q[] = { |
804 | { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, |
805 | { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, |
806 | { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) } |
807 | }; |
808 | const SkPoint r[] = { |
809 | { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }, |
810 | { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) } |
811 | }; |
812 | const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) }; |
813 | pointsLeft >>= 1; |
814 | generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc); |
815 | generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc); |
816 | } |
817 | |
818 | // Stage 1: convert the input path to a set of linear contours (linked list of Vertices). |
819 | |
820 | void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
821 | VertexList* contours, SkArenaAlloc& alloc, Mode mode, bool *isLinear) { |
822 | SkScalar toleranceSqd = tolerance * tolerance; |
823 | bool innerPolygons = (Mode::kSimpleInnerPolygons == mode); |
824 | |
825 | SkPoint pts[4]; |
826 | *isLinear = true; |
827 | VertexList* contour = contours; |
828 | SkPath::Iter iter(path, false); |
829 | if (path.isInverseFillType()) { |
830 | SkPoint quad[4]; |
831 | clipBounds.toQuad(quad); |
832 | for (int i = 3; i >= 0; i--) { |
833 | append_point_to_contour(quad[i], contours, alloc); |
834 | } |
835 | contour++; |
836 | } |
837 | SkAutoConicToQuads converter; |
838 | SkPath::Verb verb; |
839 | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
840 | switch (verb) { |
841 | case SkPath::kConic_Verb: { |
842 | *isLinear = false; |
843 | if (innerPolygons) { |
844 | append_point_to_contour(pts[2], contour, alloc); |
845 | break; |
846 | } |
847 | SkScalar weight = iter.conicWeight(); |
848 | const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd); |
849 | for (int i = 0; i < converter.countQuads(); ++i) { |
850 | append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc); |
851 | quadPts += 2; |
852 | } |
853 | break; |
854 | } |
855 | case SkPath::kMove_Verb: |
856 | if (contour->fHead) { |
857 | contour++; |
858 | } |
859 | append_point_to_contour(pts[0], contour, alloc); |
860 | break; |
861 | case SkPath::kLine_Verb: { |
862 | append_point_to_contour(pts[1], contour, alloc); |
863 | break; |
864 | } |
865 | case SkPath::kQuad_Verb: { |
866 | *isLinear = false; |
867 | if (innerPolygons) { |
868 | append_point_to_contour(pts[2], contour, alloc); |
869 | break; |
870 | } |
871 | append_quadratic_to_contour(pts, toleranceSqd, contour, alloc); |
872 | break; |
873 | } |
874 | case SkPath::kCubic_Verb: { |
875 | *isLinear = false; |
876 | if (innerPolygons) { |
877 | append_point_to_contour(pts[3], contour, alloc); |
878 | break; |
879 | } |
880 | int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); |
881 | generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour, |
882 | pointsLeft, alloc); |
883 | break; |
884 | } |
885 | case SkPath::kClose_Verb: |
886 | case SkPath::kDone_Verb: |
887 | break; |
888 | } |
889 | } |
890 | } |
891 | |
892 | inline bool apply_fill_type(SkPathFillType fillType, int winding) { |
893 | switch (fillType) { |
894 | case SkPathFillType::kWinding: |
895 | return winding != 0; |
896 | case SkPathFillType::kEvenOdd: |
897 | return (winding & 1) != 0; |
898 | case SkPathFillType::kInverseWinding: |
899 | return winding == 1; |
900 | case SkPathFillType::kInverseEvenOdd: |
901 | return (winding & 1) == 1; |
902 | default: |
903 | SkASSERT(false); |
904 | return false; |
905 | } |
906 | } |
907 | |
908 | inline bool apply_fill_type(SkPathFillType fillType, Poly* poly) { |
909 | return poly && apply_fill_type(fillType, poly->fWinding); |
910 | } |
911 | |
912 | Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) { |
913 | int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; |
914 | Vertex* top = winding < 0 ? next : prev; |
915 | Vertex* bottom = winding < 0 ? prev : next; |
916 | return alloc.make<Edge>(top, bottom, winding, type); |
917 | } |
918 | |
919 | void remove_edge(Edge* edge, EdgeList* edges) { |
920 | TESS_LOG("removing edge %g -> %g\n" , edge->fTop->fID, edge->fBottom->fID); |
921 | SkASSERT(edges->contains(edge)); |
922 | edges->remove(edge); |
923 | } |
924 | |
925 | void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { |
926 | TESS_LOG("inserting edge %g -> %g\n" , edge->fTop->fID, edge->fBottom->fID); |
927 | SkASSERT(!edges->contains(edge)); |
928 | Edge* next = prev ? prev->fRight : edges->fHead; |
929 | edges->insert(edge, prev, next); |
930 | } |
931 | |
932 | void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) { |
933 | if (v->fFirstEdgeAbove && v->fLastEdgeAbove) { |
934 | *left = v->fFirstEdgeAbove->fLeft; |
935 | *right = v->fLastEdgeAbove->fRight; |
936 | return; |
937 | } |
938 | Edge* next = nullptr; |
939 | Edge* prev; |
940 | for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) { |
941 | if (prev->isLeftOf(v)) { |
942 | break; |
943 | } |
944 | next = prev; |
945 | } |
946 | *left = prev; |
947 | *right = next; |
948 | } |
949 | |
950 | void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { |
951 | if (edge->fTop->fPoint == edge->fBottom->fPoint || |
952 | c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) { |
953 | return; |
954 | } |
955 | TESS_LOG("insert edge (%g -> %g) above vertex %g\n" , |
956 | edge->fTop->fID, edge->fBottom->fID, v->fID); |
957 | Edge* prev = nullptr; |
958 | Edge* next; |
959 | for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) { |
960 | if (next->isRightOf(edge->fTop)) { |
961 | break; |
962 | } |
963 | prev = next; |
964 | } |
965 | list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>( |
966 | edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove); |
967 | } |
968 | |
969 | void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) { |
970 | if (edge->fTop->fPoint == edge->fBottom->fPoint || |
971 | c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) { |
972 | return; |
973 | } |
974 | TESS_LOG("insert edge (%g -> %g) below vertex %g\n" , |
975 | edge->fTop->fID, edge->fBottom->fID, v->fID); |
976 | Edge* prev = nullptr; |
977 | Edge* next; |
978 | for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) { |
979 | if (next->isRightOf(edge->fBottom)) { |
980 | break; |
981 | } |
982 | prev = next; |
983 | } |
984 | list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>( |
985 | edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow); |
986 | } |
987 | |
988 | void remove_edge_above(Edge* edge) { |
989 | SkASSERT(edge->fTop && edge->fBottom); |
990 | TESS_LOG("removing edge (%g -> %g) above vertex %g\n" , edge->fTop->fID, edge->fBottom->fID, |
991 | edge->fBottom->fID); |
992 | list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>( |
993 | edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove); |
994 | } |
995 | |
996 | void remove_edge_below(Edge* edge) { |
997 | SkASSERT(edge->fTop && edge->fBottom); |
998 | TESS_LOG("removing edge (%g -> %g) below vertex %g\n" , |
999 | edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID); |
1000 | list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>( |
1001 | edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow); |
1002 | } |
1003 | |
1004 | void disconnect(Edge* edge) |
1005 | { |
1006 | remove_edge_above(edge); |
1007 | remove_edge_below(edge); |
1008 | } |
1009 | |
1010 | void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c); |
1011 | |
1012 | void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c) { |
1013 | if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) { |
1014 | return; |
1015 | } |
1016 | Vertex* v = *current; |
1017 | TESS_LOG("rewinding active edges from vertex %g to vertex %g\n" , v->fID, dst->fID); |
1018 | while (v != dst) { |
1019 | v = v->fPrev; |
1020 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1021 | remove_edge(e, activeEdges); |
1022 | } |
1023 | Edge* leftEdge = v->fLeftEnclosingEdge; |
1024 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1025 | insert_edge(e, leftEdge, activeEdges); |
1026 | leftEdge = e; |
1027 | Vertex* top = e->fTop; |
1028 | if (c.sweep_lt(top->fPoint, dst->fPoint) && |
1029 | ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) || |
1030 | (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) { |
1031 | dst = top; |
1032 | } |
1033 | } |
1034 | } |
1035 | *current = v; |
1036 | } |
1037 | |
1038 | void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1039 | if (!activeEdges || !current) { |
1040 | return; |
1041 | } |
1042 | Vertex* top = edge->fTop; |
1043 | Vertex* bottom = edge->fBottom; |
1044 | if (edge->fLeft) { |
1045 | Vertex* leftTop = edge->fLeft->fTop; |
1046 | Vertex* leftBottom = edge->fLeft->fBottom; |
1047 | if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) { |
1048 | rewind(activeEdges, current, leftTop, c); |
1049 | } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) { |
1050 | rewind(activeEdges, current, top, c); |
1051 | } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && |
1052 | !edge->fLeft->isLeftOf(bottom)) { |
1053 | rewind(activeEdges, current, leftTop, c); |
1054 | } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) { |
1055 | rewind(activeEdges, current, top, c); |
1056 | } |
1057 | } |
1058 | if (edge->fRight) { |
1059 | Vertex* rightTop = edge->fRight->fTop; |
1060 | Vertex* rightBottom = edge->fRight->fBottom; |
1061 | if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) { |
1062 | rewind(activeEdges, current, rightTop, c); |
1063 | } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) { |
1064 | rewind(activeEdges, current, top, c); |
1065 | } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && |
1066 | !edge->fRight->isRightOf(bottom)) { |
1067 | rewind(activeEdges, current, rightTop, c); |
1068 | } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) && |
1069 | !edge->isLeftOf(rightBottom)) { |
1070 | rewind(activeEdges, current, top, c); |
1071 | } |
1072 | } |
1073 | } |
1074 | |
1075 | void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1076 | remove_edge_below(edge); |
1077 | edge->fTop = v; |
1078 | edge->recompute(); |
1079 | insert_edge_below(edge, v, c); |
1080 | rewind_if_necessary(edge, activeEdges, current, c); |
1081 | merge_collinear_edges(edge, activeEdges, current, c); |
1082 | } |
1083 | |
1084 | void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1085 | remove_edge_above(edge); |
1086 | edge->fBottom = v; |
1087 | edge->recompute(); |
1088 | insert_edge_above(edge, v, c); |
1089 | rewind_if_necessary(edge, activeEdges, current, c); |
1090 | merge_collinear_edges(edge, activeEdges, current, c); |
1091 | } |
1092 | |
1093 | void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, |
1094 | Comparator& c) { |
1095 | if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) { |
1096 | TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n" , |
1097 | edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, |
1098 | edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); |
1099 | rewind(activeEdges, current, edge->fTop, c); |
1100 | other->fWinding += edge->fWinding; |
1101 | disconnect(edge); |
1102 | edge->fTop = edge->fBottom = nullptr; |
1103 | } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) { |
1104 | rewind(activeEdges, current, edge->fTop, c); |
1105 | other->fWinding += edge->fWinding; |
1106 | set_bottom(edge, other->fTop, activeEdges, current, c); |
1107 | } else { |
1108 | rewind(activeEdges, current, other->fTop, c); |
1109 | edge->fWinding += other->fWinding; |
1110 | set_bottom(other, edge->fTop, activeEdges, current, c); |
1111 | } |
1112 | } |
1113 | |
1114 | void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, |
1115 | Comparator& c) { |
1116 | if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) { |
1117 | TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n" , |
1118 | edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, |
1119 | edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); |
1120 | rewind(activeEdges, current, edge->fTop, c); |
1121 | other->fWinding += edge->fWinding; |
1122 | disconnect(edge); |
1123 | edge->fTop = edge->fBottom = nullptr; |
1124 | } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) { |
1125 | rewind(activeEdges, current, other->fTop, c); |
1126 | edge->fWinding += other->fWinding; |
1127 | set_top(other, edge->fBottom, activeEdges, current, c); |
1128 | } else { |
1129 | rewind(activeEdges, current, edge->fTop, c); |
1130 | other->fWinding += edge->fWinding; |
1131 | set_top(edge, other->fBottom, activeEdges, current, c); |
1132 | } |
1133 | } |
1134 | |
1135 | bool top_collinear(Edge* left, Edge* right) { |
1136 | if (!left || !right) { |
1137 | return false; |
1138 | } |
1139 | return left->fTop->fPoint == right->fTop->fPoint || |
1140 | !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop); |
1141 | } |
1142 | |
1143 | bool bottom_collinear(Edge* left, Edge* right) { |
1144 | if (!left || !right) { |
1145 | return false; |
1146 | } |
1147 | return left->fBottom->fPoint == right->fBottom->fPoint || |
1148 | !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom); |
1149 | } |
1150 | |
1151 | void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1152 | for (;;) { |
1153 | if (top_collinear(edge->fPrevEdgeAbove, edge)) { |
1154 | merge_edges_above(edge->fPrevEdgeAbove, edge, activeEdges, current, c); |
1155 | } else if (top_collinear(edge, edge->fNextEdgeAbove)) { |
1156 | merge_edges_above(edge->fNextEdgeAbove, edge, activeEdges, current, c); |
1157 | } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) { |
1158 | merge_edges_below(edge->fPrevEdgeBelow, edge, activeEdges, current, c); |
1159 | } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) { |
1160 | merge_edges_below(edge->fNextEdgeBelow, edge, activeEdges, current, c); |
1161 | } else { |
1162 | break; |
1163 | } |
1164 | } |
1165 | SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge)); |
1166 | SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove)); |
1167 | SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge)); |
1168 | SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow)); |
1169 | } |
1170 | |
1171 | bool split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c, |
1172 | SkArenaAlloc& alloc) { |
1173 | if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) { |
1174 | return false; |
1175 | } |
1176 | TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n" , |
1177 | edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY); |
1178 | Vertex* top; |
1179 | Vertex* bottom; |
1180 | int winding = edge->fWinding; |
1181 | if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) { |
1182 | top = v; |
1183 | bottom = edge->fTop; |
1184 | set_top(edge, v, activeEdges, current, c); |
1185 | } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) { |
1186 | top = edge->fBottom; |
1187 | bottom = v; |
1188 | set_bottom(edge, v, activeEdges, current, c); |
1189 | } else { |
1190 | top = v; |
1191 | bottom = edge->fBottom; |
1192 | set_bottom(edge, v, activeEdges, current, c); |
1193 | } |
1194 | Edge* newEdge = alloc.make<Edge>(top, bottom, winding, edge->fType); |
1195 | insert_edge_below(newEdge, top, c); |
1196 | insert_edge_above(newEdge, bottom, c); |
1197 | merge_collinear_edges(newEdge, activeEdges, current, c); |
1198 | return true; |
1199 | } |
1200 | |
1201 | bool intersect_edge_pair(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current, Comparator& c, SkArenaAlloc& alloc) { |
1202 | if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) { |
1203 | return false; |
1204 | } |
1205 | if (left->fTop == right->fTop || left->fBottom == right->fBottom) { |
1206 | return false; |
1207 | } |
1208 | if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) { |
1209 | if (!left->isLeftOf(right->fTop)) { |
1210 | rewind(activeEdges, current, right->fTop, c); |
1211 | return split_edge(left, right->fTop, activeEdges, current, c, alloc); |
1212 | } |
1213 | } else { |
1214 | if (!right->isRightOf(left->fTop)) { |
1215 | rewind(activeEdges, current, left->fTop, c); |
1216 | return split_edge(right, left->fTop, activeEdges, current, c, alloc); |
1217 | } |
1218 | } |
1219 | if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) { |
1220 | if (!left->isLeftOf(right->fBottom)) { |
1221 | rewind(activeEdges, current, right->fBottom, c); |
1222 | return split_edge(left, right->fBottom, activeEdges, current, c, alloc); |
1223 | } |
1224 | } else { |
1225 | if (!right->isRightOf(left->fBottom)) { |
1226 | rewind(activeEdges, current, left->fBottom, c); |
1227 | return split_edge(right, left->fBottom, activeEdges, current, c, alloc); |
1228 | } |
1229 | } |
1230 | return false; |
1231 | } |
1232 | |
1233 | Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc, |
1234 | int winding_scale = 1) { |
1235 | if (!prev || !next || prev->fPoint == next->fPoint) { |
1236 | return nullptr; |
1237 | } |
1238 | Edge* edge = new_edge(prev, next, type, c, alloc); |
1239 | insert_edge_below(edge, edge->fTop, c); |
1240 | insert_edge_above(edge, edge->fBottom, c); |
1241 | edge->fWinding *= winding_scale; |
1242 | merge_collinear_edges(edge, nullptr, nullptr, c); |
1243 | return edge; |
1244 | } |
1245 | |
1246 | void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c, |
1247 | SkArenaAlloc& alloc) { |
1248 | TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n" , |
1249 | src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID); |
1250 | dst->fAlpha = std::max(src->fAlpha, dst->fAlpha); |
1251 | if (src->fPartner) { |
1252 | src->fPartner->fPartner = dst; |
1253 | } |
1254 | while (Edge* edge = src->fFirstEdgeAbove) { |
1255 | set_bottom(edge, dst, nullptr, nullptr, c); |
1256 | } |
1257 | while (Edge* edge = src->fFirstEdgeBelow) { |
1258 | set_top(edge, dst, nullptr, nullptr, c); |
1259 | } |
1260 | mesh->remove(src); |
1261 | dst->fSynthetic = true; |
1262 | } |
1263 | |
1264 | Vertex* create_sorted_vertex(const SkPoint& p, uint8_t alpha, VertexList* mesh, |
1265 | Vertex* reference, Comparator& c, SkArenaAlloc& alloc) { |
1266 | Vertex* prevV = reference; |
1267 | while (prevV && c.sweep_lt(p, prevV->fPoint)) { |
1268 | prevV = prevV->fPrev; |
1269 | } |
1270 | Vertex* nextV = prevV ? prevV->fNext : mesh->fHead; |
1271 | while (nextV && c.sweep_lt(nextV->fPoint, p)) { |
1272 | prevV = nextV; |
1273 | nextV = nextV->fNext; |
1274 | } |
1275 | Vertex* v; |
1276 | if (prevV && coincident(prevV->fPoint, p)) { |
1277 | v = prevV; |
1278 | } else if (nextV && coincident(nextV->fPoint, p)) { |
1279 | v = nextV; |
1280 | } else { |
1281 | v = alloc.make<Vertex>(p, alpha); |
1282 | #if LOGGING_ENABLED |
1283 | if (!prevV) { |
1284 | v->fID = mesh->fHead->fID - 1.0f; |
1285 | } else if (!nextV) { |
1286 | v->fID = mesh->fTail->fID + 1.0f; |
1287 | } else { |
1288 | v->fID = (prevV->fID + nextV->fID) * 0.5f; |
1289 | } |
1290 | #endif |
1291 | mesh->insert(v, prevV, nextV); |
1292 | } |
1293 | return v; |
1294 | } |
1295 | |
1296 | // If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary |
1297 | // sort criterion, it may not be possible to split correctly, since there is no point which is |
1298 | // below the top and above the bottom. This function detects that case. |
1299 | bool nearly_flat(Comparator& c, Edge* edge) { |
1300 | SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint; |
1301 | float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY; |
1302 | return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f; |
1303 | } |
1304 | |
1305 | SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, Comparator& c) { |
1306 | if (c.sweep_lt(p, min)) { |
1307 | return min; |
1308 | } else if (c.sweep_lt(max, p)) { |
1309 | return max; |
1310 | } else { |
1311 | return p; |
1312 | } |
1313 | } |
1314 | |
1315 | void compute_bisector(Edge* edge1, Edge* edge2, Vertex* v, SkArenaAlloc& alloc) { |
1316 | Line line1 = edge1->fLine; |
1317 | Line line2 = edge2->fLine; |
1318 | line1.normalize(); |
1319 | line2.normalize(); |
1320 | double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB; |
1321 | if (cosAngle > 0.999) { |
1322 | return; |
1323 | } |
1324 | line1.fC += edge1->fWinding > 0 ? -1 : 1; |
1325 | line2.fC += edge2->fWinding > 0 ? -1 : 1; |
1326 | SkPoint p; |
1327 | if (line1.intersect(line2, &p)) { |
1328 | uint8_t alpha = edge1->fType == Edge::Type::kOuter ? 255 : 0; |
1329 | v->fPartner = alloc.make<Vertex>(p, alpha); |
1330 | TESS_LOG("computed bisector (%g,%g) alpha %d for vertex %g\n" , p.fX, p.fY, alpha, v->fID); |
1331 | } |
1332 | } |
1333 | |
1334 | bool check_for_intersection(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current, |
1335 | VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1336 | if (!left || !right) { |
1337 | return false; |
1338 | } |
1339 | SkPoint p; |
1340 | uint8_t alpha; |
1341 | if (left->intersect(*right, &p, &alpha) && p.isFinite()) { |
1342 | Vertex* v; |
1343 | TESS_LOG("found intersection, pt is %g, %g\n" , p.fX, p.fY); |
1344 | Vertex* top = *current; |
1345 | // If the intersection point is above the current vertex, rewind to the vertex above the |
1346 | // intersection. |
1347 | while (top && c.sweep_lt(p, top->fPoint)) { |
1348 | top = top->fPrev; |
1349 | } |
1350 | if (!nearly_flat(c, left)) { |
1351 | p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c); |
1352 | } |
1353 | if (!nearly_flat(c, right)) { |
1354 | p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c); |
1355 | } |
1356 | if (p == left->fTop->fPoint) { |
1357 | v = left->fTop; |
1358 | } else if (p == left->fBottom->fPoint) { |
1359 | v = left->fBottom; |
1360 | } else if (p == right->fTop->fPoint) { |
1361 | v = right->fTop; |
1362 | } else if (p == right->fBottom->fPoint) { |
1363 | v = right->fBottom; |
1364 | } else { |
1365 | v = create_sorted_vertex(p, alpha, mesh, top, c, alloc); |
1366 | if (left->fTop->fPartner) { |
1367 | v->fSynthetic = true; |
1368 | compute_bisector(left, right, v, alloc); |
1369 | } |
1370 | } |
1371 | rewind(activeEdges, current, top ? top : v, c); |
1372 | split_edge(left, v, activeEdges, current, c, alloc); |
1373 | split_edge(right, v, activeEdges, current, c, alloc); |
1374 | v->fAlpha = std::max(v->fAlpha, alpha); |
1375 | return true; |
1376 | } |
1377 | return intersect_edge_pair(left, right, activeEdges, current, c, alloc); |
1378 | } |
1379 | |
1380 | void sanitize_contours(VertexList* contours, int contourCnt, Mode mode) { |
1381 | bool approximate = (Mode::kEdgeAntialias == mode); |
1382 | bool removeCollinearVertices = (Mode::kSimpleInnerPolygons != mode); |
1383 | for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) { |
1384 | SkASSERT(contour->fHead); |
1385 | Vertex* prev = contour->fTail; |
1386 | if (approximate) { |
1387 | round(&prev->fPoint); |
1388 | } |
1389 | for (Vertex* v = contour->fHead; v;) { |
1390 | if (approximate) { |
1391 | round(&v->fPoint); |
1392 | } |
1393 | Vertex* next = v->fNext; |
1394 | Vertex* nextWrap = next ? next : contour->fHead; |
1395 | if (coincident(prev->fPoint, v->fPoint)) { |
1396 | TESS_LOG("vertex %g,%g coincident; removing\n" , v->fPoint.fX, v->fPoint.fY); |
1397 | contour->remove(v); |
1398 | } else if (!v->fPoint.isFinite()) { |
1399 | TESS_LOG("vertex %g,%g non-finite; removing\n" , v->fPoint.fX, v->fPoint.fY); |
1400 | contour->remove(v); |
1401 | } else if (removeCollinearVertices && |
1402 | Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) { |
1403 | TESS_LOG("vertex %g,%g collinear; removing\n" , v->fPoint.fX, v->fPoint.fY); |
1404 | contour->remove(v); |
1405 | } else { |
1406 | prev = v; |
1407 | } |
1408 | v = next; |
1409 | } |
1410 | } |
1411 | } |
1412 | |
1413 | bool merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1414 | if (!mesh->fHead) { |
1415 | return false; |
1416 | } |
1417 | bool merged = false; |
1418 | for (Vertex* v = mesh->fHead->fNext; v;) { |
1419 | Vertex* next = v->fNext; |
1420 | if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) { |
1421 | v->fPoint = v->fPrev->fPoint; |
1422 | } |
1423 | if (coincident(v->fPrev->fPoint, v->fPoint)) { |
1424 | merge_vertices(v, v->fPrev, mesh, c, alloc); |
1425 | merged = true; |
1426 | } |
1427 | v = next; |
1428 | } |
1429 | return merged; |
1430 | } |
1431 | |
1432 | // Stage 2: convert the contours to a mesh of edges connecting the vertices. |
1433 | |
1434 | void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c, |
1435 | SkArenaAlloc& alloc) { |
1436 | for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) { |
1437 | Vertex* prev = contour->fTail; |
1438 | for (Vertex* v = contour->fHead; v;) { |
1439 | Vertex* next = v->fNext; |
1440 | connect(prev, v, Edge::Type::kInner, c, alloc); |
1441 | mesh->append(v); |
1442 | prev = v; |
1443 | v = next; |
1444 | } |
1445 | } |
1446 | } |
1447 | |
1448 | void connect_partners(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1449 | for (Vertex* outer = mesh->fHead; outer; outer = outer->fNext) { |
1450 | if (Vertex* inner = outer->fPartner) { |
1451 | if ((inner->fPrev || inner->fNext) && (outer->fPrev || outer->fNext)) { |
1452 | // Connector edges get zero winding, since they're only structural (i.e., to ensure |
1453 | // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding |
1454 | // number. |
1455 | connect(outer, inner, Edge::Type::kConnector, c, alloc, 0); |
1456 | inner->fPartner = outer->fPartner = nullptr; |
1457 | } |
1458 | } |
1459 | } |
1460 | } |
1461 | |
1462 | template <CompareFunc sweep_lt> |
1463 | void sorted_merge(VertexList* front, VertexList* back, VertexList* result) { |
1464 | Vertex* a = front->fHead; |
1465 | Vertex* b = back->fHead; |
1466 | while (a && b) { |
1467 | if (sweep_lt(a->fPoint, b->fPoint)) { |
1468 | front->remove(a); |
1469 | result->append(a); |
1470 | a = front->fHead; |
1471 | } else { |
1472 | back->remove(b); |
1473 | result->append(b); |
1474 | b = back->fHead; |
1475 | } |
1476 | } |
1477 | result->append(*front); |
1478 | result->append(*back); |
1479 | } |
1480 | |
1481 | void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) { |
1482 | if (c.fDirection == Comparator::Direction::kHorizontal) { |
1483 | sorted_merge<sweep_lt_horiz>(front, back, result); |
1484 | } else { |
1485 | sorted_merge<sweep_lt_vert>(front, back, result); |
1486 | } |
1487 | #if LOGGING_ENABLED |
1488 | float id = 0.0f; |
1489 | for (Vertex* v = result->fHead; v; v = v->fNext) { |
1490 | v->fID = id++; |
1491 | } |
1492 | #endif |
1493 | } |
1494 | |
1495 | // Stage 3: sort the vertices by increasing sweep direction. |
1496 | |
1497 | template <CompareFunc sweep_lt> |
1498 | void merge_sort(VertexList* vertices) { |
1499 | Vertex* slow = vertices->fHead; |
1500 | if (!slow) { |
1501 | return; |
1502 | } |
1503 | Vertex* fast = slow->fNext; |
1504 | if (!fast) { |
1505 | return; |
1506 | } |
1507 | do { |
1508 | fast = fast->fNext; |
1509 | if (fast) { |
1510 | fast = fast->fNext; |
1511 | slow = slow->fNext; |
1512 | } |
1513 | } while (fast); |
1514 | VertexList front(vertices->fHead, slow); |
1515 | VertexList back(slow->fNext, vertices->fTail); |
1516 | front.fTail->fNext = back.fHead->fPrev = nullptr; |
1517 | |
1518 | merge_sort<sweep_lt>(&front); |
1519 | merge_sort<sweep_lt>(&back); |
1520 | |
1521 | vertices->fHead = vertices->fTail = nullptr; |
1522 | sorted_merge<sweep_lt>(&front, &back, vertices); |
1523 | } |
1524 | |
1525 | void dump_mesh(const VertexList& mesh) { |
1526 | #if LOGGING_ENABLED |
1527 | for (Vertex* v = mesh.fHead; v; v = v->fNext) { |
1528 | TESS_LOG("vertex %g (%g, %g) alpha %d" , v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
1529 | if (Vertex* p = v->fPartner) { |
1530 | TESS_LOG(", partner %g (%g, %g) alpha %d\n" , |
1531 | p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha); |
1532 | } else { |
1533 | TESS_LOG(", null partner\n" ); |
1534 | } |
1535 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1536 | TESS_LOG(" edge %g -> %g, winding %d\n" , e->fTop->fID, e->fBottom->fID, e->fWinding); |
1537 | } |
1538 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1539 | TESS_LOG(" edge %g -> %g, winding %d\n" , e->fTop->fID, e->fBottom->fID, e->fWinding); |
1540 | } |
1541 | } |
1542 | #endif |
1543 | } |
1544 | |
1545 | void dump_skel(const SSEdgeList& ssEdges) { |
1546 | #if LOGGING_ENABLED |
1547 | for (SSEdge* edge : ssEdges) { |
1548 | if (edge->fEdge) { |
1549 | TESS_LOG("skel edge %g -> %g" , |
1550 | edge->fPrev->fVertex->fID, |
1551 | edge->fNext->fVertex->fID); |
1552 | if (edge->fEdge->fTop && edge->fEdge->fBottom) { |
1553 | TESS_LOG(" (original %g -> %g)\n" , |
1554 | edge->fEdge->fTop->fID, |
1555 | edge->fEdge->fBottom->fID); |
1556 | } else { |
1557 | TESS_LOG("\n" ); |
1558 | } |
1559 | } |
1560 | } |
1561 | #endif |
1562 | } |
1563 | |
1564 | #ifdef SK_DEBUG |
1565 | void validate_edge_pair(Edge* left, Edge* right, Comparator& c) { |
1566 | if (!left || !right) { |
1567 | return; |
1568 | } |
1569 | if (left->fTop == right->fTop) { |
1570 | SkASSERT(left->isLeftOf(right->fBottom)); |
1571 | SkASSERT(right->isRightOf(left->fBottom)); |
1572 | } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) { |
1573 | SkASSERT(left->isLeftOf(right->fTop)); |
1574 | } else { |
1575 | SkASSERT(right->isRightOf(left->fTop)); |
1576 | } |
1577 | if (left->fBottom == right->fBottom) { |
1578 | SkASSERT(left->isLeftOf(right->fTop)); |
1579 | SkASSERT(right->isRightOf(left->fTop)); |
1580 | } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) { |
1581 | SkASSERT(left->isLeftOf(right->fBottom)); |
1582 | } else { |
1583 | SkASSERT(right->isRightOf(left->fBottom)); |
1584 | } |
1585 | } |
1586 | |
1587 | void validate_edge_list(EdgeList* edges, Comparator& c) { |
1588 | Edge* left = edges->fHead; |
1589 | if (!left) { |
1590 | return; |
1591 | } |
1592 | for (Edge* right = left->fRight; right; right = right->fRight) { |
1593 | validate_edge_pair(left, right, c); |
1594 | left = right; |
1595 | } |
1596 | } |
1597 | #endif |
1598 | |
1599 | // Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. |
1600 | |
1601 | bool connected(Vertex* v) { |
1602 | return v->fFirstEdgeAbove || v->fFirstEdgeBelow; |
1603 | } |
1604 | |
1605 | enum class SimplifyResult { |
1606 | kAlreadySimple, |
1607 | kFoundSelfIntersection, |
1608 | kAbort |
1609 | }; |
1610 | |
1611 | SimplifyResult simplify(Mode mode, VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1612 | TESS_LOG("simplifying complex polygons\n" ); |
1613 | EdgeList activeEdges; |
1614 | auto result = SimplifyResult::kAlreadySimple; |
1615 | for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) { |
1616 | if (!connected(v)) { |
1617 | continue; |
1618 | } |
1619 | Edge* leftEnclosingEdge; |
1620 | Edge* rightEnclosingEdge; |
1621 | bool restartChecks; |
1622 | do { |
1623 | TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n" , |
1624 | v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
1625 | restartChecks = false; |
1626 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1627 | v->fLeftEnclosingEdge = leftEnclosingEdge; |
1628 | v->fRightEnclosingEdge = rightEnclosingEdge; |
1629 | if (v->fFirstEdgeBelow) { |
1630 | for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) { |
1631 | if (check_for_intersection( |
1632 | leftEnclosingEdge, edge, &activeEdges, &v, mesh, c, alloc) || |
1633 | check_for_intersection( |
1634 | edge, rightEnclosingEdge, &activeEdges, &v, mesh, c, alloc)) { |
1635 | if (Mode::kSimpleInnerPolygons == mode) { |
1636 | return SimplifyResult::kAbort; |
1637 | } |
1638 | result = SimplifyResult::kFoundSelfIntersection; |
1639 | restartChecks = true; |
1640 | break; |
1641 | } |
1642 | } |
1643 | } else { |
1644 | if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge, |
1645 | &activeEdges, &v, mesh, c, alloc)) { |
1646 | if (Mode::kSimpleInnerPolygons == mode) { |
1647 | return SimplifyResult::kAbort; |
1648 | } |
1649 | result = SimplifyResult::kFoundSelfIntersection; |
1650 | restartChecks = true; |
1651 | } |
1652 | |
1653 | } |
1654 | } while (restartChecks); |
1655 | #ifdef SK_DEBUG |
1656 | validate_edge_list(&activeEdges, c); |
1657 | #endif |
1658 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1659 | remove_edge(e, &activeEdges); |
1660 | } |
1661 | Edge* leftEdge = leftEnclosingEdge; |
1662 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1663 | insert_edge(e, leftEdge, &activeEdges); |
1664 | leftEdge = e; |
1665 | } |
1666 | } |
1667 | SkASSERT(!activeEdges.fHead && !activeEdges.fTail); |
1668 | return result; |
1669 | } |
1670 | |
1671 | // Stage 5: Tessellate the simplified mesh into monotone polygons. |
1672 | |
1673 | Poly* tessellate(SkPathFillType fillType, Mode mode, const VertexList& vertices, |
1674 | SkArenaAlloc& alloc) { |
1675 | TESS_LOG("\ntessellating simple polygons\n" ); |
1676 | int maxWindMagnitude = std::numeric_limits<int>::max(); |
1677 | if (Mode::kSimpleInnerPolygons == mode && !SkPathFillType_IsEvenOdd(fillType)) { |
1678 | maxWindMagnitude = 1; |
1679 | } |
1680 | EdgeList activeEdges; |
1681 | Poly* polys = nullptr; |
1682 | for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) { |
1683 | if (!connected(v)) { |
1684 | continue; |
1685 | } |
1686 | #if LOGGING_ENABLED |
1687 | TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n" , v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
1688 | #endif |
1689 | Edge* leftEnclosingEdge; |
1690 | Edge* rightEnclosingEdge; |
1691 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1692 | Poly* leftPoly; |
1693 | Poly* rightPoly; |
1694 | if (v->fFirstEdgeAbove) { |
1695 | leftPoly = v->fFirstEdgeAbove->fLeftPoly; |
1696 | rightPoly = v->fLastEdgeAbove->fRightPoly; |
1697 | } else { |
1698 | leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr; |
1699 | rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr; |
1700 | } |
1701 | #if LOGGING_ENABLED |
1702 | TESS_LOG("edges above:\n" ); |
1703 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1704 | TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n" , |
1705 | e->fTop->fID, e->fBottom->fID, |
1706 | e->fLeftPoly ? e->fLeftPoly->fID : -1, |
1707 | e->fRightPoly ? e->fRightPoly->fID : -1); |
1708 | } |
1709 | TESS_LOG("edges below:\n" ); |
1710 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1711 | TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n" , |
1712 | e->fTop->fID, e->fBottom->fID, |
1713 | e->fLeftPoly ? e->fLeftPoly->fID : -1, |
1714 | e->fRightPoly ? e->fRightPoly->fID : -1); |
1715 | } |
1716 | #endif |
1717 | if (v->fFirstEdgeAbove) { |
1718 | if (leftPoly) { |
1719 | leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc); |
1720 | } |
1721 | if (rightPoly) { |
1722 | rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc); |
1723 | } |
1724 | for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) { |
1725 | Edge* rightEdge = e->fNextEdgeAbove; |
1726 | remove_edge(e, &activeEdges); |
1727 | if (e->fRightPoly) { |
1728 | e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc); |
1729 | } |
1730 | if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) { |
1731 | rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc); |
1732 | } |
1733 | } |
1734 | remove_edge(v->fLastEdgeAbove, &activeEdges); |
1735 | if (!v->fFirstEdgeBelow) { |
1736 | if (leftPoly && rightPoly && leftPoly != rightPoly) { |
1737 | SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr); |
1738 | rightPoly->fPartner = leftPoly; |
1739 | leftPoly->fPartner = rightPoly; |
1740 | } |
1741 | } |
1742 | } |
1743 | if (v->fFirstEdgeBelow) { |
1744 | if (!v->fFirstEdgeAbove) { |
1745 | if (leftPoly && rightPoly) { |
1746 | if (leftPoly == rightPoly) { |
1747 | if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) { |
1748 | leftPoly = new_poly(&polys, leftPoly->lastVertex(), |
1749 | leftPoly->fWinding, alloc); |
1750 | leftEnclosingEdge->fRightPoly = leftPoly; |
1751 | } else { |
1752 | rightPoly = new_poly(&polys, rightPoly->lastVertex(), |
1753 | rightPoly->fWinding, alloc); |
1754 | rightEnclosingEdge->fLeftPoly = rightPoly; |
1755 | } |
1756 | } |
1757 | Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner); |
1758 | leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc); |
1759 | rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc); |
1760 | } |
1761 | } |
1762 | Edge* leftEdge = v->fFirstEdgeBelow; |
1763 | leftEdge->fLeftPoly = leftPoly; |
1764 | insert_edge(leftEdge, leftEnclosingEdge, &activeEdges); |
1765 | for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge; |
1766 | rightEdge = rightEdge->fNextEdgeBelow) { |
1767 | insert_edge(rightEdge, leftEdge, &activeEdges); |
1768 | int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0; |
1769 | winding += leftEdge->fWinding; |
1770 | if (winding != 0) { |
1771 | if (abs(winding) > maxWindMagnitude) { |
1772 | return nullptr; // We can't have weighted wind in kSimpleInnerPolygons mode |
1773 | } |
1774 | Poly* poly = new_poly(&polys, v, winding, alloc); |
1775 | leftEdge->fRightPoly = rightEdge->fLeftPoly = poly; |
1776 | } |
1777 | leftEdge = rightEdge; |
1778 | } |
1779 | v->fLastEdgeBelow->fRightPoly = rightPoly; |
1780 | } |
1781 | #if LOGGING_ENABLED |
1782 | TESS_LOG("\nactive edges:\n" ); |
1783 | for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) { |
1784 | TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n" , |
1785 | e->fTop->fID, e->fBottom->fID, |
1786 | e->fLeftPoly ? e->fLeftPoly->fID : -1, |
1787 | e->fRightPoly ? e->fRightPoly->fID : -1); |
1788 | } |
1789 | #endif |
1790 | } |
1791 | return polys; |
1792 | } |
1793 | |
1794 | void remove_non_boundary_edges(const VertexList& mesh, SkPathFillType fillType, |
1795 | SkArenaAlloc& alloc) { |
1796 | TESS_LOG("removing non-boundary edges\n" ); |
1797 | EdgeList activeEdges; |
1798 | for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) { |
1799 | if (!connected(v)) { |
1800 | continue; |
1801 | } |
1802 | Edge* leftEnclosingEdge; |
1803 | Edge* rightEnclosingEdge; |
1804 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1805 | bool prevFilled = leftEnclosingEdge && |
1806 | apply_fill_type(fillType, leftEnclosingEdge->fWinding); |
1807 | for (Edge* e = v->fFirstEdgeAbove; e;) { |
1808 | Edge* next = e->fNextEdgeAbove; |
1809 | remove_edge(e, &activeEdges); |
1810 | bool filled = apply_fill_type(fillType, e->fWinding); |
1811 | if (filled == prevFilled) { |
1812 | disconnect(e); |
1813 | } |
1814 | prevFilled = filled; |
1815 | e = next; |
1816 | } |
1817 | Edge* prev = leftEnclosingEdge; |
1818 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1819 | if (prev) { |
1820 | e->fWinding += prev->fWinding; |
1821 | } |
1822 | insert_edge(e, prev, &activeEdges); |
1823 | prev = e; |
1824 | } |
1825 | } |
1826 | } |
1827 | |
1828 | // Note: this is the normal to the edge, but not necessarily unit length. |
1829 | void get_edge_normal(const Edge* e, SkVector* normal) { |
1830 | normal->set(SkDoubleToScalar(e->fLine.fA), |
1831 | SkDoubleToScalar(e->fLine.fB)); |
1832 | } |
1833 | |
1834 | // Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions |
1835 | // and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to |
1836 | // invert on stroking. |
1837 | |
1838 | void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) { |
1839 | Edge* prevEdge = boundary->fTail; |
1840 | SkVector prevNormal; |
1841 | get_edge_normal(prevEdge, &prevNormal); |
1842 | for (Edge* e = boundary->fHead; e != nullptr;) { |
1843 | Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom; |
1844 | Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop; |
1845 | double distPrev = e->dist(prev->fPoint); |
1846 | double distNext = prevEdge->dist(next->fPoint); |
1847 | SkVector normal; |
1848 | get_edge_normal(e, &normal); |
1849 | constexpr double kQuarterPixelSq = 0.25f * 0.25f; |
1850 | if (prev == next) { |
1851 | remove_edge(prevEdge, boundary); |
1852 | remove_edge(e, boundary); |
1853 | prevEdge = boundary->fTail; |
1854 | e = boundary->fHead; |
1855 | if (prevEdge) { |
1856 | get_edge_normal(prevEdge, &prevNormal); |
1857 | } |
1858 | } else if (prevNormal.dot(normal) < 0.0 && |
1859 | (distPrev * distPrev <= kQuarterPixelSq || distNext * distNext <= kQuarterPixelSq)) { |
1860 | Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc); |
1861 | if (prev->fPoint != next->fPoint) { |
1862 | join->fLine.normalize(); |
1863 | join->fLine = join->fLine * join->fWinding; |
1864 | } |
1865 | insert_edge(join, e, boundary); |
1866 | remove_edge(prevEdge, boundary); |
1867 | remove_edge(e, boundary); |
1868 | if (join->fLeft && join->fRight) { |
1869 | prevEdge = join->fLeft; |
1870 | e = join; |
1871 | } else { |
1872 | prevEdge = boundary->fTail; |
1873 | e = boundary->fHead; // join->fLeft ? join->fLeft : join; |
1874 | } |
1875 | get_edge_normal(prevEdge, &prevNormal); |
1876 | } else { |
1877 | prevEdge = e; |
1878 | prevNormal = normal; |
1879 | e = e->fRight; |
1880 | } |
1881 | } |
1882 | } |
1883 | |
1884 | void ss_connect(Vertex* v, Vertex* dest, Comparator& c, SkArenaAlloc& alloc) { |
1885 | if (v == dest) { |
1886 | return; |
1887 | } |
1888 | TESS_LOG("ss_connecting vertex %g to vertex %g\n" , v->fID, dest->fID); |
1889 | if (v->fSynthetic) { |
1890 | connect(v, dest, Edge::Type::kConnector, c, alloc, 0); |
1891 | } else if (v->fPartner) { |
1892 | TESS_LOG("setting %g's partner to %g " , v->fPartner->fID, dest->fID); |
1893 | TESS_LOG("and %g's partner to null\n" , v->fID); |
1894 | v->fPartner->fPartner = dest; |
1895 | v->fPartner = nullptr; |
1896 | } |
1897 | } |
1898 | |
1899 | void Event::apply(VertexList* mesh, Comparator& c, EventList* events, SkArenaAlloc& alloc) { |
1900 | if (!fEdge) { |
1901 | return; |
1902 | } |
1903 | Vertex* prev = fEdge->fPrev->fVertex; |
1904 | Vertex* next = fEdge->fNext->fVertex; |
1905 | SSEdge* prevEdge = fEdge->fPrev->fPrev; |
1906 | SSEdge* nextEdge = fEdge->fNext->fNext; |
1907 | if (!prevEdge || !nextEdge || !prevEdge->fEdge || !nextEdge->fEdge) { |
1908 | return; |
1909 | } |
1910 | Vertex* dest = create_sorted_vertex(fPoint, fAlpha, mesh, prev, c, alloc); |
1911 | dest->fSynthetic = true; |
1912 | SSVertex* ssv = alloc.make<SSVertex>(dest); |
1913 | TESS_LOG("collapsing %g, %g (original edge %g -> %g) to %g (%g, %g) alpha %d\n" , |
1914 | prev->fID, next->fID, fEdge->fEdge->fTop->fID, fEdge->fEdge->fBottom->fID, dest->fID, |
1915 | fPoint.fX, fPoint.fY, fAlpha); |
1916 | fEdge->fEdge = nullptr; |
1917 | |
1918 | ss_connect(prev, dest, c, alloc); |
1919 | ss_connect(next, dest, c, alloc); |
1920 | |
1921 | prevEdge->fNext = nextEdge->fPrev = ssv; |
1922 | ssv->fPrev = prevEdge; |
1923 | ssv->fNext = nextEdge; |
1924 | if (!prevEdge->fEdge || !nextEdge->fEdge) { |
1925 | return; |
1926 | } |
1927 | if (prevEdge->fEvent) { |
1928 | prevEdge->fEvent->fEdge = nullptr; |
1929 | } |
1930 | if (nextEdge->fEvent) { |
1931 | nextEdge->fEvent->fEdge = nullptr; |
1932 | } |
1933 | if (prevEdge->fPrev == nextEdge->fNext) { |
1934 | ss_connect(prevEdge->fPrev->fVertex, dest, c, alloc); |
1935 | prevEdge->fEdge = nextEdge->fEdge = nullptr; |
1936 | } else { |
1937 | compute_bisector(prevEdge->fEdge, nextEdge->fEdge, dest, alloc); |
1938 | SkASSERT(prevEdge != fEdge && nextEdge != fEdge); |
1939 | if (dest->fPartner) { |
1940 | create_event(prevEdge, events, alloc); |
1941 | create_event(nextEdge, events, alloc); |
1942 | } else { |
1943 | create_event(prevEdge, prevEdge->fPrev->fVertex, nextEdge, dest, events, c, alloc); |
1944 | create_event(nextEdge, nextEdge->fNext->fVertex, prevEdge, dest, events, c, alloc); |
1945 | } |
1946 | } |
1947 | } |
1948 | |
1949 | bool is_overlap_edge(Edge* e) { |
1950 | if (e->fType == Edge::Type::kOuter) { |
1951 | return e->fWinding != 0 && e->fWinding != 1; |
1952 | } else if (e->fType == Edge::Type::kInner) { |
1953 | return e->fWinding != 0 && e->fWinding != -2; |
1954 | } else { |
1955 | return false; |
1956 | } |
1957 | } |
1958 | |
1959 | // This is a stripped-down version of tessellate() which computes edges which |
1960 | // join two filled regions, which represent overlap regions, and collapses them. |
1961 | bool collapse_overlap_regions(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc, |
1962 | EventComparator comp) { |
1963 | TESS_LOG("\nfinding overlap regions\n" ); |
1964 | EdgeList activeEdges; |
1965 | EventList events(comp); |
1966 | SSVertexMap ssVertices; |
1967 | SSEdgeList ssEdges; |
1968 | for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) { |
1969 | if (!connected(v)) { |
1970 | continue; |
1971 | } |
1972 | Edge* leftEnclosingEdge; |
1973 | Edge* rightEnclosingEdge; |
1974 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1975 | for (Edge* e = v->fLastEdgeAbove; e && e != leftEnclosingEdge;) { |
1976 | Edge* prev = e->fPrevEdgeAbove ? e->fPrevEdgeAbove : leftEnclosingEdge; |
1977 | remove_edge(e, &activeEdges); |
1978 | bool leftOverlap = prev && is_overlap_edge(prev); |
1979 | bool rightOverlap = is_overlap_edge(e); |
1980 | bool isOuterBoundary = e->fType == Edge::Type::kOuter && |
1981 | (!prev || prev->fWinding == 0 || e->fWinding == 0); |
1982 | if (prev) { |
1983 | e->fWinding -= prev->fWinding; |
1984 | } |
1985 | if (leftOverlap && rightOverlap) { |
1986 | TESS_LOG("found interior overlap edge %g -> %g, disconnecting\n" , |
1987 | e->fTop->fID, e->fBottom->fID); |
1988 | disconnect(e); |
1989 | } else if (leftOverlap || rightOverlap) { |
1990 | TESS_LOG("found overlap edge %g -> %g%s\n" , |
1991 | e->fTop->fID, e->fBottom->fID, |
1992 | isOuterBoundary ? ", is outer boundary" : "" ); |
1993 | Vertex* prevVertex = e->fWinding < 0 ? e->fBottom : e->fTop; |
1994 | Vertex* nextVertex = e->fWinding < 0 ? e->fTop : e->fBottom; |
1995 | SSVertex* ssPrev = ssVertices[prevVertex]; |
1996 | if (!ssPrev) { |
1997 | ssPrev = ssVertices[prevVertex] = alloc.make<SSVertex>(prevVertex); |
1998 | } |
1999 | SSVertex* ssNext = ssVertices[nextVertex]; |
2000 | if (!ssNext) { |
2001 | ssNext = ssVertices[nextVertex] = alloc.make<SSVertex>(nextVertex); |
2002 | } |
2003 | SSEdge* ssEdge = alloc.make<SSEdge>(e, ssPrev, ssNext); |
2004 | ssEdges.push_back(ssEdge); |
2005 | // SkASSERT(!ssPrev->fNext && !ssNext->fPrev); |
2006 | ssPrev->fNext = ssNext->fPrev = ssEdge; |
2007 | create_event(ssEdge, &events, alloc); |
2008 | if (!isOuterBoundary) { |
2009 | disconnect(e); |
2010 | } |
2011 | } |
2012 | e = prev; |
2013 | } |
2014 | Edge* prev = leftEnclosingEdge; |
2015 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
2016 | if (prev) { |
2017 | e->fWinding += prev->fWinding; |
2018 | } |
2019 | insert_edge(e, prev, &activeEdges); |
2020 | prev = e; |
2021 | } |
2022 | } |
2023 | bool complex = events.size() > 0; |
2024 | |
2025 | TESS_LOG("\ncollapsing overlap regions\n" ); |
2026 | TESS_LOG("skeleton before:\n" ); |
2027 | dump_skel(ssEdges); |
2028 | while (events.size() > 0) { |
2029 | Event* event = events.top(); |
2030 | events.pop(); |
2031 | event->apply(mesh, c, &events, alloc); |
2032 | } |
2033 | TESS_LOG("skeleton after:\n" ); |
2034 | dump_skel(ssEdges); |
2035 | for (SSEdge* edge : ssEdges) { |
2036 | if (Edge* e = edge->fEdge) { |
2037 | connect(edge->fPrev->fVertex, edge->fNext->fVertex, e->fType, c, alloc, 0); |
2038 | } |
2039 | } |
2040 | return complex; |
2041 | } |
2042 | |
2043 | bool inversion(Vertex* prev, Vertex* next, Edge* origEdge, Comparator& c) { |
2044 | if (!prev || !next) { |
2045 | return true; |
2046 | } |
2047 | int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; |
2048 | return winding != origEdge->fWinding; |
2049 | } |
2050 | |
2051 | // Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to |
2052 | // find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a |
2053 | // new antialiased mesh from those vertices. |
2054 | |
2055 | void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh, |
2056 | Comparator& c, SkArenaAlloc& alloc) { |
2057 | TESS_LOG("\nstroking boundary\n" ); |
2058 | // A boundary with fewer than 3 edges is degenerate. |
2059 | if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) { |
2060 | return; |
2061 | } |
2062 | Edge* prevEdge = boundary->fTail; |
2063 | Vertex* prevV = prevEdge->fWinding > 0 ? prevEdge->fTop : prevEdge->fBottom; |
2064 | SkVector prevNormal; |
2065 | get_edge_normal(prevEdge, &prevNormal); |
2066 | double radius = 0.5; |
2067 | Line prevInner(prevEdge->fLine); |
2068 | prevInner.fC -= radius; |
2069 | Line prevOuter(prevEdge->fLine); |
2070 | prevOuter.fC += radius; |
2071 | VertexList innerVertices; |
2072 | VertexList outerVertices; |
2073 | bool innerInversion = true; |
2074 | bool outerInversion = true; |
2075 | for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) { |
2076 | Vertex* v = e->fWinding > 0 ? e->fTop : e->fBottom; |
2077 | SkVector normal; |
2078 | get_edge_normal(e, &normal); |
2079 | Line inner(e->fLine); |
2080 | inner.fC -= radius; |
2081 | Line outer(e->fLine); |
2082 | outer.fC += radius; |
2083 | SkPoint innerPoint, outerPoint; |
2084 | TESS_LOG("stroking vertex %g (%g, %g)\n" , v->fID, v->fPoint.fX, v->fPoint.fY); |
2085 | if (!prevEdge->fLine.nearParallel(e->fLine) && prevInner.intersect(inner, &innerPoint) && |
2086 | prevOuter.intersect(outer, &outerPoint)) { |
2087 | float cosAngle = normal.dot(prevNormal); |
2088 | if (cosAngle < -kCosMiterAngle) { |
2089 | Vertex* nextV = e->fWinding > 0 ? e->fBottom : e->fTop; |
2090 | |
2091 | // This is a pointy vertex whose angle is smaller than the threshold; miter it. |
2092 | Line bisector(innerPoint, outerPoint); |
2093 | Line tangent(v->fPoint, v->fPoint + SkPoint::Make(bisector.fA, bisector.fB)); |
2094 | if (tangent.fA == 0 && tangent.fB == 0) { |
2095 | continue; |
2096 | } |
2097 | tangent.normalize(); |
2098 | Line innerTangent(tangent); |
2099 | Line outerTangent(tangent); |
2100 | innerTangent.fC -= 0.5; |
2101 | outerTangent.fC += 0.5; |
2102 | SkPoint innerPoint1, innerPoint2, outerPoint1, outerPoint2; |
2103 | if (prevNormal.cross(normal) > 0) { |
2104 | // Miter inner points |
2105 | if (!innerTangent.intersect(prevInner, &innerPoint1) || |
2106 | !innerTangent.intersect(inner, &innerPoint2) || |
2107 | !outerTangent.intersect(bisector, &outerPoint)) { |
2108 | continue; |
2109 | } |
2110 | Line prevTangent(prevV->fPoint, |
2111 | prevV->fPoint + SkVector::Make(prevOuter.fA, prevOuter.fB)); |
2112 | Line nextTangent(nextV->fPoint, |
2113 | nextV->fPoint + SkVector::Make(outer.fA, outer.fB)); |
2114 | if (prevTangent.dist(outerPoint) > 0) { |
2115 | bisector.intersect(prevTangent, &outerPoint); |
2116 | } |
2117 | if (nextTangent.dist(outerPoint) < 0) { |
2118 | bisector.intersect(nextTangent, &outerPoint); |
2119 | } |
2120 | outerPoint1 = outerPoint2 = outerPoint; |
2121 | } else { |
2122 | // Miter outer points |
2123 | if (!outerTangent.intersect(prevOuter, &outerPoint1) || |
2124 | !outerTangent.intersect(outer, &outerPoint2)) { |
2125 | continue; |
2126 | } |
2127 | Line prevTangent(prevV->fPoint, |
2128 | prevV->fPoint + SkVector::Make(prevInner.fA, prevInner.fB)); |
2129 | Line nextTangent(nextV->fPoint, |
2130 | nextV->fPoint + SkVector::Make(inner.fA, inner.fB)); |
2131 | if (prevTangent.dist(innerPoint) > 0) { |
2132 | bisector.intersect(prevTangent, &innerPoint); |
2133 | } |
2134 | if (nextTangent.dist(innerPoint) < 0) { |
2135 | bisector.intersect(nextTangent, &innerPoint); |
2136 | } |
2137 | innerPoint1 = innerPoint2 = innerPoint; |
2138 | } |
2139 | if (!innerPoint1.isFinite() || !innerPoint2.isFinite() || |
2140 | !outerPoint1.isFinite() || !outerPoint2.isFinite()) { |
2141 | continue; |
2142 | } |
2143 | TESS_LOG("inner (%g, %g), (%g, %g), " , |
2144 | innerPoint1.fX, innerPoint1.fY, innerPoint2.fX, innerPoint2.fY); |
2145 | TESS_LOG("outer (%g, %g), (%g, %g)\n" , |
2146 | outerPoint1.fX, outerPoint1.fY, outerPoint2.fX, outerPoint2.fY); |
2147 | Vertex* innerVertex1 = alloc.make<Vertex>(innerPoint1, 255); |
2148 | Vertex* innerVertex2 = alloc.make<Vertex>(innerPoint2, 255); |
2149 | Vertex* outerVertex1 = alloc.make<Vertex>(outerPoint1, 0); |
2150 | Vertex* outerVertex2 = alloc.make<Vertex>(outerPoint2, 0); |
2151 | innerVertex1->fPartner = outerVertex1; |
2152 | innerVertex2->fPartner = outerVertex2; |
2153 | outerVertex1->fPartner = innerVertex1; |
2154 | outerVertex2->fPartner = innerVertex2; |
2155 | if (!inversion(innerVertices.fTail, innerVertex1, prevEdge, c)) { |
2156 | innerInversion = false; |
2157 | } |
2158 | if (!inversion(outerVertices.fTail, outerVertex1, prevEdge, c)) { |
2159 | outerInversion = false; |
2160 | } |
2161 | innerVertices.append(innerVertex1); |
2162 | innerVertices.append(innerVertex2); |
2163 | outerVertices.append(outerVertex1); |
2164 | outerVertices.append(outerVertex2); |
2165 | } else { |
2166 | TESS_LOG("inner (%g, %g), " , innerPoint.fX, innerPoint.fY); |
2167 | TESS_LOG("outer (%g, %g)\n" , outerPoint.fX, outerPoint.fY); |
2168 | Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255); |
2169 | Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0); |
2170 | innerVertex->fPartner = outerVertex; |
2171 | outerVertex->fPartner = innerVertex; |
2172 | if (!inversion(innerVertices.fTail, innerVertex, prevEdge, c)) { |
2173 | innerInversion = false; |
2174 | } |
2175 | if (!inversion(outerVertices.fTail, outerVertex, prevEdge, c)) { |
2176 | outerInversion = false; |
2177 | } |
2178 | innerVertices.append(innerVertex); |
2179 | outerVertices.append(outerVertex); |
2180 | } |
2181 | } |
2182 | prevInner = inner; |
2183 | prevOuter = outer; |
2184 | prevV = v; |
2185 | prevEdge = e; |
2186 | prevNormal = normal; |
2187 | } |
2188 | if (!inversion(innerVertices.fTail, innerVertices.fHead, prevEdge, c)) { |
2189 | innerInversion = false; |
2190 | } |
2191 | if (!inversion(outerVertices.fTail, outerVertices.fHead, prevEdge, c)) { |
2192 | outerInversion = false; |
2193 | } |
2194 | // Outer edges get 1 winding, and inner edges get -2 winding. This ensures that the interior |
2195 | // is always filled (1 + -2 = -1 for normal cases, 1 + 2 = 3 for thin features where the |
2196 | // interior inverts). |
2197 | // For total inversion cases, the shape has now reversed handedness, so invert the winding |
2198 | // so it will be detected during collapse_overlap_regions(). |
2199 | int innerWinding = innerInversion ? 2 : -2; |
2200 | int outerWinding = outerInversion ? -1 : 1; |
2201 | for (Vertex* v = innerVertices.fHead; v && v->fNext; v = v->fNext) { |
2202 | connect(v, v->fNext, Edge::Type::kInner, c, alloc, innerWinding); |
2203 | } |
2204 | connect(innerVertices.fTail, innerVertices.fHead, Edge::Type::kInner, c, alloc, innerWinding); |
2205 | for (Vertex* v = outerVertices.fHead; v && v->fNext; v = v->fNext) { |
2206 | connect(v, v->fNext, Edge::Type::kOuter, c, alloc, outerWinding); |
2207 | } |
2208 | connect(outerVertices.fTail, outerVertices.fHead, Edge::Type::kOuter, c, alloc, outerWinding); |
2209 | innerMesh->append(innerVertices); |
2210 | outerMesh->append(outerVertices); |
2211 | } |
2212 | |
2213 | void (EdgeList* boundary, Edge* e, SkPathFillType fillType, SkArenaAlloc& alloc) { |
2214 | TESS_LOG("\nextracting boundary\n" ); |
2215 | bool down = apply_fill_type(fillType, e->fWinding); |
2216 | Vertex* start = down ? e->fTop : e->fBottom; |
2217 | do { |
2218 | e->fWinding = down ? 1 : -1; |
2219 | Edge* next; |
2220 | e->fLine.normalize(); |
2221 | e->fLine = e->fLine * e->fWinding; |
2222 | boundary->append(e); |
2223 | if (down) { |
2224 | // Find outgoing edge, in clockwise order. |
2225 | if ((next = e->fNextEdgeAbove)) { |
2226 | down = false; |
2227 | } else if ((next = e->fBottom->fLastEdgeBelow)) { |
2228 | down = true; |
2229 | } else if ((next = e->fPrevEdgeAbove)) { |
2230 | down = false; |
2231 | } |
2232 | } else { |
2233 | // Find outgoing edge, in counter-clockwise order. |
2234 | if ((next = e->fPrevEdgeBelow)) { |
2235 | down = true; |
2236 | } else if ((next = e->fTop->fFirstEdgeAbove)) { |
2237 | down = false; |
2238 | } else if ((next = e->fNextEdgeBelow)) { |
2239 | down = true; |
2240 | } |
2241 | } |
2242 | disconnect(e); |
2243 | e = next; |
2244 | } while (e && (down ? e->fTop : e->fBottom) != start); |
2245 | } |
2246 | |
2247 | // Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh. |
2248 | |
2249 | void (const VertexList& inMesh, VertexList* innerVertices, |
2250 | VertexList* outerVertices, SkPathFillType fillType, |
2251 | Comparator& c, SkArenaAlloc& alloc) { |
2252 | remove_non_boundary_edges(inMesh, fillType, alloc); |
2253 | for (Vertex* v = inMesh.fHead; v; v = v->fNext) { |
2254 | while (v->fFirstEdgeBelow) { |
2255 | EdgeList boundary; |
2256 | extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc); |
2257 | simplify_boundary(&boundary, c, alloc); |
2258 | stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc); |
2259 | } |
2260 | } |
2261 | } |
2262 | |
2263 | // This is a driver function that calls stages 2-5 in turn. |
2264 | |
2265 | void contours_to_mesh(VertexList* contours, int contourCnt, Mode mode, |
2266 | VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
2267 | #if LOGGING_ENABLED |
2268 | for (int i = 0; i < contourCnt; ++i) { |
2269 | Vertex* v = contours[i].fHead; |
2270 | SkASSERT(v); |
2271 | TESS_LOG("path.moveTo(%20.20g, %20.20g);\n" , v->fPoint.fX, v->fPoint.fY); |
2272 | for (v = v->fNext; v; v = v->fNext) { |
2273 | TESS_LOG("path.lineTo(%20.20g, %20.20g);\n" , v->fPoint.fX, v->fPoint.fY); |
2274 | } |
2275 | } |
2276 | #endif |
2277 | sanitize_contours(contours, contourCnt, mode); |
2278 | build_edges(contours, contourCnt, mesh, c, alloc); |
2279 | } |
2280 | |
2281 | void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) { |
2282 | if (!vertices || !vertices->fHead) { |
2283 | return; |
2284 | } |
2285 | |
2286 | // Sort vertices in Y (secondarily in X). |
2287 | if (c.fDirection == Comparator::Direction::kHorizontal) { |
2288 | merge_sort<sweep_lt_horiz>(vertices); |
2289 | } else { |
2290 | merge_sort<sweep_lt_vert>(vertices); |
2291 | } |
2292 | #if LOGGING_ENABLED |
2293 | for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) { |
2294 | static float gID = 0.0f; |
2295 | v->fID = gID++; |
2296 | } |
2297 | #endif |
2298 | } |
2299 | |
2300 | Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPathFillType fillType, |
2301 | const SkRect& pathBounds, Mode mode, VertexList* outerMesh, |
2302 | SkArenaAlloc& alloc) { |
2303 | Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal |
2304 | : Comparator::Direction::kVertical); |
2305 | VertexList mesh; |
2306 | contours_to_mesh(contours, contourCnt, mode, &mesh, c, alloc); |
2307 | sort_mesh(&mesh, c, alloc); |
2308 | merge_coincident_vertices(&mesh, c, alloc); |
2309 | if (SimplifyResult::kAbort == simplify(mode, &mesh, c, alloc)) { |
2310 | return nullptr; |
2311 | } |
2312 | TESS_LOG("\nsimplified mesh:\n" ); |
2313 | dump_mesh(mesh); |
2314 | if (Mode::kEdgeAntialias == mode) { |
2315 | VertexList innerMesh; |
2316 | extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc); |
2317 | sort_mesh(&innerMesh, c, alloc); |
2318 | sort_mesh(outerMesh, c, alloc); |
2319 | merge_coincident_vertices(&innerMesh, c, alloc); |
2320 | bool was_complex = merge_coincident_vertices(outerMesh, c, alloc); |
2321 | auto result = simplify(mode, &innerMesh, c, alloc); |
2322 | SkASSERT(SimplifyResult::kAbort != result); |
2323 | was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex; |
2324 | result = simplify(mode, outerMesh, c, alloc); |
2325 | SkASSERT(SimplifyResult::kAbort != result); |
2326 | was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex; |
2327 | TESS_LOG("\ninner mesh before:\n" ); |
2328 | dump_mesh(innerMesh); |
2329 | TESS_LOG("\nouter mesh before:\n" ); |
2330 | dump_mesh(*outerMesh); |
2331 | EventComparator eventLT(EventComparator::Op::kLessThan); |
2332 | EventComparator eventGT(EventComparator::Op::kGreaterThan); |
2333 | was_complex = collapse_overlap_regions(&innerMesh, c, alloc, eventLT) || was_complex; |
2334 | was_complex = collapse_overlap_regions(outerMesh, c, alloc, eventGT) || was_complex; |
2335 | if (was_complex) { |
2336 | TESS_LOG("found complex mesh; taking slow path\n" ); |
2337 | VertexList aaMesh; |
2338 | TESS_LOG("\ninner mesh after:\n" ); |
2339 | dump_mesh(innerMesh); |
2340 | TESS_LOG("\nouter mesh after:\n" ); |
2341 | dump_mesh(*outerMesh); |
2342 | connect_partners(outerMesh, c, alloc); |
2343 | connect_partners(&innerMesh, c, alloc); |
2344 | sorted_merge(&innerMesh, outerMesh, &aaMesh, c); |
2345 | merge_coincident_vertices(&aaMesh, c, alloc); |
2346 | result = simplify(mode, &aaMesh, c, alloc); |
2347 | SkASSERT(SimplifyResult::kAbort != result); |
2348 | TESS_LOG("combined and simplified mesh:\n" ); |
2349 | dump_mesh(aaMesh); |
2350 | outerMesh->fHead = outerMesh->fTail = nullptr; |
2351 | return tessellate(fillType, mode, aaMesh, alloc); |
2352 | } else { |
2353 | TESS_LOG("no complex polygons; taking fast path\n" ); |
2354 | return tessellate(fillType, mode, innerMesh, alloc); |
2355 | } |
2356 | } else { |
2357 | return tessellate(fillType, mode, mesh, alloc); |
2358 | } |
2359 | } |
2360 | |
2361 | // Stage 6: Triangulate the monotone polygons into a vertex buffer. |
2362 | void* polys_to_triangles(Poly* polys, SkPathFillType fillType, Mode mode, void* data) { |
2363 | bool emitCoverage = (Mode::kEdgeAntialias == mode); |
2364 | for (Poly* poly = polys; poly; poly = poly->fNext) { |
2365 | if (apply_fill_type(fillType, poly)) { |
2366 | data = poly->emit(emitCoverage, data); |
2367 | } |
2368 | } |
2369 | return data; |
2370 | } |
2371 | |
2372 | Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
2373 | int contourCnt, SkArenaAlloc& alloc, Mode mode, bool* isLinear, |
2374 | VertexList* outerMesh) { |
2375 | SkPathFillType fillType = path.getFillType(); |
2376 | if (SkPathFillType_IsInverse(fillType)) { |
2377 | contourCnt++; |
2378 | } |
2379 | std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]); |
2380 | |
2381 | path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, mode, isLinear); |
2382 | return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(), |
2383 | mode, outerMesh, alloc); |
2384 | } |
2385 | |
2386 | int get_contour_count(const SkPath& path, SkScalar tolerance) { |
2387 | // We could theoretically be more aggressive about not counting empty contours, but we need to |
2388 | // actually match the exact number of contour linked lists the tessellator will create later on. |
2389 | int contourCnt = 1; |
2390 | bool hasPoints = false; |
2391 | |
2392 | SkPath::Iter iter(path, false); |
2393 | SkPath::Verb verb; |
2394 | SkPoint pts[4]; |
2395 | bool first = true; |
2396 | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
2397 | switch (verb) { |
2398 | case SkPath::kMove_Verb: |
2399 | if (!first) { |
2400 | ++contourCnt; |
2401 | } |
2402 | // fallthru. |
2403 | case SkPath::kLine_Verb: |
2404 | case SkPath::kConic_Verb: |
2405 | case SkPath::kQuad_Verb: |
2406 | case SkPath::kCubic_Verb: |
2407 | hasPoints = true; |
2408 | // fallthru to break. |
2409 | default: |
2410 | break; |
2411 | } |
2412 | first = false; |
2413 | } |
2414 | if (!hasPoints) { |
2415 | return 0; |
2416 | } |
2417 | return contourCnt; |
2418 | } |
2419 | |
2420 | int64_t count_points(Poly* polys, SkPathFillType fillType) { |
2421 | int64_t count = 0; |
2422 | for (Poly* poly = polys; poly; poly = poly->fNext) { |
2423 | if (apply_fill_type(fillType, poly) && poly->fCount >= 3) { |
2424 | count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3); |
2425 | } |
2426 | } |
2427 | return count; |
2428 | } |
2429 | |
2430 | int64_t count_outer_mesh_points(const VertexList& outerMesh) { |
2431 | int64_t count = 0; |
2432 | for (Vertex* v = outerMesh.fHead; v; v = v->fNext) { |
2433 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
2434 | count += TRIANGULATOR_WIREFRAME ? 12 : 6; |
2435 | } |
2436 | } |
2437 | return count; |
2438 | } |
2439 | |
2440 | void* outer_mesh_to_triangles(const VertexList& outerMesh, bool emitCoverage, void* data) { |
2441 | for (Vertex* v = outerMesh.fHead; v; v = v->fNext) { |
2442 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
2443 | Vertex* v0 = e->fTop; |
2444 | Vertex* v1 = e->fBottom; |
2445 | Vertex* v2 = e->fBottom->fPartner; |
2446 | Vertex* v3 = e->fTop->fPartner; |
2447 | data = emit_triangle(v0, v1, v2, emitCoverage, data); |
2448 | data = emit_triangle(v0, v2, v3, emitCoverage, data); |
2449 | } |
2450 | } |
2451 | return data; |
2452 | } |
2453 | |
2454 | } // namespace |
2455 | |
2456 | namespace GrTriangulator { |
2457 | |
2458 | // Stage 6: Triangulate the monotone polygons into a vertex buffer. |
2459 | |
2460 | int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
2461 | GrEagerVertexAllocator* vertexAllocator, Mode mode, bool* isLinear) { |
2462 | int contourCnt = get_contour_count(path, tolerance); |
2463 | if (contourCnt <= 0) { |
2464 | *isLinear = true; |
2465 | return 0; |
2466 | } |
2467 | SkArenaAlloc alloc(kArenaChunkSize); |
2468 | VertexList outerMesh; |
2469 | Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, mode, |
2470 | isLinear, &outerMesh); |
2471 | SkPathFillType fillType = (Mode::kEdgeAntialias == mode) ? |
2472 | SkPathFillType::kWinding : path.getFillType(); |
2473 | int64_t count64 = count_points(polys, fillType); |
2474 | if (Mode::kEdgeAntialias == mode) { |
2475 | count64 += count_outer_mesh_points(outerMesh); |
2476 | } |
2477 | if (0 == count64 || count64 > SK_MaxS32) { |
2478 | return 0; |
2479 | } |
2480 | int count = count64; |
2481 | |
2482 | size_t vertexStride = GetVertexStride(mode); |
2483 | void* verts = vertexAllocator->lock(vertexStride, count); |
2484 | if (!verts) { |
2485 | SkDebugf("Could not allocate vertices\n" ); |
2486 | return 0; |
2487 | } |
2488 | |
2489 | TESS_LOG("emitting %d verts\n" , count); |
2490 | void* end = polys_to_triangles(polys, fillType, mode, verts); |
2491 | end = outer_mesh_to_triangles(outerMesh, true, end); |
2492 | |
2493 | int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts)) |
2494 | / vertexStride); |
2495 | SkASSERT(actualCount <= count); |
2496 | vertexAllocator->unlock(actualCount); |
2497 | return actualCount; |
2498 | } |
2499 | |
2500 | int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
2501 | WindingVertex** verts) { |
2502 | int contourCnt = get_contour_count(path, tolerance); |
2503 | if (contourCnt <= 0) { |
2504 | *verts = nullptr; |
2505 | return 0; |
2506 | } |
2507 | SkArenaAlloc alloc(kArenaChunkSize); |
2508 | bool isLinear; |
2509 | Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, Mode::kNormal, |
2510 | &isLinear, nullptr); |
2511 | SkPathFillType fillType = path.getFillType(); |
2512 | int64_t count64 = count_points(polys, fillType); |
2513 | if (0 == count64 || count64 > SK_MaxS32) { |
2514 | *verts = nullptr; |
2515 | return 0; |
2516 | } |
2517 | int count = count64; |
2518 | |
2519 | *verts = new WindingVertex[count]; |
2520 | WindingVertex* vertsEnd = *verts; |
2521 | SkPoint* points = new SkPoint[count]; |
2522 | SkPoint* pointsEnd = points; |
2523 | for (Poly* poly = polys; poly; poly = poly->fNext) { |
2524 | if (apply_fill_type(fillType, poly)) { |
2525 | SkPoint* start = pointsEnd; |
2526 | pointsEnd = static_cast<SkPoint*>(poly->emit(false, pointsEnd)); |
2527 | while (start != pointsEnd) { |
2528 | vertsEnd->fPos = *start; |
2529 | vertsEnd->fWinding = poly->fWinding; |
2530 | ++start; |
2531 | ++vertsEnd; |
2532 | } |
2533 | } |
2534 | } |
2535 | int actualCount = static_cast<int>(vertsEnd - *verts); |
2536 | SkASSERT(actualCount <= count); |
2537 | SkASSERT(pointsEnd - points == actualCount); |
2538 | delete[] points; |
2539 | return actualCount; |
2540 | } |
2541 | |
2542 | } // namespace |
2543 | |