Flutter Engine
The Flutter Engine
GrTriangulator.h
Go to the documentation of this file.
1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrTriangulator_DEFINED
9#define GrTriangulator_DEFINED
10
11#if !defined(SK_ENABLE_OPTIMIZE_SIZE)
12
13#include "include/core/SkPath.h"
19
20#include <algorithm>
21#include <cmath>
22#include <cstdint>
23#include <tuple>
24
26enum class SkPathFillType;
27struct SkRect;
28
29#define TRIANGULATOR_LOGGING 0
30#define TRIANGULATOR_WIREFRAME 0
31
32/**
33 * Provides utility functions for converting paths to a collection of triangles.
34 */
36public:
37 constexpr static int kArenaDefaultChunkSize = 16 * 1024;
38
39 static int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
40 GrEagerVertexAllocator* vertexAllocator, bool* isLinear) {
41 if (!path.isFinite()) {
42 return 0;
43 }
45 GrTriangulator triangulator(path, &alloc);
46 auto [ polys, success ] = triangulator.pathToPolys(tolerance, clipBounds, isLinear);
47 if (!success) {
48 return 0;
49 }
50 int count = triangulator.polysToTriangles(polys, vertexAllocator);
51 return count;
52 }
53
54 // Enums used by GrTriangulator internals.
55 typedef enum { kLeft_Side, kRight_Side } Side;
56 enum class EdgeType { kInner, kOuter, kConnector };
57
58 // Structs used by GrTriangulator internals.
59 struct Vertex;
60 struct VertexList;
61 struct Line;
62 struct Edge;
63 struct EdgeList;
64 struct MonotonePoly;
65 struct Poly;
66 struct Comparator;
67
68protected:
69 GrTriangulator(const SkPath& path, SkArenaAlloc* alloc) : fPath(path), fAlloc(alloc) {}
70 virtual ~GrTriangulator() {}
71
72 // There are six stages to the basic algorithm:
73 //
74 // 1) Linearize the path contours into piecewise linear segments:
75 void pathToContours(float tolerance, const SkRect& clipBounds, VertexList* contours,
76 bool* isLinear) const;
77
78 // 2) Build a mesh of edges connecting the vertices:
79 void contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
80 const Comparator&);
81
82 // 3) Sort the vertices in Y (and secondarily in X):
83 static void SortedMerge(VertexList* front, VertexList* back, VertexList* result,
84 const Comparator&);
85 static void SortMesh(VertexList* vertices, const Comparator&);
86
87 // 4) Simplify the mesh by inserting new vertices at intersecting edges:
88 enum class SimplifyResult {
89 kFailed,
90 kAlreadySimple,
91 kFoundSelfIntersection
92 };
93
94 enum class BoolFail {
95 kFalse,
96 kTrue,
97 kFail
98 };
99
100 [[nodiscard]] SimplifyResult simplify(VertexList* mesh, const Comparator&);
101
102 // 5) Tessellate the simplified mesh into monotone polygons:
103 virtual std::tuple<Poly*, bool> tessellate(const VertexList& vertices, const Comparator&);
104
105 // 6) Triangulate the monotone polygons directly into a vertex buffer:
107 SkPathFillType overrideFillType,
109
110 // The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
111 // of vertices (and the necessity of inserting new vertices on intersection).
112 //
113 // Stages (4) and (5) use an active edge list -- a list of all edges for which the
114 // sweep line has crossed the top vertex, but not the bottom vertex. It's sorted
115 // left-to-right based on the point where both edges are active (when both top vertices
116 // have been seen, so the "lower" top vertex of the two). If the top vertices are equal
117 // (shared), it's sorted based on the last point where both edges are active, so the
118 // "upper" bottom vertex.
119 //
120 // The most complex step is the simplification (4). It's based on the Bentley-Ottman
121 // line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
122 // not exact and may violate the mesh topology or active edge list ordering. We
123 // accommodate this by adjusting the topology of the mesh and AEL to match the intersection
124 // points. This occurs in two ways:
125 //
126 // A) Intersections may cause a shortened edge to no longer be ordered with respect to its
127 // neighbouring edges at the top or bottom vertex. This is handled by merging the
128 // edges (mergeCollinearVertices()).
129 // B) Intersections may cause an edge to violate the left-to-right ordering of the
130 // active edge list. This is handled by detecting potential violations and rewinding
131 // the active edge list to the vertex before they occur (rewind() during merging,
132 // rewind_if_necessary() during splitting).
133 //
134 // The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
135 // Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
136 // currently uses a linked list for the active edge list, rather than a 2-3 tree as the
137 // paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
138 // become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
139 // insertions and removals was greater than the cost of infrequent O(N) lookups with the
140 // linked list implementation. With the latter, all removals are O(1), and most insertions
141 // are O(1), since we know the adjacent edge in the active edge list based on the topology.
142 // Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
143 // frequent. There may be other data structures worth investigating, however.
144 //
145 // Note that the orientation of the line sweep algorithms is determined by the aspect ratio of
146 // the path bounds. When the path is taller than it is wide, we sort vertices based on
147 // increasing Y coordinate, and secondarily by increasing X coordinate. When the path is wider
148 // than it is tall, we sort by increasing X coordinate, but secondarily by *decreasing* Y
149 // coordinate. This is so that the "left" and "right" orientation in the code remains correct
150 // (edges to the left are increasing in Y; edges to the right are decreasing in Y). That is, the
151 // setting rotates 90 degrees counterclockwise, rather that transposing.
152
153 // Additional helpers and driver functions.
158
159 Poly* makePoly(Poly** head, Vertex* v, int winding) const;
160 void appendPointToContour(const SkPoint& p, VertexList* contour) const;
161 void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd,
162 VertexList* contour) const;
163 void generateCubicPoints(const SkPoint&, const SkPoint&, const SkPoint&, const SkPoint&,
164 SkScalar tolSqd, VertexList* contour, int pointsLeft) const;
165 bool applyFillType(int winding) const;
166 MonotonePoly* allocateMonotonePoly(Edge* edge, Side side, int winding);
167 Edge* allocateEdge(Vertex* top, Vertex* bottom, int winding, EdgeType type);
169 [[nodiscard]] bool setTop(
170 Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
171 [[nodiscard]] bool setBottom(
172 Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
173 [[nodiscard]] bool mergeEdgesAbove(
174 Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
175 [[nodiscard]] bool mergeEdgesBelow(
176 Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, const Comparator&) const;
178 int windingScale = 1);
179 void mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh, const Comparator&) const;
180 static void FindEnclosingEdges(const Vertex& v, const EdgeList& edges,
181 Edge** left, Edge** right);
182 bool mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
183 const Comparator&) const;
184 BoolFail splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
185 const Comparator&);
186 BoolFail intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current,
187 const Comparator&);
188 Vertex* makeSortedVertex(const SkPoint&, uint8_t alpha, VertexList* mesh, Vertex* reference,
189 const Comparator&) const;
190 void computeBisector(Edge* edge1, Edge* edge2, Vertex*) const;
191 BoolFail checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current,
192 VertexList* mesh, const Comparator&);
193 void sanitizeContours(VertexList* contours, int contourCnt) const;
195 void buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
196 const Comparator&);
197 std::tuple<Poly*, bool> contoursToPolys(VertexList* contours, int contourCnt);
198 std::tuple<Poly*, bool> pathToPolys(float tolerance, const SkRect& clipBounds,
199 bool* isLinear);
200 static int64_t CountPoints(Poly* polys, SkPathFillType overrideFillType);
202
203 // FIXME: fPath should be plumbed through function parameters instead.
207 int fNumEdges = 0;
208
209 // Internal control knobs.
211 bool fEmitCoverage = false;
214
215 // The breadcrumb triangles serve as a glue that erases T-junctions between a path's outer
216 // curves and its inner polygon triangulation. Drawing a path's outer curves, breadcrumb
217 // triangles, and inner polygon triangulation all together into the stencil buffer has the same
218 // identical rasterized effect as stenciling a classic Redbook fan.
219 //
220 // The breadcrumb triangles track all the edge splits that led from the original inner polygon
221 // edges to the final triangulation. Every time an edge splits, we emit a razor-thin breadcrumb
222 // triangle consisting of the edge's original endpoints and the split point. (We also add
223 // supplemental breadcrumb triangles to areas where abs(winding) > 1.)
224 //
225 // a
226 // /
227 // /
228 // /
229 // x <- Edge splits at x. New breadcrumb triangle is: [a, b, x].
230 // /
231 // /
232 // b
233 //
234 // The opposite-direction shared edges between the triangulation and breadcrumb triangles should
235 // all cancel out, leaving just the set of edges from the original polygon.
237 public:
238 struct Node {
241 Node* fNext = nullptr;
242 };
243 const Node* head() const { return fHead; }
244 int count() const { return fCount; }
245
246 void append(SkArenaAlloc* alloc, SkPoint a, SkPoint b, SkPoint c, int winding) {
247 if (a == b || a == c || b == c || winding == 0) {
248 return;
249 }
250 if (winding < 0) {
251 std::swap(a, b);
252 winding = -winding;
253 }
254 for (int i = 0; i < winding; ++i) {
255 SkASSERT(fTail && !(*fTail));
256 *fTail = alloc->make<Node>(a, b, c);
257 fTail = &(*fTail)->fNext;
258 }
259 fCount += winding;
260 }
261
263 SkASSERT(fTail && !(*fTail));
264 if (list.fHead) {
265 *fTail = list.fHead;
266 fTail = list.fTail;
267 fCount += list.fCount;
268 list.fHead = nullptr;
269 list.fTail = &list.fHead;
270 list.fCount = 0;
271 }
272 }
273
274 private:
275 Node* fHead = nullptr;
276 Node** fTail = &fHead;
277 int fCount = 0;
278 };
279
281};
282
283/**
284 * Vertices are used in three ways: first, the path contours are converted into a
285 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
286 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
287 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
288 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
289 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
290 * an individual Vertex from the path mesh may belong to multiple
291 * MonotonePolys, so the original Vertices cannot be re-used.
292 */
293
295 Vertex(const SkPoint& point, uint8_t alpha)
296 : fPoint(point), fPrev(nullptr), fNext(nullptr)
297 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
298 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
299 , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
300 , fPartner(nullptr)
301 , fAlpha(alpha)
304 , fID (-1.0f)
305#endif
306 {}
307 SkPoint fPoint; // Vertex position
308 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
310 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
312 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
314 Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
315 Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
316 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
317 uint8_t fAlpha;
318 bool fSynthetic; // Is this a synthetic vertex?
319#if TRIANGULATOR_LOGGING
320 float fID; // Identifier used for logging.
321#endif
322 bool isConnected() const { return this->fFirstEdgeAbove || this->fFirstEdgeBelow; }
323};
324
326 VertexList() : fHead(nullptr), fTail(nullptr) {}
330 void insert(Vertex* v, Vertex* prev, Vertex* next);
331 void append(Vertex* v) { insert(v, fTail, nullptr); }
332 void append(const VertexList& list) {
333 if (!list.fHead) {
334 return;
335 }
336 if (fTail) {
337 fTail->fNext = list.fHead;
338 list.fHead->fPrev = fTail;
339 } else {
340 fHead = list.fHead;
341 }
342 fTail = list.fTail;
343 }
344 void prepend(Vertex* v) { insert(v, nullptr, fHead); }
345 void remove(Vertex* v);
346 void close() {
347 if (fHead && fTail) {
348 fTail->fNext = fHead;
349 fHead->fPrev = fTail;
350 }
351 }
352#if TRIANGULATOR_LOGGING
353 void dump() const;
354#endif
355};
356
357// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
359 Line(double a, double b, double c) : fA(a), fB(b), fC(c) {}
360 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
361 Line(const SkPoint& p, const SkPoint& q)
362 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
363 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
364 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
365 static_cast<double>(p.fX) * q.fY) {}
366 double dist(const SkPoint& p) const { return fA * p.fX + fB * p.fY + fC; }
367 Line operator*(double v) const { return Line(fA * v, fB * v, fC * v); }
368 double magSq() const { return fA * fA + fB * fB; }
369 void normalize() {
370 double len = sqrt(this->magSq());
371 if (len == 0.0) {
372 return;
373 }
374 double scale = 1.0f / len;
375 fA *= scale;
376 fB *= scale;
377 fC *= scale;
378 }
379 bool nearParallel(const Line& o) const {
380 return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001;
381 }
382
383 // Compute the intersection of two (infinite) Lines.
384 bool intersect(const Line& other, SkPoint* point) const;
385 double fA, fB, fC;
386};
387
388/**
389 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
390 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
391 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
392 * point). For speed, that case is only tested by the callers that require it (e.g.,
393 * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
394 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
395 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
396 * a lot faster in the "not found" case.
397 *
398 * The coefficients of the line equation stored in double precision to avoid catastrophic
399 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
400 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
401 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
402 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
403 * this file).
404 */
405
407 Edge(Vertex* top, Vertex* bottom, int winding, EdgeType type)
408 : fWinding(winding)
409 , fTop(top)
410 , fBottom(bottom)
411 , fType(type)
412 , fLeft(nullptr)
413 , fRight(nullptr)
414 , fPrevEdgeAbove(nullptr)
415 , fNextEdgeAbove(nullptr)
416 , fPrevEdgeBelow(nullptr)
417 , fNextEdgeBelow(nullptr)
418 , fLeftPoly(nullptr)
419 , fRightPoly(nullptr)
420 , fLeftPolyPrev(nullptr)
421 , fLeftPolyNext(nullptr)
422 , fRightPolyPrev(nullptr)
423 , fRightPolyNext(nullptr)
426 , fLine(top, bottom) {
427 }
428 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
429 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
430 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
432 Edge* fLeft; // The linked list of edges in the active edge list.
434 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
436 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
438 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
439 Poly* fRightPoly; // The Poly to the right of this edge, if any.
447
448 double dist(const SkPoint& p) const {
449 // Coerce points coincident with the vertices to have dist = 0, since converting from
450 // a double intersection point back to float storage might construct a point that's no
451 // longer on the ideal line.
452 return (p == fTop->fPoint || p == fBottom->fPoint) ? 0.0 : fLine.dist(p);
453 }
454 bool isRightOf(const Vertex& v) const { return this->dist(v.fPoint) < 0.0; }
455 bool isLeftOf(const Vertex& v) const { return this->dist(v.fPoint) > 0.0; }
457 void insertAbove(Vertex*, const Comparator&);
458 void insertBelow(Vertex*, const Comparator&);
459 void disconnect();
460 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const;
461};
462
464 EdgeList() : fHead(nullptr), fTail(nullptr) {}
467 void insert(Edge* edge, Edge* prev, Edge* next);
468 bool insert(Edge* edge, Edge* prev);
469 void append(Edge* e) { insert(e, fTail, nullptr); }
470 bool remove(Edge* edge);
471 void removeAll() {
472 while (fHead) {
473 this->remove(fHead);
474 }
475 }
476 void close() {
477 if (fHead && fTail) {
478 fTail->fRight = fHead;
479 fHead->fLeft = fTail;
480 }
481 }
482 bool contains(Edge* edge) const { return edge->fLeft || edge->fRight || fHead == edge; }
483};
484
486 MonotonePoly(Edge* edge, Side side, int winding)
487 : fSide(side)
488 , fFirstEdge(nullptr)
489 , fLastEdge(nullptr)
490 , fPrev(nullptr)
491 , fNext(nullptr)
492 , fWinding(winding) {
493 this->addEdge(edge);
494 }
501 void addEdge(Edge*);
502};
503
505 Poly(Vertex* v, int winding);
506
516#if TRIANGULATOR_LOGGING
517 int fID;
518#endif
519};
520
522 enum class Direction { kVertical, kHorizontal };
523 Comparator(Direction direction) : fDirection(direction) {}
524 bool sweep_lt(const SkPoint& a, const SkPoint& b) const;
526};
527
528#endif // SK_ENABLE_OPTIMIZE_SIZE
529
530#endif // GrTriangulator_DEFINED
int count
Definition: FontMgrTest.cpp:50
GrTriangulator::Line Line
#define TRIANGULATOR_LOGGING
static float next(float f)
static float prev(float f)
#define SkASSERT(cond)
Definition: SkAssert.h:116
static int side(double x)
SkPathFillType
Definition: SkPathTypes.h:11
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
GLenum type
void concat(BreadcrumbTriangleList &&list)
void append(SkArenaAlloc *alloc, SkPoint a, SkPoint b, SkPoint c, int winding)
void contoursToMesh(VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
GrTriangulator(const SkPath &path, SkArenaAlloc *alloc)
std::tuple< Poly *, bool > pathToPolys(float tolerance, const SkRect &clipBounds, bool *isLinear)
skgpu::VertexWriter emitMonotonePoly(const MonotonePoly *, skgpu::VertexWriter data) const
static int64_t CountPoints(Poly *polys, SkPathFillType overrideFillType)
static void SortMesh(VertexList *vertices, const Comparator &)
bool mergeCollinearEdges(Edge *edge, EdgeList *activeEdges, Vertex **current, const Comparator &) const
Edge * allocateEdge(Vertex *top, Vertex *bottom, int winding, EdgeType type)
bool setTop(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
bool fPreserveCollinearVertices
Edge * makeEdge(Vertex *prev, Vertex *next, EdgeType type, const Comparator &)
SkArenaAlloc *const fAlloc
void buildEdges(VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
bool fCollectBreadcrumbTriangles
BreadcrumbTriangleList fBreadcrumbList
bool applyFillType(int winding) const
MonotonePoly * allocateMonotonePoly(Edge *edge, Side side, int winding)
SimplifyResult simplify(VertexList *mesh, const Comparator &)
virtual std::tuple< Poly *, bool > tessellate(const VertexList &vertices, const Comparator &)
Poly * makePoly(Poly **head, Vertex *v, int winding) const
static int PathToTriangles(const SkPath &path, SkScalar tolerance, const SkRect &clipBounds, GrEagerVertexAllocator *vertexAllocator, bool *isLinear)
skgpu::VertexWriter polysToTriangles(Poly *polys, SkPathFillType overrideFillType, skgpu::VertexWriter data) const
static void SortedMerge(VertexList *front, VertexList *back, VertexList *result, const Comparator &)
bool setBottom(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
bool fRoundVerticesToQuarterPixel
void pathToContours(float tolerance, const SkRect &clipBounds, VertexList *contours, bool *isLinear) const
Edge * makeConnectingEdge(Vertex *prev, Vertex *next, EdgeType, const Comparator &, int windingScale=1)
void mergeVertices(Vertex *src, Vertex *dst, VertexList *mesh, const Comparator &) const
const SkPath fPath
Vertex * makeSortedVertex(const SkPoint &, uint8_t alpha, VertexList *mesh, Vertex *reference, const Comparator &) const
skgpu::VertexWriter emitPoly(const Poly *, skgpu::VertexWriter data) const
bool mergeEdgesAbove(Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
void generateCubicPoints(const SkPoint &, const SkPoint &, const SkPoint &, const SkPoint &, SkScalar tolSqd, VertexList *contour, int pointsLeft) const
virtual ~GrTriangulator()
static void FindEnclosingEdges(const Vertex &v, const EdgeList &edges, Edge **left, Edge **right)
std::tuple< Poly *, bool > contoursToPolys(VertexList *contours, int contourCnt)
skgpu::VertexWriter emitTriangle(Vertex *prev, Vertex *curr, Vertex *next, int winding, skgpu::VertexWriter data) const
bool mergeCoincidentVertices(VertexList *mesh, const Comparator &) const
bool mergeEdgesBelow(Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
void sanitizeContours(VertexList *contours, int contourCnt) const
void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd, VertexList *contour) const
BoolFail intersectEdgePair(Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, const Comparator &)
BoolFail checkForIntersection(Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, VertexList *mesh, const Comparator &)
void appendPointToContour(const SkPoint &p, VertexList *contour) const
BoolFail splitEdge(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &)
void computeBisector(Edge *edge1, Edge *edge2, Vertex *) const
static constexpr int kArenaDefaultChunkSize
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120
Definition: SkPath.h:59
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
if(end==-1)
GAsyncResult * result
Definition: dart.idl:29
SkMesh mesh
Definition: SkRecords.h:345
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
dst
Definition: cp.py:12
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
const Scalar scale
Node(SkPoint a, SkPoint b, SkPoint c)
bool sweep_lt(const SkPoint &a, const SkPoint &b) const
Comparator(Direction direction)
void insert(Edge *edge, Edge *prev, Edge *next)
bool contains(Edge *edge) const
void insertBelow(Vertex *, const Comparator &)
bool isLeftOf(const Vertex &v) const
void insertAbove(Vertex *, const Comparator &)
bool isRightOf(const Vertex &v) const
Edge(Vertex *top, Vertex *bottom, int winding, EdgeType type)
double dist(const SkPoint &p) const
bool intersect(const Edge &other, SkPoint *p, uint8_t *alpha=nullptr) const
bool nearParallel(const Line &o) const
double dist(const SkPoint &p) const
bool intersect(const Line &other, SkPoint *point) const
Line(Vertex *p, Vertex *q)
Line operator*(double v) const
double magSq() const
Line(const SkPoint &p, const SkPoint &q)
Line(double a, double b, double c)
MonotonePoly(Edge *edge, Side side, int winding)
Poly(Vertex *v, int winding)
MonotonePoly * fTail
Vertex * lastVertex() const
MonotonePoly * fHead
Poly * addEdge(Edge *e, Side side, GrTriangulator *)
VertexList(Vertex *head, Vertex *tail)
void insert(Vertex *v, Vertex *prev, Vertex *next)
void append(const VertexList &list)
Vertex(const SkPoint &point, uint8_t alpha)
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63