Flutter Engine
The Flutter Engine
Classes | Public Types | Static Public Member Functions | Static Public Attributes | Protected Types | Protected Member Functions | Static Protected Member Functions | Protected Attributes | List of all members
GrTriangulator Class Reference

#include <GrTriangulator.h>

Inheritance diagram for GrTriangulator:
GrAATriangulator GrInnerFanTriangulator

Classes

class  BreadcrumbTriangleList
 
struct  Comparator
 
struct  Edge
 
struct  EdgeList
 
struct  Line
 
struct  MonotonePoly
 
struct  Poly
 
struct  Vertex
 
struct  VertexList
 

Public Types

enum  Side { kLeft_Side , kRight_Side }
 
enum class  EdgeType { kInner , kOuter , kConnector }
 

Static Public Member Functions

static int PathToTriangles (const SkPath &path, SkScalar tolerance, const SkRect &clipBounds, GrEagerVertexAllocator *vertexAllocator, bool *isLinear)
 

Static Public Attributes

static constexpr int kArenaDefaultChunkSize = 16 * 1024
 

Protected Types

enum class  SimplifyResult { kFailed , kAlreadySimple , kFoundSelfIntersection }
 
enum class  BoolFail { kFalse , kTrue , kFail }
 

Protected Member Functions

 GrTriangulator (const SkPath &path, SkArenaAlloc *alloc)
 
virtual ~GrTriangulator ()
 
void pathToContours (float tolerance, const SkRect &clipBounds, VertexList *contours, bool *isLinear) const
 
