Flutter Engine
The Flutter Engine
Functions
ClipStackTest.cpp File Reference
#include "include/core/SkClipOp.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathTypes.h"
#include "include/core/SkRRect.h"
#include "include/core/SkRect.h"
#include "include/core/SkRegion.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTo.h"
#include "src/core/SkClipStack.h"
#include "tests/Test.h"
#include <array>
#include <cstring>
#include <initializer_list>

Go to the source code of this file.

Functions

static void test_assign_and_comparison (skiatest::Reporter *reporter)
 
static void assert_count (skiatest::Reporter *reporter, const SkClipStack &stack, int count)
 
static void test_iterators (skiatest::Reporter *reporter)
 
static void test_bounds (skiatest::Reporter *reporter, SkClipStack::Element::DeviceSpaceType primType)
 
static void test_isWideOpen (skiatest::Reporter *reporter)
 
static int count (const SkClipStack &stack)
 
static void test_rect_inverse_fill (skiatest::Reporter *reporter)
 
static void test_rect_replace (skiatest::Reporter *reporter)
 
static void test_path_replace (skiatest::Reporter *reporter)
 
static void test_rect_merging (skiatest::Reporter *reporter)
 
static void test_quickContains (skiatest::Reporter *reporter)
 
static void set_region_to_stack (const SkClipStack &stack, const SkIRect &bounds, SkRegion *region)
 
static void test_invfill_diff_bug (skiatest::Reporter *reporter)
 
static void test_is_rrect_deep_rect_stack (skiatest::Reporter *reporter)
 
 DEF_TEST (ClipStack, reporter)
 

Function Documentation

◆ assert_count()

static void assert_count ( skiatest::Reporter reporter,
const SkClipStack stack,
int  count 
)
static

Definition at line 122 of file ClipStackTest.cpp.

123 {
124 SkClipStack::B2TIter iter(stack);
125 int counter = 0;
126 while (iter.next()) {
127 counter += 1;
128 }
129 REPORTER_ASSERT(reporter, count == counter);
130}
static int count(const SkClipStack &stack)
reporter
Definition: FontMgrTest.cpp:39
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286

◆ count()

static int count ( const SkClipStack stack)
static

Definition at line 349 of file ClipStackTest.cpp.

349 {
350
352
353 const SkClipStack::Element* element = nullptr;
354 int count = 0;
355
356 for (element = iter.prev(); element; element = iter.prev(), ++count) {
357 }
358
359 return count;
360}

◆ DEF_TEST()

DEF_TEST ( ClipStack  ,
reporter   
)

Definition at line 843 of file ClipStackTest.cpp.

