blob: a4ec79373a6a6565d896e04a96edcb7760cccde1 [file] [log] [blame]
ethannicholase9709e82016-01-07 13:34:16 -08001/*
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 "GrTessellator.h"
9
senorblancof57372d2016-08-31 10:36:19 -070010#include "GrDefaultGeoProcFactory.h"
ethannicholase9709e82016-01-07 13:34:16 -080011#include "GrPathUtils.h"
ethannicholase9709e82016-01-07 13:34:16 -080012
Herb Derby5cdc9dd2017-02-13 12:10:46 -050013#include "SkArenaAlloc.h"
senorblanco6599eff2016-03-10 08:38:45 -080014#include "SkGeometry.h"
15#include "SkPath.h"
ethannicholase9709e82016-01-07 13:34:16 -080016
17#include <stdio.h>
18
19/*
senorblancof57372d2016-08-31 10:36:19 -070020 * There are six stages to the basic algorithm:
ethannicholase9709e82016-01-07 13:34:16 -080021 *
22 * 1) Linearize the path contours into piecewise linear segments (path_to_contours()).
23 * 2) Build a mesh of edges connecting the vertices (build_edges()).
24 * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()).
25 * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()).
26 * 5) Tessellate the simplified mesh into monotone polygons (tessellate()).
27 * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()).
28 *
senorblancof57372d2016-08-31 10:36:19 -070029 * For screenspace antialiasing, the algorithm is modified as follows:
30 *
31 * Run steps 1-5 above to produce polygons.
32 * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()).
Stephen Whitebda29c02017-03-13 15:10:13 -040033 * 5c) Simplify boundaries to remove "pointy" vertices that cause inversions (simplify_boundary()).
senorblancof57372d2016-08-31 10:36:19 -070034 * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find
35 * new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a new
Stephen Whitebda29c02017-03-13 15:10:13 -040036 * antialiased mesh from those vertices (stroke_boundary()).
senorblancof57372d2016-08-31 10:36:19 -070037 * Run steps 3-6 above on the new mesh, and produce antialiased triangles.
38 *
ethannicholase9709e82016-01-07 13:34:16 -080039 * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
40 * of vertices (and the necessity of inserting new vertices on intersection).
41 *
Stephen Whitebda29c02017-03-13 15:10:13 -040042 * Stages (4) and (5) use an active edge list -- a list of all edges for which the
ethannicholase9709e82016-01-07 13:34:16 -080043 * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted
44 * left-to-right based on the point where both edges are active (when both top vertices
45 * have been seen, so the "lower" top vertex of the two). If the top vertices are equal
46 * (shared), it's sorted based on the last point where both edges are active, so the
47 * "upper" bottom vertex.
48 *
49 * The most complex step is the simplification (4). It's based on the Bentley-Ottman
50 * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
51 * not exact and may violate the mesh topology or active edge list ordering. We
52 * accommodate this by adjusting the topology of the mesh and AEL to match the intersection
53 * points. This occurs in three ways:
54 *
55 * A) Intersections may cause a shortened edge to no longer be ordered with respect to its
56 * neighbouring edges at the top or bottom vertex. This is handled by merging the
57 * edges (merge_collinear_edges()).
58 * B) Intersections may cause an edge to violate the left-to-right ordering of the
59 * active edge list. This is handled by splitting the neighbour edge on the
60 * intersected vertex (cleanup_active_edges()).
61 * C) Shortening an edge may cause an active edge to become inactive or an inactive edge
62 * to become active. This is handled by removing or inserting the edge in the active
63 * edge list (fix_active_state()).
64 *
65 * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
66 * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
67 * currently uses a linked list for the active edge list, rather than a 2-3 tree as the
68 * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
69 * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
70 * insertions and removals was greater than the cost of infrequent O(N) lookups with the
71 * linked list implementation. With the latter, all removals are O(1), and most insertions
72 * are O(1), since we know the adjacent edge in the active edge list based on the topology.
73 * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
74 * frequent. There may be other data structures worth investigating, however.
75 *
76 * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the
77 * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y
78 * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall,
79 * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so
80 * that the "left" and "right" orientation in the code remains correct (edges to the left are
81 * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90
82 * degrees counterclockwise, rather that transposing.
83 */
84
85#define LOGGING_ENABLED 0
86
87#if LOGGING_ENABLED
88#define LOG printf
89#else
90#define LOG(...)
91#endif
92
ethannicholase9709e82016-01-07 13:34:16 -080093namespace {
94
Stephen White11f65e02017-02-16 19:00:39 -050095const int kArenaChunkSize = 16 * 1024;
96
ethannicholase9709e82016-01-07 13:34:16 -080097struct Vertex;
98struct Edge;
99struct Poly;
100
101template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800102void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800103 t->*Prev = prev;
104 t->*Next = next;
105 if (prev) {
106 prev->*Next = t;
107 } else if (head) {
108 *head = t;
109 }
110 if (next) {
111 next->*Prev = t;
112 } else if (tail) {
113 *tail = t;
114 }
115}
116
117template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800118void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800119 if (t->*Prev) {
120 t->*Prev->*Next = t->*Next;
121 } else if (head) {
122 *head = t->*Next;
123 }
124 if (t->*Next) {
125 t->*Next->*Prev = t->*Prev;
126 } else if (tail) {
127 *tail = t->*Prev;
128 }
129 t->*Prev = t->*Next = nullptr;
130}
131
132/**
133 * Vertices are used in three ways: first, the path contours are converted into a
134 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
135 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
136 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
137 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
138 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
139 * an individual Vertex from the path mesh may belong to multiple
140 * MonotonePolys, so the original Vertices cannot be re-used.
141 */
142
143struct Vertex {
senorblancof57372d2016-08-31 10:36:19 -0700144 Vertex(const SkPoint& point, uint8_t alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800145 : fPoint(point), fPrev(nullptr), fNext(nullptr)
146 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
147 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
Stephen Whitebda29c02017-03-13 15:10:13 -0400148 , fPartner(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800149 , fProcessed(false)
senorblancof57372d2016-08-31 10:36:19 -0700150 , fAlpha(alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800151#if LOGGING_ENABLED
152 , fID (-1.0f)
153#endif
154 {}
155 SkPoint fPoint; // Vertex position
156 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
157 Vertex* fNext; // "
158 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
159 Edge* fLastEdgeAbove; // "
160 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
161 Edge* fLastEdgeBelow; // "
Stephen Whitebda29c02017-03-13 15:10:13 -0400162 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
ethannicholase9709e82016-01-07 13:34:16 -0800163 bool fProcessed; // Has this vertex been seen in simplify()?
senorblancof57372d2016-08-31 10:36:19 -0700164 uint8_t fAlpha;
ethannicholase9709e82016-01-07 13:34:16 -0800165#if LOGGING_ENABLED
166 float fID; // Identifier used for logging.
167#endif
168};
169
170/***************************************************************************************/
171
senorblancof57372d2016-08-31 10:36:19 -0700172struct AAParams {
173 bool fTweakAlpha;
174 GrColor fColor;
175};
176
ethannicholase9709e82016-01-07 13:34:16 -0800177typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
178
ethannicholase9709e82016-01-07 13:34:16 -0800179bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500180 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -0800181}
182
183bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500184 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -0800185}
186
Stephen White16a40cb2017-02-23 11:10:01 -0500187struct Comparator {
188 enum class Direction { kVertical, kHorizontal };
189 Comparator(Direction direction) : fDirection(direction) {}
190 bool sweep_lt(const SkPoint& a, const SkPoint& b) const {
191 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
192 }
Stephen White16a40cb2017-02-23 11:10:01 -0500193 Direction fDirection;
194};
195
senorblancof57372d2016-08-31 10:36:19 -0700196inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) {
197 if (!aaParams) {
198 SkPoint* d = static_cast<SkPoint*>(data);
199 *d++ = v->fPoint;
200 return d;
201 }
202 if (aaParams->fTweakAlpha) {
203 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorAttr*>(data);
204 d->fPosition = v->fPoint;
lsalzman8c8fcef2016-10-11 12:20:17 -0700205 d->fColor = SkAlphaMulQ(aaParams->fColor, SkAlpha255To256(v->fAlpha));
senorblancof57372d2016-08-31 10:36:19 -0700206 d++;
207 return d;
208 }
209 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorCoverageAttr*>(data);
210 d->fPosition = v->fPoint;
211 d->fColor = aaParams->fColor;
212 d->fCoverage = GrNormalizeByteToFloat(v->fAlpha);
213 d++;
214 return d;
ethannicholase9709e82016-01-07 13:34:16 -0800215}
216
senorblancof57372d2016-08-31 10:36:19 -0700217void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams, void* data) {
Stephen White92eba8a2017-02-06 09:50:27 -0500218 LOG("emit_triangle (%g, %g) %d\n", v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
219 LOG(" (%g, %g) %d\n", v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
220 LOG(" (%g, %g) %d\n", v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -0700221#if TESSELLATOR_WIREFRAME
222 data = emit_vertex(v0, aaParams, data);
223 data = emit_vertex(v1, aaParams, data);
224 data = emit_vertex(v1, aaParams, data);
225 data = emit_vertex(v2, aaParams, data);
226 data = emit_vertex(v2, aaParams, data);
227 data = emit_vertex(v0, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800228#else
senorblancof57372d2016-08-31 10:36:19 -0700229 data = emit_vertex(v0, aaParams, data);
230 data = emit_vertex(v1, aaParams, data);
231 data = emit_vertex(v2, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800232#endif
233 return data;
234}
235
senorblancoe6eaa322016-03-08 09:06:44 -0800236struct VertexList {
237 VertexList() : fHead(nullptr), fTail(nullptr) {}
Stephen White16a40cb2017-02-23 11:10:01 -0500238 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {}
senorblancoe6eaa322016-03-08 09:06:44 -0800239 Vertex* fHead;
240 Vertex* fTail;
241 void insert(Vertex* v, Vertex* prev, Vertex* next) {
242 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
243 }
244 void append(Vertex* v) {
245 insert(v, fTail, nullptr);
246 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400247 void append(const VertexList& list) {
248 if (!list.fHead) {
249 return;
250 }
251 if (fTail) {
252 fTail->fNext = list.fHead;
253 list.fHead->fPrev = fTail;
254 } else {
255 fHead = list.fHead;
256 }
257 fTail = list.fTail;
258 }
senorblancoe6eaa322016-03-08 09:06:44 -0800259 void prepend(Vertex* v) {
260 insert(v, nullptr, fHead);
261 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500262 void remove(Vertex* v) {
263 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
264 }
senorblancof57372d2016-08-31 10:36:19 -0700265 void close() {
266 if (fHead && fTail) {
267 fTail->fNext = fHead;
268 fHead->fPrev = fTail;
269 }
270 }
senorblancoe6eaa322016-03-08 09:06:44 -0800271};
272
senorblancof57372d2016-08-31 10:36:19 -0700273// Round to nearest quarter-pixel. This is used for screenspace tessellation.
274
275inline void round(SkPoint* p) {
276 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
277 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
278}
279
senorblanco49df8d12016-10-07 08:36:56 -0700280// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
281struct Line {
282 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
283 Line(const SkPoint& p, const SkPoint& q)
284 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
285 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
286 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
287 static_cast<double>(p.fX) * q.fY) {}
288 double dist(const SkPoint& p) const {
289 return fA * p.fX + fB * p.fY + fC;
290 }
291 double magSq() const {
292 return fA * fA + fB * fB;
293 }
294
295 // Compute the intersection of two (infinite) Lines.
296 bool intersect(const Line& other, SkPoint* point) {
297 double denom = fA * other.fB - fB * other.fA;
298 if (denom == 0.0) {
299 return false;
300 }
301 double scale = 1.0f / denom;
302 point->fX = SkDoubleToScalar((fB * other.fC - other.fB * fC) * scale);
303 point->fY = SkDoubleToScalar((other.fA * fC - fA * other.fC) * scale);
Stephen Whiteb56dedf2017-03-02 10:35:56 -0500304 round(point);
senorblanco49df8d12016-10-07 08:36:56 -0700305 return true;
306 }
307 double fA, fB, fC;
308};
309
ethannicholase9709e82016-01-07 13:34:16 -0800310/**
311 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
312 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
313 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
Stephen Whitebda29c02017-03-13 15:10:13 -0400314 * point). For speed, that case is only tested by the callers that require it (e.g.,
ethannicholase9709e82016-01-07 13:34:16 -0800315 * cleanup_active_edges()). Edges also handle checking for intersection with other edges.
316 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
317 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
318 * a lot faster in the "not found" case.
319 *
320 * The coefficients of the line equation stored in double precision to avoid catastrphic
321 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
322 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
323 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
324 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
325 * this file).
326 */
327
328struct Edge {
Stephen White2f4686f2017-01-03 16:20:01 -0500329 enum class Type { kInner, kOuter, kConnector };
330 Edge(Vertex* top, Vertex* bottom, int winding, Type type)
ethannicholase9709e82016-01-07 13:34:16 -0800331 : fWinding(winding)
332 , fTop(top)
333 , fBottom(bottom)
Stephen White2f4686f2017-01-03 16:20:01 -0500334 , fType(type)
ethannicholase9709e82016-01-07 13:34:16 -0800335 , fLeft(nullptr)
336 , fRight(nullptr)
337 , fPrevEdgeAbove(nullptr)
338 , fNextEdgeAbove(nullptr)
339 , fPrevEdgeBelow(nullptr)
340 , fNextEdgeBelow(nullptr)
341 , fLeftPoly(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700342 , fRightPoly(nullptr)
343 , fLeftPolyPrev(nullptr)
344 , fLeftPolyNext(nullptr)
345 , fRightPolyPrev(nullptr)
senorblanco70f52512016-08-17 14:56:22 -0700346 , fRightPolyNext(nullptr)
347 , fUsedInLeftPoly(false)
senorblanco49df8d12016-10-07 08:36:56 -0700348 , fUsedInRightPoly(false)
349 , fLine(top, bottom) {
ethannicholase9709e82016-01-07 13:34:16 -0800350 }
351 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
352 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
353 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
Stephen White2f4686f2017-01-03 16:20:01 -0500354 Type fType;
ethannicholase9709e82016-01-07 13:34:16 -0800355 Edge* fLeft; // The linked list of edges in the active edge list.
356 Edge* fRight; // "
357 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
358 Edge* fNextEdgeAbove; // "
359 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
360 Edge* fNextEdgeBelow; // "
361 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
362 Poly* fRightPoly; // The Poly to the right of this edge, if any.
senorblanco531237e2016-06-02 11:36:48 -0700363 Edge* fLeftPolyPrev;
364 Edge* fLeftPolyNext;
365 Edge* fRightPolyPrev;
366 Edge* fRightPolyNext;
senorblanco70f52512016-08-17 14:56:22 -0700367 bool fUsedInLeftPoly;
368 bool fUsedInRightPoly;
senorblanco49df8d12016-10-07 08:36:56 -0700369 Line fLine;
ethannicholase9709e82016-01-07 13:34:16 -0800370 double dist(const SkPoint& p) const {
senorblanco49df8d12016-10-07 08:36:56 -0700371 return fLine.dist(p);
ethannicholase9709e82016-01-07 13:34:16 -0800372 }
373 bool isRightOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700374 return fLine.dist(v->fPoint) < 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800375 }
376 bool isLeftOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700377 return fLine.dist(v->fPoint) > 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800378 }
379 void recompute() {
senorblanco49df8d12016-10-07 08:36:56 -0700380 fLine = Line(fTop, fBottom);
ethannicholase9709e82016-01-07 13:34:16 -0800381 }
Ben Wagnerdab48112017-02-16 22:28:02 +0000382 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) {
ethannicholase9709e82016-01-07 13:34:16 -0800383 LOG("intersecting %g -> %g with %g -> %g\n",
384 fTop->fID, fBottom->fID,
385 other.fTop->fID, other.fBottom->fID);
386 if (fTop == other.fTop || fBottom == other.fBottom) {
387 return false;
388 }
senorblanco49df8d12016-10-07 08:36:56 -0700389 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800390 if (denom == 0.0) {
391 return false;
392 }
Stephen White8a0bfc52017-02-21 15:24:13 -0500393 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
394 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
395 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
396 double tNumer = dy * fLine.fB + dx * fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800397 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
398 // This saves us doing the divide below unless absolutely necessary.
399 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
400 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
401 return false;
402 }
403 double s = sNumer / denom;
404 SkASSERT(s >= 0.0 && s <= 1.0);
senorblanco49df8d12016-10-07 08:36:56 -0700405 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
406 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
Stephen White56158ae2017-01-30 14:31:31 -0500407 if (alpha) {
Stephen White92eba8a2017-02-06 09:50:27 -0500408 if (fType == Type::kConnector) {
409 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
410 } else if (other.fType == Type::kConnector) {
411 double t = tNumer / denom;
412 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
Stephen White56158ae2017-01-30 14:31:31 -0500413 } else if (fType == Type::kOuter && other.fType == Type::kOuter) {
414 *alpha = 0;
415 } else {
Stephen White92eba8a2017-02-06 09:50:27 -0500416 *alpha = 255;
Stephen White56158ae2017-01-30 14:31:31 -0500417 }
418 }
ethannicholase9709e82016-01-07 13:34:16 -0800419 return true;
420 }
senorblancof57372d2016-08-31 10:36:19 -0700421};
422
423struct EdgeList {
Stephen White5ad721e2017-02-23 16:50:47 -0500424 EdgeList() : fHead(nullptr), fTail(nullptr) {}
senorblancof57372d2016-08-31 10:36:19 -0700425 Edge* fHead;
426 Edge* fTail;
senorblancof57372d2016-08-31 10:36:19 -0700427 void insert(Edge* edge, Edge* prev, Edge* next) {
428 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700429 }
430 void append(Edge* e) {
431 insert(e, fTail, nullptr);
432 }
433 void remove(Edge* edge) {
434 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700435 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400436 void removeAll() {
437 while (fHead) {
438 this->remove(fHead);
439 }
440 }
senorblancof57372d2016-08-31 10:36:19 -0700441 void close() {
442 if (fHead && fTail) {
443 fTail->fRight = fHead;
444 fHead->fLeft = fTail;
445 }
446 }
447 bool contains(Edge* edge) const {
448 return edge->fLeft || edge->fRight || fHead == edge;
ethannicholase9709e82016-01-07 13:34:16 -0800449 }
450};
451
452/***************************************************************************************/
453
454struct Poly {
senorblanco531237e2016-06-02 11:36:48 -0700455 Poly(Vertex* v, int winding)
456 : fFirstVertex(v)
457 , fWinding(winding)
ethannicholase9709e82016-01-07 13:34:16 -0800458 , fHead(nullptr)
459 , fTail(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800460 , fNext(nullptr)
461 , fPartner(nullptr)
462 , fCount(0)
463 {
464#if LOGGING_ENABLED
465 static int gID = 0;
466 fID = gID++;
467 LOG("*** created Poly %d\n", fID);
468#endif
469 }
senorblanco531237e2016-06-02 11:36:48 -0700470 typedef enum { kLeft_Side, kRight_Side } Side;
ethannicholase9709e82016-01-07 13:34:16 -0800471 struct MonotonePoly {
senorblanco531237e2016-06-02 11:36:48 -0700472 MonotonePoly(Edge* edge, Side side)
473 : fSide(side)
474 , fFirstEdge(nullptr)
475 , fLastEdge(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800476 , fPrev(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700477 , fNext(nullptr) {
478 this->addEdge(edge);
479 }
ethannicholase9709e82016-01-07 13:34:16 -0800480 Side fSide;
senorblanco531237e2016-06-02 11:36:48 -0700481 Edge* fFirstEdge;
482 Edge* fLastEdge;
ethannicholase9709e82016-01-07 13:34:16 -0800483 MonotonePoly* fPrev;
484 MonotonePoly* fNext;
senorblanco531237e2016-06-02 11:36:48 -0700485 void addEdge(Edge* edge) {
senorblancoe6eaa322016-03-08 09:06:44 -0800486 if (fSide == kRight_Side) {
senorblanco212c7c32016-08-18 10:20:47 -0700487 SkASSERT(!edge->fUsedInRightPoly);
senorblanco531237e2016-06-02 11:36:48 -0700488 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
489 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700490 edge->fUsedInRightPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800491 } else {
senorblanco212c7c32016-08-18 10:20:47 -0700492 SkASSERT(!edge->fUsedInLeftPoly);
senorblanco531237e2016-06-02 11:36:48 -0700493 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
494 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700495 edge->fUsedInLeftPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800496 }
ethannicholase9709e82016-01-07 13:34:16 -0800497 }
498
senorblancof57372d2016-08-31 10:36:19 -0700499 void* emit(const AAParams* aaParams, void* data) {
senorblanco531237e2016-06-02 11:36:48 -0700500 Edge* e = fFirstEdge;
senorblanco531237e2016-06-02 11:36:48 -0700501 VertexList vertices;
502 vertices.append(e->fTop);
Stephen White651cbe92017-03-03 12:24:16 -0500503 int count = 1;
senorblanco531237e2016-06-02 11:36:48 -0700504 while (e != nullptr) {
senorblanco531237e2016-06-02 11:36:48 -0700505 if (kRight_Side == fSide) {
506 vertices.append(e->fBottom);
507 e = e->fRightPolyNext;
508 } else {
509 vertices.prepend(e->fBottom);
510 e = e->fLeftPolyNext;
511 }
Stephen White651cbe92017-03-03 12:24:16 -0500512 count++;
senorblanco531237e2016-06-02 11:36:48 -0700513 }
514 Vertex* first = vertices.fHead;
ethannicholase9709e82016-01-07 13:34:16 -0800515 Vertex* v = first->fNext;
senorblanco531237e2016-06-02 11:36:48 -0700516 while (v != vertices.fTail) {
ethannicholase9709e82016-01-07 13:34:16 -0800517 SkASSERT(v && v->fPrev && v->fNext);
518 Vertex* prev = v->fPrev;
519 Vertex* curr = v;
520 Vertex* next = v->fNext;
Stephen White651cbe92017-03-03 12:24:16 -0500521 if (count == 3) {
522 return emit_triangle(prev, curr, next, aaParams, data);
523 }
ethannicholase9709e82016-01-07 13:34:16 -0800524 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
525 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
526 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
527 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
528 if (ax * by - ay * bx >= 0.0) {
senorblancof57372d2016-08-31 10:36:19 -0700529 data = emit_triangle(prev, curr, next, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800530 v->fPrev->fNext = v->fNext;
531 v->fNext->fPrev = v->fPrev;
Stephen White651cbe92017-03-03 12:24:16 -0500532 count--;
ethannicholase9709e82016-01-07 13:34:16 -0800533 if (v->fPrev == first) {
534 v = v->fNext;
535 } else {
536 v = v->fPrev;
537 }
538 } else {
539 v = v->fNext;
540 }
541 }
542 return data;
543 }
544 };
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500545 Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
senorblanco70f52512016-08-17 14:56:22 -0700546 LOG("addEdge (%g -> %g) to poly %d, %s side\n",
547 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
ethannicholase9709e82016-01-07 13:34:16 -0800548 Poly* partner = fPartner;
549 Poly* poly = this;
senorblanco212c7c32016-08-18 10:20:47 -0700550 if (side == kRight_Side) {
551 if (e->fUsedInRightPoly) {
552 return this;
553 }
554 } else {
555 if (e->fUsedInLeftPoly) {
556 return this;
557 }
558 }
ethannicholase9709e82016-01-07 13:34:16 -0800559 if (partner) {
560 fPartner = partner->fPartner = nullptr;
561 }
senorblanco531237e2016-06-02 11:36:48 -0700562 if (!fTail) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500563 fHead = fTail = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700564 fCount += 2;
senorblanco93e3fff2016-06-07 12:36:00 -0700565 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
566 return poly;
senorblanco531237e2016-06-02 11:36:48 -0700567 } else if (side == fTail->fSide) {
568 fTail->addEdge(e);
569 fCount++;
570 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500571 e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -0700572 fTail->addEdge(e);
573 fCount++;
ethannicholase9709e82016-01-07 13:34:16 -0800574 if (partner) {
senorblanco531237e2016-06-02 11:36:48 -0700575 partner->addEdge(e, side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800576 poly = partner;
577 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500578 MonotonePoly* m = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700579 m->fPrev = fTail;
580 fTail->fNext = m;
581 fTail = m;
ethannicholase9709e82016-01-07 13:34:16 -0800582 }
583 }
ethannicholase9709e82016-01-07 13:34:16 -0800584 return poly;
585 }
senorblancof57372d2016-08-31 10:36:19 -0700586 void* emit(const AAParams* aaParams, void *data) {
ethannicholase9709e82016-01-07 13:34:16 -0800587 if (fCount < 3) {
588 return data;
589 }
590 LOG("emit() %d, size %d\n", fID, fCount);
591 for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) {
senorblancof57372d2016-08-31 10:36:19 -0700592 data = m->emit(aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800593 }
594 return data;
595 }
senorblanco531237e2016-06-02 11:36:48 -0700596 Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; }
597 Vertex* fFirstVertex;
ethannicholase9709e82016-01-07 13:34:16 -0800598 int fWinding;
599 MonotonePoly* fHead;
600 MonotonePoly* fTail;
ethannicholase9709e82016-01-07 13:34:16 -0800601 Poly* fNext;
602 Poly* fPartner;
603 int fCount;
604#if LOGGING_ENABLED
605 int fID;
606#endif
607};
608
609/***************************************************************************************/
610
611bool coincident(const SkPoint& a, const SkPoint& b) {
612 return a == b;
613}
614
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500615Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) {
616 Poly* poly = alloc.make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800617 poly->fNext = *head;
618 *head = poly;
619 return poly;
620}
621
Stephen White3a9aab92017-03-07 14:07:18 -0500622void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500623 Vertex* v = alloc.make<Vertex>(p, 255);
ethannicholase9709e82016-01-07 13:34:16 -0800624#if LOGGING_ENABLED
625 static float gID = 0.0f;
626 v->fID = gID++;
627#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500628 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800629}
630
Stephen White36e4f062017-03-27 16:11:31 -0400631SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
632 SkQuadCoeff quad(pts);
633 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
634 SkPoint mid = to_point(quad.eval(t));
635 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
636 return mid.distanceToLineSegmentBetweenSqd(p0, p1);
637}
638
639void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour,
640 SkArenaAlloc& alloc) {
641 SkQuadCoeff quad(pts);
642 Sk2s aa = quad.fA * quad.fA;
643 SkScalar denom = 2.0f * (aa[0] + aa[1]);
644 Sk2s ab = quad.fA * quad.fB;
645 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
646 int nPoints = 1;
647 SkScalar u;
648 // Test possible subdivision values only at the point of maximum curvature.
649 // If it passes the flatness metric there, it'll pass everywhere.
650 for (;;) {
651 u = 1.0f / nPoints;
652 if (quad_error_at(pts, t, u) < toleranceSqd) {
653 break;
654 }
655 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800656 }
Stephen White36e4f062017-03-27 16:11:31 -0400657 for (int j = 1; j <= nPoints; j++) {
658 append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc);
659 }
ethannicholase9709e82016-01-07 13:34:16 -0800660}
661
Stephen White3a9aab92017-03-07 14:07:18 -0500662void generate_cubic_points(const SkPoint& p0,
663 const SkPoint& p1,
664 const SkPoint& p2,
665 const SkPoint& p3,
666 SkScalar tolSqd,
667 VertexList* contour,
668 int pointsLeft,
669 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -0800670 SkScalar d1 = p1.distanceToLineSegmentBetweenSqd(p0, p3);
671 SkScalar d2 = p2.distanceToLineSegmentBetweenSqd(p0, p3);
672 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
673 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Stephen White3a9aab92017-03-07 14:07:18 -0500674 append_point_to_contour(p3, contour, alloc);
675 return;
ethannicholase9709e82016-01-07 13:34:16 -0800676 }
677 const SkPoint q[] = {
678 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
679 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
680 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
681 };
682 const SkPoint r[] = {
683 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
684 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
685 };
686 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
687 pointsLeft >>= 1;
Stephen White3a9aab92017-03-07 14:07:18 -0500688 generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc);
689 generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800690}
691
692// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
693
694void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen White3a9aab92017-03-07 14:07:18 -0500695 VertexList* contours, SkArenaAlloc& alloc, bool *isLinear) {
ethannicholase9709e82016-01-07 13:34:16 -0800696 SkScalar toleranceSqd = tolerance * tolerance;
697
698 SkPoint pts[4];
ethannicholase9709e82016-01-07 13:34:16 -0800699 *isLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500700 VertexList* contour = contours;
ethannicholase9709e82016-01-07 13:34:16 -0800701 SkPath::Iter iter(path, false);
ethannicholase9709e82016-01-07 13:34:16 -0800702 if (path.isInverseFillType()) {
703 SkPoint quad[4];
704 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700705 for (int i = 3; i >= 0; i--) {
Stephen White3a9aab92017-03-07 14:07:18 -0500706 append_point_to_contour(quad[i], contours, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800707 }
Stephen White3a9aab92017-03-07 14:07:18 -0500708 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800709 }
710 SkAutoConicToQuads converter;
Stephen White3a9aab92017-03-07 14:07:18 -0500711 SkPath::Verb verb;
712 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800713 switch (verb) {
714 case SkPath::kConic_Verb: {
715 SkScalar weight = iter.conicWeight();
716 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
717 for (int i = 0; i < converter.countQuads(); ++i) {
Stephen White36e4f062017-03-27 16:11:31 -0400718 append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800719 quadPts += 2;
720 }
721 *isLinear = false;
722 break;
723 }
724 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500725 if (contour->fHead) {
726 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800727 }
Stephen White3a9aab92017-03-07 14:07:18 -0500728 append_point_to_contour(pts[0], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800729 break;
730 case SkPath::kLine_Verb: {
Stephen White3a9aab92017-03-07 14:07:18 -0500731 append_point_to_contour(pts[1], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800732 break;
733 }
734 case SkPath::kQuad_Verb: {
Stephen White36e4f062017-03-27 16:11:31 -0400735 append_quadratic_to_contour(pts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800736 *isLinear = false;
737 break;
738 }
739 case SkPath::kCubic_Verb: {
740 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Stephen White3a9aab92017-03-07 14:07:18 -0500741 generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
742 pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800743 *isLinear = false;
744 break;
745 }
746 case SkPath::kClose_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800747 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800748 break;
749 }
750 }
751}
752
Stephen White49789062017-02-21 10:35:49 -0500753inline bool apply_fill_type(SkPath::FillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800754 switch (fillType) {
755 case SkPath::kWinding_FillType:
756 return winding != 0;
757 case SkPath::kEvenOdd_FillType:
758 return (winding & 1) != 0;
759 case SkPath::kInverseWinding_FillType:
senorblanco7ab96e92016-10-12 06:47:44 -0700760 return winding == 1;
ethannicholase9709e82016-01-07 13:34:16 -0800761 case SkPath::kInverseEvenOdd_FillType:
762 return (winding & 1) == 1;
763 default:
764 SkASSERT(false);
765 return false;
766 }
767}
768
Stephen White49789062017-02-21 10:35:49 -0500769inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) {
770 return poly && apply_fill_type(fillType, poly->fWinding);
771}
772
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500773Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) {
Stephen White2f4686f2017-01-03 16:20:01 -0500774 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800775 Vertex* top = winding < 0 ? next : prev;
776 Vertex* bottom = winding < 0 ? prev : next;
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500777 return alloc.make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800778}
779
780void remove_edge(Edge* edge, EdgeList* edges) {
781 LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700782 SkASSERT(edges->contains(edge));
783 edges->remove(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800784}
785
786void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) {
787 LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700788 SkASSERT(!edges->contains(edge));
ethannicholase9709e82016-01-07 13:34:16 -0800789 Edge* next = prev ? prev->fRight : edges->fHead;
senorblancof57372d2016-08-31 10:36:19 -0700790 edges->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800791}
792
793void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500794 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800795 *left = v->fFirstEdgeAbove->fLeft;
796 *right = v->fLastEdgeAbove->fRight;
797 return;
798 }
799 Edge* next = nullptr;
800 Edge* prev;
801 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
802 if (prev->isLeftOf(v)) {
803 break;
804 }
805 next = prev;
806 }
807 *left = prev;
808 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800809}
810
811void find_enclosing_edges(Edge* edge, EdgeList* edges, Comparator& c, Edge** left, Edge** right) {
812 Edge* prev = nullptr;
813 Edge* next;
814 for (next = edges->fHead; next != nullptr; next = next->fRight) {
Stephen Whitee30cf802017-02-27 11:37:55 -0500815 if ((c.sweep_lt(next->fTop->fPoint, edge->fTop->fPoint) && next->isRightOf(edge->fTop)) ||
816 (c.sweep_lt(edge->fTop->fPoint, next->fTop->fPoint) && edge->isLeftOf(next->fTop)) ||
ethannicholase9709e82016-01-07 13:34:16 -0800817 (c.sweep_lt(edge->fBottom->fPoint, next->fBottom->fPoint) &&
818 next->isRightOf(edge->fBottom)) ||
819 (c.sweep_lt(next->fBottom->fPoint, edge->fBottom->fPoint) &&
820 edge->isLeftOf(next->fBottom))) {
821 break;
822 }
823 prev = next;
824 }
825 *left = prev;
826 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800827}
828
829void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) {
Stephen White2f4686f2017-01-03 16:20:01 -0500830 if (!activeEdges) {
831 return;
832 }
833 if (activeEdges->contains(edge)) {
ethannicholase9709e82016-01-07 13:34:16 -0800834 if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) {
835 remove_edge(edge, activeEdges);
836 }
837 } else if (edge->fTop->fProcessed && !edge->fBottom->fProcessed) {
838 Edge* left;
839 Edge* right;
840 find_enclosing_edges(edge, activeEdges, c, &left, &right);
841 insert_edge(edge, left, activeEdges);
842 }
843}
844
845void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) {
846 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500847 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800848 return;
849 }
850 LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
851 Edge* prev = nullptr;
852 Edge* next;
853 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
854 if (next->isRightOf(edge->fTop)) {
855 break;
856 }
857 prev = next;
858 }
senorblancoe6eaa322016-03-08 09:06:44 -0800859 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800860 edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
861}
862
863void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) {
864 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500865 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800866 return;
867 }
868 LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
869 Edge* prev = nullptr;
870 Edge* next;
871 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
872 if (next->isRightOf(edge->fBottom)) {
873 break;
874 }
875 prev = next;
876 }
senorblancoe6eaa322016-03-08 09:06:44 -0800877 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800878 edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
879}
880
881void remove_edge_above(Edge* edge) {
882 LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
883 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800884 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800885 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
886}
887
888void remove_edge_below(Edge* edge) {
889 LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
890 edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800891 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800892 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
893}
894
Stephen Whitee7a364d2017-01-11 16:19:26 -0500895void disconnect(Edge* edge)
896{
ethannicholase9709e82016-01-07 13:34:16 -0800897 remove_edge_above(edge);
898 remove_edge_below(edge);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500899}
900
901void erase_edge(Edge* edge, EdgeList* edges) {
902 LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID);
903 disconnect(edge);
senorblancof57372d2016-08-31 10:36:19 -0700904 if (edges && edges->contains(edge)) {
ethannicholase9709e82016-01-07 13:34:16 -0800905 remove_edge(edge, edges);
906 }
907}
908
909void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c);
910
911void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) {
912 remove_edge_below(edge);
913 edge->fTop = v;
914 edge->recompute();
915 insert_edge_below(edge, v, c);
916 fix_active_state(edge, activeEdges, c);
917 merge_collinear_edges(edge, activeEdges, c);
918}
919
920void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c) {
921 remove_edge_above(edge);
922 edge->fBottom = v;
923 edge->recompute();
924 insert_edge_above(edge, v, c);
925 fix_active_state(edge, activeEdges, c);
926 merge_collinear_edges(edge, activeEdges, c);
927}
928
929void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) {
930 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
931 LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
932 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
933 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
934 other->fWinding += edge->fWinding;
Stephen Whitee7a364d2017-01-11 16:19:26 -0500935 erase_edge(edge, activeEdges);
ethannicholase9709e82016-01-07 13:34:16 -0800936 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
937 other->fWinding += edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800938 set_bottom(edge, other->fTop, activeEdges, c);
939 } else {
940 edge->fWinding += other->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800941 set_bottom(other, edge->fTop, activeEdges, c);
942 }
943}
944
945void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c) {
946 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
947 LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
948 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
949 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
950 other->fWinding += edge->fWinding;
Stephen Whitee7a364d2017-01-11 16:19:26 -0500951 erase_edge(edge, activeEdges);
ethannicholase9709e82016-01-07 13:34:16 -0800952 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
953 edge->fWinding += other->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800954 set_top(other, edge->fBottom, activeEdges, c);
955 } else {
956 other->fWinding += edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800957 set_top(edge, other->fBottom, activeEdges, c);
958 }
959}
960
961void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Comparator& c) {
962 if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
963 !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
964 merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, c);
965 } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
966 !edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
967 merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, c);
968 }
969 if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
970 !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
971 merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, c);
972 } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
973 !edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
974 merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, c);
975 }
976}
977
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500978void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800979
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500980void cleanup_active_edges(Edge* edge, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -0800981 Vertex* top = edge->fTop;
982 Vertex* bottom = edge->fBottom;
983 if (edge->fLeft) {
984 Vertex* leftTop = edge->fLeft->fTop;
985 Vertex* leftBottom = edge->fLeft->fBottom;
Stephen Whitee30cf802017-02-27 11:37:55 -0500986 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
ethannicholase9709e82016-01-07 13:34:16 -0800987 split_edge(edge->fLeft, edge->fTop, activeEdges, c, alloc);
Stephen Whitee30cf802017-02-27 11:37:55 -0500988 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
ethannicholase9709e82016-01-07 13:34:16 -0800989 split_edge(edge, leftTop, activeEdges, c, alloc);
990 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
991 !edge->fLeft->isLeftOf(bottom)) {
992 split_edge(edge->fLeft, bottom, activeEdges, c, alloc);
993 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
994 split_edge(edge, leftBottom, activeEdges, c, alloc);
995 }
996 }
997 if (edge->fRight) {
998 Vertex* rightTop = edge->fRight->fTop;
999 Vertex* rightBottom = edge->fRight->fBottom;
Stephen Whitee30cf802017-02-27 11:37:55 -05001000 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
ethannicholase9709e82016-01-07 13:34:16 -08001001 split_edge(edge->fRight, top, activeEdges, c, alloc);
Stephen Whitee30cf802017-02-27 11:37:55 -05001002 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
ethannicholase9709e82016-01-07 13:34:16 -08001003 split_edge(edge, rightTop, activeEdges, c, alloc);
1004 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
1005 !edge->fRight->isRightOf(bottom)) {
1006 split_edge(edge->fRight, bottom, activeEdges, c, alloc);
1007 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
1008 !edge->isLeftOf(rightBottom)) {
1009 split_edge(edge, rightBottom, activeEdges, c, alloc);
1010 }
1011 }
1012}
1013
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001014void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001015 LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
1016 edge->fTop->fID, edge->fBottom->fID,
1017 v->fID, v->fPoint.fX, v->fPoint.fY);
1018 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
1019 set_top(edge, v, activeEdges, c);
Stephen Whitee30cf802017-02-27 11:37:55 -05001020 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -08001021 set_bottom(edge, v, activeEdges, c);
1022 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001023 Edge* newEdge = alloc.make<Edge>(v, edge->fBottom, edge->fWinding, edge->fType);
ethannicholase9709e82016-01-07 13:34:16 -08001024 insert_edge_below(newEdge, v, c);
1025 insert_edge_above(newEdge, edge->fBottom, c);
1026 set_bottom(edge, v, activeEdges, c);
1027 cleanup_active_edges(edge, activeEdges, c, alloc);
1028 fix_active_state(newEdge, activeEdges, c);
1029 merge_collinear_edges(newEdge, activeEdges, c);
1030 }
1031}
1032
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001033Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc,
Stephen White48ded382017-02-03 10:15:16 -05001034 int winding_scale = 1) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001035 Edge* edge = new_edge(prev, next, type, c, alloc);
Stephen White8a0bfc52017-02-21 15:24:13 -05001036 insert_edge_below(edge, edge->fTop, c);
1037 insert_edge_above(edge, edge->fBottom, c);
Stephen White48ded382017-02-03 10:15:16 -05001038 edge->fWinding *= winding_scale;
senorblancof57372d2016-08-31 10:36:19 -07001039 merge_collinear_edges(edge, nullptr, c);
1040 return edge;
1041}
1042
Stephen Whitebf6137e2017-01-04 15:43:26 -05001043void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001044 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001045 LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY,
1046 src->fID, dst->fID);
senorblancof57372d2016-08-31 10:36:19 -07001047 dst->fAlpha = SkTMax(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -04001048 if (src->fPartner) {
1049 src->fPartner->fPartner = dst;
1050 }
ethannicholase9709e82016-01-07 13:34:16 -08001051 for (Edge* edge = src->fFirstEdgeAbove; edge;) {
1052 Edge* next = edge->fNextEdgeAbove;
1053 set_bottom(edge, dst, nullptr, c);
1054 edge = next;
1055 }
1056 for (Edge* edge = src->fFirstEdgeBelow; edge;) {
1057 Edge* next = edge->fNextEdgeBelow;
1058 set_top(edge, dst, nullptr, c);
1059 edge = next;
1060 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001061 mesh->remove(src);
ethannicholase9709e82016-01-07 13:34:16 -08001062}
1063
senorblancof57372d2016-08-31 10:36:19 -07001064uint8_t max_edge_alpha(Edge* a, Edge* b) {
Stephen White56158ae2017-01-30 14:31:31 -05001065 if (a->fType == Edge::Type::kInner || b->fType == Edge::Type::kInner) {
Stephen White2f4686f2017-01-03 16:20:01 -05001066 return 255;
1067 } else if (a->fType == Edge::Type::kOuter && b->fType == Edge::Type::kOuter) {
1068 return 0;
1069 } else {
1070 return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha),
1071 SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha));
1072 }
senorblancof57372d2016-08-31 10:36:19 -07001073}
1074
ethannicholase9709e82016-01-07 13:34:16 -08001075Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001076 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001077 if (!edge || !other) {
1078 return nullptr;
1079 }
Stephen White56158ae2017-01-30 14:31:31 -05001080 SkPoint p;
1081 uint8_t alpha;
1082 if (edge->intersect(*other, &p, &alpha)) {
ethannicholase9709e82016-01-07 13:34:16 -08001083 Vertex* v;
1084 LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
1085 if (p == edge->fTop->fPoint || c.sweep_lt(p, edge->fTop->fPoint)) {
1086 split_edge(other, edge->fTop, activeEdges, c, alloc);
1087 v = edge->fTop;
Stephen Whitee30cf802017-02-27 11:37:55 -05001088 } else if (p == edge->fBottom->fPoint || c.sweep_lt(edge->fBottom->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001089 split_edge(other, edge->fBottom, activeEdges, c, alloc);
1090 v = edge->fBottom;
1091 } else if (p == other->fTop->fPoint || c.sweep_lt(p, other->fTop->fPoint)) {
1092 split_edge(edge, other->fTop, activeEdges, c, alloc);
1093 v = other->fTop;
Stephen Whitee30cf802017-02-27 11:37:55 -05001094 } else if (p == other->fBottom->fPoint || c.sweep_lt(other->fBottom->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001095 split_edge(edge, other->fBottom, activeEdges, c, alloc);
1096 v = other->fBottom;
1097 } else {
1098 Vertex* nextV = edge->fTop;
1099 while (c.sweep_lt(p, nextV->fPoint)) {
1100 nextV = nextV->fPrev;
1101 }
1102 while (c.sweep_lt(nextV->fPoint, p)) {
1103 nextV = nextV->fNext;
1104 }
1105 Vertex* prevV = nextV->fPrev;
1106 if (coincident(prevV->fPoint, p)) {
1107 v = prevV;
1108 } else if (coincident(nextV->fPoint, p)) {
1109 v = nextV;
1110 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001111 v = alloc.make<Vertex>(p, alpha);
ethannicholase9709e82016-01-07 13:34:16 -08001112 LOG("inserting between %g (%g, %g) and %g (%g, %g)\n",
1113 prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY,
1114 nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY);
1115#if LOGGING_ENABLED
1116 v->fID = (nextV->fID + prevV->fID) * 0.5f;
1117#endif
1118 v->fPrev = prevV;
1119 v->fNext = nextV;
1120 prevV->fNext = v;
1121 nextV->fPrev = v;
1122 }
1123 split_edge(edge, v, activeEdges, c, alloc);
1124 split_edge(other, v, activeEdges, c, alloc);
1125 }
Stephen White92eba8a2017-02-06 09:50:27 -05001126 v->fAlpha = SkTMax(v->fAlpha, alpha);
ethannicholase9709e82016-01-07 13:34:16 -08001127 return v;
1128 }
1129 return nullptr;
1130}
1131
Stephen White3a9aab92017-03-07 14:07:18 -05001132void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) {
1133 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1134 SkASSERT(contour->fHead);
1135 Vertex* prev = contour->fTail;
Stephen White5926f2d2017-02-13 13:55:42 -05001136 if (approximate) {
Stephen White3a9aab92017-03-07 14:07:18 -05001137 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -05001138 }
Stephen White3a9aab92017-03-07 14:07:18 -05001139 for (Vertex* v = contour->fHead; v;) {
senorblancof57372d2016-08-31 10:36:19 -07001140 if (approximate) {
1141 round(&v->fPoint);
1142 }
Stephen White3a9aab92017-03-07 14:07:18 -05001143 Vertex* next = v->fNext;
1144 if (coincident(prev->fPoint, v->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -08001145 LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001146 contour->remove(v);
ethannicholase9709e82016-01-07 13:34:16 -08001147 }
Stephen White3a9aab92017-03-07 14:07:18 -05001148 prev = v;
1149 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001150 }
1151 }
1152}
1153
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001154void merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001155 if (!mesh->fHead) {
1156 return;
1157 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001158 for (Vertex* v = mesh->fHead->fNext; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001159 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1160 v->fPoint = v->fPrev->fPoint;
1161 }
1162 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001163 merge_vertices(v->fPrev, v, mesh, c, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001164 }
1165 }
1166}
1167
1168// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1169
Stephen White3a9aab92017-03-07 14:07:18 -05001170void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001171 SkArenaAlloc& alloc) {
Stephen White3a9aab92017-03-07 14:07:18 -05001172 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1173 Vertex* prev = contour->fTail;
1174 for (Vertex* v = contour->fHead; v;) {
1175 Vertex* next = v->fNext;
1176 connect(prev, v, Edge::Type::kInner, c, alloc);
1177 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001178 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001179 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001180 }
1181 }
ethannicholase9709e82016-01-07 13:34:16 -08001182}
1183
Stephen Whitebda29c02017-03-13 15:10:13 -04001184void connect_partners(VertexList* outerVertices, Comparator& c, SkArenaAlloc& alloc) {
1185 for (Vertex* outer = outerVertices->fHead; outer; outer = outer->fNext) {
1186 if (Vertex* inner = outer->fPartner) {
1187 // Connector edges get zero winding, since they're only structural (i.e., to ensure
1188 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding number.
1189 connect(outer, inner, Edge::Type::kConnector, c, alloc, 0);
1190 inner->fPartner = outer->fPartner = nullptr;
1191 }
1192 }
1193}
1194
1195template <CompareFunc sweep_lt>
1196void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
1197 Vertex* a = front->fHead;
1198 Vertex* b = back->fHead;
1199 while (a && b) {
1200 if (sweep_lt(a->fPoint, b->fPoint)) {
1201 front->remove(a);
1202 result->append(a);
1203 a = front->fHead;
1204 } else {
1205 back->remove(b);
1206 result->append(b);
1207 b = back->fHead;
1208 }
1209 }
1210 result->append(*front);
1211 result->append(*back);
1212}
1213
1214void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) {
1215 if (c.fDirection == Comparator::Direction::kHorizontal) {
1216 sorted_merge<sweep_lt_horiz>(front, back, result);
1217 } else {
1218 sorted_merge<sweep_lt_vert>(front, back, result);
1219 }
1220}
1221
ethannicholase9709e82016-01-07 13:34:16 -08001222// Stage 3: sort the vertices by increasing sweep direction.
1223
Stephen White16a40cb2017-02-23 11:10:01 -05001224template <CompareFunc sweep_lt>
1225void merge_sort(VertexList* vertices) {
1226 Vertex* slow = vertices->fHead;
1227 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001228 return;
1229 }
Stephen White16a40cb2017-02-23 11:10:01 -05001230 Vertex* fast = slow->fNext;
1231 if (!fast) {
1232 return;
1233 }
1234 do {
1235 fast = fast->fNext;
1236 if (fast) {
1237 fast = fast->fNext;
1238 slow = slow->fNext;
1239 }
1240 } while (fast);
1241 VertexList front(vertices->fHead, slow);
1242 VertexList back(slow->fNext, vertices->fTail);
1243 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001244
Stephen White16a40cb2017-02-23 11:10:01 -05001245 merge_sort<sweep_lt>(&front);
1246 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001247
Stephen White16a40cb2017-02-23 11:10:01 -05001248 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001249 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001250}
1251
1252// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1253
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001254void simplify(const VertexList& vertices, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001255 LOG("simplifying complex polygons\n");
1256 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001257 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001258 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1259 continue;
1260 }
1261#if LOGGING_ENABLED
senorblancof57372d2016-08-31 10:36:19 -07001262 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001263#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001264 Edge* leftEnclosingEdge;
1265 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001266 bool restartChecks;
1267 do {
1268 restartChecks = false;
1269 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White64dbb892017-05-03 16:00:38 -04001270 if (rightEnclosingEdge && !rightEnclosingEdge->isRightOf(v)) {
1271 split_edge(rightEnclosingEdge, v, &activeEdges, c, alloc);
1272 restartChecks = true;
1273 continue;
1274 }
ethannicholase9709e82016-01-07 13:34:16 -08001275 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001276 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
ethannicholase9709e82016-01-07 13:34:16 -08001277 if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, c, alloc)) {
1278 restartChecks = true;
1279 break;
1280 }
1281 if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, c, alloc)) {
1282 restartChecks = true;
1283 break;
1284 }
1285 }
1286 } else {
1287 if (Vertex* pv = check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
1288 &activeEdges, c, alloc)) {
1289 if (c.sweep_lt(pv->fPoint, v->fPoint)) {
1290 v = pv;
1291 }
1292 restartChecks = true;
1293 }
1294
1295 }
1296 } while (restartChecks);
senorblancof57372d2016-08-31 10:36:19 -07001297 if (v->fAlpha == 0) {
Stephen White48ded382017-02-03 10:15:16 -05001298 if ((leftEnclosingEdge && leftEnclosingEdge->fWinding < 0) &&
1299 (rightEnclosingEdge && rightEnclosingEdge->fWinding > 0)) {
senorblancof57372d2016-08-31 10:36:19 -07001300 v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge);
1301 }
1302 }
ethannicholase9709e82016-01-07 13:34:16 -08001303 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1304 remove_edge(e, &activeEdges);
1305 }
1306 Edge* leftEdge = leftEnclosingEdge;
1307 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1308 insert_edge(e, leftEdge, &activeEdges);
1309 leftEdge = e;
1310 }
1311 v->fProcessed = true;
1312 }
1313}
1314
Stephen Whitebda29c02017-03-13 15:10:13 -04001315// This is a stripped-down version of simplify() (the Bentley-Ottmann algorithm) that
1316// early-returns true on the first found intersection, false if none.
1317bool is_complex(const VertexList& vertices) {
1318 LOG("testing polygon complexity\n");
1319 EdgeList activeEdges;
1320 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
1321 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1322 continue;
1323 }
1324 Edge* leftEnclosingEdge;
1325 Edge* rightEnclosingEdge;
1326 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1327 SkPoint dummy;
1328 if (v->fFirstEdgeBelow) {
1329 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
1330 if (edge && leftEnclosingEdge && edge->intersect(*leftEnclosingEdge, &dummy)) {
1331 activeEdges.removeAll();
1332 return true;
1333 }
1334 if (edge && rightEnclosingEdge && edge->intersect(*rightEnclosingEdge, &dummy)) {
1335 activeEdges.removeAll();
1336 return true;
1337 }
1338 }
1339 } else if (leftEnclosingEdge && rightEnclosingEdge &&
1340 leftEnclosingEdge->intersect(*rightEnclosingEdge, &dummy)) {
1341 activeEdges.removeAll();
1342 return true;
1343 }
1344 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1345 remove_edge(e, &activeEdges);
1346 }
1347 Edge* leftEdge = leftEnclosingEdge;
1348 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1349 insert_edge(e, leftEdge, &activeEdges);
1350 leftEdge = e;
1351 }
1352 }
1353 activeEdges.removeAll();
1354 return false;
1355}
1356
ethannicholase9709e82016-01-07 13:34:16 -08001357// Stage 5: Tessellate the simplified mesh into monotone polygons.
1358
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001359Poly* tessellate(const VertexList& vertices, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001360 LOG("tessellating simple polygons\n");
1361 EdgeList activeEdges;
1362 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001363 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001364 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1365 continue;
1366 }
1367#if LOGGING_ENABLED
senorblancof57372d2016-08-31 10:36:19 -07001368 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001369#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001370 Edge* leftEnclosingEdge;
1371 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001372 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001373 Poly* leftPoly;
1374 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001375 if (v->fFirstEdgeAbove) {
1376 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1377 rightPoly = v->fLastEdgeAbove->fRightPoly;
1378 } else {
1379 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1380 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1381 }
1382#if LOGGING_ENABLED
1383 LOG("edges above:\n");
1384 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1385 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1386 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1387 }
1388 LOG("edges below:\n");
1389 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1390 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1391 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1392 }
1393#endif
1394 if (v->fFirstEdgeAbove) {
1395 if (leftPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001396 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001397 }
1398 if (rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001399 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001400 }
1401 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001402 Edge* rightEdge = e->fNextEdgeAbove;
Stephen White8a0bfc52017-02-21 15:24:13 -05001403 remove_edge(e, &activeEdges);
1404 if (e->fRightPoly) {
1405 e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001406 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001407 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001408 rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001409 }
1410 }
1411 remove_edge(v->fLastEdgeAbove, &activeEdges);
1412 if (!v->fFirstEdgeBelow) {
1413 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1414 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1415 rightPoly->fPartner = leftPoly;
1416 leftPoly->fPartner = rightPoly;
1417 }
1418 }
1419 }
1420 if (v->fFirstEdgeBelow) {
1421 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001422 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001423 if (leftPoly == rightPoly) {
1424 if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) {
1425 leftPoly = new_poly(&polys, leftPoly->lastVertex(),
1426 leftPoly->fWinding, alloc);
1427 leftEnclosingEdge->fRightPoly = leftPoly;
1428 } else {
1429 rightPoly = new_poly(&polys, rightPoly->lastVertex(),
1430 rightPoly->fWinding, alloc);
1431 rightEnclosingEdge->fLeftPoly = rightPoly;
1432 }
ethannicholase9709e82016-01-07 13:34:16 -08001433 }
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001434 Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -07001435 leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc);
1436 rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001437 }
1438 }
1439 Edge* leftEdge = v->fFirstEdgeBelow;
1440 leftEdge->fLeftPoly = leftPoly;
1441 insert_edge(leftEdge, leftEnclosingEdge, &activeEdges);
1442 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1443 rightEdge = rightEdge->fNextEdgeBelow) {
1444 insert_edge(rightEdge, leftEdge, &activeEdges);
1445 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1446 winding += leftEdge->fWinding;
1447 if (winding != 0) {
1448 Poly* poly = new_poly(&polys, v, winding, alloc);
1449 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1450 }
1451 leftEdge = rightEdge;
1452 }
1453 v->fLastEdgeBelow->fRightPoly = rightPoly;
1454 }
1455#if LOGGING_ENABLED
1456 LOG("\nactive edges:\n");
1457 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
1458 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1459 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1460 }
1461#endif
1462 }
1463 return polys;
1464}
1465
Stephen Whitebf6137e2017-01-04 15:43:26 -05001466void remove_non_boundary_edges(const VertexList& mesh, SkPath::FillType fillType,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001467 SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001468 LOG("removing non-boundary edges\n");
1469 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001470 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
Stephen White49789062017-02-21 10:35:49 -05001471 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1472 continue;
1473 }
1474 Edge* leftEnclosingEdge;
1475 Edge* rightEnclosingEdge;
1476 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1477 bool prevFilled = leftEnclosingEdge &&
1478 apply_fill_type(fillType, leftEnclosingEdge->fWinding);
1479 for (Edge* e = v->fFirstEdgeAbove; e;) {
1480 Edge* next = e->fNextEdgeAbove;
1481 remove_edge(e, &activeEdges);
1482 bool filled = apply_fill_type(fillType, e->fWinding);
1483 if (filled == prevFilled) {
Stephen Whitee7a364d2017-01-11 16:19:26 -05001484 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001485 }
Stephen White49789062017-02-21 10:35:49 -05001486 prevFilled = filled;
senorblancof57372d2016-08-31 10:36:19 -07001487 e = next;
1488 }
Stephen White49789062017-02-21 10:35:49 -05001489 Edge* prev = leftEnclosingEdge;
1490 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1491 if (prev) {
1492 e->fWinding += prev->fWinding;
1493 }
1494 insert_edge(e, prev, &activeEdges);
1495 prev = e;
1496 }
senorblancof57372d2016-08-31 10:36:19 -07001497 }
senorblancof57372d2016-08-31 10:36:19 -07001498}
1499
Stephen White66412122017-03-01 11:48:27 -05001500// Note: this is the normal to the edge, but not necessarily unit length.
senorblancof57372d2016-08-31 10:36:19 -07001501void get_edge_normal(const Edge* e, SkVector* normal) {
Stephen White66412122017-03-01 11:48:27 -05001502 normal->set(SkDoubleToScalar(e->fLine.fA) * e->fWinding,
1503 SkDoubleToScalar(e->fLine.fB) * e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001504}
1505
1506// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
1507// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
1508// invert on stroking.
1509
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001510void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) {
senorblancof57372d2016-08-31 10:36:19 -07001511 Edge* prevEdge = boundary->fTail;
1512 SkVector prevNormal;
1513 get_edge_normal(prevEdge, &prevNormal);
1514 for (Edge* e = boundary->fHead; e != nullptr;) {
1515 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
1516 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
1517 double dist = e->dist(prev->fPoint);
1518 SkVector normal;
1519 get_edge_normal(e, &normal);
Stephen White66412122017-03-01 11:48:27 -05001520 double denom = 0.0625f * e->fLine.magSq();
senorblancof57372d2016-08-31 10:36:19 -07001521 if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001522 Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001523 insert_edge(join, e, boundary);
1524 remove_edge(prevEdge, boundary);
1525 remove_edge(e, boundary);
1526 if (join->fLeft && join->fRight) {
1527 prevEdge = join->fLeft;
1528 e = join;
1529 } else {
1530 prevEdge = boundary->fTail;
1531 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
1532 }
1533 get_edge_normal(prevEdge, &prevNormal);
1534 } else {
1535 prevEdge = e;
1536 prevNormal = normal;
1537 e = e->fRight;
1538 }
1539 }
1540}
1541
Ben Wagnerdab48112017-02-16 22:28:02 +00001542void fix_inversions(Vertex* prev, Vertex* next, Edge* prevBisector, Edge* nextBisector,
Stephen White92eba8a2017-02-06 09:50:27 -05001543 Edge* prevEdge, Comparator& c) {
1544 if (!prev || !next) {
1545 return;
1546 }
1547 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
1548 SkPoint p;
1549 uint8_t alpha;
Ben Wagnerdab48112017-02-16 22:28:02 +00001550 if (winding != prevEdge->fWinding && prevBisector->intersect(*nextBisector, &p, &alpha)) {
Stephen White92eba8a2017-02-06 09:50:27 -05001551 prev->fPoint = next->fPoint = p;
1552 prev->fAlpha = next->fAlpha = alpha;
1553 }
1554}
1555
senorblancof57372d2016-08-31 10:36:19 -07001556// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
1557// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
1558// new antialiased mesh from those vertices.
1559
Stephen Whitebda29c02017-03-13 15:10:13 -04001560void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
1561 Comparator& c, SkArenaAlloc& alloc) {
Stephen White8a0bfc52017-02-21 15:24:13 -05001562 // A boundary with fewer than 3 edges is degenerate.
1563 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
1564 return;
1565 }
senorblancof57372d2016-08-31 10:36:19 -07001566 Edge* prevEdge = boundary->fTail;
1567 float radius = 0.5f;
senorblanco49df8d12016-10-07 08:36:56 -07001568 double offset = radius * sqrt(prevEdge->fLine.magSq()) * prevEdge->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001569 Line prevInner(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001570 prevInner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001571 Line prevOuter(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001572 prevOuter.fC += offset;
1573 VertexList innerVertices;
1574 VertexList outerVertices;
Ben Wagnerdab48112017-02-16 22:28:02 +00001575 Edge* prevBisector = nullptr;
senorblancof57372d2016-08-31 10:36:19 -07001576 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
senorblanco49df8d12016-10-07 08:36:56 -07001577 double offset = radius * sqrt(e->fLine.magSq()) * e->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001578 Line inner(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001579 inner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001580 Line outer(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001581 outer.fC += offset;
1582 SkPoint innerPoint, outerPoint;
senorblanco49df8d12016-10-07 08:36:56 -07001583 if (prevInner.intersect(inner, &innerPoint) &&
1584 prevOuter.intersect(outer, &outerPoint)) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001585 Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255);
1586 Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0);
Ben Wagnerdab48112017-02-16 22:28:02 +00001587 Edge* bisector = new_edge(outerVertex, innerVertex, Edge::Type::kConnector, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001588 fix_inversions(innerVertices.fTail, innerVertex, prevBisector, bisector, prevEdge, c);
1589 fix_inversions(outerVertices.fTail, outerVertex, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001590 innerVertex->fPartner = outerVertex;
1591 outerVertex->fPartner = innerVertex;
Stephen White92eba8a2017-02-06 09:50:27 -05001592 innerVertices.append(innerVertex);
1593 outerVertices.append(outerVertex);
1594 prevBisector = bisector;
senorblancof57372d2016-08-31 10:36:19 -07001595 }
1596 prevInner = inner;
1597 prevOuter = outer;
Stephen White86cc8412017-01-27 10:53:15 -05001598 prevEdge = e;
senorblancof57372d2016-08-31 10:36:19 -07001599 }
senorblancof57372d2016-08-31 10:36:19 -07001600
1601 Vertex* innerVertex = innerVertices.fHead;
1602 Vertex* outerVertex = outerVertices.fHead;
senorblancof57372d2016-08-31 10:36:19 -07001603 if (!innerVertex || !outerVertex) {
1604 return;
1605 }
Ben Wagnerdab48112017-02-16 22:28:02 +00001606 Edge* bisector = new_edge(outerVertices.fHead, innerVertices.fHead, Edge::Type::kConnector, c,
1607 alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001608 fix_inversions(innerVertices.fTail, innerVertices.fHead, prevBisector, bisector, prevEdge, c);
1609 fix_inversions(outerVertices.fTail, outerVertices.fHead, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001610 Vertex* prevInnerVertex = innerVertices.fTail;
1611 Vertex* prevOuterVertex = outerVertices.fTail;
1612 while (innerVertex && outerVertex) {
Stephen White48ded382017-02-03 10:15:16 -05001613 // Connect vertices into a quad mesh. Outer edges get default (1) winding.
1614 // Inner edges get -2 winding. This ensures that the interior is always filled
1615 // (-1 winding number for normal cases, 3 for thin features where the interior inverts).
Stephen Whitebda29c02017-03-13 15:10:13 -04001616 connect(prevOuterVertex, outerVertex, Edge::Type::kOuter, c, alloc);
1617 connect(prevInnerVertex, innerVertex, Edge::Type::kInner, c, alloc, -2);
1618 prevInnerVertex = innerVertex;
1619 prevOuterVertex = outerVertex;
1620 innerVertex = innerVertex->fNext;
1621 outerVertex = outerVertex->fNext;
1622 }
1623 innerMesh->append(innerVertices);
1624 outerMesh->append(outerVertices);
senorblancof57372d2016-08-31 10:36:19 -07001625}
1626
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001627void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001628 bool down = apply_fill_type(fillType, e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001629 while (e) {
1630 e->fWinding = down ? 1 : -1;
1631 Edge* next;
1632 boundary->append(e);
1633 if (down) {
1634 // Find outgoing edge, in clockwise order.
1635 if ((next = e->fNextEdgeAbove)) {
1636 down = false;
1637 } else if ((next = e->fBottom->fLastEdgeBelow)) {
1638 down = true;
1639 } else if ((next = e->fPrevEdgeAbove)) {
1640 down = false;
1641 }
1642 } else {
1643 // Find outgoing edge, in counter-clockwise order.
1644 if ((next = e->fPrevEdgeBelow)) {
1645 down = true;
1646 } else if ((next = e->fTop->fFirstEdgeAbove)) {
1647 down = false;
1648 } else if ((next = e->fNextEdgeBelow)) {
1649 down = true;
1650 }
1651 }
Stephen Whitee7a364d2017-01-11 16:19:26 -05001652 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001653 e = next;
1654 }
1655}
1656
Stephen White5ad721e2017-02-23 16:50:47 -05001657// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
senorblancof57372d2016-08-31 10:36:19 -07001658
Stephen Whitebda29c02017-03-13 15:10:13 -04001659void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices,
1660 VertexList* outerVertices, SkPath::FillType fillType,
Stephen White5ad721e2017-02-23 16:50:47 -05001661 Comparator& c, SkArenaAlloc& alloc) {
1662 remove_non_boundary_edges(inMesh, fillType, alloc);
1663 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001664 while (v->fFirstEdgeBelow) {
Stephen White5ad721e2017-02-23 16:50:47 -05001665 EdgeList boundary;
1666 extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc);
1667 simplify_boundary(&boundary, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001668 stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001669 }
1670 }
senorblancof57372d2016-08-31 10:36:19 -07001671}
1672
Stephen Whitebda29c02017-03-13 15:10:13 -04001673// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001674
Stephen White3a9aab92017-03-07 14:07:18 -05001675void contours_to_mesh(VertexList* contours, int contourCnt, bool antialias,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001676 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001677#if LOGGING_ENABLED
1678 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001679 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001680 SkASSERT(v);
1681 LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001682 for (v = v->fNext; v; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001683 LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1684 }
1685 }
1686#endif
senorblancof57372d2016-08-31 10:36:19 -07001687 sanitize_contours(contours, contourCnt, antialias);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001688 build_edges(contours, contourCnt, mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001689}
1690
Stephen Whitebda29c02017-03-13 15:10:13 -04001691void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001692 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001693 return;
ethannicholase9709e82016-01-07 13:34:16 -08001694 }
1695
1696 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001697 if (c.fDirection == Comparator::Direction::kHorizontal) {
1698 merge_sort<sweep_lt_horiz>(vertices);
1699 } else {
1700 merge_sort<sweep_lt_vert>(vertices);
1701 }
ethannicholase9709e82016-01-07 13:34:16 -08001702#if LOGGING_ENABLED
Stephen White2e2cb9b2017-01-09 13:11:18 -05001703 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001704 static float gID = 0.0f;
1705 v->fID = gID++;
1706 }
1707#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001708}
1709
Stephen White3a9aab92017-03-07 14:07:18 -05001710Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPath::FillType fillType,
Stephen Whitebda29c02017-03-13 15:10:13 -04001711 const SkRect& pathBounds, bool antialias, VertexList* outerMesh,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001712 SkArenaAlloc& alloc) {
Stephen White16a40cb2017-02-23 11:10:01 -05001713 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1714 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001715 VertexList mesh;
1716 contours_to_mesh(contours, contourCnt, antialias, &mesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001717 sort_mesh(&mesh, c, alloc);
1718 merge_coincident_vertices(&mesh, c, alloc);
1719 simplify(mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001720 if (antialias) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001721 VertexList innerMesh;
1722 extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc);
1723 sort_mesh(&innerMesh, c, alloc);
1724 sort_mesh(outerMesh, c, alloc);
1725 if (is_complex(innerMesh) || is_complex(*outerMesh)) {
1726 LOG("found complex mesh; taking slow path\n");
1727 VertexList aaMesh;
1728 connect_partners(outerMesh, c, alloc);
1729 sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
1730 merge_coincident_vertices(&aaMesh, c, alloc);
1731 simplify(aaMesh, c, alloc);
1732 outerMesh->fHead = outerMesh->fTail = nullptr;
1733 return tessellate(aaMesh, alloc);
1734 } else {
1735 LOG("no complex polygons; taking fast path\n");
1736 merge_coincident_vertices(&innerMesh, c, alloc);
1737 return tessellate(innerMesh, alloc);
1738 }
Stephen White49789062017-02-21 10:35:49 -05001739 } else {
1740 return tessellate(mesh, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001741 }
senorblancof57372d2016-08-31 10:36:19 -07001742}
1743
1744// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1745void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* aaParams,
1746 void* data) {
1747 for (Poly* poly = polys; poly; poly = poly->fNext) {
1748 if (apply_fill_type(fillType, poly)) {
1749 data = poly->emit(aaParams, data);
1750 }
1751 }
1752 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001753}
1754
halcanary9d524f22016-03-29 09:03:52 -07001755Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen Whitebda29c02017-03-13 15:10:13 -04001756 int contourCnt, SkArenaAlloc& alloc, bool antialias, bool* isLinear,
1757 VertexList* outerMesh) {
ethannicholase9709e82016-01-07 13:34:16 -08001758 SkPath::FillType fillType = path.getFillType();
1759 if (SkPath::IsInverseFillType(fillType)) {
1760 contourCnt++;
1761 }
Stephen White3a9aab92017-03-07 14:07:18 -05001762 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08001763
1764 path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear);
senorblancof57372d2016-08-31 10:36:19 -07001765 return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(),
Stephen Whitebda29c02017-03-13 15:10:13 -04001766 antialias, outerMesh, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001767}
1768
Stephen White11f65e02017-02-16 19:00:39 -05001769int get_contour_count(const SkPath& path, SkScalar tolerance) {
1770 int contourCnt;
1771 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001772 if (maxPts <= 0) {
Stephen White11f65e02017-02-16 19:00:39 -05001773 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001774 }
1775 if (maxPts > ((int)SK_MaxU16 + 1)) {
1776 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
Stephen White11f65e02017-02-16 19:00:39 -05001777 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001778 }
Stephen White11f65e02017-02-16 19:00:39 -05001779 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001780}
1781
1782int count_points(Poly* polys, SkPath::FillType fillType) {
1783 int count = 0;
1784 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001785 if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
ethannicholase9709e82016-01-07 13:34:16 -08001786 count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3);
1787 }
1788 }
1789 return count;
1790}
1791
Stephen Whitebda29c02017-03-13 15:10:13 -04001792int count_outer_mesh_points(const VertexList& outerMesh) {
1793 int count = 0;
1794 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1795 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1796 count += TESSELLATOR_WIREFRAME ? 12 : 6;
1797 }
1798 }
1799 return count;
1800}
1801
1802void* outer_mesh_to_triangles(const VertexList& outerMesh, const AAParams* aaParams, void* data) {
1803 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1804 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1805 Vertex* v0 = e->fTop;
1806 Vertex* v1 = e->fBottom;
1807 Vertex* v2 = e->fBottom->fPartner;
1808 Vertex* v3 = e->fTop->fPartner;
1809 data = emit_triangle(v0, v1, v2, aaParams, data);
1810 data = emit_triangle(v0, v2, v3, aaParams, data);
1811 }
1812 }
1813 return data;
1814}
1815
ethannicholase9709e82016-01-07 13:34:16 -08001816} // namespace
1817
1818namespace GrTessellator {
1819
1820// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1821
halcanary9d524f22016-03-29 09:03:52 -07001822int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
senorblancof57372d2016-08-31 10:36:19 -07001823 VertexAllocator* vertexAllocator, bool antialias, const GrColor& color,
1824 bool canTweakAlphaForCoverage, bool* isLinear) {
Stephen White11f65e02017-02-16 19:00:39 -05001825 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001826 if (contourCnt <= 0) {
1827 *isLinear = true;
1828 return 0;
1829 }
Stephen White11f65e02017-02-16 19:00:39 -05001830 SkArenaAlloc alloc(kArenaChunkSize);
Stephen Whitebda29c02017-03-13 15:10:13 -04001831 VertexList outerMesh;
senorblancof57372d2016-08-31 10:36:19 -07001832 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias,
Stephen Whitebda29c02017-03-13 15:10:13 -04001833 isLinear, &outerMesh);
senorblanco7ab96e92016-10-12 06:47:44 -07001834 SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType();
ethannicholase9709e82016-01-07 13:34:16 -08001835 int count = count_points(polys, fillType);
Stephen Whitebda29c02017-03-13 15:10:13 -04001836 if (antialias) {
1837 count += count_outer_mesh_points(outerMesh);
1838 }
Stephen Whiteff60b172017-05-05 15:54:52 -04001839 if (0 == count) {
1840 return 0;
1841 }
ethannicholase9709e82016-01-07 13:34:16 -08001842
senorblancof57372d2016-08-31 10:36:19 -07001843 void* verts = vertexAllocator->lock(count);
senorblanco6599eff2016-03-10 08:38:45 -08001844 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001845 SkDebugf("Could not allocate vertices\n");
1846 return 0;
1847 }
senorblancof57372d2016-08-31 10:36:19 -07001848
1849 LOG("emitting %d verts\n", count);
1850 AAParams aaParams;
1851 aaParams.fTweakAlpha = canTweakAlphaForCoverage;
1852 aaParams.fColor = color;
1853
1854 void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts);
Stephen Whitebda29c02017-03-13 15:10:13 -04001855 end = outer_mesh_to_triangles(outerMesh, &aaParams, end);
senorblancof57372d2016-08-31 10:36:19 -07001856 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
1857 / vertexAllocator->stride());
ethannicholase9709e82016-01-07 13:34:16 -08001858 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001859 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001860 return actualCount;
1861}
1862
halcanary9d524f22016-03-29 09:03:52 -07001863int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
ethannicholase9709e82016-01-07 13:34:16 -08001864 GrTessellator::WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05001865 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001866 if (contourCnt <= 0) {
1867 return 0;
1868 }
Stephen White11f65e02017-02-16 19:00:39 -05001869 SkArenaAlloc alloc(kArenaChunkSize);
ethannicholase9709e82016-01-07 13:34:16 -08001870 bool isLinear;
Stephen Whitebda29c02017-03-13 15:10:13 -04001871 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear,
1872 nullptr);
ethannicholase9709e82016-01-07 13:34:16 -08001873 SkPath::FillType fillType = path.getFillType();
1874 int count = count_points(polys, fillType);
1875 if (0 == count) {
1876 *verts = nullptr;
1877 return 0;
1878 }
1879
1880 *verts = new GrTessellator::WindingVertex[count];
1881 GrTessellator::WindingVertex* vertsEnd = *verts;
1882 SkPoint* points = new SkPoint[count];
1883 SkPoint* pointsEnd = points;
1884 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001885 if (apply_fill_type(fillType, poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001886 SkPoint* start = pointsEnd;
senorblancof57372d2016-08-31 10:36:19 -07001887 pointsEnd = static_cast<SkPoint*>(poly->emit(nullptr, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001888 while (start != pointsEnd) {
1889 vertsEnd->fPos = *start;
1890 vertsEnd->fWinding = poly->fWinding;
1891 ++start;
1892 ++vertsEnd;
1893 }
1894 }
1895 }
1896 int actualCount = static_cast<int>(vertsEnd - *verts);
1897 SkASSERT(actualCount <= count);
1898 SkASSERT(pointsEnd - points == actualCount);
1899 delete[] points;
1900 return actualCount;
1901}
1902
1903} // namespace