void contoursToMesh (VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
 
SimplifyResult simplify (VertexList *mesh, const Comparator &)
 
virtual std::tuple< Poly *, bool > tessellate (const VertexList &vertices, const Comparator &)
 
skgpu::VertexWriter polysToTriangles (Poly *polys, SkPathFillType overrideFillType, skgpu::VertexWriter data) const
 
skgpu::VertexWriter emitMonotonePoly (const MonotonePoly *, skgpu::VertexWriter data) const
 
skgpu::VertexWriter emitTriangle (Vertex *prev, Vertex *curr, Vertex *next, int winding, skgpu::VertexWriter data) const
 
skgpu::VertexWriter emitPoly (const Poly *, skgpu::VertexWriter data) const
 
PolymakePoly (Poly **head, Vertex *v, int winding) const
 
void appendPointToContour (const SkPoint &p, VertexList *contour) const
 
void appendQuadraticToContour (const SkPoint[3], SkScalar toleranceSqd, VertexList *contour) const
 
void generateCubicPoints (const SkPoint &, const SkPoint &, const SkPoint &, const SkPoint &, SkScalar tolSqd, VertexList *contour, int pointsLeft) const
 
bool applyFillType (int winding) const
 
MonotonePolyallocateMonotonePoly (Edge *edge, Side side, int winding)
 
EdgeallocateEdge (Vertex *top, Vertex *bottom, int winding, EdgeType type)
 
EdgemakeEdge (Vertex *prev, Vertex *next, EdgeType type, const Comparator &)
 
bool setTop (Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
 
bool setBottom (Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
 
bool mergeEdgesAbove (Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
 
bool mergeEdgesBelow (Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
 
EdgemakeConnectingEdge (Vertex *prev, Vertex *next, EdgeType, const Comparator &, int windingScale=1)
 
void mergeVertices (Vertex *src, Vertex *dst, VertexList *mesh, const Comparator &) const
 
bool mergeCollinearEdges (Edge *edge, EdgeList *activeEdges, Vertex **current, const Comparator &) const
 
BoolFail splitEdge (Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &)
 
BoolFail intersectEdgePair (Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, const Comparator &)
 
VertexmakeSortedVertex (const SkPoint &, uint8_t alpha, VertexList *mesh, Vertex *reference, const Comparator &) const
 
void computeBisector (Edge *edge1, Edge *edge2, Vertex *) const
 
BoolFail checkForIntersection (Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, VertexList *mesh, const Comparator &)
 
void sanitizeContours (VertexList *contours, int contourCnt) const
 
bool mergeCoincidentVertices (VertexList *mesh, const Comparator &) const
 
void buildEdges (VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
 
std::tuple< Poly *, bool > contoursToPolys (VertexList *contours, int contourCnt)
 
std::tuple< Poly *, bool > pathToPolys (float tolerance, const SkRect &clipBounds, bool *isLinear)
 
int polysToTriangles (Poly *, GrEagerVertexAllocator *) const
 

Static Protected Member Functions

static void SortedMerge (VertexList *front, VertexList *back, VertexList *result, const Comparator &)
 
static void SortMesh (VertexList *vertices, const Comparator &)
 
static void FindEnclosingEdges (const Vertex &v, const EdgeList &edges, Edge **left, Edge **right)
 
static int64_t CountPoints (Poly *polys, SkPathFillType overrideFillType)
 

Protected Attributes

const SkPath fPath
 
SkArenaAlloc *const fAlloc
 
int fNumMonotonePolys = 0
 
int fNumEdges = 0
 
bool fRoundVerticesToQuarterPixel = false
 
bool fEmitCoverage = false
 
bool fPreserveCollinearVertices = false
 
bool fCollectBreadcrumbTriangles = false
 
BreadcrumbTriangleList fBreadcrumbList
 

Detailed Description

Provides utility functions for converting paths to a collection of triangles.

Definition at line 35 of file GrTriangulator.h.

Member Enumeration Documentation

◆ BoolFail

enum class GrTriangulator::BoolFail
strongprotected
Enumerator
kFalse 
kTrue 
kFail 

Definition at line 94 of file GrTriangulator.h.

94 {
95 kFalse,
96 kTrue,
97 kFail
98 };

◆ EdgeType

enum class GrTriangulator::EdgeType
strong
Enumerator
kInner 
kOuter 
kConnector 

Definition at line 56 of file GrTriangulator.h.

56{ kInner, kOuter, kConnector };
@ kOuter
nothing inside, fuzzy outside
@ kInner
fuzzy inside, nothing outside

◆ Side

Enumerator
kLeft_Side 
kRight_Side 

Definition at line 55 of file GrTriangulator.h.

◆ SimplifyResult

enum class GrTriangulator::SimplifyResult
strongprotected
Enumerator
kFailed 
kAlreadySimple 
kFoundSelfIntersection 

Definition at line 88 of file GrTriangulator.h.

88 {
89 kFailed,
90 kAlreadySimple,
91 kFoundSelfIntersection
92 };

Constructor & Destructor Documentation

◆ GrTriangulator()

GrTriangulator::GrTriangulator ( const SkPath path,
SkArenaAlloc alloc 
)
inlineprotected

Definition at line 69 of file GrTriangulator.h.

69: fPath(path), fAlloc(alloc) {}
SkArenaAlloc *const fAlloc
const SkPath fPath
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

◆ ~GrTriangulator()

virtual GrTriangulator::~GrTriangulator ( )
inlineprotectedvirtual

Definition at line 70 of file GrTriangulator.h.

70{}

Member Function Documentation

◆ allocateEdge()

Edge * GrTriangulator::allocateEdge ( Vertex top,
Vertex bottom,
int  winding,
EdgeType  type 
)
protected

Definition at line 643 of file GrTriangulator.cpp.

643 {
644 ++fNumEdges;
645 return fAlloc->make<Edge>(top, bottom, winding, type);
646}
GLenum type
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))
Definition: SkArenaAlloc.h:120

◆ allocateMonotonePoly()

MonotonePoly * GrTriangulator::allocateMonotonePoly ( Edge edge,
Side  side,
int  winding 
)
protected

Definition at line 638 of file GrTriangulator.cpp.

638 {
640 return fAlloc->make<MonotonePoly>(edge, side, winding);
641}
static int side(double x)

◆ appendPointToContour()

void GrTriangulator::appendPointToContour ( const SkPoint p,
VertexList contour 
) const
protected

Definition at line 475 of file GrTriangulator.cpp.

475 {
476 Vertex* v = fAlloc->make<Vertex>(p, 255);
477#if TRIANGULATOR_LOGGING
478 static float gID = 0.0f;
479 v->fID = gID++;
480#endif
481 contour->append(v);
482}

◆ appendQuadraticToContour()

void GrTriangulator::appendQuadraticToContour ( const SkPoint  pts[3],
SkScalar  toleranceSqd,
VertexList contour 
) const
protected

Definition at line 495 of file GrTriangulator.cpp.

496 {
497 SkQuadCoeff quad(pts);
498 skvx::float2 aa = quad.fA * quad.fA;
499 SkScalar denom = 2.0f * (aa[0] + aa[1]);
500 skvx::float2 ab = quad.fA * quad.fB;
501 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
502 int nPoints = 1;
503 SkScalar u = 1.0f;
504 // Test possible subdivision values only at the point of maximum curvature.
505 // If it passes the flatness metric there, it'll pass everywhere.
506 while (nPoints < GrPathUtils::kMaxPointsPerCurve) {
507 u = 1.0f / nPoints;
508 if (quad_error_at(pts, t, u) < toleranceSqd) {
509 break;
510 }
511 nPoints++;
512 }
513 for (int j = 1; j <= nPoints; j++) {
514 this->appendPointToContour(to_point(quad.eval(j * u)), contour);
515 }
516}
static SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u)
void appendPointToContour(const SkPoint &p, VertexList *contour) const
static SkPoint to_point(SkIPoint p)
Definition: editor.cpp:75
float SkScalar
Definition: extension.cpp:12
static const int kMaxPointsPerCurve
Definition: GrPathUtils.h:35
Definition: ab.py:1
Definition: SkVx.h:83

◆ applyFillType()

bool GrTriangulator::applyFillType ( int  winding) const
protected

Definition at line 630 of file GrTriangulator.cpp.

630 {
631 return apply_fill_type(fPath.getFillType(), winding);
632}
static bool apply_fill_type(SkPathFillType fillType, int winding)
SkPathFillType getFillType() const
Definition: SkPath.h:230

◆ buildEdges()

void GrTriangulator::buildEdges ( VertexList contours,
int  contourCnt,
VertexList mesh,
const Comparator c 
)
protected

Definition at line 1303 of file GrTriangulator.cpp.

1304 {
1305 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1306 Vertex* prev = contour->fTail;
1307 for (Vertex* v = contour->fHead; v;) {
1308 Vertex* next = v->fNext;
1309 this->makeConnectingEdge(prev, v, EdgeType::kInner, c);
1310 mesh->append(v);
1311 prev = v;
1312 v = next;
1313 }
1314 }
1315}
static float next(float f)
static float prev(float f)
Edge * makeConnectingEdge(Vertex *prev, Vertex *next, EdgeType, const Comparator &, int windingScale=1)
SkMesh mesh
Definition: SkRecords.h:345

◆ checkForIntersection()

GrTriangulator::BoolFail GrTriangulator::checkForIntersection ( Edge left,
Edge right,
EdgeList activeEdges,
Vertex **  current,
VertexList mesh,
const Comparator c 
)
protected

Definition at line 1187 of file GrTriangulator.cpp.

1190 {
1191 if (!left || !right) {
1192 return BoolFail::kFalse;
1193 }
1194 SkPoint p;
1195 uint8_t alpha;
1196 // If we are going to call intersect, then there must be tops and bottoms.
1197 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
1198 return BoolFail::kFail;
1199 }
1200 if (left->intersect(*right, &p, &alpha) && p.isFinite()) {
1201 Vertex* v;
1202 TESS_LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
1203 Vertex* top = *current;
1204 // If the intersection point is above the current vertex, rewind to the vertex above the
1205 // intersection.
1206 while (top && c.sweep_lt(p, top->fPoint)) {
1207 top = top->fPrev;
1208 }
1209
1210 // Always clamp the intersection to lie between the vertices of each segment, since
1211 // in theory that's where the intersection is, but in reality, floating point error may
1212 // have computed an intersection beyond a vertex's component(s).
1213 p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c);
1214 p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c);
1215
1216 if (coincident(p, left->fTop->fPoint)) {
1217 v = left->fTop;
1218 } else if (coincident(p, left->fBottom->fPoint)) {
1219 v = left->fBottom;
1220 } else if (coincident(p, right->fTop->fPoint)) {
1221 v = right->fTop;
1222 } else if (coincident(p, right->fBottom->fPoint)) {
1223 v = right->fBottom;
1224 } else {
1225 v = this->makeSortedVertex(p, alpha, mesh, top, c);
1226 if (left->fTop->fPartner) {
1227 SkASSERT(fEmitCoverage); // Edge-AA only!
1228 v->fSynthetic = true;
1229 this->computeBisector(left, right, v);
1230 }
1231 }
1232 if (!rewind(activeEdges, current, top ? top : v, c)) {
1233 return BoolFail::kFail;
1234 }
1235 if (this->splitEdge(left, v, activeEdges, current, c) == BoolFail::kFail) {
1236 return BoolFail::kFail;
1237 }
1238 if (this->splitEdge(right, v, activeEdges, current, c) == BoolFail::kFail) {
1239 return BoolFail::kFail;
1240 }
1241 v->fAlpha = std::max(v->fAlpha, alpha);
1242 return BoolFail::kTrue;
1243 }
1244 return this->intersectEdgePair(left, right, activeEdges, current, c);
1245}
static SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, const Comparator &c)
static bool rewind(EdgeList *activeEdges, Vertex **current, Vertex *dst, const Comparator &c)
static bool coincident(const SkPoint &a, const SkPoint &b)
#define TESS_LOG(...)
#define SkASSERT(cond)
Definition: SkAssert.h:116
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
Vertex * makeSortedVertex(const SkPoint &, uint8_t alpha, VertexList *mesh, Vertex *reference, const Comparator &) const
BoolFail intersectEdgePair(Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, const Comparator &)
BoolFail splitEdge(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &)
void computeBisector(Edge *edge1, Edge *edge2, Vertex *) const
static float max(float r, float g, float b)
Definition: hsl.cpp:49
bool sweep_lt(const SkPoint &a, const SkPoint &b) const

◆ computeBisector()

