blob: 5f25e5a5fb525290e298e85cb5705743d24b27e5 [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;
714 while ((verb = iter.next(pts)) != 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 White3b5a3fa2017-06-06 14:51:19 -04001081bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Stephen White0cb31672017-06-08 14:41:01 -04001082 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001083 if (!edge || !other) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001084 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001085 }
Stephen White56158ae2017-01-30 14:31:31 -05001086 SkPoint p;
1087 uint8_t alpha;
Stephen Whitee3a0be72017-06-12 11:43:18 -04001088 if (edge->intersect(*other, &p, &alpha) && p.isFinite()) {
ethannicholase9709e82016-01-07 13:34:16 -08001089 Vertex* v;
1090 LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001091 Vertex* top = *current;
1092 // If the intersection point is above the current vertex, rewind to the vertex above the
1093 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -04001094 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001095 top = top->fPrev;
1096 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001097 if (p == edge->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001098 v = edge->fTop;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001099 } else if (p == edge->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001100 v = edge->fBottom;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001101 } else if (p == other->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001102 v = other->fTop;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001103 } else if (p == other->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001104 v = other->fBottom;
1105 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001106 Vertex* prevV = top;
Stephen White0cb31672017-06-08 14:41:01 -04001107 Vertex* nextV = top ? top->fNext : mesh->fHead;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001108 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
1109 prevV = nextV;
ethannicholase9709e82016-01-07 13:34:16 -08001110 nextV = nextV->fNext;
1111 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001112 if (prevV && coincident(prevV->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001113 v = prevV;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001114 } else if (nextV && coincident(nextV->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001115 v = nextV;
1116 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001117 v = alloc.make<Vertex>(p, alpha);
ethannicholase9709e82016-01-07 13:34:16 -08001118#if LOGGING_ENABLED
Stephen White0cb31672017-06-08 14:41:01 -04001119 if (!prevV) {
Stephen White019f6c02017-06-09 10:06:26 -04001120 v->fID = mesh->fHead->fID - 1.0f;
Stephen White0cb31672017-06-08 14:41:01 -04001121 } else if (!nextV) {
Stephen White019f6c02017-06-09 10:06:26 -04001122 v->fID = mesh->fTail->fID + 1.0f;
Stephen White0cb31672017-06-08 14:41:01 -04001123 } else {
1124 v->fID = (prevV->fID + nextV->fID) * 0.5f;
1125 }
ethannicholase9709e82016-01-07 13:34:16 -08001126#endif
Stephen White0cb31672017-06-08 14:41:01 -04001127 mesh->insert(v, prevV, nextV);
ethannicholase9709e82016-01-07 13:34:16 -08001128 }
ethannicholase9709e82016-01-07 13:34:16 -08001129 }
Stephen White0cb31672017-06-08 14:41:01 -04001130 rewind(activeEdges, current, top ? top : v, c);
1131 split_edge(edge, v, activeEdges, current, c, alloc);
1132 split_edge(other, v, activeEdges, current, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001133 v->fAlpha = SkTMax(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001134 return true;
ethannicholase9709e82016-01-07 13:34:16 -08001135 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001136 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001137}
1138
Stephen White3a9aab92017-03-07 14:07:18 -05001139void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) {
1140 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1141 SkASSERT(contour->fHead);
1142 Vertex* prev = contour->fTail;
Stephen White5926f2d2017-02-13 13:55:42 -05001143 if (approximate) {
Stephen White3a9aab92017-03-07 14:07:18 -05001144 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -05001145 }
Stephen White3a9aab92017-03-07 14:07:18 -05001146 for (Vertex* v = contour->fHead; v;) {
senorblancof57372d2016-08-31 10:36:19 -07001147 if (approximate) {
1148 round(&v->fPoint);
1149 }
Stephen White3a9aab92017-03-07 14:07:18 -05001150 Vertex* next = v->fNext;
1151 if (coincident(prev->fPoint, v->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -08001152 LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001153 contour->remove(v);
ethannicholase9709e82016-01-07 13:34:16 -08001154 }
Stephen White3a9aab92017-03-07 14:07:18 -05001155 prev = v;
1156 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001157 }
1158 }
1159}
1160
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001161void merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001162 if (!mesh->fHead) {
1163 return;
1164 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001165 for (Vertex* v = mesh->fHead->fNext; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001166 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1167 v->fPoint = v->fPrev->fPoint;
1168 }
1169 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001170 merge_vertices(v->fPrev, v, mesh, c, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001171 }
1172 }
1173}
1174
1175// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1176
Stephen White3a9aab92017-03-07 14:07:18 -05001177void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001178 SkArenaAlloc& alloc) {
Stephen White3a9aab92017-03-07 14:07:18 -05001179 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1180 Vertex* prev = contour->fTail;
1181 for (Vertex* v = contour->fHead; v;) {
1182 Vertex* next = v->fNext;
1183 connect(prev, v, Edge::Type::kInner, c, alloc);
1184 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001185 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001186 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001187 }
1188 }
ethannicholase9709e82016-01-07 13:34:16 -08001189}
1190
Stephen Whitebda29c02017-03-13 15:10:13 -04001191void connect_partners(VertexList* outerVertices, Comparator& c, SkArenaAlloc& alloc) {
1192 for (Vertex* outer = outerVertices->fHead; outer; outer = outer->fNext) {
1193 if (Vertex* inner = outer->fPartner) {
1194 // Connector edges get zero winding, since they're only structural (i.e., to ensure
1195 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding number.
1196 connect(outer, inner, Edge::Type::kConnector, c, alloc, 0);
1197 inner->fPartner = outer->fPartner = nullptr;
1198 }
1199 }
1200}
1201
1202template <CompareFunc sweep_lt>
1203void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
1204 Vertex* a = front->fHead;
1205 Vertex* b = back->fHead;
1206 while (a && b) {
1207 if (sweep_lt(a->fPoint, b->fPoint)) {
1208 front->remove(a);
1209 result->append(a);
1210 a = front->fHead;
1211 } else {
1212 back->remove(b);
1213 result->append(b);
1214 b = back->fHead;
1215 }
1216 }
1217 result->append(*front);
1218 result->append(*back);
1219}
1220
1221void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) {
1222 if (c.fDirection == Comparator::Direction::kHorizontal) {
1223 sorted_merge<sweep_lt_horiz>(front, back, result);
1224 } else {
1225 sorted_merge<sweep_lt_vert>(front, back, result);
1226 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001227#if LOGGING_ENABLED
1228 float id = 0.0f;
1229 for (Vertex* v = result->fHead; v; v = v->fNext) {
1230 v->fID = id++;
1231 }
1232#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001233}
1234
ethannicholase9709e82016-01-07 13:34:16 -08001235// Stage 3: sort the vertices by increasing sweep direction.
1236
Stephen White16a40cb2017-02-23 11:10:01 -05001237template <CompareFunc sweep_lt>
1238void merge_sort(VertexList* vertices) {
1239 Vertex* slow = vertices->fHead;
1240 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001241 return;
1242 }
Stephen White16a40cb2017-02-23 11:10:01 -05001243 Vertex* fast = slow->fNext;
1244 if (!fast) {
1245 return;
1246 }
1247 do {
1248 fast = fast->fNext;
1249 if (fast) {
1250 fast = fast->fNext;
1251 slow = slow->fNext;
1252 }
1253 } while (fast);
1254 VertexList front(vertices->fHead, slow);
1255 VertexList back(slow->fNext, vertices->fTail);
1256 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001257
Stephen White16a40cb2017-02-23 11:10:01 -05001258 merge_sort<sweep_lt>(&front);
1259 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001260
Stephen White16a40cb2017-02-23 11:10:01 -05001261 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001262 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001263}
1264
1265// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1266
Stephen White0cb31672017-06-08 14:41:01 -04001267void simplify(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001268 LOG("simplifying complex polygons\n");
1269 EdgeList activeEdges;
Stephen White0cb31672017-06-08 14:41:01 -04001270 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001271 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1272 continue;
1273 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001274 Edge* leftEnclosingEdge;
1275 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001276 bool restartChecks;
1277 do {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001278 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001279 restartChecks = false;
1280 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White64dbb892017-05-03 16:00:38 -04001281 if (rightEnclosingEdge && !rightEnclosingEdge->isRightOf(v)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001282 split_edge(rightEnclosingEdge, v, &activeEdges, &v, c, alloc);
Stephen White64dbb892017-05-03 16:00:38 -04001283 restartChecks = true;
1284 continue;
1285 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001286 SkASSERT(!rightEnclosingEdge || rightEnclosingEdge->isRightOf(v));
1287 v->fLeftEnclosingEdge = leftEnclosingEdge;
1288 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001289 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001290 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Stephen White0cb31672017-06-08 14:41:01 -04001291 if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001292 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001293 restartChecks = true;
1294 break;
1295 }
Stephen White0cb31672017-06-08 14:41:01 -04001296 if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001297 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001298 restartChecks = true;
1299 break;
1300 }
1301 }
1302 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001303 if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
Stephen White0cb31672017-06-08 14:41:01 -04001304 &activeEdges, &v, mesh, c, alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001305 restartChecks = true;
1306 }
1307
1308 }
1309 } while (restartChecks);
senorblancof57372d2016-08-31 10:36:19 -07001310 if (v->fAlpha == 0) {
Stephen White48ded382017-02-03 10:15:16 -05001311 if ((leftEnclosingEdge && leftEnclosingEdge->fWinding < 0) &&
1312 (rightEnclosingEdge && rightEnclosingEdge->fWinding > 0)) {
senorblancof57372d2016-08-31 10:36:19 -07001313 v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge);
1314 }
1315 }
ethannicholase9709e82016-01-07 13:34:16 -08001316 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1317 remove_edge(e, &activeEdges);
1318 }
1319 Edge* leftEdge = leftEnclosingEdge;
1320 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1321 insert_edge(e, leftEdge, &activeEdges);
1322 leftEdge = e;
1323 }
ethannicholase9709e82016-01-07 13:34:16 -08001324 }
1325}
1326
Stephen Whitebda29c02017-03-13 15:10:13 -04001327// This is a stripped-down version of simplify() (the Bentley-Ottmann algorithm) that
1328// early-returns true on the first found intersection, false if none.
1329bool is_complex(const VertexList& vertices) {
1330 LOG("testing polygon complexity\n");
1331 EdgeList activeEdges;
1332 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
1333 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1334 continue;
1335 }
1336 Edge* leftEnclosingEdge;
1337 Edge* rightEnclosingEdge;
1338 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1339 SkPoint dummy;
1340 if (v->fFirstEdgeBelow) {
1341 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
1342 if (edge && leftEnclosingEdge && edge->intersect(*leftEnclosingEdge, &dummy)) {
1343 activeEdges.removeAll();
1344 return true;
1345 }
1346 if (edge && rightEnclosingEdge && edge->intersect(*rightEnclosingEdge, &dummy)) {
1347 activeEdges.removeAll();
1348 return true;
1349 }
1350 }
1351 } else if (leftEnclosingEdge && rightEnclosingEdge &&
1352 leftEnclosingEdge->intersect(*rightEnclosingEdge, &dummy)) {
1353 activeEdges.removeAll();
1354 return true;
1355 }
1356 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1357 remove_edge(e, &activeEdges);
1358 }
1359 Edge* leftEdge = leftEnclosingEdge;
1360 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1361 insert_edge(e, leftEdge, &activeEdges);
1362 leftEdge = e;
1363 }
1364 }
1365 activeEdges.removeAll();
1366 return false;
1367}
1368
ethannicholase9709e82016-01-07 13:34:16 -08001369// Stage 5: Tessellate the simplified mesh into monotone polygons.
1370
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001371Poly* tessellate(const VertexList& vertices, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001372 LOG("tessellating simple polygons\n");
1373 EdgeList activeEdges;
1374 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001375 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001376 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1377 continue;
1378 }
1379#if LOGGING_ENABLED
senorblancof57372d2016-08-31 10:36:19 -07001380 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001381#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001382 Edge* leftEnclosingEdge;
1383 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001384 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001385 Poly* leftPoly;
1386 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001387 if (v->fFirstEdgeAbove) {
1388 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1389 rightPoly = v->fLastEdgeAbove->fRightPoly;
1390 } else {
1391 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1392 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1393 }
1394#if LOGGING_ENABLED
1395 LOG("edges above:\n");
1396 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1397 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1398 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1399 }
1400 LOG("edges below:\n");
1401 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1402 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1403 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1404 }
1405#endif
1406 if (v->fFirstEdgeAbove) {
1407 if (leftPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001408 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001409 }
1410 if (rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001411 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001412 }
1413 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001414 Edge* rightEdge = e->fNextEdgeAbove;
Stephen White8a0bfc52017-02-21 15:24:13 -05001415 remove_edge(e, &activeEdges);
1416 if (e->fRightPoly) {
1417 e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001418 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001419 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001420 rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001421 }
1422 }
1423 remove_edge(v->fLastEdgeAbove, &activeEdges);
1424 if (!v->fFirstEdgeBelow) {
1425 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1426 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1427 rightPoly->fPartner = leftPoly;
1428 leftPoly->fPartner = rightPoly;
1429 }
1430 }
1431 }
1432 if (v->fFirstEdgeBelow) {
1433 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001434 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001435 if (leftPoly == rightPoly) {
1436 if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) {
1437 leftPoly = new_poly(&polys, leftPoly->lastVertex(),
1438 leftPoly->fWinding, alloc);
1439 leftEnclosingEdge->fRightPoly = leftPoly;
1440 } else {
1441 rightPoly = new_poly(&polys, rightPoly->lastVertex(),
1442 rightPoly->fWinding, alloc);
1443 rightEnclosingEdge->fLeftPoly = rightPoly;
1444 }
ethannicholase9709e82016-01-07 13:34:16 -08001445 }
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001446 Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -07001447 leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc);
1448 rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001449 }
1450 }
1451 Edge* leftEdge = v->fFirstEdgeBelow;
1452 leftEdge->fLeftPoly = leftPoly;
1453 insert_edge(leftEdge, leftEnclosingEdge, &activeEdges);
1454 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1455 rightEdge = rightEdge->fNextEdgeBelow) {
1456 insert_edge(rightEdge, leftEdge, &activeEdges);
1457 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1458 winding += leftEdge->fWinding;
1459 if (winding != 0) {
1460 Poly* poly = new_poly(&polys, v, winding, alloc);
1461 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1462 }
1463 leftEdge = rightEdge;
1464 }
1465 v->fLastEdgeBelow->fRightPoly = rightPoly;
1466 }
1467#if LOGGING_ENABLED
1468 LOG("\nactive edges:\n");
1469 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
1470 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1471 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1472 }
1473#endif
1474 }
1475 return polys;
1476}
1477
Stephen Whitebf6137e2017-01-04 15:43:26 -05001478void remove_non_boundary_edges(const VertexList& mesh, SkPath::FillType fillType,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001479 SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001480 LOG("removing non-boundary edges\n");
1481 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001482 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
Stephen White49789062017-02-21 10:35:49 -05001483 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1484 continue;
1485 }
1486 Edge* leftEnclosingEdge;
1487 Edge* rightEnclosingEdge;
1488 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1489 bool prevFilled = leftEnclosingEdge &&
1490 apply_fill_type(fillType, leftEnclosingEdge->fWinding);
1491 for (Edge* e = v->fFirstEdgeAbove; e;) {
1492 Edge* next = e->fNextEdgeAbove;
1493 remove_edge(e, &activeEdges);
1494 bool filled = apply_fill_type(fillType, e->fWinding);
1495 if (filled == prevFilled) {
Stephen Whitee7a364d2017-01-11 16:19:26 -05001496 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001497 }
Stephen White49789062017-02-21 10:35:49 -05001498 prevFilled = filled;
senorblancof57372d2016-08-31 10:36:19 -07001499 e = next;
1500 }
Stephen White49789062017-02-21 10:35:49 -05001501 Edge* prev = leftEnclosingEdge;
1502 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1503 if (prev) {
1504 e->fWinding += prev->fWinding;
1505 }
1506 insert_edge(e, prev, &activeEdges);
1507 prev = e;
1508 }
senorblancof57372d2016-08-31 10:36:19 -07001509 }
senorblancof57372d2016-08-31 10:36:19 -07001510}
1511
Stephen White66412122017-03-01 11:48:27 -05001512// Note: this is the normal to the edge, but not necessarily unit length.
senorblancof57372d2016-08-31 10:36:19 -07001513void get_edge_normal(const Edge* e, SkVector* normal) {
Stephen White66412122017-03-01 11:48:27 -05001514 normal->set(SkDoubleToScalar(e->fLine.fA) * e->fWinding,
1515 SkDoubleToScalar(e->fLine.fB) * e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001516}
1517
1518// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
1519// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
1520// invert on stroking.
1521
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001522void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) {
senorblancof57372d2016-08-31 10:36:19 -07001523 Edge* prevEdge = boundary->fTail;
1524 SkVector prevNormal;
1525 get_edge_normal(prevEdge, &prevNormal);
1526 for (Edge* e = boundary->fHead; e != nullptr;) {
1527 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
1528 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
1529 double dist = e->dist(prev->fPoint);
1530 SkVector normal;
1531 get_edge_normal(e, &normal);
Stephen White66412122017-03-01 11:48:27 -05001532 double denom = 0.0625f * e->fLine.magSq();
senorblancof57372d2016-08-31 10:36:19 -07001533 if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001534 Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001535 insert_edge(join, e, boundary);
1536 remove_edge(prevEdge, boundary);
1537 remove_edge(e, boundary);
1538 if (join->fLeft && join->fRight) {
1539 prevEdge = join->fLeft;
1540 e = join;
1541 } else {
1542 prevEdge = boundary->fTail;
1543 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
1544 }
1545 get_edge_normal(prevEdge, &prevNormal);
1546 } else {
1547 prevEdge = e;
1548 prevNormal = normal;
1549 e = e->fRight;
1550 }
1551 }
1552}
1553
Ben Wagnerdab48112017-02-16 22:28:02 +00001554void fix_inversions(Vertex* prev, Vertex* next, Edge* prevBisector, Edge* nextBisector,
Stephen White92eba8a2017-02-06 09:50:27 -05001555 Edge* prevEdge, Comparator& c) {
1556 if (!prev || !next) {
1557 return;
1558 }
1559 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
1560 SkPoint p;
1561 uint8_t alpha;
Ben Wagnerdab48112017-02-16 22:28:02 +00001562 if (winding != prevEdge->fWinding && prevBisector->intersect(*nextBisector, &p, &alpha)) {
Stephen White92eba8a2017-02-06 09:50:27 -05001563 prev->fPoint = next->fPoint = p;
1564 prev->fAlpha = next->fAlpha = alpha;
1565 }
1566}
1567
senorblancof57372d2016-08-31 10:36:19 -07001568// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
1569// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
1570// new antialiased mesh from those vertices.
1571
Stephen Whitebda29c02017-03-13 15:10:13 -04001572void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
1573 Comparator& c, SkArenaAlloc& alloc) {
Stephen White8a0bfc52017-02-21 15:24:13 -05001574 // A boundary with fewer than 3 edges is degenerate.
1575 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
1576 return;
1577 }
senorblancof57372d2016-08-31 10:36:19 -07001578 Edge* prevEdge = boundary->fTail;
1579 float radius = 0.5f;
senorblanco49df8d12016-10-07 08:36:56 -07001580 double offset = radius * sqrt(prevEdge->fLine.magSq()) * prevEdge->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001581 Line prevInner(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001582 prevInner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001583 Line prevOuter(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001584 prevOuter.fC += offset;
1585 VertexList innerVertices;
1586 VertexList outerVertices;
Ben Wagnerdab48112017-02-16 22:28:02 +00001587 Edge* prevBisector = nullptr;
senorblancof57372d2016-08-31 10:36:19 -07001588 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
senorblanco49df8d12016-10-07 08:36:56 -07001589 double offset = radius * sqrt(e->fLine.magSq()) * e->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001590 Line inner(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001591 inner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001592 Line outer(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001593 outer.fC += offset;
1594 SkPoint innerPoint, outerPoint;
senorblanco49df8d12016-10-07 08:36:56 -07001595 if (prevInner.intersect(inner, &innerPoint) &&
1596 prevOuter.intersect(outer, &outerPoint)) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001597 Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255);
1598 Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0);
Ben Wagnerdab48112017-02-16 22:28:02 +00001599 Edge* bisector = new_edge(outerVertex, innerVertex, Edge::Type::kConnector, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001600 fix_inversions(innerVertices.fTail, innerVertex, prevBisector, bisector, prevEdge, c);
1601 fix_inversions(outerVertices.fTail, outerVertex, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001602 innerVertex->fPartner = outerVertex;
1603 outerVertex->fPartner = innerVertex;
Stephen White92eba8a2017-02-06 09:50:27 -05001604 innerVertices.append(innerVertex);
1605 outerVertices.append(outerVertex);
1606 prevBisector = bisector;
senorblancof57372d2016-08-31 10:36:19 -07001607 }
1608 prevInner = inner;
1609 prevOuter = outer;
Stephen White86cc8412017-01-27 10:53:15 -05001610 prevEdge = e;
senorblancof57372d2016-08-31 10:36:19 -07001611 }
senorblancof57372d2016-08-31 10:36:19 -07001612
1613 Vertex* innerVertex = innerVertices.fHead;
1614 Vertex* outerVertex = outerVertices.fHead;
senorblancof57372d2016-08-31 10:36:19 -07001615 if (!innerVertex || !outerVertex) {
1616 return;
1617 }
Ben Wagnerdab48112017-02-16 22:28:02 +00001618 Edge* bisector = new_edge(outerVertices.fHead, innerVertices.fHead, Edge::Type::kConnector, c,
1619 alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001620 fix_inversions(innerVertices.fTail, innerVertices.fHead, prevBisector, bisector, prevEdge, c);
1621 fix_inversions(outerVertices.fTail, outerVertices.fHead, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001622 Vertex* prevInnerVertex = innerVertices.fTail;
1623 Vertex* prevOuterVertex = outerVertices.fTail;
1624 while (innerVertex && outerVertex) {
Stephen White48ded382017-02-03 10:15:16 -05001625 // Connect vertices into a quad mesh. Outer edges get default (1) winding.
1626 // Inner edges get -2 winding. This ensures that the interior is always filled
1627 // (-1 winding number for normal cases, 3 for thin features where the interior inverts).
Stephen Whitebda29c02017-03-13 15:10:13 -04001628 connect(prevOuterVertex, outerVertex, Edge::Type::kOuter, c, alloc);
1629 connect(prevInnerVertex, innerVertex, Edge::Type::kInner, c, alloc, -2);
1630 prevInnerVertex = innerVertex;
1631 prevOuterVertex = outerVertex;
1632 innerVertex = innerVertex->fNext;
1633 outerVertex = outerVertex->fNext;
1634 }
1635 innerMesh->append(innerVertices);
1636 outerMesh->append(outerVertices);
senorblancof57372d2016-08-31 10:36:19 -07001637}
1638
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001639void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001640 bool down = apply_fill_type(fillType, e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001641 while (e) {
1642 e->fWinding = down ? 1 : -1;
1643 Edge* next;
1644 boundary->append(e);
1645 if (down) {
1646 // Find outgoing edge, in clockwise order.
1647 if ((next = e->fNextEdgeAbove)) {
1648 down = false;
1649 } else if ((next = e->fBottom->fLastEdgeBelow)) {
1650 down = true;
1651 } else if ((next = e->fPrevEdgeAbove)) {
1652 down = false;
1653 }
1654 } else {
1655 // Find outgoing edge, in counter-clockwise order.
1656 if ((next = e->fPrevEdgeBelow)) {
1657 down = true;
1658 } else if ((next = e->fTop->fFirstEdgeAbove)) {
1659 down = false;
1660 } else if ((next = e->fNextEdgeBelow)) {
1661 down = true;
1662 }
1663 }
Stephen Whitee7a364d2017-01-11 16:19:26 -05001664 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001665 e = next;
1666 }
1667}
1668
Stephen White5ad721e2017-02-23 16:50:47 -05001669// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
senorblancof57372d2016-08-31 10:36:19 -07001670
Stephen Whitebda29c02017-03-13 15:10:13 -04001671void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices,
1672 VertexList* outerVertices, SkPath::FillType fillType,
Stephen White5ad721e2017-02-23 16:50:47 -05001673 Comparator& c, SkArenaAlloc& alloc) {
1674 remove_non_boundary_edges(inMesh, fillType, alloc);
1675 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001676 while (v->fFirstEdgeBelow) {
Stephen White5ad721e2017-02-23 16:50:47 -05001677 EdgeList boundary;
1678 extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc);
1679 simplify_boundary(&boundary, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001680 stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001681 }
1682 }
senorblancof57372d2016-08-31 10:36:19 -07001683}
1684
Stephen Whitebda29c02017-03-13 15:10:13 -04001685// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001686
Stephen White3a9aab92017-03-07 14:07:18 -05001687void contours_to_mesh(VertexList* contours, int contourCnt, bool antialias,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001688 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001689#if LOGGING_ENABLED
1690 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001691 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001692 SkASSERT(v);
1693 LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001694 for (v = v->fNext; v; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001695 LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1696 }
1697 }
1698#endif
senorblancof57372d2016-08-31 10:36:19 -07001699 sanitize_contours(contours, contourCnt, antialias);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001700 build_edges(contours, contourCnt, mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001701}
1702
Stephen Whitebda29c02017-03-13 15:10:13 -04001703void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001704 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001705 return;
ethannicholase9709e82016-01-07 13:34:16 -08001706 }
1707
1708 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001709 if (c.fDirection == Comparator::Direction::kHorizontal) {
1710 merge_sort<sweep_lt_horiz>(vertices);
1711 } else {
1712 merge_sort<sweep_lt_vert>(vertices);
1713 }
ethannicholase9709e82016-01-07 13:34:16 -08001714#if LOGGING_ENABLED
Stephen White2e2cb9b2017-01-09 13:11:18 -05001715 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001716 static float gID = 0.0f;
1717 v->fID = gID++;
1718 }
1719#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001720}
1721
Stephen White3a9aab92017-03-07 14:07:18 -05001722Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPath::FillType fillType,
Stephen Whitebda29c02017-03-13 15:10:13 -04001723 const SkRect& pathBounds, bool antialias, VertexList* outerMesh,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001724 SkArenaAlloc& alloc) {
Stephen White16a40cb2017-02-23 11:10:01 -05001725 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1726 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001727 VertexList mesh;
1728 contours_to_mesh(contours, contourCnt, antialias, &mesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001729 sort_mesh(&mesh, c, alloc);
1730 merge_coincident_vertices(&mesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04001731 simplify(&mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001732 if (antialias) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001733 VertexList innerMesh;
1734 extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc);
1735 sort_mesh(&innerMesh, c, alloc);
1736 sort_mesh(outerMesh, c, alloc);
1737 if (is_complex(innerMesh) || is_complex(*outerMesh)) {
1738 LOG("found complex mesh; taking slow path\n");
1739 VertexList aaMesh;
1740 connect_partners(outerMesh, c, alloc);
1741 sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
1742 merge_coincident_vertices(&aaMesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04001743 simplify(&aaMesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001744 outerMesh->fHead = outerMesh->fTail = nullptr;
1745 return tessellate(aaMesh, alloc);
1746 } else {
1747 LOG("no complex polygons; taking fast path\n");
1748 merge_coincident_vertices(&innerMesh, c, alloc);
1749 return tessellate(innerMesh, alloc);
1750 }
Stephen White49789062017-02-21 10:35:49 -05001751 } else {
1752 return tessellate(mesh, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001753 }
senorblancof57372d2016-08-31 10:36:19 -07001754}
1755
1756// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1757void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* aaParams,
1758 void* data) {
1759 for (Poly* poly = polys; poly; poly = poly->fNext) {
1760 if (apply_fill_type(fillType, poly)) {
1761 data = poly->emit(aaParams, data);
1762 }
1763 }
1764 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001765}
1766
halcanary9d524f22016-03-29 09:03:52 -07001767Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen Whitebda29c02017-03-13 15:10:13 -04001768 int contourCnt, SkArenaAlloc& alloc, bool antialias, bool* isLinear,
1769 VertexList* outerMesh) {
ethannicholase9709e82016-01-07 13:34:16 -08001770 SkPath::FillType fillType = path.getFillType();
1771 if (SkPath::IsInverseFillType(fillType)) {
1772 contourCnt++;
1773 }
Stephen White3a9aab92017-03-07 14:07:18 -05001774 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08001775
1776 path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear);
senorblancof57372d2016-08-31 10:36:19 -07001777 return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(),
Stephen Whitebda29c02017-03-13 15:10:13 -04001778 antialias, outerMesh, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001779}
1780
Stephen White11f65e02017-02-16 19:00:39 -05001781int get_contour_count(const SkPath& path, SkScalar tolerance) {
1782 int contourCnt;
1783 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001784 if (maxPts <= 0) {
Stephen White11f65e02017-02-16 19:00:39 -05001785 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001786 }
1787 if (maxPts > ((int)SK_MaxU16 + 1)) {
1788 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
Stephen White11f65e02017-02-16 19:00:39 -05001789 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001790 }
Stephen White11f65e02017-02-16 19:00:39 -05001791 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001792}
1793
1794int count_points(Poly* polys, SkPath::FillType fillType) {
1795 int count = 0;
1796 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001797 if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
ethannicholase9709e82016-01-07 13:34:16 -08001798 count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3);
1799 }
1800 }
1801 return count;
1802}
1803
Stephen Whitebda29c02017-03-13 15:10:13 -04001804int count_outer_mesh_points(const VertexList& outerMesh) {
1805 int count = 0;
1806 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1807 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1808 count += TESSELLATOR_WIREFRAME ? 12 : 6;
1809 }
1810 }
1811 return count;
1812}
1813
1814void* outer_mesh_to_triangles(const VertexList& outerMesh, const AAParams* aaParams, void* data) {
1815 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1816 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1817 Vertex* v0 = e->fTop;
1818 Vertex* v1 = e->fBottom;
1819 Vertex* v2 = e->fBottom->fPartner;
1820 Vertex* v3 = e->fTop->fPartner;
1821 data = emit_triangle(v0, v1, v2, aaParams, data);
1822 data = emit_triangle(v0, v2, v3, aaParams, data);
1823 }
1824 }
1825 return data;
1826}
1827
ethannicholase9709e82016-01-07 13:34:16 -08001828} // namespace
1829
1830namespace GrTessellator {
1831
1832// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1833
halcanary9d524f22016-03-29 09:03:52 -07001834int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
senorblancof57372d2016-08-31 10:36:19 -07001835 VertexAllocator* vertexAllocator, bool antialias, const GrColor& color,
1836 bool canTweakAlphaForCoverage, bool* isLinear) {
Stephen White11f65e02017-02-16 19:00:39 -05001837 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001838 if (contourCnt <= 0) {
1839 *isLinear = true;
1840 return 0;
1841 }
Stephen White11f65e02017-02-16 19:00:39 -05001842 SkArenaAlloc alloc(kArenaChunkSize);
Stephen Whitebda29c02017-03-13 15:10:13 -04001843 VertexList outerMesh;
senorblancof57372d2016-08-31 10:36:19 -07001844 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias,
Stephen Whitebda29c02017-03-13 15:10:13 -04001845 isLinear, &outerMesh);
senorblanco7ab96e92016-10-12 06:47:44 -07001846 SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType();
ethannicholase9709e82016-01-07 13:34:16 -08001847 int count = count_points(polys, fillType);
Stephen Whitebda29c02017-03-13 15:10:13 -04001848 if (antialias) {
1849 count += count_outer_mesh_points(outerMesh);
1850 }
Stephen Whiteff60b172017-05-05 15:54:52 -04001851 if (0 == count) {
1852 return 0;
1853 }
ethannicholase9709e82016-01-07 13:34:16 -08001854
senorblancof57372d2016-08-31 10:36:19 -07001855 void* verts = vertexAllocator->lock(count);
senorblanco6599eff2016-03-10 08:38:45 -08001856 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001857 SkDebugf("Could not allocate vertices\n");
1858 return 0;
1859 }
senorblancof57372d2016-08-31 10:36:19 -07001860
1861 LOG("emitting %d verts\n", count);
1862 AAParams aaParams;
1863 aaParams.fTweakAlpha = canTweakAlphaForCoverage;
1864 aaParams.fColor = color;
1865
1866 void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts);
Stephen Whitebda29c02017-03-13 15:10:13 -04001867 end = outer_mesh_to_triangles(outerMesh, &aaParams, end);
senorblancof57372d2016-08-31 10:36:19 -07001868 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
1869 / vertexAllocator->stride());
ethannicholase9709e82016-01-07 13:34:16 -08001870 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001871 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001872 return actualCount;
1873}
1874
halcanary9d524f22016-03-29 09:03:52 -07001875int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
ethannicholase9709e82016-01-07 13:34:16 -08001876 GrTessellator::WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05001877 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001878 if (contourCnt <= 0) {
1879 return 0;
1880 }
Stephen White11f65e02017-02-16 19:00:39 -05001881 SkArenaAlloc alloc(kArenaChunkSize);
ethannicholase9709e82016-01-07 13:34:16 -08001882 bool isLinear;
Stephen Whitebda29c02017-03-13 15:10:13 -04001883 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear,
1884 nullptr);
ethannicholase9709e82016-01-07 13:34:16 -08001885 SkPath::FillType fillType = path.getFillType();
1886 int count = count_points(polys, fillType);
1887 if (0 == count) {
1888 *verts = nullptr;
1889 return 0;
1890 }
1891
1892 *verts = new GrTessellator::WindingVertex[count];
1893 GrTessellator::WindingVertex* vertsEnd = *verts;
1894 SkPoint* points = new SkPoint[count];
1895 SkPoint* pointsEnd = points;
1896 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001897 if (apply_fill_type(fillType, poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001898 SkPoint* start = pointsEnd;
senorblancof57372d2016-08-31 10:36:19 -07001899 pointsEnd = static_cast<SkPoint*>(poly->emit(nullptr, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001900 while (start != pointsEnd) {
1901 vertsEnd->fPos = *start;
1902 vertsEnd->fWinding = poly->fWinding;
1903 ++start;
1904 ++vertsEnd;
1905 }
1906 }
1907 }
1908 int actualCount = static_cast<int>(vertsEnd - *verts);
1909 SkASSERT(actualCount <= count);
1910 SkASSERT(pointsEnd - points == actualCount);
1911 delete[] points;
1912 return actualCount;
1913}
1914
1915} // namespace