blob: 34e12fb301e92eeec04c805f6e3efdd5fb348771 [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
Chris Dalton17dc4182020-03-25 16:18:16 -06008#include "src/gpu/GrTriangulator.h"
ethannicholase9709e82016-01-07 13:34:16 -08009
Chris Dalton75887a22021-01-06 00:23:13 -070010#include "src/core/SkGeometry.h"
11#include "src/core/SkPointPriv.h"
Chris Daltond081dce2020-01-23 12:09:04 -070012#include "src/gpu/GrEagerVertexAllocator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrVertexWriter.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040014#include "src/gpu/geometry/GrPathUtils.h"
Stephen White94b7e542018-01-04 14:01:10 -050015#include <algorithm>
Ben Wagnerf08d1d02018-06-18 15:11:00 -040016#include <cstdio>
Stephen Whitec4dbc372019-05-22 10:50:14 -040017#include <queue>
18#include <unordered_map>
Ben Wagnerf08d1d02018-06-18 15:11:00 -040019#include <utility>
ethannicholase9709e82016-01-07 13:34:16 -080020
Chris Dalton75887a22021-01-06 00:23:13 -070021#if TRIANGULATOR_LOGGING
22#define TESS_LOG SkDebugf
23#define DUMP_MESH(MESH) (MESH).dump()
ethannicholase9709e82016-01-07 13:34:16 -080024#else
Brian Salomon120e7d62019-09-11 10:29:22 -040025#define TESS_LOG(...)
Chris Dalton75887a22021-01-06 00:23:13 -070026#define DUMP_MESH(MESH)
ethannicholase9709e82016-01-07 13:34:16 -080027#endif
28
Chris Dalton57ea1fc2021-01-05 13:37:44 -070029constexpr static float kCosMiterAngle = 0.97f; // Corresponds to an angle of ~14 degrees.
ethannicholase9709e82016-01-07 13:34:16 -080030
Stephen Whitee260c462017-12-19 18:09:54 -050031struct Event;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070032
Chris Dalton75887a22021-01-06 00:23:13 -070033using EdgeType = GrTriangulator::EdgeType;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070034using Vertex = GrTriangulator::Vertex;
35using VertexList = GrTriangulator::VertexList;
Chris Dalton75887a22021-01-06 00:23:13 -070036using Line = GrTriangulator::Line;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070037using Edge = GrTriangulator::Edge;
38using EdgeList = GrTriangulator::EdgeList;
39using Poly = GrTriangulator::Poly;
Chris Dalton75887a22021-01-06 00:23:13 -070040using MonotonePoly = GrTriangulator::MonotonePoly;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070041using Comparator = GrTriangulator::Comparator;
ethannicholase9709e82016-01-07 13:34:16 -080042
43template <class T, T* T::*Prev, T* T::*Next>
Chris Dalton57ea1fc2021-01-05 13:37:44 -070044static void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -080045 t->*Prev = prev;
46 t->*Next = next;
47 if (prev) {
48 prev->*Next = t;
49 } else if (head) {
50 *head = t;
51 }
52 if (next) {
53 next->*Prev = t;
54 } else if (tail) {
55 *tail = t;
56 }
57}
58
59template <class T, T* T::*Prev, T* T::*Next>
Chris Dalton57ea1fc2021-01-05 13:37:44 -070060static void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -080061 if (t->*Prev) {
62 t->*Prev->*Next = t->*Next;
63 } else if (head) {
64 *head = t->*Next;
65 }
66 if (t->*Next) {
67 t->*Next->*Prev = t->*Prev;
68 } else if (tail) {
69 *tail = t->*Prev;
70 }
71 t->*Prev = t->*Next = nullptr;
72}
73
ethannicholase9709e82016-01-07 13:34:16 -080074typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
75
Chris Dalton57ea1fc2021-01-05 13:37:44 -070076static bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -050077 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -080078}
79
Chris Dalton57ea1fc2021-01-05 13:37:44 -070080static bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -050081 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -080082}
83
Chris Dalton75887a22021-01-06 00:23:13 -070084bool GrTriangulator::Comparator::sweep_lt(const SkPoint& a, const SkPoint& b) const {
85 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
86}
Stephen White16a40cb2017-02-23 11:10:01 -050087
Chris Dalton75887a22021-01-06 00:23:13 -070088static inline void* emit_vertex(const Vertex* v, bool emitCoverage, void* data) {
Brian Osmanf9aabff2018-11-13 16:11:38 -050089 GrVertexWriter verts{data};
90 verts.write(v->fPoint);
91
Brian Osman80879d42019-01-07 16:15:27 -050092 if (emitCoverage) {
93 verts.write(GrNormalizeByteToFloat(v->fAlpha));
94 }
Brian Osman0995fd52019-01-09 09:52:25 -050095
Brian Osmanf9aabff2018-11-13 16:11:38 -050096 return verts.fPtr;
ethannicholase9709e82016-01-07 13:34:16 -080097}
98
Chris Dalton75887a22021-01-06 00:23:13 -070099static void* emit_triangle(const Vertex* v0, const Vertex* v1, const Vertex* v2, bool emitCoverage,
100 void* data) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400101 TESS_LOG("emit_triangle %g (%g, %g) %d\n", v0->fID, v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
102 TESS_LOG(" %g (%g, %g) %d\n", v1->fID, v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
103 TESS_LOG(" %g (%g, %g) %d\n", v2->fID, v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -0700104#if TESSELLATOR_WIREFRAME
Brian Osman0995fd52019-01-09 09:52:25 -0500105 data = emit_vertex(v0, emitCoverage, data);
106 data = emit_vertex(v1, emitCoverage, data);
107 data = emit_vertex(v1, emitCoverage, data);
108 data = emit_vertex(v2, emitCoverage, data);
109 data = emit_vertex(v2, emitCoverage, data);
110 data = emit_vertex(v0, emitCoverage, data);
ethannicholase9709e82016-01-07 13:34:16 -0800111#else
Brian Osman0995fd52019-01-09 09:52:25 -0500112 data = emit_vertex(v0, emitCoverage, data);
113 data = emit_vertex(v1, emitCoverage, data);
114 data = emit_vertex(v2, emitCoverage, data);
ethannicholase9709e82016-01-07 13:34:16 -0800115#endif
116 return data;
117}
118
Chris Dalton75887a22021-01-06 00:23:13 -0700119void GrTriangulator::VertexList::insert(Vertex* v, Vertex* prev, Vertex* next) {
120 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
121}
122
123void GrTriangulator::VertexList::remove(Vertex* v) {
124 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
125}
senorblancoe6eaa322016-03-08 09:06:44 -0800126
senorblancof57372d2016-08-31 10:36:19 -0700127// Round to nearest quarter-pixel. This is used for screenspace tessellation.
128
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700129static inline void round(SkPoint* p) {
senorblancof57372d2016-08-31 10:36:19 -0700130 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
131 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
132}
133
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700134static inline SkScalar double_to_clamped_scalar(double d) {
Stephen White94b7e542018-01-04 14:01:10 -0500135 return SkDoubleToScalar(std::min((double) SK_ScalarMax, std::max(d, (double) -SK_ScalarMax)));
136}
137
Chris Dalton75887a22021-01-06 00:23:13 -0700138void GrTriangulator::Line::normalize() {
139 double len = sqrt(this->magSq());
140 if (len == 0.0) {
141 return;
senorblanco49df8d12016-10-07 08:36:56 -0700142 }
Chris Dalton75887a22021-01-06 00:23:13 -0700143 double scale = 1.0f / len;
144 fA *= scale;
145 fB *= scale;
146 fC *= scale;
147}
senorblanco49df8d12016-10-07 08:36:56 -0700148
Chris Dalton75887a22021-01-06 00:23:13 -0700149bool GrTriangulator::Line::intersect(const Line& other, SkPoint* point) const {
150 double denom = fA * other.fB - fB * other.fA;
151 if (denom == 0.0) {
152 return false;
senorblanco49df8d12016-10-07 08:36:56 -0700153 }
Chris Dalton75887a22021-01-06 00:23:13 -0700154 double scale = 1.0 / denom;
155 point->fX = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale);
156 point->fY = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale);
157 round(point);
158 return point->isFinite();
159}
senorblanco49df8d12016-10-07 08:36:56 -0700160
Chris Dalton75887a22021-01-06 00:23:13 -0700161bool GrTriangulator::Edge::intersect(const Edge& other, SkPoint* p, uint8_t* alpha) const {
162 TESS_LOG("intersecting %g -> %g with %g -> %g\n",
163 fTop->fID, fBottom->fID, other.fTop->fID, other.fBottom->fID);
164 if (fTop == other.fTop || fBottom == other.fBottom) {
165 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800166 }
Chris Dalton75887a22021-01-06 00:23:13 -0700167 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
168 if (denom == 0.0) {
169 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800170 }
Chris Dalton75887a22021-01-06 00:23:13 -0700171 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
172 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
173 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
174 double tNumer = dy * fLine.fB + dx * fLine.fA;
175 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
176 // This saves us doing the divide below unless absolutely necessary.
177 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
178 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
179 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800180 }
Chris Dalton75887a22021-01-06 00:23:13 -0700181 double s = sNumer / denom;
182 SkASSERT(s >= 0.0 && s <= 1.0);
183 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
184 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
185 if (alpha) {
186 if (fType == EdgeType::kConnector) {
187 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
188 } else if (other.fType == EdgeType::kConnector) {
189 double t = tNumer / denom;
190 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
191 } else if (fType == EdgeType::kOuter && other.fType == EdgeType::kOuter) {
192 *alpha = 0;
193 } else {
194 *alpha = 255;
195 }
ethannicholase9709e82016-01-07 13:34:16 -0800196 }
Chris Dalton75887a22021-01-06 00:23:13 -0700197 return true;
198}
senorblancof57372d2016-08-31 10:36:19 -0700199
Stephen Whitec4dbc372019-05-22 10:50:14 -0400200struct SSEdge;
201
202struct SSVertex {
203 SSVertex(Vertex* v) : fVertex(v), fPrev(nullptr), fNext(nullptr) {}
204 Vertex* fVertex;
205 SSEdge* fPrev;
206 SSEdge* fNext;
207};
208
209struct SSEdge {
210 SSEdge(Edge* edge, SSVertex* prev, SSVertex* next)
211 : fEdge(edge), fEvent(nullptr), fPrev(prev), fNext(next) {
212 }
213 Edge* fEdge;
214 Event* fEvent;
215 SSVertex* fPrev;
216 SSVertex* fNext;
217};
218
219typedef std::unordered_map<Vertex*, SSVertex*> SSVertexMap;
220typedef std::vector<SSEdge*> SSEdgeList;
221
Chris Dalton75887a22021-01-06 00:23:13 -0700222void GrTriangulator::EdgeList::insert(Edge* edge, Edge* prev, Edge* next) {
223 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
224}
225
226void GrTriangulator::EdgeList::remove(Edge* edge) {
227 TESS_LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
228 SkASSERT(this->contains(edge));
229 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
230}
ethannicholase9709e82016-01-07 13:34:16 -0800231
Stephen Whitec4dbc372019-05-22 10:50:14 -0400232struct EventList;
233
Stephen Whitee260c462017-12-19 18:09:54 -0500234struct Event {
Stephen Whitec4dbc372019-05-22 10:50:14 -0400235 Event(SSEdge* edge, const SkPoint& point, uint8_t alpha)
236 : fEdge(edge), fPoint(point), fAlpha(alpha) {
Stephen Whitee260c462017-12-19 18:09:54 -0500237 }
Stephen Whitec4dbc372019-05-22 10:50:14 -0400238 SSEdge* fEdge;
Stephen Whitee260c462017-12-19 18:09:54 -0500239 SkPoint fPoint;
240 uint8_t fAlpha;
Chris Dalton75887a22021-01-06 00:23:13 -0700241 void apply(VertexList* mesh, const Comparator& c, EventList* events, SkArenaAlloc& alloc);
Stephen Whitee260c462017-12-19 18:09:54 -0500242};
243
Stephen Whitec4dbc372019-05-22 10:50:14 -0400244struct EventComparator {
245 enum class Op { kLessThan, kGreaterThan };
246 EventComparator(Op op) : fOp(op) {}
247 bool operator() (Event* const &e1, Event* const &e2) {
248 return fOp == Op::kLessThan ? e1->fAlpha < e2->fAlpha
249 : e1->fAlpha > e2->fAlpha;
250 }
251 Op fOp;
252};
Stephen Whitee260c462017-12-19 18:09:54 -0500253
Stephen Whitec4dbc372019-05-22 10:50:14 -0400254typedef std::priority_queue<Event*, std::vector<Event*>, EventComparator> EventPQ;
Stephen Whitee260c462017-12-19 18:09:54 -0500255
Stephen Whitec4dbc372019-05-22 10:50:14 -0400256struct EventList : EventPQ {
257 EventList(EventComparator comparison) : EventPQ(comparison) {
258 }
259};
260
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700261static void create_event(SSEdge* e, EventList* events, SkArenaAlloc& alloc) {
Stephen Whitec4dbc372019-05-22 10:50:14 -0400262 Vertex* prev = e->fPrev->fVertex;
263 Vertex* next = e->fNext->fVertex;
264 if (prev == next || !prev->fPartner || !next->fPartner) {
265 return;
266 }
Chris Dalton75887a22021-01-06 00:23:13 -0700267 Edge bisector1(prev, prev->fPartner, 1, EdgeType::kConnector);
268 Edge bisector2(next, next->fPartner, 1, EdgeType::kConnector);
Stephen Whitee260c462017-12-19 18:09:54 -0500269 SkPoint p;
270 uint8_t alpha;
271 if (bisector1.intersect(bisector2, &p, &alpha)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400272 TESS_LOG("found edge event for %g, %g (original %g -> %g), "
273 "will collapse to %g,%g alpha %d\n",
274 prev->fID, next->fID, e->fEdge->fTop->fID, e->fEdge->fBottom->fID, p.fX, p.fY,
275 alpha);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400276 e->fEvent = alloc.make<Event>(e, p, alpha);
277 events->push(e->fEvent);
278 }
279}
280
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700281static void create_event(SSEdge* edge, Vertex* v, SSEdge* other, Vertex* dest, EventList* events,
Chris Dalton75887a22021-01-06 00:23:13 -0700282 const Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitec4dbc372019-05-22 10:50:14 -0400283 if (!v->fPartner) {
284 return;
285 }
Stephen White8a3c0592019-05-29 11:26:16 -0400286 Vertex* top = edge->fEdge->fTop;
287 Vertex* bottom = edge->fEdge->fBottom;
288 if (!top || !bottom ) {
289 return;
290 }
Stephen Whitec4dbc372019-05-22 10:50:14 -0400291 Line line = edge->fEdge->fLine;
292 line.fC = -(dest->fPoint.fX * line.fA + dest->fPoint.fY * line.fB);
Chris Dalton75887a22021-01-06 00:23:13 -0700293 Edge bisector(v, v->fPartner, 1, EdgeType::kConnector);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400294 SkPoint p;
295 uint8_t alpha = dest->fAlpha;
Stephen White8a3c0592019-05-29 11:26:16 -0400296 if (line.intersect(bisector.fLine, &p) && !c.sweep_lt(p, top->fPoint) &&
297 c.sweep_lt(p, bottom->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400298 TESS_LOG("found p edge event for %g, %g (original %g -> %g), "
299 "will collapse to %g,%g alpha %d\n",
300 dest->fID, v->fID, top->fID, bottom->fID, p.fX, p.fY, alpha);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400301 edge->fEvent = alloc.make<Event>(edge, p, alpha);
302 events->push(edge->fEvent);
Stephen Whitee260c462017-12-19 18:09:54 -0500303 }
304}
Stephen Whitee260c462017-12-19 18:09:54 -0500305
ethannicholase9709e82016-01-07 13:34:16 -0800306/***************************************************************************************/
307
Chris Dalton75887a22021-01-06 00:23:13 -0700308void GrTriangulator::MonotonePoly::addEdge(Edge* edge) {
309 if (fSide == Side::kRight) {
310 SkASSERT(!edge->fUsedInRightPoly);
311 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
312 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
313 edge->fUsedInRightPoly = true;
314 } else {
315 SkASSERT(!edge->fUsedInLeftPoly);
316 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
317 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
318 edge->fUsedInLeftPoly = true;
ethannicholase9709e82016-01-07 13:34:16 -0800319 }
Chris Dalton75887a22021-01-06 00:23:13 -0700320}
ethannicholase9709e82016-01-07 13:34:16 -0800321
Chris Dalton75887a22021-01-06 00:23:13 -0700322void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* vertexData) {
323 int winding = monotonePoly->fWinding;
324 Edge* e = monotonePoly->fFirstEdge;
325 VertexList vertices;
326 vertices.append(e->fTop);
327 int count = 1;
328 while (e != nullptr) {
329 if (Side::kRight == monotonePoly->fSide) {
330 vertices.append(e->fBottom);
331 e = e->fRightPolyNext;
senorblanco212c7c32016-08-18 10:20:47 -0700332 } else {
Chris Dalton75887a22021-01-06 00:23:13 -0700333 vertices.prepend(e->fBottom);
334 e = e->fLeftPolyNext;
senorblanco212c7c32016-08-18 10:20:47 -0700335 }
Chris Dalton75887a22021-01-06 00:23:13 -0700336 count++;
ethannicholase9709e82016-01-07 13:34:16 -0800337 }
Chris Dalton75887a22021-01-06 00:23:13 -0700338 Vertex* first = vertices.fHead;
339 Vertex* v = first->fNext;
340 while (v != vertices.fTail) {
341 SkASSERT(v && v->fPrev && v->fNext);
342 Vertex* prev = v->fPrev;
343 Vertex* curr = v;
344 Vertex* next = v->fNext;
345 if (count == 3) {
346 return this->emitTriangle(prev, curr, next, winding, vertexData);
ethannicholase9709e82016-01-07 13:34:16 -0800347 }
Chris Dalton75887a22021-01-06 00:23:13 -0700348 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
349 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
350 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
351 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
352 if (ax * by - ay * bx >= 0.0) {
353 vertexData = this->emitTriangle(prev, curr, next, winding, vertexData);
354 v->fPrev->fNext = v->fNext;
355 v->fNext->fPrev = v->fPrev;
356 count--;
357 if (v->fPrev == first) {
358 v = v->fNext;
359 } else {
360 v = v->fPrev;
361 }
362 } else {
363 v = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -0800364 }
Chris Dalton75887a22021-01-06 00:23:13 -0700365 }
366 return vertexData;
367}
368
369void* GrTriangulator::emitTriangle(const Vertex* prev, const Vertex* curr, const Vertex* next,
370 int winding, void* vertexData) const {
371 SkASSERT(winding != 0);
372 if (winding < 0) {
373 // Ensure our triangles always wind in the same direction as if the path had been
374 // triangulated as a simple fan (a la red book).
375 std::swap(prev, next);
376 }
377 return emit_triangle(next, curr, prev, fEmitCoverage, vertexData);
378}
379
380Poly* GrTriangulator::Poly::addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
381 TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n",
382 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
383 Poly* partner = fPartner;
384 Poly* poly = this;
385 if (side == Side::kRight) {
386 if (e->fUsedInRightPoly) {
387 return this;
388 }
389 } else {
390 if (e->fUsedInLeftPoly) {
391 return this;
392 }
393 }
394 if (partner) {
395 fPartner = partner->fPartner = nullptr;
396 }
397 if (!fTail) {
398 fHead = fTail = alloc.make<MonotonePoly>(e, side, fWinding);
399 fCount += 2;
400 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
401 return poly;
402 } else if (side == fTail->fSide) {
403 fTail->addEdge(e);
404 fCount++;
405 } else {
406 e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, EdgeType::kInner);
407 fTail->addEdge(e);
408 fCount++;
409 if (partner) {
410 partner->addEdge(e, side, alloc);
411 poly = partner;
412 } else {
413 MonotonePoly* m = alloc.make<MonotonePoly>(e, side, fWinding);
414 m->fPrev = fTail;
415 fTail->fNext = m;
416 fTail = m;
417 }
418 }
419 return poly;
420}
421
422void* GrTriangulator::emitPoly(const Poly* poly, void *data) {
423 if (poly->fCount < 3) {
ethannicholase9709e82016-01-07 13:34:16 -0800424 return data;
425 }
Chris Dalton75887a22021-01-06 00:23:13 -0700426 TESS_LOG("emit() %d, size %d\n", fID, fCount);
427 for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) {
428 data = this->emitMonotonePoly(m, data);
429 }
430 return data;
431}
ethannicholase9709e82016-01-07 13:34:16 -0800432
Chris Dalton75887a22021-01-06 00:23:13 -0700433Vertex* GrTriangulator::Poly::lastVertex() const {
434 return fTail ? fTail->fLastEdge->fBottom : fFirstVertex;
435}
ethannicholase9709e82016-01-07 13:34:16 -0800436
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700437static bool coincident(const SkPoint& a, const SkPoint& b) {
ethannicholase9709e82016-01-07 13:34:16 -0800438 return a == b;
439}
440
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700441static Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) {
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500442 Poly* poly = alloc.make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800443 poly->fNext = *head;
444 *head = poly;
445 return poly;
446}
447
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700448void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) {
449 Vertex* v = fAlloc.make<Vertex>(p, 255);
Chris Dalton75887a22021-01-06 00:23:13 -0700450#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -0800451 static float gID = 0.0f;
452 v->fID = gID++;
453#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500454 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800455}
456
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700457static SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
Stephen White36e4f062017-03-27 16:11:31 -0400458 SkQuadCoeff quad(pts);
459 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
460 SkPoint mid = to_point(quad.eval(t));
461 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400462 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
463 return 0;
464 }
Cary Clarkdf429f32017-11-08 11:44:31 -0500465 return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1);
Stephen White36e4f062017-03-27 16:11:31 -0400466}
467
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700468void GrTriangulator::appendQuadraticToContour(const SkPoint pts[3], SkScalar toleranceSqd,
469 VertexList* contour) {
Stephen White36e4f062017-03-27 16:11:31 -0400470 SkQuadCoeff quad(pts);
471 Sk2s aa = quad.fA * quad.fA;
472 SkScalar denom = 2.0f * (aa[0] + aa[1]);
473 Sk2s ab = quad.fA * quad.fB;
474 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
475 int nPoints = 1;
Stephen Whitee40c3612018-01-09 11:49:08 -0500476 SkScalar u = 1.0f;
Stephen White36e4f062017-03-27 16:11:31 -0400477 // Test possible subdivision values only at the point of maximum curvature.
478 // If it passes the flatness metric there, it'll pass everywhere.
Stephen Whitee40c3612018-01-09 11:49:08 -0500479 while (nPoints < GrPathUtils::kMaxPointsPerCurve) {
Stephen White36e4f062017-03-27 16:11:31 -0400480 u = 1.0f / nPoints;
481 if (quad_error_at(pts, t, u) < toleranceSqd) {
482 break;
483 }
484 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800485 }
Stephen White36e4f062017-03-27 16:11:31 -0400486 for (int j = 1; j <= nPoints; j++) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700487 this->appendPointToContour(to_point(quad.eval(j * u)), contour);
Stephen White36e4f062017-03-27 16:11:31 -0400488 }
ethannicholase9709e82016-01-07 13:34:16 -0800489}
490
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700491void GrTriangulator::generateCubicPoints(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
492 const SkPoint& p3, SkScalar tolSqd, VertexList* contour,
493 int pointsLeft) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500494 SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
495 SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
ethannicholase9709e82016-01-07 13:34:16 -0800496 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
497 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700498 this->appendPointToContour(p3, contour);
Stephen White3a9aab92017-03-07 14:07:18 -0500499 return;
ethannicholase9709e82016-01-07 13:34:16 -0800500 }
501 const SkPoint q[] = {
502 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
503 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
504 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
505 };
506 const SkPoint r[] = {
507 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
508 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
509 };
510 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
511 pointsLeft >>= 1;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700512 this->generateCubicPoints(p0, q[0], r[0], s, tolSqd, contour, pointsLeft);
513 this->generateCubicPoints(s, r[1], q[2], p3, tolSqd, contour, pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800514}
515
516// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
517
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700518void GrTriangulator::pathToContours(float tolerance, const SkRect& clipBounds,
519 VertexList* contours) {
ethannicholase9709e82016-01-07 13:34:16 -0800520 SkScalar toleranceSqd = tolerance * tolerance;
Chris Dalton7156db22020-05-07 22:06:28 +0000521 SkPoint pts[4];
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700522 fIsLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500523 VertexList* contour = contours;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700524 SkPath::Iter iter(fPath, false);
525 if (fPath.isInverseFillType()) {
ethannicholase9709e82016-01-07 13:34:16 -0800526 SkPoint quad[4];
527 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700528 for (int i = 3; i >= 0; i--) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700529 this->appendPointToContour(quad[i], contours);
ethannicholase9709e82016-01-07 13:34:16 -0800530 }
Stephen White3a9aab92017-03-07 14:07:18 -0500531 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800532 }
533 SkAutoConicToQuads converter;
Chris Dalton7156db22020-05-07 22:06:28 +0000534 SkPath::Verb verb;
535 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800536 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +0000537 case SkPath::kConic_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700538 fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700539 if (fSimpleInnerPolygons) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700540 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700541 break;
542 }
Chris Dalton7156db22020-05-07 22:06:28 +0000543 SkScalar weight = iter.conicWeight();
544 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
ethannicholase9709e82016-01-07 13:34:16 -0800545 for (int i = 0; i < converter.countQuads(); ++i) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700546 this->appendQuadraticToContour(quadPts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800547 quadPts += 2;
548 }
ethannicholase9709e82016-01-07 13:34:16 -0800549 break;
550 }
Chris Dalton7156db22020-05-07 22:06:28 +0000551 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500552 if (contour->fHead) {
553 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800554 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700555 this->appendPointToContour(pts[0], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800556 break;
Chris Dalton7156db22020-05-07 22:06:28 +0000557 case SkPath::kLine_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700558 this->appendPointToContour(pts[1], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800559 break;
560 }
Chris Dalton7156db22020-05-07 22:06:28 +0000561 case SkPath::kQuad_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700562 fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700563 if (fSimpleInnerPolygons) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700564 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700565 break;
566 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700567 this->appendQuadraticToContour(pts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800568 break;
569 }
Chris Dalton7156db22020-05-07 22:06:28 +0000570 case SkPath::kCubic_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700571 fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700572 if (fSimpleInnerPolygons) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700573 this->appendPointToContour(pts[3], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700574 break;
575 }
ethannicholase9709e82016-01-07 13:34:16 -0800576 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700577 this->generateCubicPoints(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
578 pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800579 break;
580 }
Chris Dalton7156db22020-05-07 22:06:28 +0000581 case SkPath::kClose_Verb:
582 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800583 break;
584 }
585 }
586}
587
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700588static inline bool apply_fill_type(SkPathFillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800589 switch (fillType) {
Mike Reed7d34dc72019-11-26 12:17:17 -0500590 case SkPathFillType::kWinding:
ethannicholase9709e82016-01-07 13:34:16 -0800591 return winding != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500592 case SkPathFillType::kEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800593 return (winding & 1) != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500594 case SkPathFillType::kInverseWinding:
senorblanco7ab96e92016-10-12 06:47:44 -0700595 return winding == 1;
Mike Reed7d34dc72019-11-26 12:17:17 -0500596 case SkPathFillType::kInverseEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800597 return (winding & 1) == 1;
598 default:
599 SkASSERT(false);
600 return false;
601 }
602}
603
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700604static inline bool apply_fill_type(SkPathFillType fillType, Poly* poly) {
Stephen White49789062017-02-21 10:35:49 -0500605 return poly && apply_fill_type(fillType, poly->fWinding);
606}
607
Chris Dalton75887a22021-01-06 00:23:13 -0700608static Edge* new_edge(Vertex* prev, Vertex* next, EdgeType type, const Comparator& c,
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700609 SkArenaAlloc& alloc) {
Stephen White2f4686f2017-01-03 16:20:01 -0500610 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800611 Vertex* top = winding < 0 ? next : prev;
612 Vertex* bottom = winding < 0 ? prev : next;
Herb Derby5cdc9dd2017-02-13 12:10:46 -0500613 return alloc.make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800614}
615
Chris Dalton75887a22021-01-06 00:23:13 -0700616void GrTriangulator::EdgeList::insert(Edge* edge, Edge* prev) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400617 TESS_LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
Chris Dalton75887a22021-01-06 00:23:13 -0700618 SkASSERT(!this->contains(edge));
619 Edge* next = prev ? prev->fRight : fHead;
620 this->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800621}
622
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700623static void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500624 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800625 *left = v->fFirstEdgeAbove->fLeft;
626 *right = v->fLastEdgeAbove->fRight;
627 return;
628 }
629 Edge* next = nullptr;
630 Edge* prev;
631 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
632 if (prev->isLeftOf(v)) {
633 break;
634 }
635 next = prev;
636 }
637 *left = prev;
638 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800639}
640
Chris Dalton75887a22021-01-06 00:23:13 -0700641void GrTriangulator::Vertex::insertEdgeAbove(Edge* edge, const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800642 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500643 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800644 return;
645 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400646 TESS_LOG("insert edge (%g -> %g) above vertex %g\n",
647 edge->fTop->fID, edge->fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800648 Edge* prev = nullptr;
649 Edge* next;
Chris Dalton75887a22021-01-06 00:23:13 -0700650 for (next = fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800651 if (next->isRightOf(edge->fTop)) {
652 break;
653 }
654 prev = next;
655 }
senorblancoe6eaa322016-03-08 09:06:44 -0800656 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
Chris Dalton75887a22021-01-06 00:23:13 -0700657 edge, prev, next, &fFirstEdgeAbove, &fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -0800658}
659
Chris Dalton75887a22021-01-06 00:23:13 -0700660void GrTriangulator::Vertex::insertEdgeBelow(Edge* edge, const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800661 if (edge->fTop->fPoint == edge->fBottom->fPoint ||
Stephen Whitee30cf802017-02-27 11:37:55 -0500662 c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800663 return;
664 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400665 TESS_LOG("insert edge (%g -> %g) below vertex %g\n",
666 edge->fTop->fID, edge->fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800667 Edge* prev = nullptr;
668 Edge* next;
Chris Dalton75887a22021-01-06 00:23:13 -0700669 for (next = fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
ethannicholase9709e82016-01-07 13:34:16 -0800670 if (next->isRightOf(edge->fBottom)) {
671 break;
672 }
673 prev = next;
674 }
senorblancoe6eaa322016-03-08 09:06:44 -0800675 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
Chris Dalton75887a22021-01-06 00:23:13 -0700676 edge, prev, next, &fFirstEdgeBelow, &fLastEdgeBelow);
ethannicholase9709e82016-01-07 13:34:16 -0800677}
678
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700679static void remove_edge_above(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400680 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400681 TESS_LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
682 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800683 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800684 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
685}
686
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700687static void remove_edge_below(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400688 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400689 TESS_LOG("removing edge (%g -> %g) below vertex %g\n",
690 edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800691 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800692 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
693}
694
Chris Dalton75887a22021-01-06 00:23:13 -0700695void GrTriangulator::Edge::disconnect() {
696 remove_edge_above(this);
697 remove_edge_below(this);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500698}
699
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700700static void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700701 const Comparator&);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400702
Chris Dalton75887a22021-01-06 00:23:13 -0700703static void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, const Comparator& c) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400704 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
705 return;
706 }
707 Vertex* v = *current;
Brian Salomon120e7d62019-09-11 10:29:22 -0400708 TESS_LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400709 while (v != dst) {
710 v = v->fPrev;
711 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton75887a22021-01-06 00:23:13 -0700712 activeEdges->remove(e);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400713 }
714 Edge* leftEdge = v->fLeftEnclosingEdge;
715 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton75887a22021-01-06 00:23:13 -0700716 activeEdges->insert(e, leftEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400717 leftEdge = e;
Stephen Whitec03e6982020-02-06 16:32:14 -0500718 Vertex* top = e->fTop;
719 if (c.sweep_lt(top->fPoint, dst->fPoint) &&
720 ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) ||
721 (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) {
722 dst = top;
723 }
Stephen White3b5a3fa2017-06-06 14:51:19 -0400724 }
725 }
726 *current = v;
727}
728
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700729static void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700730 const Comparator& c) {
Stephen Whitec03e6982020-02-06 16:32:14 -0500731 if (!activeEdges || !current) {
732 return;
733 }
734 Vertex* top = edge->fTop;
735 Vertex* bottom = edge->fBottom;
736 if (edge->fLeft) {
737 Vertex* leftTop = edge->fLeft->fTop;
738 Vertex* leftBottom = edge->fLeft->fBottom;
739 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
740 rewind(activeEdges, current, leftTop, c);
741 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
742 rewind(activeEdges, current, top, c);
743 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
744 !edge->fLeft->isLeftOf(bottom)) {
745 rewind(activeEdges, current, leftTop, c);
746 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
747 rewind(activeEdges, current, top, c);
748 }
749 }
750 if (edge->fRight) {
751 Vertex* rightTop = edge->fRight->fTop;
752 Vertex* rightBottom = edge->fRight->fBottom;
753 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
754 rewind(activeEdges, current, rightTop, c);
755 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
756 rewind(activeEdges, current, top, c);
757 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
758 !edge->fRight->isRightOf(bottom)) {
759 rewind(activeEdges, current, rightTop, c);
760 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
761 !edge->isLeftOf(rightBottom)) {
762 rewind(activeEdges, current, top, c);
763 }
764 }
765}
766
Chris Dalton75887a22021-01-06 00:23:13 -0700767static void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
768 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800769 remove_edge_below(edge);
770 edge->fTop = v;
771 edge->recompute();
Chris Dalton75887a22021-01-06 00:23:13 -0700772 v->insertEdgeBelow(edge, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500773 rewind_if_necessary(edge, activeEdges, current, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400774 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800775}
776
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700777static void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700778 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800779 remove_edge_above(edge);
780 edge->fBottom = v;
781 edge->recompute();
Chris Dalton75887a22021-01-06 00:23:13 -0700782 v->insertEdgeAbove(edge, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500783 rewind_if_necessary(edge, activeEdges, current, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400784 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800785}
786
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700787static void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700788 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800789 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400790 TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
791 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
792 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400793 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800794 other->fWinding += edge->fWinding;
Chris Dalton75887a22021-01-06 00:23:13 -0700795 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400796 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800797 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400798 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800799 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400800 set_bottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800801 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400802 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800803 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400804 set_bottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800805 }
806}
807
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700808static void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700809 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800810 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400811 TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
812 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
813 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400814 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800815 other->fWinding += edge->fWinding;
Chris Dalton75887a22021-01-06 00:23:13 -0700816 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400817 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800818 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400819 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800820 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400821 set_top(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800822 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400823 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800824 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400825 set_top(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800826 }
827}
828
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700829static bool top_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400830 if (!left || !right) {
831 return false;
832 }
833 return left->fTop->fPoint == right->fTop->fPoint ||
834 !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop);
835}
836
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700837static bool bottom_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400838 if (!left || !right) {
839 return false;
840 }
841 return left->fBottom->fPoint == right->fBottom->fPoint ||
842 !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom);
843}
844
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700845static void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700846 const Comparator& c) {
Stephen White6eca90f2017-05-25 14:47:11 -0400847 for (;;) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400848 if (top_collinear(edge->fPrevEdgeAbove, edge)) {
Stephen White24289e02018-06-29 17:02:21 -0400849 merge_edges_above(edge->fPrevEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400850 } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
Stephen White24289e02018-06-29 17:02:21 -0400851 merge_edges_above(edge->fNextEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400852 } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
Stephen White24289e02018-06-29 17:02:21 -0400853 merge_edges_below(edge->fPrevEdgeBelow, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400854 } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
Stephen White24289e02018-06-29 17:02:21 -0400855 merge_edges_below(edge->fNextEdgeBelow, edge, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400856 } else {
857 break;
858 }
ethannicholase9709e82016-01-07 13:34:16 -0800859 }
Stephen Whited26b4d82018-07-26 10:02:27 -0400860 SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge));
861 SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove));
862 SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge));
863 SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow));
ethannicholase9709e82016-01-07 13:34:16 -0800864}
865
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700866bool GrTriangulator::splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton75887a22021-01-06 00:23:13 -0700867 const Comparator& c) {
Stephen Whiteec79c392018-05-18 11:49:21 -0400868 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
Stephen White89042d52018-06-08 12:18:22 -0400869 return false;
Stephen White0cb31672017-06-08 14:41:01 -0400870 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400871 TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
872 edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400873 Vertex* top;
874 Vertex* bottom;
Stephen White531a48e2018-06-01 09:49:39 -0400875 int winding = edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800876 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400877 top = v;
878 bottom = edge->fTop;
879 set_top(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -0500880 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400881 top = edge->fBottom;
882 bottom = v;
883 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800884 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400885 top = v;
886 bottom = edge->fBottom;
887 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800888 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700889 Edge* newEdge = fAlloc.make<Edge>(top, bottom, winding, edge->fType);
Chris Dalton75887a22021-01-06 00:23:13 -0700890 top->insertEdgeBelow(newEdge, c);
891 bottom->insertEdgeAbove(newEdge, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400892 merge_collinear_edges(newEdge, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400893 return true;
894}
895
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700896bool GrTriangulator::intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton75887a22021-01-06 00:23:13 -0700897 Vertex** current, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -0400898 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
899 return false;
900 }
Stephen White1c5fd182018-07-12 15:54:05 -0400901 if (left->fTop == right->fTop || left->fBottom == right->fBottom) {
902 return false;
903 }
Stephen White89042d52018-06-08 12:18:22 -0400904 if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
905 if (!left->isLeftOf(right->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400906 rewind(activeEdges, current, right->fTop, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700907 return this->splitEdge(left, right->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400908 }
909 } else {
910 if (!right->isRightOf(left->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400911 rewind(activeEdges, current, left->fTop, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700912 return this->splitEdge(right, left->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400913 }
914 }
915 if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
916 if (!left->isLeftOf(right->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400917 rewind(activeEdges, current, right->fBottom, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700918 return this->splitEdge(left, right->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400919 }
920 } else {
921 if (!right->isRightOf(left->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400922 rewind(activeEdges, current, left->fBottom, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700923 return this->splitEdge(right, left->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400924 }
925 }
926 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800927}
928
Chris Dalton75887a22021-01-06 00:23:13 -0700929static Edge* connect(Vertex* prev, Vertex* next, EdgeType type, const Comparator& c,
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700930 SkArenaAlloc& alloc, int winding_scale = 1) {
Stephen Whitee260c462017-12-19 18:09:54 -0500931 if (!prev || !next || prev->fPoint == next->fPoint) {
932 return nullptr;
933 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500934 Edge* edge = new_edge(prev, next, type, c, alloc);
Chris Dalton75887a22021-01-06 00:23:13 -0700935 edge->fTop->insertEdgeBelow(edge, c);
936 edge->fBottom->insertEdgeAbove(edge, c);
Stephen White48ded382017-02-03 10:15:16 -0500937 edge->fWinding *= winding_scale;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400938 merge_collinear_edges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -0700939 return edge;
940}
941
Chris Dalton75887a22021-01-06 00:23:13 -0700942static void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, const Comparator& c) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400943 TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
944 src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
Brian Osman788b9162020-02-07 10:36:46 -0500945 dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -0400946 if (src->fPartner) {
947 src->fPartner->fPartner = dst;
948 }
Stephen White7b376942018-05-22 11:51:32 -0400949 while (Edge* edge = src->fFirstEdgeAbove) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400950 set_bottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800951 }
Stephen White7b376942018-05-22 11:51:32 -0400952 while (Edge* edge = src->fFirstEdgeBelow) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400953 set_top(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800954 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500955 mesh->remove(src);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400956 dst->fSynthetic = true;
ethannicholase9709e82016-01-07 13:34:16 -0800957}
958
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700959static Vertex* create_sorted_vertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
Chris Dalton75887a22021-01-06 00:23:13 -0700960 Vertex* reference, const Comparator& c, SkArenaAlloc& alloc) {
Stephen White95152e12017-12-18 10:52:44 -0500961 Vertex* prevV = reference;
962 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
963 prevV = prevV->fPrev;
964 }
965 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
966 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
967 prevV = nextV;
968 nextV = nextV->fNext;
969 }
970 Vertex* v;
971 if (prevV && coincident(prevV->fPoint, p)) {
972 v = prevV;
973 } else if (nextV && coincident(nextV->fPoint, p)) {
974 v = nextV;
975 } else {
976 v = alloc.make<Vertex>(p, alpha);
Chris Dalton75887a22021-01-06 00:23:13 -0700977#if TRIANGULATOR_LOGGING
Stephen White95152e12017-12-18 10:52:44 -0500978 if (!prevV) {
979 v->fID = mesh->fHead->fID - 1.0f;
980 } else if (!nextV) {
981 v->fID = mesh->fTail->fID + 1.0f;
982 } else {
983 v->fID = (prevV->fID + nextV->fID) * 0.5f;
984 }
985#endif
986 mesh->insert(v, prevV, nextV);
987 }
988 return v;
989}
990
Stephen White53a02982018-05-30 22:47:46 -0400991// If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary
992// sort criterion, it may not be possible to split correctly, since there is no point which is
993// below the top and above the bottom. This function detects that case.
Chris Dalton75887a22021-01-06 00:23:13 -0700994static bool nearly_flat(const Comparator& c, Edge* edge) {
Stephen White53a02982018-05-30 22:47:46 -0400995 SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint;
996 float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY;
Stephen White13f3d8d2018-06-22 10:19:20 -0400997 return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f;
Stephen White53a02982018-05-30 22:47:46 -0400998}
999
Chris Dalton75887a22021-01-06 00:23:13 -07001000static SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, const Comparator& c) {
Stephen Whitee62999f2018-06-05 18:45:07 -04001001 if (c.sweep_lt(p, min)) {
1002 return min;
1003 } else if (c.sweep_lt(max, p)) {
1004 return max;
1005 } else {
1006 return p;
1007 }
1008}
1009
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001010static void compute_bisector(Edge* edge1, Edge* edge2, Vertex* v, SkArenaAlloc& alloc) {
Stephen Whitec4dbc372019-05-22 10:50:14 -04001011 Line line1 = edge1->fLine;
1012 Line line2 = edge2->fLine;
1013 line1.normalize();
1014 line2.normalize();
1015 double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB;
1016 if (cosAngle > 0.999) {
1017 return;
1018 }
1019 line1.fC += edge1->fWinding > 0 ? -1 : 1;
1020 line2.fC += edge2->fWinding > 0 ? -1 : 1;
1021 SkPoint p;
1022 if (line1.intersect(line2, &p)) {
Chris Dalton75887a22021-01-06 00:23:13 -07001023 uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0;
Stephen Whitec4dbc372019-05-22 10:50:14 -04001024 v->fPartner = alloc.make<Vertex>(p, alpha);
Brian Salomon120e7d62019-09-11 10:29:22 -04001025 TESS_LOG("computed bisector (%g,%g) alpha %d for vertex %g\n", p.fX, p.fY, alpha, v->fID);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001026 }
1027}
1028
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001029bool GrTriangulator::checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton75887a22021-01-06 00:23:13 -07001030 Vertex** current, VertexList* mesh, const Comparator& c) {
Stephen Whiteb141fcb2018-06-14 10:15:47 -04001031 if (!left || !right) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001032 return false;
ethannicholase9709e82016-01-07 13:34:16 -08001033 }
Stephen White56158ae2017-01-30 14:31:31 -05001034 SkPoint p;
1035 uint8_t alpha;
Stephen Whiteb141fcb2018-06-14 10:15:47 -04001036 if (left->intersect(*right, &p, &alpha) && p.isFinite()) {
Ravi Mistrybfe95982018-05-29 18:19:07 +00001037 Vertex* v;
Brian Salomon120e7d62019-09-11 10:29:22 -04001038 TESS_LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001039 Vertex* top = *current;
1040 // If the intersection point is above the current vertex, rewind to the vertex above the
1041 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -04001042 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -04001043 top = top->fPrev;
1044 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -04001045 if (!nearly_flat(c, left)) {
1046 p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -04001047 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -04001048 if (!nearly_flat(c, right)) {
1049 p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -04001050 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -04001051 if (p == left->fTop->fPoint) {
1052 v = left->fTop;
1053 } else if (p == left->fBottom->fPoint) {
1054 v = left->fBottom;
1055 } else if (p == right->fTop->fPoint) {
1056 v = right->fTop;
1057 } else if (p == right->fBottom->fPoint) {
1058 v = right->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +00001059 } else {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001060 v = create_sorted_vertex(p, alpha, mesh, top, c, fAlloc);
Stephen Whiteb141fcb2018-06-14 10:15:47 -04001061 if (left->fTop->fPartner) {
Stephen Whitec4dbc372019-05-22 10:50:14 -04001062 v->fSynthetic = true;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001063 compute_bisector(left, right, v, fAlloc);
Stephen Whitee260c462017-12-19 18:09:54 -05001064 }
ethannicholase9709e82016-01-07 13:34:16 -08001065 }
Stephen White0cb31672017-06-08 14:41:01 -04001066 rewind(activeEdges, current, top ? top : v, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001067 this->splitEdge(left, v, activeEdges, current, c);
1068 this->splitEdge(right, v, activeEdges, current, c);
Brian Osman788b9162020-02-07 10:36:46 -05001069 v->fAlpha = std::max(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001070 return true;
ethannicholase9709e82016-01-07 13:34:16 -08001071 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001072 return this->intersectEdgePair(left, right, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -08001073}
1074
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001075void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) {
Stephen White3a9aab92017-03-07 14:07:18 -05001076 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1077 SkASSERT(contour->fHead);
1078 Vertex* prev = contour->fTail;
Chris Dalton854ee852021-01-05 15:12:59 -07001079 if (fRoundVerticesToQuarterPixel) {
Stephen White3a9aab92017-03-07 14:07:18 -05001080 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -05001081 }
Stephen White3a9aab92017-03-07 14:07:18 -05001082 for (Vertex* v = contour->fHead; v;) {
Chris Dalton854ee852021-01-05 15:12:59 -07001083 if (fRoundVerticesToQuarterPixel) {
senorblancof57372d2016-08-31 10:36:19 -07001084 round(&v->fPoint);
1085 }
Stephen White3a9aab92017-03-07 14:07:18 -05001086 Vertex* next = v->fNext;
Stephen White3de40f82018-06-28 09:36:49 -04001087 Vertex* nextWrap = next ? next : contour->fHead;
Stephen White3a9aab92017-03-07 14:07:18 -05001088 if (coincident(prev->fPoint, v->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001089 TESS_LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001090 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -04001091 } else if (!v->fPoint.isFinite()) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001092 TESS_LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White73e7f802017-08-23 13:56:07 -04001093 contour->remove(v);
Chris Dalton854ee852021-01-05 15:12:59 -07001094 } else if (fCullCollinearVertices &&
Chris Dalton6ccc0322020-01-29 11:38:16 -07001095 Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001096 TESS_LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White06768ca2018-05-25 14:50:56 -04001097 contour->remove(v);
1098 } else {
1099 prev = v;
ethannicholase9709e82016-01-07 13:34:16 -08001100 }
Stephen White3a9aab92017-03-07 14:07:18 -05001101 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001102 }
1103 }
1104}
1105
Chris Dalton75887a22021-01-06 00:23:13 -07001106bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001107 if (!mesh->fHead) {
Stephen Whitee260c462017-12-19 18:09:54 -05001108 return false;
Stephen Whitebda29c02017-03-13 15:10:13 -04001109 }
Stephen Whitee260c462017-12-19 18:09:54 -05001110 bool merged = false;
1111 for (Vertex* v = mesh->fHead->fNext; v;) {
1112 Vertex* next = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -08001113 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1114 v->fPoint = v->fPrev->fPoint;
1115 }
1116 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001117 merge_vertices(v, v->fPrev, mesh, c);
Stephen Whitee260c462017-12-19 18:09:54 -05001118 merged = true;
ethannicholase9709e82016-01-07 13:34:16 -08001119 }
Stephen Whitee260c462017-12-19 18:09:54 -05001120 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001121 }
Stephen Whitee260c462017-12-19 18:09:54 -05001122 return merged;
ethannicholase9709e82016-01-07 13:34:16 -08001123}
1124
1125// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1126
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001127void GrTriangulator::buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton75887a22021-01-06 00:23:13 -07001128 const Comparator& c) {
Stephen White3a9aab92017-03-07 14:07:18 -05001129 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1130 Vertex* prev = contour->fTail;
1131 for (Vertex* v = contour->fHead; v;) {
1132 Vertex* next = v->fNext;
Chris Dalton75887a22021-01-06 00:23:13 -07001133 connect(prev, v, EdgeType::kInner, c, fAlloc);
Stephen White3a9aab92017-03-07 14:07:18 -05001134 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001135 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001136 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001137 }
1138 }
ethannicholase9709e82016-01-07 13:34:16 -08001139}
1140
Chris Dalton75887a22021-01-06 00:23:13 -07001141static void connect_partners(VertexList* mesh, const Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitee260c462017-12-19 18:09:54 -05001142 for (Vertex* outer = mesh->fHead; outer; outer = outer->fNext) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001143 if (Vertex* inner = outer->fPartner) {
Stephen Whitee260c462017-12-19 18:09:54 -05001144 if ((inner->fPrev || inner->fNext) && (outer->fPrev || outer->fNext)) {
1145 // Connector edges get zero winding, since they're only structural (i.e., to ensure
1146 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding
1147 // number.
Chris Dalton75887a22021-01-06 00:23:13 -07001148 connect(outer, inner, EdgeType::kConnector, c, alloc, 0);
Stephen Whitee260c462017-12-19 18:09:54 -05001149 inner->fPartner = outer->fPartner = nullptr;
1150 }
Stephen Whitebda29c02017-03-13 15:10:13 -04001151 }
1152 }
1153}
1154
1155template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001156static void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001157 Vertex* a = front->fHead;
1158 Vertex* b = back->fHead;
1159 while (a && b) {
1160 if (sweep_lt(a->fPoint, b->fPoint)) {
1161 front->remove(a);
1162 result->append(a);
1163 a = front->fHead;
1164 } else {
1165 back->remove(b);
1166 result->append(b);
1167 b = back->fHead;
1168 }
1169 }
1170 result->append(*front);
1171 result->append(*back);
1172}
1173
Chris Dalton75887a22021-01-06 00:23:13 -07001174static void sorted_merge(VertexList* front, VertexList* back, VertexList* result,
1175 const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001176 if (c.fDirection == Comparator::Direction::kHorizontal) {
1177 sorted_merge<sweep_lt_horiz>(front, back, result);
1178 } else {
1179 sorted_merge<sweep_lt_vert>(front, back, result);
1180 }
Chris Dalton75887a22021-01-06 00:23:13 -07001181#if TRIANGULATOR_LOGGING
Stephen White3b5a3fa2017-06-06 14:51:19 -04001182 float id = 0.0f;
1183 for (Vertex* v = result->fHead; v; v = v->fNext) {
1184 v->fID = id++;
1185 }
1186#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001187}
1188
ethannicholase9709e82016-01-07 13:34:16 -08001189// Stage 3: sort the vertices by increasing sweep direction.
1190
Stephen White16a40cb2017-02-23 11:10:01 -05001191template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001192static void merge_sort(VertexList* vertices) {
Stephen White16a40cb2017-02-23 11:10:01 -05001193 Vertex* slow = vertices->fHead;
1194 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001195 return;
1196 }
Stephen White16a40cb2017-02-23 11:10:01 -05001197 Vertex* fast = slow->fNext;
1198 if (!fast) {
1199 return;
1200 }
1201 do {
1202 fast = fast->fNext;
1203 if (fast) {
1204 fast = fast->fNext;
1205 slow = slow->fNext;
1206 }
1207 } while (fast);
1208 VertexList front(vertices->fHead, slow);
1209 VertexList back(slow->fNext, vertices->fTail);
1210 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001211
Stephen White16a40cb2017-02-23 11:10:01 -05001212 merge_sort<sweep_lt>(&front);
1213 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001214
Stephen White16a40cb2017-02-23 11:10:01 -05001215 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001216 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001217}
1218
Chris Dalton75887a22021-01-06 00:23:13 -07001219#if TRIANGULATOR_LOGGING
1220void GrTriangulator::VertexList::dump() {
1221 for (Vertex* v = fHead; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001222 TESS_LOG("vertex %g (%g, %g) alpha %d", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001223 if (Vertex* p = v->fPartner) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001224 TESS_LOG(", partner %g (%g, %g) alpha %d\n",
1225 p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001226 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001227 TESS_LOG(", null partner\n");
Stephen White95152e12017-12-18 10:52:44 -05001228 }
1229 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001230 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001231 }
1232 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001233 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001234 }
1235 }
Stephen White95152e12017-12-18 10:52:44 -05001236}
Chris Dalton75887a22021-01-06 00:23:13 -07001237#endif
Stephen White95152e12017-12-18 10:52:44 -05001238
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001239static void dump_skel(const SSEdgeList& ssEdges) {
Chris Dalton75887a22021-01-06 00:23:13 -07001240#if TRIANGULATOR_LOGGING
Stephen Whitec4dbc372019-05-22 10:50:14 -04001241 for (SSEdge* edge : ssEdges) {
1242 if (edge->fEdge) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001243 TESS_LOG("skel edge %g -> %g",
Stephen Whitec4dbc372019-05-22 10:50:14 -04001244 edge->fPrev->fVertex->fID,
Stephen White8a3c0592019-05-29 11:26:16 -04001245 edge->fNext->fVertex->fID);
1246 if (edge->fEdge->fTop && edge->fEdge->fBottom) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001247 TESS_LOG(" (original %g -> %g)\n",
1248 edge->fEdge->fTop->fID,
1249 edge->fEdge->fBottom->fID);
Stephen White8a3c0592019-05-29 11:26:16 -04001250 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001251 TESS_LOG("\n");
Stephen White8a3c0592019-05-29 11:26:16 -04001252 }
Stephen Whitec4dbc372019-05-22 10:50:14 -04001253 }
1254 }
1255#endif
1256}
1257
Stephen White89042d52018-06-08 12:18:22 -04001258#ifdef SK_DEBUG
Chris Dalton75887a22021-01-06 00:23:13 -07001259static void validate_edge_pair(Edge* left, Edge* right, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001260 if (!left || !right) {
1261 return;
1262 }
1263 if (left->fTop == right->fTop) {
1264 SkASSERT(left->isLeftOf(right->fBottom));
1265 SkASSERT(right->isRightOf(left->fBottom));
1266 } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
1267 SkASSERT(left->isLeftOf(right->fTop));
1268 } else {
1269 SkASSERT(right->isRightOf(left->fTop));
1270 }
1271 if (left->fBottom == right->fBottom) {
1272 SkASSERT(left->isLeftOf(right->fTop));
1273 SkASSERT(right->isRightOf(left->fTop));
1274 } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
1275 SkASSERT(left->isLeftOf(right->fBottom));
1276 } else {
1277 SkASSERT(right->isRightOf(left->fBottom));
1278 }
1279}
1280
Chris Dalton75887a22021-01-06 00:23:13 -07001281static void validate_edge_list(EdgeList* edges, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001282 Edge* left = edges->fHead;
1283 if (!left) {
1284 return;
1285 }
1286 for (Edge* right = left->fRight; right; right = right->fRight) {
1287 validate_edge_pair(left, right, c);
1288 left = right;
1289 }
1290}
1291#endif
1292
ethannicholase9709e82016-01-07 13:34:16 -08001293// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1294
Chris Dalton75887a22021-01-06 00:23:13 -07001295GrTriangulator::SimplifyResult GrTriangulator::simplify(VertexList* mesh, const Comparator& c) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001296 TESS_LOG("simplifying complex polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001297 EdgeList activeEdges;
Chris Dalton6ccc0322020-01-29 11:38:16 -07001298 auto result = SimplifyResult::kAlreadySimple;
Stephen White0cb31672017-06-08 14:41:01 -04001299 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
Chris Dalton75887a22021-01-06 00:23:13 -07001300 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001301 continue;
1302 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001303 Edge* leftEnclosingEdge;
1304 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001305 bool restartChecks;
1306 do {
Brian Salomon120e7d62019-09-11 10:29:22 -04001307 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1308 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001309 restartChecks = false;
1310 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001311 v->fLeftEnclosingEdge = leftEnclosingEdge;
1312 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001313 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001314 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001315 if (this->checkForIntersection(
1316 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c) ||
1317 this->checkForIntersection(
1318 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c)) {
Chris Dalton854ee852021-01-05 15:12:59 -07001319 if (fSimpleInnerPolygons) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001320 return SimplifyResult::kAbort;
1321 }
1322 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001323 restartChecks = true;
1324 break;
1325 }
1326 }
1327 } else {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001328 if (this->checkForIntersection(leftEnclosingEdge, rightEnclosingEdge, &activeEdges,
1329 &v, mesh, c)) {
Chris Dalton854ee852021-01-05 15:12:59 -07001330 if (fSimpleInnerPolygons) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001331 return SimplifyResult::kAbort;
1332 }
1333 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001334 restartChecks = true;
1335 }
1336
1337 }
1338 } while (restartChecks);
Stephen White89042d52018-06-08 12:18:22 -04001339#ifdef SK_DEBUG
1340 validate_edge_list(&activeEdges, c);
1341#endif
ethannicholase9709e82016-01-07 13:34:16 -08001342 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton75887a22021-01-06 00:23:13 -07001343 activeEdges.remove(e);
ethannicholase9709e82016-01-07 13:34:16 -08001344 }
1345 Edge* leftEdge = leftEnclosingEdge;
1346 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton75887a22021-01-06 00:23:13 -07001347 activeEdges.insert(e, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001348 leftEdge = e;
1349 }
ethannicholase9709e82016-01-07 13:34:16 -08001350 }
Stephen Whitee260c462017-12-19 18:09:54 -05001351 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
Chris Dalton6ccc0322020-01-29 11:38:16 -07001352 return result;
ethannicholase9709e82016-01-07 13:34:16 -08001353}
1354
1355// Stage 5: Tessellate the simplified mesh into monotone polygons.
1356
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001357Poly* GrTriangulator::tessellate(const VertexList& vertices) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001358 TESS_LOG("\ntessellating simple polygons\n");
Chris Dalton6ccc0322020-01-29 11:38:16 -07001359 int maxWindMagnitude = std::numeric_limits<int>::max();
Chris Dalton854ee852021-01-05 15:12:59 -07001360 if (fSimpleInnerPolygons && !SkPathFillType_IsEvenOdd(fPath.getFillType())) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001361 maxWindMagnitude = 1;
1362 }
ethannicholase9709e82016-01-07 13:34:16 -08001363 EdgeList activeEdges;
1364 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001365 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
Chris Dalton75887a22021-01-06 00:23:13 -07001366 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001367 continue;
1368 }
Chris Dalton75887a22021-01-06 00:23:13 -07001369#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001370 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001371#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001372 Edge* leftEnclosingEdge;
1373 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001374 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001375 Poly* leftPoly;
1376 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001377 if (v->fFirstEdgeAbove) {
1378 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1379 rightPoly = v->fLastEdgeAbove->fRightPoly;
1380 } else {
1381 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1382 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1383 }
Chris Dalton75887a22021-01-06 00:23:13 -07001384#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001385 TESS_LOG("edges above:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001386 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001387 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1388 e->fTop->fID, e->fBottom->fID,
1389 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1390 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001391 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001392 TESS_LOG("edges below:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001393 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001394 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1395 e->fTop->fID, e->fBottom->fID,
1396 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1397 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001398 }
1399#endif
1400 if (v->fFirstEdgeAbove) {
1401 if (leftPoly) {
Chris Dalton75887a22021-01-06 00:23:13 -07001402 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Side::kRight, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001403 }
1404 if (rightPoly) {
Chris Dalton75887a22021-01-06 00:23:13 -07001405 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Side::kLeft, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001406 }
1407 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001408 Edge* rightEdge = e->fNextEdgeAbove;
Chris Dalton75887a22021-01-06 00:23:13 -07001409 activeEdges.remove(e);
Stephen White8a0bfc52017-02-21 15:24:13 -05001410 if (e->fRightPoly) {
Chris Dalton75887a22021-01-06 00:23:13 -07001411 e->fRightPoly->addEdge(e, Side::kLeft, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001412 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001413 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
Chris Dalton75887a22021-01-06 00:23:13 -07001414 rightEdge->fLeftPoly->addEdge(e, Side::kRight, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001415 }
1416 }
Chris Dalton75887a22021-01-06 00:23:13 -07001417 activeEdges.remove(v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -08001418 if (!v->fFirstEdgeBelow) {
1419 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1420 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1421 rightPoly->fPartner = leftPoly;
1422 leftPoly->fPartner = rightPoly;
1423 }
1424 }
1425 }
1426 if (v->fFirstEdgeBelow) {
1427 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001428 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001429 if (leftPoly == rightPoly) {
Chris Dalton75887a22021-01-06 00:23:13 -07001430 if (leftPoly->fTail && leftPoly->fTail->fSide == Side::kLeft) {
senorblanco531237e2016-06-02 11:36:48 -07001431 leftPoly = new_poly(&polys, leftPoly->lastVertex(),
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001432 leftPoly->fWinding, fAlloc);
senorblanco531237e2016-06-02 11:36:48 -07001433 leftEnclosingEdge->fRightPoly = leftPoly;
1434 } else {
1435 rightPoly = new_poly(&polys, rightPoly->lastVertex(),
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001436 rightPoly->fWinding, fAlloc);
senorblanco531237e2016-06-02 11:36:48 -07001437 rightEnclosingEdge->fLeftPoly = rightPoly;
1438 }
ethannicholase9709e82016-01-07 13:34:16 -08001439 }
Chris Dalton75887a22021-01-06 00:23:13 -07001440 Edge* join = fAlloc.make<Edge>(leftPoly->lastVertex(), v, 1, EdgeType::kInner);
1441 leftPoly = leftPoly->addEdge(join, Side::kRight, fAlloc);
1442 rightPoly = rightPoly->addEdge(join, Side::kLeft, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001443 }
1444 }
1445 Edge* leftEdge = v->fFirstEdgeBelow;
1446 leftEdge->fLeftPoly = leftPoly;
Chris Dalton75887a22021-01-06 00:23:13 -07001447 activeEdges.insert(leftEdge, leftEnclosingEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001448 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1449 rightEdge = rightEdge->fNextEdgeBelow) {
Chris Dalton75887a22021-01-06 00:23:13 -07001450 activeEdges.insert(rightEdge, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001451 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1452 winding += leftEdge->fWinding;
1453 if (winding != 0) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001454 if (abs(winding) > maxWindMagnitude) {
1455 return nullptr; // We can't have weighted wind in kSimpleInnerPolygons mode
1456 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001457 Poly* poly = new_poly(&polys, v, winding, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001458 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1459 }
1460 leftEdge = rightEdge;
1461 }
1462 v->fLastEdgeBelow->fRightPoly = rightPoly;
1463 }
Chris Dalton75887a22021-01-06 00:23:13 -07001464#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001465 TESS_LOG("\nactive edges:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001466 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001467 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1468 e->fTop->fID, e->fBottom->fID,
1469 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1470 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001471 }
1472#endif
1473 }
1474 return polys;
1475}
1476
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001477static void remove_non_boundary_edges(const VertexList& mesh, SkPathFillType fillType,
1478 SkArenaAlloc& alloc) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001479 TESS_LOG("removing non-boundary edges\n");
Stephen White49789062017-02-21 10:35:49 -05001480 EdgeList activeEdges;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001481 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
Chris Dalton75887a22021-01-06 00:23:13 -07001482 if (!v->isConnected()) {
Stephen White49789062017-02-21 10:35:49 -05001483 continue;
1484 }
1485 Edge* leftEnclosingEdge;
1486 Edge* rightEnclosingEdge;
1487 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1488 bool prevFilled = leftEnclosingEdge &&
1489 apply_fill_type(fillType, leftEnclosingEdge->fWinding);
1490 for (Edge* e = v->fFirstEdgeAbove; e;) {
1491 Edge* next = e->fNextEdgeAbove;
Chris Dalton75887a22021-01-06 00:23:13 -07001492 activeEdges.remove(e);
Stephen White49789062017-02-21 10:35:49 -05001493 bool filled = apply_fill_type(fillType, e->fWinding);
1494 if (filled == prevFilled) {
Chris Dalton75887a22021-01-06 00:23:13 -07001495 e->disconnect();
senorblancof57372d2016-08-31 10:36:19 -07001496 }
Stephen White49789062017-02-21 10:35:49 -05001497 prevFilled = filled;
senorblancof57372d2016-08-31 10:36:19 -07001498 e = next;
1499 }
Stephen White49789062017-02-21 10:35:49 -05001500 Edge* prev = leftEnclosingEdge;
1501 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1502 if (prev) {
1503 e->fWinding += prev->fWinding;
1504 }
Chris Dalton75887a22021-01-06 00:23:13 -07001505 activeEdges.insert(e, prev);
Stephen White49789062017-02-21 10:35:49 -05001506 prev = e;
1507 }
senorblancof57372d2016-08-31 10:36:19 -07001508 }
senorblancof57372d2016-08-31 10:36:19 -07001509}
1510
Stephen White66412122017-03-01 11:48:27 -05001511// Note: this is the normal to the edge, but not necessarily unit length.
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001512static void get_edge_normal(const Edge* e, SkVector* normal) {
Stephen Whitee260c462017-12-19 18:09:54 -05001513 normal->set(SkDoubleToScalar(e->fLine.fA),
1514 SkDoubleToScalar(e->fLine.fB));
senorblancof57372d2016-08-31 10:36:19 -07001515}
1516
1517// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
1518// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
1519// invert on stroking.
1520
Chris Dalton75887a22021-01-06 00:23:13 -07001521static void simplify_boundary(EdgeList* boundary, const Comparator& c, SkArenaAlloc& alloc) {
senorblancof57372d2016-08-31 10:36:19 -07001522 Edge* prevEdge = boundary->fTail;
1523 SkVector prevNormal;
1524 get_edge_normal(prevEdge, &prevNormal);
1525 for (Edge* e = boundary->fHead; e != nullptr;) {
1526 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
1527 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
Stephen Whitecfe12642018-09-26 17:25:59 -04001528 double distPrev = e->dist(prev->fPoint);
1529 double distNext = prevEdge->dist(next->fPoint);
senorblancof57372d2016-08-31 10:36:19 -07001530 SkVector normal;
1531 get_edge_normal(e, &normal);
Stephen Whitecfe12642018-09-26 17:25:59 -04001532 constexpr double kQuarterPixelSq = 0.25f * 0.25f;
Stephen Whitec4dbc372019-05-22 10:50:14 -04001533 if (prev == next) {
Chris Dalton75887a22021-01-06 00:23:13 -07001534 boundary->remove(prevEdge);
1535 boundary->remove(e);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001536 prevEdge = boundary->fTail;
1537 e = boundary->fHead;
1538 if (prevEdge) {
1539 get_edge_normal(prevEdge, &prevNormal);
1540 }
1541 } else if (prevNormal.dot(normal) < 0.0 &&
Stephen Whitecfe12642018-09-26 17:25:59 -04001542 (distPrev * distPrev <= kQuarterPixelSq || distNext * distNext <= kQuarterPixelSq)) {
Chris Dalton75887a22021-01-06 00:23:13 -07001543 Edge* join = new_edge(prev, next, EdgeType::kInner, c, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05001544 if (prev->fPoint != next->fPoint) {
1545 join->fLine.normalize();
1546 join->fLine = join->fLine * join->fWinding;
1547 }
Chris Dalton75887a22021-01-06 00:23:13 -07001548 boundary->insert(join, e);
1549 boundary->remove(prevEdge);
1550 boundary->remove(e);
senorblancof57372d2016-08-31 10:36:19 -07001551 if (join->fLeft && join->fRight) {
1552 prevEdge = join->fLeft;
1553 e = join;
1554 } else {
1555 prevEdge = boundary->fTail;
1556 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
1557 }
1558 get_edge_normal(prevEdge, &prevNormal);
1559 } else {
1560 prevEdge = e;
1561 prevNormal = normal;
1562 e = e->fRight;
1563 }
1564 }
1565}
1566
Chris Dalton75887a22021-01-06 00:23:13 -07001567static void ss_connect(Vertex* v, Vertex* dest, const Comparator& c, SkArenaAlloc& alloc) {
Stephen Whitec4dbc372019-05-22 10:50:14 -04001568 if (v == dest) {
1569 return;
Stephen Whitee260c462017-12-19 18:09:54 -05001570 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001571 TESS_LOG("ss_connecting vertex %g to vertex %g\n", v->fID, dest->fID);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001572 if (v->fSynthetic) {
Chris Dalton75887a22021-01-06 00:23:13 -07001573 connect(v, dest, EdgeType::kConnector, c, alloc, 0);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001574 } else if (v->fPartner) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001575 TESS_LOG("setting %g's partner to %g ", v->fPartner->fID, dest->fID);
1576 TESS_LOG("and %g's partner to null\n", v->fID);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001577 v->fPartner->fPartner = dest;
1578 v->fPartner = nullptr;
Stephen Whitee260c462017-12-19 18:09:54 -05001579 }
1580}
1581
Chris Dalton75887a22021-01-06 00:23:13 -07001582void Event::apply(VertexList* mesh, const Comparator& c, EventList* events, SkArenaAlloc& alloc) {
Stephen Whitec4dbc372019-05-22 10:50:14 -04001583 if (!fEdge) {
Stephen Whitee260c462017-12-19 18:09:54 -05001584 return;
1585 }
Stephen Whitec4dbc372019-05-22 10:50:14 -04001586 Vertex* prev = fEdge->fPrev->fVertex;
1587 Vertex* next = fEdge->fNext->fVertex;
1588 SSEdge* prevEdge = fEdge->fPrev->fPrev;
1589 SSEdge* nextEdge = fEdge->fNext->fNext;
1590 if (!prevEdge || !nextEdge || !prevEdge->fEdge || !nextEdge->fEdge) {
1591 return;
Stephen White77169c82018-06-05 09:15:59 -04001592 }
Stephen Whitec4dbc372019-05-22 10:50:14 -04001593 Vertex* dest = create_sorted_vertex(fPoint, fAlpha, mesh, prev, c, alloc);
1594 dest->fSynthetic = true;
1595 SSVertex* ssv = alloc.make<SSVertex>(dest);
Brian Salomon120e7d62019-09-11 10:29:22 -04001596 TESS_LOG("collapsing %g, %g (original edge %g -> %g) to %g (%g, %g) alpha %d\n",
1597 prev->fID, next->fID, fEdge->fEdge->fTop->fID, fEdge->fEdge->fBottom->fID, dest->fID,
1598 fPoint.fX, fPoint.fY, fAlpha);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001599 fEdge->fEdge = nullptr;
Stephen Whitee260c462017-12-19 18:09:54 -05001600
Stephen Whitec4dbc372019-05-22 10:50:14 -04001601 ss_connect(prev, dest, c, alloc);
1602 ss_connect(next, dest, c, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05001603
Stephen Whitec4dbc372019-05-22 10:50:14 -04001604 prevEdge->fNext = nextEdge->fPrev = ssv;
1605 ssv->fPrev = prevEdge;
1606 ssv->fNext = nextEdge;
1607 if (!prevEdge->fEdge || !nextEdge->fEdge) {
1608 return;
1609 }
1610 if (prevEdge->fEvent) {
1611 prevEdge->fEvent->fEdge = nullptr;
1612 }
1613 if (nextEdge->fEvent) {
1614 nextEdge->fEvent->fEdge = nullptr;
1615 }
1616 if (prevEdge->fPrev == nextEdge->fNext) {
1617 ss_connect(prevEdge->fPrev->fVertex, dest, c, alloc);
1618 prevEdge->fEdge = nextEdge->fEdge = nullptr;
1619 } else {
1620 compute_bisector(prevEdge->fEdge, nextEdge->fEdge, dest, alloc);
1621 SkASSERT(prevEdge != fEdge && nextEdge != fEdge);
1622 if (dest->fPartner) {
1623 create_event(prevEdge, events, alloc);
1624 create_event(nextEdge, events, alloc);
1625 } else {
1626 create_event(prevEdge, prevEdge->fPrev->fVertex, nextEdge, dest, events, c, alloc);
1627 create_event(nextEdge, nextEdge->fNext->fVertex, prevEdge, dest, events, c, alloc);
1628 }
1629 }
Stephen Whitee260c462017-12-19 18:09:54 -05001630}
1631
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001632static bool is_overlap_edge(Edge* e) {
Chris Dalton75887a22021-01-06 00:23:13 -07001633 if (e->fType == EdgeType::kOuter) {
Stephen Whitee260c462017-12-19 18:09:54 -05001634 return e->fWinding != 0 && e->fWinding != 1;
Chris Dalton75887a22021-01-06 00:23:13 -07001635 } else if (e->fType == EdgeType::kInner) {
Stephen Whitee260c462017-12-19 18:09:54 -05001636 return e->fWinding != 0 && e->fWinding != -2;
1637 } else {
1638 return false;
1639 }
1640}
1641
1642// This is a stripped-down version of tessellate() which computes edges which
1643// join two filled regions, which represent overlap regions, and collapses them.
Chris Dalton75887a22021-01-06 00:23:13 -07001644static bool collapse_overlap_regions(VertexList* mesh, const Comparator& c, SkArenaAlloc& alloc,
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001645 EventComparator comp) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001646 TESS_LOG("\nfinding overlap regions\n");
Stephen Whitee260c462017-12-19 18:09:54 -05001647 EdgeList activeEdges;
Stephen Whitec4dbc372019-05-22 10:50:14 -04001648 EventList events(comp);
1649 SSVertexMap ssVertices;
1650 SSEdgeList ssEdges;
Stephen Whitee260c462017-12-19 18:09:54 -05001651 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
Chris Dalton75887a22021-01-06 00:23:13 -07001652 if (!v->isConnected()) {
Stephen Whitee260c462017-12-19 18:09:54 -05001653 continue;
1654 }
1655 Edge* leftEnclosingEdge;
1656 Edge* rightEnclosingEdge;
1657 find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001658 for (Edge* e = v->fLastEdgeAbove; e && e != leftEnclosingEdge;) {
Stephen Whitee260c462017-12-19 18:09:54 -05001659 Edge* prev = e->fPrevEdgeAbove ? e->fPrevEdgeAbove : leftEnclosingEdge;
Chris Dalton75887a22021-01-06 00:23:13 -07001660 activeEdges.remove(e);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001661 bool leftOverlap = prev && is_overlap_edge(prev);
1662 bool rightOverlap = is_overlap_edge(e);
Chris Dalton75887a22021-01-06 00:23:13 -07001663 bool isOuterBoundary = e->fType == EdgeType::kOuter &&
Stephen Whitec4dbc372019-05-22 10:50:14 -04001664 (!prev || prev->fWinding == 0 || e->fWinding == 0);
Stephen Whitee260c462017-12-19 18:09:54 -05001665 if (prev) {
1666 e->fWinding -= prev->fWinding;
1667 }
Stephen Whitec4dbc372019-05-22 10:50:14 -04001668 if (leftOverlap && rightOverlap) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001669 TESS_LOG("found interior overlap edge %g -> %g, disconnecting\n",
1670 e->fTop->fID, e->fBottom->fID);
Chris Dalton75887a22021-01-06 00:23:13 -07001671 e->disconnect();
Stephen Whitec4dbc372019-05-22 10:50:14 -04001672 } else if (leftOverlap || rightOverlap) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001673 TESS_LOG("found overlap edge %g -> %g%s\n",
1674 e->fTop->fID, e->fBottom->fID,
1675 isOuterBoundary ? ", is outer boundary" : "");
Stephen Whitec4dbc372019-05-22 10:50:14 -04001676 Vertex* prevVertex = e->fWinding < 0 ? e->fBottom : e->fTop;
1677 Vertex* nextVertex = e->fWinding < 0 ? e->fTop : e->fBottom;
1678 SSVertex* ssPrev = ssVertices[prevVertex];
1679 if (!ssPrev) {
1680 ssPrev = ssVertices[prevVertex] = alloc.make<SSVertex>(prevVertex);
1681 }
1682 SSVertex* ssNext = ssVertices[nextVertex];
1683 if (!ssNext) {
1684 ssNext = ssVertices[nextVertex] = alloc.make<SSVertex>(nextVertex);
1685 }
1686 SSEdge* ssEdge = alloc.make<SSEdge>(e, ssPrev, ssNext);
1687 ssEdges.push_back(ssEdge);
1688// SkASSERT(!ssPrev->fNext && !ssNext->fPrev);
1689 ssPrev->fNext = ssNext->fPrev = ssEdge;
1690 create_event(ssEdge, &events, alloc);
1691 if (!isOuterBoundary) {
Chris Dalton75887a22021-01-06 00:23:13 -07001692 e->disconnect();
Stephen Whitec4dbc372019-05-22 10:50:14 -04001693 }
1694 }
1695 e = prev;
Stephen Whitee260c462017-12-19 18:09:54 -05001696 }
1697 Edge* prev = leftEnclosingEdge;
1698 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1699 if (prev) {
1700 e->fWinding += prev->fWinding;
Stephen Whitee260c462017-12-19 18:09:54 -05001701 }
Chris Dalton75887a22021-01-06 00:23:13 -07001702 activeEdges.insert(e, prev);
Stephen Whitee260c462017-12-19 18:09:54 -05001703 prev = e;
1704 }
1705 }
Stephen Whitec4dbc372019-05-22 10:50:14 -04001706 bool complex = events.size() > 0;
1707
Brian Salomon120e7d62019-09-11 10:29:22 -04001708 TESS_LOG("\ncollapsing overlap regions\n");
1709 TESS_LOG("skeleton before:\n");
Stephen White8a3c0592019-05-29 11:26:16 -04001710 dump_skel(ssEdges);
Stephen Whitec4dbc372019-05-22 10:50:14 -04001711 while (events.size() > 0) {
1712 Event* event = events.top();
Stephen Whitee260c462017-12-19 18:09:54 -05001713 events.pop();
Stephen Whitec4dbc372019-05-22 10:50:14 -04001714 event->apply(mesh, c, &events, alloc);
Stephen Whitee260c462017-12-19 18:09:54 -05001715 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001716 TESS_LOG("skeleton after:\n");
Stephen Whitec4dbc372019-05-22 10:50:14 -04001717 dump_skel(ssEdges);
1718 for (SSEdge* edge : ssEdges) {
1719 if (Edge* e = edge->fEdge) {
1720 connect(edge->fPrev->fVertex, edge->fNext->fVertex, e->fType, c, alloc, 0);
1721 }
1722 }
1723 return complex;
Stephen Whitee260c462017-12-19 18:09:54 -05001724}
1725
Chris Dalton75887a22021-01-06 00:23:13 -07001726static bool inversion(Vertex* prev, Vertex* next, Edge* origEdge, const Comparator& c) {
Stephen Whitee260c462017-12-19 18:09:54 -05001727 if (!prev || !next) {
1728 return true;
1729 }
1730 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
1731 return winding != origEdge->fWinding;
1732}
Stephen White92eba8a2017-02-06 09:50:27 -05001733
senorblancof57372d2016-08-31 10:36:19 -07001734// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
1735// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
1736// new antialiased mesh from those vertices.
1737
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001738static void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh,
Chris Dalton75887a22021-01-06 00:23:13 -07001739 const Comparator& c, SkArenaAlloc& alloc) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001740 TESS_LOG("\nstroking boundary\n");
Stephen Whitee260c462017-12-19 18:09:54 -05001741 // A boundary with fewer than 3 edges is degenerate.
1742 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
1743 return;
1744 }
1745 Edge* prevEdge = boundary->fTail;
1746 Vertex* prevV = prevEdge->fWinding > 0 ? prevEdge->fTop : prevEdge->fBottom;
1747 SkVector prevNormal;
1748 get_edge_normal(prevEdge, &prevNormal);
1749 double radius = 0.5;
1750 Line prevInner(prevEdge->fLine);
1751 prevInner.fC -= radius;
1752 Line prevOuter(prevEdge->fLine);
1753 prevOuter.fC += radius;
1754 VertexList innerVertices;
1755 VertexList outerVertices;
1756 bool innerInversion = true;
1757 bool outerInversion = true;
1758 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
1759 Vertex* v = e->fWinding > 0 ? e->fTop : e->fBottom;
1760 SkVector normal;
1761 get_edge_normal(e, &normal);
1762 Line inner(e->fLine);
1763 inner.fC -= radius;
1764 Line outer(e->fLine);
1765 outer.fC += radius;
1766 SkPoint innerPoint, outerPoint;
Brian Salomon120e7d62019-09-11 10:29:22 -04001767 TESS_LOG("stroking vertex %g (%g, %g)\n", v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen Whitee260c462017-12-19 18:09:54 -05001768 if (!prevEdge->fLine.nearParallel(e->fLine) && prevInner.intersect(inner, &innerPoint) &&
1769 prevOuter.intersect(outer, &outerPoint)) {
1770 float cosAngle = normal.dot(prevNormal);
1771 if (cosAngle < -kCosMiterAngle) {
1772 Vertex* nextV = e->fWinding > 0 ? e->fBottom : e->fTop;
1773
1774 // This is a pointy vertex whose angle is smaller than the threshold; miter it.
1775 Line bisector(innerPoint, outerPoint);
1776 Line tangent(v->fPoint, v->fPoint + SkPoint::Make(bisector.fA, bisector.fB));
1777 if (tangent.fA == 0 && tangent.fB == 0) {
1778 continue;
1779 }
1780 tangent.normalize();
1781 Line innerTangent(tangent);
1782 Line outerTangent(tangent);
1783 innerTangent.fC -= 0.5;
1784 outerTangent.fC += 0.5;
1785 SkPoint innerPoint1, innerPoint2, outerPoint1, outerPoint2;
1786 if (prevNormal.cross(normal) > 0) {
1787 // Miter inner points
1788 if (!innerTangent.intersect(prevInner, &innerPoint1) ||
1789 !innerTangent.intersect(inner, &innerPoint2) ||
1790 !outerTangent.intersect(bisector, &outerPoint)) {
Stephen Whitef470b7e2018-01-04 16:45:51 -05001791 continue;
Stephen Whitee260c462017-12-19 18:09:54 -05001792 }
1793 Line prevTangent(prevV->fPoint,
1794 prevV->fPoint + SkVector::Make(prevOuter.fA, prevOuter.fB));
1795 Line nextTangent(nextV->fPoint,
1796 nextV->fPoint + SkVector::Make(outer.fA, outer.fB));
Stephen Whitee260c462017-12-19 18:09:54 -05001797 if (prevTangent.dist(outerPoint) > 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001798 bisector.intersect(prevTangent, &outerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001799 }
1800 if (nextTangent.dist(outerPoint) < 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001801 bisector.intersect(nextTangent, &outerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001802 }
1803 outerPoint1 = outerPoint2 = outerPoint;
1804 } else {
1805 // Miter outer points
1806 if (!outerTangent.intersect(prevOuter, &outerPoint1) ||
1807 !outerTangent.intersect(outer, &outerPoint2)) {
Stephen Whitef470b7e2018-01-04 16:45:51 -05001808 continue;
Stephen Whitee260c462017-12-19 18:09:54 -05001809 }
1810 Line prevTangent(prevV->fPoint,
1811 prevV->fPoint + SkVector::Make(prevInner.fA, prevInner.fB));
1812 Line nextTangent(nextV->fPoint,
1813 nextV->fPoint + SkVector::Make(inner.fA, inner.fB));
Stephen Whitee260c462017-12-19 18:09:54 -05001814 if (prevTangent.dist(innerPoint) > 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001815 bisector.intersect(prevTangent, &innerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001816 }
1817 if (nextTangent.dist(innerPoint) < 0) {
Stephen White4f34fca2018-01-11 16:14:04 -05001818 bisector.intersect(nextTangent, &innerPoint);
Stephen Whitee260c462017-12-19 18:09:54 -05001819 }
1820 innerPoint1 = innerPoint2 = innerPoint;
1821 }
Stephen Whiteea495232018-04-03 11:28:15 -04001822 if (!innerPoint1.isFinite() || !innerPoint2.isFinite() ||
1823 !outerPoint1.isFinite() || !outerPoint2.isFinite()) {
1824 continue;
1825 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001826 TESS_LOG("inner (%g, %g), (%g, %g), ",
1827 innerPoint1.fX, innerPoint1.fY, innerPoint2.fX, innerPoint2.fY);
1828 TESS_LOG("outer (%g, %g), (%g, %g)\n",
1829 outerPoint1.fX, outerPoint1.fY, outerPoint2.fX, outerPoint2.fY);
Stephen Whitee260c462017-12-19 18:09:54 -05001830 Vertex* innerVertex1 = alloc.make<Vertex>(innerPoint1, 255);
1831 Vertex* innerVertex2 = alloc.make<Vertex>(innerPoint2, 255);
1832 Vertex* outerVertex1 = alloc.make<Vertex>(outerPoint1, 0);
1833 Vertex* outerVertex2 = alloc.make<Vertex>(outerPoint2, 0);
1834 innerVertex1->fPartner = outerVertex1;
1835 innerVertex2->fPartner = outerVertex2;
1836 outerVertex1->fPartner = innerVertex1;
1837 outerVertex2->fPartner = innerVertex2;
1838 if (!inversion(innerVertices.fTail, innerVertex1, prevEdge, c)) {
1839 innerInversion = false;
1840 }
1841 if (!inversion(outerVertices.fTail, outerVertex1, prevEdge, c)) {
1842 outerInversion = false;
1843 }
1844 innerVertices.append(innerVertex1);
1845 innerVertices.append(innerVertex2);
1846 outerVertices.append(outerVertex1);
1847 outerVertices.append(outerVertex2);
1848 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001849 TESS_LOG("inner (%g, %g), ", innerPoint.fX, innerPoint.fY);
1850 TESS_LOG("outer (%g, %g)\n", outerPoint.fX, outerPoint.fY);
Stephen Whitee260c462017-12-19 18:09:54 -05001851 Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255);
1852 Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0);
1853 innerVertex->fPartner = outerVertex;
1854 outerVertex->fPartner = innerVertex;
1855 if (!inversion(innerVertices.fTail, innerVertex, prevEdge, c)) {
1856 innerInversion = false;
1857 }
1858 if (!inversion(outerVertices.fTail, outerVertex, prevEdge, c)) {
1859 outerInversion = false;
1860 }
1861 innerVertices.append(innerVertex);
1862 outerVertices.append(outerVertex);
1863 }
1864 }
1865 prevInner = inner;
1866 prevOuter = outer;
1867 prevV = v;
1868 prevEdge = e;
1869 prevNormal = normal;
1870 }
1871 if (!inversion(innerVertices.fTail, innerVertices.fHead, prevEdge, c)) {
1872 innerInversion = false;
1873 }
1874 if (!inversion(outerVertices.fTail, outerVertices.fHead, prevEdge, c)) {
1875 outerInversion = false;
1876 }
1877 // Outer edges get 1 winding, and inner edges get -2 winding. This ensures that the interior
1878 // is always filled (1 + -2 = -1 for normal cases, 1 + 2 = 3 for thin features where the
1879 // interior inverts).
1880 // For total inversion cases, the shape has now reversed handedness, so invert the winding
1881 // so it will be detected during collapse_overlap_regions().
1882 int innerWinding = innerInversion ? 2 : -2;
1883 int outerWinding = outerInversion ? -1 : 1;
1884 for (Vertex* v = innerVertices.fHead; v && v->fNext; v = v->fNext) {
Chris Dalton75887a22021-01-06 00:23:13 -07001885 connect(v, v->fNext, EdgeType::kInner, c, alloc, innerWinding);
Stephen Whitee260c462017-12-19 18:09:54 -05001886 }
Chris Dalton75887a22021-01-06 00:23:13 -07001887 connect(innerVertices.fTail, innerVertices.fHead, EdgeType::kInner, c, alloc, innerWinding);
Stephen Whitee260c462017-12-19 18:09:54 -05001888 for (Vertex* v = outerVertices.fHead; v && v->fNext; v = v->fNext) {
Chris Dalton75887a22021-01-06 00:23:13 -07001889 connect(v, v->fNext, EdgeType::kOuter, c, alloc, outerWinding);
Stephen Whitee260c462017-12-19 18:09:54 -05001890 }
Chris Dalton75887a22021-01-06 00:23:13 -07001891 connect(outerVertices.fTail, outerVertices.fHead, EdgeType::kOuter, c, alloc, outerWinding);
Stephen Whitee260c462017-12-19 18:09:54 -05001892 innerMesh->append(innerVertices);
1893 outerMesh->append(outerVertices);
1894}
senorblancof57372d2016-08-31 10:36:19 -07001895
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001896static void extract_boundary(EdgeList* boundary, Edge* e, SkPathFillType fillType,
1897 SkArenaAlloc& alloc) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001898 TESS_LOG("\nextracting boundary\n");
Stephen White49789062017-02-21 10:35:49 -05001899 bool down = apply_fill_type(fillType, e->fWinding);
Stephen White0c72ed32019-06-13 13:13:13 -04001900 Vertex* start = down ? e->fTop : e->fBottom;
1901 do {
senorblancof57372d2016-08-31 10:36:19 -07001902 e->fWinding = down ? 1 : -1;
1903 Edge* next;
Stephen Whitee260c462017-12-19 18:09:54 -05001904 e->fLine.normalize();
1905 e->fLine = e->fLine * e->fWinding;
senorblancof57372d2016-08-31 10:36:19 -07001906 boundary->append(e);
1907 if (down) {
1908 // Find outgoing edge, in clockwise order.
1909 if ((next = e->fNextEdgeAbove)) {
1910 down = false;
1911 } else if ((next = e->fBottom->fLastEdgeBelow)) {
1912 down = true;
1913 } else if ((next = e->fPrevEdgeAbove)) {
1914 down = false;
1915 }
1916 } else {
1917 // Find outgoing edge, in counter-clockwise order.
1918 if ((next = e->fPrevEdgeBelow)) {
1919 down = true;
1920 } else if ((next = e->fTop->fFirstEdgeAbove)) {
1921 down = false;
1922 } else if ((next = e->fNextEdgeBelow)) {
1923 down = true;
1924 }
1925 }
Chris Dalton75887a22021-01-06 00:23:13 -07001926 e->disconnect();
senorblancof57372d2016-08-31 10:36:19 -07001927 e = next;
Stephen White0c72ed32019-06-13 13:13:13 -04001928 } while (e && (down ? e->fTop : e->fBottom) != start);
senorblancof57372d2016-08-31 10:36:19 -07001929}
1930
Stephen White5ad721e2017-02-23 16:50:47 -05001931// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
senorblancof57372d2016-08-31 10:36:19 -07001932
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001933static void extract_boundaries(const VertexList& inMesh, VertexList* innerVertices,
Chris Dalton75887a22021-01-06 00:23:13 -07001934 VertexList* outerVertices, SkPathFillType fillType,
1935 const Comparator& c, SkArenaAlloc& alloc) {
Stephen White5ad721e2017-02-23 16:50:47 -05001936 remove_non_boundary_edges(inMesh, fillType, alloc);
1937 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07001938 while (v->fFirstEdgeBelow) {
Stephen White5ad721e2017-02-23 16:50:47 -05001939 EdgeList boundary;
1940 extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc);
1941 simplify_boundary(&boundary, c, alloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04001942 stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc);
senorblancof57372d2016-08-31 10:36:19 -07001943 }
1944 }
senorblancof57372d2016-08-31 10:36:19 -07001945}
1946
Stephen Whitebda29c02017-03-13 15:10:13 -04001947// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001948
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001949void GrTriangulator::contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton75887a22021-01-06 00:23:13 -07001950 const Comparator& c) {
1951#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -08001952 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001953 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001954 SkASSERT(v);
Brian Salomon120e7d62019-09-11 10:29:22 -04001955 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001956 for (v = v->fNext; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001957 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
ethannicholase9709e82016-01-07 13:34:16 -08001958 }
1959 }
1960#endif
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001961 this->sanitizeContours(contours, contourCnt);
1962 this->buildEdges(contours, contourCnt, mesh, c);
senorblancof57372d2016-08-31 10:36:19 -07001963}
1964
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001965void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001966 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001967 return;
ethannicholase9709e82016-01-07 13:34:16 -08001968 }
1969
1970 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001971 if (c.fDirection == Comparator::Direction::kHorizontal) {
1972 merge_sort<sweep_lt_horiz>(vertices);
1973 } else {
1974 merge_sort<sweep_lt_vert>(vertices);
1975 }
Chris Dalton75887a22021-01-06 00:23:13 -07001976#if TRIANGULATOR_LOGGING
Stephen White2e2cb9b2017-01-09 13:11:18 -05001977 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001978 static float gID = 0.0f;
1979 v->fID = gID++;
1980 }
1981#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001982}
1983
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001984Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt, VertexList* outerMesh) {
1985 const SkRect& pathBounds = fPath.getBounds();
Stephen White16a40cb2017-02-23 11:10:01 -05001986 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1987 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001988 VertexList mesh;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001989 this->contoursToMesh(contours, contourCnt, &mesh, c);
1990 SortMesh(&mesh, c);
1991 this->mergeCoincidentVertices(&mesh, c);
1992 if (SimplifyResult::kAbort == this->simplify(&mesh, c)) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001993 return nullptr;
1994 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001995 TESS_LOG("\nsimplified mesh:\n");
Chris Dalton75887a22021-01-06 00:23:13 -07001996 DUMP_MESH(mesh);
Chris Dalton854ee852021-01-05 15:12:59 -07001997 if (fEmitCoverage) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001998 VertexList innerMesh;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001999 extract_boundaries(mesh, &innerMesh, outerMesh, fPath.getFillType(), c, fAlloc);
2000 SortMesh(&innerMesh, c);
2001 SortMesh(outerMesh, c);
2002 this->mergeCoincidentVertices(&innerMesh, c);
2003 bool was_complex = this->mergeCoincidentVertices(outerMesh, c);
2004 auto result = this->simplify(&innerMesh, c);
Chris Dalton6ccc0322020-01-29 11:38:16 -07002005 SkASSERT(SimplifyResult::kAbort != result);
2006 was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002007 result = this->simplify(outerMesh, c);
Chris Dalton6ccc0322020-01-29 11:38:16 -07002008 SkASSERT(SimplifyResult::kAbort != result);
2009 was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
Brian Salomon120e7d62019-09-11 10:29:22 -04002010 TESS_LOG("\ninner mesh before:\n");
Chris Dalton75887a22021-01-06 00:23:13 -07002011 DUMP_MESH(innerMesh);
Brian Salomon120e7d62019-09-11 10:29:22 -04002012 TESS_LOG("\nouter mesh before:\n");
Chris Dalton75887a22021-01-06 00:23:13 -07002013 DUMP_MESH(*outerMesh);
Stephen Whitec4dbc372019-05-22 10:50:14 -04002014 EventComparator eventLT(EventComparator::Op::kLessThan);
2015 EventComparator eventGT(EventComparator::Op::kGreaterThan);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002016 was_complex = collapse_overlap_regions(&innerMesh, c, fAlloc, eventLT) || was_complex;
2017 was_complex = collapse_overlap_regions(outerMesh, c, fAlloc, eventGT) || was_complex;
Stephen Whitee260c462017-12-19 18:09:54 -05002018 if (was_complex) {
Brian Salomon120e7d62019-09-11 10:29:22 -04002019 TESS_LOG("found complex mesh; taking slow path\n");
Stephen Whitebda29c02017-03-13 15:10:13 -04002020 VertexList aaMesh;
Brian Salomon120e7d62019-09-11 10:29:22 -04002021 TESS_LOG("\ninner mesh after:\n");
Chris Dalton75887a22021-01-06 00:23:13 -07002022 DUMP_MESH(innerMesh);
Brian Salomon120e7d62019-09-11 10:29:22 -04002023 TESS_LOG("\nouter mesh after:\n");
Chris Dalton75887a22021-01-06 00:23:13 -07002024 DUMP_MESH(*outerMesh);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002025 connect_partners(outerMesh, c, fAlloc);
2026 connect_partners(&innerMesh, c, fAlloc);
Stephen Whitebda29c02017-03-13 15:10:13 -04002027 sorted_merge(&innerMesh, outerMesh, &aaMesh, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002028 this->mergeCoincidentVertices(&aaMesh, c);
2029 result = this->simplify(&aaMesh, c);
Chris Dalton6ccc0322020-01-29 11:38:16 -07002030 SkASSERT(SimplifyResult::kAbort != result);
Brian Salomon120e7d62019-09-11 10:29:22 -04002031 TESS_LOG("combined and simplified mesh:\n");
Chris Dalton75887a22021-01-06 00:23:13 -07002032 DUMP_MESH(aaMesh);
Stephen Whitebda29c02017-03-13 15:10:13 -04002033 outerMesh->fHead = outerMesh->fTail = nullptr;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002034 return this->tessellate(aaMesh);
Stephen Whitebda29c02017-03-13 15:10:13 -04002035 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04002036 TESS_LOG("no complex polygons; taking fast path\n");
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002037 return this->tessellate(innerMesh);
Stephen Whitebda29c02017-03-13 15:10:13 -04002038 }
Stephen White49789062017-02-21 10:35:49 -05002039 } else {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002040 return this->tessellate(mesh);
senorblancof57372d2016-08-31 10:36:19 -07002041 }
senorblancof57372d2016-08-31 10:36:19 -07002042}
2043
2044// Stage 6: Triangulate the monotone polygons into a vertex buffer.
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002045void* GrTriangulator::polysToTriangles(Poly* polys, void* data, SkPathFillType overrideFillType) {
senorblancof57372d2016-08-31 10:36:19 -07002046 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002047 if (apply_fill_type(overrideFillType, poly)) {
Chris Dalton75887a22021-01-06 00:23:13 -07002048 data = this->emitPoly(poly, data);
senorblancof57372d2016-08-31 10:36:19 -07002049 }
2050 }
2051 return data;
ethannicholase9709e82016-01-07 13:34:16 -08002052}
2053
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002054Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt,
2055 VertexList* outerMesh) {
2056 if (SkPathFillType_IsInverse(fPath.getFillType())) {
ethannicholase9709e82016-01-07 13:34:16 -08002057 contourCnt++;
2058 }
Stephen White3a9aab92017-03-07 14:07:18 -05002059 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08002060
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002061 this->pathToContours(tolerance, clipBounds, contours.get());
2062 return this->contoursToPolys(contours.get(), contourCnt, outerMesh);
ethannicholase9709e82016-01-07 13:34:16 -08002063}
2064
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002065static int get_contour_count(const SkPath& path, SkScalar tolerance) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07002066 // We could theoretically be more aggressive about not counting empty contours, but we need to
2067 // actually match the exact number of contour linked lists the tessellator will create later on.
2068 int contourCnt = 1;
2069 bool hasPoints = false;
2070
Chris Dalton7156db22020-05-07 22:06:28 +00002071 SkPath::Iter iter(path, false);
2072 SkPath::Verb verb;
2073 SkPoint pts[4];
Chris Daltonc71b3d42020-01-08 21:29:59 -07002074 bool first = true;
Chris Dalton7156db22020-05-07 22:06:28 +00002075 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07002076 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +00002077 case SkPath::kMove_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07002078 if (!first) {
2079 ++contourCnt;
2080 }
John Stiles30212b72020-06-11 17:55:07 -04002081 [[fallthrough]];
Chris Dalton7156db22020-05-07 22:06:28 +00002082 case SkPath::kLine_Verb:
2083 case SkPath::kConic_Verb:
2084 case SkPath::kQuad_Verb:
2085 case SkPath::kCubic_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07002086 hasPoints = true;
John Stiles30212b72020-06-11 17:55:07 -04002087 break;
Chris Daltonc71b3d42020-01-08 21:29:59 -07002088 default:
2089 break;
2090 }
2091 first = false;
2092 }
2093 if (!hasPoints) {
Stephen White11f65e02017-02-16 19:00:39 -05002094 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08002095 }
Stephen White11f65e02017-02-16 19:00:39 -05002096 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08002097}
2098
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002099static int64_t count_points(Poly* polys, SkPathFillType fillType) {
Greg Danield5b45932018-06-07 13:15:10 -04002100 int64_t count = 0;
ethannicholase9709e82016-01-07 13:34:16 -08002101 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07002102 if (apply_fill_type(fillType, poly) && poly->fCount >= 3) {
Chris Dalton17dc4182020-03-25 16:18:16 -06002103 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
ethannicholase9709e82016-01-07 13:34:16 -08002104 }
2105 }
2106 return count;
2107}
2108
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002109static int64_t count_outer_mesh_points(const VertexList& outerMesh) {
Greg Danield5b45932018-06-07 13:15:10 -04002110 int64_t count = 0;
Stephen Whitebda29c02017-03-13 15:10:13 -04002111 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
2112 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton17dc4182020-03-25 16:18:16 -06002113 count += TRIANGULATOR_WIREFRAME ? 12 : 6;
Stephen Whitebda29c02017-03-13 15:10:13 -04002114 }
2115 }
2116 return count;
2117}
2118
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002119static void* outer_mesh_to_triangles(const VertexList& outerMesh, bool emitCoverage, void* data) {
Stephen Whitebda29c02017-03-13 15:10:13 -04002120 for (Vertex* v = outerMesh.fHead; v; v = v->fNext) {
2121 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
2122 Vertex* v0 = e->fTop;
2123 Vertex* v1 = e->fBottom;
2124 Vertex* v2 = e->fBottom->fPartner;
2125 Vertex* v3 = e->fTop->fPartner;
Brian Osman0995fd52019-01-09 09:52:25 -05002126 data = emit_triangle(v0, v1, v2, emitCoverage, data);
2127 data = emit_triangle(v0, v2, v3, emitCoverage, data);
Stephen Whitebda29c02017-03-13 15:10:13 -04002128 }
2129 }
2130 return data;
2131}
2132
ethannicholase9709e82016-01-07 13:34:16 -08002133// Stage 6: Triangulate the monotone polygons into a vertex buffer.
2134
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002135int GrTriangulator::pathToTriangles(float tolerance, const SkRect& clipBounds,
2136 GrEagerVertexAllocator* vertexAllocator,
2137 SkPathFillType overrideFillType) {
2138 int contourCnt = get_contour_count(fPath, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08002139 if (contourCnt <= 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002140 fIsLinear = true;
ethannicholase9709e82016-01-07 13:34:16 -08002141 return 0;
2142 }
Stephen Whitebda29c02017-03-13 15:10:13 -04002143 VertexList outerMesh;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002144 Poly* polys = this->pathToPolys(tolerance, clipBounds, contourCnt, &outerMesh);
2145 int64_t count64 = count_points(polys, overrideFillType);
Chris Dalton854ee852021-01-05 15:12:59 -07002146 if (fEmitCoverage) {
Greg Danield5b45932018-06-07 13:15:10 -04002147 count64 += count_outer_mesh_points(outerMesh);
Stephen Whitebda29c02017-03-13 15:10:13 -04002148 }
Greg Danield5b45932018-06-07 13:15:10 -04002149 if (0 == count64 || count64 > SK_MaxS32) {
Stephen Whiteff60b172017-05-05 15:54:52 -04002150 return 0;
2151 }
Greg Danield5b45932018-06-07 13:15:10 -04002152 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08002153
Chris Dalton854ee852021-01-05 15:12:59 -07002154 size_t vertexStride = sizeof(SkPoint);
2155 if (fEmitCoverage) {
2156 vertexStride += sizeof(float);
2157 }
Chris Daltond081dce2020-01-23 12:09:04 -07002158 void* verts = vertexAllocator->lock(vertexStride, 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
Brian Salomon120e7d62019-09-11 10:29:22 -04002164 TESS_LOG("emitting %d verts\n", count);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002165 void* end = this->polysToTriangles(polys, verts, overrideFillType);
Brian Osman80879d42019-01-07 16:15:27 -05002166 end = outer_mesh_to_triangles(outerMesh, true, end);
Brian Osman80879d42019-01-07 16:15:27 -05002167
senorblancof57372d2016-08-31 10:36:19 -07002168 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
Chris Daltond081dce2020-01-23 12:09:04 -07002169 / vertexStride);
ethannicholase9709e82016-01-07 13:34:16 -08002170 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08002171 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08002172 return actualCount;
2173}
2174
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002175int GrTriangulator::PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
2176 WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05002177 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08002178 if (contourCnt <= 0) {
Chris Dalton84403d72018-02-13 21:46:17 -05002179 *verts = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08002180 return 0;
2181 }
Chris Dalton854ee852021-01-05 15:12:59 -07002182 GrTriangulator triangulator(path);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07002183 Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, contourCnt, nullptr);
Mike Reedcf0e3c62019-12-03 16:26:15 -05002184 SkPathFillType fillType = path.getFillType();
Greg Danield5b45932018-06-07 13:15:10 -04002185 int64_t count64 = count_points(polys, fillType);
2186 if (0 == count64 || count64 > SK_MaxS32) {
ethannicholase9709e82016-01-07 13:34:16 -08002187 *verts = nullptr;
2188 return 0;
2189 }
Greg Danield5b45932018-06-07 13:15:10 -04002190 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08002191
Chris Dalton17dc4182020-03-25 16:18:16 -06002192 *verts = new WindingVertex[count];
2193 WindingVertex* vertsEnd = *verts;
ethannicholase9709e82016-01-07 13:34:16 -08002194 SkPoint* points = new SkPoint[count];
2195 SkPoint* pointsEnd = points;
2196 for (Poly* poly = polys; poly; poly = poly->fNext) {
senorblancof57372d2016-08-31 10:36:19 -07002197 if (apply_fill_type(fillType, poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08002198 SkPoint* start = pointsEnd;
Chris Dalton75887a22021-01-06 00:23:13 -07002199 pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08002200 while (start != pointsEnd) {
2201 vertsEnd->fPos = *start;
2202 vertsEnd->fWinding = poly->fWinding;
2203 ++start;
2204 ++vertsEnd;
2205 }
2206 }
2207 }
2208 int actualCount = static_cast<int>(vertsEnd - *verts);
2209 SkASSERT(actualCount <= count);
2210 SkASSERT(pointsEnd - points == actualCount);
2211 delete[] points;
2212 return actualCount;
2213}