1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2011 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkClipOp.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRegion.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkClipStack.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker #include <array>
22*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
23*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
24*c8dee2aaSAndroid Build Coastguard Worker
test_assign_and_comparison(skiatest::Reporter * reporter)25*c8dee2aaSAndroid Build Coastguard Worker static void test_assign_and_comparison(skiatest::Reporter* reporter) {
26*c8dee2aaSAndroid Build Coastguard Worker SkClipStack s;
27*c8dee2aaSAndroid Build Coastguard Worker bool doAA = false;
28*c8dee2aaSAndroid Build Coastguard Worker
29*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker // Build up a clip stack with a path, an empty clip, and a rect.
32*c8dee2aaSAndroid Build Coastguard Worker s.save();
33*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker SkPath p;
36*c8dee2aaSAndroid Build Coastguard Worker p.moveTo(5, 6);
37*c8dee2aaSAndroid Build Coastguard Worker p.lineTo(7, 8);
38*c8dee2aaSAndroid Build Coastguard Worker p.lineTo(5, 9);
39*c8dee2aaSAndroid Build Coastguard Worker p.close();
40*c8dee2aaSAndroid Build Coastguard Worker s.clipPath(p, SkMatrix::I(), SkClipOp::kIntersect, doAA);
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard Worker s.save();
43*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker SkRect r = SkRect::MakeLTRB(1, 2, 103, 104);
46*c8dee2aaSAndroid Build Coastguard Worker s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA);
47*c8dee2aaSAndroid Build Coastguard Worker r = SkRect::MakeLTRB(4, 5, 56, 57);
48*c8dee2aaSAndroid Build Coastguard Worker s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA);
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker s.save();
51*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
52*c8dee2aaSAndroid Build Coastguard Worker
53*c8dee2aaSAndroid Build Coastguard Worker r = SkRect::MakeLTRB(14, 15, 16, 17);
54*c8dee2aaSAndroid Build Coastguard Worker s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA);
55*c8dee2aaSAndroid Build Coastguard Worker
56*c8dee2aaSAndroid Build Coastguard Worker // Test that assignment works.
57*c8dee2aaSAndroid Build Coastguard Worker SkClipStack copy = s;
58*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s == copy);
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker // Test that different save levels triggers not equal.
61*c8dee2aaSAndroid Build Coastguard Worker s.restore();
62*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
63*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s != copy);
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker // Test that an equal, but not copied version is equal.
66*c8dee2aaSAndroid Build Coastguard Worker s.save();
67*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
68*c8dee2aaSAndroid Build Coastguard Worker r = SkRect::MakeLTRB(14, 15, 16, 17);
69*c8dee2aaSAndroid Build Coastguard Worker s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA);
70*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s == copy);
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker // Test that a different op on one level triggers not equal.
73*c8dee2aaSAndroid Build Coastguard Worker s.restore();
74*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
75*c8dee2aaSAndroid Build Coastguard Worker s.save();
76*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
77*c8dee2aaSAndroid Build Coastguard Worker r = SkRect::MakeLTRB(14, 15, 16, 17);
78*c8dee2aaSAndroid Build Coastguard Worker s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA);
79*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s != copy);
80*c8dee2aaSAndroid Build Coastguard Worker
81*c8dee2aaSAndroid Build Coastguard Worker // Test that version constructed with rect-path rather than a rect is still considered equal.
82*c8dee2aaSAndroid Build Coastguard Worker s.restore();
83*c8dee2aaSAndroid Build Coastguard Worker s.save();
84*c8dee2aaSAndroid Build Coastguard Worker SkPath rp;
85*c8dee2aaSAndroid Build Coastguard Worker rp.addRect(r);
86*c8dee2aaSAndroid Build Coastguard Worker s.clipPath(rp, SkMatrix::I(), SkClipOp::kDifference, doAA);
87*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s == copy);
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker // Test that different rects triggers not equal.
90*c8dee2aaSAndroid Build Coastguard Worker s.restore();
91*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
92*c8dee2aaSAndroid Build Coastguard Worker s.save();
93*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker r = SkRect::MakeLTRB(24, 25, 26, 27);
96*c8dee2aaSAndroid Build Coastguard Worker s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA);
97*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s != copy);
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker s.restore();
100*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker copy.restore();
103*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == copy.getSaveCount());
104*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s == copy);
105*c8dee2aaSAndroid Build Coastguard Worker s.restore();
106*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
107*c8dee2aaSAndroid Build Coastguard Worker copy.restore();
108*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == copy.getSaveCount());
109*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s == copy);
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker // Test that different paths triggers not equal.
112*c8dee2aaSAndroid Build Coastguard Worker s.restore();
113*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
114*c8dee2aaSAndroid Build Coastguard Worker s.save();
115*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker p.addRect(r);
118*c8dee2aaSAndroid Build Coastguard Worker s.clipPath(p, SkMatrix::I(), SkClipOp::kIntersect, doAA);
119*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, s != copy);
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker
assert_count(skiatest::Reporter * reporter,const SkClipStack & stack,int count)122*c8dee2aaSAndroid Build Coastguard Worker static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack,
123*c8dee2aaSAndroid Build Coastguard Worker int count) {
124*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::B2TIter iter(stack);
125*c8dee2aaSAndroid Build Coastguard Worker int counter = 0;
126*c8dee2aaSAndroid Build Coastguard Worker while (iter.next()) {
127*c8dee2aaSAndroid Build Coastguard Worker counter += 1;
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, count == counter);
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker
132*c8dee2aaSAndroid Build Coastguard Worker // Exercise the SkClipStack's bottom to top and bidirectional iterators
133*c8dee2aaSAndroid Build Coastguard Worker // (including the skipToTopmost functionality)
test_iterators(skiatest::Reporter * reporter)134*c8dee2aaSAndroid Build Coastguard Worker static void test_iterators(skiatest::Reporter* reporter) {
135*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker static const SkRect gRects[] = {
138*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 40, 40 },
139*c8dee2aaSAndroid Build Coastguard Worker { 60, 0, 100, 40 },
140*c8dee2aaSAndroid Build Coastguard Worker { 0, 60, 40, 100 },
141*c8dee2aaSAndroid Build Coastguard Worker { 60, 60, 100, 100 }
142*c8dee2aaSAndroid Build Coastguard Worker };
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(gRects); i++) {
145*c8dee2aaSAndroid Build Coastguard Worker // the difference op will prevent these from being fused together
146*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(gRects[i], SkMatrix::I(), SkClipOp::kDifference, false);
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker assert_count(reporter, stack, 4);
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker // bottom to top iteration
152*c8dee2aaSAndroid Build Coastguard Worker {
153*c8dee2aaSAndroid Build Coastguard Worker const SkClipStack::Element* element = nullptr;
154*c8dee2aaSAndroid Build Coastguard Worker
155*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::B2TIter iter(stack);
156*c8dee2aaSAndroid Build Coastguard Worker int i;
157*c8dee2aaSAndroid Build Coastguard Worker
158*c8dee2aaSAndroid Build Coastguard Worker for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
159*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect ==
160*c8dee2aaSAndroid Build Coastguard Worker element->getDeviceSpaceType());
161*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]);
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i == 4);
165*c8dee2aaSAndroid Build Coastguard Worker }
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker // top to bottom iteration
168*c8dee2aaSAndroid Build Coastguard Worker {
169*c8dee2aaSAndroid Build Coastguard Worker const SkClipStack::Element* element = nullptr;
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
172*c8dee2aaSAndroid Build Coastguard Worker int i;
173*c8dee2aaSAndroid Build Coastguard Worker
174*c8dee2aaSAndroid Build Coastguard Worker for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
175*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect ==
176*c8dee2aaSAndroid Build Coastguard Worker element->getDeviceSpaceType());
177*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]);
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i == -1);
181*c8dee2aaSAndroid Build Coastguard Worker }
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker // skipToTopmost
184*c8dee2aaSAndroid Build Coastguard Worker {
185*c8dee2aaSAndroid Build Coastguard Worker const SkClipStack::Element* element = nullptr;
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
188*c8dee2aaSAndroid Build Coastguard Worker
189*c8dee2aaSAndroid Build Coastguard Worker element = iter.skipToTopmost(SkClipOp::kDifference);
190*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect ==
191*c8dee2aaSAndroid Build Coastguard Worker element->getDeviceSpaceType());
192*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[3]);
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker }
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker // Exercise the SkClipStack's getConservativeBounds computation
test_bounds(skiatest::Reporter * reporter,SkClipStack::Element::DeviceSpaceType primType)197*c8dee2aaSAndroid Build Coastguard Worker static void test_bounds(skiatest::Reporter* reporter,
198*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::Element::DeviceSpaceType primType) {
199*c8dee2aaSAndroid Build Coastguard Worker static const int gNumCases = 8;
200*c8dee2aaSAndroid Build Coastguard Worker static const SkRect gAnswerRectsBW[gNumCases] = {
201*c8dee2aaSAndroid Build Coastguard Worker // A op B
202*c8dee2aaSAndroid Build Coastguard Worker { 40, 40, 50, 50 },
203*c8dee2aaSAndroid Build Coastguard Worker { 10, 10, 50, 50 },
204*c8dee2aaSAndroid Build Coastguard Worker
205*c8dee2aaSAndroid Build Coastguard Worker // invA op B
206*c8dee2aaSAndroid Build Coastguard Worker { 40, 40, 80, 80 },
207*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 100, 100 },
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker // A op invB
210*c8dee2aaSAndroid Build Coastguard Worker { 10, 10, 50, 50 },
211*c8dee2aaSAndroid Build Coastguard Worker { 40, 40, 50, 50 },
212*c8dee2aaSAndroid Build Coastguard Worker
213*c8dee2aaSAndroid Build Coastguard Worker // invA op invB
214*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 100, 100 },
215*c8dee2aaSAndroid Build Coastguard Worker { 40, 40, 80, 80 },
216*c8dee2aaSAndroid Build Coastguard Worker };
217*c8dee2aaSAndroid Build Coastguard Worker
218*c8dee2aaSAndroid Build Coastguard Worker static const SkClipOp gOps[] = {
219*c8dee2aaSAndroid Build Coastguard Worker SkClipOp::kIntersect,
220*c8dee2aaSAndroid Build Coastguard Worker SkClipOp::kDifference
221*c8dee2aaSAndroid Build Coastguard Worker };
222*c8dee2aaSAndroid Build Coastguard Worker
223*c8dee2aaSAndroid Build Coastguard Worker SkRect rectA, rectB;
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard Worker rectA.setLTRB(10, 10, 50, 50);
226*c8dee2aaSAndroid Build Coastguard Worker rectB.setLTRB(40, 40, 80, 80);
227*c8dee2aaSAndroid Build Coastguard Worker
228*c8dee2aaSAndroid Build Coastguard Worker SkRRect rrectA, rrectB;
229*c8dee2aaSAndroid Build Coastguard Worker rrectA.setOval(rectA);
230*c8dee2aaSAndroid Build Coastguard Worker rrectB.setRectXY(rectB, SkIntToScalar(1), SkIntToScalar(2));
231*c8dee2aaSAndroid Build Coastguard Worker
232*c8dee2aaSAndroid Build Coastguard Worker SkPath pathA, pathB;
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker pathA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
235*c8dee2aaSAndroid Build Coastguard Worker pathB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
238*c8dee2aaSAndroid Build Coastguard Worker SkRect devClipBound;
239*c8dee2aaSAndroid Build Coastguard Worker bool isIntersectionOfRects = false;
240*c8dee2aaSAndroid Build Coastguard Worker
241*c8dee2aaSAndroid Build Coastguard Worker int testCase = 0;
242*c8dee2aaSAndroid Build Coastguard Worker int numBitTests = SkClipStack::Element::DeviceSpaceType::kPath == primType ? 4 : 1;
243*c8dee2aaSAndroid Build Coastguard Worker for (int invBits = 0; invBits < numBitTests; ++invBits) {
244*c8dee2aaSAndroid Build Coastguard Worker for (size_t op = 0; op < std::size(gOps); ++op) {
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker stack.save();
247*c8dee2aaSAndroid Build Coastguard Worker bool doInvA = SkToBool(invBits & 1);
248*c8dee2aaSAndroid Build Coastguard Worker bool doInvB = SkToBool(invBits & 2);
249*c8dee2aaSAndroid Build Coastguard Worker
250*c8dee2aaSAndroid Build Coastguard Worker pathA.setFillType(doInvA ? SkPathFillType::kInverseEvenOdd :
251*c8dee2aaSAndroid Build Coastguard Worker SkPathFillType::kEvenOdd);
252*c8dee2aaSAndroid Build Coastguard Worker pathB.setFillType(doInvB ? SkPathFillType::kInverseEvenOdd :
253*c8dee2aaSAndroid Build Coastguard Worker SkPathFillType::kEvenOdd);
254*c8dee2aaSAndroid Build Coastguard Worker
255*c8dee2aaSAndroid Build Coastguard Worker switch (primType) {
256*c8dee2aaSAndroid Build Coastguard Worker case SkClipStack::Element::DeviceSpaceType::kShader:
257*c8dee2aaSAndroid Build Coastguard Worker case SkClipStack::Element::DeviceSpaceType::kEmpty:
258*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Don't call this with kEmpty or kShader.");
259*c8dee2aaSAndroid Build Coastguard Worker break;
260*c8dee2aaSAndroid Build Coastguard Worker case SkClipStack::Element::DeviceSpaceType::kRect:
261*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(rectA, SkMatrix::I(), SkClipOp::kIntersect, false);
262*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(rectB, SkMatrix::I(), gOps[op], false);
263*c8dee2aaSAndroid Build Coastguard Worker break;
264*c8dee2aaSAndroid Build Coastguard Worker case SkClipStack::Element::DeviceSpaceType::kRRect:
265*c8dee2aaSAndroid Build Coastguard Worker stack.clipRRect(rrectA, SkMatrix::I(), SkClipOp::kIntersect, false);
266*c8dee2aaSAndroid Build Coastguard Worker stack.clipRRect(rrectB, SkMatrix::I(), gOps[op], false);
267*c8dee2aaSAndroid Build Coastguard Worker break;
268*c8dee2aaSAndroid Build Coastguard Worker case SkClipStack::Element::DeviceSpaceType::kPath:
269*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(pathA, SkMatrix::I(), SkClipOp::kIntersect, false);
270*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(pathB, SkMatrix::I(), gOps[op], false);
271*c8dee2aaSAndroid Build Coastguard Worker break;
272*c8dee2aaSAndroid Build Coastguard Worker }
273*c8dee2aaSAndroid Build Coastguard Worker
274*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !stack.isWideOpen());
275*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID());
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
278*c8dee2aaSAndroid Build Coastguard Worker &isIntersectionOfRects);
279*c8dee2aaSAndroid Build Coastguard Worker
280*c8dee2aaSAndroid Build Coastguard Worker if (SkClipStack::Element::DeviceSpaceType::kRect == primType) {
281*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, isIntersectionOfRects ==
282*c8dee2aaSAndroid Build Coastguard Worker (gOps[op] == SkClipOp::kIntersect));
283*c8dee2aaSAndroid Build Coastguard Worker } else {
284*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !isIntersectionOfRects);
285*c8dee2aaSAndroid Build Coastguard Worker }
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(testCase < gNumCases);
288*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]);
289*c8dee2aaSAndroid Build Coastguard Worker ++testCase;
290*c8dee2aaSAndroid Build Coastguard Worker
291*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
292*c8dee2aaSAndroid Build Coastguard Worker }
293*c8dee2aaSAndroid Build Coastguard Worker }
294*c8dee2aaSAndroid Build Coastguard Worker }
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker // Test out 'isWideOpen' entry point
test_isWideOpen(skiatest::Reporter * reporter)297*c8dee2aaSAndroid Build Coastguard Worker static void test_isWideOpen(skiatest::Reporter* reporter) {
298*c8dee2aaSAndroid Build Coastguard Worker {
299*c8dee2aaSAndroid Build Coastguard Worker // Empty stack is wide open. Wide open stack means that gen id is wide open.
300*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
301*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, stack.isWideOpen());
302*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
303*c8dee2aaSAndroid Build Coastguard Worker }
304*c8dee2aaSAndroid Build Coastguard Worker
305*c8dee2aaSAndroid Build Coastguard Worker SkRect rectA, rectB;
306*c8dee2aaSAndroid Build Coastguard Worker
307*c8dee2aaSAndroid Build Coastguard Worker rectA.setLTRB(10, 10, 40, 40);
308*c8dee2aaSAndroid Build Coastguard Worker rectB.setLTRB(50, 50, 80, 80);
309*c8dee2aaSAndroid Build Coastguard Worker
310*c8dee2aaSAndroid Build Coastguard Worker // Stack should initially be wide open
311*c8dee2aaSAndroid Build Coastguard Worker {
312*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
313*c8dee2aaSAndroid Build Coastguard Worker
314*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, stack.isWideOpen());
315*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
316*c8dee2aaSAndroid Build Coastguard Worker }
317*c8dee2aaSAndroid Build Coastguard Worker
318*c8dee2aaSAndroid Build Coastguard Worker // Test out empty difference from a wide open clip
319*c8dee2aaSAndroid Build Coastguard Worker {
320*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
321*c8dee2aaSAndroid Build Coastguard Worker
322*c8dee2aaSAndroid Build Coastguard Worker SkRect emptyRect;
323*c8dee2aaSAndroid Build Coastguard Worker emptyRect.setEmpty();
324*c8dee2aaSAndroid Build Coastguard Worker
325*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(emptyRect, SkMatrix::I(), SkClipOp::kDifference, false);
326*c8dee2aaSAndroid Build Coastguard Worker
327*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, stack.isWideOpen());
328*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker
331*c8dee2aaSAndroid Build Coastguard Worker // Test out return to wide open
332*c8dee2aaSAndroid Build Coastguard Worker {
333*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
334*c8dee2aaSAndroid Build Coastguard Worker
335*c8dee2aaSAndroid Build Coastguard Worker stack.save();
336*c8dee2aaSAndroid Build Coastguard Worker
337*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(rectA, SkMatrix::I(), SkClipOp::kIntersect, false);
338*c8dee2aaSAndroid Build Coastguard Worker
339*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !stack.isWideOpen());
340*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID());
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, stack.isWideOpen());
345*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
346*c8dee2aaSAndroid Build Coastguard Worker }
347*c8dee2aaSAndroid Build Coastguard Worker }
348*c8dee2aaSAndroid Build Coastguard Worker
count(const SkClipStack & stack)349*c8dee2aaSAndroid Build Coastguard Worker static int count(const SkClipStack& stack) {
350*c8dee2aaSAndroid Build Coastguard Worker
351*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
352*c8dee2aaSAndroid Build Coastguard Worker
353*c8dee2aaSAndroid Build Coastguard Worker const SkClipStack::Element* element = nullptr;
354*c8dee2aaSAndroid Build Coastguard Worker int count = 0;
355*c8dee2aaSAndroid Build Coastguard Worker
356*c8dee2aaSAndroid Build Coastguard Worker for (element = iter.prev(); element; element = iter.prev(), ++count) {
357*c8dee2aaSAndroid Build Coastguard Worker }
358*c8dee2aaSAndroid Build Coastguard Worker
359*c8dee2aaSAndroid Build Coastguard Worker return count;
360*c8dee2aaSAndroid Build Coastguard Worker }
361*c8dee2aaSAndroid Build Coastguard Worker
test_rect_inverse_fill(skiatest::Reporter * reporter)362*c8dee2aaSAndroid Build Coastguard Worker static void test_rect_inverse_fill(skiatest::Reporter* reporter) {
363*c8dee2aaSAndroid Build Coastguard Worker // non-intersecting rectangles
364*c8dee2aaSAndroid Build Coastguard Worker SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10);
365*c8dee2aaSAndroid Build Coastguard Worker
366*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
367*c8dee2aaSAndroid Build Coastguard Worker path.addRect(rect);
368*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
369*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
370*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
371*c8dee2aaSAndroid Build Coastguard Worker
372*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds;
373*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::BoundsType boundsType;
374*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bounds, &boundsType);
375*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kInsideOut_BoundsType == boundsType);
376*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, bounds == rect);
377*c8dee2aaSAndroid Build Coastguard Worker }
378*c8dee2aaSAndroid Build Coastguard Worker
test_rect_replace(skiatest::Reporter * reporter)379*c8dee2aaSAndroid Build Coastguard Worker static void test_rect_replace(skiatest::Reporter* reporter) {
380*c8dee2aaSAndroid Build Coastguard Worker SkRect rect = SkRect::MakeWH(100, 100);
381*c8dee2aaSAndroid Build Coastguard Worker SkRect rect2 = SkRect::MakeXYWH(50, 50, 100, 100);
382*c8dee2aaSAndroid Build Coastguard Worker
383*c8dee2aaSAndroid Build Coastguard Worker SkRect bound;
384*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::BoundsType type;
385*c8dee2aaSAndroid Build Coastguard Worker bool isIntersectionOfRects;
386*c8dee2aaSAndroid Build Coastguard Worker
387*c8dee2aaSAndroid Build Coastguard Worker // Adding a new rect with the replace operator should not increase
388*c8dee2aaSAndroid Build Coastguard Worker // the stack depth. BW replacing BW.
389*c8dee2aaSAndroid Build Coastguard Worker {
390*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
391*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == count(stack));
392*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
393*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
394*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
395*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker
398*c8dee2aaSAndroid Build Coastguard Worker // Adding a new rect with the replace operator should not increase
399*c8dee2aaSAndroid Build Coastguard Worker // the stack depth. AA replacing AA.
400*c8dee2aaSAndroid Build Coastguard Worker {
401*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
402*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == count(stack));
403*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, true);
404*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
405*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, true);
406*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
407*c8dee2aaSAndroid Build Coastguard Worker }
408*c8dee2aaSAndroid Build Coastguard Worker
409*c8dee2aaSAndroid Build Coastguard Worker // Adding a new rect with the replace operator should not increase
410*c8dee2aaSAndroid Build Coastguard Worker // the stack depth. BW replacing AA replacing BW.
411*c8dee2aaSAndroid Build Coastguard Worker {
412*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
413*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == count(stack));
414*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
415*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
416*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, true);
417*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
418*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
419*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
420*c8dee2aaSAndroid Build Coastguard Worker }
421*c8dee2aaSAndroid Build Coastguard Worker
422*c8dee2aaSAndroid Build Coastguard Worker // Make sure replace clip rects don't collapse too much.
423*c8dee2aaSAndroid Build Coastguard Worker {
424*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
425*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
426*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(rect2, SkMatrix::I(), SkClipOp::kIntersect, false);
427*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
428*c8dee2aaSAndroid Build Coastguard Worker
429*c8dee2aaSAndroid Build Coastguard Worker stack.save();
430*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
431*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
432*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
433*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, bound == rect);
434*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
435*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
436*c8dee2aaSAndroid Build Coastguard Worker
437*c8dee2aaSAndroid Build Coastguard Worker stack.save();
438*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
439*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
440*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
441*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
442*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
443*c8dee2aaSAndroid Build Coastguard Worker
444*c8dee2aaSAndroid Build Coastguard Worker stack.save();
445*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
446*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(rect2, SkMatrix::I(), SkClipOp::kIntersect, false);
447*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, false);
448*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
449*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
450*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
451*c8dee2aaSAndroid Build Coastguard Worker }
452*c8dee2aaSAndroid Build Coastguard Worker }
453*c8dee2aaSAndroid Build Coastguard Worker
454*c8dee2aaSAndroid Build Coastguard Worker // Simplified path-based version of test_rect_replace.
test_path_replace(skiatest::Reporter * reporter)455*c8dee2aaSAndroid Build Coastguard Worker static void test_path_replace(skiatest::Reporter* reporter) {
456*c8dee2aaSAndroid Build Coastguard Worker auto replacePath = [](SkClipStack* stack, const SkPath& path, bool doAA) {
457*c8dee2aaSAndroid Build Coastguard Worker const SkRect wideOpen = SkRect::MakeLTRB(-1000, -1000, 1000, 1000);
458*c8dee2aaSAndroid Build Coastguard Worker stack->replaceClip(wideOpen, false);
459*c8dee2aaSAndroid Build Coastguard Worker stack->clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, doAA);
460*c8dee2aaSAndroid Build Coastguard Worker };
461*c8dee2aaSAndroid Build Coastguard Worker SkRect rect = SkRect::MakeWH(100, 100);
462*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
463*c8dee2aaSAndroid Build Coastguard Worker path.addCircle(50, 50, 50);
464*c8dee2aaSAndroid Build Coastguard Worker
465*c8dee2aaSAndroid Build Coastguard Worker // Emulating replace operations with more complex geometry is not atomic, it's a replace
466*c8dee2aaSAndroid Build Coastguard Worker // with a wide-open rect and then an intersection with the complex geometry. The replace can
467*c8dee2aaSAndroid Build Coastguard Worker // combine with prior elements, but the subsequent intersect cannot be combined so the stack
468*c8dee2aaSAndroid Build Coastguard Worker // continues to grow.
469*c8dee2aaSAndroid Build Coastguard Worker {
470*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
471*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == count(stack));
472*c8dee2aaSAndroid Build Coastguard Worker replacePath(&stack, path, false);
473*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
474*c8dee2aaSAndroid Build Coastguard Worker replacePath(&stack, path, false);
475*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
476*c8dee2aaSAndroid Build Coastguard Worker }
477*c8dee2aaSAndroid Build Coastguard Worker
478*c8dee2aaSAndroid Build Coastguard Worker // Replacing rect with path.
479*c8dee2aaSAndroid Build Coastguard Worker {
480*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
481*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(rect, true);
482*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
483*c8dee2aaSAndroid Build Coastguard Worker replacePath(&stack, path, true);
484*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
485*c8dee2aaSAndroid Build Coastguard Worker }
486*c8dee2aaSAndroid Build Coastguard Worker }
487*c8dee2aaSAndroid Build Coastguard Worker
488*c8dee2aaSAndroid Build Coastguard Worker // Test out SkClipStack's merging of rect clips. In particular exercise
489*c8dee2aaSAndroid Build Coastguard Worker // merging of aa vs. bw rects.
test_rect_merging(skiatest::Reporter * reporter)490*c8dee2aaSAndroid Build Coastguard Worker static void test_rect_merging(skiatest::Reporter* reporter) {
491*c8dee2aaSAndroid Build Coastguard Worker
492*c8dee2aaSAndroid Build Coastguard Worker SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50);
493*c8dee2aaSAndroid Build Coastguard Worker SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
494*c8dee2aaSAndroid Build Coastguard Worker
495*c8dee2aaSAndroid Build Coastguard Worker SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
496*c8dee2aaSAndroid Build Coastguard Worker SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60);
497*c8dee2aaSAndroid Build Coastguard Worker
498*c8dee2aaSAndroid Build Coastguard Worker SkRect bound;
499*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::BoundsType type;
500*c8dee2aaSAndroid Build Coastguard Worker bool isIntersectionOfRects;
501*c8dee2aaSAndroid Build Coastguard Worker
502*c8dee2aaSAndroid Build Coastguard Worker // all bw overlapping - should merge
503*c8dee2aaSAndroid Build Coastguard Worker {
504*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
505*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, false);
506*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, false);
507*c8dee2aaSAndroid Build Coastguard Worker
508*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
509*c8dee2aaSAndroid Build Coastguard Worker
510*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
511*c8dee2aaSAndroid Build Coastguard Worker
512*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, isIntersectionOfRects);
513*c8dee2aaSAndroid Build Coastguard Worker }
514*c8dee2aaSAndroid Build Coastguard Worker
515*c8dee2aaSAndroid Build Coastguard Worker // all aa overlapping - should merge
516*c8dee2aaSAndroid Build Coastguard Worker {
517*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
518*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, true);
519*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, true);
520*c8dee2aaSAndroid Build Coastguard Worker
521*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
522*c8dee2aaSAndroid Build Coastguard Worker
523*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
524*c8dee2aaSAndroid Build Coastguard Worker
525*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, isIntersectionOfRects);
526*c8dee2aaSAndroid Build Coastguard Worker }
527*c8dee2aaSAndroid Build Coastguard Worker
528*c8dee2aaSAndroid Build Coastguard Worker // mixed overlapping - should _not_ merge
529*c8dee2aaSAndroid Build Coastguard Worker {
530*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
531*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, true);
532*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, false);
533*c8dee2aaSAndroid Build Coastguard Worker
534*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
535*c8dee2aaSAndroid Build Coastguard Worker
536*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
537*c8dee2aaSAndroid Build Coastguard Worker
538*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !isIntersectionOfRects);
539*c8dee2aaSAndroid Build Coastguard Worker }
540*c8dee2aaSAndroid Build Coastguard Worker
541*c8dee2aaSAndroid Build Coastguard Worker // mixed nested (bw inside aa) - should merge
542*c8dee2aaSAndroid Build Coastguard Worker {
543*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
544*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, true);
545*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, false);
546*c8dee2aaSAndroid Build Coastguard Worker
547*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
548*c8dee2aaSAndroid Build Coastguard Worker
549*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
550*c8dee2aaSAndroid Build Coastguard Worker
551*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, isIntersectionOfRects);
552*c8dee2aaSAndroid Build Coastguard Worker }
553*c8dee2aaSAndroid Build Coastguard Worker
554*c8dee2aaSAndroid Build Coastguard Worker // mixed nested (aa inside bw) - should merge
555*c8dee2aaSAndroid Build Coastguard Worker {
556*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
557*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, false);
558*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, true);
559*c8dee2aaSAndroid Build Coastguard Worker
560*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 1 == count(stack));
561*c8dee2aaSAndroid Build Coastguard Worker
562*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
563*c8dee2aaSAndroid Build Coastguard Worker
564*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, isIntersectionOfRects);
565*c8dee2aaSAndroid Build Coastguard Worker }
566*c8dee2aaSAndroid Build Coastguard Worker
567*c8dee2aaSAndroid Build Coastguard Worker // reverse nested (aa inside bw) - should _not_ merge
568*c8dee2aaSAndroid Build Coastguard Worker {
569*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
570*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, false);
571*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, true);
572*c8dee2aaSAndroid Build Coastguard Worker
573*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 2 == count(stack));
574*c8dee2aaSAndroid Build Coastguard Worker
575*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&bound, &type, &isIntersectionOfRects);
576*c8dee2aaSAndroid Build Coastguard Worker
577*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !isIntersectionOfRects);
578*c8dee2aaSAndroid Build Coastguard Worker }
579*c8dee2aaSAndroid Build Coastguard Worker }
580*c8dee2aaSAndroid Build Coastguard Worker
test_quickContains(skiatest::Reporter * reporter)581*c8dee2aaSAndroid Build Coastguard Worker static void test_quickContains(skiatest::Reporter* reporter) {
582*c8dee2aaSAndroid Build Coastguard Worker SkRect testRect = SkRect::MakeLTRB(10, 10, 40, 40);
583*c8dee2aaSAndroid Build Coastguard Worker SkRect insideRect = SkRect::MakeLTRB(20, 20, 30, 30);
584*c8dee2aaSAndroid Build Coastguard Worker SkRect intersectingRect = SkRect::MakeLTRB(25, 25, 50, 50);
585*c8dee2aaSAndroid Build Coastguard Worker SkRect outsideRect = SkRect::MakeLTRB(0, 0, 50, 50);
586*c8dee2aaSAndroid Build Coastguard Worker SkRect nonIntersectingRect = SkRect::MakeLTRB(100, 100, 110, 110);
587*c8dee2aaSAndroid Build Coastguard Worker
588*c8dee2aaSAndroid Build Coastguard Worker SkPath insideCircle;
589*c8dee2aaSAndroid Build Coastguard Worker insideCircle.addCircle(25, 25, 5);
590*c8dee2aaSAndroid Build Coastguard Worker SkPath intersectingCircle;
591*c8dee2aaSAndroid Build Coastguard Worker intersectingCircle.addCircle(25, 40, 10);
592*c8dee2aaSAndroid Build Coastguard Worker SkPath outsideCircle;
593*c8dee2aaSAndroid Build Coastguard Worker outsideCircle.addCircle(25, 25, 50);
594*c8dee2aaSAndroid Build Coastguard Worker SkPath nonIntersectingCircle;
595*c8dee2aaSAndroid Build Coastguard Worker nonIntersectingCircle.addCircle(100, 100, 5);
596*c8dee2aaSAndroid Build Coastguard Worker
597*c8dee2aaSAndroid Build Coastguard Worker {
598*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
599*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kDifference, false);
600*c8dee2aaSAndroid Build Coastguard Worker // return false because quickContains currently does not care for kDifference
601*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
602*c8dee2aaSAndroid Build Coastguard Worker }
603*c8dee2aaSAndroid Build Coastguard Worker
604*c8dee2aaSAndroid Build Coastguard Worker // Replace Op tests
605*c8dee2aaSAndroid Build Coastguard Worker {
606*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
607*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(outsideRect, false);
608*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
609*c8dee2aaSAndroid Build Coastguard Worker }
610*c8dee2aaSAndroid Build Coastguard Worker
611*c8dee2aaSAndroid Build Coastguard Worker {
612*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
613*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
614*c8dee2aaSAndroid Build Coastguard Worker stack.save(); // To prevent in-place substitution by replace OP
615*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(outsideRect, false);
616*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
617*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
618*c8dee2aaSAndroid Build Coastguard Worker }
619*c8dee2aaSAndroid Build Coastguard Worker
620*c8dee2aaSAndroid Build Coastguard Worker {
621*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
622*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
623*c8dee2aaSAndroid Build Coastguard Worker stack.save(); // To prevent in-place substitution by replace OP
624*c8dee2aaSAndroid Build Coastguard Worker stack.replaceClip(insideRect, false);
625*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
626*c8dee2aaSAndroid Build Coastguard Worker stack.restore();
627*c8dee2aaSAndroid Build Coastguard Worker }
628*c8dee2aaSAndroid Build Coastguard Worker
629*c8dee2aaSAndroid Build Coastguard Worker // Verify proper traversal of multi-element clip
630*c8dee2aaSAndroid Build Coastguard Worker {
631*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
632*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
633*c8dee2aaSAndroid Build Coastguard Worker // Use a path for second clip to prevent in-place intersection
634*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(outsideCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
635*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
636*c8dee2aaSAndroid Build Coastguard Worker }
637*c8dee2aaSAndroid Build Coastguard Worker
638*c8dee2aaSAndroid Build Coastguard Worker // Intersect Op tests with rectangles
639*c8dee2aaSAndroid Build Coastguard Worker {
640*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
641*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
642*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
643*c8dee2aaSAndroid Build Coastguard Worker }
644*c8dee2aaSAndroid Build Coastguard Worker
645*c8dee2aaSAndroid Build Coastguard Worker {
646*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
647*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
648*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
649*c8dee2aaSAndroid Build Coastguard Worker }
650*c8dee2aaSAndroid Build Coastguard Worker
651*c8dee2aaSAndroid Build Coastguard Worker {
652*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
653*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(intersectingRect, SkMatrix::I(), SkClipOp::kIntersect, false);
654*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
655*c8dee2aaSAndroid Build Coastguard Worker }
656*c8dee2aaSAndroid Build Coastguard Worker
657*c8dee2aaSAndroid Build Coastguard Worker {
658*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
659*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(nonIntersectingRect, SkMatrix::I(), SkClipOp::kIntersect, false);
660*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
661*c8dee2aaSAndroid Build Coastguard Worker }
662*c8dee2aaSAndroid Build Coastguard Worker
663*c8dee2aaSAndroid Build Coastguard Worker // Intersect Op tests with circle paths
664*c8dee2aaSAndroid Build Coastguard Worker {
665*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
666*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(outsideCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
667*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
668*c8dee2aaSAndroid Build Coastguard Worker }
669*c8dee2aaSAndroid Build Coastguard Worker
670*c8dee2aaSAndroid Build Coastguard Worker {
671*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
672*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(insideCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
673*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
674*c8dee2aaSAndroid Build Coastguard Worker }
675*c8dee2aaSAndroid Build Coastguard Worker
676*c8dee2aaSAndroid Build Coastguard Worker {
677*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
678*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(intersectingCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
679*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
680*c8dee2aaSAndroid Build Coastguard Worker }
681*c8dee2aaSAndroid Build Coastguard Worker
682*c8dee2aaSAndroid Build Coastguard Worker {
683*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
684*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(nonIntersectingCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
685*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
686*c8dee2aaSAndroid Build Coastguard Worker }
687*c8dee2aaSAndroid Build Coastguard Worker
688*c8dee2aaSAndroid Build Coastguard Worker // Intersect Op tests with inverse filled rectangles
689*c8dee2aaSAndroid Build Coastguard Worker {
690*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
691*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
692*c8dee2aaSAndroid Build Coastguard Worker path.addRect(outsideRect);
693*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
694*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
695*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
696*c8dee2aaSAndroid Build Coastguard Worker }
697*c8dee2aaSAndroid Build Coastguard Worker
698*c8dee2aaSAndroid Build Coastguard Worker {
699*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
700*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
701*c8dee2aaSAndroid Build Coastguard Worker path.addRect(insideRect);
702*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
703*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
704*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
705*c8dee2aaSAndroid Build Coastguard Worker }
706*c8dee2aaSAndroid Build Coastguard Worker
707*c8dee2aaSAndroid Build Coastguard Worker {
708*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
709*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
710*c8dee2aaSAndroid Build Coastguard Worker path.addRect(intersectingRect);
711*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
712*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
713*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
714*c8dee2aaSAndroid Build Coastguard Worker }
715*c8dee2aaSAndroid Build Coastguard Worker
716*c8dee2aaSAndroid Build Coastguard Worker {
717*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
718*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
719*c8dee2aaSAndroid Build Coastguard Worker path.addRect(nonIntersectingRect);
720*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
721*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
722*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
723*c8dee2aaSAndroid Build Coastguard Worker }
724*c8dee2aaSAndroid Build Coastguard Worker
725*c8dee2aaSAndroid Build Coastguard Worker // Intersect Op tests with inverse filled circles
726*c8dee2aaSAndroid Build Coastguard Worker {
727*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
728*c8dee2aaSAndroid Build Coastguard Worker SkPath path = outsideCircle;
729*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
730*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
731*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
732*c8dee2aaSAndroid Build Coastguard Worker }
733*c8dee2aaSAndroid Build Coastguard Worker
734*c8dee2aaSAndroid Build Coastguard Worker {
735*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
736*c8dee2aaSAndroid Build Coastguard Worker SkPath path = insideCircle;
737*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
738*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
739*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
740*c8dee2aaSAndroid Build Coastguard Worker }
741*c8dee2aaSAndroid Build Coastguard Worker
742*c8dee2aaSAndroid Build Coastguard Worker {
743*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
744*c8dee2aaSAndroid Build Coastguard Worker SkPath path = intersectingCircle;
745*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
746*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
747*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
748*c8dee2aaSAndroid Build Coastguard Worker }
749*c8dee2aaSAndroid Build Coastguard Worker
750*c8dee2aaSAndroid Build Coastguard Worker {
751*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
752*c8dee2aaSAndroid Build Coastguard Worker SkPath path = nonIntersectingCircle;
753*c8dee2aaSAndroid Build Coastguard Worker path.toggleInverseFillType();
754*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false);
755*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
756*c8dee2aaSAndroid Build Coastguard Worker }
757*c8dee2aaSAndroid Build Coastguard Worker }
758*c8dee2aaSAndroid Build Coastguard Worker
set_region_to_stack(const SkClipStack & stack,const SkIRect & bounds,SkRegion * region)759*c8dee2aaSAndroid Build Coastguard Worker static void set_region_to_stack(const SkClipStack& stack, const SkIRect& bounds, SkRegion* region) {
760*c8dee2aaSAndroid Build Coastguard Worker region->setRect(bounds);
761*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
762*c8dee2aaSAndroid Build Coastguard Worker while (const SkClipStack::Element *element = iter.next()) {
763*c8dee2aaSAndroid Build Coastguard Worker SkRegion elemRegion;
764*c8dee2aaSAndroid Build Coastguard Worker SkRegion boundsRgn(bounds);
765*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
766*c8dee2aaSAndroid Build Coastguard Worker
767*c8dee2aaSAndroid Build Coastguard Worker switch (element->getDeviceSpaceType()) {
768*c8dee2aaSAndroid Build Coastguard Worker case SkClipStack::Element::DeviceSpaceType::kEmpty:
769*c8dee2aaSAndroid Build Coastguard Worker elemRegion.setEmpty();
770*c8dee2aaSAndroid Build Coastguard Worker break;
771*c8dee2aaSAndroid Build Coastguard Worker default:
772*c8dee2aaSAndroid Build Coastguard Worker element->asDeviceSpacePath(&path);
773*c8dee2aaSAndroid Build Coastguard Worker elemRegion.setPath(path, boundsRgn);
774*c8dee2aaSAndroid Build Coastguard Worker break;
775*c8dee2aaSAndroid Build Coastguard Worker }
776*c8dee2aaSAndroid Build Coastguard Worker
777*c8dee2aaSAndroid Build Coastguard Worker region->op(elemRegion, element->isReplaceOp() ? SkRegion::kReplace_Op
778*c8dee2aaSAndroid Build Coastguard Worker : (SkRegion::Op) element->getOp());
779*c8dee2aaSAndroid Build Coastguard Worker }
780*c8dee2aaSAndroid Build Coastguard Worker }
781*c8dee2aaSAndroid Build Coastguard Worker
test_invfill_diff_bug(skiatest::Reporter * reporter)782*c8dee2aaSAndroid Build Coastguard Worker static void test_invfill_diff_bug(skiatest::Reporter* reporter) {
783*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
784*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect({10, 10, 20, 20}, SkMatrix::I(), SkClipOp::kIntersect, false);
785*c8dee2aaSAndroid Build Coastguard Worker
786*c8dee2aaSAndroid Build Coastguard Worker SkPath path;
787*c8dee2aaSAndroid Build Coastguard Worker path.addRect({30, 10, 40, 20});
788*c8dee2aaSAndroid Build Coastguard Worker path.setFillType(SkPathFillType::kInverseWinding);
789*c8dee2aaSAndroid Build Coastguard Worker stack.clipPath(path, SkMatrix::I(), SkClipOp::kDifference, false);
790*c8dee2aaSAndroid Build Coastguard Worker
791*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kEmptyGenID == stack.getTopmostGenID());
792*c8dee2aaSAndroid Build Coastguard Worker
793*c8dee2aaSAndroid Build Coastguard Worker SkRect stackBounds;
794*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::BoundsType stackBoundsType;
795*c8dee2aaSAndroid Build Coastguard Worker stack.getBounds(&stackBounds, &stackBoundsType);
796*c8dee2aaSAndroid Build Coastguard Worker
797*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, stackBounds.isEmpty());
798*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipStack::kNormal_BoundsType == stackBoundsType);
799*c8dee2aaSAndroid Build Coastguard Worker
800*c8dee2aaSAndroid Build Coastguard Worker SkRegion region;
801*c8dee2aaSAndroid Build Coastguard Worker set_region_to_stack(stack, {0, 0, 50, 30}, ®ion);
802*c8dee2aaSAndroid Build Coastguard Worker
803*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, region.isEmpty());
804*c8dee2aaSAndroid Build Coastguard Worker }
805*c8dee2aaSAndroid Build Coastguard Worker
806*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
807*c8dee2aaSAndroid Build Coastguard Worker
test_is_rrect_deep_rect_stack(skiatest::Reporter * reporter)808*c8dee2aaSAndroid Build Coastguard Worker static void test_is_rrect_deep_rect_stack(skiatest::Reporter* reporter) {
809*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkRect kTargetBounds = SkRect::MakeWH(1000, 500);
810*c8dee2aaSAndroid Build Coastguard Worker // All antialiased or all not antialiased.
811*c8dee2aaSAndroid Build Coastguard Worker for (bool aa : {false, true}) {
812*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
813*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i <= 100; ++i) {
814*c8dee2aaSAndroid Build Coastguard Worker stack.save();
815*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(SkRect::MakeLTRB(i, 0.5, kTargetBounds.width(), kTargetBounds.height()),
816*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::I(), SkClipOp::kIntersect, aa);
817*c8dee2aaSAndroid Build Coastguard Worker }
818*c8dee2aaSAndroid Build Coastguard Worker SkRRect rrect;
819*c8dee2aaSAndroid Build Coastguard Worker bool isAA;
820*c8dee2aaSAndroid Build Coastguard Worker SkRRect expected = SkRRect::MakeRect(
821*c8dee2aaSAndroid Build Coastguard Worker SkRect::MakeLTRB(100, 0.5, kTargetBounds.width(), kTargetBounds.height()));
822*c8dee2aaSAndroid Build Coastguard Worker if (stack.isRRect(kTargetBounds, &rrect, &isAA)) {
823*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, rrect == expected);
824*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, aa == isAA);
825*c8dee2aaSAndroid Build Coastguard Worker } else {
826*c8dee2aaSAndroid Build Coastguard Worker ERRORF(reporter, "Expected to be an rrect.");
827*c8dee2aaSAndroid Build Coastguard Worker }
828*c8dee2aaSAndroid Build Coastguard Worker }
829*c8dee2aaSAndroid Build Coastguard Worker // Mixed AA and non-AA without simple containment.
830*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
831*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i <= 100; ++i) {
832*c8dee2aaSAndroid Build Coastguard Worker bool aa = i & 0b1;
833*c8dee2aaSAndroid Build Coastguard Worker int j = 100 - i;
834*c8dee2aaSAndroid Build Coastguard Worker stack.save();
835*c8dee2aaSAndroid Build Coastguard Worker stack.clipRect(SkRect::MakeLTRB(i, j + 0.5, kTargetBounds.width(), kTargetBounds.height()),
836*c8dee2aaSAndroid Build Coastguard Worker SkMatrix::I(), SkClipOp::kIntersect, aa);
837*c8dee2aaSAndroid Build Coastguard Worker }
838*c8dee2aaSAndroid Build Coastguard Worker SkRRect rrect;
839*c8dee2aaSAndroid Build Coastguard Worker bool isAA;
840*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !stack.isRRect(kTargetBounds, &rrect, &isAA));
841*c8dee2aaSAndroid Build Coastguard Worker }
842*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(ClipStack,reporter)843*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(ClipStack, reporter) {
844*c8dee2aaSAndroid Build Coastguard Worker SkClipStack stack;
845*c8dee2aaSAndroid Build Coastguard Worker
846*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
847*c8dee2aaSAndroid Build Coastguard Worker assert_count(reporter, stack, 0);
848*c8dee2aaSAndroid Build Coastguard Worker
849*c8dee2aaSAndroid Build Coastguard Worker static const SkIRect gRects[] = {
850*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 100, 100 },
851*c8dee2aaSAndroid Build Coastguard Worker { 25, 25, 125, 125 },
852*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 1000, 1000 },
853*c8dee2aaSAndroid Build Coastguard Worker { 0, 0, 75, 75 }
854*c8dee2aaSAndroid Build Coastguard Worker };
855*c8dee2aaSAndroid Build Coastguard Worker for (size_t i = 0; i < std::size(gRects); i++) {
856*c8dee2aaSAndroid Build Coastguard Worker stack.clipDevRect(gRects[i], SkClipOp::kIntersect);
857*c8dee2aaSAndroid Build Coastguard Worker }
858*c8dee2aaSAndroid Build Coastguard Worker
859*c8dee2aaSAndroid Build Coastguard Worker // all of the above rects should have been intersected, leaving only 1 rect
860*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::B2TIter iter(stack);
861*c8dee2aaSAndroid Build Coastguard Worker const SkClipStack::Element* element = iter.next();
862*c8dee2aaSAndroid Build Coastguard Worker SkRect answer;
863*c8dee2aaSAndroid Build Coastguard Worker answer.setLTRB(25, 25, 75, 75);
864*c8dee2aaSAndroid Build Coastguard Worker
865*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, element);
866*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter,
867*c8dee2aaSAndroid Build Coastguard Worker SkClipStack::Element::DeviceSpaceType::kRect == element->getDeviceSpaceType());
868*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkClipOp::kIntersect == element->getOp());
869*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == answer);
870*c8dee2aaSAndroid Build Coastguard Worker // now check that we only had one in our iterator
871*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !iter.next());
872*c8dee2aaSAndroid Build Coastguard Worker
873*c8dee2aaSAndroid Build Coastguard Worker stack.reset();
874*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
875*c8dee2aaSAndroid Build Coastguard Worker assert_count(reporter, stack, 0);
876*c8dee2aaSAndroid Build Coastguard Worker
877*c8dee2aaSAndroid Build Coastguard Worker test_assign_and_comparison(reporter);
878*c8dee2aaSAndroid Build Coastguard Worker test_iterators(reporter);
879*c8dee2aaSAndroid Build Coastguard Worker test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kRect);
880*c8dee2aaSAndroid Build Coastguard Worker test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kRRect);
881*c8dee2aaSAndroid Build Coastguard Worker test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kPath);
882*c8dee2aaSAndroid Build Coastguard Worker test_isWideOpen(reporter);
883*c8dee2aaSAndroid Build Coastguard Worker test_rect_merging(reporter);
884*c8dee2aaSAndroid Build Coastguard Worker test_rect_replace(reporter);
885*c8dee2aaSAndroid Build Coastguard Worker test_rect_inverse_fill(reporter);
886*c8dee2aaSAndroid Build Coastguard Worker test_path_replace(reporter);
887*c8dee2aaSAndroid Build Coastguard Worker test_quickContains(reporter);
888*c8dee2aaSAndroid Build Coastguard Worker test_invfill_diff_bug(reporter);
889*c8dee2aaSAndroid Build Coastguard Worker test_is_rrect_deep_rect_stack(reporter);
890*c8dee2aaSAndroid Build Coastguard Worker }
891