50#include <initializer_list>
67enum class SavePolicy {
98 const SkIRect& deviceBounds()
const {
return fDeviceBounds; }
99 ClipStack::ClipState expectedState()
const {
return fExpectedState; }
100 const std::vector<ClipStack::Element>& initialElements()
const {
return fElements; }
101 const std::vector<ClipStack::Element>& expectedElements()
const {
return fExpectedElements; }
104 friend class TestCaseBuilder;
109 std::vector<ClipStack::Element> actual,
110 std::vector<ClipStack::Element> expected)
112 , fElements(
std::move(actual))
113 , fDeviceBounds(deviceBounds)
114 , fExpectedElements(
std::move(expected))
115 , fExpectedState(expectedState) {}
117 SkString getTestName(
const std::vector<int>& order, SavePolicy
policy)
const;
122 std::pair<SkIRect, bool> getOptimalBounds()
const;
127 std::vector<ClipStack::Element> fElements;
132 std::vector<ClipStack::Element> fExpectedElements;
136class ElementsBuilder {
141 ElementsBuilder& localToDevice(
const SkMatrix&
m) { fLocalToDevice =
m;
return *
this; }
142 ElementsBuilder& aa() { fAA =
GrAA::kYes;
return *
this; }
143 ElementsBuilder& nonAA() { fAA =
GrAA::kNo;
return *
this; }
150 return this->
rect(rect, fLocalToDevice, fAA, fOp);
153 return this->
rect(rect, fLocalToDevice, aa, op);
161 return this->
rrect(rrect, fLocalToDevice, fAA, fOp);
164 return this->
rrect(rrect, fLocalToDevice, aa, op);
172 return this->
path(path, fLocalToDevice, fAA, fOp);
175 return this->
path(path, fLocalToDevice, aa, op);
183 TestCaseBuilder& finishElements() {
188 friend class TestCaseBuilder;
190 ElementsBuilder(TestCaseBuilder*
builder, std::vector<ClipStack::Element>* elements)
192 , fElements(elements) {}
198 TestCaseBuilder* fBuilder;
199 std::vector<ClipStack::Element>* fElements;
202class TestCaseBuilder {
206 ElementsBuilder actual() {
return ElementsBuilder(
this, &fActualElements); }
207 ElementsBuilder expect() {
return ElementsBuilder(
this, &fExpectedElements); }
209 TestCaseBuilder& expectActual() {
210 fExpectedElements = fActualElements;
214 TestCaseBuilder&
state(ClipStack::ClipState
state) {
215 fExpectedState =
state;
221 std::move(fActualElements), std::move(fExpectedElements));
223 fExpectedState = ClipStack::ClipState::kWideOpen;
230 explicit TestCaseBuilder(
const char*
name,
const SkIRect& deviceBounds)
232 , fDeviceBounds(deviceBounds)
233 , fExpectedState(ClipStack::ClipState::kWideOpen) {}
237 ClipStack::ClipState fExpectedState;
239 std::vector<ClipStack::Element> fActualElements;
240 std::vector<ClipStack::Element> fExpectedElements;
244 return TestCaseBuilder(
name, deviceBounds);
247SkString TestCase::getTestName(
const std::vector<int>& order, SavePolicy
policy)
const {
253 policyName =
"never";
255 case SavePolicy::kAtStart:
256 policyName =
"start";
258 case SavePolicy::kAtEnd:
261 case SavePolicy::kBetweenEveryOp:
262 policyName =
"between";
266 name.appendf(
"(save %s, order [", policyName.
c_str());
267 for (
size_t i = 0;
i < order.size(); ++
i) {
271 name.appendf(
"%d", order[
i]);
277std::pair<SkIRect, bool> TestCase::getOptimalBounds()
const {
282 bool expectOptimal =
true;
284 for (
const ClipStack::Element&
e : fExpectedElements) {
292 expectOptimal &=
e.fLocalToDevice.isIdentity();
297 expectOptimal =
false;
298 if (
e.fShape.isRect() &&
e.fLocalToDevice.isIdentity()) {
301 }
else if (
e.fShape.isRRect() &&
e.fLocalToDevice.isIdentity()) {
316 if (
a.fAA !=
b.fAA ||
a.fOp !=
b.fOp ||
a.fLocalToDevice !=
b.fLocalToDevice ||
317 a.fShape.type() !=
b.fShape.type()) {
320 switch(
a.fShape.type()) {
322 return a.fShape.rect() ==
b.fShape.rect();
324 return a.fShape.rrect() ==
b.fShape.rrect();
329 return a.fShape.path().getGenerationID() ==
b.fShape.path().getGenerationID() ||
330 (
a.fShape.convex() &&
332 a.fShape.path() ==
b.fShape.path());
334 SkDEBUGFAIL(
"Shape type not handled by test case yet.");
342 SkASSERT(fElements.size() == order.size());
344 ClipStack cs(fDeviceBounds, &
SkMatrix::I(),
false);
346 if (
policy == SavePolicy::kAtStart) {
350 for (
int i : order) {
351 if (
policy == SavePolicy::kBetweenEveryOp) {
354 const ClipStack::Element&
e = fElements[
i];
355 switch(
e.fShape.type()) {
357 cs.clipRect(
e.fLocalToDevice,
e.fShape.rect(),
e.fAA,
e.fOp);
360 cs.clipRRect(
e.fLocalToDevice,
e.fShape.rrect(),
e.fAA,
e.fOp);
363 cs.clipPath(
e.fLocalToDevice,
e.fShape.path(),
e.fAA,
e.fOp);
366 SkDEBUGFAIL(
"Shape type not handled by test case yet.");
370 if (
policy == SavePolicy::kAtEnd) {
377 "%s, clip state expected %d, actual %d",
378 name.c_str(), (
int) fExpectedState, (
int) cs.clipState());
379 SkIRect actualBounds = cs.getConservativeBounds();
382 std::tie(optimalBounds, expectOptimal) = this->getOptimalBounds();
386 "%s, bounds expected [%d %d %d %d], actual [%d %d %d %d]",
393 "%s, bounds are not conservative, optimal [%d %d %d %d], actual [%d %d %d %d]",
400 size_t matchedElements = 0;
401 for (
const ClipStack::Element&
a : cs) {
403 for (
const ClipStack::Element&
e : fExpectedElements) {
404 if (compare_elements(
a,
e)) {
412 "%s, unexpected clip element in stack: shape %d, aa %d, op %d",
413 name.c_str(), (
int)
a.fShape.type(), (
int)
a.fAA, (
int)
a.fOp);
414 matchedElements += found ? 1 : 0;
417 "%s, did not match all expected elements: expected %zu but matched only %zu",
418 name.c_str(), fExpectedElements.size(), matchedElements);
421 if (
policy == SavePolicy::kAtEnd) {
422 ClipStack::ClipState oldState = cs.clipState();
425 "%s, restoring an empty save record should not change clip state: "
426 "expected %d but got %d",
427 name.c_str(), (
int) oldState, (
int) cs.clipState());
429 int restoreCount =
policy == SavePolicy::kAtStart ? 1 : (
int) order.size();
430 for (
int i = 0;
i < restoreCount; ++
i) {
435 "%s, restore should make stack become wide-open, not %d",
436 name.c_str(), (
int) cs.clipState());
443 int n = (
int)
test.initialElements().size();
444 std::vector<int> order(n);
445 std::vector<int> stack(n);
448 for (
int i = 0;
i < n; ++
i) {
453 auto runTest = [&]() {
455 SavePolicy::kAtEnd, SavePolicy::kBetweenEveryOp };
456 for (
auto policy : kPolicies) {
465 static constexpr int kMaxRuns = 720;
469 while (
i < n && testRuns < kMaxRuns) {
473 swap(order[0], order[
i]);
475 swap(order[stack[
i]], order[
i]);
506 return make_octagon(r, lr, tb);
509static constexpr SkIRect kDeviceBounds = {0, 0, 100, 100};
520 const char*
name()
const override {
return "NoOp"; }
546 SkRect pixelAligned = {0, 0, 10, 10};
562 .expect().aa().
intersect().
rect(fracIntersect).finishElements()
571 .expect().nonAA().
intersect().
rect(fracIntersect).finishElements()
578 .aa().
rect(pixelAligned).nonAA().
rect(fracRect1)
580 .expect().nonAA().
intersect().
rect(alignedIntersect).finishElements()
587 .aa().
rect(fracRect1).nonAA().
rect(pixelAligned)
589 .expect().aa().
intersect().
rect(alignedIntersect).finishElements()
596 .aa().
rect(fracRect1).nonAA().
rect(fracRect2)
599 .
state(ClipState::kComplex)
608 SkRect r1 = {15.f, 14.f, 23.22f, 58.2f};
617 .
state(ClipState::kComplex)
626 SkRect pixelAligned = {0, 0, 10, 10};
639 .actual().aa().
intersect().localToDevice(lm)
642 .expect().aa().
intersect().localToDevice(lm)
643 .
rect(fracIntersect).finishElements()
644 .
state(ClipState::kComplex)
649 .actual().nonAA().
intersect().localToDevice(lm)
652 .expect().nonAA().
intersect().localToDevice(lm)
653 .
rect(fracIntersect).finishElements()
654 .
state(ClipState::kComplex)
660 .aa().
rect(pixelAligned).nonAA().
rect(fracRect1)
663 .
state(ClipState::kComplex)
684 .
state(ClipState::kDeviceRRect)
693 .
state(ClipState::kDeviceRRect)
702 .
state(ClipState::kComplex)
708 .actual().aa().
intersect().localToDevice(lm)
711 .expect().aa().
intersect().localToDevice(lm)
713 .
state(ClipState::kComplex)
716 .actual().nonAA().
intersect().localToDevice(lm)
719 .expect().nonAA().
intersect().localToDevice(lm)
721 .
state(ClipState::kComplex)
730 SkRect cutTop = {-10, -10, 10, 4};
731 SkRect cutMid = {-10, 3, 10, 7};
734 SkVector cutCorners[4] = {{2.f, 2.f}, {2.f, 2.f}, {0, 0}, {0, 0}};
740 .
state(ClipState::kDeviceRRect)
744 SkRect cutRect = {0, 3, 10, 7};
752 cutRect = {0, 0, 1.5f, 5.f};
756 .
state(ClipState::kComplex)
764 SkRect crossesDeviceEdge = {20.f, kDeviceBounds.
fTop - 13.2f,
765 kDeviceBounds.fRight + 15.5f, 30.f};
766 SkRect insideDevice = {20.f, kDeviceBounds.
fTop, kDeviceBounds.fRight, 30.f};
769 .actual().
intersect().aa().
rect(crossesDeviceEdge).finishElements()
770 .expect().
intersect().aa().
rect(insideDevice).finishElements()
775 .actual().
intersect().nonAA().
rect(crossesDeviceEdge).finishElements()
776 .expect().
intersect().nonAA().
rect(insideDevice).finishElements()
785 SkRect crossesDeviceEdge = {20.f, kDeviceBounds.
fTop - 13.2f,
786 kDeviceBounds.fRight + 15.5f, 30.f};
794 .
state(ClipState::kDeviceRRect)
800 .
path(make_octagon(crossesDeviceEdge))
803 .
state(ClipState::kComplex)
820 .actual().
path(point).finishElements()
825 line.moveTo({0.f, 0.f});
826 line.lineTo({10.f, 5.f});
828 .actual().
path(
line).finishElements()
837 .actual().
path(rectPath).finishElements()
838 .expect().
rect(
rect).finishElements()
846 .actual().
path(ovalPath).finishElements()
848 .
state(ClipState::kDeviceRRect)
856 .actual().
path(rrectPath).finishElements()
858 .
state(ClipState::kDeviceRRect)
870 .expect().
rect(
rect).finishElements()
878 .expect().localToDevice(lm).
rect(
rect).finishElements()
879 .
state(ClipState::kComplex)
887 .
state(ClipState::kDeviceRRect)
892 .expect().localToDevice(lm).
rrect(
rrect).finishElements()
893 .
state(ClipState::kComplex)
900 .expect().
path(make_octagon(
rect)).finishElements()
901 .
state(ClipState::kComplex)
904 .actual().localToDevice(lm)
907 .expect().localToDevice(lm).
path(make_octagon(
rect))
909 .
state(ClipState::kComplex)
914 path.moveTo({0.f, 0.f});
915 path.lineTo({20.f, 20.f});
916 path.lineTo({0.f, 20.f});
917 path.lineTo({20.f, 0.f});
922 .expect().
path(
path).finishElements()
923 .
state(ClipState::kComplex)
926 .actual().localToDevice(lm)
928 .expect().localToDevice(lm).
path(
path)
930 .
state(ClipState::kComplex)
942 SkPath inverseRectPath = rectPath;
946 SkPath inverseComplexPath = complexPath;
951 .actual().aa().
intersect().
path(inverseRectPath).finishElements()
953 .
state(ClipState::kComplex)
958 .actual().aa().
difference().
path(inverseRectPath).finishElements()
965 .actual().aa().
intersect().
path(inverseComplexPath).finishElements()
967 .
state(ClipState::kComplex)
972 .actual().aa().
difference().
path(inverseComplexPath).finishElements()
973 .expect().aa().
intersect().
path(complexPath).finishElements()
974 .
state(ClipState::kComplex)
982 SkRect offscreenRect = {kDeviceBounds.
fRight + 10.f, kDeviceBounds.fTop + 20.f,
983 kDeviceBounds.fRight + 40.f, kDeviceBounds.fTop + 60.f};
987 SkPath offscreenPath = make_octagon(offscreenRect);
993 .
rrect(offscreenRRect)
1000 .
rect(offscreenRect)
1006 .
rrect(offscreenRRect)
1012 .
path(offscreenPath)
1020 .
rect(offscreenRect)
1021 .
rrect(offscreenRRect)
1022 .
path(offscreenPath)
1024 .
state(ClipState::kWideOpen)
1028 .
rect(offscreenRect)
1030 .
state(ClipState::kWideOpen)
1034 .
rrect(offscreenRRect)
1036 .
state(ClipState::kWideOpen)
1040 .
path(offscreenPath)
1042 .
state(ClipState::kWideOpen)
1059 .
state(ClipState::kWideOpen)
1067 .
state(ClipState::kComplex)
1075 SkRect rightSide = {50.f, -10.f, 2.f * kDeviceBounds.
fRight, kDeviceBounds.fBottom + 10.f};
1076 SkRect clipped = rightSide;
1082 .
state(ClipState::kComplex)
1090 SkRect intR1 = {0.f, 0.f, 30.f, 30.f};
1091 SkRect intR2 = {15.f, 15.f, 45.f, 45.f};
1092 SkRect intCombo = {15.f, 15.f, 30.f, 30.f};
1093 SkRect diff = {20.f, 6.f, 50.f, 50.f};
1103 .
state(ClipState::kComplex)
1113 static constexpr int kNumOps = 16;
1116 SkRect d = {0.f, 0.f, 12.f, 12.f};
1117 for (
int i = 0;
i < kNumOps; ++
i) {
1120 d.offset(15.f, 0.f);
1121 if (
d.fRight > kDeviceBounds.fRight) {
1124 d.offset(0.f, 15.f);
1129 .state(ClipState::kComplex)
1133 d = {0.f, 0.f, 12.f, 12.f};
1134 for (
int i = 0;
i < kNumOps; ++
i) {
1136 d.offset(0.01f, 0.01f);
1140 .state(ClipState::kComplex)
1162 .
state(ClipState::kComplex)
1169 .
state(ClipState::kComplex)
1183 .
state(ClipState::kDeviceRRect)
1192 .
state(ClipState::kComplex)
1199 .
state(ClipState::kComplex)
1232 .
state(ClipState::kDeviceRRect)
1240 .
state(ClipState::kComplex)
1271 .
state(ClipState::kDeviceRRect)
1279 .
state(ClipState::kComplex)
1290 SkPath bigPath = make_octagon(
rect.makeOutset(10.f, 10.f), 5.f, 5.f);
1301 .
state(ClipState::kDeviceRRect)
1308 .
state(ClipState::kComplex)
1314 .
state(ClipState::kComplex)
1334 .
state(ClipState::kComplex)
1340 .
state(ClipState::kComplex)
1350 SkRect bigR = {-20.f, -20.f, 20.f, 20.f};
1354 SkRect smR = {-10.f, -10.f, 10.f, 10.f};
1364 .
state(ClipState::kComplex)
1372 .
state(ClipState::kComplex)
1380 .
state(ClipState::kComplex)
1388 .
state(ClipState::kComplex)
1398 .
state(ClipState::kComplex)
1406 .
state(ClipState::kComplex)
1414 .
state(ClipState::kComplex)
1422 .
state(ClipState::kComplex)
1457 .
state(ClipState::kComplex)
1464 .
state(ClipState::kComplex)
1471 .
state(ClipState::kComplex)
1478 .
state(ClipState::kComplex)
1488 SkRect r1 = {-20.f, -20.f, 20.f, 20.f};
1491 SkRect r2Safe = {-10.f, -10.f, 10.f, 10.f};
1492 SkRect r2Unsafe = {-19.5f, -19.5f, 19.5f, 19.5f};
1501 .
state(ClipState::kComplex)
1510 .
state(ClipState::kComplex)
1519 .
state(ClipState::kComplex)
1526 .
state(ClipState::kComplex)
1536 SkPath convex = make_octagon(
rect, 10.f, 10.f);
1541 .
state(ClipState::kWideOpen)
1545 .
state(ClipState::kWideOpen)
1549 .
state(ClipState::kWideOpen)
1572 SkRect rt = {10.f, 10.f, 20.f, 20.f};
1587 .
state(ClipState::kComplex)
1605 .
state(ClipState::kDeviceRRect)
1614 .
state(ClipState::kComplex)
1621 static constexpr float kN = 10.f;
1622 static constexpr float kR = kN / 3.f;
1625 static const SkRect kTL = {0.f, 0.f, 2.f * kN, 2.f * kN};
1626 static const SkRect kTR = {kN, 0.f, 3.f * kN, 2.f * kN};
1627 static const SkRect kBL = {0.f, kN, 2.f * kN, 3.f * kN};
1628 static const SkRect kBR = {kN, kN, 3.f * kN, 3.f * kN};
1634 for (
int opBits = 6; opBits < 16; ++opBits) {
1636 name.appendf(
"complex-%d-%d", (
int)
type, opBits);
1642 for (
int i = 0;
i < 4; ++
i) {
1665 expectedRRectIntersection,
rrect);
1680 ClipStack::ClipState
state = ClipStack::ClipState::kComplex;
1681 if (
type == kConvex) {
1685 }
else if (opBits) {
1690 !expectedRectIntersection.
isEmpty());
1692 if (opBits == 0xf) {
1696 SkASSERT(expectedRRectIntersection !=
1698 !expectedRRectIntersection.
isEmpty());
1700 if (opBits == 0xf) {
1701 state = ClipStack::ClipState::kDeviceRRect;
1719 ClipStack cs(kDeviceBounds,
nullptr,
false);
1724 SkIRect replace = {50, 25, 75, 40};
1726 cs.replaceClip(replace);
1729 "Clip did not become a device rect");
1730 REPORTER_ASSERT(r, cs.getConservativeBounds() == replace,
"Unexpected replaced clip bounds");
1731 const ClipStack::Element& replaceElement = *cs.begin();
1736 "Unexpected replace element state");
1740 REPORTER_ASSERT(r, cs.clipState() == ClipStack::ClipState::kDeviceRRect,
1741 "Unexpected state after restore, not kDeviceRRect");
1742 const ClipStack::Element& rrectElem = *cs.begin();
1747 "RRect element state not restored properly after replace clip undone");
1756 options.fMaxWindowRectangles = 8;
1764 ClipStack cs(kDeviceBounds, &
SkMatrix::I(),
false);
1767 for (
int y = 0;
y < 10; ++
y) {
1768 for (
int x = 0;
x < 10; ++
x) {
1789 ClipStack cs(kDeviceBounds,
nullptr,
true);
1792 SkRect aaRect = {0.25f, 12.43f, 25.2f, 23.f};
1796 SkPath nonAAPath = make_octagon({2.f, 10.f, 16.f, 20.f});
1800 SkRect nonAARect = {4.5f, 5.f, 17.25f, 18.23f};
1805 auto elements = cs.begin();
1807 const ClipStack::Element& nonAARectElement = *elements;
1808 REPORTER_ASSERT(r, nonAARectElement.fShape.isRect(),
"Expected rect element");
1810 "Axis-aligned non-AA rect ignores forceAA");
1812 "Mixed AA rects should not combine");
1815 const ClipStack::Element& aaPathElement = *elements;
1816 REPORTER_ASSERT(r, aaPathElement.fShape.isPath(),
"Expected path element");
1817 REPORTER_ASSERT(r, aaPathElement.fShape.path() == nonAAPath,
"Wrong path element");
1821 const ClipStack::Element& aaRectElement = *elements;
1822 REPORTER_ASSERT(r, aaRectElement.fShape.isRect(),
"Expected rect element");
1824 "Mixed AA rects should not combine");
1828 REPORTER_ASSERT(r, !(elements != cs.end()),
"Expected only three clip elements");
1836 ClipStack cs(kDeviceBounds,
nullptr,
false);
1841 "Offscreen draw is kClippedOut");
1846 "Wide open screen intersection is still kUnclipped");
1853 "Empty clip stack preApplies as kClippedOut");
1864 "Draw contained within clip is kUnclipped");
1869 "Draw not intersecting clip is kClippedOut");
1878 "Draw with complex clip is kClipped, but is not an rrect");
1889 "kDeviceRect clip stack should be reported by preApply");
1901 "kDeviceRRect clip stack should be reported by preApply");
1918 ClipStack cs(kDeviceBounds, &
SkMatrix::I(),
false);
1920 cs.clipShader(shader);
1923 "A clip shader should be reported as a complex clip");
1926 SkRect drawBounds = {10.f, 11.f, 16.f, 32.f};
1931 "apply() should return kClipped for a clip shader");
1933 "apply() should have converted clip shader to a coverage FP");
1936 drawBounds = {-15.f, -10.f, -1.f, 10.f};
1940 "apply() should still discard offscreen draws with a clip shader");
1944 "restore() should get rid of the clip shader");
1951 cs.clipShader(shader);
1954 "A clip shader should not produce a device rect from preApply");
1971 ClipStack cs(kDeviceBounds, &
SkMatrix::I(),
false);
1975 SkRect drawBounds = {-15.f, -15.f, -1.f, -1.f};
1985 SkRect drawBounds = {15.4f, 16.3f, 26.f, 32.f};
1999 SkRect clipRect = {kDeviceBounds.fRight - 20.f, 10.f, kDeviceBounds.fRight, 20.f};
2009 "Draw rect should be clipped to device rect");
2011 "After device clipping, this should be detected as contained within clip");
2028 REPORTER_ASSERT(r, !
out.hasCoverageFragmentProcessor(),
"Clip should not use coverage FPs");
2029 REPORTER_ASSERT(r, !
out.hardClip().hasStencilClip(),
"Clip should not need stencil");
2031 "Clip should not need window rects");
2033 out.scissorState().rect() == expectedScissor,
2034 "Clip has unexpected scissor rectangle");
2039 auto testHasCoverageFP = [&](
SkRect drawBounds) {
2044 REPORTER_ASSERT(r,
out.scissorState().enabled(),
"Coverage FPs should still set scissor");
2045 REPORTER_ASSERT(r,
out.hasCoverageFragmentProcessor(),
"Clip should use coverage FP");
2053 testHasCoverageFP({9.f, 10.f, 30.f, 18.f});
2063 testHasCoverageFP(
rect.makeOffset(2.f, 2.f));
2082 testHasCoverageFP(
rect.makeOutset(2.f, 2.f));
2090 options->fAvoidStencilBuffers =
true;
2107 std::unique_ptr<ClipStack> cs(
new ClipStack(kDeviceBounds, &
SkMatrix::I(),
false));
2111 path.addCircle(
x,
y, radius);
2112 path.addCircle(
x + radius / 2.f,
y + radius / 2.f, radius);
2119 auto drawRect = [&](
SkRect drawBounds) {
2121 paint.setColor4f({1.f, 1.f, 1.f, 1.f});
2125 auto generateMask = [&](
SkRect drawBounds) {
2127 drawRect(drawBounds);
2129 REPORTER_ASSERT(r, priorKey != newKey,
"Did not generate a new SW mask key as expected");
2133 auto verifyKeys = [&](
const std::vector<skgpu::UniqueKey>& expectedKeys,
2134 const std::vector<skgpu::UniqueKey>& releasedKeys) {
2141 SkASSERT(expectedKeys.size() > 0 || releasedKeys.size() > 0);
2142 const char* tag = expectedKeys.size() > 0 ? expectedKeys[0].tag() : releasedKeys[0].tag();
2144 int numProxies =
cache->countUniqueKeysWithTag(tag);
2146 "Unexpected proxy count, got %d, not %d",
2147 numProxies, (
int) expectedKeys.size());
2150 for (
const auto&
key : expectedKeys) {
2154 for (
const auto&
key : releasedKeys) {
2162 addMaskRequiringClip(5.f, 5.f, 20.f);
2165 verifyKeys({keyADepth1, keyBDepth1}, {});
2169 addMaskRequiringClip(6.f, 6.f, 15.f);
2172 verifyKeys({keyADepth1, keyBDepth1, keyADepth2, keyBDepth2}, {});
2175 addMaskRequiringClip(4.f, 4.f, 15.f);
2177 verifyKeys({keyADepth1, keyBDepth1, keyCDepth2}, {keyADepth2, keyBDepth2});
2181 verifyKeys({keyADepth1, keyBDepth1}, {keyCDepth2});
2184 drawRect({0.f, 0.f, 20.f, 20.f});
2185 drawRect({10.f, 10.f, 30.f, 30.f});
2186 verifyKeys({keyADepth1, keyBDepth1}, {});
2189 drawRect({5.f, 5.f, 15.f, 15.f});
2190 verifyKeys({keyADepth1, keyBDepth1}, {});
2194 verifyKeys({}, {keyADepth1, keyBDepth1});
skgpu::ganesh::SurfaceDrawContext SurfaceDrawContext
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
static bool intersect(const SkPoint &p0, const SkPoint &n0, const SkPoint &p1, const SkPoint &n1, SkScalar *t)
DEF_GANESH_TEST_FOR_CONTEXTS(ClipStack_SWMask, skgpu::IsRenderingContext, r, ctxInfo, disable_tessellation_atlas, CtsEnforcement::kNever)
DEF_TEST(ClipStack_InitialState, r)
static void disable_tessellation_atlas(GrContextOptions *options)
#define DEFINE_OP_CLASS_ID
static const uint16_t kTL
static const uint16_t kBL
static const uint16_t kBR
static const uint16_t kTR
#define SkDEBUGFAIL(message)
static size_t difference(size_t minuend, size_t subtrahend)
@ kLine_SkPathSegmentMask
void swap(sk_sp< T > &a, sk_sp< T > &b)
static constexpr bool SkToBool(const T &x)
#define REPORTER_ASSERT(r, cond,...)
static void run_test_case(const SkString &testdata, const SkBitmap &bitmap, SkCanvas *canvas)
static SkIRect GetPixelIBounds(const SkRect &bounds, GrAA aa, BoundsType mode=BoundsType::kExterior)
GrResourceCache * getResourceCache()
static sk_sp< GrDirectContext > MakeMock(const GrMockOptions *, const GrContextOptions &)
GrSemaphoresSubmitted flush(const GrFlushInfo &info)
GrDirectContextPriv priv()
static constexpr Analysis EmptySetAnalysis()
sk_sp< GrTextureProxy > findOrCreateProxyByUniqueKey(const skgpu::UniqueKey &, UseAllocator=UseAllocator::kYes)
GrProxyProvider * proxyProvider()
static sk_sp< SkColorSpace > MakeSRGB()
static SkMatrix Scale(SkScalar sx, SkScalar sy)
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
static SkMatrix RotateDeg(SkScalar deg)
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
static const SkMatrix & I()
bool isScaleTranslate() const
bool preservesAxisAlignment() const
bool mapRect(SkRect *dst, const SkRect &src, SkApplyPerspectiveClip pc=SkApplyPerspectiveClip::kYes) const
SkPath & moveTo(SkScalar x, SkScalar y)
SkPath & addRRect(const SkRRect &rrect, SkPathDirection dir=SkPathDirection::kCW)
void toggleInverseFillType()
SkPath & addOval(const SkRect &oval, SkPathDirection dir=SkPathDirection::kCW)
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
static SkRect InnerBounds(const SkRRect &rr)
static SkRRect ConservativeIntersect(const SkRRect &a, const SkRRect &b)
static SkRRect MakeOval(const SkRect &oval)
bool transform(const SkMatrix &matrix, SkRRect *dst) const
static SkRRect MakeRect(const SkRect &r)
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
void setRectRadii(const SkRect &rect, const SkVector radii[4])
SkRRect makeOffset(SkScalar dx, SkScalar dy) const
@ kIntersect_Op
target intersected with operand
@ kDifference_Op
target minus operand
const SkIRect & getBounds() const
bool op(const SkIRect &rect, Op op)
const char * c_str() const
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
EMSCRIPTEN_KEEPALIVE void empty()
const GrXPFactory * Get(SkBlendMode mode)
clipRRect(r.rrect, r.opAA.op(), r.opAA.aa())) DRAW(ClipRect
clipRect(r.rect, r.opAA.op(), r.opAA.aa())) template<> void Draw
ClipOpAndAA opAA SkRegion region
sk_sp< SkBlender > blender SkRect rect
SK_API sk_sp< SkShader > Color(SkColor)
def Build(configs, env, options)
constexpr std::array< std::array< float, 2 >, 2 > kRect
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 Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
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
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 policy
bool IsRenderingContext(skgpu::ContextType type)
constexpr bool contains(std::string_view str, std::string_view needle)
int32_t fBottom
larger y-axis bounds
int32_t fTop
smaller y-axis bounds
static constexpr SkIRect MakeEmpty()
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
int32_t fLeft
smaller x-axis bounds
bool contains(int32_t x, int32_t y) const
int32_t fRight
larger x-axis bounds
static SkRect Make(const SkISize &size)
static constexpr SkRect MakeEmpty()
SkScalar fBottom
larger y-axis bounds
void inset(float dx, float dy)
constexpr SkRect makeOffset(float dx, float dy) const
bool intersect(const SkRect &r)
SkScalar fLeft
smaller x-axis bounds
SkRect makeOutset(float dx, float dy) const
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
bool intersects(const SkRect &r) const
SkScalar fRight
larger x-axis bounds
constexpr float height() const
constexpr float width() const
static constexpr SkRect MakeWH(float w, float h)
SkScalar fTop
smaller y-axis bounds
static constexpr SkIRect kDeviceRect