blob: 247acb06584da240ca272270dbe603257dd960af [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00007
reed@google.combdee9fc2011-02-22 20:17:43 +00008#include "Test.h"
9#include "SkClipStack.h"
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000010#include "SkPath.h"
bsalomon@google.com51a62862012-11-26 21:19:43 +000011#include "SkRandom.h"
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000012#include "SkRect.h"
bsalomon@google.com51a62862012-11-26 21:19:43 +000013#include "SkRegion.h"
robertphillips@google.com80214e22012-07-20 15:33:18 +000014
csmartdaltoncbecb082016-07-22 08:59:08 -070015#if SK_SUPPORT_GPU
16#include "GrReducedClip.h"
17typedef GrReducedClip::ElementList ElementList;
18typedef GrReducedClip::InitialState InitialState;
19#endif
20
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000021static void test_assign_and_comparison(skiatest::Reporter* reporter) {
22 SkClipStack s;
reed@google.comd9f2dea2011-10-12 14:43:27 +000023 bool doAA = false;
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000024
robertphillips@google.com80214e22012-07-20 15:33:18 +000025 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
26
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000027 // Build up a clip stack with a path, an empty clip, and a rect.
28 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000029 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
30
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000031 SkPath p;
32 p.moveTo(5, 6);
33 p.lineTo(7, 8);
34 p.lineTo(5, 9);
35 p.close();
Brian Salomona3b45d42016-10-03 11:36:16 -040036 s.clipPath(p, SkMatrix::I(), SkCanvas::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000037
38 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000039 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
40
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000041 SkRect r = SkRect::MakeLTRB(1, 2, 3, 4);
Brian Salomona3b45d42016-10-03 11:36:16 -040042 s.clipRect(r, SkMatrix::I(), SkCanvas::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000043 r = SkRect::MakeLTRB(10, 11, 12, 13);
Brian Salomona3b45d42016-10-03 11:36:16 -040044 s.clipRect(r, SkMatrix::I(), SkCanvas::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000045
46 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000047 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
48
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000049 r = SkRect::MakeLTRB(14, 15, 16, 17);
Brian Salomona3b45d42016-10-03 11:36:16 -040050 s.clipRect(r, SkMatrix::I(), SkCanvas::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000051
52 // Test that assignment works.
53 SkClipStack copy = s;
54 REPORTER_ASSERT(reporter, s == copy);
55
56 // Test that different save levels triggers not equal.
57 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000058 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000059 REPORTER_ASSERT(reporter, s != copy);
60
61 // Test that an equal, but not copied version is equal.
62 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000063 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000064 r = SkRect::MakeLTRB(14, 15, 16, 17);
Brian Salomona3b45d42016-10-03 11:36:16 -040065 s.clipRect(r, SkMatrix::I(), SkCanvas::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000066 REPORTER_ASSERT(reporter, s == copy);
67
68 // Test that a different op on one level triggers not equal.
69 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000070 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000071 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000072 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000073 r = SkRect::MakeLTRB(14, 15, 16, 17);
Brian Salomona3b45d42016-10-03 11:36:16 -040074 s.clipRect(r, SkMatrix::I(), SkCanvas::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000075 REPORTER_ASSERT(reporter, s != copy);
76
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000077 // Test that version constructed with rect-path rather than a rect is still considered equal.
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000078 s.restore();
79 s.save();
80 SkPath rp;
81 rp.addRect(r);
Brian Salomona3b45d42016-10-03 11:36:16 -040082 s.clipPath(rp, SkMatrix::I(), SkCanvas::kUnion_Op, doAA);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +000083 REPORTER_ASSERT(reporter, s == copy);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000084
85 // Test that different rects triggers not equal.
86 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000087 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000088 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000089 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
90
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000091 r = SkRect::MakeLTRB(24, 25, 26, 27);
Brian Salomona3b45d42016-10-03 11:36:16 -040092 s.clipRect(r, SkMatrix::I(), SkCanvas::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000093 REPORTER_ASSERT(reporter, s != copy);
94
95 // Sanity check
96 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000097 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
98
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000099 copy.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000100 REPORTER_ASSERT(reporter, 2 == copy.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000101 REPORTER_ASSERT(reporter, s == copy);
102 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000103 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000104 copy.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000105 REPORTER_ASSERT(reporter, 1 == copy.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000106 REPORTER_ASSERT(reporter, s == copy);
107
108 // Test that different paths triggers not equal.
109 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000110 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000111 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000112 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
113
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000114 p.addRect(r);
Brian Salomona3b45d42016-10-03 11:36:16 -0400115 s.clipPath(p, SkMatrix::I(), SkCanvas::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000116 REPORTER_ASSERT(reporter, s != copy);
117}
reed@google.combdee9fc2011-02-22 20:17:43 +0000118
119static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack,
120 int count) {
robertphillips@google.com80214e22012-07-20 15:33:18 +0000121 SkClipStack::B2TIter iter(stack);
reed@google.combdee9fc2011-02-22 20:17:43 +0000122 int counter = 0;
123 while (iter.next()) {
124 counter += 1;
125 }
126 REPORTER_ASSERT(reporter, count == counter);
127}
128
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000129// Exercise the SkClipStack's bottom to top and bidirectional iterators
130// (including the skipToTopmost functionality)
robertphillips@google.com80214e22012-07-20 15:33:18 +0000131static void test_iterators(skiatest::Reporter* reporter) {
132 SkClipStack stack;
133
134 static const SkRect gRects[] = {
135 { 0, 0, 40, 40 },
136 { 60, 0, 100, 40 },
137 { 0, 60, 40, 100 },
138 { 60, 60, 100, 100 }
139 };
140
141 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
142 // the union op will prevent these from being fused together
Brian Salomona3b45d42016-10-03 11:36:16 -0400143 stack.clipRect(gRects[i], SkMatrix::I(), SkCanvas::kUnion_Op, false);
robertphillips@google.com80214e22012-07-20 15:33:18 +0000144 }
145
146 assert_count(reporter, stack, 4);
147
148 // bottom to top iteration
149 {
halcanary96fcdcc2015-08-27 07:41:13 -0700150 const SkClipStack::Element* element = nullptr;
robertphillips@google.com80214e22012-07-20 15:33:18 +0000151
152 SkClipStack::B2TIter iter(stack);
153 int i;
154
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000155 for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
156 REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
157 REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
robertphillips@google.com80214e22012-07-20 15:33:18 +0000158 }
159
160 SkASSERT(i == 4);
161 }
162
163 // top to bottom iteration
164 {
halcanary96fcdcc2015-08-27 07:41:13 -0700165 const SkClipStack::Element* element = nullptr;
robertphillips@google.com80214e22012-07-20 15:33:18 +0000166
167 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
168 int i;
169
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000170 for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
171 REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
172 REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
robertphillips@google.com80214e22012-07-20 15:33:18 +0000173 }
174
175 SkASSERT(i == -1);
176 }
177
178 // skipToTopmost
179 {
halcanary96fcdcc2015-08-27 07:41:13 -0700180 const SkClipStack::Element* element = nullptr;
robertphillips@google.com80214e22012-07-20 15:33:18 +0000181
182 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
183
reed73603f32016-09-20 08:42:38 -0700184 element = iter.skipToTopmost(SkCanvas::kUnion_Op);
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000185 REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
186 REPORTER_ASSERT(reporter, element->getRect() == gRects[3]);
robertphillips@google.com80214e22012-07-20 15:33:18 +0000187 }
188}
189
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000190// Exercise the SkClipStack's getConservativeBounds computation
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000191static void test_bounds(skiatest::Reporter* reporter, SkClipStack::Element::Type primType) {
robertphillips@google.com607fe072012-07-24 13:54:00 +0000192 static const int gNumCases = 20;
193 static const SkRect gAnswerRectsBW[gNumCases] = {
194 // A op B
195 { 40, 40, 50, 50 },
196 { 10, 10, 50, 50 },
197 { 10, 10, 80, 80 },
198 { 10, 10, 80, 80 },
199 { 40, 40, 80, 80 },
200
201 // invA op B
202 { 40, 40, 80, 80 },
203 { 0, 0, 100, 100 },
204 { 0, 0, 100, 100 },
205 { 0, 0, 100, 100 },
206 { 40, 40, 50, 50 },
207
208 // A op invB
209 { 10, 10, 50, 50 },
210 { 40, 40, 50, 50 },
211 { 0, 0, 100, 100 },
212 { 0, 0, 100, 100 },
213 { 0, 0, 100, 100 },
214
215 // invA op invB
216 { 0, 0, 100, 100 },
217 { 40, 40, 80, 80 },
218 { 0, 0, 100, 100 },
219 { 10, 10, 80, 80 },
220 { 10, 10, 50, 50 },
221 };
222
reed73603f32016-09-20 08:42:38 -0700223 static const SkCanvas::ClipOp gOps[] = {
224 SkCanvas::kIntersect_Op,
225 SkCanvas::kDifference_Op,
226 SkCanvas::kUnion_Op,
227 SkCanvas::kXOR_Op,
228 SkCanvas::kReverseDifference_Op
robertphillips@google.com607fe072012-07-24 13:54:00 +0000229 };
230
231 SkRect rectA, rectB;
232
233 rectA.iset(10, 10, 50, 50);
234 rectB.iset(40, 40, 80, 80);
235
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000236 SkRRect rrectA, rrectB;
237 rrectA.setOval(rectA);
238 rrectB.setRectXY(rectB, SkIntToScalar(1), SkIntToScalar(2));
robertphillips@google.com607fe072012-07-24 13:54:00 +0000239
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000240 SkPath pathA, pathB;
241
242 pathA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
243 pathB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
robertphillips@google.com607fe072012-07-24 13:54:00 +0000244
245 SkClipStack stack;
robertphillips@google.com7b112892012-07-31 15:18:21 +0000246 SkRect devClipBound;
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000247 bool isIntersectionOfRects = false;
robertphillips@google.com607fe072012-07-24 13:54:00 +0000248
249 int testCase = 0;
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000250 int numBitTests = SkClipStack::Element::kPath_Type == primType ? 4 : 1;
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000251 for (int invBits = 0; invBits < numBitTests; ++invBits) {
robertphillips@google.com607fe072012-07-24 13:54:00 +0000252 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
253
254 stack.save();
255 bool doInvA = SkToBool(invBits & 1);
256 bool doInvB = SkToBool(invBits & 2);
257
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000258 pathA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
robertphillips@google.com607fe072012-07-24 13:54:00 +0000259 SkPath::kEvenOdd_FillType);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000260 pathB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
robertphillips@google.com607fe072012-07-24 13:54:00 +0000261 SkPath::kEvenOdd_FillType);
262
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000263 switch (primType) {
264 case SkClipStack::Element::kEmpty_Type:
265 SkDEBUGFAIL("Don't call this with kEmpty.");
266 break;
267 case SkClipStack::Element::kRect_Type:
Brian Salomona3b45d42016-10-03 11:36:16 -0400268 stack.clipRect(rectA, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
269 stack.clipRect(rectB, SkMatrix::I(), gOps[op], false);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000270 break;
271 case SkClipStack::Element::kRRect_Type:
Brian Salomona3b45d42016-10-03 11:36:16 -0400272 stack.clipRRect(rrectA, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
273 stack.clipRRect(rrectB, SkMatrix::I(), gOps[op], false);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000274 break;
275 case SkClipStack::Element::kPath_Type:
Brian Salomona3b45d42016-10-03 11:36:16 -0400276 stack.clipPath(pathA, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
277 stack.clipPath(pathB, SkMatrix::I(), gOps[op], false);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000278 break;
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000279 }
robertphillips@google.com607fe072012-07-24 13:54:00 +0000280
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000281 REPORTER_ASSERT(reporter, !stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000282 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000283
robertphillips@google.com7b112892012-07-31 15:18:21 +0000284 stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000285 &isIntersectionOfRects);
286
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000287 if (SkClipStack::Element::kRect_Type == primType) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000288 REPORTER_ASSERT(reporter, isIntersectionOfRects ==
reed73603f32016-09-20 08:42:38 -0700289 (gOps[op] == SkCanvas::kIntersect_Op));
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000290 } else {
291 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
292 }
robertphillips@google.com607fe072012-07-24 13:54:00 +0000293
294 SkASSERT(testCase < gNumCases);
robertphillips@google.com7b112892012-07-31 15:18:21 +0000295 REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]);
robertphillips@google.com607fe072012-07-24 13:54:00 +0000296 ++testCase;
297
298 stack.restore();
299 }
300 }
301}
302
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000303// Test out 'isWideOpen' entry point
304static void test_isWideOpen(skiatest::Reporter* reporter) {
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000305 {
306 // Empty stack is wide open. Wide open stack means that gen id is wide open.
307 SkClipStack stack;
308 REPORTER_ASSERT(reporter, stack.isWideOpen());
309 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
310 }
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000311
312 SkRect rectA, rectB;
313
314 rectA.iset(10, 10, 40, 40);
315 rectB.iset(50, 50, 80, 80);
316
317 // Stack should initially be wide open
318 {
319 SkClipStack stack;
320
321 REPORTER_ASSERT(reporter, stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000322 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000323 }
324
325 // Test out case where the user specifies a union that includes everything
326 {
327 SkClipStack stack;
328
329 SkPath clipA, clipB;
330
331 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
332 clipA.setFillType(SkPath::kInverseEvenOdd_FillType);
333
334 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
335 clipB.setFillType(SkPath::kInverseEvenOdd_FillType);
336
Brian Salomona3b45d42016-10-03 11:36:16 -0400337 stack.clipPath(clipA, SkMatrix::I(), SkCanvas::kReplace_Op, false);
338 stack.clipPath(clipB, SkMatrix::I(), SkCanvas::kUnion_Op, false);
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000339
340 REPORTER_ASSERT(reporter, stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000341 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000342 }
343
344 // Test out union w/ a wide open clip
345 {
346 SkClipStack stack;
347
Brian Salomona3b45d42016-10-03 11:36:16 -0400348 stack.clipRect(rectA, SkMatrix::I(), SkCanvas::kUnion_Op, false);
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000349
350 REPORTER_ASSERT(reporter, stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000351 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000352 }
353
354 // Test out empty difference from a wide open clip
355 {
356 SkClipStack stack;
357
358 SkRect emptyRect;
359 emptyRect.setEmpty();
360
Brian Salomona3b45d42016-10-03 11:36:16 -0400361 stack.clipRect(emptyRect, SkMatrix::I(), SkCanvas::kDifference_Op, false);
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000362
363 REPORTER_ASSERT(reporter, stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000364 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000365 }
366
367 // Test out return to wide open
368 {
369 SkClipStack stack;
370
371 stack.save();
372
Brian Salomona3b45d42016-10-03 11:36:16 -0400373 stack.clipRect(rectA, SkMatrix::I(), SkCanvas::kReplace_Op, false);
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000374
375 REPORTER_ASSERT(reporter, !stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000376 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000377
378 stack.restore();
379
380 REPORTER_ASSERT(reporter, stack.isWideOpen());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +0000381 REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID());
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000382 }
383}
384
bsalomon@google.com100abf42012-09-05 17:40:04 +0000385static int count(const SkClipStack& stack) {
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000386
387 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
388
halcanary96fcdcc2015-08-27 07:41:13 -0700389 const SkClipStack::Element* element = nullptr;
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000390 int count = 0;
391
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000392 for (element = iter.prev(); element; element = iter.prev(), ++count) {
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000393 ;
394 }
395
396 return count;
397}
398
junov@chromium.orgedf32d52012-12-10 14:57:54 +0000399static void test_rect_inverse_fill(skiatest::Reporter* reporter) {
400 // non-intersecting rectangles
401 SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10);
402
403 SkPath path;
404 path.addRect(rect);
405 path.toggleInverseFillType();
406 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400407 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.orgedf32d52012-12-10 14:57:54 +0000408
409 SkRect bounds;
410 SkClipStack::BoundsType boundsType;
411 stack.getBounds(&bounds, &boundsType);
412 REPORTER_ASSERT(reporter, SkClipStack::kInsideOut_BoundsType == boundsType);
413 REPORTER_ASSERT(reporter, bounds == rect);
414}
415
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000416static void test_rect_replace(skiatest::Reporter* reporter) {
417 SkRect rect = SkRect::MakeWH(100, 100);
418 SkRect rect2 = SkRect::MakeXYWH(50, 50, 100, 100);
419
420 SkRect bound;
421 SkClipStack::BoundsType type;
422 bool isIntersectionOfRects;
423
424 // Adding a new rect with the replace operator should not increase
425 // the stack depth. BW replacing BW.
426 {
427 SkClipStack stack;
428 REPORTER_ASSERT(reporter, 0 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400429 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000430 REPORTER_ASSERT(reporter, 1 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400431 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000432 REPORTER_ASSERT(reporter, 1 == count(stack));
433 }
434
435 // Adding a new rect with the replace operator should not increase
436 // the stack depth. AA replacing AA.
437 {
438 SkClipStack stack;
439 REPORTER_ASSERT(reporter, 0 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400440 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, true);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000441 REPORTER_ASSERT(reporter, 1 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400442 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, true);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000443 REPORTER_ASSERT(reporter, 1 == count(stack));
444 }
445
446 // Adding a new rect with the replace operator should not increase
447 // the stack depth. BW replacing AA replacing BW.
448 {
449 SkClipStack stack;
450 REPORTER_ASSERT(reporter, 0 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400451 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000452 REPORTER_ASSERT(reporter, 1 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400453 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, true);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000454 REPORTER_ASSERT(reporter, 1 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400455 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000456 REPORTER_ASSERT(reporter, 1 == count(stack));
457 }
458
459 // Make sure replace clip rects don't collapse too much.
460 {
461 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400462 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
463 stack.clipRect(rect2, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000464 REPORTER_ASSERT(reporter, 1 == count(stack));
465
466 stack.save();
Brian Salomona3b45d42016-10-03 11:36:16 -0400467 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000468 REPORTER_ASSERT(reporter, 2 == count(stack));
469 stack.getBounds(&bound, &type, &isIntersectionOfRects);
470 REPORTER_ASSERT(reporter, bound == rect);
471 stack.restore();
472 REPORTER_ASSERT(reporter, 1 == count(stack));
473
474 stack.save();
Brian Salomona3b45d42016-10-03 11:36:16 -0400475 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
476 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000477 REPORTER_ASSERT(reporter, 2 == count(stack));
478 stack.restore();
479 REPORTER_ASSERT(reporter, 1 == count(stack));
480
481 stack.save();
Brian Salomona3b45d42016-10-03 11:36:16 -0400482 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
483 stack.clipRect(rect2, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
484 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000485 REPORTER_ASSERT(reporter, 2 == count(stack));
486 stack.restore();
487 REPORTER_ASSERT(reporter, 1 == count(stack));
488 }
489}
490
491// Simplified path-based version of test_rect_replace.
492static void test_path_replace(skiatest::Reporter* reporter) {
493 SkRect rect = SkRect::MakeWH(100, 100);
494 SkPath path;
495 path.addCircle(50, 50, 50);
496
497 // Replace operation doesn't grow the stack.
498 {
499 SkClipStack stack;
500 REPORTER_ASSERT(reporter, 0 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400501 stack.clipPath(path, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000502 REPORTER_ASSERT(reporter, 1 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400503 stack.clipPath(path, SkMatrix::I(), SkCanvas::kReplace_Op, false);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000504 REPORTER_ASSERT(reporter, 1 == count(stack));
505 }
506
507 // Replacing rect with path.
508 {
509 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400510 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kReplace_Op, true);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000511 REPORTER_ASSERT(reporter, 1 == count(stack));
Brian Salomona3b45d42016-10-03 11:36:16 -0400512 stack.clipPath(path, SkMatrix::I(), SkCanvas::kReplace_Op, true);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +0000513 REPORTER_ASSERT(reporter, 1 == count(stack));
514 }
515}
516
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000517// Test out SkClipStack's merging of rect clips. In particular exercise
518// merging of aa vs. bw rects.
519static void test_rect_merging(skiatest::Reporter* reporter) {
520
521 SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50);
522 SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
523
524 SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
525 SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60);
526
527 SkRect bound;
528 SkClipStack::BoundsType type;
529 bool isIntersectionOfRects;
530
531 // all bw overlapping - should merge
532 {
533 SkClipStack stack;
534
Brian Salomona3b45d42016-10-03 11:36:16 -0400535 stack.clipRect(overlapLeft, SkMatrix::I(), SkCanvas::kReplace_Op, false);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000536
Brian Salomona3b45d42016-10-03 11:36:16 -0400537 stack.clipRect(overlapRight, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000538
539 REPORTER_ASSERT(reporter, 1 == count(stack));
540
541 stack.getBounds(&bound, &type, &isIntersectionOfRects);
542
543 REPORTER_ASSERT(reporter, isIntersectionOfRects);
544 }
545
546 // all aa overlapping - should merge
547 {
548 SkClipStack stack;
549
Brian Salomona3b45d42016-10-03 11:36:16 -0400550 stack.clipRect(overlapLeft, SkMatrix::I(), SkCanvas::kReplace_Op, true);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000551
Brian Salomona3b45d42016-10-03 11:36:16 -0400552 stack.clipRect(overlapRight, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000553
554 REPORTER_ASSERT(reporter, 1 == count(stack));
555
556 stack.getBounds(&bound, &type, &isIntersectionOfRects);
557
558 REPORTER_ASSERT(reporter, isIntersectionOfRects);
559 }
560
561 // mixed overlapping - should _not_ merge
562 {
563 SkClipStack stack;
564
Brian Salomona3b45d42016-10-03 11:36:16 -0400565 stack.clipRect(overlapLeft, SkMatrix::I(), SkCanvas::kReplace_Op, true);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000566
Brian Salomona3b45d42016-10-03 11:36:16 -0400567 stack.clipRect(overlapRight, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000568
569 REPORTER_ASSERT(reporter, 2 == count(stack));
570
571 stack.getBounds(&bound, &type, &isIntersectionOfRects);
572
573 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
574 }
575
576 // mixed nested (bw inside aa) - should merge
577 {
578 SkClipStack stack;
579
Brian Salomona3b45d42016-10-03 11:36:16 -0400580 stack.clipRect(nestedParent, SkMatrix::I(), SkCanvas::kReplace_Op, true);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000581
Brian Salomona3b45d42016-10-03 11:36:16 -0400582 stack.clipRect(nestedChild, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000583
584 REPORTER_ASSERT(reporter, 1 == count(stack));
585
586 stack.getBounds(&bound, &type, &isIntersectionOfRects);
587
588 REPORTER_ASSERT(reporter, isIntersectionOfRects);
589 }
590
591 // mixed nested (aa inside bw) - should merge
592 {
593 SkClipStack stack;
594
Brian Salomona3b45d42016-10-03 11:36:16 -0400595 stack.clipRect(nestedParent, SkMatrix::I(), SkCanvas::kReplace_Op, false);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000596
Brian Salomona3b45d42016-10-03 11:36:16 -0400597 stack.clipRect(nestedChild, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000598
599 REPORTER_ASSERT(reporter, 1 == count(stack));
600
601 stack.getBounds(&bound, &type, &isIntersectionOfRects);
602
603 REPORTER_ASSERT(reporter, isIntersectionOfRects);
604 }
605
606 // reverse nested (aa inside bw) - should _not_ merge
607 {
608 SkClipStack stack;
609
Brian Salomona3b45d42016-10-03 11:36:16 -0400610 stack.clipRect(nestedChild, SkMatrix::I(), SkCanvas::kReplace_Op, false);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000611
Brian Salomona3b45d42016-10-03 11:36:16 -0400612 stack.clipRect(nestedParent, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000613
614 REPORTER_ASSERT(reporter, 2 == count(stack));
615
616 stack.getBounds(&bound, &type, &isIntersectionOfRects);
617
618 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
619 }
620}
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000621
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000622static void test_quickContains(skiatest::Reporter* reporter) {
623 SkRect testRect = SkRect::MakeLTRB(10, 10, 40, 40);
624 SkRect insideRect = SkRect::MakeLTRB(20, 20, 30, 30);
625 SkRect intersectingRect = SkRect::MakeLTRB(25, 25, 50, 50);
626 SkRect outsideRect = SkRect::MakeLTRB(0, 0, 50, 50);
627 SkRect nonIntersectingRect = SkRect::MakeLTRB(100, 100, 110, 110);
628
629 SkPath insideCircle;
630 insideCircle.addCircle(25, 25, 5);
631 SkPath intersectingCircle;
632 intersectingCircle.addCircle(25, 40, 10);
633 SkPath outsideCircle;
634 outsideCircle.addCircle(25, 25, 50);
635 SkPath nonIntersectingCircle;
636 nonIntersectingCircle.addCircle(100, 100, 5);
637
638 {
639 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400640 stack.clipRect(outsideRect, SkMatrix::I(), SkCanvas::kDifference_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000641 // return false because quickContains currently does not care for kDifference_Op
642 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
643 }
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000644
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000645 // Replace Op tests
646 {
647 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400648 stack.clipRect(outsideRect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000649 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
650 }
651
652 {
653 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400654 stack.clipRect(insideRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000655 stack.save(); // To prevent in-place substitution by replace OP
Brian Salomona3b45d42016-10-03 11:36:16 -0400656 stack.clipRect(outsideRect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000657 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
658 stack.restore();
659 }
660
661 {
662 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400663 stack.clipRect(outsideRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000664 stack.save(); // To prevent in-place substitution by replace OP
Brian Salomona3b45d42016-10-03 11:36:16 -0400665 stack.clipRect(insideRect, SkMatrix::I(), SkCanvas::kReplace_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000666 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
667 stack.restore();
668 }
669
670 // Verify proper traversal of multi-element clip
671 {
672 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400673 stack.clipRect(insideRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000674 // Use a path for second clip to prevent in-place intersection
Brian Salomona3b45d42016-10-03 11:36:16 -0400675 stack.clipPath(outsideCircle, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000676 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
677 }
678
679 // Intersect Op tests with rectangles
680 {
681 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400682 stack.clipRect(outsideRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000683 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
684 }
685
686 {
687 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400688 stack.clipRect(insideRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000689 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
690 }
691
692 {
693 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400694 stack.clipRect(intersectingRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000695 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
696 }
697
698 {
699 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400700 stack.clipRect(nonIntersectingRect, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000701 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
702 }
703
704 // Intersect Op tests with circle paths
705 {
706 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400707 stack.clipPath(outsideCircle, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000708 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
709 }
710
711 {
712 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400713 stack.clipPath(insideCircle, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000714 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
715 }
716
717 {
718 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400719 stack.clipPath(intersectingCircle, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000720 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
721 }
722
723 {
724 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400725 stack.clipPath(nonIntersectingCircle, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000726 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
727 }
728
729 // Intersect Op tests with inverse filled rectangles
730 {
731 SkClipStack stack;
732 SkPath path;
733 path.addRect(outsideRect);
734 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400735 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000736 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
737 }
738
739 {
740 SkClipStack stack;
741 SkPath path;
742 path.addRect(insideRect);
743 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400744 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000745 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
746 }
747
748 {
749 SkClipStack stack;
750 SkPath path;
751 path.addRect(intersectingRect);
752 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400753 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000754 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
755 }
756
757 {
758 SkClipStack stack;
759 SkPath path;
760 path.addRect(nonIntersectingRect);
761 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400762 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000763 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
764 }
765
766 // Intersect Op tests with inverse filled circles
767 {
768 SkClipStack stack;
769 SkPath path = outsideCircle;
770 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400771 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000772 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
773 }
774
775 {
776 SkClipStack stack;
777 SkPath path = insideCircle;
778 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400779 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000780 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
781 }
782
783 {
784 SkClipStack stack;
785 SkPath path = intersectingCircle;
786 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400787 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000788 REPORTER_ASSERT(reporter, false == stack.quickContains(testRect));
789 }
790
791 {
792 SkClipStack stack;
793 SkPath path = nonIntersectingCircle;
794 path.toggleInverseFillType();
Brian Salomona3b45d42016-10-03 11:36:16 -0400795 stack.clipPath(path, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +0000796 REPORTER_ASSERT(reporter, true == stack.quickContains(testRect));
797 }
798}
799
csmartdaltond50e2402016-07-22 08:39:06 -0700800static void set_region_to_stack(const SkClipStack& stack, const SkIRect& bounds, SkRegion* region) {
801 region->setRect(bounds);
802 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
803 while (const SkClipStack::Element *element = iter.next()) {
804 SkRegion elemRegion;
805 SkRegion boundsRgn(bounds);
806 SkPath path;
807
808 switch (element->getType()) {
809 case SkClipStack::Element::kEmpty_Type:
810 elemRegion.setEmpty();
811 break;
812 default:
813 element->asPath(&path);
814 elemRegion.setPath(path, boundsRgn);
815 break;
816 }
reed73603f32016-09-20 08:42:38 -0700817 region->op(elemRegion, (SkRegion::Op)element->getOp());
csmartdaltond50e2402016-07-22 08:39:06 -0700818 }
819}
820
821static void test_invfill_diff_bug(skiatest::Reporter* reporter) {
822 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -0400823 stack.clipRect({10, 10, 20, 20}, SkMatrix::I(), SkCanvas::kIntersect_Op, false);
csmartdaltond50e2402016-07-22 08:39:06 -0700824
825 SkPath path;
826 path.addRect({30, 10, 40, 20});
827 path.setFillType(SkPath::kInverseWinding_FillType);
Brian Salomona3b45d42016-10-03 11:36:16 -0400828 stack.clipPath(path, SkMatrix::I(), SkCanvas::kDifference_Op, false);
csmartdaltond50e2402016-07-22 08:39:06 -0700829
830 REPORTER_ASSERT(reporter, SkClipStack::kEmptyGenID == stack.getTopmostGenID());
831
832 SkRect stackBounds;
833 SkClipStack::BoundsType stackBoundsType;
834 stack.getBounds(&stackBounds, &stackBoundsType);
835
836 REPORTER_ASSERT(reporter, stackBounds.isEmpty());
837 REPORTER_ASSERT(reporter, SkClipStack::kNormal_BoundsType == stackBoundsType);
838
839 SkRegion region;
840 set_region_to_stack(stack, {0, 0, 50, 30}, &region);
841
842 REPORTER_ASSERT(reporter, region.isEmpty());
843}
844
bsalomon@google.com51a62862012-11-26 21:19:43 +0000845///////////////////////////////////////////////////////////////////////////////////////////////////
846
bsalomon@google.coma4e13c82012-11-26 21:38:37 +0000847#if SK_SUPPORT_GPU
bsalomon@google.com705e8402012-11-27 15:43:57 +0000848// Functions that add a shape to the clip stack. The shape is computed from a rectangle.
849// AA is always disabled since the clip stack reducer can cause changes in aa rasterization of the
850// stack. A fractional edge repeated in different elements may be rasterized fewer times using the
851// reduced stack.
852typedef void (*AddElementFunc) (const SkRect& rect,
853 bool invert,
reed73603f32016-09-20 08:42:38 -0700854 SkCanvas::ClipOp op,
csmartdaltoncbecb082016-07-22 08:59:08 -0700855 SkClipStack* stack,
856 bool doAA);
bsalomon@google.coma4e13c82012-11-26 21:38:37 +0000857
reed73603f32016-09-20 08:42:38 -0700858static void add_round_rect(const SkRect& rect, bool invert, SkCanvas::ClipOp op, SkClipStack* stack,
csmartdaltoncbecb082016-07-22 08:59:08 -0700859 bool doAA) {
bsalomon@google.com51a62862012-11-26 21:19:43 +0000860 SkScalar rx = rect.width() / 10;
bsalomon@google.com705e8402012-11-27 15:43:57 +0000861 SkScalar ry = rect.height() / 20;
bsalomon@google.com705e8402012-11-27 15:43:57 +0000862 if (invert) {
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000863 SkPath path;
864 path.addRoundRect(rect, rx, ry);
bsalomon@google.com705e8402012-11-27 15:43:57 +0000865 path.setFillType(SkPath::kInverseWinding_FillType);
Brian Salomona3b45d42016-10-03 11:36:16 -0400866 stack->clipPath(path, SkMatrix::I(), op, doAA);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000867 } else {
868 SkRRect rrect;
869 rrect.setRectXY(rect, rx, ry);
Brian Salomona3b45d42016-10-03 11:36:16 -0400870 stack->clipRRect(rrect, SkMatrix::I(), op, doAA);
bsalomon@google.com705e8402012-11-27 15:43:57 +0000871 }
bsalomon@google.com51a62862012-11-26 21:19:43 +0000872};
873
reed73603f32016-09-20 08:42:38 -0700874static void add_rect(const SkRect& rect, bool invert, SkCanvas::ClipOp op, SkClipStack* stack,
csmartdaltoncbecb082016-07-22 08:59:08 -0700875 bool doAA) {
bsalomon@google.com705e8402012-11-27 15:43:57 +0000876 if (invert) {
877 SkPath path;
878 path.addRect(rect);
879 path.setFillType(SkPath::kInverseWinding_FillType);
Brian Salomona3b45d42016-10-03 11:36:16 -0400880 stack->clipPath(path, SkMatrix::I(), op, doAA);
bsalomon@google.com705e8402012-11-27 15:43:57 +0000881 } else {
Brian Salomona3b45d42016-10-03 11:36:16 -0400882 stack->clipRect(rect, SkMatrix::I(), op, doAA);
bsalomon@google.com705e8402012-11-27 15:43:57 +0000883 }
bsalomon@google.com51a62862012-11-26 21:19:43 +0000884};
885
reed73603f32016-09-20 08:42:38 -0700886static void add_oval(const SkRect& rect, bool invert, SkCanvas::ClipOp op, SkClipStack* stack,
csmartdaltoncbecb082016-07-22 08:59:08 -0700887 bool doAA) {
bsalomon@google.com51a62862012-11-26 21:19:43 +0000888 SkPath path;
889 path.addOval(rect);
bsalomon@google.com705e8402012-11-27 15:43:57 +0000890 if (invert) {
891 path.setFillType(SkPath::kInverseWinding_FillType);
892 }
Brian Salomona3b45d42016-10-03 11:36:16 -0400893 stack->clipPath(path, SkMatrix::I(), op, doAA);
bsalomon@google.com51a62862012-11-26 21:19:43 +0000894};
895
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000896static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
897 switch (element.getType()) {
898 case SkClipStack::Element::kRect_Type:
Brian Salomona3b45d42016-10-03 11:36:16 -0400899 stack->clipRect(element.getRect(), SkMatrix::I(), element.getOp(), element.isAA());
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000900 break;
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000901 case SkClipStack::Element::kRRect_Type:
Brian Salomona3b45d42016-10-03 11:36:16 -0400902 stack->clipRRect(element.getRRect(), SkMatrix::I(), element.getOp(), element.isAA());
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000903 break;
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000904 case SkClipStack::Element::kPath_Type:
Brian Salomona3b45d42016-10-03 11:36:16 -0400905 stack->clipPath(element.getPath(), SkMatrix::I(), element.getOp(), element.isAA());
bsalomon@google.com8182fa02012-12-04 14:06:06 +0000906 break;
907 case SkClipStack::Element::kEmpty_Type:
908 SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
909 stack->clipEmpty();
910 break;
bsalomon@google.com51a62862012-11-26 21:19:43 +0000911 }
912}
913
bsalomon@google.com51a62862012-11-26 21:19:43 +0000914static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
915 // We construct random clip stacks, reduce them, and then rasterize both versions to verify that
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000916 // they are equal.
bsalomon@google.com51a62862012-11-26 21:19:43 +0000917
918 // All the clip elements will be contained within these bounds.
csmartdaltond211e782016-08-15 11:17:19 -0700919 static const SkIRect kIBounds = SkIRect::MakeWH(100, 100);
920 static const SkRect kBounds = SkRect::Make(kIBounds);
bsalomon@google.com51a62862012-11-26 21:19:43 +0000921
922 enum {
csmartdaltoncbecb082016-07-22 08:59:08 -0700923 kNumTests = 250,
bsalomon@google.com51a62862012-11-26 21:19:43 +0000924 kMinElemsPerTest = 1,
925 kMaxElemsPerTest = 50,
926 };
927
928 // min/max size of a clip element as a fraction of kBounds.
929 static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5;
930 static const SkScalar kMaxElemSizeFrac = SK_Scalar1;
931
reed73603f32016-09-20 08:42:38 -0700932 static const SkCanvas::ClipOp kOps[] = {
933 SkCanvas::kDifference_Op,
934 SkCanvas::kIntersect_Op,
935 SkCanvas::kUnion_Op,
936 SkCanvas::kXOR_Op,
937 SkCanvas::kReverseDifference_Op,
938 SkCanvas::kReplace_Op,
bsalomon@google.com51a62862012-11-26 21:19:43 +0000939 };
940
941 // Replace operations short-circuit the optimizer. We want to make sure that we test this code
942 // path a little bit but we don't want it to prevent us from testing many longer traversals in
943 // the optimizer.
944 static const int kReplaceDiv = 4 * kMaxElemsPerTest;
945
bsalomon@google.com705e8402012-11-27 15:43:57 +0000946 // We want to test inverse fills. However, they are quite rare in practice so don't over do it.
947 static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest;
948
csmartdaltoncbecb082016-07-22 08:59:08 -0700949 static const SkScalar kFractionAntialiased = 0.25;
950
bsalomon@google.com51a62862012-11-26 21:19:43 +0000951 static const AddElementFunc kElementFuncs[] = {
952 add_rect,
953 add_round_rect,
954 add_oval,
955 };
956
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000957 SkRandom r;
bsalomon@google.com51a62862012-11-26 21:19:43 +0000958
959 for (int i = 0; i < kNumTests; ++i) {
csmartdaltoncbecb082016-07-22 08:59:08 -0700960 SkString testCase;
961 testCase.printf("Iteration %d", i);
962
bsalomon@google.com51a62862012-11-26 21:19:43 +0000963 // Randomly generate a clip stack.
964 SkClipStack stack;
965 int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest);
csmartdaltoncbecb082016-07-22 08:59:08 -0700966 bool doAA = r.nextBiasedBool(kFractionAntialiased);
bsalomon@google.com51a62862012-11-26 21:19:43 +0000967 for (int e = 0; e < numElems; ++e) {
reed73603f32016-09-20 08:42:38 -0700968 SkCanvas::ClipOp op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))];
969 if (op == SkCanvas::kReplace_Op) {
bsalomon@google.com51a62862012-11-26 21:19:43 +0000970 if (r.nextU() % kReplaceDiv) {
971 --e;
972 continue;
973 }
974 }
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000975
bsalomon@google.com51a62862012-11-26 21:19:43 +0000976 // saves can change the clip stack behavior when an element is added.
977 bool doSave = r.nextBool();
skia.committer@gmail.com8ccf5902012-11-27 02:01:19 +0000978
bsalomon@google.com51a62862012-11-26 21:19:43 +0000979 SkSize size = SkSize::Make(
csmartdaltoncbecb082016-07-22 08:59:08 -0700980 SkScalarMul(kBounds.width(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac)),
981 SkScalarMul(kBounds.height(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac)));
bsalomon@google.com51a62862012-11-26 21:19:43 +0000982
csmartdaltoncbecb082016-07-22 08:59:08 -0700983 SkPoint xy = {r.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth),
984 r.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight)};
bsalomon@google.com51a62862012-11-26 21:19:43 +0000985
csmartdaltoncbecb082016-07-22 08:59:08 -0700986 SkRect rect;
987 if (doAA) {
988 rect.setXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
989 if (GrClip::IsPixelAligned(rect)) {
990 // Don't create an element that may accidentally become not antialiased.
991 rect.outset(0.5f, 0.5f);
992 }
993 SkASSERT(!GrClip::IsPixelAligned(rect));
994 } else {
995 rect.setXYWH(SkScalarFloorToScalar(xy.fX),
996 SkScalarFloorToScalar(xy.fY),
997 SkScalarCeilToScalar(size.fWidth),
998 SkScalarCeilToScalar(size.fHeight));
999 }
bsalomon@google.com51a62862012-11-26 21:19:43 +00001000
bsalomon@google.com705e8402012-11-27 15:43:57 +00001001 bool invert = r.nextBiasedBool(kFractionInverted);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +00001002
csmartdaltoncbecb082016-07-22 08:59:08 -07001003 kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect, invert, op, &stack,
1004 doAA);
bsalomon@google.com51a62862012-11-26 21:19:43 +00001005 if (doSave) {
1006 stack.save();
1007 }
1008 }
1009
csmartdalton8d3f92a2016-08-17 09:39:38 -07001010 // Zero the memory we will new the GrReducedClip into. This ensures the elements gen ID
1011 // will be kInvalidGenID if left uninitialized.
1012 SkAlignedSTStorage<1, GrReducedClip> storage;
1013 memset(storage.get(), 0, sizeof(GrReducedClip));
1014 GR_STATIC_ASSERT(0 == SkClipStack::kInvalidGenID);
1015
csmartdalton77f2fae2016-08-08 09:55:06 -07001016 // Get the reduced version of the stack.
csmartdaltoncbecb082016-07-22 08:59:08 -07001017 SkRect queryBounds = kBounds;
1018 queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
csmartdalton8d3f92a2016-08-17 09:39:38 -07001019 const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, queryBounds);
bsalomon@google.coma4444302012-12-04 15:22:12 +00001020
csmartdalton8d3f92a2016-08-17 09:39:38 -07001021 REPORTER_ASSERT_MESSAGE(reporter,
1022 reduced->elements().isEmpty() ||
1023 SkClipStack::kInvalidGenID != reduced->elementsGenID(),
csmartdaltoncbecb082016-07-22 08:59:08 -07001024 testCase.c_str());
1025
csmartdalton8d3f92a2016-08-17 09:39:38 -07001026 if (!reduced->elements().isEmpty()) {
1027 REPORTER_ASSERT_MESSAGE(reporter, reduced->hasIBounds(), testCase.c_str());
csmartdaltoncbecb082016-07-22 08:59:08 -07001028 SkRect stackBounds;
1029 SkClipStack::BoundsType stackBoundsType;
1030 stack.getBounds(&stackBounds, &stackBoundsType);
1031 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
1032 // Unless GrReducedClip starts doing some heroic tightening of the clip bounds, this
1033 // will be true since the stack bounds are completely contained inside the query.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001034 REPORTER_ASSERT_MESSAGE(reporter,
1035 GrClip::IsInsideClip(reduced->ibounds(), stackBounds),
csmartdaltoncbecb082016-07-22 08:59:08 -07001036 testCase.c_str());
1037 }
csmartdalton8d3f92a2016-08-17 09:39:38 -07001038 REPORTER_ASSERT_MESSAGE(reporter, reduced->requiresAA() == doAA, testCase.c_str());
csmartdaltoncbecb082016-07-22 08:59:08 -07001039 }
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001040
bsalomon@google.com51a62862012-11-26 21:19:43 +00001041 // Build a new clip stack based on the reduced clip elements
1042 SkClipStack reducedStack;
csmartdalton8d3f92a2016-08-17 09:39:38 -07001043 if (GrReducedClip::InitialState::kAllOut == reduced->initialState()) {
bsalomon@google.com51a62862012-11-26 21:19:43 +00001044 // whether the result is bounded or not, the whole plane should start outside the clip.
1045 reducedStack.clipEmpty();
1046 }
csmartdalton8d3f92a2016-08-17 09:39:38 -07001047 for (ElementList::Iter iter(reduced->elements()); iter.get(); iter.next()) {
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001048 add_elem_to_stack(*iter.get(), &reducedStack);
bsalomon@google.com51a62862012-11-26 21:19:43 +00001049 }
bsalomon@google.com51a62862012-11-26 21:19:43 +00001050
csmartdalton8d3f92a2016-08-17 09:39:38 -07001051 SkIRect ibounds = reduced->hasIBounds() ? reduced->ibounds() : kIBounds;
csmartdaltond211e782016-08-15 11:17:19 -07001052
bsalomon@google.com34cd70a2012-12-06 14:23:20 +00001053 // GrReducedClipStack assumes that the final result is clipped to the returned bounds
reed73603f32016-09-20 08:42:38 -07001054 reducedStack.clipDevRect(ibounds, SkCanvas::kIntersect_Op);
1055 stack.clipDevRect(ibounds, SkCanvas::kIntersect_Op);
bsalomon@google.com34cd70a2012-12-06 14:23:20 +00001056
bsalomon@google.com51a62862012-11-26 21:19:43 +00001057 // convert both the original stack and reduced stack to SkRegions and see if they're equal
bsalomon@google.com51a62862012-11-26 21:19:43 +00001058 SkRegion region;
csmartdaltond211e782016-08-15 11:17:19 -07001059 set_region_to_stack(stack, ibounds, &region);
csmartdaltond50e2402016-07-22 08:39:06 -07001060
bsalomon@google.com51a62862012-11-26 21:19:43 +00001061 SkRegion reducedRegion;
csmartdaltond211e782016-08-15 11:17:19 -07001062 set_region_to_stack(reducedStack, ibounds, &reducedRegion);
bsalomon@google.com51a62862012-11-26 21:19:43 +00001063
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +00001064 REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_str());
csmartdalton8d3f92a2016-08-17 09:39:38 -07001065
1066 reduced->~GrReducedClip();
bsalomon@google.com51a62862012-11-26 21:19:43 +00001067 }
1068}
1069
halcanary4dbbd042016-06-07 17:21:10 -07001070#ifdef SK_BUILD_FOR_WIN
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001071 #define SUPPRESS_VISIBILITY_WARNING
1072#else
1073 #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
1074#endif
1075
1076static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
1077 {
1078 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -04001079 stack.clipRect(SkRect::MakeXYWH(0, 0, 100, 100), SkMatrix::I(), SkCanvas::kReplace_Op,
1080 true);
1081 stack.clipRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3)), SkMatrix::I(),
1082 SkCanvas::kReplace_Op, true);
csmartdaltoncbecb082016-07-22 08:59:08 -07001083 SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001084
csmartdalton8d3f92a2016-08-17 09:39:38 -07001085 SkAlignedSTStorage<1, GrReducedClip> storage;
1086 memset(storage.get(), 0, sizeof(GrReducedClip));
1087 GR_STATIC_ASSERT(0 == SkClipStack::kInvalidGenID);
1088 const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, bounds);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001089
csmartdalton8d3f92a2016-08-17 09:39:38 -07001090 REPORTER_ASSERT(reporter, reduced->elements().count() == 1);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001091 // Clips will be cached based on the generation id. Make sure the gen id is valid.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001092 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reduced->elementsGenID());
1093
1094 reduced->~GrReducedClip();
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001095 }
1096 {
1097 SkClipStack stack;
1098
1099 // Create a clip with following 25.3, 25.3 boxes which are 25 apart:
1100 // A B
1101 // C D
1102
Brian Salomona3b45d42016-10-03 11:36:16 -04001103 stack.clipRect(SkRect::MakeXYWH(0, 0, SkScalar(25.3), SkScalar(25.3)), SkMatrix::I(),
1104 SkCanvas::kReplace_Op, true);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001105 int32_t genIDA = stack.getTopmostGenID();
Brian Salomona3b45d42016-10-03 11:36:16 -04001106 stack.clipRect(SkRect::MakeXYWH(50, 0, SkScalar(25.3), SkScalar(25.3)), SkMatrix::I(),
1107 SkCanvas::kUnion_Op, true);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001108 int32_t genIDB = stack.getTopmostGenID();
Brian Salomona3b45d42016-10-03 11:36:16 -04001109 stack.clipRect(SkRect::MakeXYWH(0, 50, SkScalar(25.3), SkScalar(25.3)), SkMatrix::I(),
1110 SkCanvas::kUnion_Op, true);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001111 int32_t genIDC = stack.getTopmostGenID();
Brian Salomona3b45d42016-10-03 11:36:16 -04001112 stack.clipRect(SkRect::MakeXYWH(50, 50, SkScalar(25.3), SkScalar(25.3)), SkMatrix::I(),
1113 SkCanvas::kUnion_Op, true);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001114 int32_t genIDD = stack.getTopmostGenID();
1115
1116
csmartdaltoncbecb082016-07-22 08:59:08 -07001117#define IXYWH SkIRect::MakeXYWH
1118#define XYWH SkRect::MakeXYWH
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001119
csmartdaltoncbecb082016-07-22 08:59:08 -07001120 SkIRect stackBounds = IXYWH(0, 0, 76, 76);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001121
1122 // The base test is to test each rect in two ways:
1123 // 1) The box dimensions. (Should reduce to "all in", no elements).
1124 // 2) A bit over the box dimensions.
1125 // In the case 2, test that the generation id is what is expected.
1126 // The rects are of fractional size so that case 2 never gets optimized to an empty element
1127 // list.
1128
1129 // Not passing in tighter bounds is tested for consistency.
1130 static const struct SUPPRESS_VISIBILITY_WARNING {
csmartdaltoncbecb082016-07-22 08:59:08 -07001131 SkRect testBounds;
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001132 int reducedClipCount;
1133 int32_t reducedGenID;
csmartdaltoncbecb082016-07-22 08:59:08 -07001134 InitialState initialState;
1135 SkIRect clipIRect;
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001136 // parameter.
1137 } testCases[] = {
csmartdalton77f2fae2016-08-08 09:55:06 -07001138
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001139 // Rect A.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001140 { XYWH(0, 0, 25, 25), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 0, 25, 25) },
1141 { XYWH(0.1f, 0.1f, 25.1f, 25.1f), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 0, 26, 26) },
csmartdalton77f2fae2016-08-08 09:55:06 -07001142 { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::InitialState::kAllOut, IXYWH(0, 0, 27, 27)},
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001143
1144 // Rect B.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001145 { XYWH(50, 0, 25, 25), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 0, 25, 25) },
1146 { XYWH(50, 0, 25.3f, 25.3f), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 0, 26, 26) },
csmartdalton77f2fae2016-08-08 09:55:06 -07001147 { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::InitialState::kAllOut, IXYWH(50, 0, 26, 27) },
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001148
1149 // Rect C.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001150 { XYWH(0, 50, 25, 25), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 50, 25, 25) },
1151 { XYWH(0.2f, 50.1f, 25.1f, 25.2f), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(0, 50, 26, 26) },
csmartdalton77f2fae2016-08-08 09:55:06 -07001152 { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::InitialState::kAllOut, IXYWH(0, 50, 27, 26) },
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001153
1154 // Rect D.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001155 { XYWH(50, 50, 25, 25), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 50, 25, 25)},
1156 { XYWH(50.3f, 50.3f, 25, 25), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllIn, IXYWH(50, 50, 26, 26)},
csmartdalton77f2fae2016-08-08 09:55:06 -07001157 { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::InitialState::kAllOut, IXYWH(50, 50, 26, 26)},
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001158
1159 // Other tests:
csmartdalton77f2fae2016-08-08 09:55:06 -07001160 { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::InitialState::kAllOut, stackBounds },
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001161
1162 // Rect in the middle, touches none.
csmartdalton8d3f92a2016-08-17 09:39:38 -07001163 { XYWH(26, 26, 24, 24), 0, SkClipStack::kInvalidGenID, GrReducedClip::InitialState::kAllOut, IXYWH(26, 26, 24, 24) },
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001164
1165 // Rect in the middle, touches all the rects. GenID is the last rect.
csmartdalton77f2fae2016-08-08 09:55:06 -07001166 { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::InitialState::kAllOut, IXYWH(24, 24, 27, 27) },
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001167 };
1168
1169#undef XYWH
csmartdaltoncbecb082016-07-22 08:59:08 -07001170#undef IXYWH
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001171
1172 for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) {
csmartdalton77f2fae2016-08-08 09:55:06 -07001173 const GrReducedClip reduced(stack, testCases[i].testBounds);
1174 REPORTER_ASSERT(reporter, reduced.elements().count() == testCases[i].reducedClipCount);
1175 SkASSERT(reduced.elements().count() == testCases[i].reducedClipCount);
csmartdalton8d3f92a2016-08-17 09:39:38 -07001176 if (reduced.elements().count()) {
1177 REPORTER_ASSERT(reporter, reduced.elementsGenID() == testCases[i].reducedGenID);
1178 SkASSERT(reduced.elementsGenID() == testCases[i].reducedGenID);
1179 }
csmartdalton77f2fae2016-08-08 09:55:06 -07001180 REPORTER_ASSERT(reporter, reduced.initialState() == testCases[i].initialState);
1181 SkASSERT(reduced.initialState() == testCases[i].initialState);
csmartdaltond211e782016-08-15 11:17:19 -07001182 REPORTER_ASSERT(reporter, reduced.hasIBounds());
1183 SkASSERT(reduced.hasIBounds());
1184 REPORTER_ASSERT(reporter, reduced.ibounds() == testCases[i].clipIRect);
1185 SkASSERT(reduced.ibounds() == testCases[i].clipIRect);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001186 }
1187 }
1188}
1189
1190static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) {
1191 SkClipStack stack;
reed73603f32016-09-20 08:42:38 -07001192 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 100, 100), SkCanvas::kReplace_Op);
1193 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkCanvas::kReplace_Op);
csmartdaltoncbecb082016-07-22 08:59:08 -07001194 SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001195
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001196 // At the time, this would crash.
csmartdalton77f2fae2016-08-08 09:55:06 -07001197 const GrReducedClip reduced(stack, bounds);
1198 REPORTER_ASSERT(reporter, reduced.elements().isEmpty());
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001199}
1200
csmartdaltoncbecb082016-07-22 08:59:08 -07001201enum class ClipMethod {
1202 kSkipDraw,
1203 kIgnoreClip,
1204 kScissor,
1205 kAAElements
1206};
1207
1208static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName,
1209 const SkClipStack& stack, const SkMatrix& queryXform,
1210 const SkRect& preXformQuery, ClipMethod expectedMethod,
1211 int numExpectedElems = 0) {
csmartdaltoncbecb082016-07-22 08:59:08 -07001212 SkRect queryBounds;
1213 queryXform.mapRect(&queryBounds, preXformQuery);
csmartdalton77f2fae2016-08-08 09:55:06 -07001214 const GrReducedClip reduced(stack, queryBounds);
csmartdaltoncbecb082016-07-22 08:59:08 -07001215
1216 SkClipStack::BoundsType stackBoundsType;
1217 SkRect stackBounds;
1218 stack.getBounds(&stackBounds, &stackBoundsType);
1219
1220 switch (expectedMethod) {
1221 case ClipMethod::kSkipDraw:
1222 SkASSERT(0 == numExpectedElems);
csmartdalton77f2fae2016-08-08 09:55:06 -07001223 REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
1224 REPORTER_ASSERT_MESSAGE(reporter,
1225 GrReducedClip::InitialState::kAllOut == reduced.initialState(),
csmartdaltoncbecb082016-07-22 08:59:08 -07001226 testName.c_str());
1227 return;
1228 case ClipMethod::kIgnoreClip:
1229 SkASSERT(0 == numExpectedElems);
csmartdaltond211e782016-08-15 11:17:19 -07001230 REPORTER_ASSERT_MESSAGE(reporter,
1231 !reduced.hasIBounds() ||
1232 GrClip::IsInsideClip(reduced.ibounds(), queryBounds),
csmartdaltoncbecb082016-07-22 08:59:08 -07001233 testName.c_str());
csmartdalton77f2fae2016-08-08 09:55:06 -07001234 REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
1235 REPORTER_ASSERT_MESSAGE(reporter,
1236 GrReducedClip::InitialState::kAllIn == reduced.initialState(),
csmartdaltoncbecb082016-07-22 08:59:08 -07001237 testName.c_str());
1238 return;
1239 case ClipMethod::kScissor: {
1240 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
1241 SkASSERT(0 == numExpectedElems);
1242 SkIRect expectedScissor;
1243 stackBounds.round(&expectedScissor);
csmartdalton77f2fae2016-08-08 09:55:06 -07001244 REPORTER_ASSERT_MESSAGE(reporter, reduced.elements().isEmpty(), testName.c_str());
csmartdaltond211e782016-08-15 11:17:19 -07001245 REPORTER_ASSERT_MESSAGE(reporter, reduced.hasIBounds(), testName.c_str());
1246 REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == reduced.ibounds(),
csmartdalton77f2fae2016-08-08 09:55:06 -07001247 testName.c_str());
1248 REPORTER_ASSERT_MESSAGE(reporter,
1249 GrReducedClip::InitialState::kAllIn == reduced.initialState(),
csmartdaltoncbecb082016-07-22 08:59:08 -07001250 testName.c_str());
1251 return;
1252 }
1253 case ClipMethod::kAAElements: {
1254 SkIRect expectedClipIBounds = GrClip::GetPixelIBounds(queryBounds);
1255 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
1256 SkAssertResult(expectedClipIBounds.intersect(GrClip::GetPixelIBounds(stackBounds)));
1257 }
csmartdalton77f2fae2016-08-08 09:55:06 -07001258 REPORTER_ASSERT_MESSAGE(reporter, numExpectedElems == reduced.elements().count(),
csmartdaltoncbecb082016-07-22 08:59:08 -07001259 testName.c_str());
csmartdaltond211e782016-08-15 11:17:19 -07001260 REPORTER_ASSERT_MESSAGE(reporter, reduced.hasIBounds(), testName.c_str());
1261 REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == reduced.ibounds(),
csmartdalton77f2fae2016-08-08 09:55:06 -07001262 testName.c_str());
1263 REPORTER_ASSERT_MESSAGE(reporter, reduced.requiresAA() == !reduced.elements().isEmpty(),
csmartdaltoncbecb082016-07-22 08:59:08 -07001264 testName.c_str());
1265 break;
1266 }
1267 }
1268}
1269
1270static void test_reduced_clip_stack_aa(skiatest::Reporter* reporter) {
1271 constexpr SkScalar IL = 2, IT = 1, IR = 6, IB = 7; // Pixel aligned rect.
1272 constexpr SkScalar L = 2.2f, T = 1.7f, R = 5.8f, B = 7.3f; // Generic rect.
1273 constexpr SkScalar l = 3.3f, t = 2.8f, r = 4.7f, b = 6.2f; // Small rect contained in R.
1274
1275 SkRect alignedRect = {IL, IT, IR, IB};
1276 SkRect rect = {L, T, R, B};
1277 SkRect innerRect = {l, t, r, b};
1278
1279 SkMatrix m;
1280 m.setIdentity();
1281
1282 constexpr SkScalar kMinScale = 2.0001f;
1283 constexpr SkScalar kMaxScale = 3;
1284 constexpr int kNumIters = 8;
1285
1286 SkString name;
1287 SkRandom rand;
1288
1289 for (int i = 0; i < kNumIters; ++i) {
1290 // Pixel-aligned rect (iior=true).
1291 name.printf("Pixel-aligned rect test, iter %i", i);
1292 SkClipStack stack;
Brian Salomona3b45d42016-10-03 11:36:16 -04001293 stack.clipRect(alignedRect, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
csmartdaltoncbecb082016-07-22 08:59:08 -07001294 test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kIgnoreClip);
1295 test_aa_query(reporter, name, stack, m, {IL, IT-1, IR, IT}, ClipMethod::kSkipDraw);
csmartdalton77f2fae2016-08-08 09:55:06 -07001296 test_aa_query(reporter, name, stack, m, {IL, IT-2, IR, IB}, ClipMethod::kScissor);
csmartdaltoncbecb082016-07-22 08:59:08 -07001297
1298 // Rect (iior=true).
1299 name.printf("Rect test, iter %i", i);
1300 stack.reset();
Brian Salomona3b45d42016-10-03 11:36:16 -04001301 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
csmartdaltoncbecb082016-07-22 08:59:08 -07001302 test_aa_query(reporter, name, stack, m, {L, T, R, B}, ClipMethod::kIgnoreClip);
1303 test_aa_query(reporter, name, stack, m, {L-.1f, T, L, B}, ClipMethod::kSkipDraw);
1304 test_aa_query(reporter, name, stack, m, {L-.1f, T, L+.1f, B}, ClipMethod::kAAElements, 1);
1305
1306 // Difference rect (iior=false, inside-out bounds).
1307 name.printf("Difference rect test, iter %i", i);
1308 stack.reset();
Brian Salomona3b45d42016-10-03 11:36:16 -04001309 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kDifference_Op, true);
csmartdaltoncbecb082016-07-22 08:59:08 -07001310 test_aa_query(reporter, name, stack, m, {L, T, R, B}, ClipMethod::kSkipDraw);
1311 test_aa_query(reporter, name, stack, m, {L, T-.1f, R, T}, ClipMethod::kIgnoreClip);
1312 test_aa_query(reporter, name, stack, m, {L, T-.1f, R, T+.1f}, ClipMethod::kAAElements, 1);
1313
1314 // Complex clip (iior=false, normal bounds).
1315 name.printf("Complex clip test, iter %i", i);
1316 stack.reset();
Brian Salomona3b45d42016-10-03 11:36:16 -04001317 stack.clipRect(rect, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
1318 stack.clipRect(innerRect, SkMatrix::I(), SkCanvas::kXOR_Op, true);
csmartdaltoncbecb082016-07-22 08:59:08 -07001319 test_aa_query(reporter, name, stack, m, {l, t, r, b}, ClipMethod::kSkipDraw);
1320 test_aa_query(reporter, name, stack, m, {r-.1f, t, R, b}, ClipMethod::kAAElements, 1);
1321 test_aa_query(reporter, name, stack, m, {r-.1f, t, R+.1f, b}, ClipMethod::kAAElements, 2);
1322 test_aa_query(reporter, name, stack, m, {r, t, R+.1f, b}, ClipMethod::kAAElements, 1);
1323 test_aa_query(reporter, name, stack, m, {r, t, R, b}, ClipMethod::kIgnoreClip);
1324 test_aa_query(reporter, name, stack, m, {R, T, R+.1f, B}, ClipMethod::kSkipDraw);
1325
1326 // Complex clip where outer rect is pixel aligned (iior=false, normal bounds).
1327 name.printf("Aligned Complex clip test, iter %i", i);
1328 stack.reset();
Brian Salomona3b45d42016-10-03 11:36:16 -04001329 stack.clipRect(alignedRect, SkMatrix::I(), SkCanvas::kIntersect_Op, true);
1330 stack.clipRect(innerRect, SkMatrix::I(), SkCanvas::kXOR_Op, true);
csmartdaltoncbecb082016-07-22 08:59:08 -07001331 test_aa_query(reporter, name, stack, m, {l, t, r, b}, ClipMethod::kSkipDraw);
1332 test_aa_query(reporter, name, stack, m, {l, b-.1f, r, IB}, ClipMethod::kAAElements, 1);
1333 test_aa_query(reporter, name, stack, m, {l, b-.1f, r, IB+.1f}, ClipMethod::kAAElements, 1);
1334 test_aa_query(reporter, name, stack, m, {l, b, r, IB+.1f}, ClipMethod::kAAElements, 0);
1335 test_aa_query(reporter, name, stack, m, {l, b, r, IB}, ClipMethod::kIgnoreClip);
1336 test_aa_query(reporter, name, stack, m, {IL, IB, IR, IB+.1f}, ClipMethod::kSkipDraw);
1337
1338 // Apply random transforms and try again. This ensures the clip stack reduction is hardened
1339 // against FP rounding error.
1340 SkScalar sx = rand.nextRangeScalar(kMinScale, kMaxScale);
1341 sx = SkScalarFloorToScalar(sx * alignedRect.width()) / alignedRect.width();
1342 SkScalar sy = rand.nextRangeScalar(kMinScale, kMaxScale);
1343 sy = SkScalarFloorToScalar(sy * alignedRect.height()) / alignedRect.height();
1344 SkScalar tx = SkScalarRoundToScalar(sx * alignedRect.x()) - sx * alignedRect.x();
1345 SkScalar ty = SkScalarRoundToScalar(sy * alignedRect.y()) - sy * alignedRect.y();
1346
1347 SkMatrix xform = SkMatrix::MakeScale(sx, sy);
1348 xform.postTranslate(tx, ty);
1349 xform.mapRect(&alignedRect);
1350 xform.mapRect(&rect);
1351 xform.mapRect(&innerRect);
1352 m.postConcat(xform);
1353 }
1354}
1355
bsalomon@google.coma4e13c82012-11-26 21:38:37 +00001356#endif
bsalomon@google.com51a62862012-11-26 21:19:43 +00001357
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00001358DEF_TEST(ClipStack, reporter) {
reed@google.combdee9fc2011-02-22 20:17:43 +00001359 SkClipStack stack;
1360
robertphillips@google.com80214e22012-07-20 15:33:18 +00001361 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
reed@google.combdee9fc2011-02-22 20:17:43 +00001362 assert_count(reporter, stack, 0);
1363
1364 static const SkIRect gRects[] = {
1365 { 0, 0, 100, 100 },
1366 { 25, 25, 125, 125 },
1367 { 0, 0, 1000, 1000 },
1368 { 0, 0, 75, 75 }
1369 };
1370 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
reed73603f32016-09-20 08:42:38 -07001371 stack.clipDevRect(gRects[i], SkCanvas::kIntersect_Op);
reed@google.combdee9fc2011-02-22 20:17:43 +00001372 }
1373
1374 // all of the above rects should have been intersected, leaving only 1 rect
robertphillips@google.com80214e22012-07-20 15:33:18 +00001375 SkClipStack::B2TIter iter(stack);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001376 const SkClipStack::Element* element = iter.next();
epoger@google.com2047f002011-05-17 17:36:59 +00001377 SkRect answer;
1378 answer.iset(25, 25, 75, 75);
reed@google.combdee9fc2011-02-22 20:17:43 +00001379
bsalomon49f085d2014-09-05 13:34:00 -07001380 REPORTER_ASSERT(reporter, element);
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001381 REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
reed73603f32016-09-20 08:42:38 -07001382 REPORTER_ASSERT(reporter, SkCanvas::kIntersect_Op == element->getOp());
bsalomon@google.com8182fa02012-12-04 14:06:06 +00001383 REPORTER_ASSERT(reporter, element->getRect() == answer);
reed@google.combdee9fc2011-02-22 20:17:43 +00001384 // now check that we only had one in our iterator
1385 REPORTER_ASSERT(reporter, !iter.next());
1386
1387 stack.reset();
robertphillips@google.com80214e22012-07-20 15:33:18 +00001388 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
reed@google.combdee9fc2011-02-22 20:17:43 +00001389 assert_count(reporter, stack, 0);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +00001390
1391 test_assign_and_comparison(reporter);
robertphillips@google.com80214e22012-07-20 15:33:18 +00001392 test_iterators(reporter);
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +00001393 test_bounds(reporter, SkClipStack::Element::kRect_Type);
1394 test_bounds(reporter, SkClipStack::Element::kRRect_Type);
1395 test_bounds(reporter, SkClipStack::Element::kPath_Type);
robertphillips@google.comcc6493b2012-07-26 18:39:13 +00001396 test_isWideOpen(reporter);
robertphillips@google.com08eacc12012-08-02 12:49:00 +00001397 test_rect_merging(reporter);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +00001398 test_rect_replace(reporter);
junov@chromium.orgedf32d52012-12-10 14:57:54 +00001399 test_rect_inverse_fill(reporter);
commit-bot@chromium.org6fbe54c2013-06-11 11:01:48 +00001400 test_path_replace(reporter);
junov@chromium.org8cdf0f52012-12-12 17:58:15 +00001401 test_quickContains(reporter);
csmartdaltond50e2402016-07-22 08:39:06 -07001402 test_invfill_diff_bug(reporter);
bsalomon@google.come7b3d292012-11-26 21:42:32 +00001403#if SK_SUPPORT_GPU
bsalomon@google.comedb26fd2012-11-28 14:42:41 +00001404 test_reduced_clip_stack(reporter);
commit-bot@chromium.orgd3e58422013-11-05 15:03:08 +00001405 test_reduced_clip_stack_genid(reporter);
1406 test_reduced_clip_stack_no_aa_crash(reporter);
csmartdaltoncbecb082016-07-22 08:59:08 -07001407 test_reduced_clip_stack_aa(reporter);
bsalomon@google.come7b3d292012-11-26 21:42:32 +00001408#endif
reed@google.combdee9fc2011-02-22 20:17:43 +00001409}