blob: 4d3c1eb0eed39bac51fd5887dd29d5a7ba1c6fa4 [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"
Stephen Whitee260c462017-12-19 18:09:54 -050017#include "SkTDPQueue.h"
ethannicholase9709e82016-01-07 13:34:16 -080018
Stephen White94b7e542018-01-04 14:01:10 -050019#include <algorithm>
ethannicholase9709e82016-01-07 13:34:16 -080020#include <stdio.h>
21
22/*
senorblancof57372d2016-08-31 10:36:19 -070023 * There are six stages to the basic algorithm:
ethannicholase9709e82016-01-07 13:34:16 -080024 *
25 * 1) Linearize the path contours into piecewise linear segments (path_to_contours()).
26 * 2) Build a mesh of edges connecting the vertices (build_edges()).
27 * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()).
28 * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()).
29 * 5) Tessellate the simplified mesh into monotone polygons (tessellate()).
30 * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()).
31 *
senorblancof57372d2016-08-31 10:36:19 -070032 * For screenspace antialiasing, the algorithm is modified as follows:
33 *
34 * Run steps 1-5 above to produce polygons.
35 * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()).
Stephen Whitebda29c02017-03-13 15:10:13 -040036 * 5c) Simplify boundaries to remove "pointy" vertices that cause inversions (simplify_boundary()).
senorblancof57372d2016-08-31 10:36:19 -070037 * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find
38 * 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 -040039 * antialiased mesh from those vertices (stroke_boundary()).
senorblancof57372d2016-08-31 10:36:19 -070040 * Run steps 3-6 above on the new mesh, and produce antialiased triangles.
41 *
ethannicholase9709e82016-01-07 13:34:16 -080042 * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
43 * of vertices (and the necessity of inserting new vertices on intersection).
44 *
Stephen Whitebda29c02017-03-13 15:10:13 -040045 * Stages (4) and (5) use an active edge list -- a list of all edges for which the
ethannicholase9709e82016-01-07 13:34:16 -080046 * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted
47 * left-to-right based on the point where both edges are active (when both top vertices
48 * have been seen, so the "lower" top vertex of the two). If the top vertices are equal
49 * (shared), it's sorted based on the last point where both edges are active, so the
50 * "upper" bottom vertex.
51 *
52 * The most complex step is the simplification (4). It's based on the Bentley-Ottman
53 * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
54 * not exact and may violate the mesh topology or active edge list ordering. We
55 * accommodate this by adjusting the topology of the mesh and AEL to match the intersection
Stephen White3b5a3fa2017-06-06 14:51:19 -040056 * points. This occurs in two ways:
ethannicholase9709e82016-01-07 13:34:16 -080057 *
58 * A) Intersections may cause a shortened edge to no longer be ordered with respect to its
59 * neighbouring edges at the top or bottom vertex. This is handled by merging the
60 * edges (merge_collinear_edges()).
61 * B) Intersections may cause an edge to violate the left-to-right ordering of the
Stephen White019f6c02017-06-09 10:06:26 -040062 * active edge list. This is handled by detecting potential violations and rewinding
Stephen White3b5a3fa2017-06-06 14:51:19 -040063 * the active edge list to the vertex before they occur (rewind() during merging,
64 * rewind_if_necessary() during splitting).
ethannicholase9709e82016-01-07 13:34:16 -080065 *
66 * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
67 * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
68 * currently uses a linked list for the active edge list, rather than a 2-3 tree as the
69 * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
70 * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
71 * insertions and removals was greater than the cost of infrequent O(N) lookups with the
72 * linked list implementation. With the latter, all removals are O(1), and most insertions
73 * are O(1), since we know the adjacent edge in the active edge list based on the topology.
74 * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
75 * frequent. There may be other data structures worth investigating, however.
76 *
77 * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the
78 * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y
79 * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall,
80 * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so
81 * that the "left" and "right" orientation in the code remains correct (edges to the left are
82 * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90
83 * degrees counterclockwise, rather that transposing.
84 */
85
86#define LOGGING_ENABLED 0
87
88#if LOGGING_ENABLED
89#define LOG printf
90#else
91#define LOG(...)
92#endif
93
ethannicholase9709e82016-01-07 13:34:16 -080094namespace {
95
Stephen White11f65e02017-02-16 19:00:39 -050096const int kArenaChunkSize = 16 * 1024;
Stephen Whitee260c462017-12-19 18:09:54 -050097const float kCosMiterAngle = 0.97f; // Corresponds to an angle of ~14 degrees.
Stephen White11f65e02017-02-16 19:00:39 -050098
ethannicholase9709e82016-01-07 13:34:16 -080099struct Vertex;
100struct Edge;
Stephen Whitee260c462017-12-19 18:09:54 -0500101struct Event;
ethannicholase9709e82016-01-07 13:34:16 -0800102struct Poly;
103
104template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800105void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800106 t->*Prev = prev;
107 t->*Next = next;
108 if (prev) {
109 prev->*Next = t;
110 } else if (head) {
111 *head = t;
112 }
113 if (next) {
114 next->*Prev = t;
115 } else if (tail) {
116 *tail = t;
117 }
118}
119
120template <class T, T* T::*Prev, T* T::*Next>
senorblancoe6eaa322016-03-08 09:06:44 -0800121void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -0800122 if (t->*Prev) {
123 t->*Prev->*Next = t->*Next;
124 } else if (head) {
125 *head = t->*Next;
126 }
127 if (t->*Next) {
128 t->*Next->*Prev = t->*Prev;
129 } else if (tail) {
130 *tail = t->*Prev;
131 }
132 t->*Prev = t->*Next = nullptr;
133}
134
135/**
136 * Vertices are used in three ways: first, the path contours are converted into a
137 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
138 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
139 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
140 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
141 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
142 * an individual Vertex from the path mesh may belong to multiple
143 * MonotonePolys, so the original Vertices cannot be re-used.
144 */
145
146struct Vertex {
senorblancof57372d2016-08-31 10:36:19 -0700147 Vertex(const SkPoint& point, uint8_t alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800148 : fPoint(point), fPrev(nullptr), fNext(nullptr)
149 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
150 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
Stephen White3b5a3fa2017-06-06 14:51:19 -0400151 , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
Stephen Whitebda29c02017-03-13 15:10:13 -0400152 , fPartner(nullptr)
senorblancof57372d2016-08-31 10:36:19 -0700153 , fAlpha(alpha)
ethannicholase9709e82016-01-07 13:34:16 -0800154#if LOGGING_ENABLED
155 , fID (-1.0f)
156#endif
157 {}
Stephen White3b5a3fa2017-06-06 14:51:19 -0400158 SkPoint fPoint; // Vertex position
159 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
160 Vertex* fNext; // "
161 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
162 Edge* fLastEdgeAbove; // "
163 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
164 Edge* fLastEdgeBelow; // "
165 Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
166 Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
167 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
senorblancof57372d2016-08-31 10:36:19 -0700168 uint8_t fAlpha;
ethannicholase9709e82016-01-07 13:34:16 -0800169#if LOGGING_ENABLED
Stephen White3b5a3fa2017-06-06 14:51:19 -0400170 float fID; // Identifier used for logging.
ethannicholase9709e82016-01-07 13:34:16 -0800171#endif
172};
173
174/***************************************************************************************/
175
senorblancof57372d2016-08-31 10:36:19 -0700176struct AAParams {
177 bool fTweakAlpha;
178 GrColor fColor;
179};
180
ethannicholase9709e82016-01-07 13:34:16 -0800181typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
182
ethannicholase9709e82016-01-07 13:34:16 -0800183bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500184 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -0800185}
186
187bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -0500188 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -0800189}
190
Stephen White16a40cb2017-02-23 11:10:01 -0500191struct Comparator {
192 enum class Direction { kVertical, kHorizontal };
193 Comparator(Direction direction) : fDirection(direction) {}
194 bool sweep_lt(const SkPoint& a, const SkPoint& b) const {
195 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
196 }
Stephen White16a40cb2017-02-23 11:10:01 -0500197 Direction fDirection;
198};
199
senorblancof57372d2016-08-31 10:36:19 -0700200inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) {
201 if (!aaParams) {
202 SkPoint* d = static_cast<SkPoint*>(data);
203 *d++ = v->fPoint;
204 return d;
205 }
206 if (aaParams->fTweakAlpha) {
207 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorAttr*>(data);
208 d->fPosition = v->fPoint;
lsalzman8c8fcef2016-10-11 12:20:17 -0700209 d->fColor = SkAlphaMulQ(aaParams->fColor, SkAlpha255To256(v->fAlpha));
senorblancof57372d2016-08-31 10:36:19 -0700210 d++;
211 return d;
212 }
213 auto d = static_cast<GrDefaultGeoProcFactory::PositionColorCoverageAttr*>(data);
214 d->fPosition = v->fPoint;
215 d->fColor = aaParams->fColor;
216 d->fCoverage = GrNormalizeByteToFloat(v->fAlpha);
217 d++;
218 return d;
ethannicholase9709e82016-01-07 13:34:16 -0800219}
220
senorblancof57372d2016-08-31 10:36:19 -0700221void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams, void* data) {
Stephen White95152e12017-12-18 10:52:44 -0500222 LOG("emit_triangle %g (%g, %g) %d\n", v0->fID, v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
223 LOG(" %g (%g, %g) %d\n", v1->fID, v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
224 LOG(" %g (%g, %g) %d\n", v2->fID, v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -0700225#if TESSELLATOR_WIREFRAME
226 data = emit_vertex(v0, aaParams, data);
227 data = emit_vertex(v1, aaParams, data);
228 data = emit_vertex(v1, aaParams, data);
229 data = emit_vertex(v2, aaParams, data);
230 data = emit_vertex(v2, aaParams, data);
231 data = emit_vertex(v0, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800232#else
senorblancof57372d2016-08-31 10:36:19 -0700233 data = emit_vertex(v0, aaParams, data);
234 data = emit_vertex(v1, aaParams, data);
235 data = emit_vertex(v2, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800236#endif
237 return data;
238}
239
senorblancoe6eaa322016-03-08 09:06:44 -0800240struct VertexList {
241 VertexList() : fHead(nullptr), fTail(nullptr) {}
Stephen White16a40cb2017-02-23 11:10:01 -0500242 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {}
senorblancoe6eaa322016-03-08 09:06:44 -0800243 Vertex* fHead;
244 Vertex* fTail;
245 void insert(Vertex* v, Vertex* prev, Vertex* next) {
246 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
247 }
248 void append(Vertex* v) {
249 insert(v, fTail, nullptr);
250 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400251 void append(const VertexList& list) {
252 if (!list.fHead) {
253 return;
254 }
255 if (fTail) {
256 fTail->fNext = list.fHead;
257 list.fHead->fPrev = fTail;
258 } else {
259 fHead = list.fHead;
260 }
261 fTail = list.fTail;
262 }
senorblancoe6eaa322016-03-08 09:06:44 -0800263 void prepend(Vertex* v) {
264 insert(v, nullptr, fHead);
265 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500266 void remove(Vertex* v) {
267 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
268 }
senorblancof57372d2016-08-31 10:36:19 -0700269 void close() {
270 if (fHead && fTail) {
271 fTail->fNext = fHead;
272 fHead->fPrev = fTail;
273 }
274 }
senorblancoe6eaa322016-03-08 09:06:44 -0800275};
276
senorblancof57372d2016-08-31 10:36:19 -0700277// Round to nearest quarter-pixel. This is used for screenspace tessellation.
278
279inline void round(SkPoint* p) {
280 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
281 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
282}
283
Stephen White94b7e542018-01-04 14:01:10 -0500284inline SkScalar double_to_clamped_scalar(double d) {
285 return SkDoubleToScalar(std::min((double) SK_ScalarMax, std::max(d, (double) -SK_ScalarMax)));
286}
287
senorblanco49df8d12016-10-07 08:36:56 -0700288// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
289struct Line {
Stephen Whitee260c462017-12-19 18:09:54 -0500290 Line(double a, double b, double c) : fA(a), fB(b), fC(c) {}
senorblanco49df8d12016-10-07 08:36:56 -0700291 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
292 Line(const SkPoint& p, const SkPoint& q)
293 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
294 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
295 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
296 static_cast<double>(p.fX) * q.fY) {}
297 double dist(const SkPoint& p) const {
298 return fA * p.fX + fB * p.fY + fC;
299 }
Stephen Whitee260c462017-12-19 18:09:54 -0500300 Line operator*(double v) const {
301 return Line(fA * v, fB * v, fC * v);
302 }
senorblanco49df8d12016-10-07 08:36:56 -0700303 double magSq() const {
304 return fA * fA + fB * fB;
305 }
Stephen Whitee260c462017-12-19 18:09:54 -0500306 void normalize() {
307 double len = sqrt(this->magSq());
308 if (len == 0.0) {
309 return;
310 }
311 double scale = 1.0f / len;
312 fA *= scale;
313 fB *= scale;
314 fC *= scale;
315 }
316 bool nearParallel(const Line& o) const {
317 return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001;
318 }
senorblanco49df8d12016-10-07 08:36:56 -0700319
320 // Compute the intersection of two (infinite) Lines.
Stephen White95152e12017-12-18 10:52:44 -0500321 bool intersect(const Line& other, SkPoint* point) const {
senorblanco49df8d12016-10-07 08:36:56 -0700322 double denom = fA * other.fB - fB * other.fA;
323 if (denom == 0.0) {
324 return false;
325 }
Stephen White94b7e542018-01-04 14:01:10 -0500326 double scale = 1.0 / denom;
327 point->fX = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale);
328 point->fY = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale);
Stephen Whiteb56dedf2017-03-02 10:35:56 -0500329 round(point);
senorblanco49df8d12016-10-07 08:36:56 -0700330 return true;
331 }
332 double fA, fB, fC;
333};
334
ethannicholase9709e82016-01-07 13:34:16 -0800335/**
336 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
337 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
338 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
Stephen Whitebda29c02017-03-13 15:10:13 -0400339 * point). For speed, that case is only tested by the callers that require it (e.g.,
Stephen White3b5a3fa2017-06-06 14:51:19 -0400340 * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
ethannicholase9709e82016-01-07 13:34:16 -0800341 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
342 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
343 * a lot faster in the "not found" case.
344 *
345 * The coefficients of the line equation stored in double precision to avoid catastrphic
346 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
347 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
348 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
349 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
350 * this file).
351 */
352
353struct Edge {
Stephen White2f4686f2017-01-03 16:20:01 -0500354 enum class Type { kInner, kOuter, kConnector };
355 Edge(Vertex* top, Vertex* bottom, int winding, Type type)
ethannicholase9709e82016-01-07 13:34:16 -0800356 : fWinding(winding)
357 , fTop(top)
358 , fBottom(bottom)
Stephen White2f4686f2017-01-03 16:20:01 -0500359 , fType(type)
ethannicholase9709e82016-01-07 13:34:16 -0800360 , fLeft(nullptr)
361 , fRight(nullptr)
362 , fPrevEdgeAbove(nullptr)
363 , fNextEdgeAbove(nullptr)
364 , fPrevEdgeBelow(nullptr)
365 , fNextEdgeBelow(nullptr)
366 , fLeftPoly(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700367 , fRightPoly(nullptr)
Stephen Whitee260c462017-12-19 18:09:54 -0500368 , fEvent(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700369 , fLeftPolyPrev(nullptr)
370 , fLeftPolyNext(nullptr)
371 , fRightPolyPrev(nullptr)
senorblanco70f52512016-08-17 14:56:22 -0700372 , fRightPolyNext(nullptr)
Stephen Whitee260c462017-12-19 18:09:54 -0500373 , fOverlap(false)
senorblanco70f52512016-08-17 14:56:22 -0700374 , fUsedInLeftPoly(false)
senorblanco49df8d12016-10-07 08:36:56 -0700375 , fUsedInRightPoly(false)
376 , fLine(top, bottom) {
ethannicholase9709e82016-01-07 13:34:16 -0800377 }
378 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
379 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
380 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
Stephen White2f4686f2017-01-03 16:20:01 -0500381 Type fType;
ethannicholase9709e82016-01-07 13:34:16 -0800382 Edge* fLeft; // The linked list of edges in the active edge list.
383 Edge* fRight; // "
384 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
385 Edge* fNextEdgeAbove; // "
386 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
387 Edge* fNextEdgeBelow; // "
388 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
389 Poly* fRightPoly; // The Poly to the right of this edge, if any.
Stephen Whitee260c462017-12-19 18:09:54 -0500390 Event* fEvent;
senorblanco531237e2016-06-02 11:36:48 -0700391 Edge* fLeftPolyPrev;
392 Edge* fLeftPolyNext;
393 Edge* fRightPolyPrev;
394 Edge* fRightPolyNext;
Stephen Whitee260c462017-12-19 18:09:54 -0500395 bool fOverlap; // True if there's an overlap region adjacent to this edge.
senorblanco70f52512016-08-17 14:56:22 -0700396 bool fUsedInLeftPoly;
397 bool fUsedInRightPoly;
senorblanco49df8d12016-10-07 08:36:56 -0700398 Line fLine;
ethannicholase9709e82016-01-07 13:34:16 -0800399 double dist(const SkPoint& p) const {
senorblanco49df8d12016-10-07 08:36:56 -0700400 return fLine.dist(p);
ethannicholase9709e82016-01-07 13:34:16 -0800401 }
402 bool isRightOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700403 return fLine.dist(v->fPoint) < 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800404 }
405 bool isLeftOf(Vertex* v) const {
senorblanco49df8d12016-10-07 08:36:56 -0700406 return fLine.dist(v->fPoint) > 0.0;
ethannicholase9709e82016-01-07 13:34:16 -0800407 }
408 void recompute() {
senorblanco49df8d12016-10-07 08:36:56 -0700409 fLine = Line(fTop, fBottom);
ethannicholase9709e82016-01-07 13:34:16 -0800410 }
Stephen White95152e12017-12-18 10:52:44 -0500411 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const {
ethannicholase9709e82016-01-07 13:34:16 -0800412 LOG("intersecting %g -> %g with %g -> %g\n",
413 fTop->fID, fBottom->fID,
414 other.fTop->fID, other.fBottom->fID);
415 if (fTop == other.fTop || fBottom == other.fBottom) {
416 return false;
417 }
senorblanco49df8d12016-10-07 08:36:56 -0700418 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800419 if (denom == 0.0) {
420 return false;
421 }
Stephen White8a0bfc52017-02-21 15:24:13 -0500422 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
423 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
424 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
425 double tNumer = dy * fLine.fB + dx * fLine.fA;
ethannicholase9709e82016-01-07 13:34:16 -0800426 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
427 // This saves us doing the divide below unless absolutely necessary.
428 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
429 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
430 return false;
431 }
432 double s = sNumer / denom;
433 SkASSERT(s >= 0.0 && s <= 1.0);
senorblanco49df8d12016-10-07 08:36:56 -0700434 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
435 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
Stephen White56158ae2017-01-30 14:31:31 -0500436 if (alpha) {
Stephen White92eba8a2017-02-06 09:50:27 -0500437 if (fType == Type::kConnector) {
438 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
439 } else if (other.fType == Type::kConnector) {
440 double t = tNumer / denom;
441 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
Stephen White56158ae2017-01-30 14:31:31 -0500442 } else if (fType == Type::kOuter && other.fType == Type::kOuter) {
443 *alpha = 0;
444 } else {
Stephen White92eba8a2017-02-06 09:50:27 -0500445 *alpha = 255;
Stephen White56158ae2017-01-30 14:31:31 -0500446 }
447 }
ethannicholase9709e82016-01-07 13:34:16 -0800448 return true;
449 }
senorblancof57372d2016-08-31 10:36:19 -0700450};
451
452struct EdgeList {
Stephen White5ad721e2017-02-23 16:50:47 -0500453 EdgeList() : fHead(nullptr), fTail(nullptr) {}
senorblancof57372d2016-08-31 10:36:19 -0700454 Edge* fHead;
455 Edge* fTail;
senorblancof57372d2016-08-31 10:36:19 -0700456 void insert(Edge* edge, Edge* prev, Edge* next) {
457 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700458 }
459 void append(Edge* e) {
460 insert(e, fTail, nullptr);
461 }
462 void remove(Edge* edge) {
463 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
senorblancof57372d2016-08-31 10:36:19 -0700464 }
Stephen Whitebda29c02017-03-13 15:10:13 -0400465 void removeAll() {
466 while (fHead) {
467 this->remove(fHead);
468 }
469 }
senorblancof57372d2016-08-31 10:36:19 -0700470 void close() {
471 if (fHead && fTail) {
472 fTail->fRight = fHead;
473 fHead->fLeft = fTail;
474 }
475 }
476 bool contains(Edge* edge) const {
477 return edge->fLeft || edge->fRight || fHead == edge;
ethannicholase9709e82016-01-07 13:34:16 -0800478 }
479};
480
Stephen Whitee260c462017-12-19 18:09:54 -0500481struct Event {
482 Event(Edge* edge, const SkPoint& point, uint8_t alpha)
483 : fEdge(edge), fPoint(point), fAlpha(alpha), fPrev(nullptr), fNext(nullptr) {
484 }
485 Edge* fEdge;
486 SkPoint fPoint;
487 uint8_t fAlpha;
488 Event* fPrev;
489 Event* fNext;
490 void apply(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc);
491};
492
493bool compare(Event* const& e1, Event* const& e2) {
494 return e1->fAlpha > e2->fAlpha;
495}
496
497struct EventList : public SkTDPQueue<Event*, &compare> {};
498
499void create_event(Edge* e, EventList* events, SkArenaAlloc& alloc) {
500 Edge bisector1(e->fTop, e->fTop->fPartner, 1, Edge::Type::kConnector);
501 Edge bisector2(e->fBottom, e->fBottom->fPartner, 1, Edge::Type::kConnector);
502 SkPoint p;
503 uint8_t alpha;
504 if (bisector1.intersect(bisector2, &p, &alpha)) {
505 LOG("found overlap edge %g -> %g, will collapse to %g,%g alpha %d\n",
506 e->fTop->fID, e->fBottom->fID, p.fX, p.fY, alpha);
507 e->fEvent = alloc.make<Event>(e, p, alpha);
508 events->insert(e->fEvent);
509 }
510}
Stephen Whitee260c462017-12-19 18:09:54 -0500511
ethannicholase9709e82016-01-07 13:34:16 -0800512/***************************************************************************************/
513
514struct Poly {
senorblanco531237e2016-06-02 11:36:48 -0700515 Poly(Vertex* v, int winding)
516 : fFirstVertex(v)
517 , fWinding(winding)
ethannicholase9709e82016-01-07 13:34:16 -0800518 , fHead(nullptr)
519 , fTail(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800520 , fNext(nullptr)
521 , fPartner(nullptr)
522 , fCount(0)
523 {
524#if LOGGING_ENABLED
525 static int gID = 0;
526 fID = gID++;
527 LOG("*** created Poly %d\n", fID);
528#endif
529 }
senorblanco531237e2016-06-02 11:36:48 -0700530 typedef enum { kLeft_Side, kRight_Side } Side;
ethannicholase9709e82016-01-07 13:34:16 -0800531 struct MonotonePoly {
senorblanco531237e2016-06-02 11:36:48 -0700532 MonotonePoly(Edge* edge, Side side)
533 : fSide(side)
534 , fFirstEdge(nullptr)
535 , fLastEdge(nullptr)
ethannicholase9709e82016-01-07 13:34:16 -0800536 , fPrev(nullptr)
senorblanco531237e2016-06-02 11:36:48 -0700537 , fNext(nullptr) {
538 this->addEdge(edge);
539 }
ethannicholase9709e82016-01-07 13:34:16 -0800540 Side fSide;
senorblanco531237e2016-06-02 11:36:48 -0700541 Edge* fFirstEdge;
542 Edge* fLastEdge;
ethannicholase9709e82016-01-07 13:34:16 -0800543 MonotonePoly* fPrev;
544 MonotonePoly* fNext;
senorblanco531237e2016-06-02 11:36:48 -0700545 void addEdge(Edge* edge) {
senorblancoe6eaa322016-03-08 09:06:44 -0800546 if (fSide == kRight_Side) {
senorblanco212c7c32016-08-18 10:20:47 -0700547 SkASSERT(!edge->fUsedInRightPoly);
senorblanco531237e2016-06-02 11:36:48 -0700548 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
549 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700550 edge->fUsedInRightPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800551 } else {
senorblanco212c7c32016-08-18 10:20:47 -0700552 SkASSERT(!edge->fUsedInLeftPoly);
senorblanco531237e2016-06-02 11:36:48 -0700553 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
554 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
senorblanco70f52512016-08-17 14:56:22 -0700555 edge->fUsedInLeftPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800556 }
ethannicholase9709e82016-01-07 13:34:16 -0800557 }
558
senorblancof57372d2016-08-31 10:36:19 -0700559 void* emit(const AAParams* aaParams, void* data) {
senorblanco531237e2016-06-02 11:36:48 -0700560 Edge* e = fFirstEdge;
senorblanco531237e2016-06-02 11:36:48 -0700561 VertexList vertices;
562 vertices.append(e->fTop);
Stephen White651cbe92017-03-03 12:24:16 -0500563 int count = 1;
senorblanco531237e2016-06-02 11:36:48 -0700564 while (e != nullptr) {
senorblanco531237e2016-06-02 11:36:48 -0700565 if (kRight_Side == fSide) {
566 vertices.append(e->fBottom);
567 e = e->fRightPolyNext;
568 } else {
569 vertices.prepend(e->fBottom);
570 e = e->fLeftPolyNext;
571 }
Stephen White651cbe92017-03-03 12:24:16 -0500572 count++;
senorblanco531237e2016-06-02 11:36:48 -0700573 }
574 Vertex* first = vertices.fHead;
ethannicholase9709e82016-01-07 13:34:16 -0800575 Vertex* v = first->fNext;
senorblanco531237e2016-06-02 11:36:48 -0700576 while (v != vertices.fTail) {
ethannicholase9709e82016-01-07 13:34:16 -0800577 SkASSERT(v && v->fPrev && v->fNext);
578 Vertex* prev = v->fPrev;
579 Vertex* curr = v;
580 Vertex* next = v->fNext;
Stephen White651cbe92017-03-03 12:24:16 -0500581 if (count == 3) {
582 return emit_triangle(prev, curr, next, aaParams, data);
583 }
ethannicholase9709e82016-01-07 13:34:16 -0800584 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
585 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
586 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
587 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
588 if (ax * by - ay * bx >= 0.0) {
senorblancof57372d2016-08-31 10:36:19 -0700589 data = emit_triangle(prev, curr, next, aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800590 v->fPrev->fNext = v->fNext;
591 v->fNext->fPrev = v->fPrev;
Stephen White651cbe92017-03-03 12:24:16 -0500592 count--;
ethannicholase9709e82016-01-07 13:34:16 -0800593 if (v->fPrev == first) {
594 v = v->fNext;
595 } else {
596 v = v->fPrev;
597 }
598 } else {
599 v = v->fNext;
600 }
601 }
602 return data;
603 }
604 };
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500605 Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
senorblanco70f52512016-08-17 14:56:22 -0700606 LOG("addEdge (%g -> %g) to poly %d, %s side\n",
607 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
ethannicholase9709e82016-01-07 13:34:16 -0800608 Poly* partner = fPartner;
609 Poly* poly = this;
senorblanco212c7c32016-08-18 10:20:47 -0700610 if (side == kRight_Side) {
611 if (e->fUsedInRightPoly) {
612 return this;
613 }
614 } else {
615 if (e->fUsedInLeftPoly) {
616 return this;
617 }
618 }
ethannicholase9709e82016-01-07 13:34:16 -0800619 if (partner) {
620 fPartner = partner->fPartner = nullptr;
621 }
senorblanco531237e2016-06-02 11:36:48 -0700622 if (!fTail) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500623 fHead = fTail = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700624 fCount += 2;
senorblanco93e3fff2016-06-07 12:36:00 -0700625 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
626 return poly;
senorblanco531237e2016-06-02 11:36:48 -0700627 } else if (side == fTail->fSide) {
628 fTail->addEdge(e);
629 fCount++;
630 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500631 e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -0700632 fTail->addEdge(e);
633 fCount++;
ethannicholase9709e82016-01-07 13:34:16 -0800634 if (partner) {
senorblanco531237e2016-06-02 11:36:48 -0700635 partner->addEdge(e, side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800636 poly = partner;
637 } else {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500638 MonotonePoly* m = alloc.make<MonotonePoly>(e, side);
senorblanco531237e2016-06-02 11:36:48 -0700639 m->fPrev = fTail;
640 fTail->fNext = m;
641 fTail = m;
ethannicholase9709e82016-01-07 13:34:16 -0800642 }
643 }
ethannicholase9709e82016-01-07 13:34:16 -0800644 return poly;
645 }
senorblancof57372d2016-08-31 10:36:19 -0700646 void* emit(const AAParams* aaParams, void *data) {
ethannicholase9709e82016-01-07 13:34:16 -0800647 if (fCount < 3) {
648 return data;
649 }
650 LOG("emit() %d, size %d\n", fID, fCount);
651 for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) {
senorblancof57372d2016-08-31 10:36:19 -0700652 data = m->emit(aaParams, data);
ethannicholase9709e82016-01-07 13:34:16 -0800653 }
654 return data;
655 }
senorblanco531237e2016-06-02 11:36:48 -0700656 Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; }
657 Vertex* fFirstVertex;
ethannicholase9709e82016-01-07 13:34:16 -0800658 int fWinding;
659 MonotonePoly* fHead;
660 MonotonePoly* fTail;
ethannicholase9709e82016-01-07 13:34:16 -0800661 Poly* fNext;
662 Poly* fPartner;
663 int fCount;
664#if LOGGING_ENABLED
665 int fID;
666#endif
667};
668
669/***************************************************************************************/
670
671bool coincident(const SkPoint& a, const SkPoint& b) {
672 return a == b;
673}
674
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500675Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) {
676 Poly* poly = alloc.make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800677 poly->fNext = *head;
678 *head = poly;
679 return poly;
680}
681
Stephen White3a9aab92017-03-07 14:07:18 -0500682void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500683 Vertex* v = alloc.make<Vertex>(p, 255);
ethannicholase9709e82016-01-07 13:34:16 -0800684#if LOGGING_ENABLED
685 static float gID = 0.0f;
686 v->fID = gID++;
687#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500688 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800689}
690
Stephen White36e4f062017-03-27 16:11:31 -0400691SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
692 SkQuadCoeff quad(pts);
693 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
694 SkPoint mid = to_point(quad.eval(t));
695 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400696 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
697 return 0;
698 }
Cary Clarkdf429f32017-11-08 11:44:31 -0500699 return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1);
Stephen White36e4f062017-03-27 16:11:31 -0400700}
701
702void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour,
703 SkArenaAlloc& alloc) {
704 SkQuadCoeff quad(pts);
705 Sk2s aa = quad.fA * quad.fA;
706 SkScalar denom = 2.0f * (aa[0] + aa[1]);
707 Sk2s ab = quad.fA * quad.fB;
708 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
709 int nPoints = 1;
Stephen Whitee40c3612018-01-09 11:49:08 -0500710 SkScalar u = 1.0f;
Stephen White36e4f062017-03-27 16:11:31 -0400711 // Test possible subdivision values only at the point of maximum curvature.
712 // If it passes the flatness metric there, it'll pass everywhere.
Stephen Whitee40c3612018-01-09 11:49:08 -0500713 while (nPoints < GrPathUtils::kMaxPointsPerCurve) {
Stephen White36e4f062017-03-27 16:11:31 -0400714 u = 1.0f / nPoints;
715 if (quad_error_at(pts, t, u) < toleranceSqd) {
716 break;
717 }
718 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800719 }
Stephen White36e4f062017-03-27 16:11:31 -0400720 for (int j = 1; j <= nPoints; j++) {
721 append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc);
722 }
ethannicholase9709e82016-01-07 13:34:16 -0800723}
724
Stephen White3a9aab92017-03-07 14:07:18 -0500725void generate_cubic_points(const SkPoint& p0,
726 const SkPoint& p1,
727 const SkPoint& p2,
728 const SkPoint& p3,
729 SkScalar tolSqd,
730 VertexList* contour,
731 int pointsLeft,
732 SkArenaAlloc& alloc) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500733 SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
734 SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
ethannicholase9709e82016-01-07 13:34:16 -0800735 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
736 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Stephen White3a9aab92017-03-07 14:07:18 -0500737 append_point_to_contour(p3, contour, alloc);
738 return;
ethannicholase9709e82016-01-07 13:34:16 -0800739 }
740 const SkPoint q[] = {
741 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
742 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
743 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
744 };
745 const SkPoint r[] = {
746 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
747 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
748 };
749 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
750 pointsLeft >>= 1;
Stephen White3a9aab92017-03-07 14:07:18 -0500751 generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc);
752 generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800753}
754
755// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
756
757void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen White3a9aab92017-03-07 14:07:18 -0500758 VertexList* contours, SkArenaAlloc& alloc, bool *isLinear) {
ethannicholase9709e82016-01-07 13:34:16 -0800759 SkScalar toleranceSqd = tolerance * tolerance;
760
761 SkPoint pts[4];
ethannicholase9709e82016-01-07 13:34:16 -0800762 *isLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500763 VertexList* contour = contours;
ethannicholase9709e82016-01-07 13:34:16 -0800764 SkPath::Iter iter(path, false);
ethannicholase9709e82016-01-07 13:34:16 -0800765 if (path.isInverseFillType()) {
766 SkPoint quad[4];
767 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700768 for (int i = 3; i >= 0; i--) {
Stephen White3a9aab92017-03-07 14:07:18 -0500769 append_point_to_contour(quad[i], contours, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800770 }
Stephen White3a9aab92017-03-07 14:07:18 -0500771 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800772 }
773 SkAutoConicToQuads converter;
Stephen White3a9aab92017-03-07 14:07:18 -0500774 SkPath::Verb verb;
Stephen White2cee2832017-08-23 09:37:16 -0400775 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800776 switch (verb) {
777 case SkPath::kConic_Verb: {
778 SkScalar weight = iter.conicWeight();
779 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
780 for (int i = 0; i < converter.countQuads(); ++i) {
Stephen White36e4f062017-03-27 16:11:31 -0400781 append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800782 quadPts += 2;
783 }
784 *isLinear = false;
785 break;
786 }
787 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500788 if (contour->fHead) {
789 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800790 }
Stephen White3a9aab92017-03-07 14:07:18 -0500791 append_point_to_contour(pts[0], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800792 break;
793 case SkPath::kLine_Verb: {
Stephen White3a9aab92017-03-07 14:07:18 -0500794 append_point_to_contour(pts[1], contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800795 break;
796 }
797 case SkPath::kQuad_Verb: {
Stephen White36e4f062017-03-27 16:11:31 -0400798 append_quadratic_to_contour(pts, toleranceSqd, contour, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800799 *isLinear = false;
800 break;
801 }
802 case SkPath::kCubic_Verb: {
803 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Stephen White3a9aab92017-03-07 14:07:18 -0500804 generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
805 pointsLeft, alloc);
ethannicholase9709e82016-01-07 13:34:16 -0800806 *isLinear = false;
807 break;
808 }
809 case SkPath::kClose_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800810 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800811 break;
812 }
813 }
814}
815
Stephen White49789062017-02-21 10:35:49 -0500816inline bool apply_fill_type(SkPath::FillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800817 switch (fillType) {
818 case SkPath::kWinding_FillType:
819 return winding != 0;
820 case SkPath::kEvenOdd_FillType:
821 return (winding & 1) != 0;
822 case SkPath::kInverseWinding_FillType:
senorblanco7ab96e92016-10-12 06:47:44 -0700823 return winding == 1;
ethannicholase9709e82016-01-07 13:34:16 -0800824 case SkPath::kInverseEvenOdd_FillType:
825 return (winding & 1) == 1;
826 default:
827 SkASSERT(false);
828 return false;
829 }
830}
831
Stephen White49789062017-02-21 10:35:49 -0500832inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) {
833 return poly && apply_fill_type(fillType, poly->fWinding);
834}
835
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500836Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) {
Stephen White2f4686f2017-01-03 16:20:01 -0500837 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800838 Vertex* top = winding < 0 ? next : prev;
839 Vertex* bottom = winding < 0 ? prev : next;
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500840 return alloc.make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800841}
842
843void remove_edge(Edge* edge, EdgeList* edges) {
844 LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700845 SkASSERT(edges->contains(edge));
846 edges->remove(edge);
ethannicholase9709e82016-01-07 13:34:16 -0800847}
848
849void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) {
850 LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
senorblancof57372d2016-08-31 10:36:19 -0700851 SkASSERT(!edges->contains(edge));
ethannicholase9709e82016-01-07 13:34:16 -0800852 Edge* next = prev ? prev->fRight : edges->fHead;
senorblancof57372d2016-08-31 10:36:19 -0700853 edges->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800854}
855
856void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500857 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800858 *left = v->fFirstEdgeAbove->fLeft;
859 *right = v->fLastEdgeAbove->fRight;
860 return;
861 }
862 Edge* next = nullptr;
863 Edge* prev;
864 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
865 if (prev->isLeftOf(v)) {
866 break;
867 }
868 next = prev;
869 }
870 *left = prev;
871 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800872}
873
ethannicholase9709e82016-01-07 13:34:16 -0800874void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) {
875 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500876 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800877 return;
878 }
879 LOG("insert edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
880 Edge* prev = nullptr;
881 Edge* next;
882 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
883 if (next->isRightOf(edge->fTop)) {
884 break;
885 }
886 prev = next;
887 }
senorblancoe6eaa322016-03-08 09:06:44 -0800888 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800889 edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
890}
891
892void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) {
893 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500894 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800895 return;
896 }
897 LOG("insert edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID, v->fID);
898 Edge* prev = nullptr;
899 Edge* next;
900 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
901 if (next->isRightOf(edge->fBottom)) {
902 break;
903 }
904 prev = next;
905 }
senorblancoe6eaa322016-03-08 09:06:44 -0800906 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800907 edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
908}
909
910void remove_edge_above(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400911 SkASSERT(edge->fTop && edge->fBottom);
ethannicholase9709e82016-01-07 13:34:16 -0800912 LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
913 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800914 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800915 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
916}
917
918void remove_edge_below(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400919 SkASSERT(edge->fTop && edge->fBottom);
ethannicholase9709e82016-01-07 13:34:16 -0800920 LOG("removing edge (%g -> %g) below vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
921 edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800922 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800923 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
924}
925
Stephen Whitee7a364d2017-01-11 16:19:26 -0500926void disconnect(Edge* edge)
927{
ethannicholase9709e82016-01-07 13:34:16 -0800928 remove_edge_above(edge);
929 remove_edge_below(edge);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500930}
931
Stephen White3b5a3fa2017-06-06 14:51:19 -0400932void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c);
933
934void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c) {
935 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
936 return;
937 }
938 Vertex* v = *current;
939 LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
940 while (v != dst) {
941 v = v->fPrev;
942 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
943 remove_edge(e, activeEdges);
944 }
945 Edge* leftEdge = v->fLeftEnclosingEdge;
946 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
947 insert_edge(e, leftEdge, activeEdges);
948 leftEdge = e;
949 }
950 }
951 *current = v;
952}
953
954void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
955 if (!activeEdges || !current) {
956 return;
957 }
958 Vertex* top = edge->fTop;
959 Vertex* bottom = edge->fBottom;
960 if (edge->fLeft) {
961 Vertex* leftTop = edge->fLeft->fTop;
962 Vertex* leftBottom = edge->fLeft->fBottom;
963 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
964 rewind(activeEdges, current, leftTop, c);
965 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
966 rewind(activeEdges, current, top, c);
967 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
968 !edge->fLeft->isLeftOf(bottom)) {
969 rewind(activeEdges, current, leftTop, c);
970 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
971 rewind(activeEdges, current, top, c);
972 }
973 }
974 if (edge->fRight) {
975 Vertex* rightTop = edge->fRight->fTop;
976 Vertex* rightBottom = edge->fRight->fBottom;
977 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
978 rewind(activeEdges, current, rightTop, c);
979 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
980 rewind(activeEdges, current, top, c);
981 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
982 !edge->fRight->isRightOf(bottom)) {
983 rewind(activeEdges, current, rightTop, c);
984 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
985 !edge->isLeftOf(rightBottom)) {
986 rewind(activeEdges, current, top, c);
987 }
ethannicholase9709e82016-01-07 13:34:16 -0800988 }
989}
990
Stephen White3b5a3fa2017-06-06 14:51:19 -0400991void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800992 remove_edge_below(edge);
993 edge->fTop = v;
994 edge->recompute();
995 insert_edge_below(edge, v, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400996 rewind_if_necessary(edge, activeEdges, current, c);
997 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800998}
999
Stephen White3b5a3fa2017-06-06 14:51:19 -04001000void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -08001001 remove_edge_above(edge);
1002 edge->fBottom = v;
1003 edge->recompute();
1004 insert_edge_above(edge, v, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001005 rewind_if_necessary(edge, activeEdges, current, c);
1006 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001007}
1008
Stephen White3b5a3fa2017-06-06 14:51:19 -04001009void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
1010 Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -08001011 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
1012 LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
1013 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
1014 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001015 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -08001016 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001017 disconnect(edge);
Stephen Whiteec79c392018-05-18 11:49:21 -04001018 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001019 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001020 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -08001021 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001022 set_bottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001023 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001024 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -08001025 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001026 set_bottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001027 }
1028}
1029
Stephen White3b5a3fa2017-06-06 14:51:19 -04001030void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
1031 Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -08001032 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
1033 LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
1034 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
1035 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001036 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -08001037 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001038 disconnect(edge);
Stephen Whiteec79c392018-05-18 11:49:21 -04001039 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001040 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001041 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -08001042 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001043 set_top(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001044 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001045 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -08001046 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001047 set_top(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001048 }
1049}
1050
Stephen White3b5a3fa2017-06-06 14:51:19 -04001051void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) {
Stephen White6eca90f2017-05-25 14:47:11 -04001052 for (;;) {
1053 if (edge->fPrevEdgeAbove && (edge->fTop == edge->fPrevEdgeAbove->fTop ||
1054 !edge->fPrevEdgeAbove->isLeftOf(edge->fTop))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001055 merge_edges_above(edge, edge->fPrevEdgeAbove, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -04001056 } else if (edge->fNextEdgeAbove && (edge->fTop == edge->fNextEdgeAbove->fTop ||
1057 !edge->isLeftOf(edge->fNextEdgeAbove->fTop))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001058 merge_edges_above(edge, edge->fNextEdgeAbove, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -04001059 } else if (edge->fPrevEdgeBelow && (edge->fBottom == edge->fPrevEdgeBelow->fBottom ||
1060 !edge->fPrevEdgeBelow->isLeftOf(edge->fBottom))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001061 merge_edges_below(edge, edge->fPrevEdgeBelow, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -04001062 } else if (edge->fNextEdgeBelow && (edge->fBottom == edge->fNextEdgeBelow->fBottom ||
1063 !edge->isLeftOf(edge->fNextEdgeBelow->fBottom))) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001064 merge_edges_below(edge, edge->fNextEdgeBelow, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -04001065 } else {
1066 break;
1067 }
ethannicholase9709e82016-01-07 13:34:16 -08001068 }
Stephen White6eca90f2017-05-25 14:47:11 -04001069 SkASSERT(!edge->fPrevEdgeAbove || edge->fPrevEdgeAbove->isLeftOf(edge->fTop));
1070 SkASSERT(!edge->fPrevEdgeBelow || edge->fPrevEdgeBelow->isLeftOf(edge->fBottom));
1071 SkASSERT(!edge->fNextEdgeAbove || edge->fNextEdgeAbove->isRightOf(edge->fTop));
1072 SkASSERT(!edge->fNextEdgeBelow || edge->fNextEdgeBelow->isRightOf(edge->fBottom));
ethannicholase9709e82016-01-07 13:34:16 -08001073}
1074
Stephen White3b5a3fa2017-06-06 14:51:19 -04001075void split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c,
1076 SkArenaAlloc& alloc) {
Stephen Whiteec79c392018-05-18 11:49:21 -04001077 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
Stephen White0cb31672017-06-08 14:41:01 -04001078 return;
1079 }
ethannicholase9709e82016-01-07 13:34:16 -08001080 LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
1081 edge->fTop->fID, edge->fBottom->fID,
1082 v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001083 Vertex* top;
1084 Vertex* bottom;
ethannicholase9709e82016-01-07 13:34:16 -08001085 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001086 top = v;
1087 bottom = edge->fTop;
1088 set_top(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -05001089 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001090 top = edge->fBottom;
1091 bottom = v;
1092 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001093 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001094 top = v;
1095 bottom = edge->fBottom;
1096 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001097 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001098 Edge* newEdge = alloc.make<Edge>(top, bottom, edge->fWinding, edge->fType);
1099 insert_edge_below(newEdge, top, c);
1100 insert_edge_above(newEdge, bottom, c);
1101 merge_collinear_edges(newEdge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001102}
1103
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001104Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc,
Stephen White48ded382017-02-03 10:15:16 -05001105 int winding_scale = 1) {
Stephen Whitee260c462017-12-19 18:09:54 -05001106 if (!prev || !next || prev->fPoint == next->fPoint) {
1107 return nullptr;
1108 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001109 Edge* edge = new_edge(prev, next, type, c, alloc);
Stephen White8a0bfc52017-02-21 15:24:13 -05001110 insert_edge_below(edge, edge->fTop, c);
1111 insert_edge_above(edge, edge->fBottom, c);
Stephen White48ded382017-02-03 10:15:16 -05001112 edge->fWinding *= winding_scale;
Stephen White3b5a3fa2017-06-06 14:51:19 -04001113 merge_collinear_edges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -07001114 return edge;
1115}
1116
Stephen Whitebf6137e2017-01-04 15:43:26 -05001117void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001118 SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001119 LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY,
1120 src->fID, dst->fID);
senorblancof57372d2016-08-31 10:36:19 -07001121 dst->fAlpha = SkTMax(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -04001122 if (src->fPartner) {
1123 src->fPartner->fPartner = dst;
1124 }
Stephen White7b376942018-05-22 11:51:32 -04001125 while (Edge* edge = src->fFirstEdgeAbove) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001126 set_bottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -08001127 }
Stephen White7b376942018-05-22 11:51:32 -04001128 while (Edge* edge = src->fFirstEdgeBelow) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001129 set_top(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -08001130 }
Stephen Whitebf6137e2017-01-04 15:43:26 -05001131 mesh->remove(src);
ethannicholase9709e82016-01-07 13:34:16 -08001132}
1133
Ravi Mistrybfe95982018-05-29 18:19:07 +00001134bool out_of_range_and_collinear(const SkPoint& p, Edge* edge, Comparator& c) {
1135 if (c.sweep_lt(p, edge->fTop->fPoint) &&
1136 !Line(p, edge->fBottom->fPoint).dist(edge->fTop->fPoint)) {
1137 return true;
1138 } else if (c.sweep_lt(edge->fBottom->fPoint, p) &&
1139 !Line(edge->fTop->fPoint, p).dist(edge->fBottom->fPoint)) {
1140 return true;
1141 }
1142 return false;
1143}
1144
Stephen White95152e12017-12-18 10:52:44 -05001145Vertex* create_sorted_vertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
1146 Vertex* reference, Comparator& c, SkArenaAlloc& alloc) {
1147 Vertex* prevV = reference;
1148 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
1149 prevV = prevV->fPrev;
1150 }
1151 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
1152 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
1153 prevV = nextV;
1154 nextV = nextV->fNext;
1155 }
1156 Vertex* v;
1157 if (prevV && coincident(prevV->fPoint, p)) {
1158 v = prevV;
1159 } else if (nextV && coincident(nextV->fPoint, p)) {
1160 v = nextV;
1161 } else {
1162 v = alloc.make<Vertex>(p, alpha);
1163#if LOGGING_ENABLED
1164 if (!prevV) {
1165 v->fID = mesh->fHead->fID - 1.0f;
1166 } else if (!nextV) {
1167 v->fID = mesh->fTail->fID + 1.0f;
1168 } else {
1169 v->fID = (prevV->fID + nextV->fID) * 0.5f;
1170 }
1171#endif
1172 mesh->insert(v, prevV, nextV);
1173 }
1174 return v;
1175}
1176
Stephen White3b5a3fa2017-06-06 14:51:19 -04001177bool check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Stephen White0cb31672017-06-08 14:41:01 -04001178 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001179 if (!edge || !other) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001180 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001181 }
Stephen White56158ae2017-01-30 14:31:31 -05001182 SkPoint p;
1183 uint8_t alpha;
Stephen Whitee3a0be72017-06-12 11:43:18 -04001184 if (edge->intersect(*other, &p, &alpha) && p.isFinite()) {
Ravi Mistrybfe95982018-05-29 18:19:07 +00001185 // Ignore any out-of-range intersections which are also collinear,
1186 // since the resulting edges would cancel each other out by merging.
1187 if (out_of_range_and_collinear(p, edge, c) ||
1188 out_of_range_and_collinear(p, other, c)) {
1189 return false;
1190 }
1191 Vertex* v;
ethannicholase9709e82016-01-07 13:34:16 -08001192 LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001193 Vertex* top = *current;
1194 // If the intersection point is above the current vertex, rewind to the vertex above the
1195 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -04001196 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001197 top = top->fPrev;
1198 }
Ravi Mistrybfe95982018-05-29 18:19:07 +00001199 if (p == edge->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001200 v = edge->fTop;
Ravi Mistrybfe95982018-05-29 18:19:07 +00001201 } else if (p == edge->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001202 v = edge->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +00001203 } else if (p == other->fTop->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001204 v = other->fTop;
Ravi Mistrybfe95982018-05-29 18:19:07 +00001205 } else if (p == other->fBottom->fPoint) {
ethannicholase9709e82016-01-07 13:34:16 -08001206 v = other->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +00001207 } else {
Stephen White95152e12017-12-18 10:52:44 -05001208 v = create_sorted_vertex(p, alpha, mesh, top, c, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05001209 if (edge->fTop->fPartner) {
1210 Line line1 = edge->fLine;
1211 Line line2 = other->fLine;
1212 int dir = edge->fType == Edge::Type::kOuter ? -1 : 1;
1213 line1.fC += sqrt(edge->fLine.magSq()) * (edge->fWinding > 0 ? 1 : -1) * dir;
1214 line2.fC += sqrt(other->fLine.magSq()) * (other->fWinding > 0 ? 1 : -1) * dir;
1215 SkPoint p;
1216 if (line1.intersect(line2, &p)) {
1217 LOG("synthesizing partner (%g,%g) for intersection vertex %g\n",
1218 p.fX, p.fY, v->fID);
1219 v->fPartner = alloc.make<Vertex>(p, 255 - v->fAlpha);
1220 }
1221 }
ethannicholase9709e82016-01-07 13:34:16 -08001222 }
Stephen White0cb31672017-06-08 14:41:01 -04001223 rewind(activeEdges, current, top ? top : v, c);
1224 split_edge(edge, v, activeEdges, current, c, alloc);
1225 split_edge(other, v, activeEdges, current, c, alloc);
Stephen White92eba8a2017-02-06 09:50:27 -05001226 v->fAlpha = SkTMax(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001227 return true;
ethannicholase9709e82016-01-07 13:34:16 -08001228 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001229 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001230}
1231
Stephen White3a9aab92017-03-07 14:07:18 -05001232void sanitize_contours(VertexList* contours, int contourCnt, bool approximate) {
1233 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1234 SkASSERT(contour->fHead);
1235 Vertex* prev = contour->fTail;
Stephen White5926f2d2017-02-13 13:55:42 -05001236 if (approximate) {
Stephen White3a9aab92017-03-07 14:07:18 -05001237 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -05001238 }
Stephen White3a9aab92017-03-07 14:07:18 -05001239 for (Vertex* v = contour->fHead; v;) {
senorblancof57372d2016-08-31 10:36:19 -07001240 if (approximate) {
1241 round(&v->fPoint);
1242 }
Stephen White3a9aab92017-03-07 14:07:18 -05001243 Vertex* next = v->fNext;
1244 if (coincident(prev->fPoint, v->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -08001245 LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001246 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -04001247 } else if (!v->fPoint.isFinite()) {
1248 LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
1249 contour->remove(v);
Stephen White06768ca2018-05-25 14:50:56 -04001250 } else if (next && Line(prev->fPoint, next->fPoint).dist(v->fPoint) == 0.0) {
1251 LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
1252 contour->remove(v);
1253 } else {
1254 prev = v;
ethannicholase9709e82016-01-07 13:34:16 -08001255 }
Stephen White3a9aab92017-03-07 14:07:18 -05001256 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001257 }
1258 }
1259}
1260
Stephen Whitee260c462017-12-19 18:09:54 -05001261bool merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001262 if (!mesh->fHead) {
Stephen Whitee260c462017-12-19 18:09:54 -05001263 return false;
Stephen Whitebda29c02017-03-13 15:10:13 -04001264 }
Stephen Whitee260c462017-12-19 18:09:54 -05001265 bool merged = false;
1266 for (Vertex* v = mesh->fHead->fNext; v;) {
1267 Vertex* next = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -08001268 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1269 v->fPoint = v->fPrev->fPoint;
1270 }
1271 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Stephen Whitee260c462017-12-19 18:09:54 -05001272 merge_vertices(v, v->fPrev, mesh, c, alloc);
1273 merged = true;
ethannicholase9709e82016-01-07 13:34:16 -08001274 }
Stephen Whitee260c462017-12-19 18:09:54 -05001275 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001276 }
Stephen Whitee260c462017-12-19 18:09:54 -05001277 return merged;
ethannicholase9709e82016-01-07 13:34:16 -08001278}
1279
1280// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1281
Stephen White3a9aab92017-03-07 14:07:18 -05001282void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001283 SkArenaAlloc& alloc) {
Stephen White3a9aab92017-03-07 14:07:18 -05001284 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1285 Vertex* prev = contour->fTail;
1286 for (Vertex* v = contour->fHead; v;) {
1287 Vertex* next = v->fNext;
1288 connect(prev, v, Edge::Type::kInner, c, alloc);
1289 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001290 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001291 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001292 }
1293 }
ethannicholase9709e82016-01-07 13:34:16 -08001294}
1295
Stephen Whitee260c462017-12-19 18:09:54 -05001296void connect_partners(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
1297 for (Vertex* outer = mesh->fHead; outer; outer = outer->fNext) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001298 if (Vertex* inner = outer->fPartner) {
Stephen Whitee260c462017-12-19 18:09:54 -05001299 if ((inner->fPrev || inner->fNext) && (outer->fPrev || outer->fNext)) {
1300 // Connector edges get zero winding, since they're only structural (i.e., to ensure
1301 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding
1302 // number.
1303 connect(outer, inner, Edge::Type::kConnector, c, alloc, 0);
1304 inner->fPartner = outer->fPartner = nullptr;
1305 }
Stephen Whitebda29c02017-03-13 15:10:13 -04001306 }
1307 }
1308}
1309
1310template <CompareFunc sweep_lt>
1311void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
1312 Vertex* a = front->fHead;
1313 Vertex* b = back->fHead;
1314 while (a && b) {
1315 if (sweep_lt(a->fPoint, b->fPoint)) {
1316 front->remove(a);
1317 result->append(a);
1318 a = front->fHead;
1319 } else {
1320 back->remove(b);
1321 result->append(b);
1322 b = back->fHead;
1323 }
1324 }
1325 result->append(*front);
1326 result->append(*back);
1327}
1328
1329void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) {
1330 if (c.fDirection == Comparator::Direction::kHorizontal) {
1331 sorted_merge<sweep_lt_horiz>(front, back, result);
1332 } else {
1333 sorted_merge<sweep_lt_vert>(front, back, result);
1334 }
Stephen White3b5a3fa2017-06-06 14:51:19 -04001335#if LOGGING_ENABLED
1336 float id = 0.0f;
1337 for (Vertex* v = result->fHead; v; v = v->fNext) {
1338 v->fID = id++;
1339 }
1340#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001341}
1342
ethannicholase9709e82016-01-07 13:34:16 -08001343// Stage 3: sort the vertices by increasing sweep direction.
1344
Stephen White16a40cb2017-02-23 11:10:01 -05001345template <CompareFunc sweep_lt>
1346void merge_sort(VertexList* vertices) {
1347 Vertex* slow = vertices->fHead;
1348 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001349 return;
1350 }
Stephen White16a40cb2017-02-23 11:10:01 -05001351 Vertex* fast = slow->fNext;
1352 if (!fast) {
1353 return;
1354 }
1355 do {
1356 fast = fast->fNext;
1357 if (fast) {
1358 fast = fast->fNext;
1359 slow = slow->fNext;
1360 }
1361 } while (fast);
1362 VertexList front(vertices->fHead, slow);
1363 VertexList back(slow->fNext, vertices->fTail);
1364 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001365
Stephen White16a40cb2017-02-23 11:10:01 -05001366 merge_sort<sweep_lt>(&front);
1367 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001368
Stephen White16a40cb2017-02-23 11:10:01 -05001369 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001370 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001371}
1372
Stephen White95152e12017-12-18 10:52:44 -05001373void dump_mesh(const VertexList& mesh) {
1374#if LOGGING_ENABLED
1375 for (Vertex* v = mesh.fHead; v; v = v->fNext) {
1376 LOG("vertex %g (%g, %g) alpha %d", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
1377 if (Vertex* p = v->fPartner) {
1378 LOG(", partner %g (%g, %g) alpha %d\n", p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha);
1379 } else {
1380 LOG(", null partner\n");
1381 }
1382 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1383 LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
1384 }
1385 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1386 LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
1387 }
1388 }
1389#endif
1390}
1391
ethannicholase9709e82016-01-07 13:34:16 -08001392// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1393
Stephen Whitee260c462017-12-19 18:09:54 -05001394bool simplify(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001395 LOG("simplifying complex polygons\n");
1396 EdgeList activeEdges;
Stephen Whitee260c462017-12-19 18:09:54 -05001397 bool found = false;
Stephen White0cb31672017-06-08 14:41:01 -04001398 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001399 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1400 continue;
1401 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001402 Edge* leftEnclosingEdge;
1403 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001404 bool restartChecks;
1405 do {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001406 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001407 restartChecks = false;
1408 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001409 v->fLeftEnclosingEdge = leftEnclosingEdge;
1410 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001411 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001412 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Stephen White0cb31672017-06-08 14:41:01 -04001413 if (check_for_intersection(edge, leftEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001414 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001415 restartChecks = true;
1416 break;
1417 }
Stephen White0cb31672017-06-08 14:41:01 -04001418 if (check_for_intersection(edge, rightEnclosingEdge, &activeEdges, &v, mesh, c,
Stephen White3b5a3fa2017-06-06 14:51:19 -04001419 alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001420 restartChecks = true;
1421 break;
1422 }
1423 }
1424 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001425 if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge,
Stephen White0cb31672017-06-08 14:41:01 -04001426 &activeEdges, &v, mesh, c, alloc)) {
ethannicholase9709e82016-01-07 13:34:16 -08001427 restartChecks = true;
1428 }
1429
1430 }
Stephen Whitee260c462017-12-19 18:09:54 -05001431 found = found || restartChecks;
ethannicholase9709e82016-01-07 13:34:16 -08001432 } while (restartChecks);
1433 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1434 remove_edge(e, &activeEdges);
1435 }
1436 Edge* leftEdge = leftEnclosingEdge;
1437 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1438 insert_edge(e, leftEdge, &activeEdges);
1439 leftEdge = e;
1440 }
ethannicholase9709e82016-01-07 13:34:16 -08001441 }
Stephen Whitee260c462017-12-19 18:09:54 -05001442 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
1443 return found;
ethannicholase9709e82016-01-07 13:34:16 -08001444}
1445
1446// Stage 5: Tessellate the simplified mesh into monotone polygons.
1447
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001448Poly* tessellate(const VertexList& vertices, SkArenaAlloc& alloc) {
Stephen White95152e12017-12-18 10:52:44 -05001449 LOG("\ntessellating simple polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001450 EdgeList activeEdges;
1451 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001452 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001453 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1454 continue;
1455 }
1456#if LOGGING_ENABLED
senorblancof57372d2016-08-31 10:36:19 -07001457 LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001458#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001459 Edge* leftEnclosingEdge;
1460 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001461 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001462 Poly* leftPoly;
1463 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001464 if (v->fFirstEdgeAbove) {
1465 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1466 rightPoly = v->fLastEdgeAbove->fRightPoly;
1467 } else {
1468 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1469 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1470 }
1471#if LOGGING_ENABLED
1472 LOG("edges above:\n");
1473 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1474 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1475 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1476 }
1477 LOG("edges below:\n");
1478 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1479 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1480 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1481 }
1482#endif
1483 if (v->fFirstEdgeAbove) {
1484 if (leftPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001485 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001486 }
1487 if (rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001488 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001489 }
1490 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001491 Edge* rightEdge = e->fNextEdgeAbove;
Stephen White8a0bfc52017-02-21 15:24:13 -05001492 remove_edge(e, &activeEdges);
1493 if (e->fRightPoly) {
1494 e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001495 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001496 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001497 rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001498 }
1499 }
1500 remove_edge(v->fLastEdgeAbove, &activeEdges);
1501 if (!v->fFirstEdgeBelow) {
1502 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1503 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1504 rightPoly->fPartner = leftPoly;
1505 leftPoly->fPartner = rightPoly;
1506 }
1507 }
1508 }
1509 if (v->fFirstEdgeBelow) {
1510 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001511 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001512 if (leftPoly == rightPoly) {
1513 if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) {
1514 leftPoly = new_poly(&polys, leftPoly->lastVertex(),
1515 leftPoly->fWinding, alloc);
1516 leftEnclosingEdge->fRightPoly = leftPoly;
1517 } else {
1518 rightPoly = new_poly(&polys, rightPoly->lastVertex(),
1519 rightPoly->fWinding, alloc);
1520 rightEnclosingEdge->fLeftPoly = rightPoly;
1521 }
ethannicholase9709e82016-01-07 13:34:16 -08001522 }
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001523 Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner);
senorblanco531237e2016-06-02 11:36:48 -07001524 leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc);
1525 rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08001526 }
1527 }
1528 Edge* leftEdge = v->fFirstEdgeBelow;
1529 leftEdge->fLeftPoly = leftPoly;
1530 insert_edge(leftEdge, leftEnclosingEdge, &activeEdges);
1531 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1532 rightEdge = rightEdge->fNextEdgeBelow) {
1533 insert_edge(rightEdge, leftEdge, &activeEdges);
1534 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1535 winding += leftEdge->fWinding;
1536 if (winding != 0) {
1537 Poly* poly = new_poly(&polys, v, winding, alloc);
1538 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1539 }
1540 leftEdge = rightEdge;
1541 }
1542 v->fLastEdgeBelow->fRightPoly = rightPoly;
1543 }
1544#if LOGGING_ENABLED
1545 LOG("\nactive edges:\n");
1546 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
1547 LOG("%g -> %g, lpoly %d, rpoly %d\n", e->fTop->fID, e->fBottom->fID,
1548 e->fLeftPoly ? e->fLeftPoly->fID : -1, e->fRightPoly ? e->fRightPoly->fID : -1);
1549 }
1550#endif
1551 }
1552 return polys;
1553}
1554
Stephen Whitebf6137e2017-01-04 15:43:26 -05001555void remove_non_boundary_edges(const VertexList& mesh, SkPath::FillType fillType,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001556 SkArenaAlloc& alloc) {
Stephen White49789062017-02-21 10:35:49 -05001557 LOG("removing non-boundary edges\n");
1558 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001559 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
Stephen White49789062017-02-21 10:35:49 -05001560 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1561 continue;
1562 }
1563 Edge* leftEnclosingEdge;
1564 Edge* rightEnclosingEdge;
1565 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1566 bool prevFilled = leftEnclosingEdge &&
1567 apply_fill_type(fillType, leftEnclosingEdge->fWinding);
1568 for (Edge* e = v->fFirstEdgeAbove; e;) {
1569 Edge* next = e->fNextEdgeAbove;
1570 remove_edge(e, &activeEdges);
1571 bool filled = apply_fill_type(fillType, e->fWinding);
1572 if (filled == prevFilled) {
Stephen Whitee7a364d2017-01-11 16:19:26 -05001573 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001574 }
Stephen White49789062017-02-21 10:35:49 -05001575 prevFilled = filled;
senorblancof57372d2016-08-31 10:36:19 -07001576 e = next;
1577 }
Stephen White49789062017-02-21 10:35:49 -05001578 Edge* prev = leftEnclosingEdge;
1579 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1580 if (prev) {
1581 e->fWinding += prev->fWinding;
1582 }
1583 insert_edge(e, prev, &activeEdges);
1584 prev = e;
1585 }
senorblancof57372d2016-08-31 10:36:19 -07001586 }
senorblancof57372d2016-08-31 10:36:19 -07001587}
1588
Stephen White66412122017-03-01 11:48:27 -05001589// Note: this is the normal to the edge, but not necessarily unit length.
senorblancof57372d2016-08-31 10:36:19 -07001590void get_edge_normal(const Edge* e, SkVector* normal) {
Stephen Whitee260c462017-12-19 18:09:54 -05001591 normal->set(SkDoubleToScalar(e->fLine.fA),
1592 SkDoubleToScalar(e->fLine.fB));
senorblancof57372d2016-08-31 10:36:19 -07001593}
1594
Stephen Whitee260c462017-12-19 18:09:54 -05001595void reconnect(Edge* edge, Vertex* src, Vertex* dst, Comparator& c) {
1596 disconnect(edge);
1597 if (src == edge->fTop) {
1598 edge->fTop = dst;
1599 } else {
1600 SkASSERT(src == edge->fBottom);
1601 edge->fBottom = dst;
1602 }
1603 if (edge->fEvent) {
1604 edge->fEvent->fEdge = nullptr;
1605 }
1606 if (edge->fTop == edge->fBottom) {
1607 return;
1608 }
1609 if (c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
1610 SkTSwap(edge->fTop, edge->fBottom);
1611 edge->fWinding *= -1;
1612 }
1613 edge->recompute();
1614 insert_edge_below(edge, edge->fTop, c);
1615 insert_edge_above(edge, edge->fBottom, c);
1616 merge_collinear_edges(edge, nullptr, nullptr, c);
1617}
Stephen Whitee260c462017-12-19 18:09:54 -05001618
senorblancof57372d2016-08-31 10:36:19 -07001619// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
1620// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
1621// invert on stroking.
1622
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001623void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) {
senorblancof57372d2016-08-31 10:36:19 -07001624 Edge* prevEdge = boundary->fTail;
1625 SkVector prevNormal;
1626 get_edge_normal(prevEdge, &prevNormal);
1627 for (Edge* e = boundary->fHead; e != nullptr;) {
1628 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
1629 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
1630 double dist = e->dist(prev->fPoint);
1631 SkVector normal;
1632 get_edge_normal(e, &normal);
Stephen Whitee260c462017-12-19 18:09:54 -05001633 double denom = 0.0625f;
senorblancof57372d2016-08-31 10:36:19 -07001634 if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001635 Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05001636 if (prev->fPoint != next->fPoint) {
1637 join->fLine.normalize();
1638 join->fLine = join->fLine * join->fWinding;
1639 }
senorblancof57372d2016-08-31 10:36:19 -07001640 insert_edge(join, e, boundary);
1641 remove_edge(prevEdge, boundary);
1642 remove_edge(e, boundary);
1643 if (join->fLeft && join->fRight) {
1644 prevEdge = join->fLeft;
1645 e = join;
1646 } else {
1647 prevEdge = boundary->fTail;
1648 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
1649 }
1650 get_edge_normal(prevEdge, &prevNormal);
1651 } else {
1652 prevEdge = e;
1653 prevNormal = normal;
1654 e = e->fRight;
1655 }
1656 }
1657}
1658
Stephen Whitee260c462017-12-19 18:09:54 -05001659void reconnect_all_overlap_edges(Vertex* src, Vertex* dst, Edge* current, Comparator& c) {
1660 if (src->fPartner) {
1661 src->fPartner->fPartner = dst;
1662 }
1663 for (Edge* e = src->fFirstEdgeAbove; e; ) {
1664 Edge* next = e->fNextEdgeAbove;
1665 if (e->fOverlap && e != current) {
1666 reconnect(e, src, dst, c);
1667 }
1668 e = next;
1669 }
1670 for (Edge* e = src->fFirstEdgeBelow; e; ) {
1671 Edge* next = e->fNextEdgeBelow;
1672 if (e->fOverlap && e != current) {
1673 reconnect(e, src, dst, c);
1674 }
1675 e = next;
1676 }
1677}
1678
1679void Event::apply(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
1680 if (!fEdge) {
1681 return;
1682 }
1683 Vertex* top = fEdge->fTop;
1684 Vertex* bottom = fEdge->fBottom;
1685 Vertex* dest = create_sorted_vertex(fPoint, fAlpha, mesh, fEdge->fTop, c, alloc);
1686 LOG("collapsing edge %g -> %g to %g (%g, %g) alpha %d\n",
1687 top->fID, bottom->fID, dest->fID, fPoint.fX, fPoint.fY, fAlpha);
1688 reconnect_all_overlap_edges(top, dest, fEdge, c);
1689 reconnect_all_overlap_edges(bottom, dest, fEdge, c);
1690
1691 // Since the destination has multiple partners, give it none.
1692 dest->fPartner = nullptr;
1693 disconnect(fEdge);
1694
1695 // If top still has some connected edges, set its partner to dest.
1696 top->fPartner = top->fFirstEdgeAbove || top->fFirstEdgeBelow ? dest : nullptr;
1697
1698 // If bottom still has some connected edges, set its partner to dest.
1699 bottom->fPartner = bottom->fFirstEdgeAbove || bottom->fFirstEdgeBelow ? dest : nullptr;
1700}
1701
1702bool is_overlap_edge(Edge* e) {
1703 if (e->fType == Edge::Type::kOuter) {
1704 return e->fWinding != 0 && e->fWinding != 1;
1705 } else if (e->fType == Edge::Type::kInner) {
1706 return e->fWinding != 0 && e->fWinding != -2;
1707 } else {
1708 return false;
1709 }
1710}
1711
1712// This is a stripped-down version of tessellate() which computes edges which
1713// join two filled regions, which represent overlap regions, and collapses them.
1714bool collapse_overlap_regions(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
1715 LOG("\nfinding overlap regions\n");
1716 EdgeList activeEdges;
1717 EventList events;
1718 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
1719 if (!v->fFirstEdgeAbove && !v->fFirstEdgeBelow) {
1720 continue;
1721 }
1722 Edge* leftEnclosingEdge;
1723 Edge* rightEnclosingEdge;
1724 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1725 for (Edge* e = v->fLastEdgeAbove; e; e = e->fPrevEdgeAbove) {
1726 Edge* prev = e->fPrevEdgeAbove ? e->fPrevEdgeAbove : leftEnclosingEdge;
1727 remove_edge(e, &activeEdges);
1728 if (prev) {
1729 e->fWinding -= prev->fWinding;
1730 }
1731 }
1732 Edge* prev = leftEnclosingEdge;
1733 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1734 if (prev) {
1735 e->fWinding += prev->fWinding;
1736 e->fOverlap = e->fOverlap || is_overlap_edge(prev);
1737 }
1738 e->fOverlap = e->fOverlap || is_overlap_edge(e);
1739 if (e->fOverlap) {
1740 create_event(e, &events, alloc);
1741 }
1742 insert_edge(e, prev, &activeEdges);
1743 prev = e;
1744 }
1745 }
1746 LOG("\ncollapsing overlap regions\n");
1747 if (events.count() == 0) {
1748 return false;
1749 }
1750 while (events.count() > 0) {
1751 Event* event = events.peek();
1752 events.pop();
1753 event->apply(mesh, c, alloc);
1754 }
1755 return true;
1756}
1757
1758bool inversion(Vertex* prev, Vertex* next, Edge* origEdge, Comparator& c) {
1759 if (!prev || !next) {
1760 return true;
1761 }
1762 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
1763 return winding != origEdge->fWinding;
1764}
Stephen White92eba8a2017-02-06 09:50:27 -05001765
senorblancof57372d2016-08-31 10:36:19 -07001766// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
1767// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
1768// new antialiased mesh from those vertices.
1769
Stephen Whitee260c462017-12-19 18:09:54 -05001770void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
1771 Comparator& c, SkArenaAlloc& alloc) {
1772 LOG("\nstroking boundary\n");
1773 // A boundary with fewer than 3 edges is degenerate.
1774 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
1775 return;
1776 }
1777 Edge* prevEdge = boundary->fTail;
1778 Vertex* prevV = prevEdge->fWinding > 0 ? prevEdge->fTop : prevEdge->fBottom;
1779 SkVector prevNormal;
1780 get_edge_normal(prevEdge, &prevNormal);
1781 double radius = 0.5;
1782 Line prevInner(prevEdge->fLine);
1783 prevInner.fC -= radius;
1784 Line prevOuter(prevEdge->fLine);
1785 prevOuter.fC += radius;
1786 VertexList innerVertices;
1787 VertexList outerVertices;
1788 bool innerInversion = true;
1789 bool outerInversion = true;
1790 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
1791 Vertex* v = e->fWinding > 0 ? e->fTop : e->fBottom;
1792 SkVector normal;
1793 get_edge_normal(e, &normal);
1794 Line inner(e->fLine);
1795 inner.fC -= radius;
1796 Line outer(e->fLine);
1797 outer.fC += radius;
1798 SkPoint innerPoint, outerPoint;
1799 LOG("stroking vertex %g (%g, %g)\n", v->fID, v->fPoint.fX, v->fPoint.fY);
1800 if (!prevEdge->fLine.nearParallel(e->fLine) && prevInner.intersect(inner, &innerPoint) &&
1801 prevOuter.intersect(outer, &outerPoint)) {
1802 float cosAngle = normal.dot(prevNormal);
1803 if (cosAngle < -kCosMiterAngle) {
1804 Vertex* nextV = e->fWinding > 0 ? e->fBottom : e->fTop;
1805
1806 // This is a pointy vertex whose angle is smaller than the threshold; miter it.
1807 Line bisector(innerPoint, outerPoint);
1808 Line tangent(v->fPoint, v->fPoint + SkPoint::Make(bisector.fA, bisector.fB));
1809 if (tangent.fA == 0 && tangent.fB == 0) {
1810 continue;
1811 }
1812 tangent.normalize();
1813 Line innerTangent(tangent);
1814 Line outerTangent(tangent);
1815 innerTangent.fC -= 0.5;
1816 outerTangent.fC += 0.5;
1817 SkPoint innerPoint1, innerPoint2, outerPoint1, outerPoint2;
1818 if (prevNormal.cross(normal) > 0) {
1819 // Miter inner points
1820 if (!innerTangent.intersect(prevInner, &innerPoint1) ||
1821 !innerTangent.intersect(inner, &innerPoint2) ||
1822 !outerTangent.intersect(bisector, &outerPoint)) {
Stephen Whitef470b7e2018-01-04 16:45:51 -05001823 continue;
Stephen Whitee260c462017-12-19 18:09:54 -05001824 }
1825 Line prevTangent(prevV->fPoint,
1826 prevV->fPoint + SkVector::Make(prevOuter.fA, prevOuter.fB));
1827 Line nextTangent(nextV->fPoint,
1828 nextV->fPoint + SkVector::Make(outer.fA, outer.fB));
Stephen Whitee260c462017-12-19 18:09:54 -05001829 if (prevTangent.dist(outerPoint) > 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001830 bisector.intersect(prevTangent, &outerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001831 }
1832 if (nextTangent.dist(outerPoint) < 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001833 bisector.intersect(nextTangent, &outerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001834 }
1835 outerPoint1 = outerPoint2 = outerPoint;
1836 } else {
1837 // Miter outer points
1838 if (!outerTangent.intersect(prevOuter, &outerPoint1) ||
1839 !outerTangent.intersect(outer, &outerPoint2)) {
Stephen Whitef470b7e2018-01-04 16:45:51 -05001840 continue;
Stephen Whitee260c462017-12-19 18:09:54 -05001841 }
1842 Line prevTangent(prevV->fPoint,
1843 prevV->fPoint + SkVector::Make(prevInner.fA, prevInner.fB));
1844 Line nextTangent(nextV->fPoint,
1845 nextV->fPoint + SkVector::Make(inner.fA, inner.fB));
Stephen Whitee260c462017-12-19 18:09:54 -05001846 if (prevTangent.dist(innerPoint) > 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001847 bisector.intersect(prevTangent, &innerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001848 }
1849 if (nextTangent.dist(innerPoint) < 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001850 bisector.intersect(nextTangent, &innerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001851 }
1852 innerPoint1 = innerPoint2 = innerPoint;
1853 }
Stephen Whiteea495232018-04-03 11:28:15 -04001854 if (!innerPoint1.isFinite() || !innerPoint2.isFinite() ||
1855 !outerPoint1.isFinite() || !outerPoint2.isFinite()) {
1856 continue;
1857 }
Stephen Whitee260c462017-12-19 18:09:54 -05001858 LOG("inner (%g, %g), (%g, %g), ",
1859 innerPoint1.fX, innerPoint1.fY, innerPoint2.fX, innerPoint2.fY);
1860 LOG("outer (%g, %g), (%g, %g)\n",
1861 outerPoint1.fX, outerPoint1.fY, outerPoint2.fX, outerPoint2.fY);
1862 Vertex* innerVertex1 = alloc.make<Vertex>(innerPoint1, 255);
1863 Vertex* innerVertex2 = alloc.make<Vertex>(innerPoint2, 255);
1864 Vertex* outerVertex1 = alloc.make<Vertex>(outerPoint1, 0);
1865 Vertex* outerVertex2 = alloc.make<Vertex>(outerPoint2, 0);
1866 innerVertex1->fPartner = outerVertex1;
1867 innerVertex2->fPartner = outerVertex2;
1868 outerVertex1->fPartner = innerVertex1;
1869 outerVertex2->fPartner = innerVertex2;
1870 if (!inversion(innerVertices.fTail, innerVertex1, prevEdge, c)) {
1871 innerInversion = false;
1872 }
1873 if (!inversion(outerVertices.fTail, outerVertex1, prevEdge, c)) {
1874 outerInversion = false;
1875 }
1876 innerVertices.append(innerVertex1);
1877 innerVertices.append(innerVertex2);
1878 outerVertices.append(outerVertex1);
1879 outerVertices.append(outerVertex2);
1880 } else {
1881 LOG("inner (%g, %g), ", innerPoint.fX, innerPoint.fY);
1882 LOG("outer (%g, %g)\n", outerPoint.fX, outerPoint.fY);
1883 Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255);
1884 Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0);
1885 innerVertex->fPartner = outerVertex;
1886 outerVertex->fPartner = innerVertex;
1887 if (!inversion(innerVertices.fTail, innerVertex, prevEdge, c)) {
1888 innerInversion = false;
1889 }
1890 if (!inversion(outerVertices.fTail, outerVertex, prevEdge, c)) {
1891 outerInversion = false;
1892 }
1893 innerVertices.append(innerVertex);
1894 outerVertices.append(outerVertex);
1895 }
1896 }
1897 prevInner = inner;
1898 prevOuter = outer;
1899 prevV = v;
1900 prevEdge = e;
1901 prevNormal = normal;
1902 }
1903 if (!inversion(innerVertices.fTail, innerVertices.fHead, prevEdge, c)) {
1904 innerInversion = false;
1905 }
1906 if (!inversion(outerVertices.fTail, outerVertices.fHead, prevEdge, c)) {
1907 outerInversion = false;
1908 }
1909 // Outer edges get 1 winding, and inner edges get -2 winding. This ensures that the interior
1910 // is always filled (1 + -2 = -1 for normal cases, 1 + 2 = 3 for thin features where the
1911 // interior inverts).
1912 // For total inversion cases, the shape has now reversed handedness, so invert the winding
1913 // so it will be detected during collapse_overlap_regions().
1914 int innerWinding = innerInversion ? 2 : -2;
1915 int outerWinding = outerInversion ? -1 : 1;
1916 for (Vertex* v = innerVertices.fHead; v && v->fNext; v = v->fNext) {
1917 connect(v, v->fNext, Edge::Type::kInner, c, alloc, innerWinding);
1918 }
1919 connect(innerVertices.fTail, innerVertices.fHead, Edge::Type::kInner, c, alloc, innerWinding);
1920 for (Vertex* v = outerVertices.fHead; v && v->fNext; v = v->fNext) {
1921 connect(v, v->fNext, Edge::Type::kOuter, c, alloc, outerWinding);
1922 }
1923 connect(outerVertices.fTail, outerVertices.fHead, Edge::Type::kOuter, c, alloc, outerWinding);
1924 innerMesh->append(innerVertices);
1925 outerMesh->append(outerVertices);
1926}
senorblancof57372d2016-08-31 10:36:19 -07001927
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001928void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkArenaAlloc& alloc) {
Stephen White95152e12017-12-18 10:52:44 -05001929 LOG("\nextracting boundary\n");
Stephen White49789062017-02-21 10:35:49 -05001930 bool down = apply_fill_type(fillType, e->fWinding);
senorblancof57372d2016-08-31 10:36:19 -07001931 while (e) {
1932 e->fWinding = down ? 1 : -1;
1933 Edge* next;
Stephen Whitee260c462017-12-19 18:09:54 -05001934 e->fLine.normalize();
1935 e->fLine = e->fLine * e->fWinding;
senorblancof57372d2016-08-31 10:36:19 -07001936 boundary->append(e);
1937 if (down) {
1938 // Find outgoing edge, in clockwise order.
1939 if ((next = e->fNextEdgeAbove)) {
1940 down = false;
1941 } else if ((next = e->fBottom->fLastEdgeBelow)) {
1942 down = true;
1943 } else if ((next = e->fPrevEdgeAbove)) {
1944 down = false;
1945 }
1946 } else {
1947 // Find outgoing edge, in counter-clockwise order.
1948 if ((next = e->fPrevEdgeBelow)) {
1949 down = true;
1950 } else if ((next = e->fTop->fFirstEdgeAbove)) {
1951 down = false;
1952 } else if ((next = e->fNextEdgeBelow)) {
1953 down = true;
1954 }
1955 }
Stephen Whitee7a364d2017-01-11 16:19:26 -05001956 disconnect(e);
senorblancof57372d2016-08-31 10:36:19 -07001957 e = next;
1958 }
1959}
1960
Stephen White5ad721e2017-02-23 16:50:47 -05001961// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
senorblancof57372d2016-08-31 10:36:19 -07001962
Stephen Whitebda29c02017-03-13 15:10:13 -04001963void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices,
1964 VertexList* outerVertices, SkPath::FillType fillType,
Stephen White5ad721e2017-02-23 16:50:47 -05001965 Comparator& c, SkArenaAlloc& alloc) {
1966 remove_non_boundary_edges(inMesh, fillType, alloc);
1967 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001968 while (v->fFirstEdgeBelow) {
Stephen White5ad721e2017-02-23 16:50:47 -05001969 EdgeList boundary;
1970 extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc);
1971 simplify_boundary(&boundary, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001972 stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001973 }
1974 }
senorblancof57372d2016-08-31 10:36:19 -07001975}
1976
Stephen Whitebda29c02017-03-13 15:10:13 -04001977// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001978
Stephen White3a9aab92017-03-07 14:07:18 -05001979void contours_to_mesh(VertexList* contours, int contourCnt, bool antialias,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05001980 VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) {
ethannicholase9709e82016-01-07 13:34:16 -08001981#if LOGGING_ENABLED
1982 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001983 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001984 SkASSERT(v);
1985 LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001986 for (v = v->fNext; v; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001987 LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1988 }
1989 }
1990#endif
senorblancof57372d2016-08-31 10:36:19 -07001991 sanitize_contours(contours, contourCnt, antialias);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001992 build_edges(contours, contourCnt, mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001993}
1994
Stephen Whitebda29c02017-03-13 15:10:13 -04001995void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001996 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001997 return;
ethannicholase9709e82016-01-07 13:34:16 -08001998 }
1999
2000 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05002001 if (c.fDirection == Comparator::Direction::kHorizontal) {
2002 merge_sort<sweep_lt_horiz>(vertices);
2003 } else {
2004 merge_sort<sweep_lt_vert>(vertices);
2005 }
ethannicholase9709e82016-01-07 13:34:16 -08002006#if LOGGING_ENABLED
Stephen White2e2cb9b2017-01-09 13:11:18 -05002007 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08002008 static float gID = 0.0f;
2009 v->fID = gID++;
2010 }
2011#endif
Stephen White2f4686f2017-01-03 16:20:01 -05002012}
2013
Stephen White3a9aab92017-03-07 14:07:18 -05002014Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPath::FillType fillType,
Stephen Whitebda29c02017-03-13 15:10:13 -04002015 const SkRect& pathBounds, bool antialias, VertexList* outerMesh,
Herb Derby5cdc9dd2017-02-13 12:10:46 -05002016 SkArenaAlloc& alloc) {
Stephen White16a40cb2017-02-23 11:10:01 -05002017 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
2018 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05002019 VertexList mesh;
2020 contours_to_mesh(contours, contourCnt, antialias, &mesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04002021 sort_mesh(&mesh, c, alloc);
2022 merge_coincident_vertices(&mesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04002023 simplify(&mesh, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07002024 if (antialias) {
Stephen Whitebda29c02017-03-13 15:10:13 -04002025 VertexList innerMesh;
2026 extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc);
2027 sort_mesh(&innerMesh, c, alloc);
2028 sort_mesh(outerMesh, c, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05002029 merge_coincident_vertices(&innerMesh, c, alloc);
2030 bool was_complex = merge_coincident_vertices(outerMesh, c, alloc);
2031 was_complex = simplify(&innerMesh, c, alloc) || was_complex;
2032 was_complex = simplify(outerMesh, c, alloc) || was_complex;
2033 LOG("\ninner mesh before:\n");
2034 dump_mesh(innerMesh);
2035 LOG("\nouter mesh before:\n");
2036 dump_mesh(*outerMesh);
2037 was_complex = collapse_overlap_regions(&innerMesh, c, alloc) || was_complex;
2038 was_complex = collapse_overlap_regions(outerMesh, c, alloc) || was_complex;
2039 if (was_complex) {
Stephen Whitebda29c02017-03-13 15:10:13 -04002040 LOG("found complex mesh; taking slow path\n");
2041 VertexList aaMesh;
Stephen White95152e12017-12-18 10:52:44 -05002042 LOG("\ninner mesh after:\n");
2043 dump_mesh(innerMesh);
2044 LOG("\nouter mesh after:\n");
2045 dump_mesh(*outerMesh);
Stephen Whitebda29c02017-03-13 15:10:13 -04002046 connect_partners(outerMesh, c, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05002047 connect_partners(&innerMesh, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04002048 sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
2049 merge_coincident_vertices(&aaMesh, c, alloc);
Stephen White0cb31672017-06-08 14:41:01 -04002050 simplify(&aaMesh, c, alloc);
Stephen White95152e12017-12-18 10:52:44 -05002051 dump_mesh(aaMesh);
Stephen Whitebda29c02017-03-13 15:10:13 -04002052 outerMesh->fHead = outerMesh->fTail = nullptr;
2053 return tessellate(aaMesh, alloc);
2054 } else {
2055 LOG("no complex polygons; taking fast path\n");
Stephen Whitebda29c02017-03-13 15:10:13 -04002056 return tessellate(innerMesh, alloc);
2057 }
Stephen White49789062017-02-21 10:35:49 -05002058 } else {
2059 return tessellate(mesh, alloc);
senorblancof57372d2016-08-31 10:36:19 -07002060 }
senorblancof57372d2016-08-31 10:36:19 -07002061}
2062
2063// Stage 6: Triangulate the monotone polygons into a vertex buffer.
2064void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* aaParams,
2065 void* data) {
2066 for (Poly* poly = polys; poly; poly = poly->fNext) {
2067 if (apply_fill_type(fillType, poly)) {
2068 data = poly->emit(aaParams, data);
2069 }
2070 }
2071 return data;
ethannicholase9709e82016-01-07 13:34:16 -08002072}
2073
halcanary9d524f22016-03-29 09:03:52 -07002074Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
Stephen Whitebda29c02017-03-13 15:10:13 -04002075 int contourCnt, SkArenaAlloc& alloc, bool antialias, bool* isLinear,
2076 VertexList* outerMesh) {
ethannicholase9709e82016-01-07 13:34:16 -08002077 SkPath::FillType fillType = path.getFillType();
2078 if (SkPath::IsInverseFillType(fillType)) {
2079 contourCnt++;
2080 }
Stephen White3a9aab92017-03-07 14:07:18 -05002081 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08002082
2083 path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear);
senorblancof57372d2016-08-31 10:36:19 -07002084 return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(),
Stephen Whitebda29c02017-03-13 15:10:13 -04002085 antialias, outerMesh, alloc);
ethannicholase9709e82016-01-07 13:34:16 -08002086}
2087
Stephen White11f65e02017-02-16 19:00:39 -05002088int get_contour_count(const SkPath& path, SkScalar tolerance) {
2089 int contourCnt;
2090 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08002091 if (maxPts <= 0) {
Stephen White11f65e02017-02-16 19:00:39 -05002092 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08002093 }
Stephen White11f65e02017-02-16 19:00:39 -05002094 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08002095}
2096
2097int count_points(Poly* polys, SkPath::FillType fillType) {
2098 int count = 0;
2099 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07002100 if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
ethannicholase9709e82016-01-07 13:34:16 -08002101 count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3);
2102 }
2103 }
2104 return count;
2105}
2106
Stephen Whitebda29c02017-03-13 15:10:13 -04002107int count_outer_mesh_points(const VertexList& outerMesh) {
2108 int count = 0;
2109 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
2110 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
2111 count += TESSELLATOR_WIREFRAME ? 12 : 6;
2112 }
2113 }
2114 return count;
2115}
2116
2117void* outer_mesh_to_triangles(const VertexList& outerMesh, const AAParams* aaParams, void* data) {
2118 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
2119 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
2120 Vertex* v0 = e->fTop;
2121 Vertex* v1 = e->fBottom;
2122 Vertex* v2 = e->fBottom->fPartner;
2123 Vertex* v3 = e->fTop->fPartner;
2124 data = emit_triangle(v0, v1, v2, aaParams, data);
2125 data = emit_triangle(v0, v2, v3, aaParams, data);
2126 }
2127 }
2128 return data;
2129}
2130
ethannicholase9709e82016-01-07 13:34:16 -08002131} // namespace
2132
2133namespace GrTessellator {
2134
2135// Stage 6: Triangulate the monotone polygons into a vertex buffer.
2136
halcanary9d524f22016-03-29 09:03:52 -07002137int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
senorblancof57372d2016-08-31 10:36:19 -07002138 VertexAllocator* vertexAllocator, bool antialias, const GrColor& color,
2139 bool canTweakAlphaForCoverage, bool* isLinear) {
Stephen White11f65e02017-02-16 19:00:39 -05002140 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08002141 if (contourCnt <= 0) {
2142 *isLinear = true;
2143 return 0;
2144 }
Stephen White11f65e02017-02-16 19:00:39 -05002145 SkArenaAlloc alloc(kArenaChunkSize);
Stephen Whitebda29c02017-03-13 15:10:13 -04002146 VertexList outerMesh;
senorblancof57372d2016-08-31 10:36:19 -07002147 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias,
Stephen Whitebda29c02017-03-13 15:10:13 -04002148 isLinear, &outerMesh);
senorblanco7ab96e92016-10-12 06:47:44 -07002149 SkPath::FillType fillType = antialias ? SkPath::kWinding_FillType : path.getFillType();
ethannicholase9709e82016-01-07 13:34:16 -08002150 int count = count_points(polys, fillType);
Stephen Whitebda29c02017-03-13 15:10:13 -04002151 if (antialias) {
2152 count += count_outer_mesh_points(outerMesh);
2153 }
Stephen Whiteff60b172017-05-05 15:54:52 -04002154 if (0 == count) {
2155 return 0;
2156 }
ethannicholase9709e82016-01-07 13:34:16 -08002157
senorblancof57372d2016-08-31 10:36:19 -07002158 void* verts = vertexAllocator->lock(count);
senorblanco6599eff2016-03-10 08:38:45 -08002159 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08002160 SkDebugf("Could not allocate vertices\n");
2161 return 0;
2162 }
senorblancof57372d2016-08-31 10:36:19 -07002163
2164 LOG("emitting %d verts\n", count);
2165 AAParams aaParams;
2166 aaParams.fTweakAlpha = canTweakAlphaForCoverage;
2167 aaParams.fColor = color;
2168
2169 void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts);
Stephen Whitebda29c02017-03-13 15:10:13 -04002170 end = outer_mesh_to_triangles(outerMesh, &aaParams, end);
senorblancof57372d2016-08-31 10:36:19 -07002171 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
2172 / vertexAllocator->stride());
ethannicholase9709e82016-01-07 13:34:16 -08002173 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08002174 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08002175 return actualCount;
2176}
2177
halcanary9d524f22016-03-29 09:03:52 -07002178int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
ethannicholase9709e82016-01-07 13:34:16 -08002179 GrTessellator::WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05002180 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08002181 if (contourCnt <= 0) {
Chris Dalton84403d72018-02-13 21:46:17 -05002182 *verts = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08002183 return 0;
2184 }
Stephen White11f65e02017-02-16 19:00:39 -05002185 SkArenaAlloc alloc(kArenaChunkSize);
ethannicholase9709e82016-01-07 13:34:16 -08002186 bool isLinear;
Stephen Whitebda29c02017-03-13 15:10:13 -04002187 Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear,
2188 nullptr);
ethannicholase9709e82016-01-07 13:34:16 -08002189 SkPath::FillType fillType = path.getFillType();
2190 int count = count_points(polys, fillType);
2191 if (0 == count) {
2192 *verts = nullptr;
2193 return 0;
2194 }
2195
2196 *verts = new GrTessellator::WindingVertex[count];
2197 GrTessellator::WindingVertex* vertsEnd = *verts;
2198 SkPoint* points = new SkPoint[count];
2199 SkPoint* pointsEnd = points;
2200 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07002201 if (apply_fill_type(fillType, poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08002202 SkPoint* start = pointsEnd;
senorblancof57372d2016-08-31 10:36:19 -07002203 pointsEnd = static_cast<SkPoint*>(poly->emit(nullptr, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08002204 while (start != pointsEnd) {
2205 vertsEnd->fPos = *start;
2206 vertsEnd->fWinding = poly->fWinding;
2207 ++start;
2208 ++vertsEnd;
2209 }
2210 }
2211 }
2212 int actualCount = static_cast<int>(vertsEnd - *verts);
2213 SkASSERT(actualCount <= count);
2214 SkASSERT(pointsEnd - points == actualCount);
2215 delete[] points;
2216 return actualCount;
2217}
2218
2219} // namespace