void GrTriangulator::computeBisector ( Edge edge1,
Edge edge2,
Vertex v 
) const
protected

Definition at line 1167 of file GrTriangulator.cpp.

1167 {
1168 SkASSERT(fEmitCoverage); // Edge-AA only!
1169 Line line1 = edge1->fLine;
1170 Line line2 = edge2->fLine;
1171 line1.normalize();
1172 line2.normalize();
1173 double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB;
1174 if (cosAngle > 0.999) {
1175 return;
1176 }
1177 line1.fC += edge1->fWinding > 0 ? -1 : 1;
1178 line2.fC += edge2->fWinding > 0 ? -1 : 1;
1179 SkPoint p;
1180 if (line1.intersect(line2, &p)) {
1181 uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0;
1182 v->fPartner = fAlloc->make<Vertex>(p, alpha);
1183 TESS_LOG("computed bisector (%g,%g) alpha %d for vertex %g\n", p.fX, p.fY, alpha, v->fID);
1184 }
1185}
bool intersect(const Line &other, SkPoint *point) const

◆ contoursToMesh()

void GrTriangulator::contoursToMesh ( VertexList contours,
int  contourCnt,
VertexList mesh,
const Comparator c 
)
protected

Definition at line 1648 of file GrTriangulator.cpp.

1649 {
1650#if TRIANGULATOR_LOGGING
1651 for (int i = 0; i < contourCnt; ++i) {
1652 Vertex* v = contours[i].fHead;
1653 SkASSERT(v);
1654 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1655 for (v = v->fNext; v; v = v->fNext) {
1656 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1657 }
1658 }
1659#endif
1660 this->sanitizeContours(contours, contourCnt);
1661 this->buildEdges(contours, contourCnt, mesh, c);
1662}
void buildEdges(VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
void sanitizeContours(VertexList *contours, int contourCnt) const

◆ contoursToPolys()

std::tuple< Poly *, bool > GrTriangulator::contoursToPolys ( VertexList contours,
int  contourCnt 
)
protected

Definition at line 1683 of file GrTriangulator.cpp.

1683 {
1684 const SkRect& pathBounds = fPath.getBounds();
1685 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1688 this->contoursToMesh(contours, contourCnt, &mesh, c);
1689 TESS_LOG("\ninitial mesh:\n");
1690 DUMP_MESH(mesh);
1691 SortMesh(&mesh, c);
1692 TESS_LOG("\nsorted mesh:\n");
1693 DUMP_MESH(mesh);
1694 this->mergeCoincidentVertices(&mesh, c);
1695 TESS_LOG("\nsorted+merged mesh:\n");
1696 DUMP_MESH(mesh);
1697 auto result = this->simplify(&mesh, c);
1699 return { nullptr, false };
1700 }
1701 TESS_LOG("\nsimplified mesh:\n");
1702 DUMP_MESH(mesh);
1703 return this->tessellate(mesh, c);
1704}
#define DUMP_MESH(M)
void contoursToMesh(VertexList *contours, int contourCnt, VertexList *mesh, const Comparator &)
static void SortMesh(VertexList *vertices, const Comparator &)
SimplifyResult simplify(VertexList *mesh, const Comparator &)
virtual std::tuple< Poly *, bool > tessellate(const VertexList &vertices, const Comparator &)
bool mergeCoincidentVertices(VertexList *mesh, const Comparator &) const
const SkRect & getBounds() const
Definition: SkPath.cpp:430
GAsyncResult * result
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762

◆ CountPoints()

int64_t GrTriangulator::CountPoints ( Poly polys,
SkPathFillType  overrideFillType 
)
staticprotected

Definition at line 1768 of file GrTriangulator.cpp.

1768 {
1769 int64_t count = 0;
1770 for (Poly* poly = polys; poly; poly = poly->fNext) {
1771 if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
1772 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
1773 }
1774 }
1775 return count;
1776}
int count
Definition: FontMgrTest.cpp:50
#define TRIANGULATOR_WIREFRAME

◆ emitMonotonePoly()

skgpu::VertexWriter GrTriangulator::emitMonotonePoly ( const MonotonePoly monotonePoly,
skgpu::VertexWriter  data 
) const
protected

Definition at line 332 of file GrTriangulator.cpp.

333 {
334 SkASSERT(monotonePoly->fWinding != 0);
335 Edge* e = monotonePoly->fFirstEdge;
336 VertexList vertices;
337 vertices.append(e->fTop);
338 int count = 1;
339 while (e != nullptr) {
340 if (kRight_Side == monotonePoly->fSide) {
341 vertices.append(e->fBottom);
342 e = e->fRightPolyNext;
343 } else {
344 vertices.prepend(e->fBottom);
345 e = e->fLeftPolyNext;
346 }
347 count++;
348 }
349 Vertex* first = vertices.fHead;
350 Vertex* v = first->fNext;
351 while (v != vertices.fTail) {
352 SkASSERT(v && v->fPrev && v->fNext);
353 Vertex* prev = v->fPrev;
354 Vertex* curr = v;
355 Vertex* next = v->fNext;
356 if (count == 3) {
357 return this->emitTriangle(prev, curr, next, monotonePoly->fWinding, std::move(data));
358 }
359 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
360 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
361 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
362 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
363 if (ax * by - ay * bx >= 0.0) {
364 data = this->emitTriangle(prev, curr, next, monotonePoly->fWinding, std::move(data));
365 v->fPrev->fNext = v->fNext;
366 v->fNext->fPrev = v->fPrev;
367 count--;
368 if (v->fPrev == first) {
369 v = v->fNext;
370 } else {
371 v = v->fPrev;
372 }
373 } else {
374 v = v->fNext;
375 }
376 }
377 return data;
378}
skgpu::VertexWriter emitTriangle(Vertex *prev, Vertex *curr, Vertex *next, int winding, skgpu::VertexWriter data) const
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63

◆ emitPoly()

skgpu::VertexWriter GrTriangulator::emitPoly ( const Poly poly,
skgpu::VertexWriter  data 
) const
protected

Definition at line 453 of file GrTriangulator.cpp.

453 {
454 if (poly->fCount < 3) {
455 return data;
456 }
457 TESS_LOG("emit() %d, size %d\n", poly->fID, poly->fCount);
458 for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) {
459 data = this->emitMonotonePoly(m, std::move(data));
460 }
461 return data;
462}
skgpu::VertexWriter emitMonotonePoly(const MonotonePoly *, skgpu::VertexWriter data) const
MonotonePoly * fHead

◆ emitTriangle()

skgpu::VertexWriter GrTriangulator::emitTriangle ( Vertex prev,
Vertex curr,
Vertex next,
int  winding,
skgpu::VertexWriter  data 
) const
protected

Definition at line 380 of file GrTriangulator.cpp.

