Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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.

◆ EdgeType

enum class GrTriangulator::EdgeType
strong
Enumerator
kInner 
kOuter 
kConnector 

Definition at line 56 of file GrTriangulator.h.

◆ 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.

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

◆ ~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}
auto make(Ctor &&ctor) -> decltype(ctor(nullptr))

◆ 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

◆ 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}
#define TESS_LOG(...)
static bool rewind(EdgeList *activeEdges, Vertex **current, Vertex *dst, const Comparator &c)
static bool coincident(const SkPoint &a, const SkPoint &b)
#define SkASSERT(cond)
Definition SkAssert.h:116
static unsigned clamp(SkFixed fx, int max)
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
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 1638 of file GrTriangulator.cpp.

1639 {
1640#if TRIANGULATOR_LOGGING
1641 for (int i = 0; i < contourCnt; ++i) {
1642 Vertex* v = contours[i].fHead;
1643 SkASSERT(v);
1644 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1645 for (v = v->fNext; v; v = v->fNext) {
1646 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
1647 }
1648 }
1649#endif
1650 this->sanitizeContours(contours, contourCnt);
1651 this->buildEdges(contours, contourCnt, mesh, c);
1652}
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 1673 of file GrTriangulator.cpp.

1673 {
1674 const SkRect& pathBounds = fPath.getBounds();
1675 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1676 : Comparator::Direction::kVertical);
1678 this->contoursToMesh(contours, contourCnt, &mesh, c);
1679 TESS_LOG("\ninitial mesh:\n");
1680 DUMP_MESH(mesh);
1681 SortMesh(&mesh, c);
1682 TESS_LOG("\nsorted mesh:\n");
1683 DUMP_MESH(mesh);
1684 this->mergeCoincidentVertices(&mesh, c);
1685 TESS_LOG("\nsorted+merged mesh:\n");
1686 DUMP_MESH(mesh);
1687 auto result = this->simplify(&mesh, c);
1689 return { nullptr, false };
1690 }
1691 TESS_LOG("\nsimplified mesh:\n");
1692 DUMP_MESH(mesh);
1693 return this->tessellate(mesh, c);
1694}
#define DUMP_MESH(MESH)
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:420
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 1758 of file GrTriangulator.cpp.

1758 {
1759 int64_t count = 0;
1760 for (Poly* poly = polys; poly; poly = poly->fNext) {
1761 if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
1762 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
1763 }
1764 }
1765 return count;
1766}
int count
#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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41

◆ 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

◆ 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).
385 std::swap(prev, next);
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 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
float fY
y-axis value

◆ 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:1463
@ kMove_Verb
Definition SkPath.h:1458
@ kConic_Verb
Definition SkPath.h:1461
@ kDone_Verb
Definition SkPath.h:1464
@ kCubic_Verb
Definition SkPath.h:1462
@ kQuad_Verb
Definition SkPath.h:1460
@ kLine_Verb
Definition SkPath.h:1459
uint32_t cubicPointCount(const SkPoint points[], SkScalar tol)
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 1742 of file GrTriangulator.cpp.

1742 {
1743 int contourCnt = get_contour_count(fPath, tolerance);
1744 if (contourCnt <= 0) {
1745 *isLinear = true;
1746 return { nullptr, true };
1747 }
1748
1750 contourCnt++;
1751 }
1752 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
1753
1754 this->pathToContours(tolerance, clipBounds, contours.get(), isLinear);
1755 return this->contoursToPolys(contours.get(), contourCnt);
1756}
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
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

◆ polysToTriangles() [1/2]

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

Definition at line 1770 of file GrTriangulator.cpp.