843 {
844 SkClipStack stack;
845
847 assert_count(reporter, stack, 0);
848
849 static const SkIRect gRects[] = {
850 { 0, 0, 100, 100 },
851 { 25, 25, 125, 125 },
852 { 0, 0, 1000, 1000 },
853 { 0, 0, 75, 75 }
854 };
855 for (size_t i = 0; i < std::size(gRects); i++) {
856 stack.clipDevRect(gRects[i], SkClipOp::kIntersect);
857 }
858
859 // all of the above rects should have been intersected, leaving only 1 rect
860 SkClipStack::B2TIter iter(stack);
861 const SkClipStack::Element* element = iter.next();
862 SkRect answer;
863 answer.setLTRB(25, 25, 75, 75);
864
865 REPORTER_ASSERT(reporter, element);
869 REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == answer);
870 // now check that we only had one in our iterator
871 REPORTER_ASSERT(reporter, !iter.next());
872
873 stack.reset();
875 assert_count(reporter, stack, 0);
876
890}
static void assert_count(skiatest::Reporter *reporter, const SkClipStack &stack, int count)
static void test_rect_merging(skiatest::Reporter *reporter)
static void test_rect_inverse_fill(skiatest::Reporter *reporter)
static void test_bounds(skiatest::Reporter *reporter, SkClipStack::Element::DeviceSpaceType primType)
static void test_is_rrect_deep_rect_stack(skiatest::Reporter *reporter)
static void test_assign_and_comparison(skiatest::Reporter *reporter)
static void test_rect_replace(skiatest::Reporter *reporter)
static void test_isWideOpen(skiatest::Reporter *reporter)
static void test_iterators(skiatest::Reporter *reporter)
static void test_path_replace(skiatest::Reporter *reporter)
static void test_invfill_diff_bug(skiatest::Reporter *reporter)
static void test_quickContains(skiatest::Reporter *reporter)
@ kPath
This element does not have geometry, but applies a shader to the clip.
@ kRect
This element combines a device space round-rect with the current clip.
@ kRRect
This element combines a device space path with the current clip.
SkClipOp getOp() const
Definition: SkClipStack.h:136
const SkRect & getDeviceSpaceRect() const
Call if getDeviceSpaceType() is kShader to get a reference to the clip shader.
Definition: SkClipStack.h:120
DeviceSpaceType getDeviceSpaceType() const
Call to get the save count associated with this clip element.
Definition: SkClipStack.h:102
void clipDevRect(const SkIRect &ir, SkClipOp op)
Definition: SkClipStack.h:344
int getSaveCount() const
Definition: SkClipStack.h:290
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: SkRect.h:32
void setLTRB(float left, float top, float right, float bottom)
Definition: SkRect.h:865

◆ set_region_to_stack()

static void set_region_to_stack ( const SkClipStack stack,
const SkIRect bounds,
SkRegion region 
)
static

Definition at line 759 of file ClipStackTest.cpp.

759 {
762 while (const SkClipStack::Element *element = iter.next()) {
763 SkRegion elemRegion;
764 SkRegion boundsRgn(bounds);
765 SkPath path;
766
767 switch (element->getDeviceSpaceType()) {
769 elemRegion.setEmpty();
770 break;
771 default:
772 element->asDeviceSpacePath(&path);
773 elemRegion.setPath(path, boundsRgn);
774 break;
775 }
776
777 region->op(elemRegion, element->isReplaceOp() ? SkRegion::kReplace_Op
778 : (SkRegion::Op) element->getOp());
779 }
780}
@ kEmpty
This element makes the clip empty (regardless of previous elements).
Definition: SkPath.h:59
bool setEmpty()
Definition: SkRegion.cpp:185
@ kReplace_Op
replace target with operand
Definition: SkRegion.h:372
bool op(const SkIRect &rect, Op op)
Definition: SkRegion.h:384
bool setRect(const SkIRect &rect)
Definition: SkRegion.cpp:192
bool setPath(const SkPath &path, const SkRegion &clip)
Optional< SkRect > bounds
Definition: SkRecords.h:189
ClipOpAndAA opAA SkRegion region
Definition: SkRecords.h:238
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57

◆ test_assign_and_comparison()

static void test_assign_and_comparison ( skiatest::Reporter reporter)
static

Definition at line 25 of file ClipStackTest.cpp.