381 {
382 if (winding > 0) {
383 // Ensure our triangles always wind in the same direction as if the path had been
384 // triangulated as a simple fan (a la red book).
386 }
387 if (fCollectBreadcrumbTriangles && abs(winding) > 1 &&
389 // The first winding count will come from the actual triangle we emit. The remaining counts
390 // come from the breadcrumb triangle.
391 fBreadcrumbList.append(fAlloc, prev->fPoint, curr->fPoint, next->fPoint, abs(winding) - 1);
392 }
393 return emit_triangle(prev, curr, next, fEmitCoverage, std::move(data));
394}
static skgpu::VertexWriter emit_triangle(Vertex *v0, Vertex *v1, Vertex *v2, bool emitCoverage, skgpu::VertexWriter data)
void swap(sk_sp< T > &a, sk_sp< T > &b)
Definition: SkRefCnt.h:341
void append(SkArenaAlloc *alloc, SkPoint a, SkPoint b, SkPoint c, int winding)
bool fCollectBreadcrumbTriangles
BreadcrumbTriangleList fBreadcrumbList
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707

◆ FindEnclosingEdges()

void GrTriangulator::FindEnclosingEdges ( const Vertex v,
const EdgeList edges,
Edge **  left,
Edge **  right 
)
staticprotected

Definition at line 668 of file GrTriangulator.cpp.

670 {
671 if (v.fFirstEdgeAbove && v.fLastEdgeAbove) {
672 *left = v.fFirstEdgeAbove->fLeft;
673 *right = v.fLastEdgeAbove->fRight;
674 return;
675 }
676 Edge* next = nullptr;
677 Edge* prev;
678 for (prev = edges.fTail; prev != nullptr; prev = prev->fLeft) {
679 if (prev->isLeftOf(v)) {
680 break;
681 }
682 next = prev;
683 }
684 *left = prev;
685 *right = next;
686}

◆ generateCubicPoints()

void GrTriangulator::generateCubicPoints ( const SkPoint p0,
const SkPoint p1,
const SkPoint p2,
const SkPoint p3,
SkScalar  tolSqd,
VertexList contour,
int  pointsLeft 
) const
protected

Definition at line 518 of file GrTriangulator.cpp.

520 {
523 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || !SkIsFinite(d1, d2)) {
524 this->appendPointToContour(p3, contour);
525 return;
526 }
527 const SkPoint q[] = {
528 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
529 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
530 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
531 };
532 const SkPoint r[] = {
533 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
534 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
535 };
536 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
537 pointsLeft >>= 1;
538 this->generateCubicPoints(p0, q[0], r[0], s, tolSqd, contour, pointsLeft);
539 this->generateCubicPoints(s, r[1], q[2], p3, tolSqd, contour, pointsLeft);
540}
static bool SkIsFinite(T x, Pack... values)
#define SkScalarAve(a, b)
Definition: SkScalar.h:74
void generateCubicPoints(const SkPoint &, const SkPoint &, const SkPoint &, const SkPoint &, SkScalar tolSqd, VertexList *contour, int pointsLeft) const
static SkScalar DistanceToLineSegmentBetweenSqd(const SkPoint &pt, const SkPoint &a, const SkPoint &b)
Definition: SkPoint.cpp:126
struct MyStruct s
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165

◆ intersectEdgePair()

GrTriangulator::BoolFail GrTriangulator::intersectEdgePair ( Edge left,
Edge right,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
)
protected

Definition at line 1036 of file GrTriangulator.cpp.

1037 {
1038 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
1039 return BoolFail::kFalse;
1040 }
1041 if (left->fTop == right->fTop || left->fBottom == right->fBottom) {
1042 return BoolFail::kFalse;
1043 }
1044
1045 // Check if the lines intersect as determined by isLeftOf and isRightOf, since that is the
1046 // source of ground truth. It may suggest an intersection even if Edge::intersect() did not have
1047 // the precision to check it. In this case we are explicitly correcting the edge topology to
1048 // match the sided-ness checks.
1049 Edge* split = nullptr;
1050 Vertex* splitAt = nullptr;
1051 if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
1052 if (!left->isLeftOf(*right->fTop)) {
1053 split = left;
1054 splitAt = right->fTop;
1055 }
1056 } else {
1057 if (!right->isRightOf(*left->fTop)) {
1058 split = right;
1059 splitAt = left->fTop;
1060 }
1061 }
1062 if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
1063 if (!left->isLeftOf(*right->fBottom)) {
1064 split = left;
1065 splitAt = right->fBottom;
1066 }
1067 } else {
1068 if (!right->isRightOf(*left->fBottom)) {
1069 split = right;
1070 splitAt = left->fBottom;
1071 }
1072 }
1073
1074 if (!split) {
1075 return BoolFail::kFalse;
1076 }
1077
1078 // Rewind to the top of the edge that is "moving" since this topology correction can change the
1079 // geometry of the split edge.
1080 if (!rewind(activeEdges, current, split->fTop, c)) {
1081 return BoolFail::kFail;
1082 }
1083 return this->splitEdge(split, splitAt, activeEdges, current, c);
1084}

◆ makeConnectingEdge()

Edge * GrTriangulator::makeConnectingEdge ( Vertex prev,
Vertex next,
EdgeType  type,
const Comparator c,
int  windingScale = 1 
)
protected

Definition at line 1086 of file GrTriangulator.cpp.

1087 {
1088 if (!prev || !next || prev->fPoint == next->fPoint) {
1089 return nullptr;
1090 }
1091 Edge* edge = this->makeEdge(prev, next, type, c);
1092 edge->insertBelow(edge->fTop, c);
1093 edge->insertAbove(edge->fBottom, c);
1094 edge->fWinding *= windingScale;
1095 this->mergeCollinearEdges(edge, nullptr, nullptr, c);
1096 return edge;
1097}
bool mergeCollinearEdges(Edge *edge, EdgeList *activeEdges, Vertex **current, const Comparator &) const
Edge * makeEdge(Vertex *prev, Vertex *next, EdgeType type, const Comparator &)

◆ makeEdge()

Edge * GrTriangulator::makeEdge ( Vertex prev,
Vertex next,
EdgeType  type,
const Comparator c 
)
protected

Definition at line 648 of file GrTriangulator.cpp.

649 {
650 SkASSERT(prev->fPoint != next->fPoint);
651 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
652 Vertex* top = winding < 0 ? next : prev;
653 Vertex* bottom = winding < 0 ? prev : next;
654 return this->allocateEdge(top, bottom, winding, type);
655}
Edge * allocateEdge(Vertex *top, Vertex *bottom, int winding, EdgeType type)

◆ makePoly()

Poly * GrTriangulator::makePoly ( Poly **  head,
Vertex v,
int  winding 
) const
protected

Definition at line 468 of file GrTriangulator.cpp.

468 {
469 Poly* poly = fAlloc->make<Poly>(v, winding);
470 poly->fNext = *head;
471 *head = poly;
472 return poly;
473}

◆ makeSortedVertex()

Vertex * GrTriangulator::makeSortedVertex ( const SkPoint p,
uint8_t  alpha,
VertexList mesh,
Vertex reference,
const Comparator c 
) const
protected

Definition at line 1117 of file GrTriangulator.cpp.