1770 {
1771 int64_t count64 = CountPoints(polys, fPath.getFillType());
1772 if (0 == count64 || count64 > SK_MaxS32) {
1773 return 0;
1774 }
1775 int count = count64;
1776
1777 size_t vertexStride = sizeof(SkPoint);
1778 if (fEmitCoverage) {
1779 vertexStride += sizeof(float);
1780 }
1781 skgpu::VertexWriter verts = vertexAllocator->lockWriter(vertexStride, count);
1782 if (!verts) {
1783 SkDebugf("Could not allocate vertices\n");
1784 return 0;
1785 }
1786
1787 TESS_LOG("emitting %d verts\n", count);
1788
1790 verts = this->polysToTriangles(polys, fPath.getFillType(), std::move(verts));
1791
1792 int actualCount = static_cast<int>((verts.mark() - start) / vertexStride);
1793 SkASSERT(actualCount <= count);
1794 vertexAllocator->unlock(actualCount);
1795 return actualCount;
1796}
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

◆ polysToTriangles() [2/2]

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

Definition at line 1697 of file GrTriangulator.cpp.

1699 {
1700 for (Poly* poly = polys; poly; poly = poly->fNext) {
1701 if (apply_fill_type(overrideFillType, poly)) {
1702 data = this->emitPoly(poly, std::move(data));
1703 }
1704 }
1705 return data;
1706}
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}
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
1444 EdgeList activeEdges;
1446 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
1447 if (!v->isConnected()) {
1448 continue;
1449 }
1450
1451 // The max increase across all skps, svgs and gms with only the triangulating and SW path
1452 // renderers enabled and with the triangulator's maxVerbCount set to the Chrome value is
1453 // 17x.
1454 if (fNumEdges > 170*initialNumEdges) {
1456 }
1457
1458 Edge* leftEnclosingEdge;
1459 Edge* rightEnclosingEdge;
1460 bool restartChecks;
1461 do {
1462 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1463 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
1464 restartChecks = false;
1465 FindEnclosingEdges(*v, activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
1466 v->fLeftEnclosingEdge = leftEnclosingEdge;
1467 v->fRightEnclosingEdge = rightEnclosingEdge;
1468 if (v->fFirstEdgeBelow) {
1469 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
1471 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c);
1472 if (l == BoolFail::kFail) {
1474 } else if (l == BoolFail::kFalse) {
1476 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c);
1477 if (r == BoolFail::kFail) {
1479 } else if (r == BoolFail::kFalse) {
1480 // Neither l and r are both false.
1481 continue;
1482 }
1483 }
1484
1485 // Either l or r are true.
1487 restartChecks = true;
1488 break;
1489 } // for
1490 } else {
1491 BoolFail bf = this->checkForIntersection(
1492 leftEnclosingEdge, rightEnclosingEdge, &activeEdges, &v, mesh, c);
1493 if (bf == BoolFail::kFail) {
1495 }
1496 if (bf == BoolFail::kTrue) {
1498 restartChecks = true;
1499 }
1500
1501 }
1502 } while (restartChecks);
1503#ifdef SK_DEBUG
1504 validate_edge_list(&activeEdges, c);
1505#endif
1506 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
1507 if (!activeEdges.remove(e)) {
1509 }
1510 }
1511 Edge* leftEdge = leftEnclosingEdge;
1512 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
1513 activeEdges.insert(e, leftEdge);
1514 leftEdge = e;
1515 }
1516 }
1517 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
1518 return result;
1519}
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 1654 of file GrTriangulator.cpp.

1654 {
1655 if (!vertices || !vertices->fHead) {
1656 return;
1657 }
1658
1659 // Sort vertices in Y (secondarily in X).
1661 merge_sort<sweep_lt_horiz>(vertices);
1662 } else {
1663 merge_sort<sweep_lt_vert>(vertices);
1664 }
1665#if TRIANGULATOR_LOGGING
1666 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
1667 static float gID = 0.0f;
1668 v->fID = gID++;
1669 }
1670#endif
1671}

◆ 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

Reimplemented in GrAATriangulator.

Definition at line 1523 of file GrTriangulator.cpp.

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