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