25 {
27 bool doAA = false;
28
29 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
30
31 // Build up a clip stack with a path, an empty clip, and a rect.
32 s.save();
33 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
34
35 SkPath p;
36 p.moveTo(5, 6);
37 p.lineTo(7, 8);
38 p.lineTo(5, 9);
39 p.close();
40 s.clipPath(p, SkMatrix::I(), SkClipOp::kIntersect, doAA);
41
42 s.save();
43 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
44
45 SkRect r = SkRect::MakeLTRB(1, 2, 103, 104);
46 s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA);
47 r = SkRect::MakeLTRB(4, 5, 56, 57);
48 s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA);
49
50 s.save();
51 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
52
53 r = SkRect::MakeLTRB(14, 15, 16, 17);
54 s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA);
55
56 // Test that assignment works.
59
60 // Test that different save levels triggers not equal.
61 s.restore();
62 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
64
65 // Test that an equal, but not copied version is equal.
66 s.save();
67 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
68 r = SkRect::MakeLTRB(14, 15, 16, 17);
69 s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA);
71
72 // Test that a different op on one level triggers not equal.
73 s.restore();
74 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
75 s.save();
76 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
77 r = SkRect::MakeLTRB(14, 15, 16, 17);
78 s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA);
80
81 // Test that version constructed with rect-path rather than a rect is still considered equal.
82 s.restore();
83 s.save();
84 SkPath rp;
85 rp.addRect(r);
86 s.clipPath(rp, SkMatrix::I(), SkClipOp::kDifference, doAA);
88
89 // Test that different rects triggers not equal.
90 s.restore();
91 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
92 s.save();
93 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
94
95 r = SkRect::MakeLTRB(24, 25, 26, 27);
96 s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA);
98
99 s.restore();
100 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
101
102 copy.restore();
103 REPORTER_ASSERT(reporter, 2 == copy.getSaveCount());
105 s.restore();
106 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
107 copy.restore();
108 REPORTER_ASSERT(reporter, 1 == copy.getSaveCount());
110
111 // Test that different paths triggers not equal.
112 s.restore();
113 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
114 s.save();
115 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
116
117 p.addRect(r);
118 s.clipPath(p, SkMatrix::I(), SkClipOp::kIntersect, doAA);
120}
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition: SkPath.cpp:864
struct MyStruct s
Definition: copy.py:1
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646

◆ test_bounds()

static void test_bounds ( skiatest::Reporter reporter,
SkClipStack::Element::DeviceSpaceType  primType 
)
static

Definition at line 197 of file ClipStackTest.cpp.

