Flutter Engine
The Flutter Engine
Classes | Functions | Variables
SkPathOpsAsWinding.cpp File Reference
#include "include/core/SkPath.h"
#include "include/core/SkPathBuilder.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkPoint.h"
#include "include/core/SkRect.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/pathops/SkPathOps.h"
#include "include/private/base/SkMacros.h"
#include "src/core/SkPathPriv.h"
#include "src/pathops/SkPathOpsConic.h"
#include "src/pathops/SkPathOpsCubic.h"
#include "src/pathops/SkPathOpsCurve.h"
#include "src/pathops/SkPathOpsPoint.h"
#include "src/pathops/SkPathOpsQuad.h"
#include "src/pathops/SkPathOpsTypes.h"
#include <algorithm>
#include <vector>

Go to the source code of this file.

Classes

struct  Contour
 
class  OpAsWinding
 

Functions

static Contour::Direction to_direction (SkScalar dy)
 
static int contains_edge (SkPoint pts[4], SkPath::Verb verb, SkScalar weight, const SkPoint &edge)
 
static SkScalar conic_weight (const SkPath::Iter &iter, SkPath::Verb verb)
 
static SkPoint left_edge (SkPoint pts[4], SkPath::Verb verb, SkScalar weight)
 
static bool set_result_path (SkPath *result, const SkPath &path, SkPathFillType fillType)
 
bool AsWinding (const SkPath &path, SkPath *result)
 

Variables

static const int kPtCount [] = { 1, 1, 2, 2, 3, 0 }
 
static const int kPtIndex [] = { 0, 1, 1, 1, 1, 0 }
 

Function Documentation

◆ AsWinding()

bool AsWinding ( const SkPath path,
SkPath result 
)

Set the result with fill type winding to area equivalent to path. Returns true if successful. Does not detect if path contains contours which contain self-crossings or cross other contours; in these cases, may return true even though result does not fill same area as path.

Returns true if operation was able to produce a result; otherwise, result is unmodified. The result may be the input.

Parameters
pathThe path typically with fill type set to even odd.
resultThe equivalent path with fill type set to winding.
Returns
True if winding path was set.

Definition at line 408 of file SkPathOpsAsWinding.cpp.

408 {
409 if (!path.isFinite()) {
410 return false;
411 }
412 SkPathFillType fillType = path.getFillType();
413 if (fillType == SkPathFillType::kWinding
414 || fillType == SkPathFillType::kInverseWinding ) {
415 return set_result_path(result, path, fillType);
416 }
417 fillType = path.isInverseFillType() ? SkPathFillType::kInverseWinding :
419 if (path.isEmpty() || path.isConvex()) {
420 return set_result_path(result, path, fillType);
421 }
422 // count contours
423 vector<Contour> contours; // one per contour
424 OpAsWinding winder(path);
425 winder.contourBounds(&contours);
426 if (contours.size() <= 1) {
427 return set_result_path(result, path, fillType);
428 }
429 // create contour bounding box tree
430 Contour sorted(SkRect(), 0, 0);
431 for (auto& contour : contours) {
432 winder.inParent(contour, sorted);
433 }
434 // if sorted has no grandchildren, no child has to fix its children's winding
435 if (std::all_of(sorted.fChildren.begin(), sorted.fChildren.end(),
436 [](const Contour* contour) -> bool { return contour->fChildren.empty(); } )) {
437 return set_result_path(result, path, fillType);
438 }
439 // starting with outermost and moving inward, see if one path contains another
440 for (auto contour : sorted.fChildren) {
441 winder.nextEdge(*contour, OpAsWinding::Edge::kInitial);
442 contour->fDirection = winder.getDirection(*contour);
443 if (!winder.checkContainerChildren(nullptr, contour)) {
444 return false;
445 }
446 }
447 // starting with outermost and moving inward, mark paths to reverse
448 bool reversed = false;
449 for (auto contour : sorted.fChildren) {
450 reversed |= winder.markReverse(nullptr, contour);
451 }
452 if (!reversed) {
453 return set_result_path(result, path, fillType);
454 }
455 *result = winder.reverseMarkedContours(contours, fillType);
456 return true;
457}
static bool set_result_path(SkPath *result, const SkPath &path, SkPathFillType fillType)
SkPathFillType
Definition: SkPathTypes.h:11
GAsyncResult * result
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

◆ conic_weight()

static SkScalar conic_weight ( const SkPath::Iter iter,
SkPath::Verb  verb 
)
static

Definition at line 113 of file SkPathOpsAsWinding.cpp.

113 {
114 return SkPath::kConic_Verb == verb ? iter.conicWeight() : 1;
115}
SkScalar conicWeight() const
Definition: SkPath.h:1535
@ kConic_Verb
Definition: SkPath.h:1469

◆ contains_edge()

static int contains_edge ( SkPoint  pts[4],
SkPath::Verb  verb,
SkScalar  weight,
const SkPoint edge 
)
static

Definition at line 60 of file SkPathOpsAsWinding.cpp.

