42#include <initializer_list>
50 if (
const auto* lp = this->originalPathForListeners()) {
51 return lp->getGenerationID();
89 static constexpr int kRes = 2000;
91 static constexpr int kTol = 2;
92 static_assert(kRes % 4 == 0);
95 surface->getCanvas()->clear(0x0);
100 surface->getCanvas()->concat(matrix);
103 surface->getCanvas()->drawPath(path, whitePaint);
105 surface->getCanvas()->peekPixels(&pixmap);
106#if defined(SK_BUILD_FOR_WIN)
108 const uint8_t* kZeros =
reinterpret_cast<uint8_t*
>(calloc(kRes, 1));
110 static constexpr uint8_t kZeros[kRes] = {0};
112 for (
int y = 0;
y < kRes; ++
y) {
113 const uint8_t* row = pixmap.
addr8(0,
y);
114 if (0 != memcmp(kZeros, row, kRes)) {
118#ifdef SK_BUILD_FOR_WIN
119 free(
const_cast<uint8_t*
>(kZeros));
137 const Key& keyA,
const Key& keyB) {
149 unsigned startA = ~0U, startB = ~0U;
150 bool invertedA =
true, invertedB =
true;
152 bool aIsRRect =
a.asRRect(&rrectA, &dirA, &startA, &invertedA);
153 bool bIsRRect =
b.asRRect(&rrectB, &dirB, &startB, &invertedB);
154 bool aHasPE =
a.style().hasPathEffect();
155 bool bHasPE =
b.style().hasPathEffect();
156 bool allowSameRRectButDiffStartAndDir = (aIsRRect && bIsRRect) && (aHasPE != bHasPE);
158 bool allowedClosednessDiff = (
a.style().isSimpleFill() !=
b.style().isSimpleFill());
165 bool ignoreInversenessDifference =
false;
171 ignoreInversenessDifference = (canDropInverse1 != canDropInverse2);
173 bool ignoreWindingVsEvenOdd =
false;
178 if (aCanChange != bCanChange) {
179 ignoreWindingVsEvenOdd =
true;
182 if (allowSameRRectButDiffStartAndDir) {
185 REPORTER_ASSERT(r, ignoreInversenessDifference || invertedA == invertedB);
191 if (ignoreInversenessDifference) {
195 if (ignoreWindingVsEvenOdd) {
201 if (!ignoreInversenessDifference && !ignoreWindingVsEvenOdd) {
206 if (allowedClosednessDiff) {
219 REPORTER_ASSERT(r, ignoreInversenessDifference || invertedA == invertedB);
223 REPORTER_ASSERT(r, allowedClosednessDiff ||
a.knownToBeClosed() ==
b.knownToBeClosed());
225 REPORTER_ASSERT(r, allowedClosednessDiff ||
a.knownToBeConvex() ==
b.knownToBeConvex());
226 if (
a.knownToBeConvex()) {
229 if (
b.knownToBeConvex()) {
235 SkPoint pts[4] {{0, 0,}, {0, 0}, {0, 0}, {0, 0}} ;
236 bool invertedLine[2] {
true,
true};
237 REPORTER_ASSERT(r,
a.asLine(pts, &invertedLine[0]) ==
b.asLine(pts + 2, &invertedLine[1]));
242 if (
a.style().hasNonDashPathEffect() ==
b.style().hasNonDashPathEffect() &&
243 a.style().isDashed() ==
b.style().isDashed()) {
245 b.mayBeInverseFilledAfterStyling());
247 if (
a.asLine(
nullptr,
nullptr)) {
249 REPORTER_ASSERT(r, ignoreInversenessDifference || invertedLine[0] == invertedLine[1]);
253 REPORTER_ASSERT(r, ignoreInversenessDifference ||
a.inverseFilled() ==
b.inverseFilled());
259 bool baseIsNonVolatilePath =
base.testingOnly_isNonVolatilePath();
262 bool fullIsPath =
full.testingOnly_isPath();
266 uint32_t baseID =
base.testingOnly_getOriginalGenerationID();
269 uint32_t fullID =
full.testingOnly_getOriginalGenerationID();
291 if (baseIsNonVolatilePath) {
295 if (peStrokeIsPath) {
300 if (baseIsNonVolatilePath && peStrokeIsPath) {
324 make_key(&noninvertedKey, noninverted);
326 if (invertedKey.
size() || noninvertedKey.
size()) {
342 make_key(&doubleFlipKey, doubleFlip);
345 if (preserveKey.
size() && !doubleFlipKey.
size()) {
366 virtual bool fillChangesGeom()
const {
return false; }
367 virtual bool strokeIsConvertedToFill()
const {
return false; }
368 virtual bool strokeAndFillIsConvertedToFill(
const SkPaint&)
const {
return false; }
370 virtual bool isNonPath(
const SkPaint&
paint)
const {
return true; }
373class RectGeo :
public Geo {
387 bool strokeAndFillIsConvertedToFill(
const SkPaint&
paint)
const override {
399class RRectGeo :
public Geo {
409 path.addRRect(fRRect);
413 bool strokeAndFillIsConvertedToFill(
const SkPaint&
paint)
const override {
425class ArcGeo :
public Geo {
431 , fUseCenter(useCenter) {}
445 bool isNonPath(
const SkPaint&
paint)
const override {
return false; }
454class PathGeo :
public Geo {
456 enum class Invert {
kNo,
kYes };
460 if (Invert::kYes ==
invert) {
476 bool fillChangesGeom()
const override {
478 return this->isUnclosedRect() ||
fPath.
isLine(
nullptr);
481 bool strokeIsConvertedToFill()
const override {
482 return this->isAxisAlignedLine();
485 bool strokeAndFillIsConvertedToFill(
const SkPaint&
paint)
const override {
487 if (this->isAxisAlignedLine()) {
495 return RectGeo(rect).strokeAndFillIsConvertedToFill(
paint);
505 bool isAxisAlignedLine()
const {
510 return pts[0].
fX == pts[1].
fX || pts[0].
fY == pts[1].
fY;
513 bool isUnclosedRect()
const {
515 return fPath.
isRect(
nullptr, &closed,
nullptr) && !closed;
521class RRectPathGeo :
public PathGeo {
523 enum class RRectForStroke {
kNo,
kYes };
525 RRectPathGeo(
const SkPath& path,
const SkRRect& equivalentRRect, RRectForStroke rrectForStroke,
529 , fRRectForStroke(rrectForStroke) {}
531 RRectPathGeo(
const SkPath& path,
const SkRect& equivalentRect, RRectForStroke rrectForStroke,
533 : RRectPathGeo(
path,
SkRRect::MakeRect(equivalentRect), rrectForStroke,
invert) {}
546 RRectForStroke fRRectForStroke;
557 template <
typename... ShapeArgs>
568 struct SelfExpectations {
576 enum ComparisonExpecation {
577 kAllDifferent_ComparisonExpecation,
578 kSameUpToPE_ComparisonExpecation,
579 kSameUpToStroke_ComparisonExpecation,
580 kAllSame_ComparisonExpecation,
586 const GrStyledShape& appliedPathEffectShape()
const {
return *fAppliedPE; }
587 const GrStyledShape& appliedFullStyleShape()
const {
return *fAppliedFull; }
590 const Key& baseKey()
const {
return fBaseKey; }
591 const Key& appliedPathEffectKey()
const {
return fAppliedPEKey; }
592 const Key& appliedFullStyleKey()
const {
return fAppliedFullKey; }
593 const Key& appliedPathEffectThenStrokeKey()
const {
return fAppliedPEThenStrokeKey; }
605 if (
path.isEmpty()) {
615 fAppliedPE = std::make_unique<GrStyledShape>();
616 fAppliedPEThenStroke = std::make_unique<GrStyledShape>();
617 fAppliedFull = std::make_unique<GrStyledShape>();
620 *fAppliedPEThenStroke =
625 make_key(&fAppliedPEKey, *fAppliedPE);
626 make_key(&fAppliedPEThenStrokeKey, *fAppliedPEThenStroke);
627 make_key(&fAppliedFullKey, *fAppliedFull);
637 fAppliedPEThenStroke->asPath(&
a);
638 fAppliedFull->asPath(&
b);
645 if (fAppliedPE->asRRect(
nullptr,
nullptr,
nullptr,
nullptr)) {
650 REPORTER_ASSERT(r, fAppliedFull->isEmpty() == fAppliedPEThenStroke->isEmpty());
653 fBase->asPath(&path);
656 fAppliedPE->asPath(&path);
659 fAppliedFull->asPath(&path);
663 CheckBounds(r, *fBase, fBase->bounds());
664 CheckBounds(r, *fAppliedPE, fAppliedPE->bounds());
665 CheckBounds(r, *fAppliedPEThenStroke, fAppliedPEThenStroke->bounds());
666 CheckBounds(r, *fAppliedFull, fAppliedFull->bounds());
667 SkRect styledBounds = fBase->styledBounds();
668 CheckBounds(r, *fAppliedFull, styledBounds);
669 styledBounds = fAppliedPE->styledBounds();
670 CheckBounds(r, *fAppliedFull, styledBounds);
677 fBase->asPath(&preStyle);
679 if (fBase->style().applyPathEffectToPath(&postPathEffect, &postPEStrokeRec, preStyle,
687 fAppliedPE->asPath(&testPath);
689 REPORTER_ASSERT(r, postPEStrokeRec.hasEqualEffect(fAppliedPE->style().strokeRec()));
692 if (fBase->style().applyToPath(&postAllStyle, &fillOrHairline, preStyle,
scale)) {
694 fAppliedFull->asPath(&testPath);
695 if (fBase->style().hasPathEffect()) {
719 std::unique_ptr<GrStyledShape> fBase;
720 std::unique_ptr<GrStyledShape> fAppliedPE;
721 std::unique_ptr<GrStyledShape> fAppliedPEThenStroke;
722 std::unique_ptr<GrStyledShape> fAppliedFull;
726 Key fAppliedPEThenStrokeKey;
733 if (expectations.fPEHasEffect) {
738 if (expectations.fStrokeApplies && expectations.fPEHasValidKey) {
746 fAppliedPE->asPath(&
b);
748 if (expectations.fStrokeApplies) {
757 ComparisonExpecation expectation)
const {
759 switch (expectation) {
760 case kAllDifferent_ComparisonExpecation:
765 case kSameUpToPE_ComparisonExpecation:
770 case kSameUpToStroke_ComparisonExpecation:
772 check_equivalence(r, *fAppliedPE, *that.fAppliedPE, fAppliedPEKey, that.fAppliedPEKey);
775 case kAllSame_ComparisonExpecation:
777 check_equivalence(r, *fAppliedPE, *that.fAppliedPE, fAppliedPEKey, that.fAppliedPEKey);
779 that.fAppliedFullKey);
786 static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f };
787 static const SkScalar kPhase = 0.75;
792 static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0};
798template <
typename... Args>
800 return std::make_unique<TestCase>( std::forward<Args>(
args)... );
806 TestCase::SelfExpectations expectations;
810 expectations.fPEHasEffect =
false;
811 expectations.fPEHasValidKey =
false;
812 expectations.fStrokeApplies =
false;
813 fillCase.testExpectations(
reporter, expectations);
816 ->compare(
reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
824 expectations.fPEHasValidKey =
true;
825 expectations.fPEHasEffect =
false;
826 expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
827 stroke2RoundBevelCase.testExpectations(
reporter, expectations);
829 ->compare(
reporter, stroke2RoundBevelCase, TestCase::kAllSame_ComparisonExpecation);
831 SkPaint stroke2RoundBevelDash = stroke2RoundBevel;
834 expectations.fPEHasValidKey =
true;
835 expectations.fPEHasEffect =
true;
836 expectations.fStrokeApplies =
true;
837 stroke2RoundBevelDashCase.testExpectations(
reporter, expectations);
839 ->compare(
reporter, stroke2RoundBevelDashCase, TestCase::kAllSame_ComparisonExpecation);
841 if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
842 fillCase.compare(
reporter, stroke2RoundBevelCase,
843 TestCase::kAllDifferent_ComparisonExpecation);
844 fillCase.compare(
reporter, stroke2RoundBevelDashCase,
845 TestCase::kAllDifferent_ComparisonExpecation);
847 fillCase.compare(
reporter, stroke2RoundBevelCase,
848 TestCase::kSameUpToStroke_ComparisonExpecation);
849 fillCase.compare(
reporter, stroke2RoundBevelDashCase,
850 TestCase::kSameUpToPE_ComparisonExpecation);
852 if (geo.strokeIsConvertedToFill()) {
853 stroke2RoundBevelCase.compare(
reporter, stroke2RoundBevelDashCase,
854 TestCase::kAllDifferent_ComparisonExpecation);
856 stroke2RoundBevelCase.compare(
reporter, stroke2RoundBevelDashCase,
857 TestCase::kSameUpToPE_ComparisonExpecation);
861 SkPaint stroke2RoundBevelAndFill = stroke2RoundBevel;
863 TestCase stroke2RoundBevelAndFillCase(geo, stroke2RoundBevelAndFill,
reporter);
864 expectations.fPEHasValidKey =
true;
865 expectations.fPEHasEffect =
false;
866 expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
867 stroke2RoundBevelAndFillCase.testExpectations(
reporter, expectations);
869 reporter, stroke2RoundBevelAndFillCase, TestCase::kAllSame_ComparisonExpecation);
871 SkPaint stroke2RoundBevelAndFillDash = stroke2RoundBevelDash;
873 TestCase stroke2RoundBevelAndFillDashCase(geo, stroke2RoundBevelAndFillDash,
reporter);
874 expectations.fPEHasValidKey =
true;
875 expectations.fPEHasEffect =
false;
876 expectations.fStrokeApplies = !geo.strokeIsConvertedToFill();
877 stroke2RoundBevelAndFillDashCase.testExpectations(
reporter, expectations);
879 reporter, stroke2RoundBevelAndFillDashCase, TestCase::kAllSame_ComparisonExpecation);
880 stroke2RoundBevelAndFillDashCase.compare(
reporter, stroke2RoundBevelAndFillCase,
881 TestCase::kAllSame_ComparisonExpecation);
889 if (geo.fillChangesGeom()) {
890 hairlineCase.compare(
reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
892 hairlineCase.compare(
reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
910 fillCase1.compare(
reporter, fillCase2, TestCase::kAllSame_ComparisonExpecation);
918 hairlineCase1.compare(
reporter, hairlineCase2, TestCase::kAllSame_ComparisonExpecation);
926 if (geo.strokeIsConvertedToFill()) {
928 strokeCase1.compare(
reporter, strokeCase2, TestCase::kAllSame_ComparisonExpecation);
930 strokeCase1.compare(
reporter, strokeCase2, TestCase::kSameUpToStroke_ComparisonExpecation);
938 strokeDashCase1.compare(
reporter, strokeDashCase2,
939 TestCase::kSameUpToPE_ComparisonExpecation);
942 SkPaint strokeAndFill = stroke;
946 SkPaint strokeAndFillDash = strokeDash;
954 if (geo.strokeAndFillIsConvertedToFill(strokeAndFillDash)) {
956 strokeAndFillCase1.compare(
reporter, strokeAndFillCase2,
957 TestCase::kAllSame_ComparisonExpecation);
958 strokeAndFillDashCase1.compare(
reporter, strokeAndFillDashCase2,
959 TestCase::kAllSame_ComparisonExpecation);
961 strokeAndFillCase1.compare(
reporter, strokeAndFillCase2,
962 TestCase::kSameUpToStroke_ComparisonExpecation);
964 strokeAndFillDashCase1.compare(
reporter, strokeAndFillCase1,
965 TestCase::kAllSame_ComparisonExpecation);
966 strokeAndFillDashCase2.compare(
reporter, strokeAndFillCase2,
967 TestCase::kAllSame_ComparisonExpecation);
972 std::function<
void(
SkPaint*, T)> setter, T
a, T
b,
973 bool paramAffectsStroke,
974 bool paramAffectsDashAndStroke) {
988 if (paramAffectsStroke) {
991 if (geo.strokeIsConvertedToFill()) {
992 strokeACase.compare(
reporter, strokeBCase,
993 TestCase::kAllDifferent_ComparisonExpecation);
995 strokeACase.compare(
reporter, strokeBCase,
996 TestCase::kSameUpToStroke_ComparisonExpecation);
999 strokeACase.compare(
reporter, strokeBCase, TestCase::kAllSame_ComparisonExpecation);
1002 SkPaint strokeAndFillA = strokeA;
1003 SkPaint strokeAndFillB = strokeB;
1008 if (paramAffectsStroke) {
1011 if (geo.strokeAndFillIsConvertedToFill(strokeAndFillA) ||
1012 geo.strokeAndFillIsConvertedToFill(strokeAndFillB)) {
1013 strokeAndFillACase.compare(
reporter, strokeAndFillBCase,
1014 TestCase::kAllDifferent_ComparisonExpecation);
1016 strokeAndFillACase.compare(
reporter, strokeAndFillBCase,
1017 TestCase::kSameUpToStroke_ComparisonExpecation);
1020 strokeAndFillACase.compare(
reporter, strokeAndFillBCase,
1021 TestCase::kAllSame_ComparisonExpecation);
1025 SkPaint fillA = strokeA, fillB = strokeB;
1030 fillACase.compare(
reporter, fillBCase, TestCase::kAllSame_ComparisonExpecation);
1034 SkPaint dashA = strokeA, dashB = strokeB;
1039 if (paramAffectsDashAndStroke) {
1040 dashACase.compare(
reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1042 dashACase.compare(
reporter, dashBCase, TestCase::kAllSame_ComparisonExpecation);
1046template <
typename T>
1048 std::function<
void(
SkPaint*, T)> setter, T
a, T
b) {
1060 bool affectsDashAndStroke =
true;
1061 test_stroke_param_impl<SkPaint::Cap>(
1067 affectsDashAndStroke);
1084 test_stroke_param_impl<SkPaint::Join>(
1089 affectsStroke,
true);
1095 p->setStrokeMiter(miter);
1100 p->setStrokeMiter(miter);
1111 test_stroke_param_impl<SkScalar>(
1114 setMiterJoinAndLimit,
1121 test_stroke_param_impl<SkScalar>(
1124 setOtherJoinAndLimit,
1139 dashFillCase.compare(
reporter, fillCase, TestCase::kAllSame_ComparisonExpecation);
1163 nullDashCase.compare(
reporter, strokeCase, TestCase::kAllSame_ComparisonExpecation);
1166 if (geo.fillChangesGeom() || geo.strokeIsConvertedToFill()) {
1167 nullDashCase.compare(
reporter, fillCase, TestCase::kAllDifferent_ComparisonExpecation);
1169 nullDashCase.compare(
reporter, fillCase, TestCase::kSameUpToStroke_ComparisonExpecation);
1172 if (geo.strokeIsConvertedToFill()) {
1173 nullDashCase.compare(
reporter, dashCase, TestCase::kAllDifferent_ComparisonExpecation);
1175 nullDashCase.compare(
reporter, dashCase, TestCase::kSameUpToPE_ComparisonExpecation);
1186 static const SkRRect& RRect() {
1192 Factory
getFactory()
const override {
return nullptr; }
1193 const char*
getTypeName()
const override {
return nullptr; }
1199 dst->addRRect(RRect());
1205 *bounds = RRect().getBounds();
1211 RRectPathEffect() {}
1229 if (geo.fillChangesGeom()) {
1230 fillGeoCase.compare(
reporter, geoPECase, TestCase::kAllDifferent_ComparisonExpecation);
1231 fillGeoCase.compare(
reporter, geoPEStrokeCase,
1232 TestCase::kAllDifferent_ComparisonExpecation);
1234 fillGeoCase.compare(
reporter, geoPECase, TestCase::kSameUpToPE_ComparisonExpecation);
1235 fillGeoCase.compare(
reporter, geoPEStrokeCase, TestCase::kSameUpToPE_ComparisonExpecation);
1237 geoPECase.compare(
reporter, geoPEStrokeCase,
1238 TestCase::kSameUpToStroke_ComparisonExpecation);
1267 rrectStrokeCase.appliedFullStyleKey());
1277 Factory
getFactory()
const override {
return nullptr; }
1278 const char*
getTypeName()
const override {
return nullptr; }
1285 for (
int i = 0; i < 100; ++i) {
1298 AddLineTosPathEffect() {}
1309 TestCase::SelfExpectations expectations;
1310 expectations.fPEHasEffect =
true;
1311 expectations.fPEHasValidKey =
false;
1312 expectations.fStrokeApplies =
true;
1313 geoPEStrokeCase.testExpectations(
reporter, expectations);
1325 Factory
getFactory()
const override {
return nullptr; }
1326 const char*
getTypeName()
const override {
return nullptr; }
1338 MakeHairlinePathEffect() {}
1348 peCase.baseShape().asPath(&
a);
1349 peCase.appliedPathEffectShape().asPath(&
b);
1350 peCase.appliedFullStyleShape().asPath(&c);
1351 if (geo.isNonPath(pe)) {
1363 a.setFillType(
b.getFillType());
1377 SkPath vPath = geo.path();
1387 if (geo.isNonPath(dashAndStroke)) {
1391 volatileCase.compare(
reporter, nonVolatileCase, TestCase::kAllSame_ComparisonExpecation);
1410 Factory
getFactory()
const override {
return nullptr; }
1411 const char*
getTypeName()
const override {
return nullptr; }
1417 dst->toggleInverseFillType();
1423 *bounds = { 0, 0, 0, 0 };
1440 Key invertedEmptyKey;
1441 make_key(&invertedEmptyKey, invertedEmptyShape);
1485 geoPEInvertStrokeCase.appliedPathEffectThenStrokeKey() == invertedEmptyKey);
1499 Factory
getFactory()
const override {
return nullptr; }
1500 const char*
getTypeName()
const override {
return nullptr; }
1509 FailurePathEffect() {}
1537 fillCase.appliedPathEffectShape().asPath(&
a);
1538 peCase.appliedPathEffectShape().asPath(&
b);
1541 fillCase.appliedFullStyleShape().asPath(&
a);
1542 peCase.appliedFullStyleShape().asPath(&
b);
1545 strokeCase.appliedPathEffectShape().asPath(&
a);
1546 peStrokeCase.appliedPathEffectShape().asPath(&
b);
1549 strokeCase.appliedFullStyleShape().asPath(&
a);
1550 peStrokeCase.appliedFullStyleShape().asPath(&
b);
1556 SkPath invertedEmptyPath;
1574 const Key& emptyKey = fillEmptyCase.baseKey();
1576 const Key& inverseEmptyKey = fillInvertedEmptyCase.baseKey();
1578 TestCase::SelfExpectations expectations;
1579 expectations.fStrokeApplies =
false;
1580 expectations.fPEHasEffect =
false;
1582 fillEmptyCase.testExpectations(
reporter, expectations);
1583 fillInvertedEmptyCase.testExpectations(
reporter, expectations);
1592 strokeEmptyCase.compare(
reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1594 strokeInvertedEmptyCase.compare(
reporter, fillInvertedEmptyCase,
1595 TestCase::kAllSame_ComparisonExpecation);
1603 dashAndStrokeEmptyCase.compare(
reporter, fillEmptyCase,
1604 TestCase::kAllSame_ComparisonExpecation);
1605 TestCase dashAndStrokeInvertexEmptyCase(
reporter, invertedEmptyPath, dashAndStroke);
1607 dashAndStrokeInvertexEmptyCase.compare(
reporter, fillEmptyCase,
1608 TestCase::kAllSame_ComparisonExpecation);
1617 fillEmptyRRectCase.compare(
reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1620 strokeEmptyRRectCase.compare(
reporter, strokeEmptyCase,
1621 TestCase::kAllSame_ComparisonExpecation);
1624 dashAndStrokeEmptyRRectCase.compare(
reporter, fillEmptyCase,
1625 TestCase::kAllSame_ComparisonExpecation);
1628 static constexpr int kStart = 0;
1631 fillInvertedEmptyRRectCase.compare(
reporter, fillInvertedEmptyCase,
1632 TestCase::kAllSame_ComparisonExpecation);
1634 TestCase strokeInvertedEmptyRRectCase(
reporter, emptyRRect, kDir, kStart,
true,
1636 strokeInvertedEmptyRRectCase.compare(
reporter, strokeInvertedEmptyCase,
1637 TestCase::kAllSame_ComparisonExpecation);
1639 TestCase dashAndStrokeEmptyInvertedRRectCase(
reporter, emptyRRect, kDir, kStart,
true,
1641 dashAndStrokeEmptyInvertedRRectCase.compare(
reporter, fillEmptyCase,
1642 TestCase::kAllSame_ComparisonExpecation);
1647 fillEmptyRectCase.compare(
reporter, fillEmptyCase, TestCase::kAllSame_ComparisonExpecation);
1650 dashAndStrokeEmptyRectCase.compare(
reporter, fillEmptyCase,
1651 TestCase::kAllSame_ComparisonExpecation);
1654 kStart,
true,
GrStyle(dashAndStroke));
1656 dashAndStrokeEmptyInvertedRectCase.compare(
reporter, fillEmptyCase,
1657 TestCase::kAllSame_ComparisonExpecation);
1665 return (
s + 1) & 0b110;
1685 strokeRecs[
kStroke].setStrokeStyle(2.f);
1686 strokeRecs[
kHairline].setHairlineStyle();
1687 strokeRecs[kStrokeAndFill].setStrokeStyle(3.f,
true);
1693 static constexpr size_t kStyleCnt = std::size(strokeRecs);
1695 auto index = [](
bool inverted,
1700 return inverted * (2 * 8 * kStyleCnt * 2) +
1701 (
int)dir * ( 8 * kStyleCnt * 2) +
1702 start * ( kStyleCnt * 2) +
1707 const int cnt = index(
true, kSecondDirection, 7,
static_cast<Style
>(kStyleCnt - 1),
true) + 1;
1709 for (
bool inverted : {
false,
true}) {
1713 for (
bool dash : {
false,
true}) {
1715 shapes[index(inverted, dir,
start, style, dash)] =
1717 GrStyle(strokeRecs[style], std::move(pe)));
1727 static constexpr unsigned kExamplesStart = 0;
1728 const GrStyledShape& exampleFillCase = shapes[index(
false, kExamplesDir, kExamplesStart,
kFill,
1730 Key exampleFillCaseKey;
1731 make_key(&exampleFillCaseKey, exampleFillCase);
1733 const GrStyledShape& exampleStrokeAndFillCase = shapes[index(
false, kExamplesDir,
1734 kExamplesStart, kStrokeAndFill,
false)];
1735 Key exampleStrokeAndFillCaseKey;
1736 make_key(&exampleStrokeAndFillCaseKey, exampleStrokeAndFillCase);
1738 const GrStyledShape& exampleInvFillCase = shapes[index(
true, kExamplesDir,
1739 kExamplesStart,
kFill,
false)];
1740 Key exampleInvFillCaseKey;
1741 make_key(&exampleInvFillCaseKey, exampleInvFillCase);
1743 const GrStyledShape& exampleInvStrokeAndFillCase = shapes[index(
true, kExamplesDir,
1744 kExamplesStart, kStrokeAndFill,
1746 Key exampleInvStrokeAndFillCaseKey;
1747 make_key(&exampleInvStrokeAndFillCaseKey, exampleInvStrokeAndFillCase);
1749 const GrStyledShape& exampleStrokeCase = shapes[index(
false, kExamplesDir, kExamplesStart,
1751 Key exampleStrokeCaseKey;
1752 make_key(&exampleStrokeCaseKey, exampleStrokeCase);
1754 const GrStyledShape& exampleInvStrokeCase = shapes[index(
true, kExamplesDir, kExamplesStart,
1756 Key exampleInvStrokeCaseKey;
1757 make_key(&exampleInvStrokeCaseKey, exampleInvStrokeCase);
1759 const GrStyledShape& exampleHairlineCase = shapes[index(
false, kExamplesDir, kExamplesStart,
1761 Key exampleHairlineCaseKey;
1762 make_key(&exampleHairlineCaseKey, exampleHairlineCase);
1764 const GrStyledShape& exampleInvHairlineCase = shapes[index(
true, kExamplesDir, kExamplesStart,
1766 Key exampleInvHairlineCaseKey;
1767 make_key(&exampleInvHairlineCaseKey, exampleInvHairlineCase);
1772 unsigned queryStart = ~0U;
1773 bool queryInverted =
true;
1831 REPORTER_ASSERT(r, exampleFillCaseKey == exampleStrokeAndFillCaseKey);
1832 REPORTER_ASSERT(r, exampleFillCaseKey != exampleInvStrokeAndFillCaseKey);
1837 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvFillCaseKey);
1838 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvStrokeCaseKey);
1839 REPORTER_ASSERT(r, exampleInvStrokeAndFillCaseKey == exampleInvHairlineCaseKey);
1841 for (
bool inverted : {
false,
true}) {
1844 for (
bool dash : {
false,
true}) {
1851 kStrokeAndFill, dash)];
1852 Key strokeAndFillCaseKey;
1853 make_key(&strokeAndFillCaseKey, strokeAndFillCase);
1860 TestCase b(inverted ? exampleInvFillCase : exampleFillCase, r);
1862 TestCase d(inverted ? exampleInvStrokeAndFillCase
1863 : exampleStrokeAndFillCase, r);
1864 a.compare(r,
b, TestCase::kAllSame_ComparisonExpecation);
1865 c.compare(r,
d, TestCase::kAllSame_ComparisonExpecation);
1900 e.compare(r, f, TestCase::kSameUpToPE_ComparisonExpecation);
1901 g.compare(r,
h, TestCase::kSameUpToPE_ComparisonExpecation);
1903 e.compare(r, f, TestCase::kAllDifferent_ComparisonExpecation);
1904 g.compare(r,
h, TestCase::kAllDifferent_ComparisonExpecation);
1907 TestCase f(inverted ? exampleInvStrokeCase : exampleStrokeCase, r);
1908 TestCase h(inverted ? exampleInvHairlineCase : exampleHairlineCase, r);
1911 e.compare(r, f, TestCase::kAllSame_ComparisonExpecation);
1912 g.compare(r,
h, TestCase::kAllSame_ComparisonExpecation);
1928 SkPath invLineAB = lineAB;
1944 fillAB.compare(r, fillEmpty, TestCase::kAllSame_ComparisonExpecation);
1948 path.toggleInverseFillType();
1949 TestCase fillEmptyInverted(r, path, fill);
1950 TestCase fillABInverted(r, invLineAB, fill);
1951 fillABInverted.compare(r, fillEmptyInverted, TestCase::kAllSame_ComparisonExpecation);
1952 REPORTER_ASSERT(r, !fillABInverted.baseShape().asLine(
nullptr,
nullptr));
1954 TestCase strokeAB(r, lineAB, stroke);
1955 TestCase strokeBA(r, lineBA, stroke);
1956 TestCase strokeAC(r, lineAC, stroke);
1958 TestCase hairlineAB(r, lineAB, hairline);
1959 TestCase hairlineBA(r, lineBA, hairline);
1960 TestCase hairlineAC(r, lineAC, hairline);
1966 strokeAB.compare(r, fillAB, TestCase::kAllDifferent_ComparisonExpecation);
1968 strokeAB.compare(r, strokeBA, TestCase::kAllSame_ComparisonExpecation);
1969 strokeAB.compare(r, strokeAC, TestCase::kAllDifferent_ComparisonExpecation);
1971 hairlineAB.compare(r, hairlineBA, TestCase::kAllSame_ComparisonExpecation);
1972 hairlineAB.compare(r, hairlineAC, TestCase::kAllDifferent_ComparisonExpecation);
1974 dashAB.compare(r, dashBA, TestCase::kAllDifferent_ComparisonExpecation);
1975 dashAB.compare(r, dashAC, TestCase::kAllDifferent_ComparisonExpecation);
1977 strokeAB.compare(r, hairlineAB, TestCase::kSameUpToStroke_ComparisonExpecation);
1981 bool canonicalizeAsAB;
1984 bool inverted =
true;
1985 SkPoint pts[2] {{0, 0}, {0, 0}};
1986 REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted);
1987 if (pts[0] ==
kA && pts[1] ==
kB) {
1988 canonicalizeAsAB =
true;
1989 }
else if (pts[1] ==
kA && pts[0] ==
kB) {
1990 canonicalizeAsAB =
false;
1992 swap(canonicalPts[0], canonicalPts[1]);
1994 ERRORF(r,
"Should return pts (a,b) or (b, a)");
1998 strokeAB.compare(r, canonicalizeAsAB ? dashAB : dashBA,
1999 TestCase::kSameUpToPE_ComparisonExpecation);
2000 REPORTER_ASSERT(r, strokeAB.baseShape().asLine(pts, &inverted) && !inverted &&
2001 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2002 REPORTER_ASSERT(r, hairlineAB.baseShape().asLine(pts, &inverted) && !inverted &&
2003 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2004 REPORTER_ASSERT(r, dashAB.baseShape().asLine(pts, &inverted) && !inverted &&
2005 pts[0] ==
kA && pts[1] ==
kB);
2006 REPORTER_ASSERT(r, dashBA.baseShape().asLine(pts, &inverted) && !inverted &&
2007 pts[0] ==
kB && pts[1] ==
kA);
2010 TestCase strokeInvAB(r, invLineAB, stroke);
2011 TestCase hairlineInvAB(r, invLineAB, hairline);
2012 TestCase dashInvAB(r, invLineAB, dash);
2013 strokeInvAB.compare(r, strokeAB, TestCase::kAllDifferent_ComparisonExpecation);
2014 hairlineInvAB.compare(r, hairlineAB, TestCase::kAllDifferent_ComparisonExpecation);
2016 dashInvAB.compare(r, dashAB, TestCase::kAllSame_ComparisonExpecation);
2018 REPORTER_ASSERT(r, strokeInvAB.baseShape().asLine(pts, &inverted) && inverted &&
2019 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2020 REPORTER_ASSERT(r, hairlineInvAB.baseShape().asLine(pts, &inverted) && inverted &&
2021 pts[0] == canonicalPts[0] && pts[1] == canonicalPts[1]);
2023 REPORTER_ASSERT(r, dashInvAB.baseShape().asLine(pts, &inverted) && !inverted &&
2024 pts[0] ==
kA && pts[1] ==
kB);
2029 static constexpr SkScalar kIntervals1[] = {1.f, 0.f};
2032 static constexpr SkScalar kIntervals2[] = {10.f, 0.f, 5.f, 0.f};
2038 for (
const auto& pe : pathEffects) {
2063 TestCase::kAllSame_ComparisonExpecation);
2067 TestCase::kAllSame_ComparisonExpecation);
2071 TestCase::kAllSame_ComparisonExpecation);
2080 TestCase::kAllSame_ComparisonExpecation);
2083 TestCase::kAllSame_ComparisonExpecation);
2086 TestCase::kAllSame_ComparisonExpecation);
2095 TestCase::kAllSame_ComparisonExpecation);
2098 TestCase::kAllSame_ComparisonExpecation);
2101 TestCase::kAllSame_ComparisonExpecation);
2115 TestCase::ComparisonExpecation expectation) {
2116 SkPath volatileA = pathA;
2117 SkPath volatileB = pathB;
2123 for (PathGeo::Invert
invert : {PathGeo::Invert::kNo, PathGeo::Invert::kYes}) {
2126 caseA.compare(r, caseB, expectation);
2135 pathA.
lineTo(10.f, 10.f);
2136 pathA.
conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2138 pathB.
lineTo(10.f, 10.f);
2139 pathB.
conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2140 compare(pathA, pathB, TestCase::kAllSame_ComparisonExpecation);
2144 pathB.lineTo(10.f, 10.f);
2145 pathB.conicTo(21.f, 20.f, 20.f, 30.f, 0.7f);
2146 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2150 pathB.lineTo(10.f, 10.f);
2151 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2152 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2156 pathB.lineTo(10.f, 10.f);
2157 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.6f);
2158 pathB.lineTo(50.f, 50.f);
2159 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2163 pathB.lineTo(10.f, 10.f);
2164 pathB.conicTo(20.f, 20.f, 20.f, 30.f, 0.7f);
2166 compare(pathA, pathB, TestCase::kAllDifferent_ComparisonExpecation);
2180 geos.
emplace_back(
new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2181 PathGeo::Invert::kNo));
2182 geos.
emplace_back(
new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2183 PathGeo::Invert::kYes));
2184 rrectPathGeos.
emplace_back(
new RRectPathGeo(rectPath, r, RRectPathGeo::RRectForStroke::kYes,
2185 PathGeo::Invert::kNo));
2194 geos.
emplace_back(
new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2195 PathGeo::Invert::kNo));
2196 geos.
emplace_back(
new RRectPathGeo(rectPath, rr, RRectPathGeo::RRectForStroke::kYes,
2197 PathGeo::Invert::kYes));
2198 rrectPathGeos.
emplace_back(
new RRectPathGeo(rectPath, rr,
2199 RRectPathGeo::RRectForStroke::kYes,
2200 PathGeo::Invert::kNo));
2209 openRectPath.
moveTo(0, 0);
2210 openRectPath.
lineTo(10, 0);
2211 openRectPath.
lineTo(10, 10);
2212 openRectPath.
lineTo(0, 10);
2215 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2218 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kYes));
2221 RRectPathGeo::RRectForStroke::kNo, PathGeo::Invert::kNo));
2226 quadPath.
quadTo(10, 10, 5, 8);
2227 geos.
emplace_back(
new PathGeo(quadPath, PathGeo::Invert::kNo));
2228 geos.
emplace_back(
new PathGeo(quadPath, PathGeo::Invert::kYes));
2234 geos.
emplace_back(
new PathGeo(linePath, PathGeo::Invert::kNo));
2235 geos.
emplace_back(
new PathGeo(linePath, PathGeo::Invert::kYes));
2242 geos.
emplace_back(
new PathGeo(vLinePath, PathGeo::Invert::kNo));
2243 geos.
emplace_back(
new PathGeo(vLinePath, PathGeo::Invert::kYes));
2249 geos.
emplace_back(
new PathGeo(hLinePath, PathGeo::Invert::kNo));
2250 geos.
emplace_back(
new PathGeo(hLinePath, PathGeo::Invert::kYes));
2253 for (
int i = 0; i < geos.
size(); ++i) {
2259 test_stroke_param<SkScalar>(
2274 for (
int i = 0; i < rrectPathGeos.
size(); ++i) {
2275 const RRectPathGeo& rrgeo = *rrectPathGeos[i];
2280 fillPathCase.baseShape().asRRect(&rrect,
nullptr,
nullptr,
2282 if (rrgeo.isNonPath(fillPaint)) {
2286 fillPathCase2.compare(
reporter, fillRRectCase,
2287 TestCase::kAllSame_ComparisonExpecation);
2293 if (rrgeo.isNonPath(strokePaint)) {
2298 strokePathCase.compare(
reporter, strokeRRectCase,
2299 TestCase::kAllSame_ComparisonExpecation);
2318 static constexpr SkScalar kIntervals[] = {1, 2};
2329 for (
const auto& style : styles) {
2334 emptyArc.compare(
reporter, emptyPath, TestCase::kAllSame_ComparisonExpecation);
2336 static constexpr SkRect kOval1{0, 0, 50, 50};
2337 static constexpr SkRect kOval2{50, 0, 100, 50};
2350 auto reversedExepectations = style.hasPathEffect()
2351 ? TestCase::kAllDifferent_ComparisonExpecation
2352 : TestCase::kAllSame_ComparisonExpecation;
2353 arc1CW.compare(
reporter, arc1CCW, reversedExepectations);
2354 arc1CWWithCenter.compare(
reporter, arc1CCWWithCenter, reversedExepectations);
2355 arc1CW.compare(
reporter, arc2CW, TestCase::kAllDifferent_ComparisonExpecation);
2356 arc1CW.compare(
reporter, arc1CWWithCenter, TestCase::kAllDifferent_ComparisonExpecation);
2357 arc1CWWithCenter.compare(
reporter, arc2CWWithCenter,
2358 TestCase::kAllDifferent_ComparisonExpecation);
2363 arc3A.compare(
reporter, arc3B, TestCase::kAllDifferent_ComparisonExpecation);
2369 auto ovalExpectations = style.hasPathEffect() ? TestCase::kAllDifferent_ComparisonExpecation
2370 : TestCase::kAllSame_ComparisonExpecation;
2371 if (style.strokeRec().getWidth() >= 0 && style.strokeRec().getCap() !=
SkPaint::kButt_Cap) {
2372 ovalExpectations = TestCase::kAllDifferent_ComparisonExpecation;
2374 ovalArc.compare(
reporter, oval, ovalExpectations);
2380 ovalExpectations = style.isSimpleFill() ? TestCase::kAllSame_ComparisonExpecation
2381 : TestCase::kAllDifferent_ComparisonExpecation;
2382 ovalArcWithCenter.compare(
reporter, oval, ovalExpectations);
2388 SkScalar radii[] = {10.f, 10.f, 10.f, 10.f,
2389 10.f, 10.f, 10.f, 10.f};
2391 path.toggleInverseFillType();
2395 rrect.setInverted(
false);
2408 inverseRRect.
reset();
2411 inverseRRect.
reset();
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static bool paths_fill_same(const SkPath &a, const SkPath &b)
static void test_stroke_cap(skiatest::Reporter *reporter, const Geo &geo)
static void test_stroke_join(skiatest::Reporter *reporter, const Geo &geo)
void test_path_effect_makes_empty_shape(skiatest::Reporter *reporter, const Geo &geo)
unsigned canonicalize_rrect_start(int s, const SkRRect &rrect)
static void test_scale(skiatest::Reporter *reporter, const Geo &geo)
void test_make_hairline_path_effect(skiatest::Reporter *reporter, const Geo &geo)
void test_path_effect_makes_rrect(skiatest::Reporter *reporter, const Geo &geo)
static void test_basic(skiatest::Reporter *reporter, const Geo &geo)
void test_rrect(skiatest::Reporter *r, const SkRRect &rrect)
static void test_stroke_param(skiatest::Reporter *reporter, const Geo &geo, std::function< void(SkPaint *, T)> setter, T a, T b)
void test_inversions(skiatest::Reporter *r, const GrStyledShape &shape, const Key &shapeKey)
static void test_stroke_param_impl(skiatest::Reporter *reporter, const Geo &geo, std::function< void(SkPaint *, T)> setter, T a, T b, bool paramAffectsStroke, bool paramAffectsDashAndStroke)
static sk_sp< SkPathEffect > make_null_dash()
static void check_original_path_ids(skiatest::Reporter *r, const GrStyledShape &base, const GrStyledShape &pe, const GrStyledShape &peStroke, const GrStyledShape &full)
static bool shape_known_not_to_have_joins(const GrStyledShape &shape)
static std::unique_ptr< TestCase > make_TestCase(Args &&... args)
static void check_equivalence(skiatest::Reporter *r, const GrStyledShape &a, const GrStyledShape &b, const Key &keyA, const Key &keyB)
static bool make_key(Key *key, const GrStyledShape &shape)
void test_volatile_path(skiatest::Reporter *reporter, const Geo &geo)
void test_unknown_path_effect(skiatest::Reporter *reporter, const Geo &geo)
static bool can_interchange_winding_and_even_odd_fill(const GrStyledShape &shape)
static void test_dash_fill(skiatest::Reporter *reporter, const Geo &geo)
static bool test_bounds_by_rasterizing(const SkPath &path, const SkRect &bounds)
void test_null_dash(skiatest::Reporter *reporter, const Geo &geo)
static sk_sp< SkPathEffect > make_dash()
static void test_miter_limit(skiatest::Reporter *reporter, const Geo &geo)
void test_path_effect_fails(skiatest::Reporter *reporter, const Geo &geo)
constexpr SkColor SK_ColorWHITE
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
@ kNo
Don't pre-clip the geometry before applying the (perspective) matrix.
static SkPDFGradientShader::Key make_key(const SkShader *shader, const SkMatrix &canvasTransform, const SkIRect &bbox)
@ kXOR_SkPathOp
exclusive-or the two paths
static SkPathFillType SkPathFillType_ConvertToNonInverse(SkPathFillType ft)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
static constexpr bool SkToBool(const T &x)
#define DEF_TEST(name, reporter)
#define REPORTER_ASSERT(r, cond,...)
void setPath(const SkPath &path)
bool simplify(unsigned flags=kAll_Flags)
static const GrStyle & SimpleHairline()
@ kPathEffectAndStrokeRec
SkPathEffect * pathEffect() const
static const GrStyle & SimpleFill()
bool hasNonDashPathEffect() const
bool isSimpleFill() const
const SkStrokeRec & strokeRec() const
bool knownToBeClosed() const
void asPath(SkPath *out) const
void writeUnstyledKey(uint32_t *key) const
int unstyledKeySize() const
bool asLine(SkPoint pts[2], bool *inverted) const
bool inverseFilled() const
const GrStyle & style() const
static GrStyledShape MakeArc(const SkRect &oval, SkScalar startAngleDegrees, SkScalar sweepAngleDegrees, bool useCenter, const GrStyle &style, DoSimplify=DoSimplify::kYes)
bool testingOnly_isPath() const
bool testingOnly_isNonVolatilePath() const
uint32_t testingOnly_getOriginalGenerationID() const
static GrStyledShape MakeFilled(const GrStyledShape &original, FillInversion=FillInversion::kPreserve)
bool asRRect(SkRRect *rrect, SkPathDirection *dir, unsigned *start, bool *inverted) const
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
virtual const char * getTypeName() const =0
virtual Factory getFactory() const =0
static SkMatrix RectToRect(const SkRect &src, const SkRect &dst, ScaleToFit mode=kFill_ScaleToFit)
@ kButt_Cap
no stroke extension
void setStyle(Style style)
void setColor(SkColor color)
void setStrokeCap(Cap cap)
@ kStroke_Style
set to stroke geometry
@ kFill_Style
set to fill geometry
@ kStrokeAndFill_Style
sets to stroke and fill geometry
void setStrokeJoin(Join join)
void setPathEffect(sk_sp< SkPathEffect > pathEffect)
@ kMiter_Join
extends to miter limit
@ kBevel_Join
connects outside edges
void setStrokeWidth(SkScalar width)
virtual bool computeFastBounds(SkRect *bounds) const =0
virtual bool onFilterPath(SkPath *, const SkPath &, SkStrokeRec *, const SkRect *, const SkMatrix &) const =0
static bool IsSimpleRect(const SkPath &path, bool isSimpleFill, SkRect *rect, SkPathDirection *direction, unsigned *start)
static void CreateDrawArcPath(SkPath *path, const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect)
bool isInverseFillType() const
uint32_t getGenerationID() const
SkPath & moveTo(SkScalar x, SkScalar y)
bool isLine(SkPoint line[2]) const
SkPathFillType getFillType() const
void setFillType(SkPathFillType ft)
SkPath & lineTo(SkScalar x, SkScalar y)
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
void toggleInverseFillType()
SkPath & setIsVolatile(bool isVolatile)
SkPath & quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2)
SkPath & conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar w)
bool isRect(SkRect *rect, bool *isClosed=nullptr, SkPathDirection *direction=nullptr) const
static SkPath Line(const SkPoint a, const SkPoint b)
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
const uint8_t * addr8() const
const SkRect & rect() const
@ kOval_Type
non-zero width and height filled with radii
@ kEmpty_Type
zero width or height
@ kRect_Type
non-zero width and height, and zeroed radii
static SkRRect MakeOval(const SkRect &oval)
static SkRRect MakeRect(const SkRect &r)
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
static SkRRect MakeEmpty()
static void GrowToInclude(SkRect *r, const SkPoint &pt)
void setStrokeStyle(SkScalar width, bool strokeAndFill=false)
void setStrokeParams(SkPaint::Cap cap, SkPaint::Join join, SkScalar miterLimit)
T & emplace_back(Args &&... args)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Optional< SkRect > bounds
sk_sp< SkBlender > blender SkRect rect
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
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
static void swap(TArray< T, M > &a, TArray< T, M > &b)
static SkImageInfo MakeA8(int width, int height)
static constexpr SkRect MakeEmpty()
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
static constexpr SkRect MakeWH(float w, float h)
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)