198 {
199 static const int gNumCases = 8;
200 static const SkRect gAnswerRectsBW[gNumCases] = {
201 // A op B
202 { 40, 40, 50, 50 },
203 { 10, 10, 50, 50 },
204
205 // invA op B
206 { 40, 40, 80, 80 },
207 { 0, 0, 100, 100 },
208
209 // A op invB
210 { 10, 10, 50, 50 },
211 { 40, 40, 50, 50 },
212
213 // invA op invB
214 { 0, 0, 100, 100 },
215 { 40, 40, 80, 80 },
216 };
217
218 static const SkClipOp gOps[] = {
221 };
222
223 SkRect rectA, rectB;
224
225 rectA.setLTRB(10, 10, 50, 50);
226 rectB.setLTRB(40, 40, 80, 80);
227
228 SkRRect rrectA, rrectB;
229 rrectA.setOval(rectA);
230 rrectB.setRectXY(rectB, SkIntToScalar(1), SkIntToScalar(2));
231
232 SkPath pathA, pathB;
233
234 pathA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
235 pathB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
236
237 SkClipStack stack;
238 SkRect devClipBound;
239 bool isIntersectionOfRects = false;
240
241 int testCase = 0;
242 int numBitTests = SkClipStack::Element::DeviceSpaceType::kPath == primType ? 4 : 1;
243 for (int invBits = 0; invBits < numBitTests; ++invBits) {
244 for (size_t op = 0; op < std::size(gOps); ++op) {
245
246 stack.save();
247 bool doInvA = SkToBool(invBits & 1);
248 bool doInvB = SkToBool(invBits & 2);
249
254
255 switch (primType) {
258 SkDEBUGFAIL("Don't call this with kEmpty or kShader.");
259 break;
261 stack.clipRect(rectA, SkMatrix::I(), SkClipOp::kIntersect, false);
262 stack.clipRect(rectB, SkMatrix::I(), gOps[op], false);
263 break;
265 stack.clipRRect(rrectA, SkMatrix::I(), SkClipOp::kIntersect, false);
266 stack.clipRRect(rrectB, SkMatrix::I(), gOps[op], false);
267 break;
269 stack.clipPath(pathA, SkMatrix::I(), SkClipOp::kIntersect, false);
270 stack.clipPath(pathB, SkMatrix::I(), gOps[op], false);
271 break;
272 }
273
276
277 stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
278 &isIntersectionOfRects);
279
281 REPORTER_ASSERT(reporter, isIntersectionOfRects ==
282 (gOps[op] == SkClipOp::kIntersect));
283 } else {
284 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
285 }
286
287 SkASSERT(testCase < gNumCases);
288 REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]);
289 ++testCase;
290
291 stack.restore();
292 }
293 }
294}
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkClipOp
Definition: SkClipOp.h:13
#define SkIntToScalar(x)
Definition: SkScalar.h:57
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
void clipRect(const SkRect &, const SkMatrix &matrix, SkClipOp, bool doAA)
void clipRRect(const SkRRect &, const SkMatrix &matrix, SkClipOp, bool doAA)
void getConservativeBounds(int offsetX, int offsetY, int maxWidth, int maxHeight, SkRect *devBounds, bool *isIntersectionOfRects=nullptr) const
uint32_t getTopmostGenID() const
static const uint32_t kWideOpenGenID
Definition: SkClipStack.h:387
void restore()
bool isWideOpen() const
Definition: SkClipStack.h:362
void clipPath(const SkPath &, const SkMatrix &matrix, SkClipOp, bool doAA)
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
SkPath & addRoundRect(const SkRect &rect, SkScalar rx, SkScalar ry, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1093
void setOval(const SkRect &oval)
Definition: SkRRect.cpp:30
void setRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.cpp:52

◆ test_invfill_diff_bug()

static void test_invfill_diff_bug ( skiatest::Reporter reporter)
static

Definition at line 782 of file ClipStackTest.cpp.

782 {
783 SkClipStack stack;
784 stack.clipRect({10, 10, 20, 20}, SkMatrix::I(), SkClipOp::kIntersect, false);
785
786 SkPath path;
787 path.addRect({30, 10, 40, 20});
790
792
793 SkRect stackBounds;
794 SkClipStack::BoundsType stackBoundsType;
795 stack.getBounds(&stackBounds, &stackBoundsType);
796
797 REPORTER_ASSERT(reporter, stackBounds.isEmpty());
799
801 set_region_to_stack(stack, {0, 0, 50, 30}, &region);
802
804}
static void set_region_to_stack(const SkClipStack &stack, const SkIRect &bounds, SkRegion *region)
@ kNormal_BoundsType
Definition: SkClipStack.h:37
static const uint32_t kEmptyGenID
Definition: SkClipStack.h:386
void getBounds(SkRect *canvFiniteBound, BoundsType *boundType, bool *isIntersectionOfRects=nullptr) const
bool isEmpty() const
Definition: SkRegion.h:146
bool isEmpty() const
Definition: SkRect.h:693

◆ test_is_rrect_deep_rect_stack()

static void test_is_rrect_deep_rect_stack ( skiatest::Reporter reporter)
static

Definition at line 808 of file ClipStackTest.cpp.

808 {
809 static constexpr SkRect kTargetBounds = SkRect::MakeWH(1000, 500);
810 // All antialiased or all not antialiased.
811 for (bool aa : {false, true}) {
812 SkClipStack stack;
813 for (int i = 0; i <= 100; ++i) {
814 stack.save();
815 stack.clipRect(SkRect::MakeLTRB(i, 0.5, kTargetBounds.width(), kTargetBounds.height()),
817 }
819 bool isAA;
820 SkRRect expected = SkRRect::MakeRect(
821 SkRect::MakeLTRB(100, 0.5, kTargetBounds.width(), kTargetBounds.height()));
822 if (stack.isRRect(kTargetBounds, &rrect, &isAA)) {
823 REPORTER_ASSERT(reporter, rrect == expected);
824 REPORTER_ASSERT(reporter, aa == isAA);
825 } else {
826 ERRORF(reporter, "Expected to be an rrect.");
827 }
828 }
829 // Mixed AA and non-AA without simple containment.
830 SkClipStack stack;
831 for (int i = 0; i <= 100; ++i) {
832 bool aa = i & 0b1;
833 int j = 100 - i;
834 stack.save();
835 stack.clipRect(SkRect::MakeLTRB(i, j + 0.5, kTargetBounds.width(), kTargetBounds.height()),
837 }
839 bool isAA;
840 REPORTER_ASSERT(reporter, !stack.isRRect(kTargetBounds, &rrect, &isAA));
841}
#define ERRORF(r,...)
Definition: Test.h:293
bool isRRect(const SkRect &bounds, SkRRect *rrect, bool *aa) const
static SkRRect MakeRect(const SkRect &r)
Definition: SkRRect.h:149
SkRRect rrect
Definition: SkRecords.h:232
constexpr float height() const
Definition: SkRect.h:769
constexpr float width() const
Definition: SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609

◆ test_isWideOpen()

static void test_isWideOpen ( skiatest::Reporter reporter)
static

Definition at line 297 of file ClipStackTest.cpp.

297 {
298 {
299 // Empty stack is wide open. Wide open stack means that gen id is wide open.
300 SkClipStack stack;
303 }
304
305 SkRect rectA, rectB;
306
307 rectA.setLTRB(10, 10, 40, 40);
308 rectB.setLTRB(50, 50, 80, 80);
309
310 // Stack should initially be wide open
311 {
312 SkClipStack stack;
313
316 }
317
318 // Test out empty difference from a wide open clip
319 {
320 SkClipStack stack;
321
322 SkRect emptyRect;
323 emptyRect.setEmpty();
324
325 stack.clipRect(emptyRect, SkMatrix::I(), SkClipOp::kDifference, false);
326
329 }
330
331 // Test out return to wide open
332 {
333 SkClipStack stack;
334
335 stack.save();
336
337 stack.clipRect(rectA, SkMatrix::I(), SkClipOp::kIntersect, false);
338
341
342 stack.restore();
343
346 }
347}
void setEmpty()
Definition: SkRect.h:842

◆ test_iterators()

static void test_iterators ( skiatest::Reporter reporter)
static

Definition at line 134 of file ClipStackTest.cpp.

134 {
135 SkClipStack stack;
136
137 static const SkRect gRects[] = {
138 { 0, 0, 40, 40 },
139 { 60, 0, 100, 40 },
140 { 0, 60, 40, 100 },
141 { 60, 60, 100, 100 }
142 };
143
144 for (size_t i = 0; i < std::size(gRects); i++) {
145 // the difference op will prevent these from being fused together
146 stack.clipRect(gRects[i], SkMatrix::I(), SkClipOp::kDifference, false);
147 }
148
149 assert_count(reporter, stack, 4);
150
151 // bottom to top iteration
152 {
153 const SkClipStack::Element* element = nullptr;
154
155 SkClipStack::B2TIter iter(stack);
156 int i;
157
158 for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
160 element->getDeviceSpaceType());
161 REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]);
162 }
163
164 SkASSERT(i == 4);
165 }
166
167 // top to bottom iteration
168 {
169 const SkClipStack::Element* element = nullptr;
170
172 int i;
173
174 for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
176 element->getDeviceSpaceType());
177 REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]);
178 }
179
180 SkASSERT(i == -1);
181 }
182
183 // skipToTopmost
184 {
185 const SkClipStack::Element* element = nullptr;
186
188
189 element = iter.skipToTopmost(SkClipOp::kDifference);
191 element->getDeviceSpaceType());
192 REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[3]);
193 }
194}