60 {
62 bounds.setBounds(pts, kPtCount[verb] + 1);
63 if (bounds.fTop > edge.fY) {
64 return 0;
65 }
66 if (bounds.fBottom <= edge.fY) { // check to see if y is at line end to avoid double counting
67 return 0;
68 }
69 if (bounds.fLeft >= edge.fX) {
70 return 0;
71 }
72 int winding = 0;
73 double tVals[3];
74 Contour::Direction directions[3];
75 // must intersect horz ray with curve in case it intersects more than once
76 int count = (*CurveIntercept[verb * 2])(pts, weight, edge.fY, tVals);
77 SkASSERT(between(0, count, 3));
78 // remove results to the right of edge
79 for (int index = 0; index < count; ) {
80 SkScalar intersectX = (*CurvePointAtT[verb])(pts, weight, tVals[index]).fX;
81 if (intersectX < edge.fX) {
82 ++index;
83 continue;
84 }
85 if (intersectX > edge.fX) {
86 tVals[index] = tVals[--count];
87 continue;
88 }
89 // if intersect x equals edge x, we need to determine if pts is to the left or right of edge
90 if (pts[0].fX < edge.fX && pts[kPtCount[verb]].fX < edge.fX) {
91 ++index;
92 continue;
93 }
94 // TODO : other cases need discriminating. need op angle code to figure it out
95 // example: edge ends 45 degree diagonal going up. If pts is to the left of edge, keep.
96 // if pts is to the right of edge, discard. With code as is, can't distiguish the two cases.
97 tVals[index] = tVals[--count];
98 }
99 // use first derivative to determine if intersection is contributing +1 or -1 to winding
100 for (int index = 0; index < count; ++index) {
101 directions[index] = to_direction((*CurveSlopeAtT[verb])(pts, weight, tVals[index]).fY);
102 }
103 for (int index = 0; index < count; ++index) {
104 // skip intersections that end at edge and go up
105 if (zero_or_one(tVals[index]) && Contour::Direction::kCCW != directions[index]) {
106 continue;
107 }
108 winding += (int) directions[index];
109 }
110 return winding; // note winding indicates containership, not contour direction
111}
int count
Definition: FontMgrTest.cpp:50
#define SkASSERT(cond)
Definition: SkAssert.h:116
static Contour::Direction to_direction(SkScalar dy)
static const int kPtCount[]
static int(*const CurveIntercept[])(const SkPoint[], SkScalar, SkScalar, double *)
static SkPoint(*const CurvePointAtT[])(const SkPoint[], SkScalar, double)
static SkVector(*const CurveSlopeAtT[])(const SkPoint[], SkScalar, double)
bool between(double a, double b, double c)
bool zero_or_one(double x)
float SkScalar
Definition: extension.cpp:12
Optional< SkRect > bounds
Definition: SkRecords.h:189
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165

◆ left_edge()

static SkPoint left_edge ( SkPoint  pts[4],
SkPath::Verb  verb,
SkScalar  weight 
)
static

Definition at line 117 of file SkPathOpsAsWinding.cpp.

117 {
121 int roots = 0;
122 if (SkPath::kLine_Verb == verb) {
123 result = pts[0].fX < pts[1].fX ? pts[0] : pts[1];
124 } else if (SkPath::kQuad_Verb == verb) {
125 SkDQuad quad;
126 quad.set(pts);
127 if (!quad.monotonicInX()) {
128 roots = SkDQuad::FindExtrema(&quad[0].fX, &t);
129 }
130 if (roots) {
131 result = quad.ptAtT(t).asSkPoint();
132 } else {
133 result = pts[0].fX < pts[2].fX ? pts[0] : pts[2];
134 }
135 } else if (SkPath::kConic_Verb == verb) {
137 conic.set(pts, weight);
138 if (!conic.monotonicInX()) {
139 roots = SkDConic::FindExtrema(&conic[0].fX, weight, &t);
140 }
141 if (roots) {
142 result = conic.ptAtT(t).asSkPoint();
143 } else {
144 result = pts[0].fX < pts[2].fX ? pts[0] : pts[2];
145 }
146 } else {
149 cubic.set(pts);
150 if (!cubic.monotonicInX()) {
151 double tValues[2];
152 roots = SkDCubic::FindExtrema(&cubic[0].fX, tValues);
153 SkASSERT(roots <= 2);
154 for (int index = 0; index < roots; ++index) {
155 SkPoint temp = cubic.ptAtT(tValues[index]).asSkPoint();
156 if (0 == index || result.fX > temp.fX) {
157 result = temp;
158 }
159 }
160 }
161 if (roots) {
162 result = cubic.ptAtT(t).asSkPoint();
163 } else {
164 result = pts[0].fX < pts[3].fX ? pts[0] : pts[3];
165 }
166 }
167 return result;
168}
#define SK_INIT_TO_AVOID_WARNING
Definition: SkMacros.h:58
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:287
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:195
static int FindExtrema(const double src[], SkScalar weight, double tValue[1])
static int FindExtrema(const double src[], double tValue[2])
SkPoint asSkPoint() const
const SkDQuad & set(const SkPoint pts[kPointCount] SkDEBUGPARAMS(SkOpGlobalState *state=nullptr))
Definition: SkPathOpsQuad.h:65
bool monotonicInX() const
static int FindExtrema(const double src[], double tValue[1])
SkDPoint ptAtT(double t) const

◆ set_result_path()

static bool set_result_path ( SkPath result,
const SkPath path,
SkPathFillType  fillType 
)
static

Definition at line 402 of file SkPathOpsAsWinding.cpp.

402 {
403 *result = path;
404 result->setFillType(fillType);
405 return true;
406}

◆ to_direction()

static Contour::Direction to_direction ( SkScalar  dy)
static

Variable Documentation

◆ kPtCount

const int kPtCount[] = { 1, 1, 2, 2, 3, 0 }
static

Definition at line 52 of file SkPathOpsAsWinding.cpp.

◆ kPtIndex

const int kPtIndex[] = { 0, 1, 1, 1, 1, 0 }
static

Definition at line 53 of file SkPathOpsAsWinding.cpp.