47 "Please keep an eye on SkPath packing.");
50 return (
A * t +
B) * t +
C;
54 return ((
A * t +
B) * t +
C) * t +
D;
65 dst->fLeft = std::min(dst->fLeft, src.fLeft);
66 dst->fTop = std::min(dst->fTop, src.fTop);
67 dst->fRight = std::max(dst->fRight, src.fRight);
68 dst->fBottom = std::max(dst->fBottom, src.fBottom);
82 fPath->setFirstDirection(fSaved);
109 fHasValidBounds = path->hasComputedBounds() && path->isFinite();
110 fEmpty = path->isEmpty();
111 if (fHasValidBounds && !fEmpty) {
120 if ((fEmpty || fHasValidBounds) && fRect.
isFinite()) {
121 fPath->setBounds(fRect);
128 bool fHasValidBounds;
152#define INITIAL_LASTMOVETOINDEX_VALUE ~0
162 : fPathRef(
std::move(pr))
164 , fConvexity((uint8_t)ct)
165 , fFirstDirection((uint8_t)firstDirection)
166 , fFillType((unsigned)ft)
167 , fIsVolatile(isVolatile)
170void SkPath::resetFields() {
179 : fPathRef(
SkRef(that.fPathRef.get())) {
180 this->copyFields(that);
193 this->copyFields(that);
199void SkPath::copyFields(
const SkPath& that) {
201 fLastMoveToIndex = that.fLastMoveToIndex;
202 fFillType = that.fFillType;
203 fIsVolatile = that.fIsVolatile;
206 this->setConvexity(that.getConvexityOrUnknown());
207 this->setFirstDirection(that.getFirstDirection());
214 (
a.fFillType ==
b.fFillType && *
a.fPathRef == *
b.fPathRef);
219 fPathRef.
swap(that.fPathRef);
220 std::swap(fLastMoveToIndex, that.fLastMoveToIndex);
222 const auto ft = fFillType;
223 fFillType = that.fFillType;
226 const auto iv = fIsVolatile;
227 fIsVolatile = that.fIsVolatile;
228 that.fIsVolatile = iv;
232 this->setConvexity(that.getConvexityOrUnknown());
233 that.setConvexity(c);
236 this->setFirstDirection(that.getFirstDirection());
237 that.setFirstDirection(fd);
243 return fPathRef->fPoints.
size() ==
compare.fPathRef->fPoints.size() &&
244 fPathRef->fVerbs ==
compare.fPathRef->fVerbs &&
245 fPathRef->fConicWeights ==
compare.fPathRef->fConicWeights;
250 if (pointCount != ending.fPathRef->
countPoints()) {
259 fPathRef->
interpolate(*ending.fPathRef, weight, out->fPathRef.get());
282 if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) {
302 int segmentCount = 0;
317 firstPt = prevPt = pts[0];
324 int nextPt = pointCount;
329 orig.
set(pts, *weight);
345 prevPt = pts[nextPt];
357 return fPathRef->
genID(fFillType);
382 if (0 == verbCount) {
391 if (2 == verbCount) {
429 return this->isValidImpl() && fPathRef->
isValid();
432bool SkPath::hasComputedBounds()
const {
437void SkPath::setBounds(
const SkRect& rect) {
447void SkPath::validate()
const {
451void SkPath::validateRef()
const {
453 fPathRef->validate();
503 return ((0 != dx) << 0) | ((dx > 0 || dy > 0) << 1);
522 return fPathRef->
isArc(arc);
540 if ((
unsigned)index < (
unsigned)fPathRef->
countPoints()) {
541 return fPathRef->
atPoint(index);
563 size_t size =
sizeof (
SkPath);
564 if (fPathRef !=
nullptr) {
590 if (
count <= index) {
594 ed.atPoint(index)->set(
x,
y);
612 fConvexity.store((uint8_t)c, std::memory_order_relaxed);
617 fConvexity.store((uint8_t)c, std::memory_order_relaxed);
620 fFirstDirection.store((uint8_t)
d, std::memory_order_relaxed);
626bool SkPath::isConvexityAccurate()
const {
629 auto conv = this->computeConvexity();
630 if (conv != convexity) {
643 convexity = this->computeConvexity();
652SkPath& SkPath::dirtyAfterEdit() {
670 if (extraPtCount > 0) {
673 SkPathRef::Editor(&fPathRef, extraVerbCount == 0 ? extraPtCount : extraVerbCount, extraPtCount, extraConicCount);
688 return this->dirtyAfterEdit();
695 if (fLastMoveToIndex >= 0) {
698 pt = fPathRef->
atPoint(~fLastMoveToIndex);
704void SkPath::injectMoveToIfNeeded() {
705 if (fLastMoveToIndex < 0) {
721 this->injectMoveToIfNeeded();
726 return this->dirtyAfterEdit();
730 this->injectMoveToIfNeeded();
739 this->injectMoveToIfNeeded();
746 return this->dirtyAfterEdit();
750 this->injectMoveToIfNeeded();
753 return this->
quadTo(pt.
fX + x1, pt.
fY + y1, pt.
fX + x2, pt.
fY + y2);
765 this->
quadTo(x1, y1, x2, y2);
769 this->injectMoveToIfNeeded();
776 (void)this->dirtyAfterEdit();
783 this->injectMoveToIfNeeded();
786 return this->
conicTo(pt.
fX + dx1, pt.
fY + dy1, pt.
fX + dx2, pt.
fY + dy2,
w);
793 this->injectMoveToIfNeeded();
801 return this->dirtyAfterEdit();
806 this->injectMoveToIfNeeded();
810 pt.
fX + x3, pt.
fY + y3);
839 if (fLastMoveToIndex >= 0) {
840 fLastMoveToIndex = ~fLastMoveToIndex;
843 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 *
sizeof(fLastMoveToIndex) - 1);
863 const int kVerbs = 5;
874 (void)this->dirtyAfterEdit();
899 fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 *
sizeof(fLastMoveToIndex) - 1);
902 (void)this->dirtyAfterEdit();
909 if (0 == sweepAngle && (0 == startAngle ||
SkIntToScalar(360) == startAngle)) {
915 }
else if (0 == oval.
width() && 0 == oval.
height()) {
948 if (*startV == *stopV) {
958 }
while (*startV == *stopV);
978 matrix.mapXY(stop.
x(), stop.
y(), singlePt);
998 bool isRRect = hasOnlyMoveTos();
1003 this->
addRect(bounds, dir, (startIndex + 1) / 2);
1004 }
else if (rrect.
isOval()) {
1006 this->
addOval(bounds, dir, startIndex / 2);
1019 const int kVerbs = startsWithConic
1031 if (startsWithConic) {
1032 for (
unsigned i = 0; i < 3; ++i) {
1039 for (
unsigned i = 0; i < 4; ++i) {
1058bool SkPath::hasOnlyMoveTos()
const {
1060 const uint8_t* verbs = fPathRef->
verbsBegin();
1061 for (
int i = 0; i <
count; ++i) {
1073bool SkPath::isZeroLengthSincePoint(
int startPtIndex)
const {
1080 for (
int index = 1; index <
count; ++index) {
1081 if (first != pts[index]) {
1092 if (rx < 0 || ry < 0) {
1103 return this->
addOval(oval, dir, 1);
1115 bool isOval = hasOnlyMoveTos();
1126 const int kVerbs = 6;
1135 for (
unsigned i = 0; i < 4; ++i) {
1170 return forceMoveTo ? this->
moveTo(lonePt) : this->
lineTo(lonePt);
1179 bool isArc = this->hasOnlyMoveTos();
1184 auto addPt = [&forceMoveTo, &
isArc,
this](
const SkPoint& pt) {
1199 if (startV == stopV) {
1219 for (
int i = 0; i <
count; ++i) {
1224 ed.
setIsArc({oval, startAngle, sweepAngle,
false});
1240 this->injectMoveToIfNeeded();
1251 srcPts[1].
set(
x,
y);
1252 if (srcPts[0] == srcPts[1]) {
1257 SkVector midPointDistance = srcPts[0] - srcPts[1];
1258 midPointDistance *= 0.5f;
1264 pointTransform.
mapPoints(&transformedMidPoint, &midPointDistance, 1);
1267 SkScalar squareX = transformedMidPoint.
fX * transformedMidPoint.
fX;
1268 SkScalar squareY = transformedMidPoint.
fY * transformedMidPoint.
fY;
1272 SkScalar radiiScale = squareX / squareRx + squareY / squareRy;
1273 if (radiiScale > 1) {
1279 pointTransform.
setScale(1 / rx, 1 / ry);
1283 pointTransform.
mapPoints(unitPts, srcPts, (
int) std::size(unitPts));
1284 SkVector delta = unitPts[1] - unitPts[0];
1286 SkScalar d = delta.fX * delta.fX + delta.fY * delta.fY;
1287 SkScalar scaleFactorSquared = std::max(1 /
d - 0.25f, 0.f);
1291 scaleFactor = -scaleFactor;
1293 delta.scale(scaleFactor);
1294 SkPoint centerPoint = unitPts[0] + unitPts[1];
1295 centerPoint *= 0.5f;
1296 centerPoint.
offset(-delta.fY, delta.fX);
1297 unitPts[0] -= centerPoint;
1298 unitPts[1] -= centerPoint;
1301 SkScalar thetaArc = theta2 - theta1;
1321 SkScalar thetaWidth = thetaArc / segments;
1328 auto scalar_is_integer = [](
SkScalar scalar) ->
bool {
1332 scalar_is_integer(rx) && scalar_is_integer(ry) &&
1333 scalar_is_integer(
x) && scalar_is_integer(
y);
1335 for (
int i = 0; i < segments; ++i) {
1336 SkScalar endTheta = startTheta + thetaWidth,
1340 unitPts[1].
set(cosEndTheta, sinEndTheta);
1341 unitPts[1] += centerPoint;
1342 unitPts[0] = unitPts[1];
1343 unitPts[0].
offset(t * sinEndTheta, -t * cosEndTheta);
1345 pointTransform.
mapPoints(mapped, unitPts, (
int) std::size(unitPts));
1351 if (expectIntegers) {
1352 for (
SkPoint& point : mapped) {
1357 this->
conicTo(mapped[0], mapped[1],
w);
1358 startTheta = endTheta;
1371 return this->
arcTo(rx, ry, xAxisRotate, largeArc, sweep,
1372 currentPoint.
fX + dx, currentPoint.
fY + dy);
1376 if (oval.
isEmpty() || 0 == sweepAngle) {
1382 if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) {
1385 SkScalar startOver90 = startAngle / 90.f;
1390 SkScalar startIndex = std::fmod(startOver90I + 1.f, 4.f);
1391 startIndex = startIndex < 0 ? startIndex + 4.f : startIndex;
1393 (unsigned) startIndex);
1396 return this->
arcTo(oval, startAngle, sweepAngle,
true);
1404 this->injectMoveToIfNeeded();
1407 return this->
lineTo(x1, y1);
1417 double cosh = dot(befored, afterd);
1418 double sinh = cross(befored, afterd);
1425 return this->
lineTo(x1, y1);
1430 SkScalar xx = x1 - dist * befored[0];
1431 SkScalar yy = y1 - dist * befored[1];
1437 return this->
conicTo(x1, y1, x1 + after.
fX, y1 + after.
fY, weight);
1445 matrix.setTranslate(dx, dy);
1446 return this->
addPath(path, matrix, mode);
1455 const uint8_t fillType = fFillType;
1457 fFillType = fillType;
1462 const SkPath* src = &srcPath;
1465 src = tmp.
set(srcPath);
1469 if (src->fLastMoveToIndex >= 0) {
1470 fLastMoveToIndex = src->fLastMoveToIndex + this->
countPoints();
1472 fLastMoveToIndex = src->fLastMoveToIndex - this->
countPoints();
1476 matrix.mapPoints(newPts, src->fPathRef->points(), src->countPoints());
1477 if (
int numWeights = src->fPathRef->countWeights()) {
1478 memcpy(newWeights, src->fPathRef->conicWeights(), numWeights *
sizeof(newWeights[0]));
1480 return this->dirtyAfterEdit();
1484 bool firstVerb =
true;
1489 mapPtsProc(matrix, mappedPts, &pts[0], 1);
1491 injectMoveToIfNeeded();
1494 if (!this->
getLastPt(&lastPt) || lastPt != mappedPts[0]) {
1495 this->
lineTo(mappedPts[0]);
1498 this->
moveTo(mappedPts[0]);
1502 mapPtsProc(matrix, mappedPts, &pts[1], 1);
1503 this->
lineTo(mappedPts[0]);
1506 mapPtsProc(matrix, mappedPts, &pts[1], 2);
1507 this->
quadTo(mappedPts[0], mappedPts[1]);
1510 mapPtsProc(matrix, mappedPts, &pts[1], 2);
1511 this->
conicTo(mappedPts[0], mappedPts[1], *
w);
1514 mapPtsProc(matrix, mappedPts, &pts[1], 3);
1515 this->
cubicTo(mappedPts[0], mappedPts[1], mappedPts[2]);
1530 if (path.fPathRef->fVerbs.empty()) {
1534 const uint8_t* verbs =
path.fPathRef->verbsEnd();
1535 const uint8_t* verbsBegin =
path.fPathRef->verbsBegin();
1537 const SkPoint* pts =
path.fPathRef->pointsEnd() - 1;
1538 const SkScalar* conicWeights =
path.fPathRef->conicWeightsEnd();
1540 while (verbs > verbsBegin) {
1541 uint8_t v = *--verbs;
1551 this->
quadTo(pts[1], pts[0]);
1554 this->
conicTo(pts[1], pts[0], *--conicWeights);
1557 this->
cubicTo(pts[2], pts[1], pts[0]);
1571 const SkPath* src = &srcPath;
1574 src = tmp.
set(srcPath);
1577 const uint8_t* verbsBegin = src->fPathRef->verbsBegin();
1578 const uint8_t* verbs = src->fPathRef->verbsEnd();
1579 const SkPoint* pts = src->fPathRef->pointsEnd();
1580 const SkScalar* conicWeights = src->fPathRef->conicWeightsEnd();
1582 bool needMove =
true;
1583 bool needClose =
false;
1584 while (verbs > verbsBegin) {
1585 uint8_t v = *--verbs;
1607 this->
quadTo(pts[1], pts[0]);
1610 this->
conicTo(pts[1], pts[0], *--conicWeights);
1613 this->
cubicTo(pts[2], pts[1], pts[0]);
1630 matrix.setTranslate(dx, dy);
1643 path->cubicTo(pts[1], pts[2], pts[3]);
1648 if (matrix.isIdentity()) {
1649 if (dst !=
nullptr && dst !=
this) {
1656 if (dst ==
nullptr) {
1657 dst =
const_cast<SkPath*
>(
this);
1660 if (matrix.hasPerspective()) {
1662 tmp.fFillType = fFillType;
1665 const SkPath* src =
this;
1715 dst->fLastMoveToIndex = fLastMoveToIndex;
1716 dst->fFillType = fFillType;
1717 dst->fIsVolatile = fIsVolatile;
1730 dst->setConvexity(convexity);
1739 dst->setFirstDirection(
1742 }
else if (det2x2 > 0) {
1743 dst->setFirstDirection(this->getFirstDirection());
1759 fConicWeights =
nullptr;
1760 fMoveTo.
fX = fMoveTo.
fY = fLastPt.
fX = fLastPt.
fY = 0;
1761 fForceClose = fCloseLine =
false;
1765 fVerbStop =
nullptr;
1770 this->setPath(path, forceClose);
1774 fPts = path.fPathRef->points();
1775 fVerbs = path.fPathRef->verbsBegin();
1776 fVerbStop = path.fPathRef->verbsEnd();
1777 fConicWeights = path.fPathRef->conicWeights();
1778 if (fConicWeights) {
1781 fLastPt.fX = fLastPt.fY = 0;
1782 fMoveTo.fX = fMoveTo.fY = 0;
1783 fForceClose =
SkToU8(forceClose);
1788 if (fVerbs ==
nullptr || fVerbs == fVerbStop) {
1795 const uint8_t* verbs = fVerbs;
1796 const uint8_t* stop = fVerbStop;
1802 while (verbs < stop) {
1804 unsigned v = *verbs++;
1817 if (fLastPt != fMoveTo) {
1840 if (fVerbs == fVerbStop) {
1843 if (
kLine_Verb == this->autoClose(ptsParam)) {
1852 unsigned verb = *fVerbs++;
1860 verb = this->autoClose(pts);
1866 if (fVerbs == fVerbStop) {
1873 fNeedClose = fForceClose;
1878 fLastPt = srcPts[0];
1887 memcpy(&pts[1], srcPts, 2 *
sizeof(
SkPoint));
1888 fLastPt = srcPts[1];
1893 memcpy(&pts[1], srcPts, 3 *
sizeof(
SkPoint));
1894 fLastPt = srcPts[2];
1898 verb = this->autoClose(pts);
1914 fEnd = iterate.
end();
1918 if (!(
fIter != fEnd)) {
1921 auto [verb, iterPts, weights] = *
fIter;
1929 fConicWeight = *weights;
1934 memcpy(pts, iterPts,
sizeof(
SkPoint) * numPts);
1949 for (
int i = 0; i <
count; ++i) {
1951 if (i <
count - 1) {
1955 if (conicWeight != -12345) {
1962 for (
int i = 0; i <
count; ++i) {
1964 if (i <
count - 1) {
1968 if (conicWeight >= 0) {
1978 Iter iter(*
this,
false);
1983 char const *
const gFillTypeStrs[] = {
1989 builder.printf(
"path.setFillType(SkPathFillType::k%s);\n",
2006 append_params(&builder,
"path.cubicTo", &pts[1], 3, asType);
2009 builder.append(
"path.close();\n");
2012 SkDebugf(
" path: UNKNOWN VERB %d, aborting dump...\n", verb);
2016 if (!wStream && builder.size()) {
2029 auto bool_str = [](
bool v) {
return v ?
"true" :
"false"; };
2031 builder.appendf(
"// fBoundsIsDirty = %s\n", bool_str(fPathRef->fBoundsIsDirty));
2032 builder.appendf(
"// fGenerationID = %u\n", fPathRef->fGenerationID);
2033 builder.appendf(
"// fSegmentMask = %d\n", fPathRef->fSegmentMask);
2035 const char* gTypeStrs[] = {
2036 "General",
"Oval",
"RRect",
2038 builder.appendf(
"// fType = %s\n", gTypeStrs[
static_cast<int>(fPathRef->fType)]);
2040 auto append_scalar = [&](
SkScalar v) {
2042 builder.appendf(
"SkBits2Float(0x%08X) /* %g */",
SkFloat2Bits(v), v);
2044 builder.appendf(
"%g", v);
2048 builder.append(
"const SkPoint path_points[] = {\n");
2051 builder.append(
" { ");
2052 append_scalar(p.fX);
2053 builder.append(
", ");
2054 append_scalar(p.fY);
2055 builder.append(
" },\n");
2057 builder.append(
"};\n");
2059 const char* gVerbStrs[] = {
2060 "Move",
"Line",
"Quad",
"Conic",
"Cubic",
"Close"
2062 builder.append(
"const uint8_t path_verbs[] = {\n ");
2064 builder.appendf(
"(uint8_t)SkPathVerb::k%s, ", gVerbStrs[*v]);
2066 builder.append(
"\n};\n");
2070 builder.append(
"const SkScalar path_conics[] = {\n ");
2073 builder.append(
", ");
2075 builder.append(
"\n};\n");
2078 char const *
const gFillTypeStrs[] = {
2085 builder.appendf(
"SkPath path = SkPath::Make(path_points, %d, path_verbs, %d, %s, %d,\n",
2087 nConics ?
"path_conics" :
"nullptr", nConics);
2088 builder.appendf(
" SkPathFillType::k%s, %s);\n",
2090 bool_str(fIsVolatile));
2099bool SkPath::isValidImpl()
const {
2100 if ((fFillType & ~3) != 0) {
2105 if (!fBoundsIsDirty) {
2108 bool isFinite = compute_pt_bounds(&bounds, *fPathRef.
get());
2142#define kValueNeverReturnedBySign 2
2160 fFirstPt = fLastPt = pt;
2165 if (fLastPt == pt) {
2170 if (fFirstPt == fLastPt && fExpectedDir ==
kInvalid_DirChange && fLastVec.equals(0,0)) {
2171 fLastVec = pt - fLastPt;
2172 fFirstVec = fLastVec;
2173 }
else if (!this->addVec(pt - fLastPt)) {
2193 for (
int outerLoop = 0; outerLoop < 2; ++outerLoop ) {
2203 dxes += (sx != lastSx);
2204 dyes += (sy != lastSy);
2205 if (dxes > 3 || dyes > 3) {
2225 return this->addPt(fFirstPt) && this->addVec(fFirstVec);
2248 bool addVec(
const SkVector& curVec) {
2257 }
else if (dir != fExpectedDir) {
2271 return ++fReversals < 3;
2273 return (fIsFinite =
false);
2275 SK_ABORT(
"Use of invalid direction change flag");
2289 int fReversals { 0 };
2290 bool fIsFinite {
true };
2296 this->setConvexity(convexity);
2311 if (fLastMoveToIndex >= 0) {
2312 if (fLastMoveToIndex == pointCount - 1) {
2314 auto verbs = fPathRef->
verbsEnd() - 1;
2319 }
else if (fLastMoveToIndex != skipCount) {
2326 if (skipCount > 0) {
2328 pointCount -= skipCount;
2337 int contourCount = 0;
2338 bool needsClose =
false;
2341 for (
auto [verb, pts, wt] :
SkPathPriv::Iterate(*this)) {
2343 if (contourCount == 0) {
2353 if (contourCount == 1) {
2355 if (!
state.close()) {
2364 for (
int i = 1; i <=
count; ++i) {
2365 if (!
state.addPt(pts[i])) {
2380 if (needsClose && !
state.close()) {
2386 && !this->getBounds().isEmpty()) {
2387 return setComputedConvexity(
state.reversals() < 3 ?
2390 this->setFirstDirection(
state.getFirstDirection());
2401 bool done()
const {
return fDone; }
2403 int count()
const {
return fCurrPtCount; }
2410 const uint8_t* fCurrVerb;
2411 const uint8_t* fStopVerbs;
2420 fCurrPt = pathRef.
points();
2429 if (fCurrVerb >= fStopVerbs) {
2437 fCurrPt += fCurrPtCount;
2441 const uint8_t* verbs = fCurrVerb;
2443 for (verbs++; verbs < fStopVerbs; verbs++) {
2451 fCurrConicWeight += 1;
2467 fCurrPtCount = ptCount;
2488 (p1y - p0y) * (p2x - p0x));
2499 for (
int i = 1; i <
count; ++i) {
2516 if (pts[index] != pts[i]) {
2532 int minIndex = index;
2533 int maxIndex = index;
2534 for (
int i = index + 1; i < n; ++i) {
2535 if (pts[i].fY !=
y) {
2542 }
else if (
x >
max) {
2547 *maxIndexPtr = maxIndex;
2564 auto d = path.getFirstDirection();
2579 SkScalar ymax = path.getBounds().fTop;
2582 for (; !iter.
done(); iter.
next()) {
2583 int n = iter.
count();
2591 if (pts[index].fY < ymax) {
2597 if (pts[(index + 1) % n].fY == pts[index].fY) {
2600 if (minIndex == maxIndex) {
2603 SkASSERT(pts[minIndex].fY == pts[index].fY);
2604 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2605 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2608 cross = minIndex - maxIndex;
2621 if (
prev == index) {
2631 if (0 == cross && pts[
prev].fY == pts[index].fY && pts[
next].fY == pts[index].fY) {
2633 cross = pts[index].
fX - pts[
next].
fX;
2639 ymax = pts[index].
fY;
2645 path.setFirstDirection(
d);
2655 return (
a -
b) * (c -
b) <= 0;
2671 for (
size_t i = 1; i <
N; ++i) {
2672 min = std::min(
min, pts[i].fX);
2673 max = std::max(
max, pts[i].fX);
2697 if (y < y0 || y > y3) {
2710 find_minmax<4>(pts, &
min, &
max);
2725 if (
x != pts[3].fX ||
y != pts[3].fY) {
2730 return xt <
x ? dir : 0;
2737 for (
int i = 0; i <= n; ++i) {
2762 const SkPoint* pts = conic.fPts;
2772 if (y < y0 || y > y2) {
2797 xt = pts[1 - dir].
fX;
2803 if (
x != pts[2].fX ||
y != pts[2].fY) {
2808 return xt <
x ? dir : 0;
2824 int* onCurveCount) {
2829 bool isMono =
is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped);
2847 if (y < y0 || y > y2) {
2859 if (pts[0].fX >
x && pts[1].fX >
x && pts[2].fX >
x) {
2866 2 * (pts[1].fY - pts[0].fY),
2875 xt = pts[1 - dir].
fX;
2884 if (
x != pts[2].fX ||
y != pts[2].fY) {
2889 return xt <
x ? dir : 0;
2921 if (y < y0 || y > y1) {
2931 SkScalar cross = (x1 - x0) * (
y - pts[0].fY) - dy * (
x - x0);
2937 if (
x != x1 ||
y != pts[1].fY) {
2950 && !
between(pts[2].fY,
y, pts[3].fY)) {
2954 && !
between(pts[2].fX,
x, pts[3].fX)) {
2959 for (
int i = 0; i <= n; ++i) {
2977 if (!
between(pts[0].fY,
y, pts[1].fY) && !
between(pts[1].fY,
y, pts[2].fY)) {
2980 if (!
between(pts[0].fX,
x, pts[1].fX) && !
between(pts[1].fX,
x, pts[2].fX)) {
2991 for (
int index = 0; index < n; ++index) {
2998 tangents->
push_back(conic.evalTangentAt(t));
3004 if (!
between(pts[0].fY,
y, pts[1].fY) && !
between(pts[1].fY,
y, pts[2].fY)) {
3007 if (!
between(pts[0].fX,
x, pts[1].fX) && !
between(pts[1].fX,
x, pts[2].fX)) {
3012 2 * (pts[1].fY - pts[0].fY),
3015 for (
int index = 0; index < n; ++index) {
3067 int onCurveCount = 0;
3070 switch (iter.
next(pts)) {
3099 if (onCurveCount <= 1) {
3100 return SkToBool(onCurveCount) ^ isInverse;
3102 if ((onCurveCount & 1) || evenOddFill) {
3103 return SkToBool(onCurveCount & 1) ^ isInverse;
3112 int oldCount = tangents.
size();
3113 switch (iter.
next(pts)) {
3133 if (tangents.
size() > oldCount) {
3134 int last = tangents.
size() - 1;
3135 const SkVector& tangent = tangents[last];
3139 for (
int index = 0; index < last; ++index) {
3158void SkPath::shrinkToFit() {
3162 if (!fPathRef->
unique()) {
3164 pr->copy(*fPathRef, 0, 0, 0);
3176 const SkConic conic(p0, p1, p2,
w);
3177 return conic.chopIntoQuadsPOW2(pts, pow2);
3187 bool needsClose = !isSimpleFill;
3191 if (0 != rectPtCnt) {
3194 rectPts[0] = verbPts[0];
3198 if (5 == rectPtCnt) {
3201 rectPts[rectPtCnt] = verbPts[1];
3205 if (4 == rectPtCnt) {
3206 rectPts[4] = rectPts[0];
3220 if (rectPtCnt < 5) {
3223 if (rectPts[0] != rectPts[4]) {
3228 bool vec03IsVertical;
3229 if (rectPts[0].fX == rectPts[3].fX && rectPts[1].fX == rectPts[2].fX &&
3230 rectPts[0].fY == rectPts[1].fY && rectPts[3].fY == rectPts[2].fY) {
3232 if (rectPts[0].fX == rectPts[1].fX || rectPts[0].fY == rectPts[3].fY) {
3235 vec03IsVertical =
true;
3236 }
else if (rectPts[0].fY == rectPts[3].fY && rectPts[1].fY == rectPts[2].fY &&
3237 rectPts[0].fX == rectPts[1].fX && rectPts[3].fX == rectPts[2].fX) {
3239 if (rectPts[0].fY == rectPts[1].fY || rectPts[0].fX == rectPts[3].fX) {
3242 vec03IsVertical =
false;
3248 unsigned sortFlags =
3249 ((rectPts[0].
fX < rectPts[2].
fX) ? 0b00 : 0b01) |
3250 ((rectPts[0].fY < rectPts[2].fY) ? 0b00 : 0b10);
3251 switch (sortFlags) {
3253 rect->setLTRB(rectPts[0].fX, rectPts[0].fY, rectPts[2].fX, rectPts[2].fY);
3258 rect->setLTRB(rectPts[2].fX, rectPts[0].fY, rectPts[0].fX, rectPts[2].fY);
3263 rect->setLTRB(rectPts[0].fX, rectPts[2].fY, rectPts[2].fX, rectPts[0].fY);
3268 rect->setLTRB(rectPts[2].fX, rectPts[2].fY, rectPts[0].fX, rectPts[0].fY);
3277 if (isFillNoPathEffect &&
SkScalarAbs(sweepAngle) >= 360.f) {
3291 SkScalar sweepAngle,
bool useCenter,
bool isFillNoPathEffect) {
3297 sweepAngle = std::copysign(3600.0f, sweepAngle) + std::fmod(sweepAngle, 360.0f);
3300 path->setIsVolatile(
true);
3302 if (isFillNoPathEffect &&
SkScalarAbs(sweepAngle) >= 360.f) {
3303 path->addOval(oval);
3304 SkASSERT(path->isConvex() && DrawArcIsConvex(sweepAngle,
false, isFillNoPathEffect));
3312 bool convex = DrawArcIsConvex(sweepAngle, useCenter, isFillNoPathEffect);
3314 bool forceMoveTo = !useCenter;
3315 while (sweepAngle <= -360.f) {
3316 path->arcTo(oval, startAngle, -180.f, forceMoveTo);
3317 startAngle -= 180.f;
3318 path->arcTo(oval, startAngle, -180.f,
false);
3319 startAngle -= 180.f;
3320 forceMoveTo =
false;
3321 sweepAngle += 360.f;
3323 while (sweepAngle >= 360.f) {
3324 path->arcTo(oval, startAngle, 180.f, forceMoveTo);
3325 startAngle += 180.f;
3326 path->arcTo(oval, startAngle, 180.f,
false);
3327 startAngle += 180.f;
3328 forceMoveTo =
false;
3329 sweepAngle -= 360.f;
3331 path->arcTo(oval, startAngle, sweepAngle, forceMoveTo);
3336 path->setFirstDirection(firstDir);
3346 for (
int i = 0; i < n; ++i) {
3349 extremas[n] = src[2];
3354 SkConic conic(src[0], src[1], src[2],
w);
3356 int n = conic.findXExtrema(ts);
3357 n += conic.findYExtrema(&ts[n]);
3359 for (
int i = 0; i < n; ++i) {
3360 extremas[i] = conic.evalAt(ts[i]);
3362 extremas[n] = src[2];
3371 for (
int i = 0; i < n; ++i) {
3374 extremas[n] = src[3];
3396 extremas[0] = pts[0];
3400 extremas[0] = pts[1];
3415 for (
int i = 0; i <
count; ++i) {
3432 const SkPoint& p3,
bool exact) {
3439 return exact ? p1 == p2 && p2 == p3 && p3 == p4 :
3449 bool needMove =
true;
3452 if (verbCount >= (INT_MAX / 3)) {
3460 for (
int i = 0; i < verbCount; ++i) {
3502 const uint8_t vbs[],
int verbCount,
3505 if (verbCount <= 0) {
3510 if (!
info.valid ||
info.points > pointCount ||
info.weights > wCount) {
3511 SkDEBUGFAIL(
"invalid verbs and number of points/weights");
3515 return MakeInternal(
info, pts, vbs, verbCount, ws, ft,
isVolatile);
3556 const uint8_t verbs[],
3577 const SkPoint* firstPt =
nullptr;
3578 const SkPoint* lastPt =
nullptr;
3582 const SkPoint* savePts =
nullptr;
3583 lineStart.
set(0, 0);
3584 signed char directions[] = {-1, -1, -1, -1, -1};
3585 bool closedOrMoved =
false;
3586 bool autoClose =
false;
3587 bool insertClose =
false;
3588 int verbCnt = path.fPathRef->countVerbs();
3589 while (*currVerb < verbCnt && (!allowPartial || !autoClose)) {
3590 uint8_t verb = insertClose ? (uint8_t)
SkPath::kClose_Verb : path.fPathRef->atVerb(*currVerb);
3595 insertClose =
false;
3602 SkVector lineDelta = lineEnd - lineStart;
3603 if (lineDelta.
fX && lineDelta.
fY) {
3609 if (lineStart == lineEnd) {
3614 directions[0] = nextDirection;
3616 closedOrMoved =
false;
3617 lineStart = lineEnd;
3620 if (closedOrMoved) {
3623 if (autoClose && nextDirection == directions[0]) {
3626 closedOrMoved = autoClose;
3627 if (directions[corners - 1] == nextDirection) {
3629 thirdCorner = lineEnd;
3631 lineStart = lineEnd;
3634 directions[corners++] = nextDirection;
3638 firstCorner = lineStart;
3641 if ((directions[0] ^ directions[2]) != 2) {
3644 thirdCorner = lineEnd;
3647 if ((directions[1] ^ directions[3]) != 2) {
3654 lineStart = lineEnd;
3662 if (allowPartial && !autoClose && directions[0] >= 0) {
3665 goto addMissingClose;
3670 closeXY = *firstPt - *lastPt;
3671 if (closeXY.
fX && closeXY.
fY) {
3676 closedOrMoved =
true;
3687 if (corners < 3 || corners > 4) {
3694 closeXY = *firstPt - *lastPt;
3695 if (closeXY.
fX && closeXY.
fY) {
3699 rect->set(firstCorner, thirdCorner);
3702 *isClosed = autoClose;
3705 *direction = directions[0] == ((directions[1] + 1) & 3) ?
3715 const SkPoint* pts = path.fPathRef->points();
3718 if (!IsRectContour(path,
true, &currVerb, &pts,
nullptr, &testDirs[0], &testRects[0])) {
3721 if (IsRectContour(path,
false, &currVerb, &pts,
nullptr, &testDirs[1], &testRects[1])) {
3722 if (testRects[0].
contains(testRects[1])) {
3724 rects[0] = testRects[0];
3725 rects[1] = testRects[1];
3728 dirs[0] = testDirs[0];
3729 dirs[1] = testDirs[1];
3733 if (testRects[1].
contains(testRects[0])) {
3735 rects[0] = testRects[1];
3736 rects[1] = testRects[0];
3739 dirs[0] = testDirs[1];
3740 dirs[1] = testDirs[0];
3754 return fA *
x + fB *
y + fC;
3762 double dmag = sqrt(
a *
a +
b *
b);
3775 (
a == 0 &&
b == 0)) {
3795 diagMin.
fX = bounds.fLeft;
3796 diagMax.
fX = bounds.fRight;
3798 diagMin.
fX = bounds.fRight;
3799 diagMax.
fX = bounds.fLeft;
3802 diagMin.
fY = bounds.fTop;
3803 diagMax.
fY = bounds.fBottom;
3805 diagMin.
fY = bounds.fBottom;
3806 diagMax.
fY = bounds.fTop;
3813 return kAllNegative;
3815 return kAllPositive;
3828 -plane.
fA, plane.
fB, p0.
fY,
3835 path.transform(
inv, &rotated);
3850 Rec* rec = (Rec*)ctx;
3852 bool addLineTo =
false;
3857 rec->fResult.moveTo(pts[0]);
3858 rec->fPrev = pts[0];
3862 if (addLineTo || pts[0] != rec->fPrev) {
3863 rec->fResult.lineTo(pts[0]);
3868 rec->fResult.lineTo(pts[1]);
3869 rec->fPrev = pts[1];
3872 rec->fResult.quadTo(pts[1], pts[2]);
3873 rec->fPrev = pts[2];
3876 rec->fResult.cubicTo(pts[1], pts[2], pts[3]);
3877 rec->fPrev = pts[3];
3885 rec.fResult.setFillType(path.getFillType());
3887 if (!
result.isFinite()) {
3895 if (!matrix.hasPerspective()) {
3904 if (plane.normalize()) {
3905 switch (plane.test(path.getBounds())) {
3909 *clippedPath =
clip(path, plane);
3921 return path.fPathRef->genIDChangeListenerCount();
3929 const SkPoint* pts = path.fPathRef->points();
3930 const int count = path.fPathRef->countPoints();
3932 for (
int i = 1; i <
count; ++i) {
3933 if (pts[i-1].fX != pts[i].fX && pts[i-1].fY != pts[i].fY) {
3943 fMoveToPtr =
fPts = path.fPathRef->points();
3944 fVerbs = path.fPathRef->verbsBegin();
3945 fVerbsStop = path.fPathRef->verbsEnd();
3946 fConicWeights = path.fPathRef->conicWeights();
3947 if (fConicWeights) {
3951 fNeedsCloseLine =
false;
3952 fNextIsNewContour =
false;
static SkM44 inv(const SkM44 &m)
static bool invalid(const SkISize &size)
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static const int points[]
std::unique_ptr< SkLatticeIter > fIter
static float next(float f)
static float prev(float f)
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
#define SkASSERT_RELEASE(cond)
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static uint32_t SkFloat2Bits(float value)
static bool SkIsFinite(T x, Pack... values)
static constexpr double sk_ieee_double_divide(double numer, double denom)
static void normalize(int n, double *gauss)
int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10])
void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7])
void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint *loc, SkVector *tangent, SkVector *curvature)
int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2])
SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t)
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent)
int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1])
static bool between(SkScalar a, SkScalar b, SkScalar c)
int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
@ kCW_SkRotationDirection
@ kCCW_SkRotationDirection
static skvx::float2 from_point(const SkPoint &point)
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t verbs[], int count)
@ kCubic_SkPathSegmentMask
@ kConic_SkPathSegmentMask
@ kQuad_SkPathSegmentMask
@ kLine_SkPathSegmentMask
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
static void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y, SkTDArray< SkVector > *tangents)
static bool is_degenerate(const SkPath &path)
#define INITIAL_LASTMOVETOINDEX_VALUE
static SkScalar cross_prod(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2)
static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint &start, const SkPoint &end)
static int winding_mono_conic(const SkConic &conic, SkScalar x, SkScalar y, int *onCurveCount)
static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2)
static int build_arc_conics(const SkRect &oval, const SkVector &start, const SkVector &stop, SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc], SkPoint *singlePt)
#define kValueNeverReturnedBySign
static void assert_known_direction(SkPathDirection dir)
static float poly_eval(float A, float B, float C, float t)
static bool arc_is_lone_point(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, SkPoint *pt)
static bool check_edge_against_rect(const SkPoint &p0, const SkPoint &p1, const SkRect &rect, SkPathFirstDirection dir)
static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int *onCurveCount)
static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int *onCurveCount)
static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int *onCurveCount)
static int find_diff_pt(const SkPoint pts[], int index, int n, int inc)
static int rect_make_dir(SkScalar dx, SkScalar dy)
static int compute_cubic_extremas(const SkPoint src[4], SkPoint extremas[5])
static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int *onCurveCount)
static bool contains_inclusive(const SkRect &r, SkScalar x, SkScalar y)
static int sign(SkScalar x)
static int compute_conic_extremas(const SkPoint src[3], SkScalar w, SkPoint extremas[3])
static void subdivide_cubic_to(SkPath *path, const SkPoint pts[4], int level=2)
static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y, SkTDArray< SkVector > *tangents)
static void angles_to_unit_vectors(SkScalar startAngle, SkScalar sweepAngle, SkVector *startV, SkVector *stopV, SkRotationDirection *dir)
static int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight, int *onCurveCount)
bool operator==(const SkPath &a, const SkPath &b)
static int find_max_y(const SkPoint pts[], int count)
static void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w, SkTDArray< SkVector > *tangents)
static double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t)
static SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, SkScalar t)
static SkPathFirstDirection crossToDir(SkScalar cross)
static double conic_eval_denominator(SkScalar w, SkScalar t)
static int compute_quad_extremas(const SkPoint src[3], SkPoint extremas[3])
static void append_params(SkString *str, const char label[], const SkPoint pts[], int count, SkScalarAsStringType strType, SkScalar conicWeight=-12345)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
static int find_min_max_x_at_y(const SkPoint pts[], int index, int n, int *maxIndexPtr)
static void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y, SkTDArray< SkVector > *tangents)
static void joinNoEmptyChecks(SkRect *dst, const SkRect &src)
static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int *onCurveCount)
static void find_minmax(const SkPoint pts[], SkScalar *minPtr, SkScalar *maxPtr)
#define SkDegreesToRadians(degrees)
#define SkScalarCopySign(x, y)
#define SkScalarFloorToScalar(x)
static float SkScalarSinSnapToZero(SkScalar radians)
#define SkScalarTan(radians)
#define SkScalarToDouble(x)
#define SkScalarMod(x, y)
#define SkScalarATan2(y, x)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
static int SkScalarSignAsInt(SkScalar x)
#define SkScalarSin(radians)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SkDoubleToScalar(x)
#define SkScalarCeilToInt(x)
#define SkScalarRoundToScalar(x)
#define SkScalarCos(radians)
#define SK_ScalarRoot2Over2
static float SkScalarCosSnapToZero(SkScalar radians)
void SkAppendScalar(SkString *str, SkScalar value, SkScalarAsStringType asType)
@ kHex_SkScalarAsStringType
@ kDec_SkScalarAsStringType
static void SkAppendScalarDec(SkString *str, SkScalar value)
static constexpr bool SkToBool(const T &x)
constexpr uint8_t SkToU8(S x)
ContourIter(const SkPathRef &pathRef)
const SkPoint * pts() const
SkAutoDisableDirectionCheck(SkPath *path)
~SkAutoDisableDirectionCheck()
~SkAutoPathBoundsUpdate()
SkAutoPathBoundsUpdate(SkPath *path, const SkRect &r)
static bool ChopMonoAtY(const SkPoint pts[4], SkScalar y, SkScalar *t)
static void ClipPath(const SkPath &path, const SkRect &clip, bool canCullToTheRight, void(*consume)(SkEdgeClipper *, bool newCtr, void *ctx), void *ctx)
SkPath::Verb next(SkPoint pts[])
static MapPtsProc GetMapPtsProc(const SkMatrix &matrix)
SkMatrix::MapPtsProc MapPtsProc
static constexpr int kMScaleX
horizontal scale factor
static constexpr int kMPersp1
input y perspective factor
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
void mapPoints(SkPoint dst[], const SkPoint src[], int count) const
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
bool invert(SkMatrix *inverse) const
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
static constexpr int kMPersp0
input x perspective factor
SkMatrix & preRotate(SkScalar degrees, SkScalar px, SkScalar py)
static constexpr int kMPersp2
perspective bias
static constexpr int kMSkewY
vertical skew factor
static constexpr int kMScaleY
vertical scale factor
static constexpr int kMSkewX
horizontal skew factor
SkMatrix & preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
SkPathEdgeIter(const SkPath &path)
static int PtsInVerb(unsigned verb)
static bool IsRRect(const SkPath &path, SkRRect *rrect, SkPathDirection *dir, unsigned *start)
static bool IsNestedFillRects(const SkPath &, SkRect rect[2], SkPathDirection dirs[2]=nullptr)
static bool IsSimpleRect(const SkPath &path, bool isSimpleFill, SkRect *rect, SkPathDirection *direction, unsigned *start)
static int GenIDChangeListenersCount(const SkPath &)
static bool DrawArcIsConvex(SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect)
static bool IsOval(const SkPath &path, SkRect *rect, SkPathDirection *dir, unsigned *start)
static bool IsAxisAligned(const SkPath &path)
static SkPathFirstDirection ComputeFirstDirection(const SkPath &)
static int LeadingMoveToCount(const SkPath &path)
static bool PerspectiveClip(const SkPath &src, const SkMatrix &, SkPath *result)
static bool IsRectContour(const SkPath &, bool allowPartial, int *currVerb, const SkPoint **ptsPtr, bool *isClosed, SkPathDirection *direction, SkRect *rect)
static bool AllPointsEq(const SkPoint pts[], int count)
static void CreateDrawArcPath(SkPath *path, const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect)
static SkPathFirstDirection OppositeFirstDirection(SkPathFirstDirection dir)
std::tuple< SkPoint *, SkScalar * > growForVerbsInPath(const SkPathRef &path)
SkPoint * growForRepeatedVerb(int verb, int numVbs, SkScalar **weights=nullptr)
void setIsOval(bool isCCW, unsigned start)
SkPoint * growForVerb(int verb, SkScalar weight=0)
void setIsRRect(bool isCCW, unsigned start)
SkPoint * writablePoints()
void setIsArc(const SkArc &arc)
uint32_t genID(uint8_t fillType) const
const SkPoint & atPoint(int index) const
const SkRect & getBounds() const
static void Rewind(sk_sp< SkPathRef > *pathRef)
static void CreateTransformedCopy(sk_sp< SkPathRef > *dst, const SkPathRef &src, const SkMatrix &matrix)
const uint8_t * verbsEnd() const
const SkScalar * conicWeightsEnd() const
uint8_t atVerb(int index) const
static SkPathRef * CreateEmpty()
const SkPoint * points() const
size_t approximateBytesUsed() const
bool hasComputedBounds() const
const SkScalar * conicWeights() const
const uint8_t * verbsBegin() const
bool dataMatchesVerbs() const
bool isArc(SkArc *arc) const
void interpolate(const SkPathRef &ending, SkScalar weight, SkPathRef *out) const
uint32_t getSegmentMasks() const
bool isClosedContour() const
void setPath(const SkPath &path, bool forceClose)
Verb next(SkPoint pts[4])
SkScalar conicWeight() const
void setPath(const SkPath &)
const SkPoint & current() const
SkPath & rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, ArcSize largeArc, SkPathDirection sweep, SkScalar dx, SkScalar dy)
bool isInverseFillType() const
SkPath & reverseAddPath(const SkPath &src)
uint32_t getGenerationID() const
void offset(SkScalar dx, SkScalar dy, SkPath *dst) const
static bool IsLineDegenerate(const SkPoint &p1, const SkPoint &p2, bool exact)
static SkPath RRect(const SkRRect &, SkPathDirection dir=SkPathDirection::kCW)
static SkPath Rect(const SkRect &, SkPathDirection=SkPathDirection::kCW, unsigned startIndex=0)
bool conservativelyContainsRect(const SkRect &rect) const
void setLastPt(SkScalar x, SkScalar y)
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
SkPath & arcTo(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool forceMoveTo)
SkPath & rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, SkScalar w)
SkPath & operator=(const SkPath &path)
SkPoint getPoint(int index) const
SkPath & moveTo(SkScalar x, SkScalar y)
bool isLine(SkPoint line[2]) const
bool getLastPt(SkPoint *lastPt) const
static bool IsQuadDegenerate(const SkPoint &p1, const SkPoint &p2, const SkPoint &p3, bool exact)
SkPathFillType getFillType() const
int getPoints(SkPoint points[], int max) const
void setFillType(SkPathFillType ft)
SkPath & addPoly(const SkPoint pts[], int count, bool close)
SkPath & lineTo(SkScalar x, SkScalar y)
static bool IsCubicDegenerate(const SkPoint &p1, const SkPoint &p2, const SkPoint &p3, const SkPoint &p4, bool exact)
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
SkPath & rCubicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, SkScalar dx3, SkScalar dy3)
SkPath & addPath(const SkPath &src, SkScalar dx, SkScalar dy, AddPathMode mode=kAppend_AddPathMode)
SkRect computeTightBounds() const
size_t approximateBytesUsed() const
bool isInterpolatable(const SkPath &compare) const
SkPath & rMoveTo(SkScalar dx, SkScalar dy)
bool interpolate(const SkPath &ending, SkScalar weight, SkPath *out) const
SkPath & addArc(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle)
static SkPath Make(const SkPoint[], int pointCount, const uint8_t[], int verbCount, const SkScalar[], int conicWeightCount, SkPathFillType, bool isVolatile=false)
bool isOval(SkRect *bounds) const
int getVerbs(uint8_t verbs[], int max) const
static SkPath Circle(SkScalar center_x, SkScalar center_y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
SkPath & addRoundRect(const SkRect &rect, SkScalar rx, SkScalar ry, SkPathDirection dir=SkPathDirection::kCW)
static int ConvertConicToQuads(const SkPoint &p0, const SkPoint &p1, const SkPoint &p2, SkScalar w, SkPoint pts[], int pow2)
const SkRect & getBounds() const
uint32_t getSegmentMasks() const
static SkPath Oval(const SkRect &, SkPathDirection=SkPathDirection::kCW)
SkPath & addOval(const SkRect &oval, SkPathDirection dir=SkPathDirection::kCW)
static SkPath Polygon(const SkPoint pts[], int count, bool isClosed, SkPathFillType=SkPathFillType::kWinding, bool isVolatile=false)
SkPath & cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar x3, SkScalar y3)
bool isLastContourClosed() const
SkPath & conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
SkPath & rQuadTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2)
bool isRect(SkRect *rect, bool *isClosed=nullptr, SkPathDirection *direction=nullptr) const
void transform(const SkMatrix &matrix, SkPath *dst, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
bool isRRect(SkRRect *rrect) const
bool isArc(SkArc *arc) const
SkPath makeTransform(const SkMatrix &m, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
SkPath & rLineTo(SkScalar dx, SkScalar dy)
bool contains(SkScalar x, SkScalar y) const
friend class SkPathBuilder
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
void incReserve(int extraPtCount, int extraVerbCount=0, int extraConicCount=0)
static SkScalar LengthSqd(const SkPoint &pt)
static bool EqualsWithinTolerance(const SkPoint &p1, const SkPoint &p2)
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
void setRectRadii(const SkRect &rect, const SkVector radii[4])
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
const SkRect & getBounds() const
void append(const char text[])
void push_back(const T &v)
void remove(int index, int count=1)
void removeShuffle(int index)
bool writeText(const char text[])
void swap(sk_sp< T > &that)
void reset(T *ptr=nullptr)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
const uint8_t uint32_t uint32_t GError ** error
static float max(float r, float g, float b)
static float min(float r, float g, float b)
Optional< SkRect > bounds
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
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
SIT T max(const Vec< 1, T > &x)
SIT T min(const Vec< 1, T > &x)
SkPathFirstDirection getFirstDirection() const
bool addPt(const SkPoint &pt)
static SkPathConvexity BySign(const SkPoint points[], int count)
void setMovePt(const SkPoint &pt)
int SK_SPI chopIntoQuadsPOW2(SkPoint pts[], int pow2) const
static SkScalar TransformW(const SkPoint[3], SkScalar w, const SkMatrix &)
void set(const SkPoint pts[3], SkScalar w)
static int BuildUnitArc(const SkVector &start, const SkVector &stop, SkRotationDirection, const SkMatrix *, SkConic conics[kMaxConicsForArc])
Result test(const SkRect &bounds) const
SkScalar operator()(SkScalar x, SkScalar y) const
SkScalar eval(SkScalar x, SkScalar y) const
SkPath::RangeIter begin()
static float CrossProduct(const SkVector &a, const SkVector &b)
bool setLength(float length)
void offset(float dx, float dy)
static constexpr SkPoint Make(float x, float y)
void set(float x, float y)
constexpr float y() const
constexpr float x() const
static constexpr SkRect MakeEmpty()
SkScalar fBottom
larger y-axis bounds
SkScalar fLeft
smaller x-axis bounds
SkScalar fRight
larger x-axis bounds
bool contains(SkScalar x, SkScalar y) const
constexpr float centerX() const
constexpr float height() const
constexpr float centerY() const
constexpr float width() const
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
SkScalar fTop
smaller y-axis bounds