◆ test_path_replace()

static void test_path_replace ( skiatest::Reporter reporter)
static

Definition at line 455 of file ClipStackTest.cpp.

455 {
456 auto replacePath = [](SkClipStack* stack, const SkPath& path, bool doAA) {
457 const SkRect wideOpen = SkRect::MakeLTRB(-1000, -1000, 1000, 1000);
458 stack->replaceClip(wideOpen, false);
460 };
461 SkRect rect = SkRect::MakeWH(100, 100);
462 SkPath path;
463 path.addCircle(50, 50, 50);
464
465 // Emulating replace operations with more complex geometry is not atomic, it's a replace
466 // with a wide-open rect and then an intersection with the complex geometry. The replace can
467 // combine with prior elements, but the subsequent intersect cannot be combined so the stack
468 // continues to grow.
469 {
470 SkClipStack stack;
471 REPORTER_ASSERT(reporter, 0 == count(stack));
472 replacePath(&stack, path, false);
473 REPORTER_ASSERT(reporter, 2 == count(stack));
474 replacePath(&stack, path, false);
475 REPORTER_ASSERT(reporter, 2 == count(stack));
476 }
477
478 // Replacing rect with path.
479 {
480 SkClipStack stack;
481 stack.replaceClip(rect, true);
482 REPORTER_ASSERT(reporter, 1 == count(stack));
483 replacePath(&stack, path, true);
484 REPORTER_ASSERT(reporter, 2 == count(stack));
485 }
486}
void replaceClip(const SkRect &devRect, bool doAA)
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350