1118 {
1119 Vertex* prevV = reference;
1120 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
1121 prevV = prevV->fPrev;
1122 }
1123 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
1124 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
1125 prevV = nextV;
1126 nextV = nextV->fNext;
1127 }
1128 Vertex* v;
1129 if (prevV && coincident(prevV->fPoint, p)) {
1130 v = prevV;
1131 } else if (nextV && coincident(nextV->fPoint, p)) {
1132 v = nextV;
1133 } else {
1134 v = fAlloc->make<Vertex>(p, alpha);
1135#if TRIANGULATOR_LOGGING
1136 if (!prevV) {
1137 v->fID = mesh->fHead->fID - 1.0f;
1138 } else if (!nextV) {
1139 v->fID = mesh->fTail->fID + 1.0f;
1140 } else {
1141 v->fID = (prevV->fID + nextV->fID) * 0.5f;
1142 }
1143#endif
1144 mesh->insert(v, prevV, nextV);
1145 }
1146 return v;
1147}

◆ mergeCoincidentVertices()

bool GrTriangulator::mergeCoincidentVertices ( VertexList mesh,
const Comparator c 
) const
protected

Definition at line 1282 of file GrTriangulator.cpp.

1282 {
1283 if (!mesh->fHead) {
1284 return false;
1285 }
1286 bool merged = false;
1287 for (Vertex* v = mesh->fHead->fNext; v;) {
1288 Vertex* next = v->fNext;
1289 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1290 v->fPoint = v->fPrev->fPoint;
1291 }
1292 if (coincident(v->fPrev->fPoint, v->fPoint)) {
1293 this->mergeVertices(v, v->fPrev, mesh, c);
1294 merged = true;
1295 }
1296 v = next;
1297 }
1298 return merged;
1299}
void mergeVertices(Vertex *src, Vertex *dst, VertexList *mesh, const Comparator &) const

◆ mergeCollinearEdges()

bool GrTriangulator::mergeCollinearEdges ( Edge edge,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
) const
protected

Definition at line 957 of file GrTriangulator.cpp.

958 {
959 for (;;) {
960 if (top_collinear(edge->fPrevEdgeAbove, edge)) {
961 if (!this->mergeEdgesAbove(edge->fPrevEdgeAbove, edge, activeEdges, current, c)) {
962 return false;
963 }
964 } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
965 if (!this->mergeEdgesAbove(edge->fNextEdgeAbove, edge, activeEdges, current, c)) {
966 return false;
967 }
968 } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
969 if (!this->mergeEdgesBelow(edge->fPrevEdgeBelow, edge, activeEdges, current, c)) {
970 return false;
971 }
972 } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
973 if (!this->mergeEdgesBelow(edge->fNextEdgeBelow, edge, activeEdges, current, c)) {
974 return false;
975 }
976 } else {
977 break;
978 }
979 }
980 SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge));
981 SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove));
982 SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge));
983 SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow));
984 return true;
985}
static bool bottom_collinear(Edge *left, Edge *right)
static bool top_collinear(Edge *left, Edge *right)
bool mergeEdgesAbove(Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const
bool mergeEdgesBelow(Edge *edge, Edge *other, EdgeList *activeEdges, Vertex **current, const Comparator &) const

◆ mergeEdgesAbove()

bool GrTriangulator::mergeEdgesAbove ( Edge edge,
Edge other,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
) const
protected

Definition at line 871 of file GrTriangulator.cpp.

872 {
873 if (!edge || !other) {
874 return false;
875 }
876 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
877 TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
878 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
879 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
880 if (!rewind(activeEdges, current, edge->fTop, c)) {
881 return false;
882 }
883 other->fWinding += edge->fWinding;
884 edge->disconnect();
885 edge->fTop = edge->fBottom = nullptr;
886 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
887 if (!rewind(activeEdges, current, edge->fTop, c)) {
888 return false;
889 }
890 other->fWinding += edge->fWinding;
891 if (!this->setBottom(edge, other->fTop, activeEdges, current, c)) {
892 return false;
893 }
894 } else {
895 if (!rewind(activeEdges, current, other->fTop, c)) {
896 return false;
897 }
898 edge->fWinding += other->fWinding;
899 if (!this->setBottom(other, edge->fTop, activeEdges, current, c)) {
900 return false;
901 }
902 }
903 return true;
904}
bool setBottom(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const
SkRegionPriv::RunType fX

◆ mergeEdgesBelow()

bool GrTriangulator::mergeEdgesBelow ( Edge edge,
Edge other,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
) const
protected

Definition at line 906 of file GrTriangulator.cpp.

907 {
908 if (!edge || !other) {
909 return false;
910 }
911 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
912 TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
913 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
914 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
915 if (!rewind(activeEdges, current, edge->fTop, c)) {
916 return false;
917 }
918 other->fWinding += edge->fWinding;
919 edge->disconnect();
920 edge->fTop = edge->fBottom = nullptr;
921 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
922 if (!rewind(activeEdges, current, other->fTop, c)) {
923 return false;
924 }
925 edge->fWinding += other->fWinding;
926 if (!this->setTop(other, edge->fBottom, activeEdges, current, c)) {
927 return false;
928 }
929 } else {
930 if (!rewind(activeEdges, current, edge->fTop, c)) {
931 return false;
932 }
933 other->fWinding += edge->fWinding;
934 if (!this->setTop(edge, other->fBottom, activeEdges, current, c)) {
935 return false;
936 }
937 }
938 return true;
939}
bool setTop(Edge *edge, Vertex *v, EdgeList *activeEdges, Vertex **current, const Comparator &) const

◆ mergeVertices()

void GrTriangulator::mergeVertices ( Vertex src,
Vertex dst,
VertexList mesh,
const Comparator c 
) const
protected

Definition at line 1099 of file GrTriangulator.cpp.

1100 {
1101 TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
1102 src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
1103 dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
1104 if (src->fPartner) {
1105 src->fPartner->fPartner = dst;
1106 }
1107 while (Edge* edge = src->fFirstEdgeAbove) {
1108 std::ignore = this->setBottom(edge, dst, nullptr, nullptr, c);
1109 }
1110 while (Edge* edge = src->fFirstEdgeBelow) {
1111 std::ignore = this->setTop(edge, dst, nullptr, nullptr, c);
1112 }
1113 mesh->remove(src);
1114 dst->fSynthetic = true;
1115}
dst
Definition: cp.py:12

◆ pathToContours()

void GrTriangulator::pathToContours ( float  tolerance,
const SkRect clipBounds,
VertexList contours,
bool *  isLinear 
) const
protected

Definition at line 544 of file GrTriangulator.cpp.

