blob: 0516d9eba7cce502e7b23fd43ec8344d0dc23965 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
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"
11#include "SkRect.h"
12
robertphillips@google.com80214e22012-07-20 15:33:18 +000013
14
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000015static void test_assign_and_comparison(skiatest::Reporter* reporter) {
16 SkClipStack s;
reed@google.comd9f2dea2011-10-12 14:43:27 +000017 bool doAA = false;
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000018
robertphillips@google.com80214e22012-07-20 15:33:18 +000019 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
20
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000021 // Build up a clip stack with a path, an empty clip, and a rect.
22 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000023 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
24
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000025 SkPath p;
26 p.moveTo(5, 6);
27 p.lineTo(7, 8);
28 p.lineTo(5, 9);
29 p.close();
reed@google.comd9f2dea2011-10-12 14:43:27 +000030 s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000031
32 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000033 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
34
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000035 SkRect r = SkRect::MakeLTRB(1, 2, 3, 4);
reed@google.comd9f2dea2011-10-12 14:43:27 +000036 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000037 r = SkRect::MakeLTRB(10, 11, 12, 13);
reed@google.comd9f2dea2011-10-12 14:43:27 +000038 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000039
40 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000041 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
42
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000043 r = SkRect::MakeLTRB(14, 15, 16, 17);
reed@google.comd9f2dea2011-10-12 14:43:27 +000044 s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000045
46 // Test that assignment works.
47 SkClipStack copy = s;
48 REPORTER_ASSERT(reporter, s == copy);
49
50 // Test that different save levels triggers not equal.
51 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000052 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000053 REPORTER_ASSERT(reporter, s != copy);
54
55 // Test that an equal, but not copied version is equal.
56 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000057 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
58
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000059 r = SkRect::MakeLTRB(14, 15, 16, 17);
reed@google.comd9f2dea2011-10-12 14:43:27 +000060 s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000061 REPORTER_ASSERT(reporter, s == copy);
62
63 // Test that a different op on one level triggers not equal.
64 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000065 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000066 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000067 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
68
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000069 r = SkRect::MakeLTRB(14, 15, 16, 17);
reed@google.comd9f2dea2011-10-12 14:43:27 +000070 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000071 REPORTER_ASSERT(reporter, s != copy);
72
73 // Test that different state (clip type) triggers not equal.
tomhudson@google.com4c433722012-03-09 16:48:20 +000074 // NO LONGER VALID: if a path contains only a rect, we turn
75 // it into a bare rect for performance reasons (working
76 // around Chromium/JavaScript bad pattern).
77/*
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000078 s.restore();
79 s.save();
80 SkPath rp;
81 rp.addRect(r);
reed@google.comd9f2dea2011-10-12 14:43:27 +000082 s.clipDevPath(rp, SkRegion::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000083 REPORTER_ASSERT(reporter, s != copy);
tomhudson@google.com4c433722012-03-09 16:48:20 +000084*/
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000085
86 // Test that different rects triggers not equal.
87 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000088 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000089 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +000090 REPORTER_ASSERT(reporter, 3 == s.getSaveCount());
91
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000092 r = SkRect::MakeLTRB(24, 25, 26, 27);
reed@google.comd9f2dea2011-10-12 14:43:27 +000093 s.clipDevRect(r, SkRegion::kUnion_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +000094 REPORTER_ASSERT(reporter, s != copy);
95
96 // Sanity check
97 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +000098 REPORTER_ASSERT(reporter, 2 == s.getSaveCount());
99
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000100 copy.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000101 REPORTER_ASSERT(reporter, 2 == copy.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000102 REPORTER_ASSERT(reporter, s == copy);
103 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000104 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000105 copy.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000106 REPORTER_ASSERT(reporter, 1 == copy.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000107 REPORTER_ASSERT(reporter, s == copy);
108
109 // Test that different paths triggers not equal.
110 s.restore();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000111 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000112 s.save();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000113 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
114
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000115 p.addRect(r);
reed@google.comd9f2dea2011-10-12 14:43:27 +0000116 s.clipDevPath(p, SkRegion::kIntersect_Op, doAA);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000117 REPORTER_ASSERT(reporter, s != copy);
118}
reed@google.combdee9fc2011-02-22 20:17:43 +0000119
120static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack,
121 int count) {
robertphillips@google.com80214e22012-07-20 15:33:18 +0000122 SkClipStack::B2TIter iter(stack);
reed@google.combdee9fc2011-02-22 20:17:43 +0000123 int counter = 0;
124 while (iter.next()) {
125 counter += 1;
126 }
127 REPORTER_ASSERT(reporter, count == counter);
128}
129
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000130// Exercise the SkClipStack's bottom to top and bidirectional iterators
131// (including the skipToTopmost functionality)
robertphillips@google.com80214e22012-07-20 15:33:18 +0000132static void test_iterators(skiatest::Reporter* reporter) {
133 SkClipStack stack;
134
135 static const SkRect gRects[] = {
136 { 0, 0, 40, 40 },
137 { 60, 0, 100, 40 },
138 { 0, 60, 40, 100 },
139 { 60, 60, 100, 100 }
140 };
141
142 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
143 // the union op will prevent these from being fused together
144 stack.clipDevRect(gRects[i], SkRegion::kUnion_Op, false);
145 }
146
147 assert_count(reporter, stack, 4);
148
149 // bottom to top iteration
150 {
151 const SkClipStack::B2TIter::Clip* clip = NULL;
152
153 SkClipStack::B2TIter iter(stack);
154 int i;
155
156 for (i = 0, clip = iter.next(); clip; ++i, clip = iter.next()) {
157 REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]);
158 }
159
160 SkASSERT(i == 4);
161 }
162
163 // top to bottom iteration
164 {
165 const SkClipStack::Iter::Clip* clip = NULL;
166
167 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
168 int i;
169
170 for (i = 3, clip = iter.prev(); clip; --i, clip = iter.prev()) {
171 REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]);
172 }
173
174 SkASSERT(i == -1);
175 }
176
177 // skipToTopmost
178 {
179 const SkClipStack::Iter::Clip*clip = NULL;
180
181 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
182
183 clip = iter.skipToTopmost(SkRegion::kUnion_Op);
184 REPORTER_ASSERT(reporter, *clip->fRect == gRects[3]);
185 }
186}
187
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000188// Exercise the SkClipStack's getConservativeBounds computation
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000189static void test_bounds(skiatest::Reporter* reporter, bool useRects) {
robertphillips@google.com607fe072012-07-24 13:54:00 +0000190
191 static const int gNumCases = 20;
192 static const SkRect gAnswerRectsBW[gNumCases] = {
193 // A op B
194 { 40, 40, 50, 50 },
195 { 10, 10, 50, 50 },
196 { 10, 10, 80, 80 },
197 { 10, 10, 80, 80 },
198 { 40, 40, 80, 80 },
199
200 // invA op B
201 { 40, 40, 80, 80 },
202 { 0, 0, 100, 100 },
203 { 0, 0, 100, 100 },
204 { 0, 0, 100, 100 },
205 { 40, 40, 50, 50 },
206
207 // A op invB
208 { 10, 10, 50, 50 },
209 { 40, 40, 50, 50 },
210 { 0, 0, 100, 100 },
211 { 0, 0, 100, 100 },
212 { 0, 0, 100, 100 },
213
214 // invA op invB
215 { 0, 0, 100, 100 },
216 { 40, 40, 80, 80 },
217 { 0, 0, 100, 100 },
218 { 10, 10, 80, 80 },
219 { 10, 10, 50, 50 },
220 };
221
222 static const SkRegion::Op gOps[] = {
223 SkRegion::kIntersect_Op,
224 SkRegion::kDifference_Op,
225 SkRegion::kUnion_Op,
226 SkRegion::kXOR_Op,
227 SkRegion::kReverseDifference_Op
228 };
229
230 SkRect rectA, rectB;
231
232 rectA.iset(10, 10, 50, 50);
233 rectB.iset(40, 40, 80, 80);
234
235 SkPath clipA, clipB;
236
237 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
238 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
239
240 SkClipStack stack;
robertphillips@google.com7b112892012-07-31 15:18:21 +0000241 SkRect devClipBound;
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000242 bool isIntersectionOfRects = false;
robertphillips@google.com607fe072012-07-24 13:54:00 +0000243
244 int testCase = 0;
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000245 int numBitTests = useRects ? 1 : 4;
246 for (int invBits = 0; invBits < numBitTests; ++invBits) {
robertphillips@google.com607fe072012-07-24 13:54:00 +0000247 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
248
249 stack.save();
250 bool doInvA = SkToBool(invBits & 1);
251 bool doInvB = SkToBool(invBits & 2);
252
253 clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType :
254 SkPath::kEvenOdd_FillType);
255 clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType :
256 SkPath::kEvenOdd_FillType);
257
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000258 if (useRects) {
259 stack.clipDevRect(rectA, SkRegion::kIntersect_Op, false);
260 stack.clipDevRect(rectB, gOps[op], false);
261 } else {
262 stack.clipDevPath(clipA, SkRegion::kIntersect_Op, false);
263 stack.clipDevPath(clipB, gOps[op], false);
264 }
robertphillips@google.com607fe072012-07-24 13:54:00 +0000265
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000266 REPORTER_ASSERT(reporter, !stack.isWideOpen());
267
robertphillips@google.com7b112892012-07-31 15:18:21 +0000268 stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000269 &isIntersectionOfRects);
270
271 if (useRects) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000272 REPORTER_ASSERT(reporter, isIntersectionOfRects ==
robertphillips@google.com4c2a2f72012-07-24 22:07:50 +0000273 (gOps[op] == SkRegion::kIntersect_Op));
274 } else {
275 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
276 }
robertphillips@google.com607fe072012-07-24 13:54:00 +0000277
278 SkASSERT(testCase < gNumCases);
robertphillips@google.com7b112892012-07-31 15:18:21 +0000279 REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]);
robertphillips@google.com607fe072012-07-24 13:54:00 +0000280 ++testCase;
281
282 stack.restore();
283 }
284 }
285}
286
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000287// Test out 'isWideOpen' entry point
288static void test_isWideOpen(skiatest::Reporter* reporter) {
289
290 SkRect rectA, rectB;
291
292 rectA.iset(10, 10, 40, 40);
293 rectB.iset(50, 50, 80, 80);
294
295 // Stack should initially be wide open
296 {
297 SkClipStack stack;
298
299 REPORTER_ASSERT(reporter, stack.isWideOpen());
300 }
301
302 // Test out case where the user specifies a union that includes everything
303 {
304 SkClipStack stack;
305
306 SkPath clipA, clipB;
307
308 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5));
309 clipA.setFillType(SkPath::kInverseEvenOdd_FillType);
310
311 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5));
312 clipB.setFillType(SkPath::kInverseEvenOdd_FillType);
313
314 stack.clipDevPath(clipA, SkRegion::kReplace_Op, false);
315 stack.clipDevPath(clipB, SkRegion::kUnion_Op, false);
316
317 REPORTER_ASSERT(reporter, stack.isWideOpen());
318 }
319
320 // Test out union w/ a wide open clip
321 {
322 SkClipStack stack;
323
324 stack.clipDevRect(rectA, SkRegion::kUnion_Op, false);
325
326 REPORTER_ASSERT(reporter, stack.isWideOpen());
327 }
328
329 // Test out empty difference from a wide open clip
330 {
331 SkClipStack stack;
332
333 SkRect emptyRect;
334 emptyRect.setEmpty();
335
336 stack.clipDevRect(emptyRect, SkRegion::kDifference_Op, false);
337
338 REPORTER_ASSERT(reporter, stack.isWideOpen());
339 }
340
341 // Test out return to wide open
342 {
343 SkClipStack stack;
344
345 stack.save();
346
347 stack.clipDevRect(rectA, SkRegion::kReplace_Op, false);
348
349 REPORTER_ASSERT(reporter, !stack.isWideOpen());
350
351 stack.restore();
352
353 REPORTER_ASSERT(reporter, stack.isWideOpen());
354 }
355}
356
bsalomon@google.com100abf42012-09-05 17:40:04 +0000357static int count(const SkClipStack& stack) {
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000358
359 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart);
360
361 const SkClipStack::Iter::Clip* clip = NULL;
362 int count = 0;
363
364 for (clip = iter.prev(); clip; clip = iter.prev(), ++count) {
365 ;
366 }
367
368 return count;
369}
370
371// Test out SkClipStack's merging of rect clips. In particular exercise
372// merging of aa vs. bw rects.
373static void test_rect_merging(skiatest::Reporter* reporter) {
374
375 SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50);
376 SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
377
378 SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
379 SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60);
380
381 SkRect bound;
382 SkClipStack::BoundsType type;
383 bool isIntersectionOfRects;
384
385 // all bw overlapping - should merge
386 {
387 SkClipStack stack;
388
389 stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, false);
390
391 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false);
392
393 REPORTER_ASSERT(reporter, 1 == count(stack));
394
395 stack.getBounds(&bound, &type, &isIntersectionOfRects);
396
397 REPORTER_ASSERT(reporter, isIntersectionOfRects);
398 }
399
400 // all aa overlapping - should merge
401 {
402 SkClipStack stack;
403
404 stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true);
405
406 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true);
407
408 REPORTER_ASSERT(reporter, 1 == count(stack));
409
410 stack.getBounds(&bound, &type, &isIntersectionOfRects);
411
412 REPORTER_ASSERT(reporter, isIntersectionOfRects);
413 }
414
415 // mixed overlapping - should _not_ merge
416 {
417 SkClipStack stack;
418
419 stack.clipDevRect(overlapLeft, SkRegion::kReplace_Op, true);
420
421 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false);
422
423 REPORTER_ASSERT(reporter, 2 == count(stack));
424
425 stack.getBounds(&bound, &type, &isIntersectionOfRects);
426
427 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
428 }
429
430 // mixed nested (bw inside aa) - should merge
431 {
432 SkClipStack stack;
433
434 stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, true);
435
436 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, false);
437
438 REPORTER_ASSERT(reporter, 1 == count(stack));
439
440 stack.getBounds(&bound, &type, &isIntersectionOfRects);
441
442 REPORTER_ASSERT(reporter, isIntersectionOfRects);
443 }
444
445 // mixed nested (aa inside bw) - should merge
446 {
447 SkClipStack stack;
448
449 stack.clipDevRect(nestedParent, SkRegion::kReplace_Op, false);
450
451 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, true);
452
453 REPORTER_ASSERT(reporter, 1 == count(stack));
454
455 stack.getBounds(&bound, &type, &isIntersectionOfRects);
456
457 REPORTER_ASSERT(reporter, isIntersectionOfRects);
458 }
459
460 // reverse nested (aa inside bw) - should _not_ merge
461 {
462 SkClipStack stack;
463
464 stack.clipDevRect(nestedChild, SkRegion::kReplace_Op, false);
465
466 stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, true);
467
468 REPORTER_ASSERT(reporter, 2 == count(stack));
469
470 stack.getBounds(&bound, &type, &isIntersectionOfRects);
471
472 REPORTER_ASSERT(reporter, !isIntersectionOfRects);
473 }
474}
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000475
bsalomon@google.come8ca6c62012-11-07 21:19:10 +0000476
477// This is similar to the above test but tests the iterator's ability to merge rects in the
478// middle of a clip stack's sequence using nextCombined(). There is a save after every clip
479// element to prevent the clip stack from merging the rectangles as they are added.
480static void test_iter_rect_merging(skiatest::Reporter* reporter) {
481
482 SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50);
483 SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80);
484
485 SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90);
486 SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60);
487
488 SkRect farAway = SkRect::MakeLTRB(1000, 1000, 1010, 1010);
489
490 SkRect overlapIntersect;
491 overlapIntersect.intersect(overlapLeft, overlapRight);
492
493 SkPath path1, path2;
494 path1.addCircle(SkIntToScalar(30), SkIntToScalar(30), SkIntToScalar(1000));
495 path2.addOval(SkRect::MakeWH(500, 600));
496
497 const SkClipStack::Iter::Clip* clip;
498
499 // call nextCombined with an empty clip stack
500 {
501 SkClipStack stack;
502 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
503 REPORTER_ASSERT(reporter, NULL == iter.nextCombined());
504 }
505
506 // two bw overlapping - should merge, bracketed by paths
507 {
508 SkClipStack stack;
509 stack.clipDevPath(path1, SkRegion::kIntersect_Op, false); stack.save();
510
511 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, false); stack.save();
512
513 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); stack.save();
514
515 stack.clipDevPath(path2, SkRegion::kIntersect_Op, false); stack.save();
516
517 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
518
519 clip = iter.nextCombined();
520 REPORTER_ASSERT(reporter, *clip->fPath == path1 && !clip->fDoAA);
521
522 clip = iter.nextCombined();
523 REPORTER_ASSERT(reporter, !clip->fDoAA && *clip->fRect == overlapIntersect);
524
525 clip = iter.nextCombined();
526 REPORTER_ASSERT(reporter, *clip->fPath == path2 && !clip->fDoAA);
527
528 clip = iter.nextCombined();
529 REPORTER_ASSERT(reporter, NULL == clip);
530 }
531
532 // same as above but rects are aa and no final path.
533 {
534 SkClipStack stack;
535 stack.clipDevPath(path1, SkRegion::kIntersect_Op, false); stack.save();
536
537 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, true); stack.save();
538
539 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true); stack.save();
540
541 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
542
543 clip = iter.nextCombined();
544 REPORTER_ASSERT(reporter, *clip->fPath == path1 && !clip->fDoAA);
545
546 clip = iter.nextCombined();
547 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == overlapIntersect);
548
549 clip = iter.nextCombined();
550 REPORTER_ASSERT(reporter, NULL == clip);
551 }
552
553 // mixed overlapping - no paths - should _not_ merge
554 {
555 SkClipStack stack;
556
557 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, true); stack.save();
558 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); stack.save();
559
560 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
561
562 clip = iter.nextCombined();
563 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == overlapLeft);
564
565 clip = iter.nextCombined();
566 REPORTER_ASSERT(reporter, !clip->fDoAA && *clip->fRect == overlapRight);
567
568 clip = iter.nextCombined();
569 REPORTER_ASSERT(reporter, NULL == clip);
570 }
571
572 // three rects in a row where the third rect uses a non-intersect op.
573 {
574 SkClipStack stack;
575
576 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, true); stack.save();
577 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, true); stack.save();
578 stack.clipDevRect(nestedParent, SkRegion::kXOR_Op, true); stack.save();
579
580 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
581
582 clip = iter.nextCombined();
583 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == overlapIntersect);
584 clip = iter.nextCombined();
585 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == nestedParent);
586 clip = iter.nextCombined();
587 REPORTER_ASSERT(reporter, NULL == clip);
588 }
589
590 // mixed nested (bw inside aa) - should merge
591 {
592 SkClipStack stack;
593 stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, false); stack.save();
594
595 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, true); stack.save();
596
597 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
598
599 clip = iter.nextCombined();
600 REPORTER_ASSERT(reporter, clip->fDoAA && *clip->fRect == nestedChild);
601
602 clip = iter.nextCombined();
603 REPORTER_ASSERT(reporter, NULL == clip);
604 }
605
606 // mixed nested (aa inside bw) - should merge
607 {
608 SkClipStack stack;
609 stack.clipDevRect(nestedChild, SkRegion::kIntersect_Op, false); stack.save();
610
611 stack.clipDevRect(nestedParent, SkRegion::kIntersect_Op, true); stack.save();
612
613 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
614
615 clip = iter.nextCombined();
616 REPORTER_ASSERT(reporter, !clip->fDoAA && *clip->fRect == nestedChild);
617
618 clip = iter.nextCombined();
619 REPORTER_ASSERT(reporter, NULL == clip);
620 }
621
622 // three rect intersects in a row where result is empty after the second.
623 {
624 SkClipStack stack;
625
626 stack.clipDevRect(overlapLeft, SkRegion::kIntersect_Op, false); stack.save();
627 stack.clipDevRect(farAway, SkRegion::kIntersect_Op, false); stack.save();
628 stack.clipDevRect(overlapRight, SkRegion::kIntersect_Op, false); stack.save();
629
630 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
631
632 clip = iter.nextCombined();
633 REPORTER_ASSERT(reporter, clip->fRect->isEmpty());
634
635 clip = iter.nextCombined();
636 REPORTER_ASSERT(reporter, *clip->fRect == overlapRight);
637
638 clip = iter.nextCombined();
639 REPORTER_ASSERT(reporter, NULL == clip);
640 }
641}
642
reed@google.combdee9fc2011-02-22 20:17:43 +0000643static void TestClipStack(skiatest::Reporter* reporter) {
644 SkClipStack stack;
645
robertphillips@google.com80214e22012-07-20 15:33:18 +0000646 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
reed@google.combdee9fc2011-02-22 20:17:43 +0000647 assert_count(reporter, stack, 0);
648
649 static const SkIRect gRects[] = {
650 { 0, 0, 100, 100 },
651 { 25, 25, 125, 125 },
652 { 0, 0, 1000, 1000 },
653 { 0, 0, 75, 75 }
654 };
655 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) {
reed@google.comd9f2dea2011-10-12 14:43:27 +0000656 stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op);
reed@google.combdee9fc2011-02-22 20:17:43 +0000657 }
658
659 // all of the above rects should have been intersected, leaving only 1 rect
robertphillips@google.com80214e22012-07-20 15:33:18 +0000660 SkClipStack::B2TIter iter(stack);
661 const SkClipStack::B2TIter::Clip* clip = iter.next();
epoger@google.com2047f002011-05-17 17:36:59 +0000662 SkRect answer;
663 answer.iset(25, 25, 75, 75);
reed@google.combdee9fc2011-02-22 20:17:43 +0000664
665 REPORTER_ASSERT(reporter, clip);
666 REPORTER_ASSERT(reporter, clip->fRect);
667 REPORTER_ASSERT(reporter, !clip->fPath);
668 REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == clip->fOp);
669 REPORTER_ASSERT(reporter, *clip->fRect == answer);
670 // now check that we only had one in our iterator
671 REPORTER_ASSERT(reporter, !iter.next());
672
673 stack.reset();
robertphillips@google.com80214e22012-07-20 15:33:18 +0000674 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
reed@google.combdee9fc2011-02-22 20:17:43 +0000675 assert_count(reporter, stack, 0);
vandebo@chromium.org1e1c36f2011-05-03 16:26:09 +0000676
677 test_assign_and_comparison(reporter);
robertphillips@google.com80214e22012-07-20 15:33:18 +0000678 test_iterators(reporter);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000679 test_bounds(reporter, true); // once with rects
680 test_bounds(reporter, false); // once with paths
robertphillips@google.comcc6493b2012-07-26 18:39:13 +0000681 test_isWideOpen(reporter);
robertphillips@google.com08eacc12012-08-02 12:49:00 +0000682 test_rect_merging(reporter);
bsalomon@google.come8ca6c62012-11-07 21:19:10 +0000683 test_iter_rect_merging(reporter);
reed@google.combdee9fc2011-02-22 20:17:43 +0000684}
685
686#include "TestClassDef.h"
687DEFINE_TESTCLASS("ClipStack", TestClipStackClass, TestClipStack)