blob: a77f23d708e13d457c9c2c9531ea7bb8ea297ae8 [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
Stephen White3b5a3fa2017-06-06 14:51:19 -040053 * points. This occurs in two ways:
ethannicholase9709e82016-01-07 13:34:16 -080054 *
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
Stephen White019f6c02017-06-09 10:06:26 -040059 * active edge list. This is handled by detecting potential violations and rewinding
Stephen White3b5a3fa2017-06-06 14:51:19 -040060 * the active edge list to the vertex before they occur (rewind() during merging,
61 * rewind_if_necessary() during splitting).
ethannicholase9709e82016-01-07 13:34:16 -080062 *
63 * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
64 * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
65 * currently uses a linked list for the active edge list, rather than a 2-3 tree as the
66 * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
67 * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
68 * insertions and removals was greater than the cost of infrequent O(N) lookups with the
69 * linked list implementation. With the latter, all removals are O(1), and most insertions
70 * are O(1), since we know the adjacent edge in the active edge list based on the topology.
71 * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
72 * frequent. There may be other data structures worth investigating, however.
73 *
74 * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the
75 * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y
76 * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall,
77 * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so
78 * that the "left" and "right" orientation in the code remains correct (edges to the left are
79 * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90
80 * degrees counterclockwise, rather that transposing.
81 */
82
83#define LOGGING_ENABLED 0
84
85#if LOGGING_ENABLED
86#define LOG printf
87#else
88#define LOG(...)
89#endif
90
ethannicholase9709e82016-01-07 13:34:16 -080091namespace {
92
Stephen White11f65e02017-02-16 19:00:39 -050093const int kArenaChunkSize = 16 * 1024;
94
ethannicholase9709e82016-01-07 13:34:16 -080095struct Vertex;
96struct Edge;
97struct Poly;
98
99template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800100void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800101 t->*Prev = prev;
102 t->*Next = next;
103 if (prev) {
104 prev->*Next = t;
105 } else if (head) {
106 *head = t;
107 }
108 if (next) {
109 next->*Prev = t;
110 } else if (tail) {
111 *tail = t;
112 }
113}
114
115template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800116void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800117 if (t->*Prev) {
118 t->*Prev->*Next = t->*Next;
119 } else if (head) {
120 *head = t->*Next;
121 }
122 if (t->*Next) {
123 t->*Next->*Prev = t->*Prev;
124 } else if (tail) {
125 *tail = t->*Prev;
126 }
127 t->*Prev = t->*Next = nullptr;
128}
129
130/**
131 * Vertices are used in three ways: first, the path contours are converted into a
132 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
133 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
134 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
135 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
136 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
137 * an individual Vertex from the path mesh may belong to multiple
138 * MonotonePolys, so the original Vertices cannot be re-used.
139 */
140
141struct Vertex {
senorblancof57372d2016-08-31 10:36:19 -0700142 Vertex(const SkPoint& point, uint8_t alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800143 : fPoint(point), fPrev(nullptr), fNext(nullptr)
144 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
145 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
Stephen White3b5a3fa2017-06-06 14:51:19 -0400146 , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
Stephen Whitebda29c02017-03-13 15:10:13 -0400147 , fPartner(nullptr)
senorblancof57372d2016-08-31 10:36:19 -0700148 , fAlpha(alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800149#if LOGGING_ENABLED
150 , fID (-1.0f)
151#endif
152 {}
Stephen White3b5a3fa2017-06-06 14:51:19 -0400153 SkPoint fPoint; // Vertex position
154 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
155 Vertex* fNext; // "
156 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
157 Edge* fLastEdgeAbove; // "
158 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
159 Edge* fLastEdgeBelow; // "
160 Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
161 Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
162 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
senorblancof57372d2016-08-31 10:36:19 -0700163 uint8_t fAlpha;
ethannicholase9709e82016-01-07 13:34:16 -0800164#if LOGGING_ENABLED
Stephen White3b5a3fa2017-06-06 14:51:19 -0400165 float fID; // Identifier used for logging.
ethannicholase9709e82016-01-07 13:34:16 -0800166#endif
167};
168
169/***************************************************************************************/
170
senorblancof57372d2016-08-31 10:36:19 -0700171struct AAParams {
172 bool fTweakAlpha;
173 GrColor fColor;
174};
175
ethannicholase9709e82016-01-07 13:34:16 -0800176typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
177
ethannicholase9709e82016-01-07 13:34:16 -0800178bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500179 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -0800180}
181
182bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500183 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -0800184}
185
Stephen White16a40cb2017-02-23 11:10:01 -0500186struct Comparator {
187 enum class Direction { kVertical, kHorizontal };
188 Comparator(Direction direction) : fDirection(direction) {}
189 bool sweep_lt(const SkPoint& a, const SkPoint& b) const {
190 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
191 }
Stephen White16a40cb2017-02-23 11:10:01 -0500192 Direction fDirection;
193};
194
senorblancof57372d2016-08-31 10:36:19 -0700195inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) {
196 if (!aaParams) {
197 SkPoint* d = static_cast<SkPoint*>(data);
198 *d++ = v->fPoint;
199 return d;
200 }
201 if (aaParams->fTweakAlpha) {
202 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorAttr*>(data);
203 d->fPosition = v->fPoint;
lsalzman8c8fcef2016-10-11 12:20:17 -0700204 d->fColor = SkAlphaMulQ(aaParams->fColor, SkAlpha255To256(v->fAlpha));
senorblancof57372d2016-08-31 10:36:19 -0700205 d++;
206 return d;
207 }
208 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorCoverageAttr*>(data);
209 d->fPosition = v->fPoint;
210 d->fColor = aaParams->fColor;
211 d->fCoverage = GrNormalizeByteToFloat(v->fAlpha);
212 d++;
213 return d;
ethannicholase9709e82016-01-07 13:34:16 -0800214}
215
senorblancof57372d2016-08-31 10:36:19 -0700216void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams, void* data) {
Stephen White92eba8a2017-02-06 09:50:27 -0500217 LOG("emit_triangle (%g, %g) %d\n", v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
218 LOG(" (%g, %g) %d\n", v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
219 LOG(" (%g, %g) %d\n", v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -0700220#if TESSELLATOR_WIREFRAME
221 data = emit_vertex(v0, aaParams, data);
222 data = emit_vertex(v1, aaParams, data);
223 data = emit_vertex(v1, aaParams, data);
224 data = emit_vertex(v2, aaParams, data);
225 data = emit_vertex(v2, aaParams, data);
226 data = emit_vertex(v0, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800227#else
senorblancof57372d2016-08-31 10:36:19 -0700228 data = emit_vertex(v0, aaParams, data);
229 data = emit_vertex(v1, aaParams, data);
230 data = emit_vertex(v2, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800231#endif
232 return data;
233}
234
senorblancoe6eaa322016-03-08 09:06:44 -0800235struct VertexList {
236 VertexList() : fHead(nullptr), fTail(nullptr) {}
Stephen White16a40cb2017-02-23 11:10:01 -0500237 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {}
senorblancoe6eaa322016-03-08 09:06:44 -0800238 Vertex* fHead;
239 Vertex* fTail;
240 void insert(Vertex* v, Vertex* prev, Vertex* next) {
241 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
242 }
243 void append(Vertex* v) {
244 insert(v, fTail, nullptr);
245 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400246 void append(const VertexList& list) {
247 if (!list.fHead) {
248 return;
249 }
250 if (fTail) {
251 fTail->fNext = list.fHead;
252 list.fHead->fPrev = fTail;
253 } else {
254 fHead = list.fHead;
255 }
256 fTail = list.fTail;
257 }
senorblancoe6eaa322016-03-08 09:06:44 -0800258 void prepend(Vertex* v) {
259 insert(v, nullptr, fHead);
260 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500261 void remove(Vertex* v) {
262 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
263 }
senorblancof57372d2016-08-31 10:36:19 -0700264 void close() {
265 if (fHead && fTail) {
266 fTail->fNext = fHead;
267 fHead->fPrev = fTail;
268 }
269 }
senorblancoe6eaa322016-03-08 09:06:44 -0800270};
271
senorblancof57372d2016-08-31 10:36:19 -0700272// Round to nearest quarter-pixel. This is used for screenspace tessellation.
273
274inline void round(SkPoint* p) {
275 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
276 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
277}
278
senorblanco49df8d12016-10-07 08:36:56 -0700279// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
280struct Line {
281 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
282 Line(const SkPoint& p, const SkPoint& q)
283 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
284 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
285 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
286 static_cast<double>(p.fX) * q.fY) {}
287 double dist(const SkPoint& p) const {
288 return fA * p.fX + fB * p.fY + fC;
289 }
290 double magSq() const {
291 return fA * fA + fB * fB;
292 }
293
294 // Compute the intersection of two (infinite) Lines.
295 bool intersect(const Line& other, SkPoint* point) {
296 double denom = fA * other.fB - fB * other.fA;
297 if (denom == 0.0) {
298 return false;
299 }
300 double scale = 1.0f / denom;
301 point->fX = SkDoubleToScalar((fB * other.fC - other.fB * fC) * scale);
302 point->fY = SkDoubleToScalar((other.fA * fC - fA * other.fC) * scale);
Stephen Whiteb56dedf2017-03-02 10:35:56 -0500303 round(point);
senorblanco49df8d12016-10-07 08:36:56 -0700304 return true;
305 }
306 double fA, fB, fC;
307};
308
ethannicholase9709e82016-01-07 13:34:16 -0800309/**
310 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
311 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
312 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
Stephen Whitebda29c02017-03-13 15:10:13 -0400313 * point). For speed, that case is only tested by the callers that require it (e.g.,
Stephen White3b5a3fa2017-06-06 14:51:19 -0400314 * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
ethannicholase9709e82016-01-07 13:34:16 -0800315 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
316 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
317 * a lot faster in the "not found" case.
318 *
319 * The coefficients of the line equation stored in double precision to avoid catastrphic
320 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
321 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
322 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
323 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
324 * this file).
325 */
326
327struct Edge {
Stephen White2f4686f2017-01-03 16:20:01 -0500328 enum class Type { kInner, kOuter, kConnector };
329 Edge(Vertex* top, Vertex* bottom, int winding, Type type)
ethannicholase9709e82016-01-07 13:34:16 -0800330 : fWinding(winding)
331 , fTop(top)
332 , fBottom(bottom)
Stephen White2f4686f2017-01-03 16:20:01 -0500333 , fType(type)
ethannicholase9709e82016-01-07 13:34:16 -0800334 , fLeft(nullptr)
335 , fRight(nullptr)
336 , fPrevEdgeAbove(nullptr)
337 , fNextEdgeAbove(nullptr)
338 , fPrevEdgeBelow(nullptr)
339 , fNextEdgeBelow(nullptr)
340 , fLeftPoly(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700341 , fRightPoly(nullptr)
342 , fLeftPolyPrev(nullptr)
343 , fLeftPolyNext(nullptr)
344 , fRightPolyPrev(nullptr)
senorblanco70f52512016-08-17 14:56:22 -0700345 , fRightPolyNext(nullptr)
346 , fUsedInLeftPoly(false)
senorblanco49df8d12016-10-07 08:36:56 -0700347 , fUsedInRightPoly(false)
348 , fLine(top, bottom) {
ethannicholase9709e82016-01-07 13:34:16 -0800349 }
350 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
351 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
352 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
Stephen White2f4686f2017-01-03 16:20:01 -0500353 Type fType;
ethannicholase9709e82016-01-07 13:34:16 -0800354 Edge* fLeft; // The linked list of edges in the active edge list.
355 Edge* fRight; // "
356 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
357 Edge* fNextEdgeAbove; // "
358 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
359 Edge* fNextEdgeBelow; // "
360 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
361 Poly* fRightPoly; // The Poly to the right of this edge, if any.
senorblanco531237e2016-06-02 11:36:48 -0700362 Edge* fLeftPolyPrev;
363 Edge* fLeftPolyNext;
364 Edge* fRightPolyPrev;
365 Edge* fRightPolyNext;
senorblanco70f52512016-08-17 14:56:22 -0700366 bool fUsedInLeftPoly;
367 bool fUsedInRightPoly;
senorblanco49df8d12016-10-07 08:36:56 -0700368 Line fLine;
ethannicholase9709e82016-01-07 13:34:16 -0800369 double dist(const SkPoint& p) const {
senorblanco49df8d12016-10-07 08:36:56 -0700370 return fLine.dist(p);
ethannicholase9709e82016-01-07 13:34:16 -0800371 }
372 bool isRightOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700373 return fLine.dist(v->fPoint) < 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800374 }
375 bool isLeftOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700376 return fLine.dist(v->fPoint) > 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800377 }
378 void recompute() {
senorblanco49df8d12016-10-07 08:36:56 -0700379 fLine = Line(fTop, fBottom);
ethannicholase9709e82016-01-07 13:34:16 -0800380 }
Ben Wagnerdab48112017-02-16 22:28:02 +0000381 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) {
ethannicholase9709e82016-01-07 13:34:16 -0800382 LOG("intersecting %g -> %g with %g -> %g\n",
383 fTop->fID, fBottom->fID,
384 other.fTop->fID, other.fBottom->fID);
385 if (fTop == other.fTop || fBottom == other.fBottom) {
386 return false;
387 }
senorblanco49df8d12016-10-07 08:36:56 -0700388 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800389 if (denom == 0.0) {
390 return false;
391 }
Stephen White8a0bfc52017-02-21 15:24:13 -0500392 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
393 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
394 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
395 double tNumer = dy * fLine.fB + dx * fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800396 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
397 // This saves us doing the divide below unless absolutely necessary.
398 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
399 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
400 return false;
401 }
402 double s = sNumer / denom;
403 SkASSERT(s >= 0.0 && s <= 1.0);
senorblanco49df8d12016-10-07 08:36:56 -0700404 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
405 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
Stephen White56158ae2017-01-30 14:31:31 -0500406 if (alpha) {
Stephen White92eba8a2017-02-06 09:50:27 -0500407 if (fType == Type::kConnector) {
408 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
409 } else if (other.fType == Type::kConnector) {
410 double t = tNumer / denom;
411 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
Stephen White56158ae2017-01-30 14:31:31 -0500412 } else if (fType == Type::kOuter && other.fType == Type::kOuter) {
413 *alpha = 0;
414 } else {
Stephen White92eba8a2017-02-06 09:50:27 -0500415 *alpha = 255;
Stephen White56158ae2017-01-30 14:31:31 -0500416 }
417 }
ethannicholase9709e82016-01-07 13:34:16 -0800418 return true;
419 }
senorblancof57372d2016-08-31 10:36:19 -0700420};
421
422struct EdgeList {
Stephen White5ad721e2017-02-23 16:50:47 -0500423 EdgeList() : fHead(nullptr), fTail(nullptr) {}
senorblancof57372d2016-08-31 10:36:19 -0700424 Edge* fHead;
425 Edge* fTail;
senorblancof57372d2016-08-31 10:36:19 -0700426 void insert(Edge* edge, Edge* prev, Edge* next) {
427 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700428 }
429 void append(Edge* e) {
430 insert(e, fTail, nullptr);
431 }
432 void remove(Edge* edge) {
433 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700434 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400435 void removeAll() {
436 while (fHead) {
437 this->remove(fHead);
438 }
439 }
senorblancof57372d2016-08-31 10:36:19 -0700440 void close() {
441 if (fHead && fTail) {
442 fTail->fRight = fHead;
443 fHead->fLeft = fTail;
444 }
445 }
446 bool contains(Edge* edge) const {
447 return edge->fLeft || edge->fRight || fHead == edge;
ethannicholase9709e82016-01-07 13:34:16 -0800448 }
449};
450
451/***************************************************************************************/
452
453struct Poly {
senorblanco531237e2016-06-02 11:36:48 -0700454 Poly(Vertex* v, int winding)
455 : fFirstVertex(v)
456 , fWinding(winding)
ethannicholase9709e82016-01-07 13:34:16 -0800457 , fHead(nullptr)
458 , fTail(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800459 , fNext(nullptr)
460 , fPartner(nullptr)
461 , fCount(0)
462 {
463#if LOGGING_ENABLED
464 static int gID = 0;
465 fID = gID++;
466 LOG("*** created Poly %d\n", fID);
467#endif
468 }
senorblanco531237e2016-06-02 11:36:48 -0700469 typedef enum { kLeft_Side, kRight_Side } Side;
ethannicholase9709e82016-01-07 13:34:16 -0800470 struct MonotonePoly {
senorblanco531237e2016-06-02 11:36:48 -0700471 MonotonePoly(Edge* edge, Side side)
472 : fSide(side)
473 , fFirstEdge(nullptr)
474 , fLastEdge(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800475 , fPrev(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700476 , fNext(nullptr) {
477 this->addEdge(edge);
478 }
ethannicholase9709e82016-01-07 13:34:16 -0800479 Side fSide;
senorblanco531237e2016-06-02 11:36:48 -0700480 Edge* fFirstEdge;
481 Edge* fLastEdge;
ethannicholase9709e82016-01-07 13:34:16 -0800482 MonotonePoly* fPrev;
483 MonotonePoly* fNext;
senorblanco531237e2016-06-02 11:36:48 -0700484 void addEdge(Edge* edge) {
senorblancoe6eaa322016-03-08 09:06:44 -0800485 if (fSide == kRight_Side) {
senorblanco212c7c32016-08-18 10:20:47 -0700486 SkASSERT(!edge->fUsedInRightPoly);
senorblanco531237e2016-06-02 11:36:48 -0700487 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
488 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700489 edge->fUsedInRightPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800490 } else {
senorblanco212c7c32016-08-18 10:20:47 -0700491 SkASSERT(!edge->fUsedInLeftPoly);
senorblanco531237e2016-06-02 11:36:48 -0700492 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
493 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700494 edge->fUsedInLeftPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800495 }
ethannicholase9709e82016-01-07 13:34:16 -0800496 }
497
senorblancof57372d2016-08-31 10:36:19 -0700498 void* emit(const AAParams* aaParams, void* data) {
senorblanco531237e2016-06-02 11:36:48 -0700499 Edge* e = fFirstEdge;
senorblanco531237e2016-06-02 11:36:48 -0700500 VertexList vertices;
501 vertices.append(e->fTop);
Stephen White651cbe92017-03-03 12:24:16 -0500502 int count = 1;
senorblanco531237e2016-06-02 11:36:48 -0700503 while (e != nullptr) {
senorblanco531237e2016-06-02 11:36:48 -0700504 if (kRight_Side == fSide) {
505 vertices.append(e->fBottom);
506 e = e->fRightPolyNext;
507 } else {
508 vertices.prepend(e->fBottom);
509 e = e->fLeftPolyNext;
510 }
Stephen White651cbe92017-03-03 12:24:16 -0500511 count++;
senorblanco531237e2016-06-02 11:36:48 -0700512 }
513 Vertex* first = vertices.fHead;
ethannicholase9709e82016-01-07 13:34:16 -0800514 Vertex* v = first->fNext;
senorblanco531237e2016-06-02 11:36:48 -0700515 while (v != vertices.fTail) {
ethannicholase9709e82016-01-07 13:34:16 -0800516 SkASSERT(v && v->fPrev && v->fNext);
517 Vertex* prev = v->fPrev;
518 Vertex* curr = v;
519 Vertex* next = v->fNext;
Stephen White651cbe92017-03-03 12:24:16 -0500520 if (count == 3) {
521 return emit_triangle(prev, curr, next, aaParams, data);
522 }
ethannicholase9709e82016-01-07 13:34:16 -0800523 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
524 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
525 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
526 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
527 if (ax * by - ay * bx >= 0.0) {
senorblancof57372d2016-08-31 10:36:19 -0700528 data = emit_triangle(prev, curr, next, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800529 v->fPrev->fNext = v->fNext;
530 v->fNext->fPrev = v->fPrev;
Stephen White651cbe92017-03-03 12:24:16 -0500531 count--;
ethannicholase9709e82016-01-07 13:34:16 -0800532 if (v->fPrev == first) {
533 v = v->fNext;
534 } else {
535 v = v->fPrev;
536 }
537 } else {
538 v = v->fNext;
539 }
540 }
541 return data;
542 }
543 };
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500544 Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
senorblanco70f52512016-08-17 14:56:22 -0700545 LOG("addEdge (%g -> %g) to poly %d, %s side\n",
546 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
ethannicholase9709e82016-01-07 13:34:16 -0800547 Poly* partner = fPartner;
548 Poly* poly = this;
senorblanco212c7c32016-08-18 10:20:47 -0700549 if (side == kRight_Side) {
550 if (e->fUsedInRightPoly) {
551 return this;
552 }
553 } else {
554 if (e->fUsedInLeftPoly) {
555 return this;
556 }
557 }
ethannicholase9709e82016-01-07 13:34:16 -0800558 if (partner) {
559 fPartner = partner->fPartner = nullptr;
560 }
senorblanco531237e2016-06-02 11:36:48 -0700561 if (!fTail) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500562 fHead = fTail = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700563 fCount += 2;
senorblanco93e3fff2016-06-07 12:36:00 -0700564 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
565 return poly;
senorblanco531237e2016-06-02 11:36:48 -0700566 } else if (side == fTail->fSide) {
567 fTail->addEdge(e);
568 fCount++;
569 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500570 e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -0700571 fTail->addEdge(e);
572 fCount++;
ethannicholase9709e82016-01-07 13:34:16 -0800573 if (partner) {
senorblanco531237e2016-06-02 11:36:48 -0700574 partner->addEdge(e, side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800575 poly = partner;
576 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500577 MonotonePoly* m = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700578 m->fPrev = fTail;
579 fTail->fNext = m;
580 fTail = m;
ethannicholase9709e82016-01-07 13:34:16 -0800581 }
582 }
ethannicholase9709e82016-01-07 13:34:16 -0800583 return poly;
584 }
senorblancof57372d2016-08-31 10:36:19 -0700585 void* emit(const AAParams* aaParams, void *data) {
ethannicholase9709e82016-01-07 13:34:16 -0800586 if (fCount < 3) {
587 return data;
588 }
589 LOG("emit() %d, size %d\n", fID, fCount);
590 for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) {
senorblancof57372d2016-08-31 10:36:19 -0700591 data = m->emit(aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800592 }
593 return data;
594 }
senorblanco531237e2016-06-02 11:36:48 -0700595 Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; }
596 Vertex* fFirstVertex;
ethannicholase9709e82016-01-07 13:34:16 -0800597 int fWinding;
598 MonotonePoly* fHead;
599 MonotonePoly* fTail;
ethannicholase9709e82016-01-07 13:34:16 -0800600 Poly* fNext;
601 Poly* fPartner;
602 int fCount;
603#if LOGGING_ENABLED
604 int fID;
605#endif
606};
607
608/***************************************************************************************/
609
610bool coincident(const SkPoint& a, const SkPoint& b) {
611 return a == b;
612}
613
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500614Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) {
615 Poly* poly = alloc.make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800616 poly->fNext = *head;
617 *head = poly;
618 return poly;
619}
620
Stephen White3a9aab92017-03-07 14:07:18 -0500621void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500622 Vertex* v = alloc.make<Vertex>(p, 255);
ethannicholase9709e82016-01-07 13:34:16 -0800623#if LOGGING_ENABLED
624 static float gID = 0.0f;
625 v->fID = gID++;
626#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500627 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800628}
629
Stephen White36e4f062017-03-27 16:11:31 -0400630SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
631 SkQuadCoeff quad(pts);
632 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
633 SkPoint mid = to_point(quad.eval(t));
634 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400635 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
636 return 0;
637 }
Stephen White36e4f062017-03-27 16:11:31 -0400638 return mid.distanceToLineSegmentBetweenSqd(p0, p1);
639}
640
641void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour,
642 SkArenaAlloc& alloc) {
643 SkQuadCoeff quad(pts);
644 Sk2s aa = quad.fA * quad.fA;
645 SkScalar denom = 2.0f * (aa[0] + aa[1]);
646 Sk2s ab = quad.fA * quad.fB;
647 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
648 int nPoints = 1;
649 SkScalar u;
650 // Test possible subdivision values only at the point of maximum curvature.
651 // If it passes the flatness metric there, it'll pass everywhere.
652 for (;;) {
653 u = 1.0f / nPoints;
654 if (quad_error_at(pts, t, u) < toleranceSqd) {
655 break;
656 }
657 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800658 }
Stephen White36e4f062017-03-27 16:11:31 -0400659 for (int j = 1; j <= nPoints; j++) {
660 append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc);
661 }
ethannicholase9709e82016-01-07 13:34:16 -0800662}
663
Stephen White3a9aab92017-03-07 14:07:18 -0500664void generate_cubic_points(const SkPoint& p0,
665 const SkPoint& p1,
666 const SkPoint& p2,
667 const SkPoint& p3,
668 SkScalar tolSqd,
669 VertexList* contour,
670 int pointsLeft,
671 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -0800672 SkScalar d1 = p1.distanceToLineSegmentBetweenSqd(p0, p3);
673 SkScalar d2 = p2.distanceToLineSegmentBetweenSqd(p0, p3);
674 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
675 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Stephen White3a9aab92017-03-07 14:07:18 -0500676 append_point_to_contour(p3, contour, alloc);
677 return;
ethannicholase9709e82016-01-07 13:34:16 -0800678 }
679 const SkPoint q[] = {
680 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
681 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
682 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
683 };
684 const SkPoint r[] = {
685 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
686 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
687 };
688 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
689 pointsLeft >>= 1;
Stephen White3a9aab92017-03-07 14:07:18 -0500690 generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc);
691 generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800692}
693
694// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
695
696void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen White3a9aab92017-03-07 14:07:18 -0500697 VertexList* contours, SkArenaAlloc& alloc, bool *isLinear) {
ethannicholase9709e82016-01-07 13:34:16 -0800698 SkScalar toleranceSqd = tolerance * tolerance;
699
700 SkPoint pts[4];
ethannicholase9709e82016-01-07 13:34:16 -0800701 *isLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500702 VertexList* contour = contours;
ethannicholase9709e82016-01-07 13:34:16 -0800703 SkPath::Iter iter(path, false);
ethannicholase9709e82016-01-07 13:34:16 -0800704 if (path.isInverseFillType()) {
705 SkPoint quad[4];
706 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700707 for (int i = 3; i >= 0; i--) {
Stephen White3a9aab92017-03-07 14:07:18 -0500708 append_point_to_contour(quad[i], contours, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800709 }
Stephen White3a9aab92017-03-07 14:07:18 -0500710 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800711 }
712 SkAutoConicToQuads converter;
Stephen White3a9aab92017-03-07 14:07:18 -0500713 SkPath::Verb verb;
Stephen White2cee2832017-08-23 09:37:16 -0400714 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800715 switch (verb) {
716 case SkPath::kConic_Verb: {
717 SkScalar weight = iter.conicWeight();
718 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
719 for (int i = 0; i < converter.countQuads(); ++i) {
Stephen White36e4f062017-03-27 16:11:31 -0400720 append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800721 quadPts += 2;
722 }
723 *isLinear = false;
724 break;
725 }
726 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500727 if (contour->fHead) {
728 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800729 }
Stephen White3a9aab92017-03-07 14:07:18 -0500730 append_point_to_contour(pts[0], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800731 break;
732 case SkPath::kLine_Verb: {
Stephen White3a9aab92017-03-07 14:07:18 -0500733 append_point_to_contour(pts[1], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800734 break;
735 }
736 case SkPath::kQuad_Verb: {
Stephen White36e4f062017-03-27 16:11:31 -0400737 append_quadratic_to_contour(pts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800738 *isLinear = false;
739 break;
740 }
741 case SkPath::kCubic_Verb: {
742 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Stephen White3a9aab92017-03-07 14:07:18 -0500743 generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
744 pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800745 *isLinear = false;
746 break;
747 }
748 case SkPath::kClose_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800749 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800750 break;
751 }
752 }
753}
754
Stephen White49789062017-02-21 10:35:49 -0500755inline bool apply_fill_type(SkPath::FillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800756 switch (fillType) {
757 case SkPath::kWinding_FillType:
758 return winding != 0;
759 case SkPath::kEvenOdd_FillType:
760 return (winding & 1) != 0;
761 case SkPath::kInverseWinding_FillType:
senorblanco7ab96e92016-10-12 06:47:44 -0700762 return winding == 1;
ethannicholase9709e82016-01-07 13:34:16 -0800763 case SkPath::kInverseEvenOdd_FillType:
764 return (winding & 1) == 1;
765 default:
766 SkASSERT(false);
767 return false;
768 }
769}
770
Stephen White49789062017-02-21 10:35:49 -0500771inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) {
772 return poly && apply_fill_type(fillType, poly->fWinding);
773}
774
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500775Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) {
Stephen White2f4686f2017-01-03 16:20:01 -0500776 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800777 Vertex* top = winding < 0 ? next : prev;
778 Vertex* bottom = winding < 0 ? prev : next;
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500779 return alloc.make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800780}
781
782void remove_edge(Edge* edge, EdgeList* edges) {
783 LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700784 SkASSERT(edges->contains(edge));
785 edges->remove(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800786}
787
788void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) {
789 LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700790 SkASSERT(!edges->contains(edge));
ethannicholase9709e82016-01-07 13:34:16 -0800791 Edge* next = prev ? prev->fRight : edges->fHead;
senorblancof57372d2016-08-31 10:36:19 -0700792 edges->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800793}
794
795void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500796 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800797 *left = v->fFirstEdgeAbove->fLeft;
798 *right = v->fLastEdgeAbove->fRight;
799 return;
800 }
801 Edge* next = nullptr;
802 Edge* prev;
803 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
804 if (prev->isLeftOf(v)) {
805 break;
806 }
807 next = prev;
808 }
809 *left = prev;
810 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800811}
812
ethannicholase9709e82016-01-07 13:34:16 -0800813void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) {
814 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500815 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800816 return;
817 }
818 LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
819 Edge* prev = nullptr;
820 Edge* next;
821 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
822 if (next->isRightOf(edge->fTop)) {
823 break;
824 }
825 prev = next;
826 }
senorblancoe6eaa322016-03-08 09:06:44 -0800827 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800828 edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
829}
830
831void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) {
832 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500833 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800834 return;
835 }
836 LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
837 Edge* prev = nullptr;
838 Edge* next;
839 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
840 if (next->isRightOf(edge->fBottom)) {
841 break;
842 }
843 prev = next;
844 }
senorblancoe6eaa322016-03-08 09:06:44 -0800845 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800846 edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
847}
848
849void remove_edge_above(Edge* edge) {
850 LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
851 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800852 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800853 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
854}
855
856void remove_edge_below(Edge* edge) {
857 LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
858 edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800859 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800860 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
861}
862
Stephen Whitee7a364d2017-01-11 16:19:26 -0500863void disconnect(Edge* edge)
864{
ethannicholase9709e82016-01-07 13:34:16 -0800865 remove_edge_above(edge);
866 remove_edge_below(edge);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500867}
868
Stephen White3b5a3fa2017-06-06 14:51:19 -0400869void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c);
870
871void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c) {
872 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
873 return;
874 }
875 Vertex* v = *current;
876 LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
877 while (v != dst) {
878 v = v->fPrev;
879 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
880 remove_edge(e, activeEdges);
881 }
882 Edge* leftEdge = v->fLeftEnclosingEdge;
883 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
884 insert_edge(e, leftEdge, activeEdges);
885 leftEdge = e;
886 }
887 }
888 *current = v;
889}
890
891void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
892 if (!activeEdges || !current) {
893 return;
894 }
895 Vertex* top = edge->fTop;
896 Vertex* bottom = edge->fBottom;
897 if (edge->fLeft) {
898 Vertex* leftTop = edge->fLeft->fTop;
899 Vertex* leftBottom = edge->fLeft->fBottom;
900 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
901 rewind(activeEdges, current, leftTop, c);
902 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
903 rewind(activeEdges, current, top, c);
904 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
905 !edge->fLeft->isLeftOf(bottom)) {
906 rewind(activeEdges, current, leftTop, c);
907 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
908 rewind(activeEdges, current, top, c);
909 }
910 }
911 if (edge->fRight) {
912 Vertex* rightTop = edge->fRight->fTop;
913 Vertex* rightBottom = edge->fRight->fBottom;
914 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
915 rewind(activeEdges, current, rightTop, c);
916 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
917 rewind(activeEdges, current, top, c);
918 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
919 !edge->fRight->isRightOf(bottom)) {
920 rewind(activeEdges, current, rightTop, c);
921 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
922 !edge->isLeftOf(rightBottom)) {
923 rewind(activeEdges, current, top, c);
924 }
ethannicholase9709e82016-01-07 13:34:16 -0800925 }
926}
927
Stephen White3b5a3fa2017-06-06 14:51:19 -0400928void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800929 remove_edge_below(edge);
930 edge->fTop = v;
931 edge->recompute();
932 insert_edge_below(edge, v, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400933 rewind_if_necessary(edge, activeEdges, current, c);
934 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800935}
936
Stephen White3b5a3fa2017-06-06 14:51:19 -0400937void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800938 remove_edge_above(edge);
939 edge->fBottom = v;
940 edge->recompute();
941 insert_edge_above(edge, v, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400942 rewind_if_necessary(edge, activeEdges, current, c);
943 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800944}
945
Stephen White3b5a3fa2017-06-06 14:51:19 -0400946void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
947 Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800948 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
949 LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
950 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
951 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400952 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800953 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400954 disconnect(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800955 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400956 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800957 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400958 set_bottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800959 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400960 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800961 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400962 set_bottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800963 }
964}
965
Stephen White3b5a3fa2017-06-06 14:51:19 -0400966void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
967 Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800968 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
969 LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
970 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
971 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400972 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800973 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400974 disconnect(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800975 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400976 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800977 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400978 set_top(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800979 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400980 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800981 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400982 set_top(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800983 }
984}
985
Stephen White3b5a3fa2017-06-06 14:51:19 -0400986void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
Stephen White6eca90f2017-05-25 14:47:11 -0400987 for (;;) {
988 if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
989 !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400990 merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400991 } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
992 !edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400993 merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400994 } else if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
995 !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400996 merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400997 } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
998 !edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400999 merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -04001000 } else {
1001 break;
1002 }
ethannicholase9709e82016-01-07 13:34:16 -08001003 }
Stephen White6eca90f2017-05-25 14:47:11 -04001004 SkASSERT(!edge->fPrevEdgeAbove || edge->fPrevEdgeAbove->isLeftOf(edge->fTop));
1005 SkASSERT(!edge->fPrevEdgeBelow || edge->fPrevEdgeBelow->isLeftOf(edge->fBottom));
1006 SkASSERT(!edge->fNextEdgeAbove || edge->fNextEdgeAbove->isRightOf(edge->fTop));
1007 SkASSERT(!edge->fNextEdgeBelow || edge->fNextEdgeBelow->isRightOf(edge->fBottom));
ethannicholase9709e82016-01-07 13:34:16 -08001008}
1009
Stephen White3b5a3fa2017-06-06 14:51:19 -04001010void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c,
1011 SkArenaAlloc& alloc) {
Stephen White0cb31672017-06-08 14:41:01 -04001012 if (v == edge->fTop || v == edge->fBottom) {
1013 return;
1014 }
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);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001018 Vertex* top;
1019 Vertex* bottom;
ethannicholase9709e82016-01-07 13:34:16 -08001020 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001021 top = v;
1022 bottom = edge->fTop;
1023 set_top(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -05001024 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001025 top = edge->fBottom;
1026 bottom = v;
1027 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001028 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001029 top = v;
1030 bottom = edge->fBottom;
1031 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001032 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001033 Edge* newEdge = alloc.make<Edge>(top, bottom, edge->fWinding, edge->fType);
1034 insert_edge_below(newEdge, top, c);
1035 insert_edge_above(newEdge, bottom, c);
1036 merge_collinear_edges(newEdge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001037}
1038
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001039Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc,
Stephen White48ded382017-02-03 10:15:16 -05001040 int winding_scale = 1) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001041 Edge* edge = new_edge(prev, next, type, c, alloc);
Stephen White8a0bfc52017-02-21 15:24:13 -05001042 insert_edge_below(edge, edge->fTop, c);
1043 insert_edge_above(edge, edge->fBottom, c);
Stephen White48ded382017-02-03 10:15:16 -05001044 edge->fWinding *= winding_scale;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001045 merge_collinear_edges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -07001046 return edge;
1047}
1048
Stephen Whitebf6137e2017-01-04 15:43:26 -05001049void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001050 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001051 LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY,
1052 src->fID, dst->fID);
senorblancof57372d2016-08-31 10:36:19 -07001053 dst->fAlpha = SkTMax(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -04001054 if (src->fPartner) {
1055 src->fPartner->fPartner = dst;
1056 }
ethannicholase9709e82016-01-07 13:34:16 -08001057 for (Edge* edge = src->fFirstEdgeAbove; edge;) {
1058 Edge* next = edge->fNextEdgeAbove;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001059 set_bottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -08001060 edge = next;
1061 }
1062 for (Edge* edge = src->fFirstEdgeBelow; edge;) {
1063 Edge* next = edge->fNextEdgeBelow;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001064 set_top(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -08001065 edge = next;
1066 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001067 mesh->remove(src);
ethannicholase9709e82016-01-07 13:34:16 -08001068}
1069
senorblancof57372d2016-08-31 10:36:19 -07001070uint8_t max_edge_alpha(Edge* a, Edge* b) {
Stephen White56158ae2017-01-30 14:31:31 -05001071 if (a->fType == Edge::Type::kInner || b->fType == Edge::Type::kInner) {
Stephen White2f4686f2017-01-03 16:20:01 -05001072 return 255;
1073 } else if (a->fType == Edge::Type::kOuter && b->fType == Edge::Type::kOuter) {
1074 return 0;
1075 } else {
1076 return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha),
1077 SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha));
1078 }
senorblancof57372d2016-08-31 10:36:19 -07001079}
1080
Stephen White3f5301b2017-08-15 17:01:15 -04001081bool out_of_range_and_collinear(const SkPoint& p, Edge* edge, Comparator& c) {
1082 if (c.sweep_lt(p, edge->fTop->fPoint) &&
1083 !Line(p, edge->fBottom->fPoint).dist(edge->fTop->fPoint)) {
1084 return true;
1085 } else if (c.sweep_lt(edge->fBottom->fPoint, p) &&
1086 !Line(edge->fTop->fPoint, p).dist(edge->fBottom->fPoint)) {
1087 return true;
1088 }
1089 return false;
1090}
1091
Stephen White3b5a3fa2017-06-06 14:51:19 -04001092bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Stephen White0cb31672017-06-08 14:41:01 -04001093 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001094 if (!edge || !other) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001095 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001096 }
Stephen White56158ae2017-01-30 14:31:31 -05001097 SkPoint p;
1098 uint8_t alpha;
Stephen Whitee3a0be72017-06-12 11:43:18 -04001099 if (edge->intersect(*other, &p, &alpha) && p.isFinite()) {
Stephen White3f5301b2017-08-15 17:01:15 -04001100 // Ignore any out-of-range intersections which are also collinear,
1101 // since the resulting edges would cancel each other out by merging.
1102 if (out_of_range_and_collinear(p, edge, c) ||
1103 out_of_range_and_collinear(p, other, c)) {
1104 return false;
1105 }
ethannicholase9709e82016-01-07 13:34:16 -08001106 Vertex* v;
1107 LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001108 Vertex* top = *current;
1109 // If the intersection point is above the current vertex, rewind to the vertex above the
1110 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -04001111 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001112 top = top->fPrev;
1113 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001114 if (p == edge->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001115 v = edge->fTop;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001116 } else if (p == edge->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001117 v = edge->fBottom;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001118 } else if (p == other->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001119 v = other->fTop;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001120 } else if (p == other->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001121 v = other->fBottom;
1122 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001123 Vertex* prevV = top;
Stephen White0cb31672017-06-08 14:41:01 -04001124 Vertex* nextV = top ? top->fNext : mesh->fHead;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001125 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
1126 prevV = nextV;
ethannicholase9709e82016-01-07 13:34:16 -08001127 nextV = nextV->fNext;
1128 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001129 if (prevV && coincident(prevV->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001130 v = prevV;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001131 } else if (nextV && coincident(nextV->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001132 v = nextV;
1133 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001134 v = alloc.make<Vertex>(p, alpha);
ethannicholase9709e82016-01-07 13:34:16 -08001135#if LOGGING_ENABLED
Stephen White0cb31672017-06-08 14:41:01 -04001136 if (!prevV) {
Stephen White019f6c02017-06-09 10:06:26 -04001137 v->fID = mesh->fHead->fID - 1.0f;
Stephen White0cb31672017-06-08 14:41:01 -04001138 } else if (!nextV) {
Stephen White019f6c02017-06-09 10:06:26 -04001139 v->fID = mesh->fTail->fID + 1.0f;
Stephen White0cb31672017-06-08 14:41:01 -04001140 } else {
1141 v->fID = (prevV->fID + nextV->fID) * 0.5f;
1142 }
ethannicholase9709e82016-01-07 13:34:16 -08001143#endif
Stephen White0cb31672017-06-08 14:41:01 -04001144 mesh->insert(v, prevV, nextV);
ethannicholase9709e82016-01-07 13:34:16 -08001145 }
ethannicholase9709e82016-01-07 13:34:16 -08001146 }
Stephen White0cb31672017-06-08 14:41:01 -04001147 rewind(activeEdges, current, top ? top : v, c);
1148 split_edge(edge, v, activeEdges, current, c, alloc);
1149 split_edge(other, v, activeEdges, current, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001150 v->fAlpha = SkTMax(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001151 return true;
ethannicholase9709e82016-01-07 13:34:16 -08001152 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001153 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001154}
1155
Stephen White3a9aab92017-03-07 14:07:18 -05001156void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) {
1157 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1158 SkASSERT(contour->fHead);
1159 Vertex* prev = contour->fTail;
Stephen White5926f2d2017-02-13 13:55:42 -05001160 if (approximate) {
Stephen White3a9aab92017-03-07 14:07:18 -05001161 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -05001162 }
Stephen White3a9aab92017-03-07 14:07:18 -05001163 for (Vertex* v = contour->fHead; v;) {
senorblancof57372d2016-08-31 10:36:19 -07001164 if (approximate) {
1165 round(&v->fPoint);
1166 }
Stephen White3a9aab92017-03-07 14:07:18 -05001167 Vertex* next = v->fNext;
1168 if (coincident(prev->fPoint, v->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -08001169 LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001170 contour->remove(v);
ethannicholase9709e82016-01-07 13:34:16 -08001171 }
Stephen White3a9aab92017-03-07 14:07:18 -05001172 prev = v;
1173 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001174 }
1175 }
1176}
1177
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001178void merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001179 if (!mesh->fHead) {
1180 return;
1181 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001182 for (Vertex* v = mesh->fHead->fNext; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001183 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1184 v->fPoint = v->fPrev->fPoint;
1185 }
1186 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001187 merge_vertices(v->fPrev, v, mesh, c, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001188 }
1189 }
1190}
1191
1192// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1193
Stephen White3a9aab92017-03-07 14:07:18 -05001194void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001195 SkArenaAlloc& alloc) {
Stephen White3a9aab92017-03-07 14:07:18 -05001196 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1197 Vertex* prev = contour->fTail;
1198 for (Vertex* v = contour->fHead; v;) {
1199 Vertex* next = v->fNext;
1200 connect(prev, v, Edge::Type::kInner, c, alloc);
1201 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001202 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001203 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001204 }
1205 }
ethannicholase9709e82016-01-07 13:34:16 -08001206}
1207
Stephen Whitebda29c02017-03-13 15:10:13 -04001208void connect_partners(VertexList* outerVertices, Comparator& c, SkArenaAlloc& alloc) {
1209 for (Vertex* outer = outerVertices->fHead; outer; outer = outer->fNext) {
1210 if (Vertex* inner = outer->fPartner) {
1211 // Connector edges get zero winding, since they're only structural (i.e., to ensure
1212 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding number.
1213 connect(outer, inner, Edge::Type::kConnector, c, alloc, 0);
1214 inner->fPartner = outer->fPartner = nullptr;
1215 }
1216 }
1217}
1218
1219template <CompareFunc sweep_lt>
1220void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
1221 Vertex* a = front->fHead;
1222 Vertex* b = back->fHead;
1223 while (a && b) {
1224 if (sweep_lt(a->fPoint, b->fPoint)) {
1225 front->remove(a);
1226 result->append(a);
1227 a = front->fHead;
1228 } else {
1229 back->remove(b);
1230 result->append(b);
1231 b = back->fHead;
1232 }
1233 }
1234 result->append(*front);
1235 result->append(*back);
1236}
1237
1238void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) {
1239 if (c.fDirection == Comparator::Direction::kHorizontal) {
1240 sorted_merge<sweep_lt_horiz>(front, back, result);
1241 } else {
1242 sorted_merge<sweep_lt_vert>(front, back, result);
1243 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001244#if LOGGING_ENABLED
1245 float id = 0.0f;
1246 for (Vertex* v = result->fHead; v; v = v->fNext) {
1247 v->fID = id++;
1248 }
1249#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001250}
1251
ethannicholase9709e82016-01-07 13:34:16 -08001252// Stage 3: sort the vertices by increasing sweep direction.
1253
Stephen White16a40cb2017-02-23 11:10:01 -05001254template <CompareFunc sweep_lt>
1255void merge_sort(VertexList* vertices) {
1256 Vertex* slow = vertices->fHead;
1257 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001258 return;
1259 }
Stephen White16a40cb2017-02-23 11:10:01 -05001260 Vertex* fast = slow->fNext;
1261 if (!fast) {
1262 return;
1263 }
1264 do {
1265 fast = fast->fNext;
1266 if (fast) {
1267 fast = fast->fNext;
1268 slow = slow->fNext;
1269 }
1270 } while (fast);
1271 VertexList front(vertices->fHead, slow);
1272 VertexList back(slow->fNext, vertices->fTail);
1273 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001274
Stephen White16a40cb2017-02-23 11:10:01 -05001275 merge_sort<sweep_lt>(&front);
1276 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001277
Stephen White16a40cb2017-02-23 11:10:01 -05001278 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001279 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001280}
1281
1282// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1283
Stephen White0cb31672017-06-08 14:41:01 -04001284void simplify(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001285 LOG("simplifying complex polygons\n");
1286 EdgeList activeEdges;
Stephen White0cb31672017-06-08 14:41:01 -04001287 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001288 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1289 continue;
1290 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001291 Edge* leftEnclosingEdge;
1292 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001293 bool restartChecks;
1294 do {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001295 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001296 restartChecks = false;
1297 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White64dbb892017-05-03 16:00:38 -04001298 if (rightEnclosingEdge && !rightEnclosingEdge->isRightOf(v)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001299 split_edge(rightEnclosingEdge, v, &activeEdges, &v, c, alloc);
Stephen White64dbb892017-05-03 16:00:38 -04001300 restartChecks = true;
1301 continue;
1302 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001303 SkASSERT(!rightEnclosingEdge || rightEnclosingEdge->isRightOf(v));
1304 v->fLeftEnclosingEdge = leftEnclosingEdge;
1305 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001306 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001307 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Stephen White0cb31672017-06-08 14:41:01 -04001308 if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001309 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001310 restartChecks = true;
1311 break;
1312 }
Stephen White0cb31672017-06-08 14:41:01 -04001313 if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001314 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001315 restartChecks = true;
1316 break;
1317 }
1318 }
1319 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001320 if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
Stephen White0cb31672017-06-08 14:41:01 -04001321 &activeEdges, &v, mesh, c, alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001322 restartChecks = true;
1323 }
1324
1325 }
1326 } while (restartChecks);
senorblancof57372d2016-08-31 10:36:19 -07001327 if (v->fAlpha == 0) {
Stephen White48ded382017-02-03 10:15:16 -05001328 if ((leftEnclosingEdge && leftEnclosingEdge->fWinding < 0) &&
1329 (rightEnclosingEdge && rightEnclosingEdge->fWinding > 0)) {
senorblancof57372d2016-08-31 10:36:19 -07001330 v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge);
1331 }
1332 }
ethannicholase9709e82016-01-07 13:34:16 -08001333 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1334 remove_edge(e, &activeEdges);
1335 }
1336 Edge* leftEdge = leftEnclosingEdge;
1337 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1338 insert_edge(e, leftEdge, &activeEdges);
1339 leftEdge = e;
1340 }
ethannicholase9709e82016-01-07 13:34:16 -08001341 }
1342}
1343
Stephen Whitebda29c02017-03-13 15:10:13 -04001344// This is a stripped-down version of simplify() (the Bentley-Ottmann algorithm) that
1345// early-returns true on the first found intersection, false if none.
1346bool is_complex(const VertexList& vertices) {
1347 LOG("testing polygon complexity\n");
1348 EdgeList activeEdges;
1349 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
1350 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1351 continue;
1352 }
1353 Edge* leftEnclosingEdge;
1354 Edge* rightEnclosingEdge;
1355 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1356 SkPoint dummy;
1357 if (v->fFirstEdgeBelow) {
1358 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
1359 if (edge && leftEnclosingEdge && edge->intersect(*leftEnclosingEdge, &dummy)) {
1360 activeEdges.removeAll();
1361 return true;
1362 }
1363 if (edge && rightEnclosingEdge && edge->intersect(*rightEnclosingEdge, &dummy)) {
1364 activeEdges.removeAll();
1365 return true;
1366 }
1367 }
1368 } else if (leftEnclosingEdge && rightEnclosingEdge &&
1369 leftEnclosingEdge->intersect(*rightEnclosingEdge, &dummy)) {
1370 activeEdges.removeAll();
1371 return true;
1372 }
1373 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1374 remove_edge(e, &activeEdges);
1375 }
1376 Edge* leftEdge = leftEnclosingEdge;
1377 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1378 insert_edge(e, leftEdge, &activeEdges);
1379 leftEdge = e;
1380 }
1381 }
1382 activeEdges.removeAll();
1383 return false;
1384}
1385
ethannicholase9709e82016-01-07 13:34:16 -08001386// Stage 5: Tessellate the simplified mesh into monotone polygons.
1387
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001388Poly* tessellate(const VertexList& vertices, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001389 LOG("tessellating simple polygons\n");
1390 EdgeList activeEdges;
1391 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001392 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001393 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1394 continue;
1395 }
1396#if LOGGING_ENABLED
senorblancof57372d2016-08-31 10:36:19 -07001397 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001398#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001399 Edge* leftEnclosingEdge;
1400 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001401 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001402 Poly* leftPoly;
1403 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001404 if (v->fFirstEdgeAbove) {
1405 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1406 rightPoly = v->fLastEdgeAbove->fRightPoly;
1407 } else {
1408 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1409 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1410 }
1411#if LOGGING_ENABLED
1412 LOG("edges above:\n");
1413 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1414 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1415 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1416 }
1417 LOG("edges below:\n");
1418 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1419 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1420 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1421 }
1422#endif
1423 if (v->fFirstEdgeAbove) {
1424 if (leftPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001425 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001426 }
1427 if (rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001428 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001429 }
1430 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001431 Edge* rightEdge = e->fNextEdgeAbove;
Stephen White8a0bfc52017-02-21 15:24:13 -05001432 remove_edge(e, &activeEdges);
1433 if (e->fRightPoly) {
1434 e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001435 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001436 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001437 rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001438 }
1439 }
1440 remove_edge(v->fLastEdgeAbove, &activeEdges);
1441 if (!v->fFirstEdgeBelow) {
1442 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1443 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1444 rightPoly->fPartner = leftPoly;
1445 leftPoly->fPartner = rightPoly;
1446 }
1447 }
1448 }
1449 if (v->fFirstEdgeBelow) {
1450 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001451 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001452 if (leftPoly == rightPoly) {
1453 if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) {
1454 leftPoly = new_poly(&polys, leftPoly->lastVertex(),
1455 leftPoly->fWinding, alloc);
1456 leftEnclosingEdge->fRightPoly = leftPoly;
1457 } else {
1458 rightPoly = new_poly(&polys, rightPoly->lastVertex(),
1459 rightPoly->fWinding, alloc);
1460 rightEnclosingEdge->fLeftPoly = rightPoly;
1461 }
ethannicholase9709e82016-01-07 13:34:16 -08001462 }
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001463 Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -07001464 leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc);
1465 rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001466 }
1467 }
1468 Edge* leftEdge = v->fFirstEdgeBelow;
1469 leftEdge->fLeftPoly = leftPoly;
1470 insert_edge(leftEdge, leftEnclosingEdge, &activeEdges);
1471 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1472 rightEdge = rightEdge->fNextEdgeBelow) {
1473 insert_edge(rightEdge, leftEdge, &activeEdges);
1474 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1475 winding += leftEdge->fWinding;
1476 if (winding != 0) {
1477 Poly* poly = new_poly(&polys, v, winding, alloc);
1478 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1479 }
1480 leftEdge = rightEdge;
1481 }
1482 v->fLastEdgeBelow->fRightPoly = rightPoly;
1483 }
1484#if LOGGING_ENABLED
1485 LOG("\nactive edges:\n");
1486 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
1487 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1488 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1489 }
1490#endif
1491 }
1492 return polys;
1493}
1494
Stephen Whitebf6137e2017-01-04 15:43:26 -05001495void remove_non_boundary_edges(const VertexList& mesh, SkPath::FillType fillType,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001496 SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001497 LOG("removing non-boundary edges\n");
1498 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001499 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
Stephen White49789062017-02-21 10:35:49 -05001500 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1501 continue;
1502 }
1503 Edge* leftEnclosingEdge;
1504 Edge* rightEnclosingEdge;
1505 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1506 bool prevFilled = leftEnclosingEdge &&
1507 apply_fill_type(fillType, leftEnclosingEdge->fWinding);
1508 for (Edge* e = v->fFirstEdgeAbove; e;) {
1509 Edge* next = e->fNextEdgeAbove;
1510 remove_edge(e, &activeEdges);
1511 bool filled = apply_fill_type(fillType, e->fWinding);
1512 if (filled == prevFilled) {
Stephen Whitee7a364d2017-01-11 16:19:26 -05001513 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001514 }
Stephen White49789062017-02-21 10:35:49 -05001515 prevFilled = filled;
senorblancof57372d2016-08-31 10:36:19 -07001516 e = next;
1517 }
Stephen White49789062017-02-21 10:35:49 -05001518 Edge* prev = leftEnclosingEdge;
1519 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1520 if (prev) {
1521 e->fWinding += prev->fWinding;
1522 }
1523 insert_edge(e, prev, &activeEdges);
1524 prev = e;
1525 }
senorblancof57372d2016-08-31 10:36:19 -07001526 }
senorblancof57372d2016-08-31 10:36:19 -07001527}
1528
Stephen White66412122017-03-01 11:48:27 -05001529// Note: this is the normal to the edge, but not necessarily unit length.
senorblancof57372d2016-08-31 10:36:19 -07001530void get_edge_normal(const Edge* e, SkVector* normal) {
Stephen White66412122017-03-01 11:48:27 -05001531 normal->set(SkDoubleToScalar(e->fLine.fA) * e->fWinding,
1532 SkDoubleToScalar(e->fLine.fB) * e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001533}
1534
1535// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
1536// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
1537// invert on stroking.
1538
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001539void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) {
senorblancof57372d2016-08-31 10:36:19 -07001540 Edge* prevEdge = boundary->fTail;
1541 SkVector prevNormal;
1542 get_edge_normal(prevEdge, &prevNormal);
1543 for (Edge* e = boundary->fHead; e != nullptr;) {
1544 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
1545 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
1546 double dist = e->dist(prev->fPoint);
1547 SkVector normal;
1548 get_edge_normal(e, &normal);
Stephen White66412122017-03-01 11:48:27 -05001549 double denom = 0.0625f * e->fLine.magSq();
senorblancof57372d2016-08-31 10:36:19 -07001550 if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001551 Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001552 insert_edge(join, e, boundary);
1553 remove_edge(prevEdge, boundary);
1554 remove_edge(e, boundary);
1555 if (join->fLeft && join->fRight) {
1556 prevEdge = join->fLeft;
1557 e = join;
1558 } else {
1559 prevEdge = boundary->fTail;
1560 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
1561 }
1562 get_edge_normal(prevEdge, &prevNormal);
1563 } else {
1564 prevEdge = e;
1565 prevNormal = normal;
1566 e = e->fRight;
1567 }
1568 }
1569}
1570
Ben Wagnerdab48112017-02-16 22:28:02 +00001571void fix_inversions(Vertex* prev, Vertex* next, Edge* prevBisector, Edge* nextBisector,
Stephen White92eba8a2017-02-06 09:50:27 -05001572 Edge* prevEdge, Comparator& c) {
1573 if (!prev || !next) {
1574 return;
1575 }
1576 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
1577 SkPoint p;
1578 uint8_t alpha;
Ben Wagnerdab48112017-02-16 22:28:02 +00001579 if (winding != prevEdge->fWinding && prevBisector->intersect(*nextBisector, &p, &alpha)) {
Stephen White92eba8a2017-02-06 09:50:27 -05001580 prev->fPoint = next->fPoint = p;
1581 prev->fAlpha = next->fAlpha = alpha;
1582 }
1583}
1584
senorblancof57372d2016-08-31 10:36:19 -07001585// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
1586// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
1587// new antialiased mesh from those vertices.
1588
Stephen Whitebda29c02017-03-13 15:10:13 -04001589void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
1590 Comparator& c, SkArenaAlloc& alloc) {
Stephen White8a0bfc52017-02-21 15:24:13 -05001591 // A boundary with fewer than 3 edges is degenerate.
1592 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
1593 return;
1594 }
senorblancof57372d2016-08-31 10:36:19 -07001595 Edge* prevEdge = boundary->fTail;
1596 float radius = 0.5f;
senorblanco49df8d12016-10-07 08:36:56 -07001597 double offset = radius * sqrt(prevEdge->fLine.magSq()) * prevEdge->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001598 Line prevInner(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001599 prevInner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001600 Line prevOuter(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001601 prevOuter.fC += offset;
1602 VertexList innerVertices;
1603 VertexList outerVertices;
Ben Wagnerdab48112017-02-16 22:28:02 +00001604 Edge* prevBisector = nullptr;
senorblancof57372d2016-08-31 10:36:19 -07001605 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
senorblanco49df8d12016-10-07 08:36:56 -07001606 double offset = radius * sqrt(e->fLine.magSq()) * e->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001607 Line inner(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001608 inner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001609 Line outer(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001610 outer.fC += offset;
1611 SkPoint innerPoint, outerPoint;
senorblanco49df8d12016-10-07 08:36:56 -07001612 if (prevInner.intersect(inner, &innerPoint) &&
1613 prevOuter.intersect(outer, &outerPoint)) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001614 Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255);
1615 Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0);
Ben Wagnerdab48112017-02-16 22:28:02 +00001616 Edge* bisector = new_edge(outerVertex, innerVertex, Edge::Type::kConnector, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001617 fix_inversions(innerVertices.fTail, innerVertex, prevBisector, bisector, prevEdge, c);
1618 fix_inversions(outerVertices.fTail, outerVertex, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001619 innerVertex->fPartner = outerVertex;
1620 outerVertex->fPartner = innerVertex;
Stephen White92eba8a2017-02-06 09:50:27 -05001621 innerVertices.append(innerVertex);
1622 outerVertices.append(outerVertex);
1623 prevBisector = bisector;
senorblancof57372d2016-08-31 10:36:19 -07001624 }
1625 prevInner = inner;
1626 prevOuter = outer;
Stephen White86cc8412017-01-27 10:53:15 -05001627 prevEdge = e;
senorblancof57372d2016-08-31 10:36:19 -07001628 }
senorblancof57372d2016-08-31 10:36:19 -07001629
1630 Vertex* innerVertex = innerVertices.fHead;
1631 Vertex* outerVertex = outerVertices.fHead;
senorblancof57372d2016-08-31 10:36:19 -07001632 if (!innerVertex || !outerVertex) {
1633 return;
1634 }
Ben Wagnerdab48112017-02-16 22:28:02 +00001635 Edge* bisector = new_edge(outerVertices.fHead, innerVertices.fHead, Edge::Type::kConnector, c,
1636 alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001637 fix_inversions(innerVertices.fTail, innerVertices.fHead, prevBisector, bisector, prevEdge, c);
1638 fix_inversions(outerVertices.fTail, outerVertices.fHead, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001639 Vertex* prevInnerVertex = innerVertices.fTail;
1640 Vertex* prevOuterVertex = outerVertices.fTail;
1641 while (innerVertex && outerVertex) {
Stephen White48ded382017-02-03 10:15:16 -05001642 // Connect vertices into a quad mesh. Outer edges get default (1) winding.
1643 // Inner edges get -2 winding. This ensures that the interior is always filled
1644 // (-1 winding number for normal cases, 3 for thin features where the interior inverts).
Stephen Whitebda29c02017-03-13 15:10:13 -04001645 connect(prevOuterVertex, outerVertex, Edge::Type::kOuter, c, alloc);
1646 connect(prevInnerVertex, innerVertex, Edge::Type::kInner, c, alloc, -2);
1647 prevInnerVertex = innerVertex;
1648 prevOuterVertex = outerVertex;
1649 innerVertex = innerVertex->fNext;
1650 outerVertex = outerVertex->fNext;
1651 }
1652 innerMesh->append(innerVertices);
1653 outerMesh->append(outerVertices);
senorblancof57372d2016-08-31 10:36:19 -07001654}
1655
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001656void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001657 bool down = apply_fill_type(fillType, e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001658 while (e) {
1659 e->fWinding = down ? 1 : -1;
1660 Edge* next;
1661 boundary->append(e);
1662 if (down) {
1663 // Find outgoing edge, in clockwise order.
1664 if ((next = e->fNextEdgeAbove)) {
1665 down = false;
1666 } else if ((next = e->fBottom->fLastEdgeBelow)) {
1667 down = true;
1668 } else if ((next = e->fPrevEdgeAbove)) {
1669 down = false;
1670 }
1671 } else {
1672 // Find outgoing edge, in counter-clockwise order.
1673 if ((next = e->fPrevEdgeBelow)) {
1674 down = true;
1675 } else if ((next = e->fTop->fFirstEdgeAbove)) {
1676 down = false;
1677 } else if ((next = e->fNextEdgeBelow)) {
1678 down = true;
1679 }
1680 }
Stephen Whitee7a364d2017-01-11 16:19:26 -05001681 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001682 e = next;
1683 }
1684}
1685
Stephen White5ad721e2017-02-23 16:50:47 -05001686// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
senorblancof57372d2016-08-31 10:36:19 -07001687
Stephen Whitebda29c02017-03-13 15:10:13 -04001688void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices,
1689 VertexList* outerVertices, SkPath::FillType fillType,
Stephen White5ad721e2017-02-23 16:50:47 -05001690 Comparator& c, SkArenaAlloc& alloc) {
1691 remove_non_boundary_edges(inMesh, fillType, alloc);
1692 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001693 while (v->fFirstEdgeBelow) {
Stephen White5ad721e2017-02-23 16:50:47 -05001694 EdgeList boundary;
1695 extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc);
1696 simplify_boundary(&boundary, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001697 stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001698 }
1699 }
senorblancof57372d2016-08-31 10:36:19 -07001700}
1701
Stephen Whitebda29c02017-03-13 15:10:13 -04001702// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001703
Stephen White3a9aab92017-03-07 14:07:18 -05001704void contours_to_mesh(VertexList* contours, int contourCnt, bool antialias,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001705 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001706#if LOGGING_ENABLED
1707 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001708 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001709 SkASSERT(v);
1710 LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001711 for (v = v->fNext; v; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001712 LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1713 }
1714 }
1715#endif
senorblancof57372d2016-08-31 10:36:19 -07001716 sanitize_contours(contours, contourCnt, antialias);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001717 build_edges(contours, contourCnt, mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001718}
1719
Stephen Whitebda29c02017-03-13 15:10:13 -04001720void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001721 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001722 return;
ethannicholase9709e82016-01-07 13:34:16 -08001723 }
1724
1725 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001726 if (c.fDirection == Comparator::Direction::kHorizontal) {
1727 merge_sort<sweep_lt_horiz>(vertices);
1728 } else {
1729 merge_sort<sweep_lt_vert>(vertices);
1730 }
ethannicholase9709e82016-01-07 13:34:16 -08001731#if LOGGING_ENABLED
Stephen White2e2cb9b2017-01-09 13:11:18 -05001732 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001733 static float gID = 0.0f;
1734 v->fID = gID++;
1735 }
1736#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001737}
1738
Stephen White3a9aab92017-03-07 14:07:18 -05001739Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPath::FillType fillType,
Stephen Whitebda29c02017-03-13 15:10:13 -04001740 const SkRect& pathBounds, bool antialias, VertexList* outerMesh,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001741 SkArenaAlloc& alloc) {
Stephen White16a40cb2017-02-23 11:10:01 -05001742 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1743 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001744 VertexList mesh;
1745 contours_to_mesh(contours, contourCnt, antialias, &mesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001746 sort_mesh(&mesh, c, alloc);
1747 merge_coincident_vertices(&mesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04001748 simplify(&mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001749 if (antialias) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001750 VertexList innerMesh;
1751 extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc);
1752 sort_mesh(&innerMesh, c, alloc);
1753 sort_mesh(outerMesh, c, alloc);
1754 if (is_complex(innerMesh) || is_complex(*outerMesh)) {
1755 LOG("found complex mesh; taking slow path\n");
1756 VertexList aaMesh;
1757 connect_partners(outerMesh, c, alloc);
1758 sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
1759 merge_coincident_vertices(&aaMesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04001760 simplify(&aaMesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001761 outerMesh->fHead = outerMesh->fTail = nullptr;
1762 return tessellate(aaMesh, alloc);
1763 } else {
1764 LOG("no complex polygons; taking fast path\n");
1765 merge_coincident_vertices(&innerMesh, c, alloc);
1766 return tessellate(innerMesh, alloc);
1767 }
Stephen White49789062017-02-21 10:35:49 -05001768 } else {
1769 return tessellate(mesh, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001770 }
senorblancof57372d2016-08-31 10:36:19 -07001771}
1772
1773// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1774void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* aaParams,
1775 void* data) {
1776 for (Poly* poly = polys; poly; poly = poly->fNext) {
1777 if (apply_fill_type(fillType, poly)) {
1778 data = poly->emit(aaParams, data);
1779 }
1780 }
1781 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001782}
1783
halcanary9d524f22016-03-29 09:03:52 -07001784Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen Whitebda29c02017-03-13 15:10:13 -04001785 int contourCnt, SkArenaAlloc& alloc, bool antialias, bool* isLinear,
1786 VertexList* outerMesh) {
ethannicholase9709e82016-01-07 13:34:16 -08001787 SkPath::FillType fillType = path.getFillType();
1788 if (SkPath::IsInverseFillType(fillType)) {
1789 contourCnt++;
1790 }
Stephen White3a9aab92017-03-07 14:07:18 -05001791 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08001792
1793 path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear);
senorblancof57372d2016-08-31 10:36:19 -07001794 return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(),
Stephen Whitebda29c02017-03-13 15:10:13 -04001795 antialias, outerMesh, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001796}
1797
Stephen White11f65e02017-02-16 19:00:39 -05001798int get_contour_count(const SkPath& path, SkScalar tolerance) {
1799 int contourCnt;
1800 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001801 if (maxPts <= 0) {
Stephen White11f65e02017-02-16 19:00:39 -05001802 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001803 }
1804 if (maxPts > ((int)SK_MaxU16 + 1)) {
1805 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
Stephen White11f65e02017-02-16 19:00:39 -05001806 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001807 }
Stephen White11f65e02017-02-16 19:00:39 -05001808 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001809}
1810
1811int count_points(Poly* polys, SkPath::FillType fillType) {
1812 int count = 0;
1813 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001814 if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
ethannicholase9709e82016-01-07 13:34:16 -08001815 count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3);
1816 }
1817 }
1818 return count;
1819}
1820
Stephen Whitebda29c02017-03-13 15:10:13 -04001821int count_outer_mesh_points(const VertexList& outerMesh) {
1822 int count = 0;
1823 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1824 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1825 count += TESSELLATOR_WIREFRAME ? 12 : 6;
1826 }
1827 }
1828 return count;
1829}
1830
1831void* outer_mesh_to_triangles(const VertexList& outerMesh, const AAParams* aaParams, void* data) {
1832 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1833 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1834 Vertex* v0 = e->fTop;
1835 Vertex* v1 = e->fBottom;
1836 Vertex* v2 = e->fBottom->fPartner;
1837 Vertex* v3 = e->fTop->fPartner;
1838 data = emit_triangle(v0, v1, v2, aaParams, data);
1839 data = emit_triangle(v0, v2, v3, aaParams, data);
1840 }
1841 }
1842 return data;
1843}
1844
ethannicholase9709e82016-01-07 13:34:16 -08001845} // namespace
1846
1847namespace GrTessellator {
1848
1849// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1850
halcanary9d524f22016-03-29 09:03:52 -07001851int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
senorblancof57372d2016-08-31 10:36:19 -07001852 VertexAllocator* vertexAllocator, bool antialias, const GrColor& color,
1853 bool canTweakAlphaForCoverage, bool* isLinear) {
Stephen White11f65e02017-02-16 19:00:39 -05001854 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001855 if (contourCnt <= 0) {
1856 *isLinear = true;
1857 return 0;
1858 }
Stephen White11f65e02017-02-16 19:00:39 -05001859 SkArenaAlloc alloc(kArenaChunkSize);
Stephen Whitebda29c02017-03-13 15:10:13 -04001860 VertexList outerMesh;
senorblancof57372d2016-08-31 10:36:19 -07001861 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias,
Stephen Whitebda29c02017-03-13 15:10:13 -04001862 isLinear, &outerMesh);
senorblanco7ab96e92016-10-12 06:47:44 -07001863 SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType();
ethannicholase9709e82016-01-07 13:34:16 -08001864 int count = count_points(polys, fillType);
Stephen Whitebda29c02017-03-13 15:10:13 -04001865 if (antialias) {
1866 count += count_outer_mesh_points(outerMesh);
1867 }
Stephen Whiteff60b172017-05-05 15:54:52 -04001868 if (0 == count) {
1869 return 0;
1870 }
ethannicholase9709e82016-01-07 13:34:16 -08001871
senorblancof57372d2016-08-31 10:36:19 -07001872 void* verts = vertexAllocator->lock(count);
senorblanco6599eff2016-03-10 08:38:45 -08001873 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001874 SkDebugf("Could not allocate vertices\n");
1875 return 0;
1876 }
senorblancof57372d2016-08-31 10:36:19 -07001877
1878 LOG("emitting %d verts\n", count);
1879 AAParams aaParams;
1880 aaParams.fTweakAlpha = canTweakAlphaForCoverage;
1881 aaParams.fColor = color;
1882
1883 void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts);
Stephen Whitebda29c02017-03-13 15:10:13 -04001884 end = outer_mesh_to_triangles(outerMesh, &aaParams, end);
senorblancof57372d2016-08-31 10:36:19 -07001885 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
1886 / vertexAllocator->stride());
ethannicholase9709e82016-01-07 13:34:16 -08001887 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001888 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001889 return actualCount;
1890}
1891
halcanary9d524f22016-03-29 09:03:52 -07001892int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
ethannicholase9709e82016-01-07 13:34:16 -08001893 GrTessellator::WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05001894 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001895 if (contourCnt <= 0) {
1896 return 0;
1897 }
Stephen White11f65e02017-02-16 19:00:39 -05001898 SkArenaAlloc alloc(kArenaChunkSize);
ethannicholase9709e82016-01-07 13:34:16 -08001899 bool isLinear;
Stephen Whitebda29c02017-03-13 15:10:13 -04001900 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear,
1901 nullptr);
ethannicholase9709e82016-01-07 13:34:16 -08001902 SkPath::FillType fillType = path.getFillType();
1903 int count = count_points(polys, fillType);
1904 if (0 == count) {
1905 *verts = nullptr;
1906 return 0;
1907 }
1908
1909 *verts = new GrTessellator::WindingVertex[count];
1910 GrTessellator::WindingVertex* vertsEnd = *verts;
1911 SkPoint* points = new SkPoint[count];
1912 SkPoint* pointsEnd = points;
1913 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001914 if (apply_fill_type(fillType, poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001915 SkPoint* start = pointsEnd;
senorblancof57372d2016-08-31 10:36:19 -07001916 pointsEnd = static_cast<SkPoint*>(poly->emit(nullptr, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001917 while (start != pointsEnd) {
1918 vertsEnd->fPos = *start;
1919 vertsEnd->fWinding = poly->fWinding;
1920 ++start;
1921 ++vertsEnd;
1922 }
1923 }
1924 }
1925 int actualCount = static_cast<int>(vertsEnd - *verts);
1926 SkASSERT(actualCount <= count);
1927 SkASSERT(pointsEnd - points == actualCount);
1928 delete[] points;
1929 return actualCount;
1930}
1931
1932} // namespace