545 {
546 SkScalar toleranceSqd = tolerance * tolerance;
547 SkPoint pts[4];
548 *isLinear = true;
549 VertexList* contour = contours;
550 SkPath::Iter iter(fPath, false);
551 if (fPath.isInverseFillType()) {
552 SkPoint quad[4];
553 clipBounds.toQuad(quad);
554 for (int i = 3; i >= 0; i--) {
555 this->appendPointToContour(quad[i], contours);
556 }
557 contour++;
558 }
560 SkPath::Verb verb;
561 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
562 switch (verb) {
563 case SkPath::kConic_Verb: {
564 *isLinear = false;
565 if (toleranceSqd == 0) {
566 this->appendPointToContour(pts[2], contour);
567 break;
568 }
569 SkScalar weight = iter.conicWeight();
570 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
571 for (int i = 0; i < converter.countQuads(); ++i) {
572 this->appendQuadraticToContour(quadPts, toleranceSqd, contour);
573 quadPts += 2;
574 }
575 break;
576 }
578 if (contour->fHead) {
579 contour++;
580 }
581 this->appendPointToContour(pts[0], contour);
582 break;
583 case SkPath::kLine_Verb: {
584 this->appendPointToContour(pts[1], contour);
585 break;
586 }
587 case SkPath::kQuad_Verb: {
588 *isLinear = false;
589 if (toleranceSqd == 0) {
590 this->appendPointToContour(pts[2], contour);
591 break;
592 }
593 this->appendQuadraticToContour(pts, toleranceSqd, contour);
594 break;
595 }
596 case SkPath::kCubic_Verb: {
597 *isLinear = false;
598 if (toleranceSqd == 0) {
599 this->appendPointToContour(pts[3], contour);
600 break;
601 }
602 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
603 this->generateCubicPoints(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
604 pointsLeft);
605 break;
606 }
609 break;
610 }
611 }
612}
void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd, VertexList *contour) const
bool isInverseFillType() const
Definition: SkPath.h:244
@ kClose_Verb
Definition: SkPath.h:1471
@ kMove_Verb
Definition: SkPath.h:1466
@ kConic_Verb
Definition: SkPath.h:1469
@ kDone_Verb
Definition: SkPath.h:1472
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
uint32_t cubicPointCount(const SkPoint points[], SkScalar tol)
string converter
Definition: cacheimages.py:19
void toQuad(SkPoint quad[4]) const
Definition: SkRect.cpp:50

◆ pathToPolys()

std::tuple< Poly *, bool > GrTriangulator::pathToPolys ( float  tolerance,
const SkRect clipBounds,
bool *  isLinear 
)
protected

Definition at line 1752 of file GrTriangulator.cpp.

1752 {
1753 int contourCnt = get_contour_count(fPath, tolerance);
1754 if (contourCnt <= 0) {
1755 *isLinear = true;
1756 return { nullptr, true };
1757 }
1758
1760 contourCnt++;
1761 }
1762 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
1763
1764 this->pathToContours(tolerance, clipBounds, contours.get(), isLinear);
1765 return this->contoursToPolys(contours.get(), contourCnt);
1766}
static int get_contour_count(const SkPath &path, SkScalar tolerance)
static bool SkPathFillType_IsInverse(SkPathFillType ft)
Definition: SkPathTypes.h:26
void pathToContours(float tolerance, const SkRect &clipBounds, VertexList *contours, bool *isLinear) const
std::tuple< Poly *, bool > contoursToPolys(VertexList *contours, int contourCnt)

◆ PathToTriangles()

static int GrTriangulator::PathToTriangles ( const SkPath path,
SkScalar  tolerance,
const SkRect clipBounds,
GrEagerVertexAllocator vertexAllocator,
bool *  isLinear 
)
inlinestatic

Definition at line 39 of file GrTriangulator.h.

40 {
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 }
static constexpr int kArenaDefaultChunkSize

◆ polysToTriangles() [1/2]

int GrTriangulator::polysToTriangles ( Poly polys,
GrEagerVertexAllocator vertexAllocator 
) const
protected

Definition at line 1780 of file GrTriangulator.cpp.

1780 {
1781 int64_t count64 = CountPoints(polys, fPath.getFillType());
1782 if (0 == count64 || count64 > SK_MaxS32) {
1783 return 0;
1784 }
1785 int count = count64;
1786
1787 size_t vertexStride = sizeof(SkPoint);
1788 if (fEmitCoverage) {
1789 vertexStride += sizeof(float);
1790 }
1791 skgpu::VertexWriter verts = vertexAllocator->lockWriter(vertexStride, count);
1792 if (!verts) {
1793 SkDebugf("Could not allocate vertices\n");
1794 return 0;
1795 }
1796
1797 TESS_LOG("emitting %d verts\n", count);
1798
1800 verts = this->polysToTriangles(polys, fPath.getFillType(), std::move(verts));
1801
1802 int actualCount = static_cast<int>((verts.mark() - start) / vertexStride);
1803 SkASSERT(actualCount <= count);
1804 vertexAllocator->unlock(actualCount);
1805 return actualCount;
1806}
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr int32_t SK_MaxS32
Definition: SkMath.h:21
skgpu::VertexWriter lockWriter(size_t stride, int eagerCount)
virtual void unlock(int actualCount)=0
static int64_t CountPoints(Poly *polys, SkPathFillType overrideFillType)
skgpu::VertexWriter polysToTriangles(Poly *polys, SkPathFillType overrideFillType, skgpu::VertexWriter data) const
Mark mark(size_t offset=0) const
Definition: BufferWriter.h:58

◆ polysToTriangles() [2/2]

skgpu::VertexWriter GrTriangulator::polysToTriangles ( Poly polys,
SkPathFillType  overrideFillType,
skgpu::VertexWriter  data 
) const
protected

Definition at line 1707 of file GrTriangulator.cpp.

1709 {
1710 for (Poly* poly = polys; poly; poly = poly->fNext) {
1711 if (apply_fill_type(overrideFillType, poly)) {
1712 data = this->emitPoly(poly, std::move(data));
1713 }
1714 }
1715 return data;
1716}
skgpu::VertexWriter emitPoly(const Poly *, skgpu::VertexWriter data) const

◆ sanitizeContours()

void GrTriangulator::sanitizeContours ( VertexList contours,
int  contourCnt 
) const
protected

Definition at line 1247 of file GrTriangulator.cpp.

1247 {
1248 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1249 SkASSERT(contour->fHead);
1250 Vertex* prev = contour->fTail;
1251 prev->fPoint.fX = double_to_clamped_scalar((double) prev->fPoint.fX);
1252 prev->fPoint.fY = double_to_clamped_scalar((double) prev->fPoint.fY);
1254 round(&prev->fPoint);
1255 }
1256 for (Vertex* v = contour->fHead; v;) {
1257 v->fPoint.fX = double_to_clamped_scalar((double) v->fPoint.fX);
1258 v->fPoint.fY = double_to_clamped_scalar((double) v->fPoint.fY);
1260 round(&v->fPoint);
1261 }
1262 Vertex* next = v->fNext;
1263 Vertex* nextWrap = next ? next : contour->fHead;
1264 if (coincident(prev->fPoint, v->fPoint)) {
1265 TESS_LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
1266 contour->remove(v);
1267 } else if (!v->fPoint.isFinite()) {
1268 TESS_LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
1269 contour->remove(v);
1270 } else if (!fPreserveCollinearVertices &&
1271 Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) {
1272 TESS_LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
1273 contour->remove(v);
1274 } else {
1275 prev = v;
1276 }
1277 v = next;
1278 }
1279 }
1280}
GrTriangulator::Line Line
static void round(SkPoint *p)
static SkScalar double_to_clamped_scalar(double d)
bool fPreserveCollinearVertices
bool fRoundVerticesToQuarterPixel
double dist(const SkPoint &p) const