◆ test_quickContains()

static void test_quickContains ( skiatest::Reporter reporter)
static

Definition at line 581 of file ClipStackTest.cpp.

581 {
582 SkRect testRect = SkRect::MakeLTRB(10, 10, 40, 40);
583 SkRect insideRect = SkRect::MakeLTRB(20, 20, 30, 30);
584 SkRect intersectingRect = SkRect::MakeLTRB(25, 25, 50, 50);
585 SkRect outsideRect = SkRect::MakeLTRB(0, 0, 50, 50);
586 SkRect nonIntersectingRect = SkRect::MakeLTRB(100, 100, 110, 110);
587
588 SkPath insideCircle;
589 insideCircle.addCircle(25, 25, 5);
590 SkPath intersectingCircle;
591 intersectingCircle.addCircle(25, 40, 10);
592 SkPath outsideCircle;
593 outsideCircle.addCircle(25, 25, 50);
594 SkPath nonIntersectingCircle;
595 nonIntersectingCircle.addCircle(100, 100, 5);
596
597 {
598 SkClipStack stack;
599 stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kDifference, false);
600 // return false because quickContains currently does not care for kDifference
601 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
602 }
603
604 // Replace Op tests
605 {
606 SkClipStack stack;
607 stack.replaceClip(outsideRect, false);
608 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
609 }
610
611 {
612 SkClipStack stack;
613 stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
614 stack.save(); // To prevent in-place substitution by replace OP
615 stack.replaceClip(outsideRect, false);
616 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
617 stack.restore();
618 }
619
620 {
621 SkClipStack stack;
622 stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
623 stack.save(); // To prevent in-place substitution by replace OP
624 stack.replaceClip(insideRect, false);
625 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
626 stack.restore();
627 }
628
629 // Verify proper traversal of multi-element clip
630 {
631 SkClipStack stack;
632 stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
633 // Use a path for second clip to prevent in-place intersection
634 stack.clipPath(outsideCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
635 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
636 }
637
638 // Intersect Op tests with rectangles
639 {
640 SkClipStack stack;
641 stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
642 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
643 }
644
645 {
646 SkClipStack stack;
647 stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false);
648 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
649 }
650
651 {
652 SkClipStack stack;
653 stack.clipRect(intersectingRect, SkMatrix::I(), SkClipOp::kIntersect, false);
654 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
655 }
656
657 {
658 SkClipStack stack;
659 stack.clipRect(nonIntersectingRect, SkMatrix::I(), SkClipOp::kIntersect, false);
660 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
661 }
662
663 // Intersect Op tests with circle paths
664 {
665 SkClipStack stack;
666 stack.clipPath(outsideCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
667 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
668 }
669
670 {
671 SkClipStack stack;
672 stack.clipPath(insideCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
673 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
674 }
675
676 {
677 SkClipStack stack;
678 stack.clipPath(intersectingCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
679 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
680 }
681
682 {
683 SkClipStack stack;
684 stack.clipPath(nonIntersectingCircle, SkMatrix::I(), SkClipOp::kIntersect, false);
685 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
686 }
687
688 // Intersect Op tests with inverse filled rectangles
689 {
690 SkClipStack stack;
691 SkPath path;
692 path.addRect(outsideRect);
693 path.toggleInverseFillType();
695 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
696 }
697
698 {
699 SkClipStack stack;
700 SkPath path;
701 path.addRect(insideRect);
702 path.toggleInverseFillType();
704 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
705 }
706
707 {
708 SkClipStack stack;
709 SkPath path;
710 path.addRect(intersectingRect);
711 path.toggleInverseFillType();
713 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
714 }
715
716 {
717 SkClipStack stack;
718 SkPath path;
719 path.addRect(nonIntersectingRect);
720 path.toggleInverseFillType();
722 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
723 }
724
725 // Intersect Op tests with inverse filled circles
726 {
727 SkClipStack stack;
728 SkPath path = outsideCircle;
729 path.toggleInverseFillType();
731 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
732 }
733
734 {
735 SkClipStack stack;
736 SkPath path = insideCircle;
737 path.toggleInverseFillType();
739 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
740 }
741
742 {
743 SkClipStack stack;
744 SkPath path = intersectingCircle;
745 path.toggleInverseFillType();
747 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
748 }
749
750 {
751 SkClipStack stack;
752 SkPath path = nonIntersectingCircle;
753 path.toggleInverseFillType();
755 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
756 }
757}
bool quickContains(const SkRect &devRect) const
Definition: SkClipStack.h:336
SkPath & addCircle(SkScalar x, SkScalar y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1213

◆ test_rect_inverse_fill()

static void test_rect_inverse_fill ( skiatest::Reporter reporter)
static

Definition at line 362 of file ClipStackTest.cpp.

362 {
363 // non-intersecting rectangles
364 SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10);
365
366 SkPath path;
367 path.addRect(rect);
368 path.toggleInverseFillType();
369 SkClipStack stack;
371
373 SkClipStack::BoundsType boundsType;
374 stack.getBounds(&bounds, &boundsType);
377}
@ kInsideOut_BoundsType
Definition: SkClipStack.h:43

◆ test_rect_merging()

static void test_rect_merging ( skiatest::Reporter reporter)
static

Definition at line 490 of file ClipStackTest.cpp.

490 {
491
492 SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50);
493 SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
494
495 SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
496 SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60);
497
498 SkRect bound;
500 bool isIntersectionOfRects;
501
502 // all bw overlapping - should merge
503 {
504 SkClipStack stack;
505 stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, false);
506 stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, false);
507
508 REPORTER_ASSERT(reporter, 1 == count(stack));
509
510 stack.getBounds(&bound, &type, &isIntersectionOfRects);
511
512 REPORTER_ASSERT(reporter, isIntersectionOfRects);
513 }
514
515 // all aa overlapping - should merge
516 {
517 SkClipStack stack;
518 stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, true);
519 stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, true);
520
521 REPORTER_ASSERT(reporter, 1 == count(stack));
522
523 stack.getBounds(&bound, &type, &isIntersectionOfRects);
524
525 REPORTER_ASSERT(reporter, isIntersectionOfRects);
526 }
527
528 // mixed overlapping - should _not_ merge
529 {
530 SkClipStack stack;
531 stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, true);
532 stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, false);
533
534 REPORTER_ASSERT(reporter, 2 == count(stack));
535
536 stack.getBounds(&bound, &type, &isIntersectionOfRects);
537
538 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
539 }
540
541 // mixed nested (bw inside aa) - should merge
542 {
543 SkClipStack stack;
544 stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, true);
545 stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, false);
546
547 REPORTER_ASSERT(reporter, 1 == count(stack));
548
549 stack.getBounds(&bound, &type, &isIntersectionOfRects);
550
551 REPORTER_ASSERT(reporter, isIntersectionOfRects);
552 }
553
554 // mixed nested (aa inside bw) - should merge
555 {
556 SkClipStack stack;
557 stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, false);
558 stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, true);
559
560 REPORTER_ASSERT(reporter, 1 == count(stack));
561
562 stack.getBounds(&bound, &type, &isIntersectionOfRects);
563
564 REPORTER_ASSERT(reporter, isIntersectionOfRects);
565 }
566
567 // reverse nested (aa inside bw) - should _not_ merge
568 {
569 SkClipStack stack;
570 stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, false);
571 stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, true);
572
573 REPORTER_ASSERT(reporter, 2 == count(stack));
574
575 stack.getBounds(&bound, &type, &isIntersectionOfRects);
576
577 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
578 }
579}
GLenum type

