45 "recursive_limits_mismatch");
47#if defined SK_DEBUG && QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
50#ifndef DEBUG_QUAD_STROKER
51 #define DEBUG_QUAD_STROKER 0
57 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \
58 SkDebugf("[%d] %s " format "\n", depth, __FUNCTION__, __VA_ARGS__), \
59 SkDebugf(" " #resultType " t=(%g,%g)\n", quadPts->fStartT, quadPts->fEndT), \
61 #define STROKER_DEBUG_PARAMS(...) , __VA_ARGS__
63 #define STROKER_RESULT(resultType, depth, quadPts, format, ...) \
65 #define STROKER_DEBUG_PARAMS(...)
68#ifndef DEBUG_CUBIC_RECURSION_DEPTHS
69#define DEBUG_CUBIC_RECURSION_DEPTHS 0
71#if DEBUG_CUBIC_RECURSION_DEPTHS
73 static struct DepthHistogram {
74 inline static constexpr int kMaxDepth = 75;
75 int fCubicDepths[kMaxDepth + 1];
77 DepthHistogram() { memset(fCubicDepths, 0,
sizeof(fCubicDepths)); }
80 SkDebugf(
"# times recursion terminated per depth:\n");
81 for (
int i = 0;
i <= kMaxDepth;
i++) {
82 SkDebugf(
" depth %d: %d\n",
i, fCubicDepths[
i]);
86 inline void incDepth(
int depth) {
87 SkASSERT(depth >= 0 && depth <= kMaxDepth);
88 fCubicDepths[depth]++;
90 } sCubicDepthHistogram;
92#define DEBUG_CUBIC_RECURSION_TRACK_DEPTH(depth) sCubicDepthHistogram.incDepth(depth)
94#define DEBUG_CUBIC_RECURSION_TRACK_DEPTH(depth) (void)(depth)
109 unitNormal->
scale(radius, normal);
120 unitNormal->
scale(radius, normal);
172 bool canIgnoreCenter);
182 void close(
bool isLine) { this->finishContour(
true, isLine); }
185 this->finishContour(
false, isLine);
192 return fInner.isZeroLengthSincePoint(0) &&
193 fOuter.isZeroLengthSincePoint(fFirstOuterPtIndexInContour);
203 SkVector fFirstNormal, fPrevNormal, fFirstUnitNormal, fPrevUnitNormal;
206 int fFirstOuterPtIndexInContour;
209 bool fCanIgnoreCenter;
214 SkPath fInner, fOuter, fCusper;
217 kOuter_StrokeType = 1,
218 kInner_StrokeType = -1
223 kDegenerate_ResultType,
228 kPoint_ReductionType,
231 kDegenerate_ReductionType,
232 kDegenerate2_ReductionType,
233 kDegenerate3_ReductionType,
236 enum IntersectRayType {
246 static ReductionType CheckConicLinear(
const SkConic& ,
SkPoint* reduction);
249 static ReductionType CheckQuadLinear(
const SkPoint quad[3],
SkPoint* reduction);
265 bool ptInQuadBounds(
const SkPoint quad[3],
const SkPoint& pt)
const;
269 void setConicEndNormal(
const SkConic& ,
275 void setQuadEndNormal(
const SkPoint quad[3],
284 void finishContour(
bool close,
bool isLine);
296 SkVector* unitNormal,
bool currIsLine) {
310 unitNormal->
set(1, 0);
313 if (fSegmentCount == 0) {
315 fFirstUnitNormal = *unitNormal;
318 fOuter.
moveTo(fFirstOuterPt.
fX, fFirstOuterPt.
fY);
321 fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, *unitNormal,
322 fRadius, fInvMiterLimit, fPrevIsLine, currIsLine);
324 fPrevIsLine = currIsLine;
328void SkPathStroker::postJoinTo(
const SkPoint& currPt,
const SkVector& normal,
330 fJoinCompleted =
true;
332 fPrevUnitNormal = unitNormal;
337void SkPathStroker::finishContour(
bool close,
bool currIsLine) {
338 if (fSegmentCount > 0) {
342 fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt,
343 fFirstUnitNormal, fRadius, fInvMiterLimit,
344 fPrevIsLine, currIsLine);
347 if (fCanIgnoreCenter) {
357 fOuter.reversePathTo(fInner);
363 fCapper(&fOuter, fPrevPt, fPrevNormal, pt,
364 currIsLine ? &fInner :
nullptr);
365 fOuter.reversePathTo(fInner);
367 fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt,
368 fPrevIsLine ? &fInner :
nullptr);
380 fFirstOuterPtIndexInContour = fOuter.
countPoints();
388 bool canIgnoreCenter)
390 , fResScale(resScale)
391 , fCanIgnoreCenter(canIgnoreCenter) {
408 fFirstOuterPtIndexInContour = 0;
424 fInvResScaleSquared = fInvResScale * fInvResScale;
429 if (fSegmentCount > 0) {
430 this->finishContour(
false,
false);
433 fFirstPt = fPrevPt = pt;
434 fJoinCompleted =
false;
437void SkPathStroker::line_to(
const SkPoint& currPt,
const SkVector& normal) {
438 fOuter.
lineTo(currPt.
fX + normal.fX, currPt.
fY + normal.fY);
439 fInner.
lineTo(currPt.
fX - normal.fX, currPt.
fY - normal.fY);
446 while ((verb =
copy.next(pts))) {
451 if (pts[0] == pts[1]) {
457 if (pts[0] == pts[1] && pts[0] == pts[2]) {
462 if (pts[0] == pts[1] && pts[0] == pts[2] && pts[0] == pts[3]) {
484 if (!this->preJoinTo(currPt, &normal, &unitNormal,
true)) {
487 this->line_to(currPt, normal);
488 this->postJoinTo(currPt, normal, unitNormal);
491void SkPathStroker::setQuadEndNormal(
const SkPoint quad[3],
const SkVector& normalAB,
494 *normalBC = normalAB;
495 *unitNormalBC = unitNormalAB;
501 setQuadEndNormal(
conic.fPts, normalAB, unitNormalAB, normalBC, unitNormalBC);
512 if (degenerateAB && degenerateCD) {
513 goto DEGENERATE_NORMAL;
524 if (degenerateAB || degenerateCD) {
526 *normalCD = normalAB;
527 *unitNormalCD = unitNormalAB;
535 fStrokeType = strokeType;
536 fFoundTangents =
false;
537 quadPts->
init(tStart, tEnd);
547 if (t >= 0 && t <= 1) {
549 hit.
fX = lineStart.
fX * (1 - t) + lineEnd.
fX * t;
550 hit.
fY = lineStart.
fY * (1 - t) + lineEnd.
fY * t;
584 for (
int index = 0; index < 3; ++index) {
585 for (
int inner = index + 1; inner < 4; ++inner) {
588 if (ptMax < testMax) {
595 SkASSERT(outer1 >= 0 && outer1 <= 2);
596 SkASSERT(outer2 >= 1 && outer2 <= 3);
598 int mid1 = (1 + (2 >> outer2)) >> outer1;
600 SkASSERT(outer1 != mid1 && outer2 != mid1);
601 int mid2 = outer1 ^ outer2 ^ mid1;
603 SkASSERT(mid2 != outer1 && mid2 != outer2 && mid2 != mid1);
604 SkASSERT(((1 << outer1) | (1 << outer2) | (1 << mid1) | (1 << mid2)) == 0x0f);
605 SkScalar lineSlop = ptMax * ptMax * 0.00001f;
621 for (
int index = 0; index < 2; ++index) {
622 for (
int inner = index + 1; inner < 3; ++inner) {
623 SkVector testDiff = quad[inner] - quad[index];
625 if (ptMax < testMax) {
632 SkASSERT(outer1 >= 0 && outer1 <= 1);
633 SkASSERT(outer2 >= 1 && outer2 <= 2);
635 int mid = outer1 ^ outer2 ^ 3;
636 const float kCurvatureSlop = 0.000005f;
637 SkScalar lineSlop = ptMax * ptMax * kCurvatureSlop;
638 return pt_to_line(quad[mid], quad[outer1], quad[outer2]) <= lineSlop;
645SkPathStroker::ReductionType SkPathStroker::CheckCubicLinear(
const SkPoint cubic[4],
650 if (degenerateAB & degenerateBC & degenerateCD) {
651 return kPoint_ReductionType;
653 if (degenerateAB + degenerateBC + degenerateCD == 2) {
654 return kLine_ReductionType;
657 *tangentPtPtr = degenerateAB ? &
cubic[2] : &
cubic[1];
658 return kQuad_ReductionType;
664 for (
int index = 0; index <
count; ++index) {
666 if (0 >= t || t >= 1) {
670 if (reduction[rCount] !=
cubic[0] && reduction[rCount] !=
cubic[3]) {
675 return kLine_ReductionType;
677 static_assert(kQuad_ReductionType + 1 == kDegenerate_ReductionType,
"enum_out_of_whack");
678 static_assert(kQuad_ReductionType + 2 == kDegenerate2_ReductionType,
"enum_out_of_whack");
679 static_assert(kQuad_ReductionType + 3 == kDegenerate3_ReductionType,
"enum_out_of_whack");
681 return (ReductionType) (kQuad_ReductionType + rCount);
684SkPathStroker::ReductionType SkPathStroker::CheckConicLinear(
const SkConic&
conic,
688 if (degenerateAB & degenerateBC) {
689 return kPoint_ReductionType;
691 if (degenerateAB | degenerateBC) {
692 return kLine_ReductionType;
695 return kQuad_ReductionType;
701 return kLine_ReductionType;
703 conic.evalAt(t, reduction,
nullptr);
704 return kDegenerate_ReductionType;
707SkPathStroker::ReductionType SkPathStroker::CheckQuadLinear(
const SkPoint quad[3],
711 if (degenerateAB & degenerateBC) {
712 return kPoint_ReductionType;
714 if (degenerateAB | degenerateBC) {
715 return kLine_ReductionType;
718 return kQuad_ReductionType;
721 if (0 == t || 1 == t) {
722 return kLine_ReductionType;
725 return kDegenerate_ReductionType;
731 ReductionType reductionType = CheckConicLinear(
conic, &reduction);
732 if (kPoint_ReductionType == reductionType) {
739 if (kLine_ReductionType == reductionType) {
743 if (kDegenerate_ReductionType == reductionType) {
748 fJoiner = saveJoiner;
751 SkASSERT(kQuad_ReductionType == reductionType);
752 SkVector normalAB, unitAB, normalBC, unitBC;
753 if (!this->preJoinTo(pt1, &normalAB, &unitAB,
false)) {
758 this->init(kOuter_StrokeType, &quadPts, 0, 1);
759 (void) this->conicStroke(
conic, &quadPts);
760 this->init(kInner_StrokeType, &quadPts, 0, 1);
761 (void) this->conicStroke(
conic, &quadPts);
762 this->setConicEndNormal(
conic, normalAB, unitAB, &normalBC, &unitBC);
763 this->postJoinTo(pt2, normalBC, unitBC);
767 const SkPoint quad[3] = { fPrevPt, pt1, pt2 };
769 ReductionType reductionType = CheckQuadLinear(quad, &reduction);
770 if (kPoint_ReductionType == reductionType) {
777 if (kLine_ReductionType == reductionType) {
781 if (kDegenerate_ReductionType == reductionType) {
786 fJoiner = saveJoiner;
789 SkASSERT(kQuad_ReductionType == reductionType);
790 SkVector normalAB, unitAB, normalBC, unitBC;
791 if (!this->preJoinTo(pt1, &normalAB, &unitAB,
false)) {
796 this->init(kOuter_StrokeType, &quadPts, 0, 1);
797 (void) this->quadStroke(quad, &quadPts);
798 this->init(kInner_StrokeType, &quadPts, 0, 1);
799 (void) this->quadStroke(quad, &quadPts);
800 this->setQuadEndNormal(quad, normalAB, unitAB, &normalBC, &unitBC);
802 this->postJoinTo(pt2, normalBC, unitBC);
810 dxy->
set(fRadius, 0);
813 onPt->
fX = tPt.
fX + axisFlip * dxy->
fY;
814 onPt->
fY = tPt.
fY - axisFlip * dxy->
fX;
816 tangent->
fX = onPt->
fX + dxy->
fX;
817 tangent->
fY = onPt->
fY + dxy->
fY;
826 conic.evalAt(t, tPt, &dxy);
827 if (dxy.
fX == 0 && dxy.
fY == 0) {
830 this->setRayPts(*tPt, &dxy, onPt, tangent);
843 this->conicPerpRay(
conic, quadPts->
fEndT, &conicEndPt, &quadPts->
fQuad[2],
856 if (dxy.
fX == 0 && dxy.
fY == 0) {
866 dxy = chopped[3] - chopped[2];
867 if (dxy.
fX == 0 && dxy.
fY == 0) {
868 dxy = chopped[3] - chopped[1];
872 if (dxy.
fX == 0 && dxy.
fY == 0) {
873 dxy = cPts[3] - cPts[0];
876 setRayPts(*tPt, &dxy, onPt, tangent);
889 this->cubicPerpRay(
cubic, quadPts->
fEndT, &cubicEndPt, &quadPts->
fQuad[2],
898 this->cubicPerpRay(
cubic, quadPts->
fMidT, &cubicMidPt, mid,
nullptr);
906 if (dxy.
fX == 0 && dxy.
fY == 0) {
907 dxy = quad[2] - quad[0];
909 setRayPts(*tPt, &dxy, onPt, tangent);
915SkPathStroker::ResultType SkPathStroker::intersectRay(
SkQuadConstruct* quadPts,
930 return STROKER_RESULT(kDegenerate_ResultType, depth, quadPts,
"denom == 0");
936 if ((numerA >= 0) == (numerB >= 0)) {
941 if (
std::max(dist1, dist2) <= fInvResScaleSquared) {
943 "std::max(dist1=%g, dist2=%g) <= fInvResScaleSquared", dist1, dist2);
946 "(numerA=%g >= 0) == (numerB=%g >= 0)", numerA, numerB);
951 bool validDivide = numerA > numerA - 1;
953 if (kCtrlPt_RayType == intersectRayType) {
961 "(numerA=%g >= 0) != (numerB=%g >= 0)", numerA, numerB);
966 "SkScalarNearlyZero(denom=%g)", denom);
970SkPathStroker::ResultType SkPathStroker::tangentsMeet(
const SkPoint cubic[4],
972 this->cubicQuadEnds(
cubic, quadPts);
980 for (
int n = 0; n < 3; ++n) {
981 r[n] = (quad[n].
fY -
line[0].fY) * vec.
fX - (quad[n].
fX -
line[0].fX) * vec.
fY;
992bool SkPathStroker::ptInQuadBounds(
const SkPoint quad[3],
const SkPoint& pt)
const {
994 if (pt.
fX + fInvResScale < xMin) {
998 if (pt.
fX - fInvResScale > xMax) {
1002 if (pt.
fY + fInvResScale < yMin) {
1006 if (pt.
fY - fInvResScale > yMax) {
1017 SkVector smaller = quad[1] - quad[0];
1018 SkVector larger = quad[1] - quad[2];
1021 if (smallerLen > largerLen) {
1023 swap(smaller, larger);
1024 largerLen = smallerLen;
1033SkPathStroker::ResultType SkPathStroker::strokeCloseEnough(
const SkPoint stroke[3],
1040 "sharp_angle (1) =%g,%g, %g,%g, %g,%g",
1046 "points_within_dist(ray[0]=%g,%g, strokeMid=%g,%g, fInvResScale=%g)",
1047 ray[0].fX, ray[0].fY, strokeMid.
fX, strokeMid.
fY, fInvResScale);
1051 if (!ptInQuadBounds(
stroke, ray[0])) {
1053 "!pt_in_quad_bounds(stroke=(%g,%g %g,%g %g,%g), ray[0]=%g,%g)",
1055 ray[0].fX, ray[0].fY);
1060 if (rootCount != 1) {
1062 "rootCount=%d != 1", rootCount);
1069 "sharp_angle (2) =%g,%g, %g,%g, %g,%g",
1075 "points_within_dist(ray[0]=%g,%g, quadPt=%g,%g, error=%g)",
1076 ray[0].fX, ray[0].fY, quadPt.
fX, quadPt.
fY,
error);
1079 return STROKER_RESULT(kSplit_ResultType, depth, quadPts,
"%s",
"fall through");
1082SkPathStroker::ResultType SkPathStroker::compareQuadCubic(
const SkPoint cubic[4],
1085 this->cubicQuadEnds(
cubic, quadPts);
1086 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType
1088 if (resultType != kQuad_ResultType) {
1093 this->cubicPerpRay(
cubic, quadPts->
fMidT, &ray[1], &ray[0],
nullptr);
1094 return this->strokeCloseEnough(quadPts->
fQuad, ray, quadPts
1098SkPathStroker::ResultType SkPathStroker::compareQuadConic(
const SkConic&
conic,
1101 this->conicQuadEnds(
conic, quadPts);
1102 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType
1104 if (resultType != kQuad_ResultType) {
1109 this->conicPerpRay(
conic, quadPts->
fMidT, &ray[1], &ray[0],
nullptr);
1110 return this->strokeCloseEnough(quadPts->
fQuad, ray, quadPts
1114SkPathStroker::ResultType SkPathStroker::compareQuadQuad(
const SkPoint quad[3],
1119 this->quadPerpRay(quad, quadPts->
fStartT, &quadStartPt, &quadPts->
fQuad[0],
1125 this->quadPerpRay(quad, quadPts->
fEndT, &quadEndPt, &quadPts->
fQuad[2],
1129 ResultType resultType = this->intersectRay(quadPts, kCtrlPt_RayType
1131 if (resultType != kQuad_ResultType) {
1136 this->quadPerpRay(quad, quadPts->
fMidT, &ray[1], &ray[0],
nullptr);
1137 return this->strokeCloseEnough(quadPts->
fQuad, ray, quadPts
1141void SkPathStroker::addDegenerateLine(
const SkQuadConstruct* quadPts) {
1143 SkPath*
path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1144 path->lineTo(quad[2].fX, quad[2].fY);
1149 this->cubicQuadMid(
cubic, quadPts, &strokeMid);
1151 return dist < fInvResScaleSquared;
1155 if (!fFoundTangents) {
1156 ResultType resultType = this->tangentsMeet(
cubic, quadPts);
1157 if (kQuad_ResultType != resultType) {
1158 if ((kDegenerate_ResultType == resultType
1160 fInvResScale)) && cubicMidOnLine(
cubic, quadPts)) {
1161 addDegenerateLine(quadPts);
1166 fFoundTangents =
true;
1169 if (fFoundTangents) {
1170 ResultType resultType = this->compareQuadCubic(
cubic, quadPts);
1171 if (kQuad_ResultType == resultType) {
1172 SkPath*
path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1178 if (kDegenerate_ResultType == resultType) {
1180 addDegenerateLine(quadPts);
1190#if QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
1192 fRecursionDepth + 1));
1197 addDegenerateLine(quadPts);
1202 addDegenerateLine(quadPts);
1207 if (!this->cubicStroke(
cubic, &half)) {
1211 addDegenerateLine(quadPts);
1216 if (!this->cubicStroke(
cubic, &half)) {
1224 ResultType resultType = this->compareQuadConic(
conic, quadPts);
1225 if (kQuad_ResultType == resultType) {
1227 SkPath*
path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1231 if (kDegenerate_ResultType == resultType) {
1232 addDegenerateLine(quadPts);
1235#if QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
1237 fRecursionDepth + 1));
1241 addDegenerateLine(quadPts);
1246 if (!this->conicStroke(
conic, &half)) {
1250 if (!this->conicStroke(
conic, &half)) {
1258 ResultType resultType = this->compareQuadQuad(quad, quadPts);
1259 if (kQuad_ResultType == resultType) {
1261 SkPath*
path = fStrokeType == kOuter_StrokeType ? &fOuter : &fInner;
1265 if (kDegenerate_ResultType == resultType) {
1266 addDegenerateLine(quadPts);
1269#if QUAD_STROKE_APPROX_EXTENDED_DEBUGGING
1271 fRecursionDepth + 1));
1275 addDegenerateLine(quadPts);
1280 if (!this->quadStroke(quad, &half)) {
1284 if (!this->quadStroke(quad, &half)) {
1296 ReductionType reductionType = CheckCubicLinear(
cubic, reduction, &tangentPt);
1297 if (kPoint_ReductionType == reductionType) {
1304 if (kLine_ReductionType == reductionType) {
1308 if (kDegenerate_ReductionType <= reductionType && kDegenerate3_ReductionType >= reductionType) {
1309 this->
lineTo(reduction[0]);
1312 if (kDegenerate2_ReductionType <= reductionType) {
1313 this->
lineTo(reduction[1]);
1315 if (kDegenerate3_ReductionType == reductionType) {
1316 this->
lineTo(reduction[2]);
1319 fJoiner = saveJoiner;
1322 SkASSERT(kQuad_ReductionType == reductionType);
1323 SkVector normalAB, unitAB, normalCD, unitCD;
1324 if (!this->preJoinTo(*tangentPt, &normalAB, &unitAB,
false)) {
1331 for (
int index = 0; index <=
count; ++index) {
1334 this->init(kOuter_StrokeType, &quadPts, lastT, nextT);
1335 (void) this->cubicStroke(
cubic, &quadPts);
1336 this->init(kInner_StrokeType, &quadPts, lastT, nextT);
1337 (void) this->cubicStroke(
cubic, &quadPts);
1348 this->setCubicEndNormal(
cubic, normalAB, unitAB, &normalCD, &unitCD);
1350 this->postJoinTo(pt3, normalCD, unitCD);
1368 fWidth =
p.getStrokeWidth();
1369 fMiterLimit =
p.getStrokeMiter();
1371 fCap = (uint8_t)
p.getStrokeCap();
1372 fJoin = (uint8_t)
p.getStrokeJoin();
1378 fMiterLimit =
p.getStrokeMiter();
1380 fCap = (uint8_t)
p.getStrokeCap();
1381 fJoin = (uint8_t)
p.getStrokeJoin();
1392 fMiterLimit = miterLimit;
1414 fSwapWithSrc =
true;
1417 fSwapWithSrc =
false;
1447 bool isClosed =
false;
1449 if (
src.isRect(&
rect, &isClosed, &
dir) && isClosed) {
1452 if (
src.isInverseFillType()) {
1454 dst->toggleInverseFillType();
1463 src.isLastContourClosed() &&
src.isConvex();
1466 fResScale, ignoreCenter);
1472 switch (iter.
next(pts)) {
1477 stroker.
lineTo(pts[1], &iter);
1481 stroker.
quadTo(pts[1], pts[2]);
1489 stroker.
cubicTo(pts[1], pts[2], pts[3]);
1519 if (fDoFill && !ignoreCenter) {
1521 dst->reverseAddPath(
src);
1533 SkPoint pts[] = { 146.333328, 192.333328, 300.333344, 293.333344 };
1535 paint.setStrokeWidth(7);
1537 canvas->
drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY,
paint);
1541 if (2 ==
src.countPoints()) {
1542 dst->setIsConvex(
true);
1548 if (
src.isInverseFillType()) {
1550 dst->toggleInverseFillType();
1556 return gOpposite[(
int)
dir];
1581 path->addPoly(pts, 8,
true);
1596 if ((rw < 0) ^ (rh < 0)) {
1606 r.
outset(radius, radius);
1621 dst->addRoundRect(r, radius, radius,
dir);
1627 if (fWidth <
std::min(rw, rh) && !fDoFill) {
1629 r.
inset(radius, radius);
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
#define SkPaintDefaults_MiterLimit
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr bool SkIsNaN(T x)
static bool SkIsFinite(T x, Pack... values)
static constexpr float sk_ieee_float_divide(float numer, float denom)
void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
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])
SkScalar SkFindCubicCusp(const SkPoint src[4])
SkScalar SkFindQuadMaxCurvature(const SkPoint src[3])
int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3])
void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint *pt, SkVector *tangent)
int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[2])
#define SK_INIT_TO_AVOID_WARNING
void swap(sk_sp< T > &a, sk_sp< T > &b)
#define SkScalarInvert(x)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
#define SK_ScalarNearlyZero
static bool sharp_angle(const SkPoint quad[3])
static int intersect_quad_ray(const SkPoint line[2], const SkPoint quad[3], SkScalar roots[2])
#define DEBUG_CUBIC_RECURSION_TRACK_DEPTH(depth)
static bool cubic_in_line(const SkPoint cubic[4])
static bool degenerate_vector(const SkVector &v)
static bool set_normal_unitnormal(const SkPoint &before, const SkPoint &after, SkScalar scale, SkScalar radius, SkVector *normal, SkVector *unitNormal)
static SkScalar pt_to_line(const SkPoint &pt, const SkPoint &lineStart, const SkPoint &lineEnd)
static bool has_valid_tangent(const SkPath::Iter *iter)
#define STROKER_RESULT(resultType, depth, quadPts, format,...)
static bool quad_in_line(const SkPoint quad[3])
static bool conic_in_line(const SkConic &conic)
static const int kRecursiveLimits[]
static bool points_within_dist(const SkPoint &nearPt, const SkPoint &farPt, SkScalar limit)
static SkPathDirection reverse_direction(SkPathDirection dir)
static void addBevel(SkPath *path, const SkRect &r, const SkRect &outer, SkPathDirection dir)
@ kTangent_RecursiveLimit
#define STROKER_DEBUG_PARAMS(...)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr uint8_t SkToU8(S x)
AutoTmpPath(const SkPath &src, SkPath **dst)
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
@ kDefault_Cap
equivalent to kButt_Cap
@ kButt_Cap
no stroke extension
static constexpr int kCapCount
@ kStrokeAndFill_Style
sets to stroke and fill geometry
static constexpr int kJoinCount
@ kDefault_Join
equivalent to kMiter_Join
@ kMiter_Join
extends to miter limit
@ kBevel_Join
connects outside edges
static SkPathFirstDirection ComputeFirstDirection(const SkPath &)
bool hasOnlyMoveTo() const
void done(SkPath *dst, bool isLine)
SkPathStroker(const SkPath &src, SkScalar radius, SkScalar miterLimit, SkPaint::Cap, SkPaint::Join, SkScalar resScale, bool canIgnoreCenter)
SkScalar getResScale() const
void quadTo(const SkPoint &, const SkPoint &)
void conicTo(const SkPoint &, const SkPoint &, SkScalar weight)
bool isCurrentContourEmpty() const
void cubicTo(const SkPoint &, const SkPoint &, const SkPoint &)
void moveTo(const SkPoint &)
void lineTo(const SkPoint &, const SkPath::Iter *iter=nullptr)
Verb next(SkPoint pts[4])
SkScalar conicWeight() const
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
SkPath & moveTo(SkScalar x, SkScalar y)
bool getLastPt(SkPoint *lastPt) const
SkPath & lineTo(SkScalar x, SkScalar y)
SkPath & addPath(const SkPath &src, SkScalar dx, SkScalar dy, AddPathMode mode=kAppend_AddPathMode)
SkPath & setIsVolatile(bool isVolatile)
const SkRect & getBounds() const
void incReserve(int extraPtCount, int extraVerbCount=0, int extraConicCount=0)
static void RotateCCW(const SkPoint &src, SkPoint *dst)
static bool CanNormalize(SkScalar dx, SkScalar dy)
static SkScalar LengthSqd(const SkPoint &pt)
static bool EqualsWithinTolerance(const SkPoint &p1, const SkPoint &p2)
static SkScalar DistanceToSqd(const SkPoint &pt, const SkPoint &a)
SkPaint::Cap getCap() const
void strokePath(const SkPath &path, SkPath *) const
void setCap(SkPaint::Cap)
void setJoin(SkPaint::Join)
void strokeRect(const SkRect &rect, SkPath *result, SkPathDirection=SkPathDirection::kCW) const
SkPaint::Join getJoin() const
void setMiterLimit(SkScalar)
void(* JoinProc)(SkPath *outer, SkPath *inner, const SkVector &beforeUnitNormal, const SkPoint &pivot, const SkVector &afterUnitNormal, SkScalar radius, SkScalar invMiterLimit, bool prevIsLine, bool currIsLine)
static CapProc CapFactory(SkPaint::Cap)
static JoinProc JoinFactory(SkPaint::Join)
void(* CapProc)(SkPath *path, const SkPoint &pivot, const SkVector &normal, const SkPoint &stop, SkPath *otherPath)
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)
sk_sp< SkBlender > blender SkRect rect
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
SINT T dot(const Vec< N, T > &a, const Vec< N, T > &b)
static SkString join(const CommandLineFlags::StringArray &)
bool setLength(float length)
bool setNormalize(float x, float y)
float dot(const SkVector &vec) const
void set(float x, float y)
float cross(const SkVector &vec) const
void scale(float scale, SkPoint *dst) const
bool initWithEnd(SkQuadConstruct *parent)
bool initWithStart(SkQuadConstruct *parent)
bool init(SkScalar start, SkScalar end)
SkScalar fBottom
larger y-axis bounds
void inset(float dx, float dy)
SkScalar fLeft
smaller x-axis bounds
void outset(float dx, float dy)
SkScalar fRight
larger x-axis bounds
bool contains(SkScalar x, SkScalar y) const
constexpr float height() const
constexpr float width() const
SkScalar fTop
smaller y-axis bounds