◆ setBottom()

bool GrTriangulator::setBottom ( Edge edge,
Vertex v,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
) const
protected

Definition at line 855 of file GrTriangulator.cpp.

856 {
857 remove_edge_above(edge);
859 fBreadcrumbList.append(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
860 edge->fWinding);
861 }
862 edge->fBottom = v;
863 edge->recompute();
864 edge->insertAbove(v, c);
865 if (!rewind_if_necessary(edge, activeEdges, current, c)) {
866 return false;
867 }
868 return this->mergeCollinearEdges(edge, activeEdges, current, c);
869}
static bool rewind_if_necessary(Edge *edge, EdgeList *activeEdges, Vertex **current, const Comparator &c)
static void remove_edge_above(Edge *edge)

◆ setTop()

bool GrTriangulator::setTop ( Edge edge,
Vertex v,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
) const
protected

Definition at line 839 of file GrTriangulator.cpp.

840 {
841 remove_edge_below(edge);
843 fBreadcrumbList.append(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
844 edge->fWinding);
845 }
846 edge->fTop = v;
847 edge->recompute();
848 edge->insertBelow(v, c);
849 if (!rewind_if_necessary(edge, activeEdges, current, c)) {
850 return false;
851 }
852 return this->mergeCollinearEdges(edge, activeEdges, current, c);
853}
static void remove_edge_below(Edge *edge)

◆ simplify()

GrTriangulator::SimplifyResult GrTriangulator::simplify ( VertexList mesh,
const Comparator c 
)
protected

Definition at line 1438 of file GrTriangulator.cpp.

1439 {
1440 TESS_LOG("simplifying complex polygons\n");
1441
1442 int initialNumEdges = fNumEdges;
1443 int numSelfIntersections = 0;
1444
1445 EdgeList activeEdges;
1447 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
1448 if (!v->isConnected()) {
1449 continue;
1450 }
1451
1452 // The max increase across all skps, svgs and gms with only the triangulating and SW path
1453 // renderers enabled and with the triangulator's maxVerbCount set to the Chrome value is
1454 // 17x.
1455 if (fNumEdges > 170*initialNumEdges) {
1457 }
1458
1459 // In pathological cases, a path can intersect itself millions of times. After 500,000
1460 // self-intersections are found, reject the path.
1461 if (numSelfIntersections > 500000) {
1463 }
1464
1465 Edge* leftEnclosingEdge;
1466 Edge* rightEnclosingEdge;
1467 bool restartChecks;
1468 do {
1469 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1470 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
1471 restartChecks = false;
1472 FindEnclosingEdges(*v, activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1473 v->fLeftEnclosingEdge = leftEnclosingEdge;
1474 v->fRightEnclosingEdge = rightEnclosingEdge;
1475 if (v->fFirstEdgeBelow) {
1476 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
1478 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c);
1479 if (l == BoolFail::kFail) {
1481 }
1482 if (l == BoolFail::kFalse) {
1484 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c);
1485 if (r == BoolFail::kFail) {
1487 }
1488 if (r == BoolFail::kFalse) {
1489 // Neither l and r are both false.
1490 continue;
1491 }
1492 }
1493
1494 // Either l or r are true.
1496 restartChecks = true;
1497 ++numSelfIntersections;
1498 break;
1499 } // for
1500 } else {
1501 BoolFail bf = this->checkForIntersection(
1502 leftEnclosingEdge, rightEnclosingEdge, &activeEdges, &v, mesh, c);
1503 if (bf == BoolFail::kFail) {
1505 }
1506 if (bf == BoolFail::kTrue) {
1508 restartChecks = true;
1509 ++numSelfIntersections;
1510 }
1511 }
1512 } while (restartChecks);
1513#ifdef SK_DEBUG
1514 validate_edge_list(&activeEdges, c);
1515#endif
1516 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1517 if (!activeEdges.remove(e)) {
1519 }
1520 }
1521 Edge* leftEdge = leftEnclosingEdge;
1522 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1523 activeEdges.insert(e, leftEdge);
1524 leftEdge = e;
1525 }
1526 }
1527 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
1528 return result;
1529}
static void FindEnclosingEdges(const Vertex &v, const EdgeList &edges, Edge **left, Edge **right)
BoolFail checkForIntersection(Edge *left, Edge *right, EdgeList *activeEdges, Vertex **current, VertexList *mesh, const Comparator &)
void insert(Edge *edge, Edge *prev, Edge *next)

◆ SortedMerge()

void GrTriangulator::SortedMerge ( VertexList front,
VertexList back,
VertexList result,
const Comparator c 
)
staticprotected

Definition at line 1336 of file GrTriangulator.cpp.

1337 {
1339 sorted_merge<sweep_lt_horiz>(front, back, result);
1340 } else {
1341 sorted_merge<sweep_lt_vert>(front, back, result);
1342 }
1343#if TRIANGULATOR_LOGGING
1344 float id = 0.0f;
1345 for (Vertex* v = result->fHead; v; v = v->fNext) {
1346 v->fID = id++;
1347 }
1348#endif
1349}

◆ SortMesh()

void GrTriangulator::SortMesh ( VertexList vertices,
const Comparator c 
)
staticprotected

Definition at line 1664 of file GrTriangulator.cpp.

1664 {
1665 if (!vertices || !vertices->fHead) {
1666 return;
1667 }
1668
1669 // Sort vertices in Y (secondarily in X).
1671 merge_sort<sweep_lt_horiz>(vertices);
1672 } else {
1673 merge_sort<sweep_lt_vert>(vertices);
1674 }
1675#if TRIANGULATOR_LOGGING
1676 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
1677 static float gID = 0.0f;
1678 v->fID = gID++;
1679 }
1680#endif
1681}

◆ splitEdge()

GrTriangulator::BoolFail GrTriangulator::splitEdge ( Edge edge,
Vertex v,
EdgeList activeEdges,
Vertex **  current,
const Comparator c 
)
protected

Definition at line 987 of file GrTriangulator.cpp.

988 {
989 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
990 return BoolFail::kFalse;
991 }
992 TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
993 edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY);
994 Vertex* top;
995 Vertex* bottom;
996 int winding = edge->fWinding;
997 // Theoretically, and ideally, the edge betwee p0 and p1 is being split by v, and v is "between"
998 // the segment end points according to c. This is equivalent to p0 < v < p1. Unfortunately, if
999 // v was clamped/rounded this relation doesn't always hold.
1000 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
1001 // Actually "v < p0 < p1": update 'edge' to be v->p1 and add v->p0. We flip the winding on
1002 // the new edge so that it winds as if it were p0->v.
1003 top = v;
1004 bottom = edge->fTop;
1005 winding *= -1;
1006 if (!this->setTop(edge, v, activeEdges, current, c)) {
1007 return BoolFail::kFail;
1008 }
1009 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
1010 // Actually "p0 < p1 < v": update 'edge' to be p0->v and add p1->v. We flip the winding on
1011 // the new edge so that it winds as if it were v->p1.
1012 top = edge->fBottom;
1013 bottom = v;
1014 winding *= -1;
1015 if (!this->setBottom(edge, v, activeEdges, current, c)) {
1016 return BoolFail::kFail;
1017 }
1018 } else {
1019 // The ideal case, "p0 < v < p1": update 'edge' to be p0->v and add v->p1. Original winding
1020 // is valid for both edges.
1021 top = v;
1022 bottom = edge->fBottom;
1023 if (!this->setBottom(edge, v, activeEdges, current, c)) {
1024 return BoolFail::kFail;
1025 }
1026 }
1027 Edge* newEdge = this->allocateEdge(top, bottom, winding, edge->fType);
1028 newEdge->insertBelow(top, c);
1029 newEdge->insertAbove(bottom, c);
1030 if (!this->mergeCollinearEdges(newEdge, activeEdges, current, c)) {
1031 return BoolFail::kFail;
1032 }
1033 return BoolFail::kTrue;
1034}