◆ test_rect_replace()

static void test_rect_replace ( skiatest::Reporter reporter)
static

Definition at line 379 of file ClipStackTest.cpp.

379 {
380 SkRect rect = SkRect::MakeWH(100, 100);
381 SkRect rect2 = SkRect::MakeXYWH(50, 50, 100, 100);
382
383 SkRect bound;
385 bool isIntersectionOfRects;
386
387 // Adding a new rect with the replace operator should not increase
388 // the stack depth. BW replacing BW.
389 {
390 SkClipStack stack;
391 REPORTER_ASSERT(reporter, 0 == count(stack));
392 stack.replaceClip(rect, false);
393 REPORTER_ASSERT(reporter, 1 == count(stack));
394 stack.replaceClip(rect, false);
395 REPORTER_ASSERT(reporter, 1 == count(stack));
396 }
397
398 // Adding a new rect with the replace operator should not increase
399 // the stack depth. AA replacing AA.
400 {
401 SkClipStack stack;
402 REPORTER_ASSERT(reporter, 0 == count(stack));
403 stack.replaceClip(rect, true);
404 REPORTER_ASSERT(reporter, 1 == count(stack));
405 stack.replaceClip(rect, true);
406 REPORTER_ASSERT(reporter, 1 == count(stack));
407 }
408
409 // Adding a new rect with the replace operator should not increase
410 // the stack depth. BW replacing AA replacing BW.
411 {
412 SkClipStack stack;
413 REPORTER_ASSERT(reporter, 0 == count(stack));
414 stack.replaceClip(rect, false);
415 REPORTER_ASSERT(reporter, 1 == count(stack));
416 stack.replaceClip(rect, true);
417 REPORTER_ASSERT(reporter, 1 == count(stack));
418 stack.replaceClip(rect, false);
419 REPORTER_ASSERT(reporter, 1 == count(stack));
420 }
421
422 // Make sure replace clip rects don't collapse too much.
423 {
424 SkClipStack stack;
425 stack.replaceClip(rect, false);
426 stack.clipRect(rect2, SkMatrix::I(), SkClipOp::kIntersect, false);
427 REPORTER_ASSERT(reporter, 1 == count(stack));
428
429 stack.save();
430 stack.replaceClip(rect, false);
431 REPORTER_ASSERT(reporter, 2 == count(stack));
432 stack.getBounds(&bound, &type, &isIntersectionOfRects);
433 REPORTER_ASSERT(reporter, bound == rect);
434 stack.restore();
435 REPORTER_ASSERT(reporter, 1 == count(stack));
436
437 stack.save();
438 stack.replaceClip(rect, false);
439 stack.replaceClip(rect, false);
440 REPORTER_ASSERT(reporter, 2 == count(stack));
441 stack.restore();
442 REPORTER_ASSERT(reporter, 1 == count(stack));
443
444 stack.save();
445 stack.replaceClip(rect, false);
446 stack.clipRect(rect2, SkMatrix::I(), SkClipOp::kIntersect, false);
447 stack.replaceClip(rect, false);
448 REPORTER_ASSERT(reporter, 2 == count(stack));
449 stack.restore();
450 REPORTER_ASSERT(reporter, 1 == count(stack));
451 }
452}
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659