1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrAATriangulator.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "src/gpu/GrEagerVertexAllocator.h"
11cb93a386Sopenharmony_ci#include <queue>
12cb93a386Sopenharmony_ci#include <vector>
13cb93a386Sopenharmony_ci#include <unordered_map>
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#if TRIANGULATOR_LOGGING
16cb93a386Sopenharmony_ci#define TESS_LOG SkDebugf
17cb93a386Sopenharmony_ci#define DUMP_MESH(MESH) (MESH).dump()
18cb93a386Sopenharmony_ci#else
19cb93a386Sopenharmony_ci#define TESS_LOG(...)
20cb93a386Sopenharmony_ci#define DUMP_MESH(MESH)
21cb93a386Sopenharmony_ci#endif
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciconstexpr static float kCosMiterAngle = 0.97f; // Corresponds to an angle of ~14 degrees.
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ciusing EdgeType = GrTriangulator::EdgeType;
26cb93a386Sopenharmony_ciusing Vertex = GrTriangulator::Vertex;
27cb93a386Sopenharmony_ciusing VertexList = GrTriangulator::VertexList;
28cb93a386Sopenharmony_ciusing Line = GrTriangulator::Line;
29cb93a386Sopenharmony_ciusing Edge = GrTriangulator::Edge;
30cb93a386Sopenharmony_ciusing EdgeList = GrTriangulator::EdgeList;
31cb93a386Sopenharmony_ciusing Poly = GrTriangulator::Poly;
32cb93a386Sopenharmony_ciusing Comparator = GrTriangulator::Comparator;
33cb93a386Sopenharmony_ciusing SSEdge = GrAATriangulator::SSEdge;
34cb93a386Sopenharmony_ciusing EventList = GrAATriangulator::EventList;
35cb93a386Sopenharmony_ciusing Event = GrAATriangulator::Event;
36cb93a386Sopenharmony_ciusing EventComparator = GrAATriangulator::EventComparator;
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_cistruct SSVertex {
39cb93a386Sopenharmony_ci    SSVertex(Vertex* v) : fVertex(v), fPrev(nullptr), fNext(nullptr) {}
40cb93a386Sopenharmony_ci    Vertex* fVertex;
41cb93a386Sopenharmony_ci    SSEdge* fPrev;
42cb93a386Sopenharmony_ci    SSEdge* fNext;
43cb93a386Sopenharmony_ci};
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_cistruct GrAATriangulator::SSEdge {
46cb93a386Sopenharmony_ci    SSEdge(Edge* edge, SSVertex* prev, SSVertex* next)
47cb93a386Sopenharmony_ci      : fEdge(edge), fEvent(nullptr), fPrev(prev), fNext(next) {
48cb93a386Sopenharmony_ci    }
49cb93a386Sopenharmony_ci    Edge*     fEdge;
50cb93a386Sopenharmony_ci    Event*    fEvent;
51cb93a386Sopenharmony_ci    SSVertex* fPrev;
52cb93a386Sopenharmony_ci    SSVertex* fNext;
53cb93a386Sopenharmony_ci};
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_citypedef std::unordered_map<Vertex*, SSVertex*> SSVertexMap;
56cb93a386Sopenharmony_citypedef std::vector<SSEdge*> SSEdgeList;
57cb93a386Sopenharmony_citypedef std::priority_queue<Event*, std::vector<Event*>, EventComparator> EventPQ;
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_cistruct GrAATriangulator::EventList : EventPQ {
60cb93a386Sopenharmony_ci    EventList(EventComparator comparison) : EventPQ(comparison) {
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci};
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_civoid GrAATriangulator::makeEvent(SSEdge* e, EventList* events) const {
65cb93a386Sopenharmony_ci    Vertex* prev = e->fPrev->fVertex;
66cb93a386Sopenharmony_ci    Vertex* next = e->fNext->fVertex;
67cb93a386Sopenharmony_ci    if (prev == next || !prev->fPartner || !next->fPartner) {
68cb93a386Sopenharmony_ci        return;
69cb93a386Sopenharmony_ci    }
70cb93a386Sopenharmony_ci    Edge bisector1(prev, prev->fPartner, 1, EdgeType::kConnector);
71cb93a386Sopenharmony_ci    Edge bisector2(next, next->fPartner, 1, EdgeType::kConnector);
72cb93a386Sopenharmony_ci    SkPoint p;
73cb93a386Sopenharmony_ci    uint8_t alpha;
74cb93a386Sopenharmony_ci    if (bisector1.intersect(bisector2, &p, &alpha)) {
75cb93a386Sopenharmony_ci        TESS_LOG("found edge event for %g, %g (original %g -> %g), "
76cb93a386Sopenharmony_ci                 "will collapse to %g,%g alpha %d\n",
77cb93a386Sopenharmony_ci                  prev->fID, next->fID, e->fEdge->fTop->fID, e->fEdge->fBottom->fID, p.fX, p.fY,
78cb93a386Sopenharmony_ci                  alpha);
79cb93a386Sopenharmony_ci        e->fEvent = fAlloc->make<Event>(e, p, alpha);
80cb93a386Sopenharmony_ci        events->push(e->fEvent);
81cb93a386Sopenharmony_ci    }
82cb93a386Sopenharmony_ci}
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_civoid GrAATriangulator::makeEvent(SSEdge* edge, Vertex* v, SSEdge* other, Vertex* dest,
85cb93a386Sopenharmony_ci                                 EventList* events, const Comparator& c) const {
86cb93a386Sopenharmony_ci    if (!v->fPartner) {
87cb93a386Sopenharmony_ci        return;
88cb93a386Sopenharmony_ci    }
89cb93a386Sopenharmony_ci    Vertex* top = edge->fEdge->fTop;
90cb93a386Sopenharmony_ci    Vertex* bottom = edge->fEdge->fBottom;
91cb93a386Sopenharmony_ci    if (!top || !bottom ) {
92cb93a386Sopenharmony_ci        return;
93cb93a386Sopenharmony_ci    }
94cb93a386Sopenharmony_ci    Line line = edge->fEdge->fLine;
95cb93a386Sopenharmony_ci    line.fC = -(dest->fPoint.fX * line.fA  + dest->fPoint.fY * line.fB);
96cb93a386Sopenharmony_ci    Edge bisector(v, v->fPartner, 1, EdgeType::kConnector);
97cb93a386Sopenharmony_ci    SkPoint p;
98cb93a386Sopenharmony_ci    uint8_t alpha = dest->fAlpha;
99cb93a386Sopenharmony_ci    if (line.intersect(bisector.fLine, &p) && !c.sweep_lt(p, top->fPoint) &&
100cb93a386Sopenharmony_ci                                               c.sweep_lt(p, bottom->fPoint)) {
101cb93a386Sopenharmony_ci        TESS_LOG("found p edge event for %g, %g (original %g -> %g), "
102cb93a386Sopenharmony_ci                 "will collapse to %g,%g alpha %d\n",
103cb93a386Sopenharmony_ci                 dest->fID, v->fID, top->fID, bottom->fID, p.fX, p.fY, alpha);
104cb93a386Sopenharmony_ci        edge->fEvent = fAlloc->make<Event>(edge, p, alpha);
105cb93a386Sopenharmony_ci        events->push(edge->fEvent);
106cb93a386Sopenharmony_ci    }
107cb93a386Sopenharmony_ci}
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_civoid GrAATriangulator::connectPartners(VertexList* mesh, const Comparator& c) const {
110cb93a386Sopenharmony_ci    for (Vertex* outer = mesh->fHead; outer; outer = outer->fNext) {
111cb93a386Sopenharmony_ci        if (Vertex* inner = outer->fPartner) {
112cb93a386Sopenharmony_ci            if ((inner->fPrev || inner->fNext) && (outer->fPrev || outer->fNext)) {
113cb93a386Sopenharmony_ci                // Connector edges get zero winding, since they're only structural (i.e., to ensure
114cb93a386Sopenharmony_ci                // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding
115cb93a386Sopenharmony_ci                // number.
116cb93a386Sopenharmony_ci                this->makeConnectingEdge(outer, inner, EdgeType::kConnector, c, 0);
117cb93a386Sopenharmony_ci                inner->fPartner = outer->fPartner = nullptr;
118cb93a386Sopenharmony_ci            }
119cb93a386Sopenharmony_ci        }
120cb93a386Sopenharmony_ci    }
121cb93a386Sopenharmony_ci}
122cb93a386Sopenharmony_ci
123cb93a386Sopenharmony_cistatic void dump_skel(const SSEdgeList& ssEdges) {
124cb93a386Sopenharmony_ci#if TRIANGULATOR_LOGGING
125cb93a386Sopenharmony_ci    for (SSEdge* edge : ssEdges) {
126cb93a386Sopenharmony_ci        if (edge->fEdge) {
127cb93a386Sopenharmony_ci            TESS_LOG("skel edge %g -> %g",
128cb93a386Sopenharmony_ci                edge->fPrev->fVertex->fID,
129cb93a386Sopenharmony_ci                edge->fNext->fVertex->fID);
130cb93a386Sopenharmony_ci            if (edge->fEdge->fTop && edge->fEdge->fBottom) {
131cb93a386Sopenharmony_ci                TESS_LOG(" (original %g -> %g)\n",
132cb93a386Sopenharmony_ci                         edge->fEdge->fTop->fID,
133cb93a386Sopenharmony_ci                         edge->fEdge->fBottom->fID);
134cb93a386Sopenharmony_ci            } else {
135cb93a386Sopenharmony_ci                TESS_LOG("\n");
136cb93a386Sopenharmony_ci            }
137cb93a386Sopenharmony_ci        }
138cb93a386Sopenharmony_ci    }
139cb93a386Sopenharmony_ci#endif
140cb93a386Sopenharmony_ci}
141cb93a386Sopenharmony_ci
142cb93a386Sopenharmony_civoid GrAATriangulator::removeNonBoundaryEdges(const VertexList& mesh) const {
143cb93a386Sopenharmony_ci    TESS_LOG("removing non-boundary edges\n");
144cb93a386Sopenharmony_ci    EdgeList activeEdges;
145cb93a386Sopenharmony_ci    for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
146cb93a386Sopenharmony_ci        if (!v->isConnected()) {
147cb93a386Sopenharmony_ci            continue;
148cb93a386Sopenharmony_ci        }
149cb93a386Sopenharmony_ci        Edge* leftEnclosingEdge;
150cb93a386Sopenharmony_ci        Edge* rightEnclosingEdge;
151cb93a386Sopenharmony_ci        FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
152cb93a386Sopenharmony_ci        bool prevFilled = leftEnclosingEdge && this->applyFillType(leftEnclosingEdge->fWinding);
153cb93a386Sopenharmony_ci        for (Edge* e = v->fFirstEdgeAbove; e;) {
154cb93a386Sopenharmony_ci            Edge* next = e->fNextEdgeAbove;
155cb93a386Sopenharmony_ci            activeEdges.remove(e);
156cb93a386Sopenharmony_ci            bool filled = this->applyFillType(e->fWinding);
157cb93a386Sopenharmony_ci            if (filled == prevFilled) {
158cb93a386Sopenharmony_ci                e->disconnect();
159cb93a386Sopenharmony_ci            }
160cb93a386Sopenharmony_ci            prevFilled = filled;
161cb93a386Sopenharmony_ci            e = next;
162cb93a386Sopenharmony_ci        }
163cb93a386Sopenharmony_ci        Edge* prev = leftEnclosingEdge;
164cb93a386Sopenharmony_ci        for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
165cb93a386Sopenharmony_ci            if (prev) {
166cb93a386Sopenharmony_ci                e->fWinding += prev->fWinding;
167cb93a386Sopenharmony_ci            }
168cb93a386Sopenharmony_ci            activeEdges.insert(e, prev);
169cb93a386Sopenharmony_ci            prev = e;
170cb93a386Sopenharmony_ci        }
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci}
173cb93a386Sopenharmony_ci
174cb93a386Sopenharmony_ci// Note: this is the normal to the edge, but not necessarily unit length.
175cb93a386Sopenharmony_cistatic void get_edge_normal(const Edge* e, SkVector* normal) {
176cb93a386Sopenharmony_ci    normal->set(SkDoubleToScalar(e->fLine.fA),
177cb93a386Sopenharmony_ci                SkDoubleToScalar(e->fLine.fB));
178cb93a386Sopenharmony_ci}
179cb93a386Sopenharmony_ci
180cb93a386Sopenharmony_ci// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
181cb93a386Sopenharmony_ci// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
182cb93a386Sopenharmony_ci// invert on stroking.
183cb93a386Sopenharmony_ci
184cb93a386Sopenharmony_civoid GrAATriangulator::simplifyBoundary(EdgeList* boundary, const Comparator& c) const {
185cb93a386Sopenharmony_ci    Edge* prevEdge = boundary->fTail;
186cb93a386Sopenharmony_ci    SkVector prevNormal;
187cb93a386Sopenharmony_ci    get_edge_normal(prevEdge, &prevNormal);
188cb93a386Sopenharmony_ci    for (Edge* e = boundary->fHead; e != nullptr;) {
189cb93a386Sopenharmony_ci        Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
190cb93a386Sopenharmony_ci        Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
191cb93a386Sopenharmony_ci        double distPrev = e->dist(prev->fPoint);
192cb93a386Sopenharmony_ci        double distNext = prevEdge->dist(next->fPoint);
193cb93a386Sopenharmony_ci        SkVector normal;
194cb93a386Sopenharmony_ci        get_edge_normal(e, &normal);
195cb93a386Sopenharmony_ci        constexpr double kQuarterPixelSq = 0.25f * 0.25f;
196cb93a386Sopenharmony_ci        if (prev == next) {
197cb93a386Sopenharmony_ci            boundary->remove(prevEdge);
198cb93a386Sopenharmony_ci            boundary->remove(e);
199cb93a386Sopenharmony_ci            prevEdge = boundary->fTail;
200cb93a386Sopenharmony_ci            e = boundary->fHead;
201cb93a386Sopenharmony_ci            if (prevEdge) {
202cb93a386Sopenharmony_ci                get_edge_normal(prevEdge, &prevNormal);
203cb93a386Sopenharmony_ci            }
204cb93a386Sopenharmony_ci        } else if (prevNormal.dot(normal) < 0.0 &&
205cb93a386Sopenharmony_ci            (distPrev * distPrev <= kQuarterPixelSq || distNext * distNext <= kQuarterPixelSq)) {
206cb93a386Sopenharmony_ci            Edge* join = this->makeEdge(prev, next, EdgeType::kInner, c);
207cb93a386Sopenharmony_ci            if (prev->fPoint != next->fPoint) {
208cb93a386Sopenharmony_ci                join->fLine.normalize();
209cb93a386Sopenharmony_ci                join->fLine = join->fLine * join->fWinding;
210cb93a386Sopenharmony_ci            }
211cb93a386Sopenharmony_ci            boundary->insert(join, e);
212cb93a386Sopenharmony_ci            boundary->remove(prevEdge);
213cb93a386Sopenharmony_ci            boundary->remove(e);
214cb93a386Sopenharmony_ci            if (join->fLeft && join->fRight) {
215cb93a386Sopenharmony_ci                prevEdge = join->fLeft;
216cb93a386Sopenharmony_ci                e = join;
217cb93a386Sopenharmony_ci            } else {
218cb93a386Sopenharmony_ci                prevEdge = boundary->fTail;
219cb93a386Sopenharmony_ci                e = boundary->fHead; // join->fLeft ? join->fLeft : join;
220cb93a386Sopenharmony_ci            }
221cb93a386Sopenharmony_ci            get_edge_normal(prevEdge, &prevNormal);
222cb93a386Sopenharmony_ci        } else {
223cb93a386Sopenharmony_ci            prevEdge = e;
224cb93a386Sopenharmony_ci            prevNormal = normal;
225cb93a386Sopenharmony_ci            e = e->fRight;
226cb93a386Sopenharmony_ci        }
227cb93a386Sopenharmony_ci    }
228cb93a386Sopenharmony_ci}
229cb93a386Sopenharmony_ci
230cb93a386Sopenharmony_civoid GrAATriangulator::connectSSEdge(Vertex* v, Vertex* dest, const Comparator& c) const {
231cb93a386Sopenharmony_ci    if (v == dest) {
232cb93a386Sopenharmony_ci        return;
233cb93a386Sopenharmony_ci    }
234cb93a386Sopenharmony_ci    TESS_LOG("ss_connecting vertex %g to vertex %g\n", v->fID, dest->fID);
235cb93a386Sopenharmony_ci    if (v->fSynthetic) {
236cb93a386Sopenharmony_ci        this->makeConnectingEdge(v, dest, EdgeType::kConnector, c, 0);
237cb93a386Sopenharmony_ci    } else if (v->fPartner) {
238cb93a386Sopenharmony_ci        TESS_LOG("setting %g's partner to %g ", v->fPartner->fID, dest->fID);
239cb93a386Sopenharmony_ci        TESS_LOG("and %g's partner to null\n", v->fID);
240cb93a386Sopenharmony_ci        v->fPartner->fPartner = dest;
241cb93a386Sopenharmony_ci        v->fPartner = nullptr;
242cb93a386Sopenharmony_ci    }
243cb93a386Sopenharmony_ci}
244cb93a386Sopenharmony_ci
245cb93a386Sopenharmony_civoid GrAATriangulator::Event::apply(VertexList* mesh, const Comparator& c, EventList* events,
246cb93a386Sopenharmony_ci                                    const GrAATriangulator* triangulator) {
247cb93a386Sopenharmony_ci    if (!fEdge) {
248cb93a386Sopenharmony_ci        return;
249cb93a386Sopenharmony_ci    }
250cb93a386Sopenharmony_ci    Vertex* prev = fEdge->fPrev->fVertex;
251cb93a386Sopenharmony_ci    Vertex* next = fEdge->fNext->fVertex;
252cb93a386Sopenharmony_ci    SSEdge* prevEdge = fEdge->fPrev->fPrev;
253cb93a386Sopenharmony_ci    SSEdge* nextEdge = fEdge->fNext->fNext;
254cb93a386Sopenharmony_ci    if (!prevEdge || !nextEdge || !prevEdge->fEdge || !nextEdge->fEdge) {
255cb93a386Sopenharmony_ci        return;
256cb93a386Sopenharmony_ci    }
257cb93a386Sopenharmony_ci    Vertex* dest = triangulator->makeSortedVertex(fPoint, fAlpha, mesh, prev, c);
258cb93a386Sopenharmony_ci    dest->fSynthetic = true;
259cb93a386Sopenharmony_ci    SSVertex* ssv = triangulator->fAlloc->make<SSVertex>(dest);
260cb93a386Sopenharmony_ci    TESS_LOG("collapsing %g, %g (original edge %g -> %g) to %g (%g, %g) alpha %d\n",
261cb93a386Sopenharmony_ci             prev->fID, next->fID, fEdge->fEdge->fTop->fID, fEdge->fEdge->fBottom->fID, dest->fID,
262cb93a386Sopenharmony_ci             fPoint.fX, fPoint.fY, fAlpha);
263cb93a386Sopenharmony_ci    fEdge->fEdge = nullptr;
264cb93a386Sopenharmony_ci
265cb93a386Sopenharmony_ci    triangulator->connectSSEdge(prev, dest, c);
266cb93a386Sopenharmony_ci    triangulator->connectSSEdge(next, dest, c);
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci    prevEdge->fNext = nextEdge->fPrev = ssv;
269cb93a386Sopenharmony_ci    ssv->fPrev = prevEdge;
270cb93a386Sopenharmony_ci    ssv->fNext = nextEdge;
271cb93a386Sopenharmony_ci    if (!prevEdge->fEdge || !nextEdge->fEdge) {
272cb93a386Sopenharmony_ci        return;
273cb93a386Sopenharmony_ci    }
274cb93a386Sopenharmony_ci    if (prevEdge->fEvent) {
275cb93a386Sopenharmony_ci        prevEdge->fEvent->fEdge = nullptr;
276cb93a386Sopenharmony_ci    }
277cb93a386Sopenharmony_ci    if (nextEdge->fEvent) {
278cb93a386Sopenharmony_ci        nextEdge->fEvent->fEdge = nullptr;
279cb93a386Sopenharmony_ci    }
280cb93a386Sopenharmony_ci    if (prevEdge->fPrev == nextEdge->fNext) {
281cb93a386Sopenharmony_ci        triangulator->connectSSEdge(prevEdge->fPrev->fVertex, dest, c);
282cb93a386Sopenharmony_ci        prevEdge->fEdge = nextEdge->fEdge = nullptr;
283cb93a386Sopenharmony_ci    } else {
284cb93a386Sopenharmony_ci        triangulator->computeBisector(prevEdge->fEdge, nextEdge->fEdge, dest);
285cb93a386Sopenharmony_ci        SkASSERT(prevEdge != fEdge && nextEdge != fEdge);
286cb93a386Sopenharmony_ci        if (dest->fPartner) {
287cb93a386Sopenharmony_ci            triangulator->makeEvent(prevEdge, events);
288cb93a386Sopenharmony_ci            triangulator->makeEvent(nextEdge, events);
289cb93a386Sopenharmony_ci        } else {
290cb93a386Sopenharmony_ci            triangulator->makeEvent(prevEdge, prevEdge->fPrev->fVertex, nextEdge, dest, events, c);
291cb93a386Sopenharmony_ci            triangulator->makeEvent(nextEdge, nextEdge->fNext->fVertex, prevEdge, dest, events, c);
292cb93a386Sopenharmony_ci        }
293cb93a386Sopenharmony_ci    }
294cb93a386Sopenharmony_ci}
295cb93a386Sopenharmony_ci
296cb93a386Sopenharmony_cistatic bool is_overlap_edge(Edge* e) {
297cb93a386Sopenharmony_ci    if (e->fType == EdgeType::kOuter) {
298cb93a386Sopenharmony_ci        return e->fWinding != 0 && e->fWinding != 1;
299cb93a386Sopenharmony_ci    } else if (e->fType == EdgeType::kInner) {
300cb93a386Sopenharmony_ci        return e->fWinding != 0 && e->fWinding != -2;
301cb93a386Sopenharmony_ci    } else {
302cb93a386Sopenharmony_ci        return false;
303cb93a386Sopenharmony_ci    }
304cb93a386Sopenharmony_ci}
305cb93a386Sopenharmony_ci
306cb93a386Sopenharmony_ci// This is a stripped-down version of tessellate() which computes edges which
307cb93a386Sopenharmony_ci// join two filled regions, which represent overlap regions, and collapses them.
308cb93a386Sopenharmony_cibool GrAATriangulator::collapseOverlapRegions(VertexList* mesh, const Comparator& c,
309cb93a386Sopenharmony_ci                                              EventComparator comp) const {
310cb93a386Sopenharmony_ci    TESS_LOG("\nfinding overlap regions\n");
311cb93a386Sopenharmony_ci    EdgeList activeEdges;
312cb93a386Sopenharmony_ci    EventList events(comp);
313cb93a386Sopenharmony_ci    SSVertexMap ssVertices;
314cb93a386Sopenharmony_ci    SSEdgeList ssEdges;
315cb93a386Sopenharmony_ci    for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
316cb93a386Sopenharmony_ci        if (!v->isConnected()) {
317cb93a386Sopenharmony_ci            continue;
318cb93a386Sopenharmony_ci        }
319cb93a386Sopenharmony_ci        Edge* leftEnclosingEdge;
320cb93a386Sopenharmony_ci        Edge* rightEnclosingEdge;
321cb93a386Sopenharmony_ci        FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
322cb93a386Sopenharmony_ci        for (Edge* e = v->fLastEdgeAbove; e && e != leftEnclosingEdge;) {
323cb93a386Sopenharmony_ci            Edge* prev = e->fPrevEdgeAbove ? e->fPrevEdgeAbove : leftEnclosingEdge;
324cb93a386Sopenharmony_ci            activeEdges.remove(e);
325cb93a386Sopenharmony_ci            bool leftOverlap = prev && is_overlap_edge(prev);
326cb93a386Sopenharmony_ci            bool rightOverlap = is_overlap_edge(e);
327cb93a386Sopenharmony_ci            bool isOuterBoundary = e->fType == EdgeType::kOuter &&
328cb93a386Sopenharmony_ci                                   (!prev || prev->fWinding == 0 || e->fWinding == 0);
329cb93a386Sopenharmony_ci            if (prev) {
330cb93a386Sopenharmony_ci                e->fWinding -= prev->fWinding;
331cb93a386Sopenharmony_ci            }
332cb93a386Sopenharmony_ci            if (leftOverlap && rightOverlap) {
333cb93a386Sopenharmony_ci                TESS_LOG("found interior overlap edge %g -> %g, disconnecting\n",
334cb93a386Sopenharmony_ci                         e->fTop->fID, e->fBottom->fID);
335cb93a386Sopenharmony_ci                e->disconnect();
336cb93a386Sopenharmony_ci            } else if (leftOverlap || rightOverlap) {
337cb93a386Sopenharmony_ci                TESS_LOG("found overlap edge %g -> %g%s\n",
338cb93a386Sopenharmony_ci                         e->fTop->fID, e->fBottom->fID,
339cb93a386Sopenharmony_ci                         isOuterBoundary ? ", is outer boundary" : "");
340cb93a386Sopenharmony_ci                Vertex* prevVertex = e->fWinding < 0 ? e->fBottom : e->fTop;
341cb93a386Sopenharmony_ci                Vertex* nextVertex = e->fWinding < 0 ? e->fTop : e->fBottom;
342cb93a386Sopenharmony_ci                SSVertex* ssPrev = ssVertices[prevVertex];
343cb93a386Sopenharmony_ci                if (!ssPrev) {
344cb93a386Sopenharmony_ci                    ssPrev = ssVertices[prevVertex] = fAlloc->make<SSVertex>(prevVertex);
345cb93a386Sopenharmony_ci                }
346cb93a386Sopenharmony_ci                SSVertex* ssNext = ssVertices[nextVertex];
347cb93a386Sopenharmony_ci                if (!ssNext) {
348cb93a386Sopenharmony_ci                    ssNext = ssVertices[nextVertex] = fAlloc->make<SSVertex>(nextVertex);
349cb93a386Sopenharmony_ci                }
350cb93a386Sopenharmony_ci                SSEdge* ssEdge = fAlloc->make<SSEdge>(e, ssPrev, ssNext);
351cb93a386Sopenharmony_ci                ssEdges.push_back(ssEdge);
352cb93a386Sopenharmony_ci//                SkASSERT(!ssPrev->fNext && !ssNext->fPrev);
353cb93a386Sopenharmony_ci                ssPrev->fNext = ssNext->fPrev = ssEdge;
354cb93a386Sopenharmony_ci                this->makeEvent(ssEdge, &events);
355cb93a386Sopenharmony_ci                if (!isOuterBoundary) {
356cb93a386Sopenharmony_ci                    e->disconnect();
357cb93a386Sopenharmony_ci                } else {
358cb93a386Sopenharmony_ci                    SkASSERT(e->fType != EdgeType::kConnector);
359cb93a386Sopenharmony_ci                    // Ensure winding values match expected scale for the edge type. During merging of
360cb93a386Sopenharmony_ci                    // collinear edges in overlap regions, windings are summed and so could exceed the
361cb93a386Sopenharmony_ci                    // expected +/-1 for outer and +/-2 for inner that is used to fill properly during
362cb93a386Sopenharmony_ci                    // subsequent polygon generation.
363cb93a386Sopenharmony_ci                    e->fWinding = SkScalarCopySign(e->fType == EdgeType::kInner ? 2 : 1,
364cb93a386Sopenharmony_ci                                                   e->fWinding);
365cb93a386Sopenharmony_ci                }
366cb93a386Sopenharmony_ci            }
367cb93a386Sopenharmony_ci            e = prev;
368cb93a386Sopenharmony_ci        }
369cb93a386Sopenharmony_ci        Edge* prev = leftEnclosingEdge;
370cb93a386Sopenharmony_ci        for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
371cb93a386Sopenharmony_ci            if (prev) {
372cb93a386Sopenharmony_ci                e->fWinding += prev->fWinding;
373cb93a386Sopenharmony_ci            }
374cb93a386Sopenharmony_ci            activeEdges.insert(e, prev);
375cb93a386Sopenharmony_ci            prev = e;
376cb93a386Sopenharmony_ci        }
377cb93a386Sopenharmony_ci    }
378cb93a386Sopenharmony_ci    bool complex = events.size() > 0;
379cb93a386Sopenharmony_ci
380cb93a386Sopenharmony_ci    TESS_LOG("\ncollapsing overlap regions\n");
381cb93a386Sopenharmony_ci    TESS_LOG("skeleton before:\n");
382cb93a386Sopenharmony_ci    dump_skel(ssEdges);
383cb93a386Sopenharmony_ci    while (events.size() > 0) {
384cb93a386Sopenharmony_ci        Event* event = events.top();
385cb93a386Sopenharmony_ci        events.pop();
386cb93a386Sopenharmony_ci        event->apply(mesh, c, &events, this);
387cb93a386Sopenharmony_ci    }
388cb93a386Sopenharmony_ci    TESS_LOG("skeleton after:\n");
389cb93a386Sopenharmony_ci    dump_skel(ssEdges);
390cb93a386Sopenharmony_ci    for (SSEdge* edge : ssEdges) {
391cb93a386Sopenharmony_ci        if (Edge* e = edge->fEdge) {
392cb93a386Sopenharmony_ci            this->makeConnectingEdge(edge->fPrev->fVertex, edge->fNext->fVertex, e->fType, c, 0);
393cb93a386Sopenharmony_ci        }
394cb93a386Sopenharmony_ci    }
395cb93a386Sopenharmony_ci    return complex;
396cb93a386Sopenharmony_ci}
397cb93a386Sopenharmony_ci
398cb93a386Sopenharmony_cistatic bool inversion(Vertex* prev, Vertex* next, Edge* origEdge, const Comparator& c) {
399cb93a386Sopenharmony_ci    if (!prev || !next) {
400cb93a386Sopenharmony_ci        return true;
401cb93a386Sopenharmony_ci    }
402cb93a386Sopenharmony_ci    int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
403cb93a386Sopenharmony_ci    return winding != origEdge->fWinding;
404cb93a386Sopenharmony_ci}
405cb93a386Sopenharmony_ci
406cb93a386Sopenharmony_ci// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
407cb93a386Sopenharmony_ci// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
408cb93a386Sopenharmony_ci// new antialiased mesh from those vertices.
409cb93a386Sopenharmony_ci
410cb93a386Sopenharmony_civoid GrAATriangulator::strokeBoundary(EdgeList* boundary, VertexList* innerMesh,
411cb93a386Sopenharmony_ci                                      const Comparator& c) const {
412cb93a386Sopenharmony_ci    TESS_LOG("\nstroking boundary\n");
413cb93a386Sopenharmony_ci    // A boundary with fewer than 3 edges is degenerate.
414cb93a386Sopenharmony_ci    if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
415cb93a386Sopenharmony_ci        return;
416cb93a386Sopenharmony_ci    }
417cb93a386Sopenharmony_ci    Edge* prevEdge = boundary->fTail;
418cb93a386Sopenharmony_ci    Vertex* prevV = prevEdge->fWinding > 0 ? prevEdge->fTop : prevEdge->fBottom;
419cb93a386Sopenharmony_ci    SkVector prevNormal;
420cb93a386Sopenharmony_ci    get_edge_normal(prevEdge, &prevNormal);
421cb93a386Sopenharmony_ci    double radius = 0.5;
422cb93a386Sopenharmony_ci    Line prevInner(prevEdge->fLine);
423cb93a386Sopenharmony_ci    prevInner.fC -= radius;
424cb93a386Sopenharmony_ci    Line prevOuter(prevEdge->fLine);
425cb93a386Sopenharmony_ci    prevOuter.fC += radius;
426cb93a386Sopenharmony_ci    VertexList innerVertices;
427cb93a386Sopenharmony_ci    VertexList outerVertices;
428cb93a386Sopenharmony_ci    bool innerInversion = true;
429cb93a386Sopenharmony_ci    bool outerInversion = true;
430cb93a386Sopenharmony_ci    for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
431cb93a386Sopenharmony_ci        Vertex* v = e->fWinding > 0 ? e->fTop : e->fBottom;
432cb93a386Sopenharmony_ci        SkVector normal;
433cb93a386Sopenharmony_ci        get_edge_normal(e, &normal);
434cb93a386Sopenharmony_ci        Line inner(e->fLine);
435cb93a386Sopenharmony_ci        inner.fC -= radius;
436cb93a386Sopenharmony_ci        Line outer(e->fLine);
437cb93a386Sopenharmony_ci        outer.fC += radius;
438cb93a386Sopenharmony_ci        SkPoint innerPoint, outerPoint;
439cb93a386Sopenharmony_ci        TESS_LOG("stroking vertex %g (%g, %g)\n", v->fID, v->fPoint.fX, v->fPoint.fY);
440cb93a386Sopenharmony_ci        if (!prevEdge->fLine.nearParallel(e->fLine) && prevInner.intersect(inner, &innerPoint) &&
441cb93a386Sopenharmony_ci            prevOuter.intersect(outer, &outerPoint)) {
442cb93a386Sopenharmony_ci            float cosAngle = normal.dot(prevNormal);
443cb93a386Sopenharmony_ci            if (cosAngle < -kCosMiterAngle) {
444cb93a386Sopenharmony_ci                Vertex* nextV = e->fWinding > 0 ? e->fBottom : e->fTop;
445cb93a386Sopenharmony_ci
446cb93a386Sopenharmony_ci                // This is a pointy vertex whose angle is smaller than the threshold; miter it.
447cb93a386Sopenharmony_ci                Line bisector(innerPoint, outerPoint);
448cb93a386Sopenharmony_ci                Line tangent(v->fPoint, v->fPoint + SkPoint::Make(bisector.fA, bisector.fB));
449cb93a386Sopenharmony_ci                if (tangent.fA == 0 && tangent.fB == 0) {
450cb93a386Sopenharmony_ci                    continue;
451cb93a386Sopenharmony_ci                }
452cb93a386Sopenharmony_ci                tangent.normalize();
453cb93a386Sopenharmony_ci                Line innerTangent(tangent);
454cb93a386Sopenharmony_ci                Line outerTangent(tangent);
455cb93a386Sopenharmony_ci                innerTangent.fC -= 0.5;
456cb93a386Sopenharmony_ci                outerTangent.fC += 0.5;
457cb93a386Sopenharmony_ci                SkPoint innerPoint1, innerPoint2, outerPoint1, outerPoint2;
458cb93a386Sopenharmony_ci                if (prevNormal.cross(normal) > 0) {
459cb93a386Sopenharmony_ci                    // Miter inner points
460cb93a386Sopenharmony_ci                    if (!innerTangent.intersect(prevInner, &innerPoint1) ||
461cb93a386Sopenharmony_ci                        !innerTangent.intersect(inner, &innerPoint2) ||
462cb93a386Sopenharmony_ci                        !outerTangent.intersect(bisector, &outerPoint)) {
463cb93a386Sopenharmony_ci                        continue;
464cb93a386Sopenharmony_ci                    }
465cb93a386Sopenharmony_ci                    Line prevTangent(prevV->fPoint,
466cb93a386Sopenharmony_ci                                     prevV->fPoint + SkVector::Make(prevOuter.fA, prevOuter.fB));
467cb93a386Sopenharmony_ci                    Line nextTangent(nextV->fPoint,
468cb93a386Sopenharmony_ci                                     nextV->fPoint + SkVector::Make(outer.fA, outer.fB));
469cb93a386Sopenharmony_ci                    if (prevTangent.dist(outerPoint) > 0) {
470cb93a386Sopenharmony_ci                        bisector.intersect(prevTangent, &outerPoint);
471cb93a386Sopenharmony_ci                    }
472cb93a386Sopenharmony_ci                    if (nextTangent.dist(outerPoint) < 0) {
473cb93a386Sopenharmony_ci                        bisector.intersect(nextTangent, &outerPoint);
474cb93a386Sopenharmony_ci                    }
475cb93a386Sopenharmony_ci                    outerPoint1 = outerPoint2 = outerPoint;
476cb93a386Sopenharmony_ci                } else {
477cb93a386Sopenharmony_ci                    // Miter outer points
478cb93a386Sopenharmony_ci                    if (!outerTangent.intersect(prevOuter, &outerPoint1) ||
479cb93a386Sopenharmony_ci                        !outerTangent.intersect(outer, &outerPoint2)) {
480cb93a386Sopenharmony_ci                        continue;
481cb93a386Sopenharmony_ci                    }
482cb93a386Sopenharmony_ci                    Line prevTangent(prevV->fPoint,
483cb93a386Sopenharmony_ci                                     prevV->fPoint + SkVector::Make(prevInner.fA, prevInner.fB));
484cb93a386Sopenharmony_ci                    Line nextTangent(nextV->fPoint,
485cb93a386Sopenharmony_ci                                     nextV->fPoint + SkVector::Make(inner.fA, inner.fB));
486cb93a386Sopenharmony_ci                    if (prevTangent.dist(innerPoint) > 0) {
487cb93a386Sopenharmony_ci                        bisector.intersect(prevTangent, &innerPoint);
488cb93a386Sopenharmony_ci                    }
489cb93a386Sopenharmony_ci                    if (nextTangent.dist(innerPoint) < 0) {
490cb93a386Sopenharmony_ci                        bisector.intersect(nextTangent, &innerPoint);
491cb93a386Sopenharmony_ci                    }
492cb93a386Sopenharmony_ci                    innerPoint1 = innerPoint2 = innerPoint;
493cb93a386Sopenharmony_ci                }
494cb93a386Sopenharmony_ci                if (!innerPoint1.isFinite() || !innerPoint2.isFinite() ||
495cb93a386Sopenharmony_ci                    !outerPoint1.isFinite() || !outerPoint2.isFinite()) {
496cb93a386Sopenharmony_ci                    continue;
497cb93a386Sopenharmony_ci                }
498cb93a386Sopenharmony_ci                TESS_LOG("inner (%g, %g), (%g, %g), ",
499cb93a386Sopenharmony_ci                         innerPoint1.fX, innerPoint1.fY, innerPoint2.fX, innerPoint2.fY);
500cb93a386Sopenharmony_ci                TESS_LOG("outer (%g, %g), (%g, %g)\n",
501cb93a386Sopenharmony_ci                         outerPoint1.fX, outerPoint1.fY, outerPoint2.fX, outerPoint2.fY);
502cb93a386Sopenharmony_ci                Vertex* innerVertex1 = fAlloc->make<Vertex>(innerPoint1, 255);
503cb93a386Sopenharmony_ci                Vertex* innerVertex2 = fAlloc->make<Vertex>(innerPoint2, 255);
504cb93a386Sopenharmony_ci                Vertex* outerVertex1 = fAlloc->make<Vertex>(outerPoint1, 0);
505cb93a386Sopenharmony_ci                Vertex* outerVertex2 = fAlloc->make<Vertex>(outerPoint2, 0);
506cb93a386Sopenharmony_ci                innerVertex1->fPartner = outerVertex1;
507cb93a386Sopenharmony_ci                innerVertex2->fPartner = outerVertex2;
508cb93a386Sopenharmony_ci                outerVertex1->fPartner = innerVertex1;
509cb93a386Sopenharmony_ci                outerVertex2->fPartner = innerVertex2;
510cb93a386Sopenharmony_ci                if (!inversion(innerVertices.fTail, innerVertex1, prevEdge, c)) {
511cb93a386Sopenharmony_ci                    innerInversion = false;
512cb93a386Sopenharmony_ci                }
513cb93a386Sopenharmony_ci                if (!inversion(outerVertices.fTail, outerVertex1, prevEdge, c)) {
514cb93a386Sopenharmony_ci                    outerInversion = false;
515cb93a386Sopenharmony_ci                }
516cb93a386Sopenharmony_ci                innerVertices.append(innerVertex1);
517cb93a386Sopenharmony_ci                innerVertices.append(innerVertex2);
518cb93a386Sopenharmony_ci                outerVertices.append(outerVertex1);
519cb93a386Sopenharmony_ci                outerVertices.append(outerVertex2);
520cb93a386Sopenharmony_ci            } else {
521cb93a386Sopenharmony_ci                TESS_LOG("inner (%g, %g), ", innerPoint.fX, innerPoint.fY);
522cb93a386Sopenharmony_ci                TESS_LOG("outer (%g, %g)\n", outerPoint.fX, outerPoint.fY);
523cb93a386Sopenharmony_ci                Vertex* innerVertex = fAlloc->make<Vertex>(innerPoint, 255);
524cb93a386Sopenharmony_ci                Vertex* outerVertex = fAlloc->make<Vertex>(outerPoint, 0);
525cb93a386Sopenharmony_ci                innerVertex->fPartner = outerVertex;
526cb93a386Sopenharmony_ci                outerVertex->fPartner = innerVertex;
527cb93a386Sopenharmony_ci                if (!inversion(innerVertices.fTail, innerVertex, prevEdge, c)) {
528cb93a386Sopenharmony_ci                    innerInversion = false;
529cb93a386Sopenharmony_ci                }
530cb93a386Sopenharmony_ci                if (!inversion(outerVertices.fTail, outerVertex, prevEdge, c)) {
531cb93a386Sopenharmony_ci                    outerInversion = false;
532cb93a386Sopenharmony_ci                }
533cb93a386Sopenharmony_ci                innerVertices.append(innerVertex);
534cb93a386Sopenharmony_ci                outerVertices.append(outerVertex);
535cb93a386Sopenharmony_ci            }
536cb93a386Sopenharmony_ci        }
537cb93a386Sopenharmony_ci        prevInner = inner;
538cb93a386Sopenharmony_ci        prevOuter = outer;
539cb93a386Sopenharmony_ci        prevV = v;
540cb93a386Sopenharmony_ci        prevEdge = e;
541cb93a386Sopenharmony_ci        prevNormal = normal;
542cb93a386Sopenharmony_ci    }
543cb93a386Sopenharmony_ci    if (!inversion(innerVertices.fTail, innerVertices.fHead, prevEdge, c)) {
544cb93a386Sopenharmony_ci        innerInversion = false;
545cb93a386Sopenharmony_ci    }
546cb93a386Sopenharmony_ci    if (!inversion(outerVertices.fTail, outerVertices.fHead, prevEdge, c)) {
547cb93a386Sopenharmony_ci        outerInversion = false;
548cb93a386Sopenharmony_ci    }
549cb93a386Sopenharmony_ci    // Outer edges get 1 winding, and inner edges get -2 winding. This ensures that the interior
550cb93a386Sopenharmony_ci    // is always filled (1 + -2 = -1 for normal cases, 1 + 2 = 3 for thin features where the
551cb93a386Sopenharmony_ci    // interior inverts).
552cb93a386Sopenharmony_ci    // For total inversion cases, the shape has now reversed handedness, so invert the winding
553cb93a386Sopenharmony_ci    // so it will be detected during collapseOverlapRegions().
554cb93a386Sopenharmony_ci    int innerWinding = innerInversion ? 2 : -2;
555cb93a386Sopenharmony_ci    int outerWinding = outerInversion ? -1 : 1;
556cb93a386Sopenharmony_ci    for (Vertex* v = innerVertices.fHead; v && v->fNext; v = v->fNext) {
557cb93a386Sopenharmony_ci        this->makeConnectingEdge(v, v->fNext, EdgeType::kInner, c, innerWinding);
558cb93a386Sopenharmony_ci    }
559cb93a386Sopenharmony_ci    this->makeConnectingEdge(innerVertices.fTail, innerVertices.fHead, EdgeType::kInner, c,
560cb93a386Sopenharmony_ci                             innerWinding);
561cb93a386Sopenharmony_ci    for (Vertex* v = outerVertices.fHead; v && v->fNext; v = v->fNext) {
562cb93a386Sopenharmony_ci        this->makeConnectingEdge(v, v->fNext, EdgeType::kOuter, c, outerWinding);
563cb93a386Sopenharmony_ci    }
564cb93a386Sopenharmony_ci    this->makeConnectingEdge(outerVertices.fTail, outerVertices.fHead, EdgeType::kOuter, c,
565cb93a386Sopenharmony_ci                             outerWinding);
566cb93a386Sopenharmony_ci    innerMesh->append(innerVertices);
567cb93a386Sopenharmony_ci    fOuterMesh.append(outerVertices);
568cb93a386Sopenharmony_ci}
569cb93a386Sopenharmony_ci
570cb93a386Sopenharmony_civoid GrAATriangulator::extractBoundary(EdgeList* boundary, Edge* e) const {
571cb93a386Sopenharmony_ci    TESS_LOG("\nextracting boundary\n");
572cb93a386Sopenharmony_ci    bool down = this->applyFillType(e->fWinding);
573cb93a386Sopenharmony_ci    Vertex* start = down ? e->fTop : e->fBottom;
574cb93a386Sopenharmony_ci    do {
575cb93a386Sopenharmony_ci        e->fWinding = down ? 1 : -1;
576cb93a386Sopenharmony_ci        Edge* next;
577cb93a386Sopenharmony_ci        e->fLine.normalize();
578cb93a386Sopenharmony_ci        e->fLine = e->fLine * e->fWinding;
579cb93a386Sopenharmony_ci        boundary->append(e);
580cb93a386Sopenharmony_ci        if (down) {
581cb93a386Sopenharmony_ci            // Find outgoing edge, in clockwise order.
582cb93a386Sopenharmony_ci            if ((next = e->fNextEdgeAbove)) {
583cb93a386Sopenharmony_ci                down = false;
584cb93a386Sopenharmony_ci            } else if ((next = e->fBottom->fLastEdgeBelow)) {
585cb93a386Sopenharmony_ci                down = true;
586cb93a386Sopenharmony_ci            } else if ((next = e->fPrevEdgeAbove)) {
587cb93a386Sopenharmony_ci                down = false;
588cb93a386Sopenharmony_ci            }
589cb93a386Sopenharmony_ci        } else {
590cb93a386Sopenharmony_ci            // Find outgoing edge, in counter-clockwise order.
591cb93a386Sopenharmony_ci            if ((next = e->fPrevEdgeBelow)) {
592cb93a386Sopenharmony_ci                down = true;
593cb93a386Sopenharmony_ci            } else if ((next = e->fTop->fFirstEdgeAbove)) {
594cb93a386Sopenharmony_ci                down = false;
595cb93a386Sopenharmony_ci            } else if ((next = e->fNextEdgeBelow)) {
596cb93a386Sopenharmony_ci                down = true;
597cb93a386Sopenharmony_ci            }
598cb93a386Sopenharmony_ci        }
599cb93a386Sopenharmony_ci        e->disconnect();
600cb93a386Sopenharmony_ci        e = next;
601cb93a386Sopenharmony_ci    } while (e && (down ? e->fTop : e->fBottom) != start);
602cb93a386Sopenharmony_ci}
603cb93a386Sopenharmony_ci
604cb93a386Sopenharmony_ci// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
605cb93a386Sopenharmony_ci
606cb93a386Sopenharmony_civoid GrAATriangulator::extractBoundaries(const VertexList& inMesh, VertexList* innerVertices,
607cb93a386Sopenharmony_ci                                         const Comparator& c) const {
608cb93a386Sopenharmony_ci    this->removeNonBoundaryEdges(inMesh);
609cb93a386Sopenharmony_ci    for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
610cb93a386Sopenharmony_ci        while (v->fFirstEdgeBelow) {
611cb93a386Sopenharmony_ci            EdgeList boundary;
612cb93a386Sopenharmony_ci            this->extractBoundary(&boundary, v->fFirstEdgeBelow);
613cb93a386Sopenharmony_ci            this->simplifyBoundary(&boundary, c);
614cb93a386Sopenharmony_ci            this->strokeBoundary(&boundary, innerVertices, c);
615cb93a386Sopenharmony_ci        }
616cb93a386Sopenharmony_ci    }
617cb93a386Sopenharmony_ci}
618cb93a386Sopenharmony_ci
619cb93a386Sopenharmony_ciPoly* GrAATriangulator::tessellate(const VertexList& mesh, const Comparator& c) const {
620cb93a386Sopenharmony_ci    VertexList innerMesh;
621cb93a386Sopenharmony_ci    this->extractBoundaries(mesh, &innerMesh, c);
622cb93a386Sopenharmony_ci    SortMesh(&innerMesh, c);
623cb93a386Sopenharmony_ci    SortMesh(&fOuterMesh, c);
624cb93a386Sopenharmony_ci    this->mergeCoincidentVertices(&innerMesh, c);
625cb93a386Sopenharmony_ci    bool was_complex = this->mergeCoincidentVertices(&fOuterMesh, c);
626cb93a386Sopenharmony_ci    auto result = this->simplify(&innerMesh, c);
627cb93a386Sopenharmony_ci    was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
628cb93a386Sopenharmony_ci    result = this->simplify(&fOuterMesh, c);
629cb93a386Sopenharmony_ci    was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
630cb93a386Sopenharmony_ci    TESS_LOG("\ninner mesh before:\n");
631cb93a386Sopenharmony_ci    DUMP_MESH(innerMesh);
632cb93a386Sopenharmony_ci    TESS_LOG("\nouter mesh before:\n");
633cb93a386Sopenharmony_ci    DUMP_MESH(fOuterMesh);
634cb93a386Sopenharmony_ci    EventComparator eventLT(EventComparator::Op::kLessThan);
635cb93a386Sopenharmony_ci    EventComparator eventGT(EventComparator::Op::kGreaterThan);
636cb93a386Sopenharmony_ci    was_complex = this->collapseOverlapRegions(&innerMesh, c, eventLT) || was_complex;
637cb93a386Sopenharmony_ci    was_complex = this->collapseOverlapRegions(&fOuterMesh, c, eventGT) || was_complex;
638cb93a386Sopenharmony_ci    if (was_complex) {
639cb93a386Sopenharmony_ci        TESS_LOG("found complex mesh; taking slow path\n");
640cb93a386Sopenharmony_ci        VertexList aaMesh;
641cb93a386Sopenharmony_ci        TESS_LOG("\ninner mesh after:\n");
642cb93a386Sopenharmony_ci        DUMP_MESH(innerMesh);
643cb93a386Sopenharmony_ci        TESS_LOG("\nouter mesh after:\n");
644cb93a386Sopenharmony_ci        DUMP_MESH(fOuterMesh);
645cb93a386Sopenharmony_ci        this->connectPartners(&fOuterMesh, c);
646cb93a386Sopenharmony_ci        this->connectPartners(&innerMesh, c);
647cb93a386Sopenharmony_ci        SortedMerge(&innerMesh, &fOuterMesh, &aaMesh, c);
648cb93a386Sopenharmony_ci        TESS_LOG("\nmerged mesh:\n");
649cb93a386Sopenharmony_ci        DUMP_MESH(aaMesh);
650cb93a386Sopenharmony_ci        this->mergeCoincidentVertices(&aaMesh, c);
651cb93a386Sopenharmony_ci        result = this->simplify(&aaMesh, c);
652cb93a386Sopenharmony_ci        TESS_LOG("combined and simplified mesh:\n");
653cb93a386Sopenharmony_ci        DUMP_MESH(aaMesh);
654cb93a386Sopenharmony_ci        fOuterMesh.fHead = fOuterMesh.fTail = nullptr;
655cb93a386Sopenharmony_ci        return this->GrTriangulator::tessellate(aaMesh, c);
656cb93a386Sopenharmony_ci    } else {
657cb93a386Sopenharmony_ci        TESS_LOG("no complex polygons; taking fast path\n");
658cb93a386Sopenharmony_ci        return this->GrTriangulator::tessellate(innerMesh, c);
659cb93a386Sopenharmony_ci    }
660cb93a386Sopenharmony_ci}
661cb93a386Sopenharmony_ci
662cb93a386Sopenharmony_ciint GrAATriangulator::polysToAATriangles(Poly* polys,
663cb93a386Sopenharmony_ci                                         GrEagerVertexAllocator* vertexAllocator) const {
664cb93a386Sopenharmony_ci    int64_t count64 = CountPoints(polys, SkPathFillType::kWinding);
665cb93a386Sopenharmony_ci    // Count the points from the outer mesh.
666cb93a386Sopenharmony_ci    for (Vertex* v = fOuterMesh.fHead; v; v = v->fNext) {
667cb93a386Sopenharmony_ci        for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
668cb93a386Sopenharmony_ci            count64 += TRIANGULATOR_WIREFRAME ? 12 : 6;
669cb93a386Sopenharmony_ci        }
670cb93a386Sopenharmony_ci    }
671cb93a386Sopenharmony_ci    if (0 == count64 || count64 > SK_MaxS32) {
672cb93a386Sopenharmony_ci        return 0;
673cb93a386Sopenharmony_ci    }
674cb93a386Sopenharmony_ci    int count = count64;
675cb93a386Sopenharmony_ci
676cb93a386Sopenharmony_ci    size_t vertexStride = sizeof(SkPoint) + sizeof(float);
677cb93a386Sopenharmony_ci    void* verts = vertexAllocator->lock(vertexStride, count);
678cb93a386Sopenharmony_ci    if (!verts) {
679cb93a386Sopenharmony_ci        SkDebugf("Could not allocate vertices\n");
680cb93a386Sopenharmony_ci        return 0;
681cb93a386Sopenharmony_ci    }
682cb93a386Sopenharmony_ci
683cb93a386Sopenharmony_ci    TESS_LOG("emitting %d verts\n", count);
684cb93a386Sopenharmony_ci    void* end = this->polysToTriangles(polys, verts, SkPathFillType::kWinding);
685cb93a386Sopenharmony_ci    // Emit the triangles from the outer mesh.
686cb93a386Sopenharmony_ci    for (Vertex* v = fOuterMesh.fHead; v; v = v->fNext) {
687cb93a386Sopenharmony_ci        for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
688cb93a386Sopenharmony_ci            Vertex* v0 = e->fTop;
689cb93a386Sopenharmony_ci            Vertex* v1 = e->fBottom;
690cb93a386Sopenharmony_ci            Vertex* v2 = e->fBottom->fPartner;
691cb93a386Sopenharmony_ci            Vertex* v3 = e->fTop->fPartner;
692cb93a386Sopenharmony_ci            end = this->emitTriangle(v0, v1, v2, 0/*winding*/, end);
693cb93a386Sopenharmony_ci            end = this->emitTriangle(v0, v2, v3, 0/*winding*/, end);
694cb93a386Sopenharmony_ci        }
695cb93a386Sopenharmony_ci    }
696cb93a386Sopenharmony_ci
697cb93a386Sopenharmony_ci    int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
698cb93a386Sopenharmony_ci                                       / vertexStride);
699cb93a386Sopenharmony_ci    SkASSERT(actualCount <= count);
700cb93a386Sopenharmony_ci    vertexAllocator->unlock(actualCount);
701cb93a386Sopenharmony_ci    return actualCount;
702cb93a386Sopenharmony_ci}
703