◆ tessellate()

std::tuple< Poly *, bool > GrTriangulator::tessellate ( const VertexList vertices,
const Comparator  
)
protectedvirtual

Definition at line 1533 of file GrTriangulator.cpp.

1533 {
1534 TESS_LOG("\ntessellating simple polygons\n");
1535 EdgeList activeEdges;
1536 Poly* polys = nullptr;
1537 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
1538 if (!v->isConnected()) {
1539 continue;
1540 }
1541#if TRIANGULATOR_LOGGING
1542 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
1543#endif
1544 Edge* leftEnclosingEdge;
1545 Edge* rightEnclosingEdge;
1546 FindEnclosingEdges(*v, activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1547 Poly* leftPoly;
1548 Poly* rightPoly;
1549 if (v->fFirstEdgeAbove) {
1550 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1551 rightPoly = v->fLastEdgeAbove->fRightPoly;
1552 } else {
1553 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1554 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1555 }
1556#if TRIANGULATOR_LOGGING
1557 TESS_LOG("edges above:\n");
1558 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1559 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1560 e->fTop->fID, e->fBottom->fID,
1561 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1562 e->fRightPoly ? e->fRightPoly->fID : -1);
1563 }
1564 TESS_LOG("edges below:\n");
1565 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1566 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1567 e->fTop->fID, e->fBottom->fID,
1568 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1569 e->fRightPoly ? e->fRightPoly->fID : -1);
1570 }
1571#endif
1572 if (v->fFirstEdgeAbove) {
1573 if (leftPoly) {
1574 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, kRight_Side, this);
1575 }
1576 if (rightPoly) {
1577 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, kLeft_Side, this);
1578 }
1579 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
1580 Edge* rightEdge = e->fNextEdgeAbove;
1581 activeEdges.remove(e);
1582 if (e->fRightPoly) {
1583 e->fRightPoly->addEdge(e, kLeft_Side, this);
1584 }
1585 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
1586 rightEdge->fLeftPoly->addEdge(e, kRight_Side, this);
1587 }
1588 }
1589 activeEdges.remove(v->fLastEdgeAbove);
1590 if (!v->fFirstEdgeBelow) {
1591 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1592 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1593 rightPoly->fPartner = leftPoly;
1594 leftPoly->fPartner = rightPoly;
1595 }
1596 }
1597 }
1598 if (v->fFirstEdgeBelow) {
1599 if (!v->fFirstEdgeAbove) {
1600 if (leftPoly && rightPoly) {
1601 if (leftPoly == rightPoly) {
1602 if (leftPoly->fTail && leftPoly->fTail->fSide == kLeft_Side) {
1603 leftPoly = this->makePoly(&polys, leftPoly->lastVertex(),
1604 leftPoly->fWinding);
1605 leftEnclosingEdge->fRightPoly = leftPoly;
1606 } else {
1607 rightPoly = this->makePoly(&polys, rightPoly->lastVertex(),
1608 rightPoly->fWinding);
1609 rightEnclosingEdge->fLeftPoly = rightPoly;
1610 }
1611 }
1612 Edge* join = this->allocateEdge(leftPoly->lastVertex(), v, 1, EdgeType::kInner);
1613 leftPoly = leftPoly->addEdge(join, kRight_Side, this);
1614 rightPoly = rightPoly->addEdge(join, kLeft_Side, this);
1615 }
1616 }
1617 Edge* leftEdge = v->fFirstEdgeBelow;
1618 leftEdge->fLeftPoly = leftPoly;
1619 activeEdges.insert(leftEdge, leftEnclosingEdge);
1620 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1621 rightEdge = rightEdge->fNextEdgeBelow) {
1622 activeEdges.insert(rightEdge, leftEdge);
1623 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1624 winding += leftEdge->fWinding;
1625 if (winding != 0) {
1626 Poly* poly = this->makePoly(&polys, v, winding);
1627 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1628 }
1629 leftEdge = rightEdge;
1630 }
1631 v->fLastEdgeBelow->fRightPoly = rightPoly;
1632 }
1633#if TRIANGULATOR_LOGGING
1634 TESS_LOG("\nactive edges:\n");
1635 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
1636 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1637 e->fTop->fID, e->fBottom->fID,
1638 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1639 e->fRightPoly ? e->fRightPoly->fID : -1);
1640 }
1641#endif
1642 }
1643 return { polys, true };
1644}
Poly * makePoly(Poly **head, Vertex *v, int winding) const
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
MonotonePoly * fTail
Vertex * lastVertex() const
Poly * addEdge(Edge *e, Side side, GrTriangulator *)

Member Data Documentation

◆ fAlloc

SkArenaAlloc* const GrTriangulator::fAlloc
protected

Definition at line 205 of file GrTriangulator.h.

◆ fBreadcrumbList

BreadcrumbTriangleList GrTriangulator::fBreadcrumbList
mutableprotected

Definition at line 280 of file GrTriangulator.h.

◆ fCollectBreadcrumbTriangles

bool GrTriangulator::fCollectBreadcrumbTriangles = false
protected

Definition at line 213 of file GrTriangulator.h.

◆ fEmitCoverage

bool GrTriangulator::fEmitCoverage = false
protected

Definition at line 211 of file GrTriangulator.h.

◆ fNumEdges

int GrTriangulator::fNumEdges = 0
protected

Definition at line 207 of file GrTriangulator.h.

◆ fNumMonotonePolys

int GrTriangulator::fNumMonotonePolys = 0
protected

Definition at line 206 of file GrTriangulator.h.

◆ fPath

const SkPath GrTriangulator::fPath
protected

Definition at line 204 of file GrTriangulator.h.

◆ fPreserveCollinearVertices

bool GrTriangulator::fPreserveCollinearVertices = false
protected

Definition at line 212 of file GrTriangulator.h.

◆ fRoundVerticesToQuarterPixel

bool GrTriangulator::fRoundVerticesToQuarterPixel = false
protected

Definition at line 210 of file GrTriangulator.h.

◆ kArenaDefaultChunkSize

constexpr int GrTriangulator::kArenaDefaultChunkSize = 16 * 1024
staticconstexpr

Definition at line 37 of file GrTriangulator.h.


The documentation for this class was generated from the following files: