Flutter Engine
The Flutter Engine
Public Member Functions | List of all members
SkPathStroker Class Reference

Public Member Functions

 SkPathStroker (const SkPath &src, SkScalar radius, SkScalar miterLimit, SkPaint::Cap, SkPaint::Join, SkScalar resScale, bool canIgnoreCenter)
 
bool hasOnlyMoveTo () const
 
SkPoint moveToPt () const
 
void moveTo (const SkPoint &)
 
void lineTo (const SkPoint &, const SkPath::Iter *iter=nullptr)
 
void quadTo (const SkPoint &, const SkPoint &)
 
void conicTo (const SkPoint &, const SkPoint &, SkScalar weight)
 
void cubicTo (const SkPoint &, const SkPoint &, const SkPoint &)
 
void close (bool isLine)
 
void done (SkPath *dst, bool isLine)
 
SkScalar getResScale () const
 
bool isCurrentContourEmpty () const
 

Detailed Description

Definition at line 167 of file SkStroke.cpp.

Constructor & Destructor Documentation

◆ SkPathStroker()

SkPathStroker::SkPathStroker ( const SkPath src,
SkScalar  radius,
SkScalar  miterLimit,
SkPaint::Cap  cap,
SkPaint::Join  join,
SkScalar  resScale,
bool  canIgnoreCenter 
)

Definition at line 385 of file SkStroke.cpp.

389 : fRadius(radius)
390 , fResScale(resScale)
391 , fCanIgnoreCenter(canIgnoreCenter) {
392
393 /* This is only used when join is miter_join, but we initialize it here
394 so that it is always defined, to fis valgrind warnings.
395 */
396 fInvMiterLimit = 0;
397
398 if (join == SkPaint::kMiter_Join) {
399 if (miterLimit <= SK_Scalar1) {
401 } else {
402 fInvMiterLimit = SkScalarInvert(miterLimit);
403 }
404 }
405 fCapper = SkStrokerPriv::CapFactory(cap);
407 fSegmentCount = -1;
408 fFirstOuterPtIndexInContour = 0;
409 fPrevIsLine = false;
410
411 // Need some estimate of how large our final result (fOuter)
412 // and our per-contour temp (fInner) will be, so we don't spend
413 // extra time repeatedly growing these arrays.
414 //
415 // 3x for result == inner + outer + join (swag)
416 // 1x for inner == 'wag' (worst contour length would be better guess)
417 fOuter.incReserve(src.countPoints() * 3);
418 fOuter.setIsVolatile(true);
419 fInner.incReserve(src.countPoints());
420 fInner.setIsVolatile(true);
421 // TODO : write a common error function used by stroking and filling
422 // The '4' below matches the fill scan converter's error term
423 fInvResScale = SkScalarInvert(resScale * 4);
424 fInvResScaleSquared = fInvResScale * fInvResScale;
425 fRecursionDepth = 0;
426}
#define SkScalarInvert(x)
Definition: SkScalar.h:73
#define SK_Scalar1
Definition: SkScalar.h:18
@ kMiter_Join
extends to miter limit
Definition: SkPaint.h:359
@ kBevel_Join
connects outside edges
Definition: SkPaint.h:361
SkPath & setIsVolatile(bool isVolatile)
Definition: SkPath.h:370
void incReserve(int extraPtCount, int extraVerbCount=0, int extraConicCount=0)
Definition: SkPath.cpp:678
static CapProc CapFactory(SkPaint::Cap)
static JoinProc JoinFactory(SkPaint::Join)
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741

Member Function Documentation

◆ close()

void SkPathStroker::close ( bool  isLine)
inline

Definition at line 182 of file SkStroke.cpp.

182{ this->finishContour(true, isLine); }

◆ conicTo()

void SkPathStroker::conicTo ( const SkPoint pt1,
const SkPoint pt2,
SkScalar  weight 
)

Definition at line 728 of file SkStroke.cpp.

728 {
729 const SkConic conic(fPrevPt, pt1, pt2, weight);
730 SkPoint reduction;
731 ReductionType reductionType = CheckConicLinear(conic, &reduction);
732 if (kPoint_ReductionType == reductionType) {
733 /* If the stroke consists of a moveTo followed by a degenerate curve, treat it
734 as if it were followed by a zero-length line. Lines without length
735 can have square and round end caps. */
736 this->lineTo(pt2);
737 return;
738 }
739 if (kLine_ReductionType == reductionType) {
740 this->lineTo(pt2);
741 return;
742 }
743 if (kDegenerate_ReductionType == reductionType) {
744 this->lineTo(reduction);
745 SkStrokerPriv::JoinProc saveJoiner = fJoiner;
747 this->lineTo(pt2);
748 fJoiner = saveJoiner;
749 return;
750 }
751 SkASSERT(kQuad_ReductionType == reductionType);
752 SkVector normalAB, unitAB, normalBC, unitBC;
753 if (!this->preJoinTo(pt1, &normalAB, &unitAB, false)) {
754 this->lineTo(pt2);
755 return;
756 }
757 SkQuadConstruct quadPts;
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);
764}
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kRound_Join
adds circle
Definition: SkPaint.h:360
void lineTo(const SkPoint &, const SkPath::Iter *iter=nullptr)
Definition: SkStroke.cpp:474
void(* JoinProc)(SkPath *outer, SkPath *inner, const SkVector &beforeUnitNormal, const SkPoint &pivot, const SkVector &afterUnitNormal, SkScalar radius, SkScalar invMiterLimit, bool prevIsLine, bool currIsLine)
Definition: SkStrokerPriv.h:36
AI float conic(float tolerance, const SkPoint pts[], float w, const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:287

◆ cubicTo()

void SkPathStroker::cubicTo ( const SkPoint pt1,
const SkPoint pt2,
const SkPoint pt3 
)

Definition at line 1291 of file SkStroke.cpp.

1292 {
1293 const SkPoint cubic[4] = { fPrevPt, pt1, pt2, pt3 };
1294 SkPoint reduction[3];
1295 const SkPoint* tangentPt;
1296 ReductionType reductionType = CheckCubicLinear(cubic, reduction, &tangentPt);
1297 if (kPoint_ReductionType == reductionType) {
1298 /* If the stroke consists of a moveTo followed by a degenerate curve, treat it
1299 as if it were followed by a zero-length line. Lines without length
1300 can have square and round end caps. */
1301 this->lineTo(pt3);
1302 return;
1303 }
1304 if (kLine_ReductionType == reductionType) {
1305 this->lineTo(pt3);
1306 return;
1307 }
1308 if (kDegenerate_ReductionType <= reductionType && kDegenerate3_ReductionType >= reductionType) {
1309 this->lineTo(reduction[0]);
1310 SkStrokerPriv::JoinProc saveJoiner = fJoiner;
1312 if (kDegenerate2_ReductionType <= reductionType) {
1313 this->lineTo(reduction[1]);
1314 }
1315 if (kDegenerate3_ReductionType == reductionType) {
1316 this->lineTo(reduction[2]);
1317 }
1318 this->lineTo(pt3);
1319 fJoiner = saveJoiner;
1320 return;
1321 }
1322 SkASSERT(kQuad_ReductionType == reductionType);
1323 SkVector normalAB, unitAB, normalCD, unitCD;
1324 if (!this->preJoinTo(*tangentPt, &normalAB, &unitAB, false)) {
1325 this->lineTo(pt3);
1326 return;
1327 }
1328 SkScalar tValues[2];
1329 int count = SkFindCubicInflections(cubic, tValues);
1330 SkScalar lastT = 0;
1331 for (int index = 0; index <= count; ++index) {
1332 SkScalar nextT = index < count ? tValues[index] : 1;
1333 SkQuadConstruct quadPts;
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);
1338 lastT = nextT;
1339 }
1341 if (cusp > 0) {
1342 SkPoint cuspLoc;
1343 SkEvalCubicAt(cubic, cusp, &cuspLoc, nullptr, nullptr);
1344 fCusper.addCircle(cuspLoc.fX, cuspLoc.fY, fRadius);
1345 }
1346 // emit the join even if one stroke succeeded but the last one failed
1347 // this avoids reversing an inner stroke with a partial path followed by another moveto
1348 this->setCubicEndNormal(cubic, normalAB, unitAB, &normalCD, &unitCD);
1349
1350 this->postJoinTo(pt3, normalCD, unitCD);
1351}
int count
Definition: FontMgrTest.cpp:50
void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint *loc, SkVector *tangent, SkVector *curvature)
Definition: SkGeometry.cpp:418
SkScalar SkFindCubicCusp(const SkPoint src[4])
int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[2])
Definition: SkGeometry.cpp:741
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1213
float SkScalar
Definition: extension.cpp:12
AI float cubic(float precision, const SkPoint pts[], const VectorXform &vectorXform=VectorXform())
Definition: WangsFormula.h:195
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165

◆ done()

void SkPathStroker::done ( SkPath dst,
bool  isLine 
)
inline

Definition at line 184 of file SkStroke.cpp.

184 {
185 this->finishContour(false, isLine);
186 dst->swap(fOuter);
187 }
dst
Definition: cp.py:12

◆ getResScale()

SkScalar SkPathStroker::getResScale ( ) const
inline

Definition at line 189 of file SkStroke.cpp.

189{ return fResScale; }

◆ hasOnlyMoveTo()

bool SkPathStroker::hasOnlyMoveTo ( ) const
inline

Definition at line 174 of file SkStroke.cpp.

174{ return 0 == fSegmentCount; }

◆ isCurrentContourEmpty()

bool SkPathStroker::isCurrentContourEmpty ( ) const
inline

Definition at line 191 of file SkStroke.cpp.

191 {
192 return fInner.isZeroLengthSincePoint(0) &&
193 fOuter.isZeroLengthSincePoint(fFirstOuterPtIndexInContour);
194 }

◆ lineTo()

void SkPathStroker::lineTo ( const SkPoint currPt,
const SkPath::Iter iter = nullptr 
)

Definition at line 474 of file SkStroke.cpp.

474 {
475 bool teenyLine = SkPointPriv::EqualsWithinTolerance(fPrevPt, currPt, SK_ScalarNearlyZero * fInvResScale);
476 if (SkStrokerPriv::CapFactory(SkPaint::kButt_Cap) == fCapper && teenyLine) {
477 return;
478 }
479 if (teenyLine && (fJoinCompleted || (iter && has_valid_tangent(iter)))) {
480 return;
481 }
482 SkVector normal, unitNormal;
483
484 if (!this->preJoinTo(currPt, &normal, &unitNormal, true)) {
485 return;
486 }
487 this->line_to(currPt, normal);
488 this->postJoinTo(currPt, normal, unitNormal);
489}
#define SK_ScalarNearlyZero
Definition: SkScalar.h:99
static bool has_valid_tangent(const SkPath::Iter *iter)
Definition: SkStroke.cpp:442
@ kButt_Cap
no stroke extension
Definition: SkPaint.h:334
static bool EqualsWithinTolerance(const SkPoint &p1, const SkPoint &p2)
Definition: SkPointPriv.h:54

◆ moveTo()

void SkPathStroker::moveTo ( const SkPoint pt)

Definition at line 428 of file SkStroke.cpp.

428 {
429 if (fSegmentCount > 0) {
430 this->finishContour(false, false);
431 }
432 fSegmentCount = 0;
433 fFirstPt = fPrevPt = pt;
434 fJoinCompleted = false;
435}

◆ moveToPt()

SkPoint SkPathStroker::moveToPt ( ) const
inline

Definition at line 175 of file SkStroke.cpp.

175{ return fFirstPt; }

◆ quadTo()

void SkPathStroker::quadTo ( const SkPoint pt1,
const SkPoint pt2 
)

Definition at line 766 of file SkStroke.cpp.

766 {
767 const SkPoint quad[3] = { fPrevPt, pt1, pt2 };
768 SkPoint reduction;
769 ReductionType reductionType = CheckQuadLinear(quad, &reduction);
770 if (kPoint_ReductionType == reductionType) {
771 /* If the stroke consists of a moveTo followed by a degenerate curve, treat it
772 as if it were followed by a zero-length line. Lines without length
773 can have square and round end caps. */
774 this->lineTo(pt2);
775 return;
776 }
777 if (kLine_ReductionType == reductionType) {
778 this->lineTo(pt2);
779 return;
780 }
781 if (kDegenerate_ReductionType == reductionType) {
782 this->lineTo(reduction);
783 SkStrokerPriv::JoinProc saveJoiner = fJoiner;
785 this->lineTo(pt2);
786 fJoiner = saveJoiner;
787 return;
788 }
789 SkASSERT(kQuad_ReductionType == reductionType);
790 SkVector normalAB, unitAB, normalBC, unitBC;
791 if (!this->preJoinTo(pt1, &normalAB, &unitAB, false)) {
792 this->lineTo(pt2);
793 return;
794 }
795 SkQuadConstruct quadPts;
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);
801
802 this->postJoinTo(pt2, normalBC, unitBC);
803}

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