blob: a183439634d171a127f15a24585f490baac8e139 [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"
Cary Clarkdf429f32017-11-08 11:44:31 -050016#include "SkPointPriv.h"
ethannicholase9709e82016-01-07 13:34:16 -080017
18#include <stdio.h>
19
20/*
senorblancof57372d2016-08-31 10:36:19 -070021 * There are six stages to the basic algorithm:
ethannicholase9709e82016-01-07 13:34:16 -080022 *
23 * 1) Linearize the path contours into piecewise linear segments (path_to_contours()).
24 * 2) Build a mesh of edges connecting the vertices (build_edges()).
25 * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()).
26 * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()).
27 * 5) Tessellate the simplified mesh into monotone polygons (tessellate()).
28 * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()).
29 *
senorblancof57372d2016-08-31 10:36:19 -070030 * For screenspace antialiasing, the algorithm is modified as follows:
31 *
32 * Run steps 1-5 above to produce polygons.
33 * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()).
Stephen Whitebda29c02017-03-13 15:10:13 -040034 * 5c) Simplify boundaries to remove "pointy" vertices that cause inversions (simplify_boundary()).
senorblancof57372d2016-08-31 10:36:19 -070035 * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find
36 * 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 -040037 * antialiased mesh from those vertices (stroke_boundary()).
senorblancof57372d2016-08-31 10:36:19 -070038 * Run steps 3-6 above on the new mesh, and produce antialiased triangles.
39 *
ethannicholase9709e82016-01-07 13:34:16 -080040 * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
41 * of vertices (and the necessity of inserting new vertices on intersection).
42 *
Stephen Whitebda29c02017-03-13 15:10:13 -040043 * Stages (4) and (5) use an active edge list -- a list of all edges for which the
ethannicholase9709e82016-01-07 13:34:16 -080044 * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted
45 * left-to-right based on the point where both edges are active (when both top vertices
46 * have been seen, so the "lower" top vertex of the two). If the top vertices are equal
47 * (shared), it's sorted based on the last point where both edges are active, so the
48 * "upper" bottom vertex.
49 *
50 * The most complex step is the simplification (4). It's based on the Bentley-Ottman
51 * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
52 * not exact and may violate the mesh topology or active edge list ordering. We
53 * accommodate this by adjusting the topology of the mesh and AEL to match the intersection
Stephen White3b5a3fa2017-06-06 14:51:19 -040054 * points. This occurs in two ways:
ethannicholase9709e82016-01-07 13:34:16 -080055 *
56 * A) Intersections may cause a shortened edge to no longer be ordered with respect to its
57 * neighbouring edges at the top or bottom vertex. This is handled by merging the
58 * edges (merge_collinear_edges()).
59 * B) Intersections may cause an edge to violate the left-to-right ordering of the
Stephen White019f6c02017-06-09 10:06:26 -040060 * active edge list. This is handled by detecting potential violations and rewinding
Stephen White3b5a3fa2017-06-06 14:51:19 -040061 * the active edge list to the vertex before they occur (rewind() during merging,
62 * rewind_if_necessary() during splitting).
ethannicholase9709e82016-01-07 13:34:16 -080063 *
64 * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
65 * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
66 * currently uses a linked list for the active edge list, rather than a 2-3 tree as the
67 * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
68 * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
69 * insertions and removals was greater than the cost of infrequent O(N) lookups with the
70 * linked list implementation. With the latter, all removals are O(1), and most insertions
71 * are O(1), since we know the adjacent edge in the active edge list based on the topology.
72 * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
73 * frequent. There may be other data structures worth investigating, however.
74 *
75 * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the
76 * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y
77 * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall,
78 * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so
79 * that the "left" and "right" orientation in the code remains correct (edges to the left are
80 * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90
81 * degrees counterclockwise, rather that transposing.
82 */
83
84#define LOGGING_ENABLED 0
85
86#if LOGGING_ENABLED
87#define LOG printf
88#else
89#define LOG(...)
90#endif
91
ethannicholase9709e82016-01-07 13:34:16 -080092namespace {
93
Stephen White11f65e02017-02-16 19:00:39 -050094const int kArenaChunkSize = 16 * 1024;
95
ethannicholase9709e82016-01-07 13:34:16 -080096struct Vertex;
97struct Edge;
98struct Poly;
99
100template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800101void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800102 t->*Prev = prev;
103 t->*Next = next;
104 if (prev) {
105 prev->*Next = t;
106 } else if (head) {
107 *head = t;
108 }
109 if (next) {
110 next->*Prev = t;
111 } else if (tail) {
112 *tail = t;
113 }
114}
115
116template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800117void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800118 if (t->*Prev) {
119 t->*Prev->*Next = t->*Next;
120 } else if (head) {
121 *head = t->*Next;
122 }
123 if (t->*Next) {
124 t->*Next->*Prev = t->*Prev;
125 } else if (tail) {
126 *tail = t->*Prev;
127 }
128 t->*Prev = t->*Next = nullptr;
129}
130
131/**
132 * Vertices are used in three ways: first, the path contours are converted into a
133 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
134 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
135 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
136 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
137 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
138 * an individual Vertex from the path mesh may belong to multiple
139 * MonotonePolys, so the original Vertices cannot be re-used.
140 */
141
142struct Vertex {
senorblancof57372d2016-08-31 10:36:19 -0700143 Vertex(const SkPoint& point, uint8_t alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800144 : fPoint(point), fPrev(nullptr), fNext(nullptr)
145 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
146 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
Stephen White3b5a3fa2017-06-06 14:51:19 -0400147 , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
Stephen Whitebda29c02017-03-13 15:10:13 -0400148 , fPartner(nullptr)
senorblancof57372d2016-08-31 10:36:19 -0700149 , fAlpha(alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800150#if LOGGING_ENABLED
151 , fID (-1.0f)
152#endif
153 {}
Stephen White3b5a3fa2017-06-06 14:51:19 -0400154 SkPoint fPoint; // Vertex position
155 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
156 Vertex* fNext; // "
157 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
158 Edge* fLastEdgeAbove; // "
159 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
160 Edge* fLastEdgeBelow; // "
161 Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
162 Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
163 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
senorblancof57372d2016-08-31 10:36:19 -0700164 uint8_t fAlpha;
ethannicholase9709e82016-01-07 13:34:16 -0800165#if LOGGING_ENABLED
Stephen White3b5a3fa2017-06-06 14:51:19 -0400166 float fID; // Identifier used for logging.
ethannicholase9709e82016-01-07 13:34:16 -0800167#endif
168};
169
170/***************************************************************************************/
171
senorblancof57372d2016-08-31 10:36:19 -0700172struct AAParams {
173 bool fTweakAlpha;
174 GrColor fColor;
175};
176
ethannicholase9709e82016-01-07 13:34:16 -0800177typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
178
ethannicholase9709e82016-01-07 13:34:16 -0800179bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500180 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -0800181}
182
183bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500184 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -0800185}
186
Stephen White16a40cb2017-02-23 11:10:01 -0500187struct Comparator {
188 enum class Direction { kVertical, kHorizontal };
189 Comparator(Direction direction) : fDirection(direction) {}
190 bool sweep_lt(const SkPoint& a, const SkPoint& b) const {
191 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
192 }
Stephen White16a40cb2017-02-23 11:10:01 -0500193 Direction fDirection;
194};
195
senorblancof57372d2016-08-31 10:36:19 -0700196inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) {
197 if (!aaParams) {
198 SkPoint* d = static_cast<SkPoint*>(data);
199 *d++ = v->fPoint;
200 return d;
201 }
202 if (aaParams->fTweakAlpha) {
203 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorAttr*>(data);
204 d->fPosition = v->fPoint;
lsalzman8c8fcef2016-10-11 12:20:17 -0700205 d->fColor = SkAlphaMulQ(aaParams->fColor, SkAlpha255To256(v->fAlpha));
senorblancof57372d2016-08-31 10:36:19 -0700206 d++;
207 return d;
208 }
209 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorCoverageAttr*>(data);
210 d->fPosition = v->fPoint;
211 d->fColor = aaParams->fColor;
212 d->fCoverage = GrNormalizeByteToFloat(v->fAlpha);
213 d++;
214 return d;
ethannicholase9709e82016-01-07 13:34:16 -0800215}
216
senorblancof57372d2016-08-31 10:36:19 -0700217void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams, void* data) {
Stephen White92eba8a2017-02-06 09:50:27 -0500218 LOG("emit_triangle (%g, %g) %d\n", v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
219 LOG(" (%g, %g) %d\n", v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
220 LOG(" (%g, %g) %d\n", v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -0700221#if TESSELLATOR_WIREFRAME
222 data = emit_vertex(v0, aaParams, data);
223 data = emit_vertex(v1, aaParams, data);
224 data = emit_vertex(v1, aaParams, data);
225 data = emit_vertex(v2, aaParams, data);
226 data = emit_vertex(v2, aaParams, data);
227 data = emit_vertex(v0, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800228#else
senorblancof57372d2016-08-31 10:36:19 -0700229 data = emit_vertex(v0, aaParams, data);
230 data = emit_vertex(v1, aaParams, data);
231 data = emit_vertex(v2, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800232#endif
233 return data;
234}
235
senorblancoe6eaa322016-03-08 09:06:44 -0800236struct VertexList {
237 VertexList() : fHead(nullptr), fTail(nullptr) {}
Stephen White16a40cb2017-02-23 11:10:01 -0500238 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {}
senorblancoe6eaa322016-03-08 09:06:44 -0800239 Vertex* fHead;
240 Vertex* fTail;
241 void insert(Vertex* v, Vertex* prev, Vertex* next) {
242 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
243 }
244 void append(Vertex* v) {
245 insert(v, fTail, nullptr);
246 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400247 void append(const VertexList& list) {
248 if (!list.fHead) {
249 return;
250 }
251 if (fTail) {
252 fTail->fNext = list.fHead;
253 list.fHead->fPrev = fTail;
254 } else {
255 fHead = list.fHead;
256 }
257 fTail = list.fTail;
258 }
senorblancoe6eaa322016-03-08 09:06:44 -0800259 void prepend(Vertex* v) {
260 insert(v, nullptr, fHead);
261 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500262 void remove(Vertex* v) {
263 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
264 }
senorblancof57372d2016-08-31 10:36:19 -0700265 void close() {
266 if (fHead && fTail) {
267 fTail->fNext = fHead;
268 fHead->fPrev = fTail;
269 }
270 }
senorblancoe6eaa322016-03-08 09:06:44 -0800271};
272
senorblancof57372d2016-08-31 10:36:19 -0700273// Round to nearest quarter-pixel. This is used for screenspace tessellation.
274
275inline void round(SkPoint* p) {
276 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
277 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
278}
279
senorblanco49df8d12016-10-07 08:36:56 -0700280// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
281struct Line {
282 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
283 Line(const SkPoint& p, const SkPoint& q)
284 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
285 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
286 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
287 static_cast<double>(p.fX) * q.fY) {}
288 double dist(const SkPoint& p) const {
289 return fA * p.fX + fB * p.fY + fC;
290 }
291 double magSq() const {
292 return fA * fA + fB * fB;
293 }
294
295 // Compute the intersection of two (infinite) Lines.
296 bool intersect(const Line& other, SkPoint* point) {
297 double denom = fA * other.fB - fB * other.fA;
298 if (denom == 0.0) {
299 return false;
300 }
301 double scale = 1.0f / denom;
302 point->fX = SkDoubleToScalar((fB * other.fC - other.fB * fC) * scale);
303 point->fY = SkDoubleToScalar((other.fA * fC - fA * other.fC) * scale);
Stephen Whiteb56dedf2017-03-02 10:35:56 -0500304 round(point);
senorblanco49df8d12016-10-07 08:36:56 -0700305 return true;
306 }
307 double fA, fB, fC;
308};
309
ethannicholase9709e82016-01-07 13:34:16 -0800310/**
311 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
312 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
313 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
Stephen Whitebda29c02017-03-13 15:10:13 -0400314 * point). For speed, that case is only tested by the callers that require it (e.g.,
Stephen White3b5a3fa2017-06-06 14:51:19 -0400315 * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
ethannicholase9709e82016-01-07 13:34:16 -0800316 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
317 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
318 * a lot faster in the "not found" case.
319 *
320 * The coefficients of the line equation stored in double precision to avoid catastrphic
321 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
322 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
323 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
324 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
325 * this file).
326 */
327
328struct Edge {
Stephen White2f4686f2017-01-03 16:20:01 -0500329 enum class Type { kInner, kOuter, kConnector };
330 Edge(Vertex* top, Vertex* bottom, int winding, Type type)
ethannicholase9709e82016-01-07 13:34:16 -0800331 : fWinding(winding)
332 , fTop(top)
333 , fBottom(bottom)
Stephen White2f4686f2017-01-03 16:20:01 -0500334 , fType(type)
ethannicholase9709e82016-01-07 13:34:16 -0800335 , fLeft(nullptr)
336 , fRight(nullptr)
337 , fPrevEdgeAbove(nullptr)
338 , fNextEdgeAbove(nullptr)
339 , fPrevEdgeBelow(nullptr)
340 , fNextEdgeBelow(nullptr)
341 , fLeftPoly(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700342 , fRightPoly(nullptr)
343 , fLeftPolyPrev(nullptr)
344 , fLeftPolyNext(nullptr)
345 , fRightPolyPrev(nullptr)
senorblanco70f52512016-08-17 14:56:22 -0700346 , fRightPolyNext(nullptr)
347 , fUsedInLeftPoly(false)
senorblanco49df8d12016-10-07 08:36:56 -0700348 , fUsedInRightPoly(false)
349 , fLine(top, bottom) {
ethannicholase9709e82016-01-07 13:34:16 -0800350 }
351 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
352 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
353 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
Stephen White2f4686f2017-01-03 16:20:01 -0500354 Type fType;
ethannicholase9709e82016-01-07 13:34:16 -0800355 Edge* fLeft; // The linked list of edges in the active edge list.
356 Edge* fRight; // "
357 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
358 Edge* fNextEdgeAbove; // "
359 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
360 Edge* fNextEdgeBelow; // "
361 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
362 Poly* fRightPoly; // The Poly to the right of this edge, if any.
senorblanco531237e2016-06-02 11:36:48 -0700363 Edge* fLeftPolyPrev;
364 Edge* fLeftPolyNext;
365 Edge* fRightPolyPrev;
366 Edge* fRightPolyNext;
senorblanco70f52512016-08-17 14:56:22 -0700367 bool fUsedInLeftPoly;
368 bool fUsedInRightPoly;
senorblanco49df8d12016-10-07 08:36:56 -0700369 Line fLine;
ethannicholase9709e82016-01-07 13:34:16 -0800370 double dist(const SkPoint& p) const {
senorblanco49df8d12016-10-07 08:36:56 -0700371 return fLine.dist(p);
ethannicholase9709e82016-01-07 13:34:16 -0800372 }
373 bool isRightOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700374 return fLine.dist(v->fPoint) < 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800375 }
376 bool isLeftOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700377 return fLine.dist(v->fPoint) > 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800378 }
379 void recompute() {
senorblanco49df8d12016-10-07 08:36:56 -0700380 fLine = Line(fTop, fBottom);
ethannicholase9709e82016-01-07 13:34:16 -0800381 }
Ben Wagnerdab48112017-02-16 22:28:02 +0000382 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) {
ethannicholase9709e82016-01-07 13:34:16 -0800383 LOG("intersecting %g -> %g with %g -> %g\n",
384 fTop->fID, fBottom->fID,
385 other.fTop->fID, other.fBottom->fID);
386 if (fTop == other.fTop || fBottom == other.fBottom) {
387 return false;
388 }
senorblanco49df8d12016-10-07 08:36:56 -0700389 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800390 if (denom == 0.0) {
391 return false;
392 }
Stephen White8a0bfc52017-02-21 15:24:13 -0500393 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
394 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
395 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
396 double tNumer = dy * fLine.fB + dx * fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800397 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
398 // This saves us doing the divide below unless absolutely necessary.
399 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
400 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
401 return false;
402 }
403 double s = sNumer / denom;
404 SkASSERT(s >= 0.0 && s <= 1.0);
senorblanco49df8d12016-10-07 08:36:56 -0700405 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
406 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
Stephen White56158ae2017-01-30 14:31:31 -0500407 if (alpha) {
Stephen White92eba8a2017-02-06 09:50:27 -0500408 if (fType == Type::kConnector) {
409 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
410 } else if (other.fType == Type::kConnector) {
411 double t = tNumer / denom;
412 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
Stephen White56158ae2017-01-30 14:31:31 -0500413 } else if (fType == Type::kOuter && other.fType == Type::kOuter) {
414 *alpha = 0;
415 } else {
Stephen White92eba8a2017-02-06 09:50:27 -0500416 *alpha = 255;
Stephen White56158ae2017-01-30 14:31:31 -0500417 }
418 }
ethannicholase9709e82016-01-07 13:34:16 -0800419 return true;
420 }
senorblancof57372d2016-08-31 10:36:19 -0700421};
422
423struct EdgeList {
Stephen White5ad721e2017-02-23 16:50:47 -0500424 EdgeList() : fHead(nullptr), fTail(nullptr) {}
senorblancof57372d2016-08-31 10:36:19 -0700425 Edge* fHead;
426 Edge* fTail;
senorblancof57372d2016-08-31 10:36:19 -0700427 void insert(Edge* edge, Edge* prev, Edge* next) {
428 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700429 }
430 void append(Edge* e) {
431 insert(e, fTail, nullptr);
432 }
433 void remove(Edge* edge) {
434 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700435 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400436 void removeAll() {
437 while (fHead) {
438 this->remove(fHead);
439 }
440 }
senorblancof57372d2016-08-31 10:36:19 -0700441 void close() {
442 if (fHead && fTail) {
443 fTail->fRight = fHead;
444 fHead->fLeft = fTail;
445 }
446 }
447 bool contains(Edge* edge) const {
448 return edge->fLeft || edge->fRight || fHead == edge;
ethannicholase9709e82016-01-07 13:34:16 -0800449 }
450};
451
452/***************************************************************************************/
453
454struct Poly {
senorblanco531237e2016-06-02 11:36:48 -0700455 Poly(Vertex* v, int winding)
456 : fFirstVertex(v)
457 , fWinding(winding)
ethannicholase9709e82016-01-07 13:34:16 -0800458 , fHead(nullptr)
459 , fTail(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800460 , fNext(nullptr)
461 , fPartner(nullptr)
462 , fCount(0)
463 {
464#if LOGGING_ENABLED
465 static int gID = 0;
466 fID = gID++;
467 LOG("*** created Poly %d\n", fID);
468#endif
469 }
senorblanco531237e2016-06-02 11:36:48 -0700470 typedef enum { kLeft_Side, kRight_Side } Side;
ethannicholase9709e82016-01-07 13:34:16 -0800471 struct MonotonePoly {
senorblanco531237e2016-06-02 11:36:48 -0700472 MonotonePoly(Edge* edge, Side side)
473 : fSide(side)
474 , fFirstEdge(nullptr)
475 , fLastEdge(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800476 , fPrev(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700477 , fNext(nullptr) {
478 this->addEdge(edge);
479 }
ethannicholase9709e82016-01-07 13:34:16 -0800480 Side fSide;
senorblanco531237e2016-06-02 11:36:48 -0700481 Edge* fFirstEdge;
482 Edge* fLastEdge;
ethannicholase9709e82016-01-07 13:34:16 -0800483 MonotonePoly* fPrev;
484 MonotonePoly* fNext;
senorblanco531237e2016-06-02 11:36:48 -0700485 void addEdge(Edge* edge) {
senorblancoe6eaa322016-03-08 09:06:44 -0800486 if (fSide == kRight_Side) {
senorblanco212c7c32016-08-18 10:20:47 -0700487 SkASSERT(!edge->fUsedInRightPoly);
senorblanco531237e2016-06-02 11:36:48 -0700488 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
489 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700490 edge->fUsedInRightPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800491 } else {
senorblanco212c7c32016-08-18 10:20:47 -0700492 SkASSERT(!edge->fUsedInLeftPoly);
senorblanco531237e2016-06-02 11:36:48 -0700493 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
494 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700495 edge->fUsedInLeftPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800496 }
ethannicholase9709e82016-01-07 13:34:16 -0800497 }
498
senorblancof57372d2016-08-31 10:36:19 -0700499 void* emit(const AAParams* aaParams, void* data) {
senorblanco531237e2016-06-02 11:36:48 -0700500 Edge* e = fFirstEdge;
senorblanco531237e2016-06-02 11:36:48 -0700501 VertexList vertices;
502 vertices.append(e->fTop);
Stephen White651cbe92017-03-03 12:24:16 -0500503 int count = 1;
senorblanco531237e2016-06-02 11:36:48 -0700504 while (e != nullptr) {
senorblanco531237e2016-06-02 11:36:48 -0700505 if (kRight_Side == fSide) {
506 vertices.append(e->fBottom);
507 e = e->fRightPolyNext;
508 } else {
509 vertices.prepend(e->fBottom);
510 e = e->fLeftPolyNext;
511 }
Stephen White651cbe92017-03-03 12:24:16 -0500512 count++;
senorblanco531237e2016-06-02 11:36:48 -0700513 }
514 Vertex* first = vertices.fHead;
ethannicholase9709e82016-01-07 13:34:16 -0800515 Vertex* v = first->fNext;
senorblanco531237e2016-06-02 11:36:48 -0700516 while (v != vertices.fTail) {
ethannicholase9709e82016-01-07 13:34:16 -0800517 SkASSERT(v && v->fPrev && v->fNext);
518 Vertex* prev = v->fPrev;
519 Vertex* curr = v;
520 Vertex* next = v->fNext;
Stephen White651cbe92017-03-03 12:24:16 -0500521 if (count == 3) {
522 return emit_triangle(prev, curr, next, aaParams, data);
523 }
ethannicholase9709e82016-01-07 13:34:16 -0800524 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
525 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
526 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
527 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
528 if (ax * by - ay * bx >= 0.0) {
senorblancof57372d2016-08-31 10:36:19 -0700529 data = emit_triangle(prev, curr, next, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800530 v->fPrev->fNext = v->fNext;
531 v->fNext->fPrev = v->fPrev;
Stephen White651cbe92017-03-03 12:24:16 -0500532 count--;
ethannicholase9709e82016-01-07 13:34:16 -0800533 if (v->fPrev == first) {
534 v = v->fNext;
535 } else {
536 v = v->fPrev;
537 }
538 } else {
539 v = v->fNext;
540 }
541 }
542 return data;
543 }
544 };
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500545 Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
senorblanco70f52512016-08-17 14:56:22 -0700546 LOG("addEdge (%g -> %g) to poly %d, %s side\n",
547 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
ethannicholase9709e82016-01-07 13:34:16 -0800548 Poly* partner = fPartner;
549 Poly* poly = this;
senorblanco212c7c32016-08-18 10:20:47 -0700550 if (side == kRight_Side) {
551 if (e->fUsedInRightPoly) {
552 return this;
553 }
554 } else {
555 if (e->fUsedInLeftPoly) {
556 return this;
557 }
558 }
ethannicholase9709e82016-01-07 13:34:16 -0800559 if (partner) {
560 fPartner = partner->fPartner = nullptr;
561 }
senorblanco531237e2016-06-02 11:36:48 -0700562 if (!fTail) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500563 fHead = fTail = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700564 fCount += 2;
senorblanco93e3fff2016-06-07 12:36:00 -0700565 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
566 return poly;
senorblanco531237e2016-06-02 11:36:48 -0700567 } else if (side == fTail->fSide) {
568 fTail->addEdge(e);
569 fCount++;
570 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500571 e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -0700572 fTail->addEdge(e);
573 fCount++;
ethannicholase9709e82016-01-07 13:34:16 -0800574 if (partner) {
senorblanco531237e2016-06-02 11:36:48 -0700575 partner->addEdge(e, side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800576 poly = partner;
577 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500578 MonotonePoly* m = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700579 m->fPrev = fTail;
580 fTail->fNext = m;
581 fTail = m;
ethannicholase9709e82016-01-07 13:34:16 -0800582 }
583 }
ethannicholase9709e82016-01-07 13:34:16 -0800584 return poly;
585 }
senorblancof57372d2016-08-31 10:36:19 -0700586 void* emit(const AAParams* aaParams, void *data) {
ethannicholase9709e82016-01-07 13:34:16 -0800587 if (fCount < 3) {
588 return data;
589 }
590 LOG("emit() %d, size %d\n", fID, fCount);
591 for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) {
senorblancof57372d2016-08-31 10:36:19 -0700592 data = m->emit(aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800593 }
594 return data;
595 }
senorblanco531237e2016-06-02 11:36:48 -0700596 Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; }
597 Vertex* fFirstVertex;
ethannicholase9709e82016-01-07 13:34:16 -0800598 int fWinding;
599 MonotonePoly* fHead;
600 MonotonePoly* fTail;
ethannicholase9709e82016-01-07 13:34:16 -0800601 Poly* fNext;
602 Poly* fPartner;
603 int fCount;
604#if LOGGING_ENABLED
605 int fID;
606#endif
607};
608
609/***************************************************************************************/
610
611bool coincident(const SkPoint& a, const SkPoint& b) {
612 return a == b;
613}
614
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500615Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) {
616 Poly* poly = alloc.make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800617 poly->fNext = *head;
618 *head = poly;
619 return poly;
620}
621
Stephen White3a9aab92017-03-07 14:07:18 -0500622void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500623 Vertex* v = alloc.make<Vertex>(p, 255);
ethannicholase9709e82016-01-07 13:34:16 -0800624#if LOGGING_ENABLED
625 static float gID = 0.0f;
626 v->fID = gID++;
627#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500628 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800629}
630
Stephen White36e4f062017-03-27 16:11:31 -0400631SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
632 SkQuadCoeff quad(pts);
633 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
634 SkPoint mid = to_point(quad.eval(t));
635 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400636 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
637 return 0;
638 }
Cary Clarkdf429f32017-11-08 11:44:31 -0500639 return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1);
Stephen White36e4f062017-03-27 16:11:31 -0400640}
641
642void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour,
643 SkArenaAlloc& alloc) {
644 SkQuadCoeff quad(pts);
645 Sk2s aa = quad.fA * quad.fA;
646 SkScalar denom = 2.0f * (aa[0] + aa[1]);
647 Sk2s ab = quad.fA * quad.fB;
648 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
649 int nPoints = 1;
650 SkScalar u;
651 // Test possible subdivision values only at the point of maximum curvature.
652 // If it passes the flatness metric there, it'll pass everywhere.
653 for (;;) {
654 u = 1.0f / nPoints;
655 if (quad_error_at(pts, t, u) < toleranceSqd) {
656 break;
657 }
658 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800659 }
Stephen White36e4f062017-03-27 16:11:31 -0400660 for (int j = 1; j <= nPoints; j++) {
661 append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc);
662 }
ethannicholase9709e82016-01-07 13:34:16 -0800663}
664
Stephen White3a9aab92017-03-07 14:07:18 -0500665void generate_cubic_points(const SkPoint& p0,
666 const SkPoint& p1,
667 const SkPoint& p2,
668 const SkPoint& p3,
669 SkScalar tolSqd,
670 VertexList* contour,
671 int pointsLeft,
672 SkArenaAlloc& alloc) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500673 SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
674 SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
ethannicholase9709e82016-01-07 13:34:16 -0800675 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
676 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Stephen White3a9aab92017-03-07 14:07:18 -0500677 append_point_to_contour(p3, contour, alloc);
678 return;
ethannicholase9709e82016-01-07 13:34:16 -0800679 }
680 const SkPoint q[] = {
681 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
682 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
683 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
684 };
685 const SkPoint r[] = {
686 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
687 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
688 };
689 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
690 pointsLeft >>= 1;
Stephen White3a9aab92017-03-07 14:07:18 -0500691 generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc);
692 generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800693}
694
695// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
696
697void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen White3a9aab92017-03-07 14:07:18 -0500698 VertexList* contours, SkArenaAlloc& alloc, bool *isLinear) {
ethannicholase9709e82016-01-07 13:34:16 -0800699 SkScalar toleranceSqd = tolerance * tolerance;
700
701 SkPoint pts[4];
ethannicholase9709e82016-01-07 13:34:16 -0800702 *isLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500703 VertexList* contour = contours;
ethannicholase9709e82016-01-07 13:34:16 -0800704 SkPath::Iter iter(path, false);
ethannicholase9709e82016-01-07 13:34:16 -0800705 if (path.isInverseFillType()) {
706 SkPoint quad[4];
707 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700708 for (int i = 3; i >= 0; i--) {
Stephen White3a9aab92017-03-07 14:07:18 -0500709 append_point_to_contour(quad[i], contours, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800710 }
Stephen White3a9aab92017-03-07 14:07:18 -0500711 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800712 }
713 SkAutoConicToQuads converter;
Stephen White3a9aab92017-03-07 14:07:18 -0500714 SkPath::Verb verb;
Stephen White2cee2832017-08-23 09:37:16 -0400715 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800716 switch (verb) {
717 case SkPath::kConic_Verb: {
718 SkScalar weight = iter.conicWeight();
719 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
720 for (int i = 0; i < converter.countQuads(); ++i) {
Stephen White36e4f062017-03-27 16:11:31 -0400721 append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800722 quadPts += 2;
723 }
724 *isLinear = false;
725 break;
726 }
727 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500728 if (contour->fHead) {
729 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800730 }
Stephen White3a9aab92017-03-07 14:07:18 -0500731 append_point_to_contour(pts[0], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800732 break;
733 case SkPath::kLine_Verb: {
Stephen White3a9aab92017-03-07 14:07:18 -0500734 append_point_to_contour(pts[1], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800735 break;
736 }
737 case SkPath::kQuad_Verb: {
Stephen White36e4f062017-03-27 16:11:31 -0400738 append_quadratic_to_contour(pts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800739 *isLinear = false;
740 break;
741 }
742 case SkPath::kCubic_Verb: {
743 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Stephen White3a9aab92017-03-07 14:07:18 -0500744 generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
745 pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800746 *isLinear = false;
747 break;
748 }
749 case SkPath::kClose_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800750 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800751 break;
752 }
753 }
754}
755
Stephen White49789062017-02-21 10:35:49 -0500756inline bool apply_fill_type(SkPath::FillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800757 switch (fillType) {
758 case SkPath::kWinding_FillType:
759 return winding != 0;
760 case SkPath::kEvenOdd_FillType:
761 return (winding & 1) != 0;
762 case SkPath::kInverseWinding_FillType:
senorblanco7ab96e92016-10-12 06:47:44 -0700763 return winding == 1;
ethannicholase9709e82016-01-07 13:34:16 -0800764 case SkPath::kInverseEvenOdd_FillType:
765 return (winding & 1) == 1;
766 default:
767 SkASSERT(false);
768 return false;
769 }
770}
771
Stephen White49789062017-02-21 10:35:49 -0500772inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) {
773 return poly && apply_fill_type(fillType, poly->fWinding);
774}
775
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500776Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) {
Stephen White2f4686f2017-01-03 16:20:01 -0500777 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800778 Vertex* top = winding < 0 ? next : prev;
779 Vertex* bottom = winding < 0 ? prev : next;
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500780 return alloc.make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800781}
782
783void remove_edge(Edge* edge, EdgeList* edges) {
784 LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700785 SkASSERT(edges->contains(edge));
786 edges->remove(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800787}
788
789void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) {
790 LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700791 SkASSERT(!edges->contains(edge));
ethannicholase9709e82016-01-07 13:34:16 -0800792 Edge* next = prev ? prev->fRight : edges->fHead;
senorblancof57372d2016-08-31 10:36:19 -0700793 edges->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800794}
795
796void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500797 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800798 *left = v->fFirstEdgeAbove->fLeft;
799 *right = v->fLastEdgeAbove->fRight;
800 return;
801 }
802 Edge* next = nullptr;
803 Edge* prev;
804 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
805 if (prev->isLeftOf(v)) {
806 break;
807 }
808 next = prev;
809 }
810 *left = prev;
811 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800812}
813
ethannicholase9709e82016-01-07 13:34:16 -0800814void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) {
815 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500816 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800817 return;
818 }
819 LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
820 Edge* prev = nullptr;
821 Edge* next;
822 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
823 if (next->isRightOf(edge->fTop)) {
824 break;
825 }
826 prev = next;
827 }
senorblancoe6eaa322016-03-08 09:06:44 -0800828 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800829 edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
830}
831
832void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) {
833 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500834 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800835 return;
836 }
837 LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
838 Edge* prev = nullptr;
839 Edge* next;
840 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
841 if (next->isRightOf(edge->fBottom)) {
842 break;
843 }
844 prev = next;
845 }
senorblancoe6eaa322016-03-08 09:06:44 -0800846 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800847 edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
848}
849
850void remove_edge_above(Edge* edge) {
851 LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
852 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800853 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800854 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
855}
856
857void remove_edge_below(Edge* edge) {
858 LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
859 edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800860 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800861 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
862}
863
Stephen Whitee7a364d2017-01-11 16:19:26 -0500864void disconnect(Edge* edge)
865{
ethannicholase9709e82016-01-07 13:34:16 -0800866 remove_edge_above(edge);
867 remove_edge_below(edge);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500868}
869
Stephen White3b5a3fa2017-06-06 14:51:19 -0400870void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c);
871
872void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c) {
873 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
874 return;
875 }
876 Vertex* v = *current;
877 LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
878 while (v != dst) {
879 v = v->fPrev;
880 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
881 remove_edge(e, activeEdges);
882 }
883 Edge* leftEdge = v->fLeftEnclosingEdge;
884 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
885 insert_edge(e, leftEdge, activeEdges);
886 leftEdge = e;
887 }
888 }
889 *current = v;
890}
891
892void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
893 if (!activeEdges || !current) {
894 return;
895 }
896 Vertex* top = edge->fTop;
897 Vertex* bottom = edge->fBottom;
898 if (edge->fLeft) {
899 Vertex* leftTop = edge->fLeft->fTop;
900 Vertex* leftBottom = edge->fLeft->fBottom;
901 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
902 rewind(activeEdges, current, leftTop, c);
903 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
904 rewind(activeEdges, current, top, c);
905 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
906 !edge->fLeft->isLeftOf(bottom)) {
907 rewind(activeEdges, current, leftTop, c);
908 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
909 rewind(activeEdges, current, top, c);
910 }
911 }
912 if (edge->fRight) {
913 Vertex* rightTop = edge->fRight->fTop;
914 Vertex* rightBottom = edge->fRight->fBottom;
915 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
916 rewind(activeEdges, current, rightTop, c);
917 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
918 rewind(activeEdges, current, top, c);
919 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
920 !edge->fRight->isRightOf(bottom)) {
921 rewind(activeEdges, current, rightTop, c);
922 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
923 !edge->isLeftOf(rightBottom)) {
924 rewind(activeEdges, current, top, c);
925 }
ethannicholase9709e82016-01-07 13:34:16 -0800926 }
927}
928
Stephen White3b5a3fa2017-06-06 14:51:19 -0400929void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800930 remove_edge_below(edge);
931 edge->fTop = v;
932 edge->recompute();
933 insert_edge_below(edge, v, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400934 rewind_if_necessary(edge, activeEdges, current, c);
935 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800936}
937
Stephen White3b5a3fa2017-06-06 14:51:19 -0400938void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800939 remove_edge_above(edge);
940 edge->fBottom = v;
941 edge->recompute();
942 insert_edge_above(edge, v, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400943 rewind_if_necessary(edge, activeEdges, current, c);
944 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800945}
946
Stephen White3b5a3fa2017-06-06 14:51:19 -0400947void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
948 Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800949 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
950 LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
951 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
952 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400953 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800954 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400955 disconnect(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800956 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400957 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800958 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400959 set_bottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800960 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400961 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800962 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400963 set_bottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800964 }
965}
966
Stephen White3b5a3fa2017-06-06 14:51:19 -0400967void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
968 Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800969 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
970 LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
971 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
972 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400973 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800974 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400975 disconnect(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800976 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400977 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800978 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400979 set_top(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800980 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400981 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800982 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400983 set_top(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800984 }
985}
986
Stephen White3b5a3fa2017-06-06 14:51:19 -0400987void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
Stephen White6eca90f2017-05-25 14:47:11 -0400988 for (;;) {
989 if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
990 !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400991 merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400992 } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
993 !edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400994 merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400995 } else if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
996 !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400997 merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400998 } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
999 !edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001000 merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -04001001 } else {
1002 break;
1003 }
ethannicholase9709e82016-01-07 13:34:16 -08001004 }
Stephen White6eca90f2017-05-25 14:47:11 -04001005 SkASSERT(!edge->fPrevEdgeAbove || edge->fPrevEdgeAbove->isLeftOf(edge->fTop));
1006 SkASSERT(!edge->fPrevEdgeBelow || edge->fPrevEdgeBelow->isLeftOf(edge->fBottom));
1007 SkASSERT(!edge->fNextEdgeAbove || edge->fNextEdgeAbove->isRightOf(edge->fTop));
1008 SkASSERT(!edge->fNextEdgeBelow || edge->fNextEdgeBelow->isRightOf(edge->fBottom));
ethannicholase9709e82016-01-07 13:34:16 -08001009}
1010
Stephen White3b5a3fa2017-06-06 14:51:19 -04001011void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c,
1012 SkArenaAlloc& alloc) {
Stephen White0cb31672017-06-08 14:41:01 -04001013 if (v == edge->fTop || v == edge->fBottom) {
1014 return;
1015 }
ethannicholase9709e82016-01-07 13:34:16 -08001016 LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
1017 edge->fTop->fID, edge->fBottom->fID,
1018 v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001019 Vertex* top;
1020 Vertex* bottom;
ethannicholase9709e82016-01-07 13:34:16 -08001021 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001022 top = v;
1023 bottom = edge->fTop;
1024 set_top(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -05001025 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001026 top = edge->fBottom;
1027 bottom = v;
1028 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001029 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001030 top = v;
1031 bottom = edge->fBottom;
1032 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001033 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001034 Edge* newEdge = alloc.make<Edge>(top, bottom, edge->fWinding, edge->fType);
1035 insert_edge_below(newEdge, top, c);
1036 insert_edge_above(newEdge, bottom, c);
1037 merge_collinear_edges(newEdge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001038}
1039
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001040Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc,
Stephen White48ded382017-02-03 10:15:16 -05001041 int winding_scale = 1) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001042 Edge* edge = new_edge(prev, next, type, c, alloc);
Stephen White8a0bfc52017-02-21 15:24:13 -05001043 insert_edge_below(edge, edge->fTop, c);
1044 insert_edge_above(edge, edge->fBottom, c);
Stephen White48ded382017-02-03 10:15:16 -05001045 edge->fWinding *= winding_scale;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001046 merge_collinear_edges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -07001047 return edge;
1048}
1049
Stephen Whitebf6137e2017-01-04 15:43:26 -05001050void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001051 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001052 LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY,
1053 src->fID, dst->fID);
senorblancof57372d2016-08-31 10:36:19 -07001054 dst->fAlpha = SkTMax(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -04001055 if (src->fPartner) {
1056 src->fPartner->fPartner = dst;
1057 }
ethannicholase9709e82016-01-07 13:34:16 -08001058 for (Edge* edge = src->fFirstEdgeAbove; edge;) {
1059 Edge* next = edge->fNextEdgeAbove;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001060 set_bottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -08001061 edge = next;
1062 }
1063 for (Edge* edge = src->fFirstEdgeBelow; edge;) {
1064 Edge* next = edge->fNextEdgeBelow;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001065 set_top(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -08001066 edge = next;
1067 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001068 mesh->remove(src);
ethannicholase9709e82016-01-07 13:34:16 -08001069}
1070
senorblancof57372d2016-08-31 10:36:19 -07001071uint8_t max_edge_alpha(Edge* a, Edge* b) {
Stephen White56158ae2017-01-30 14:31:31 -05001072 if (a->fType == Edge::Type::kInner || b->fType == Edge::Type::kInner) {
Stephen White2f4686f2017-01-03 16:20:01 -05001073 return 255;
1074 } else if (a->fType == Edge::Type::kOuter && b->fType == Edge::Type::kOuter) {
1075 return 0;
1076 } else {
1077 return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha),
1078 SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha));
1079 }
senorblancof57372d2016-08-31 10:36:19 -07001080}
1081
Stephen White3f5301b2017-08-15 17:01:15 -04001082bool out_of_range_and_collinear(const SkPoint& p, Edge* edge, Comparator& c) {
1083 if (c.sweep_lt(p, edge->fTop->fPoint) &&
1084 !Line(p, edge->fBottom->fPoint).dist(edge->fTop->fPoint)) {
1085 return true;
1086 } else if (c.sweep_lt(edge->fBottom->fPoint, p) &&
1087 !Line(edge->fTop->fPoint, p).dist(edge->fBottom->fPoint)) {
1088 return true;
1089 }
1090 return false;
1091}
1092
Stephen White3b5a3fa2017-06-06 14:51:19 -04001093bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Stephen White0cb31672017-06-08 14:41:01 -04001094 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001095 if (!edge || !other) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001096 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001097 }
Stephen White56158ae2017-01-30 14:31:31 -05001098 SkPoint p;
1099 uint8_t alpha;
Stephen Whitee3a0be72017-06-12 11:43:18 -04001100 if (edge->intersect(*other, &p, &alpha) && p.isFinite()) {
Stephen White3f5301b2017-08-15 17:01:15 -04001101 // Ignore any out-of-range intersections which are also collinear,
1102 // since the resulting edges would cancel each other out by merging.
1103 if (out_of_range_and_collinear(p, edge, c) ||
1104 out_of_range_and_collinear(p, other, c)) {
1105 return false;
1106 }
ethannicholase9709e82016-01-07 13:34:16 -08001107 Vertex* v;
1108 LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001109 Vertex* top = *current;
1110 // If the intersection point is above the current vertex, rewind to the vertex above the
1111 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -04001112 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001113 top = top->fPrev;
1114 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001115 if (p == edge->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001116 v = edge->fTop;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001117 } else if (p == edge->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001118 v = edge->fBottom;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001119 } else if (p == other->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001120 v = other->fTop;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001121 } else if (p == other->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001122 v = other->fBottom;
1123 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001124 Vertex* prevV = top;
Stephen White0cb31672017-06-08 14:41:01 -04001125 Vertex* nextV = top ? top->fNext : mesh->fHead;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001126 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
1127 prevV = nextV;
ethannicholase9709e82016-01-07 13:34:16 -08001128 nextV = nextV->fNext;
1129 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001130 if (prevV && coincident(prevV->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001131 v = prevV;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001132 } else if (nextV && coincident(nextV->fPoint, p)) {
ethannicholase9709e82016-01-07 13:34:16 -08001133 v = nextV;
1134 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001135 v = alloc.make<Vertex>(p, alpha);
ethannicholase9709e82016-01-07 13:34:16 -08001136#if LOGGING_ENABLED
Stephen White0cb31672017-06-08 14:41:01 -04001137 if (!prevV) {
Stephen White019f6c02017-06-09 10:06:26 -04001138 v->fID = mesh->fHead->fID - 1.0f;
Stephen White0cb31672017-06-08 14:41:01 -04001139 } else if (!nextV) {
Stephen White019f6c02017-06-09 10:06:26 -04001140 v->fID = mesh->fTail->fID + 1.0f;
Stephen White0cb31672017-06-08 14:41:01 -04001141 } else {
1142 v->fID = (prevV->fID + nextV->fID) * 0.5f;
1143 }
ethannicholase9709e82016-01-07 13:34:16 -08001144#endif
Stephen White0cb31672017-06-08 14:41:01 -04001145 mesh->insert(v, prevV, nextV);
ethannicholase9709e82016-01-07 13:34:16 -08001146 }
ethannicholase9709e82016-01-07 13:34:16 -08001147 }
Stephen White0cb31672017-06-08 14:41:01 -04001148 rewind(activeEdges, current, top ? top : v, c);
1149 split_edge(edge, v, activeEdges, current, c, alloc);
1150 split_edge(other, v, activeEdges, current, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001151 v->fAlpha = SkTMax(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001152 return true;
ethannicholase9709e82016-01-07 13:34:16 -08001153 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001154 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001155}
1156
Stephen White3a9aab92017-03-07 14:07:18 -05001157void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) {
1158 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1159 SkASSERT(contour->fHead);
1160 Vertex* prev = contour->fTail;
Stephen White5926f2d2017-02-13 13:55:42 -05001161 if (approximate) {
Stephen White3a9aab92017-03-07 14:07:18 -05001162 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -05001163 }
Stephen White3a9aab92017-03-07 14:07:18 -05001164 for (Vertex* v = contour->fHead; v;) {
senorblancof57372d2016-08-31 10:36:19 -07001165 if (approximate) {
1166 round(&v->fPoint);
1167 }
Stephen White3a9aab92017-03-07 14:07:18 -05001168 Vertex* next = v->fNext;
1169 if (coincident(prev->fPoint, v->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -08001170 LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001171 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -04001172 } else if (!v->fPoint.isFinite()) {
1173 LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
1174 contour->remove(v);
ethannicholase9709e82016-01-07 13:34:16 -08001175 }
Stephen White3a9aab92017-03-07 14:07:18 -05001176 prev = v;
1177 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001178 }
1179 }
1180}
1181
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001182void merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001183 if (!mesh->fHead) {
1184 return;
1185 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001186 for (Vertex* v = mesh->fHead->fNext; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001187 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1188 v->fPoint = v->fPrev->fPoint;
1189 }
1190 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001191 merge_vertices(v->fPrev, v, mesh, c, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001192 }
1193 }
1194}
1195
1196// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1197
Stephen White3a9aab92017-03-07 14:07:18 -05001198void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001199 SkArenaAlloc& alloc) {
Stephen White3a9aab92017-03-07 14:07:18 -05001200 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1201 Vertex* prev = contour->fTail;
1202 for (Vertex* v = contour->fHead; v;) {
1203 Vertex* next = v->fNext;
1204 connect(prev, v, Edge::Type::kInner, c, alloc);
1205 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001206 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001207 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001208 }
1209 }
ethannicholase9709e82016-01-07 13:34:16 -08001210}
1211
Stephen Whitebda29c02017-03-13 15:10:13 -04001212void connect_partners(VertexList* outerVertices, Comparator& c, SkArenaAlloc& alloc) {
1213 for (Vertex* outer = outerVertices->fHead; outer; outer = outer->fNext) {
1214 if (Vertex* inner = outer->fPartner) {
1215 // Connector edges get zero winding, since they're only structural (i.e., to ensure
1216 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding number.
1217 connect(outer, inner, Edge::Type::kConnector, c, alloc, 0);
1218 inner->fPartner = outer->fPartner = nullptr;
1219 }
1220 }
1221}
1222
1223template <CompareFunc sweep_lt>
1224void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
1225 Vertex* a = front->fHead;
1226 Vertex* b = back->fHead;
1227 while (a && b) {
1228 if (sweep_lt(a->fPoint, b->fPoint)) {
1229 front->remove(a);
1230 result->append(a);
1231 a = front->fHead;
1232 } else {
1233 back->remove(b);
1234 result->append(b);
1235 b = back->fHead;
1236 }
1237 }
1238 result->append(*front);
1239 result->append(*back);
1240}
1241
1242void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) {
1243 if (c.fDirection == Comparator::Direction::kHorizontal) {
1244 sorted_merge<sweep_lt_horiz>(front, back, result);
1245 } else {
1246 sorted_merge<sweep_lt_vert>(front, back, result);
1247 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001248#if LOGGING_ENABLED
1249 float id = 0.0f;
1250 for (Vertex* v = result->fHead; v; v = v->fNext) {
1251 v->fID = id++;
1252 }
1253#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001254}
1255
ethannicholase9709e82016-01-07 13:34:16 -08001256// Stage 3: sort the vertices by increasing sweep direction.
1257
Stephen White16a40cb2017-02-23 11:10:01 -05001258template <CompareFunc sweep_lt>
1259void merge_sort(VertexList* vertices) {
1260 Vertex* slow = vertices->fHead;
1261 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001262 return;
1263 }
Stephen White16a40cb2017-02-23 11:10:01 -05001264 Vertex* fast = slow->fNext;
1265 if (!fast) {
1266 return;
1267 }
1268 do {
1269 fast = fast->fNext;
1270 if (fast) {
1271 fast = fast->fNext;
1272 slow = slow->fNext;
1273 }
1274 } while (fast);
1275 VertexList front(vertices->fHead, slow);
1276 VertexList back(slow->fNext, vertices->fTail);
1277 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001278
Stephen White16a40cb2017-02-23 11:10:01 -05001279 merge_sort<sweep_lt>(&front);
1280 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001281
Stephen White16a40cb2017-02-23 11:10:01 -05001282 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001283 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001284}
1285
1286// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1287
Stephen White0cb31672017-06-08 14:41:01 -04001288void simplify(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001289 LOG("simplifying complex polygons\n");
1290 EdgeList activeEdges;
Stephen White0cb31672017-06-08 14:41:01 -04001291 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001292 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1293 continue;
1294 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001295 Edge* leftEnclosingEdge;
1296 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001297 bool restartChecks;
1298 do {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001299 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001300 restartChecks = false;
1301 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White64dbb892017-05-03 16:00:38 -04001302 if (rightEnclosingEdge && !rightEnclosingEdge->isRightOf(v)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001303 split_edge(rightEnclosingEdge, v, &activeEdges, &v, c, alloc);
Stephen White64dbb892017-05-03 16:00:38 -04001304 restartChecks = true;
1305 continue;
1306 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001307 SkASSERT(!rightEnclosingEdge || rightEnclosingEdge->isRightOf(v));
1308 v->fLeftEnclosingEdge = leftEnclosingEdge;
1309 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001310 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001311 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Stephen White0cb31672017-06-08 14:41:01 -04001312 if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001313 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001314 restartChecks = true;
1315 break;
1316 }
Stephen White0cb31672017-06-08 14:41:01 -04001317 if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001318 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001319 restartChecks = true;
1320 break;
1321 }
1322 }
1323 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001324 if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
Stephen White0cb31672017-06-08 14:41:01 -04001325 &activeEdges, &v, mesh, c, alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001326 restartChecks = true;
1327 }
1328
1329 }
1330 } while (restartChecks);
senorblancof57372d2016-08-31 10:36:19 -07001331 if (v->fAlpha == 0) {
Stephen White48ded382017-02-03 10:15:16 -05001332 if ((leftEnclosingEdge && leftEnclosingEdge->fWinding < 0) &&
1333 (rightEnclosingEdge && rightEnclosingEdge->fWinding > 0)) {
senorblancof57372d2016-08-31 10:36:19 -07001334 v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge);
1335 }
1336 }
ethannicholase9709e82016-01-07 13:34:16 -08001337 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1338 remove_edge(e, &activeEdges);
1339 }
1340 Edge* leftEdge = leftEnclosingEdge;
1341 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1342 insert_edge(e, leftEdge, &activeEdges);
1343 leftEdge = e;
1344 }
ethannicholase9709e82016-01-07 13:34:16 -08001345 }
1346}
1347
Stephen Whitebda29c02017-03-13 15:10:13 -04001348// This is a stripped-down version of simplify() (the Bentley-Ottmann algorithm) that
1349// early-returns true on the first found intersection, false if none.
1350bool is_complex(const VertexList& vertices) {
1351 LOG("testing polygon complexity\n");
1352 EdgeList activeEdges;
1353 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
1354 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1355 continue;
1356 }
1357 Edge* leftEnclosingEdge;
1358 Edge* rightEnclosingEdge;
1359 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1360 SkPoint dummy;
1361 if (v->fFirstEdgeBelow) {
1362 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
1363 if (edge && leftEnclosingEdge && edge->intersect(*leftEnclosingEdge, &dummy)) {
1364 activeEdges.removeAll();
1365 return true;
1366 }
1367 if (edge && rightEnclosingEdge && edge->intersect(*rightEnclosingEdge, &dummy)) {
1368 activeEdges.removeAll();
1369 return true;
1370 }
1371 }
1372 } else if (leftEnclosingEdge && rightEnclosingEdge &&
1373 leftEnclosingEdge->intersect(*rightEnclosingEdge, &dummy)) {
1374 activeEdges.removeAll();
1375 return true;
1376 }
1377 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1378 remove_edge(e, &activeEdges);
1379 }
1380 Edge* leftEdge = leftEnclosingEdge;
1381 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1382 insert_edge(e, leftEdge, &activeEdges);
1383 leftEdge = e;
1384 }
1385 }
1386 activeEdges.removeAll();
1387 return false;
1388}
1389
ethannicholase9709e82016-01-07 13:34:16 -08001390// Stage 5: Tessellate the simplified mesh into monotone polygons.
1391
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001392Poly* tessellate(const VertexList& vertices, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001393 LOG("tessellating simple polygons\n");
1394 EdgeList activeEdges;
1395 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001396 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001397 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1398 continue;
1399 }
1400#if LOGGING_ENABLED
senorblancof57372d2016-08-31 10:36:19 -07001401 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001402#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001403 Edge* leftEnclosingEdge;
1404 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001405 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001406 Poly* leftPoly;
1407 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001408 if (v->fFirstEdgeAbove) {
1409 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1410 rightPoly = v->fLastEdgeAbove->fRightPoly;
1411 } else {
1412 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1413 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1414 }
1415#if LOGGING_ENABLED
1416 LOG("edges above:\n");
1417 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1418 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1419 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1420 }
1421 LOG("edges below:\n");
1422 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1423 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1424 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1425 }
1426#endif
1427 if (v->fFirstEdgeAbove) {
1428 if (leftPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001429 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001430 }
1431 if (rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001432 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001433 }
1434 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001435 Edge* rightEdge = e->fNextEdgeAbove;
Stephen White8a0bfc52017-02-21 15:24:13 -05001436 remove_edge(e, &activeEdges);
1437 if (e->fRightPoly) {
1438 e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001439 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001440 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001441 rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001442 }
1443 }
1444 remove_edge(v->fLastEdgeAbove, &activeEdges);
1445 if (!v->fFirstEdgeBelow) {
1446 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1447 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1448 rightPoly->fPartner = leftPoly;
1449 leftPoly->fPartner = rightPoly;
1450 }
1451 }
1452 }
1453 if (v->fFirstEdgeBelow) {
1454 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001455 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001456 if (leftPoly == rightPoly) {
1457 if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) {
1458 leftPoly = new_poly(&polys, leftPoly->lastVertex(),
1459 leftPoly->fWinding, alloc);
1460 leftEnclosingEdge->fRightPoly = leftPoly;
1461 } else {
1462 rightPoly = new_poly(&polys, rightPoly->lastVertex(),
1463 rightPoly->fWinding, alloc);
1464 rightEnclosingEdge->fLeftPoly = rightPoly;
1465 }
ethannicholase9709e82016-01-07 13:34:16 -08001466 }
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001467 Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -07001468 leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc);
1469 rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001470 }
1471 }
1472 Edge* leftEdge = v->fFirstEdgeBelow;
1473 leftEdge->fLeftPoly = leftPoly;
1474 insert_edge(leftEdge, leftEnclosingEdge, &activeEdges);
1475 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1476 rightEdge = rightEdge->fNextEdgeBelow) {
1477 insert_edge(rightEdge, leftEdge, &activeEdges);
1478 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1479 winding += leftEdge->fWinding;
1480 if (winding != 0) {
1481 Poly* poly = new_poly(&polys, v, winding, alloc);
1482 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1483 }
1484 leftEdge = rightEdge;
1485 }
1486 v->fLastEdgeBelow->fRightPoly = rightPoly;
1487 }
1488#if LOGGING_ENABLED
1489 LOG("\nactive edges:\n");
1490 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
1491 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1492 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1493 }
1494#endif
1495 }
1496 return polys;
1497}
1498
Stephen Whitebf6137e2017-01-04 15:43:26 -05001499void remove_non_boundary_edges(const VertexList& mesh, SkPath::FillType fillType,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001500 SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001501 LOG("removing non-boundary edges\n");
1502 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001503 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
Stephen White49789062017-02-21 10:35:49 -05001504 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1505 continue;
1506 }
1507 Edge* leftEnclosingEdge;
1508 Edge* rightEnclosingEdge;
1509 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1510 bool prevFilled = leftEnclosingEdge &&
1511 apply_fill_type(fillType, leftEnclosingEdge->fWinding);
1512 for (Edge* e = v->fFirstEdgeAbove; e;) {
1513 Edge* next = e->fNextEdgeAbove;
1514 remove_edge(e, &activeEdges);
1515 bool filled = apply_fill_type(fillType, e->fWinding);
1516 if (filled == prevFilled) {
Stephen Whitee7a364d2017-01-11 16:19:26 -05001517 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001518 }
Stephen White49789062017-02-21 10:35:49 -05001519 prevFilled = filled;
senorblancof57372d2016-08-31 10:36:19 -07001520 e = next;
1521 }
Stephen White49789062017-02-21 10:35:49 -05001522 Edge* prev = leftEnclosingEdge;
1523 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1524 if (prev) {
1525 e->fWinding += prev->fWinding;
1526 }
1527 insert_edge(e, prev, &activeEdges);
1528 prev = e;
1529 }
senorblancof57372d2016-08-31 10:36:19 -07001530 }
senorblancof57372d2016-08-31 10:36:19 -07001531}
1532
Stephen White66412122017-03-01 11:48:27 -05001533// Note: this is the normal to the edge, but not necessarily unit length.
senorblancof57372d2016-08-31 10:36:19 -07001534void get_edge_normal(const Edge* e, SkVector* normal) {
Stephen White66412122017-03-01 11:48:27 -05001535 normal->set(SkDoubleToScalar(e->fLine.fA) * e->fWinding,
1536 SkDoubleToScalar(e->fLine.fB) * e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001537}
1538
1539// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
1540// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
1541// invert on stroking.
1542
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001543void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) {
senorblancof57372d2016-08-31 10:36:19 -07001544 Edge* prevEdge = boundary->fTail;
1545 SkVector prevNormal;
1546 get_edge_normal(prevEdge, &prevNormal);
1547 for (Edge* e = boundary->fHead; e != nullptr;) {
1548 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
1549 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
1550 double dist = e->dist(prev->fPoint);
1551 SkVector normal;
1552 get_edge_normal(e, &normal);
Stephen White66412122017-03-01 11:48:27 -05001553 double denom = 0.0625f * e->fLine.magSq();
senorblancof57372d2016-08-31 10:36:19 -07001554 if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001555 Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001556 insert_edge(join, e, boundary);
1557 remove_edge(prevEdge, boundary);
1558 remove_edge(e, boundary);
1559 if (join->fLeft && join->fRight) {
1560 prevEdge = join->fLeft;
1561 e = join;
1562 } else {
1563 prevEdge = boundary->fTail;
1564 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
1565 }
1566 get_edge_normal(prevEdge, &prevNormal);
1567 } else {
1568 prevEdge = e;
1569 prevNormal = normal;
1570 e = e->fRight;
1571 }
1572 }
1573}
1574
Ben Wagnerdab48112017-02-16 22:28:02 +00001575void fix_inversions(Vertex* prev, Vertex* next, Edge* prevBisector, Edge* nextBisector,
Stephen White92eba8a2017-02-06 09:50:27 -05001576 Edge* prevEdge, Comparator& c) {
1577 if (!prev || !next) {
1578 return;
1579 }
1580 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
1581 SkPoint p;
1582 uint8_t alpha;
Ben Wagnerdab48112017-02-16 22:28:02 +00001583 if (winding != prevEdge->fWinding && prevBisector->intersect(*nextBisector, &p, &alpha)) {
Stephen White92eba8a2017-02-06 09:50:27 -05001584 prev->fPoint = next->fPoint = p;
1585 prev->fAlpha = next->fAlpha = alpha;
1586 }
1587}
1588
senorblancof57372d2016-08-31 10:36:19 -07001589// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
1590// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
1591// new antialiased mesh from those vertices.
1592
Stephen Whitebda29c02017-03-13 15:10:13 -04001593void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
1594 Comparator& c, SkArenaAlloc& alloc) {
Stephen White8a0bfc52017-02-21 15:24:13 -05001595 // A boundary with fewer than 3 edges is degenerate.
1596 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
1597 return;
1598 }
senorblancof57372d2016-08-31 10:36:19 -07001599 Edge* prevEdge = boundary->fTail;
1600 float radius = 0.5f;
senorblanco49df8d12016-10-07 08:36:56 -07001601 double offset = radius * sqrt(prevEdge->fLine.magSq()) * prevEdge->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001602 Line prevInner(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001603 prevInner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001604 Line prevOuter(prevEdge->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001605 prevOuter.fC += offset;
1606 VertexList innerVertices;
1607 VertexList outerVertices;
Ben Wagnerdab48112017-02-16 22:28:02 +00001608 Edge* prevBisector = nullptr;
senorblancof57372d2016-08-31 10:36:19 -07001609 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
senorblanco49df8d12016-10-07 08:36:56 -07001610 double offset = radius * sqrt(e->fLine.magSq()) * e->fWinding;
Stephen White66412122017-03-01 11:48:27 -05001611 Line inner(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001612 inner.fC -= offset;
Stephen White66412122017-03-01 11:48:27 -05001613 Line outer(e->fLine);
senorblancof57372d2016-08-31 10:36:19 -07001614 outer.fC += offset;
1615 SkPoint innerPoint, outerPoint;
senorblanco49df8d12016-10-07 08:36:56 -07001616 if (prevInner.intersect(inner, &innerPoint) &&
1617 prevOuter.intersect(outer, &outerPoint)) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001618 Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255);
1619 Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0);
Ben Wagnerdab48112017-02-16 22:28:02 +00001620 Edge* bisector = new_edge(outerVertex, innerVertex, Edge::Type::kConnector, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001621 fix_inversions(innerVertices.fTail, innerVertex, prevBisector, bisector, prevEdge, c);
1622 fix_inversions(outerVertices.fTail, outerVertex, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001623 innerVertex->fPartner = outerVertex;
1624 outerVertex->fPartner = innerVertex;
Stephen White92eba8a2017-02-06 09:50:27 -05001625 innerVertices.append(innerVertex);
1626 outerVertices.append(outerVertex);
1627 prevBisector = bisector;
senorblancof57372d2016-08-31 10:36:19 -07001628 }
1629 prevInner = inner;
1630 prevOuter = outer;
Stephen White86cc8412017-01-27 10:53:15 -05001631 prevEdge = e;
senorblancof57372d2016-08-31 10:36:19 -07001632 }
senorblancof57372d2016-08-31 10:36:19 -07001633
1634 Vertex* innerVertex = innerVertices.fHead;
1635 Vertex* outerVertex = outerVertices.fHead;
senorblancof57372d2016-08-31 10:36:19 -07001636 if (!innerVertex || !outerVertex) {
1637 return;
1638 }
Ben Wagnerdab48112017-02-16 22:28:02 +00001639 Edge* bisector = new_edge(outerVertices.fHead, innerVertices.fHead, Edge::Type::kConnector, c,
1640 alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001641 fix_inversions(innerVertices.fTail, innerVertices.fHead, prevBisector, bisector, prevEdge, c);
1642 fix_inversions(outerVertices.fTail, outerVertices.fHead, prevBisector, bisector, prevEdge, c);
Stephen Whitebda29c02017-03-13 15:10:13 -04001643 Vertex* prevInnerVertex = innerVertices.fTail;
1644 Vertex* prevOuterVertex = outerVertices.fTail;
1645 while (innerVertex && outerVertex) {
Stephen White48ded382017-02-03 10:15:16 -05001646 // Connect vertices into a quad mesh. Outer edges get default (1) winding.
1647 // Inner edges get -2 winding. This ensures that the interior is always filled
1648 // (-1 winding number for normal cases, 3 for thin features where the interior inverts).
Stephen Whitebda29c02017-03-13 15:10:13 -04001649 connect(prevOuterVertex, outerVertex, Edge::Type::kOuter, c, alloc);
1650 connect(prevInnerVertex, innerVertex, Edge::Type::kInner, c, alloc, -2);
1651 prevInnerVertex = innerVertex;
1652 prevOuterVertex = outerVertex;
1653 innerVertex = innerVertex->fNext;
1654 outerVertex = outerVertex->fNext;
1655 }
1656 innerMesh->append(innerVertices);
1657 outerMesh->append(outerVertices);
senorblancof57372d2016-08-31 10:36:19 -07001658}
1659
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001660void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001661 bool down = apply_fill_type(fillType, e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001662 while (e) {
1663 e->fWinding = down ? 1 : -1;
1664 Edge* next;
1665 boundary->append(e);
1666 if (down) {
1667 // Find outgoing edge, in clockwise order.
1668 if ((next = e->fNextEdgeAbove)) {
1669 down = false;
1670 } else if ((next = e->fBottom->fLastEdgeBelow)) {
1671 down = true;
1672 } else if ((next = e->fPrevEdgeAbove)) {
1673 down = false;
1674 }
1675 } else {
1676 // Find outgoing edge, in counter-clockwise order.
1677 if ((next = e->fPrevEdgeBelow)) {
1678 down = true;
1679 } else if ((next = e->fTop->fFirstEdgeAbove)) {
1680 down = false;
1681 } else if ((next = e->fNextEdgeBelow)) {
1682 down = true;
1683 }
1684 }
Stephen Whitee7a364d2017-01-11 16:19:26 -05001685 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001686 e = next;
1687 }
1688}
1689
Stephen White5ad721e2017-02-23 16:50:47 -05001690// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
senorblancof57372d2016-08-31 10:36:19 -07001691
Stephen Whitebda29c02017-03-13 15:10:13 -04001692void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices,
1693 VertexList* outerVertices, SkPath::FillType fillType,
Stephen White5ad721e2017-02-23 16:50:47 -05001694 Comparator& c, SkArenaAlloc& alloc) {
1695 remove_non_boundary_edges(inMesh, fillType, alloc);
1696 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001697 while (v->fFirstEdgeBelow) {
Stephen White5ad721e2017-02-23 16:50:47 -05001698 EdgeList boundary;
1699 extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc);
1700 simplify_boundary(&boundary, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001701 stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001702 }
1703 }
senorblancof57372d2016-08-31 10:36:19 -07001704}
1705
Stephen Whitebda29c02017-03-13 15:10:13 -04001706// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001707
Stephen White3a9aab92017-03-07 14:07:18 -05001708void contours_to_mesh(VertexList* contours, int contourCnt, bool antialias,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001709 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001710#if LOGGING_ENABLED
1711 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001712 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001713 SkASSERT(v);
1714 LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001715 for (v = v->fNext; v; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001716 LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1717 }
1718 }
1719#endif
senorblancof57372d2016-08-31 10:36:19 -07001720 sanitize_contours(contours, contourCnt, antialias);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001721 build_edges(contours, contourCnt, mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001722}
1723
Stephen Whitebda29c02017-03-13 15:10:13 -04001724void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001725 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001726 return;
ethannicholase9709e82016-01-07 13:34:16 -08001727 }
1728
1729 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001730 if (c.fDirection == Comparator::Direction::kHorizontal) {
1731 merge_sort<sweep_lt_horiz>(vertices);
1732 } else {
1733 merge_sort<sweep_lt_vert>(vertices);
1734 }
ethannicholase9709e82016-01-07 13:34:16 -08001735#if LOGGING_ENABLED
Stephen White2e2cb9b2017-01-09 13:11:18 -05001736 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001737 static float gID = 0.0f;
1738 v->fID = gID++;
1739 }
1740#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001741}
1742
Stephen White3a9aab92017-03-07 14:07:18 -05001743Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPath::FillType fillType,
Stephen Whitebda29c02017-03-13 15:10:13 -04001744 const SkRect& pathBounds, bool antialias, VertexList* outerMesh,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001745 SkArenaAlloc& alloc) {
Stephen White16a40cb2017-02-23 11:10:01 -05001746 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1747 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001748 VertexList mesh;
1749 contours_to_mesh(contours, contourCnt, antialias, &mesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001750 sort_mesh(&mesh, c, alloc);
1751 merge_coincident_vertices(&mesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04001752 simplify(&mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001753 if (antialias) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001754 VertexList innerMesh;
1755 extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc);
1756 sort_mesh(&innerMesh, c, alloc);
1757 sort_mesh(outerMesh, c, alloc);
1758 if (is_complex(innerMesh) || is_complex(*outerMesh)) {
1759 LOG("found complex mesh; taking slow path\n");
1760 VertexList aaMesh;
1761 connect_partners(outerMesh, c, alloc);
1762 sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
1763 merge_coincident_vertices(&aaMesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04001764 simplify(&aaMesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001765 outerMesh->fHead = outerMesh->fTail = nullptr;
1766 return tessellate(aaMesh, alloc);
1767 } else {
1768 LOG("no complex polygons; taking fast path\n");
1769 merge_coincident_vertices(&innerMesh, c, alloc);
1770 return tessellate(innerMesh, alloc);
1771 }
Stephen White49789062017-02-21 10:35:49 -05001772 } else {
1773 return tessellate(mesh, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001774 }
senorblancof57372d2016-08-31 10:36:19 -07001775}
1776
1777// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1778void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* aaParams,
1779 void* data) {
1780 for (Poly* poly = polys; poly; poly = poly->fNext) {
1781 if (apply_fill_type(fillType, poly)) {
1782 data = poly->emit(aaParams, data);
1783 }
1784 }
1785 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001786}
1787
halcanary9d524f22016-03-29 09:03:52 -07001788Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen Whitebda29c02017-03-13 15:10:13 -04001789 int contourCnt, SkArenaAlloc& alloc, bool antialias, bool* isLinear,
1790 VertexList* outerMesh) {
ethannicholase9709e82016-01-07 13:34:16 -08001791 SkPath::FillType fillType = path.getFillType();
1792 if (SkPath::IsInverseFillType(fillType)) {
1793 contourCnt++;
1794 }
Stephen White3a9aab92017-03-07 14:07:18 -05001795 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08001796
1797 path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear);
senorblancof57372d2016-08-31 10:36:19 -07001798 return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(),
Stephen Whitebda29c02017-03-13 15:10:13 -04001799 antialias, outerMesh, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001800}
1801
Stephen White11f65e02017-02-16 19:00:39 -05001802int get_contour_count(const SkPath& path, SkScalar tolerance) {
1803 int contourCnt;
1804 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001805 if (maxPts <= 0) {
Stephen White11f65e02017-02-16 19:00:39 -05001806 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001807 }
1808 if (maxPts > ((int)SK_MaxU16 + 1)) {
1809 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
Stephen White11f65e02017-02-16 19:00:39 -05001810 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001811 }
Stephen White11f65e02017-02-16 19:00:39 -05001812 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001813}
1814
1815int count_points(Poly* polys, SkPath::FillType fillType) {
1816 int count = 0;
1817 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001818 if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
ethannicholase9709e82016-01-07 13:34:16 -08001819 count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3);
1820 }
1821 }
1822 return count;
1823}
1824
Stephen Whitebda29c02017-03-13 15:10:13 -04001825int count_outer_mesh_points(const VertexList& outerMesh) {
1826 int count = 0;
1827 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1828 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1829 count += TESSELLATOR_WIREFRAME ? 12 : 6;
1830 }
1831 }
1832 return count;
1833}
1834
1835void* outer_mesh_to_triangles(const VertexList& outerMesh, const AAParams* aaParams, void* data) {
1836 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
1837 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1838 Vertex* v0 = e->fTop;
1839 Vertex* v1 = e->fBottom;
1840 Vertex* v2 = e->fBottom->fPartner;
1841 Vertex* v3 = e->fTop->fPartner;
1842 data = emit_triangle(v0, v1, v2, aaParams, data);
1843 data = emit_triangle(v0, v2, v3, aaParams, data);
1844 }
1845 }
1846 return data;
1847}
1848
ethannicholase9709e82016-01-07 13:34:16 -08001849} // namespace
1850
1851namespace GrTessellator {
1852
1853// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1854
halcanary9d524f22016-03-29 09:03:52 -07001855int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
senorblancof57372d2016-08-31 10:36:19 -07001856 VertexAllocator* vertexAllocator, bool antialias, const GrColor& color,
1857 bool canTweakAlphaForCoverage, bool* isLinear) {
Stephen White11f65e02017-02-16 19:00:39 -05001858 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001859 if (contourCnt <= 0) {
1860 *isLinear = true;
1861 return 0;
1862 }
Stephen White11f65e02017-02-16 19:00:39 -05001863 SkArenaAlloc alloc(kArenaChunkSize);
Stephen Whitebda29c02017-03-13 15:10:13 -04001864 VertexList outerMesh;
senorblancof57372d2016-08-31 10:36:19 -07001865 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias,
Stephen Whitebda29c02017-03-13 15:10:13 -04001866 isLinear, &outerMesh);
senorblanco7ab96e92016-10-12 06:47:44 -07001867 SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType();
ethannicholase9709e82016-01-07 13:34:16 -08001868 int count = count_points(polys, fillType);
Stephen Whitebda29c02017-03-13 15:10:13 -04001869 if (antialias) {
1870 count += count_outer_mesh_points(outerMesh);
1871 }
Stephen Whiteff60b172017-05-05 15:54:52 -04001872 if (0 == count) {
1873 return 0;
1874 }
ethannicholase9709e82016-01-07 13:34:16 -08001875
senorblancof57372d2016-08-31 10:36:19 -07001876 void* verts = vertexAllocator->lock(count);
senorblanco6599eff2016-03-10 08:38:45 -08001877 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001878 SkDebugf("Could not allocate vertices\n");
1879 return 0;
1880 }
senorblancof57372d2016-08-31 10:36:19 -07001881
1882 LOG("emitting %d verts\n", count);
1883 AAParams aaParams;
1884 aaParams.fTweakAlpha = canTweakAlphaForCoverage;
1885 aaParams.fColor = color;
1886
1887 void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts);
Stephen Whitebda29c02017-03-13 15:10:13 -04001888 end = outer_mesh_to_triangles(outerMesh, &aaParams, end);
senorblancof57372d2016-08-31 10:36:19 -07001889 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
1890 / vertexAllocator->stride());
ethannicholase9709e82016-01-07 13:34:16 -08001891 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001892 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001893 return actualCount;
1894}
1895
halcanary9d524f22016-03-29 09:03:52 -07001896int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
ethannicholase9709e82016-01-07 13:34:16 -08001897 GrTessellator::WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05001898 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001899 if (contourCnt <= 0) {
1900 return 0;
1901 }
Stephen White11f65e02017-02-16 19:00:39 -05001902 SkArenaAlloc alloc(kArenaChunkSize);
ethannicholase9709e82016-01-07 13:34:16 -08001903 bool isLinear;
Stephen Whitebda29c02017-03-13 15:10:13 -04001904 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear,
1905 nullptr);
ethannicholase9709e82016-01-07 13:34:16 -08001906 SkPath::FillType fillType = path.getFillType();
1907 int count = count_points(polys, fillType);
1908 if (0 == count) {
1909 *verts = nullptr;
1910 return 0;
1911 }
1912
1913 *verts = new GrTessellator::WindingVertex[count];
1914 GrTessellator::WindingVertex* vertsEnd = *verts;
1915 SkPoint* points = new SkPoint[count];
1916 SkPoint* pointsEnd = points;
1917 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001918 if (apply_fill_type(fillType, poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001919 SkPoint* start = pointsEnd;
senorblancof57372d2016-08-31 10:36:19 -07001920 pointsEnd = static_cast<SkPoint*>(poly->emit(nullptr, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001921 while (start != pointsEnd) {
1922 vertsEnd->fPos = *start;
1923 vertsEnd->fWinding = poly->fWinding;
1924 ++start;
1925 ++vertsEnd;
1926 }
1927 }
1928 }
1929 int actualCount = static_cast<int>(vertsEnd - *verts);
1930 SkASSERT(actualCount <= count);
1931 SkASSERT(pointsEnd - points == actualCount);
1932 delete[] points;
1933 return actualCount;
1934}
1935
1936} // namespace