ClipStackTest.cpp revision cc6493bbef7c9c2adf4b1ed8701e2ed015ae745d
1 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 */ 8#include "Test.h" 9#include "SkClipStack.h" 10#include "SkPath.h" 11#include "SkRect.h" 12 13 14 15static void test_assign_and_comparison(skiatest::Reporter* reporter) { 16 SkClipStack s; 17 bool doAA = false; 18 19 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 20 21 // Build up a clip stack with a path, an empty clip, and a rect. 22 s.save(); 23 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 24 25 SkPath p; 26 p.moveTo(5, 6); 27 p.lineTo(7, 8); 28 p.lineTo(5, 9); 29 p.close(); 30 s.clipDevPath(p, SkRegion::kIntersect_Op, doAA); 31 32 s.save(); 33 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 34 35 SkRect r = SkRect::MakeLTRB(1, 2, 3, 4); 36 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA); 37 r = SkRect::MakeLTRB(10, 11, 12, 13); 38 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA); 39 40 s.save(); 41 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 42 43 r = SkRect::MakeLTRB(14, 15, 16, 17); 44 s.clipDevRect(r, SkRegion::kUnion_Op, doAA); 45 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(); 52 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 53 REPORTER_ASSERT(reporter, s != copy); 54 55 // Test that an equal, but not copied version is equal. 56 s.save(); 57 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 58 59 r = SkRect::MakeLTRB(14, 15, 16, 17); 60 s.clipDevRect(r, SkRegion::kUnion_Op, doAA); 61 REPORTER_ASSERT(reporter, s == copy); 62 63 // Test that a different op on one level triggers not equal. 64 s.restore(); 65 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 66 s.save(); 67 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 68 69 r = SkRect::MakeLTRB(14, 15, 16, 17); 70 s.clipDevRect(r, SkRegion::kIntersect_Op, doAA); 71 REPORTER_ASSERT(reporter, s != copy); 72 73 // Test that different state (clip type) triggers not equal. 74 // 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/* 78 s.restore(); 79 s.save(); 80 SkPath rp; 81 rp.addRect(r); 82 s.clipDevPath(rp, SkRegion::kUnion_Op, doAA); 83 REPORTER_ASSERT(reporter, s != copy); 84*/ 85 86 // Test that different rects triggers not equal. 87 s.restore(); 88 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 89 s.save(); 90 REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 91 92 r = SkRect::MakeLTRB(24, 25, 26, 27); 93 s.clipDevRect(r, SkRegion::kUnion_Op, doAA); 94 REPORTER_ASSERT(reporter, s != copy); 95 96 // Sanity check 97 s.restore(); 98 REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 99 100 copy.restore(); 101 REPORTER_ASSERT(reporter, 2 == copy.getSaveCount()); 102 REPORTER_ASSERT(reporter, s == copy); 103 s.restore(); 104 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 105 copy.restore(); 106 REPORTER_ASSERT(reporter, 1 == copy.getSaveCount()); 107 REPORTER_ASSERT(reporter, s == copy); 108 109 // Test that different paths triggers not equal. 110 s.restore(); 111 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 112 s.save(); 113 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 114 115 p.addRect(r); 116 s.clipDevPath(p, SkRegion::kIntersect_Op, doAA); 117 REPORTER_ASSERT(reporter, s != copy); 118} 119 120static void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack, 121 int count) { 122 SkClipStack::B2TIter iter(stack); 123 int counter = 0; 124 while (iter.next()) { 125 counter += 1; 126 } 127 REPORTER_ASSERT(reporter, count == counter); 128} 129 130static void test_iterators(skiatest::Reporter* reporter) { 131 SkClipStack stack; 132 133 static const SkRect gRects[] = { 134 { 0, 0, 40, 40 }, 135 { 60, 0, 100, 40 }, 136 { 0, 60, 40, 100 }, 137 { 60, 60, 100, 100 } 138 }; 139 140 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 141 // the union op will prevent these from being fused together 142 stack.clipDevRect(gRects[i], SkRegion::kUnion_Op, false); 143 } 144 145 assert_count(reporter, stack, 4); 146 147 // bottom to top iteration 148 { 149 const SkClipStack::B2TIter::Clip* clip = NULL; 150 151 SkClipStack::B2TIter iter(stack); 152 int i; 153 154 for (i = 0, clip = iter.next(); clip; ++i, clip = iter.next()) { 155 REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]); 156 } 157 158 SkASSERT(i == 4); 159 } 160 161 // top to bottom iteration 162 { 163 const SkClipStack::Iter::Clip* clip = NULL; 164 165 SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 166 int i; 167 168 for (i = 3, clip = iter.prev(); clip; --i, clip = iter.prev()) { 169 REPORTER_ASSERT(reporter, *clip->fRect == gRects[i]); 170 } 171 172 SkASSERT(i == -1); 173 } 174 175 // skipToTopmost 176 { 177 const SkClipStack::Iter::Clip*clip = NULL; 178 179 SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 180 181 clip = iter.skipToTopmost(SkRegion::kUnion_Op); 182 REPORTER_ASSERT(reporter, *clip->fRect == gRects[3]); 183 } 184} 185 186static void test_bounds(skiatest::Reporter* reporter, bool useRects) { 187 188 static const int gNumCases = 20; 189 static const SkRect gAnswerRectsBW[gNumCases] = { 190 // A op B 191 { 40, 40, 50, 50 }, 192 { 10, 10, 50, 50 }, 193 { 10, 10, 80, 80 }, 194 { 10, 10, 80, 80 }, 195 { 40, 40, 80, 80 }, 196 197 // invA op B 198 { 40, 40, 80, 80 }, 199 { 0, 0, 100, 100 }, 200 { 0, 0, 100, 100 }, 201 { 0, 0, 100, 100 }, 202 { 40, 40, 50, 50 }, 203 204 // A op invB 205 { 10, 10, 50, 50 }, 206 { 40, 40, 50, 50 }, 207 { 0, 0, 100, 100 }, 208 { 0, 0, 100, 100 }, 209 { 0, 0, 100, 100 }, 210 211 // invA op invB 212 { 0, 0, 100, 100 }, 213 { 40, 40, 80, 80 }, 214 { 0, 0, 100, 100 }, 215 { 10, 10, 80, 80 }, 216 { 10, 10, 50, 50 }, 217 }; 218 219 static const SkRegion::Op gOps[] = { 220 SkRegion::kIntersect_Op, 221 SkRegion::kDifference_Op, 222 SkRegion::kUnion_Op, 223 SkRegion::kXOR_Op, 224 SkRegion::kReverseDifference_Op 225 }; 226 227 SkRect rectA, rectB; 228 229 rectA.iset(10, 10, 50, 50); 230 rectB.iset(40, 40, 80, 80); 231 232 SkPath clipA, clipB; 233 234 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5)); 235 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5)); 236 237 SkClipStack stack; 238 SkRect bound; 239 bool isIntersectionOfRects = false; 240 241 int testCase = 0; 242 int numBitTests = useRects ? 1 : 4; 243 for (int invBits = 0; invBits < numBitTests; ++invBits) { 244 for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { 245 246 stack.save(); 247 bool doInvA = SkToBool(invBits & 1); 248 bool doInvB = SkToBool(invBits & 2); 249 250 clipA.setFillType(doInvA ? SkPath::kInverseEvenOdd_FillType : 251 SkPath::kEvenOdd_FillType); 252 clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType : 253 SkPath::kEvenOdd_FillType); 254 255 if (useRects) { 256 stack.clipDevRect(rectA, SkRegion::kIntersect_Op, false); 257 stack.clipDevRect(rectB, gOps[op], false); 258 } else { 259 stack.clipDevPath(clipA, SkRegion::kIntersect_Op, false); 260 stack.clipDevPath(clipB, gOps[op], false); 261 } 262 263 REPORTER_ASSERT(reporter, !stack.isWideOpen()); 264 265 stack.getConservativeBounds(0, 0, 100, 100, &bound, 266 &isIntersectionOfRects); 267 268 if (useRects) { 269 REPORTER_ASSERT(reporter, isIntersectionOfRects == 270 (gOps[op] == SkRegion::kIntersect_Op)); 271 } else { 272 REPORTER_ASSERT(reporter, !isIntersectionOfRects); 273 } 274 275 SkASSERT(testCase < gNumCases); 276 REPORTER_ASSERT(reporter, bound == gAnswerRectsBW[testCase]); 277 ++testCase; 278 279 stack.restore(); 280 } 281 } 282} 283 284// Test out 'isWideOpen' entry point 285static void test_isWideOpen(skiatest::Reporter* reporter) { 286 287 SkRect rectA, rectB; 288 289 rectA.iset(10, 10, 40, 40); 290 rectB.iset(50, 50, 80, 80); 291 292 // Stack should initially be wide open 293 { 294 SkClipStack stack; 295 296 REPORTER_ASSERT(reporter, stack.isWideOpen()); 297 } 298 299 // Test out case where the user specifies a union that includes everything 300 { 301 SkClipStack stack; 302 303 SkPath clipA, clipB; 304 305 clipA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5)); 306 clipA.setFillType(SkPath::kInverseEvenOdd_FillType); 307 308 clipB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5)); 309 clipB.setFillType(SkPath::kInverseEvenOdd_FillType); 310 311 stack.clipDevPath(clipA, SkRegion::kReplace_Op, false); 312 stack.clipDevPath(clipB, SkRegion::kUnion_Op, false); 313 314 REPORTER_ASSERT(reporter, stack.isWideOpen()); 315 } 316 317 // Test out union w/ a wide open clip 318 { 319 SkClipStack stack; 320 321 stack.clipDevRect(rectA, SkRegion::kUnion_Op, false); 322 323 REPORTER_ASSERT(reporter, stack.isWideOpen()); 324 } 325 326 // Test out empty difference from a wide open clip 327 { 328 SkClipStack stack; 329 330 SkRect emptyRect; 331 emptyRect.setEmpty(); 332 333 stack.clipDevRect(emptyRect, SkRegion::kDifference_Op, false); 334 335 REPORTER_ASSERT(reporter, stack.isWideOpen()); 336 } 337 338 // Test out return to wide open 339 { 340 SkClipStack stack; 341 342 stack.save(); 343 344 stack.clipDevRect(rectA, SkRegion::kReplace_Op, false); 345 346 REPORTER_ASSERT(reporter, !stack.isWideOpen()); 347 348 stack.restore(); 349 350 REPORTER_ASSERT(reporter, stack.isWideOpen()); 351 } 352} 353 354 355static void TestClipStack(skiatest::Reporter* reporter) { 356 SkClipStack stack; 357 358 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 359 assert_count(reporter, stack, 0); 360 361 static const SkIRect gRects[] = { 362 { 0, 0, 100, 100 }, 363 { 25, 25, 125, 125 }, 364 { 0, 0, 1000, 1000 }, 365 { 0, 0, 75, 75 } 366 }; 367 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 368 stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op); 369 } 370 371 // all of the above rects should have been intersected, leaving only 1 rect 372 SkClipStack::B2TIter iter(stack); 373 const SkClipStack::B2TIter::Clip* clip = iter.next(); 374 SkRect answer; 375 answer.iset(25, 25, 75, 75); 376 377 REPORTER_ASSERT(reporter, clip); 378 REPORTER_ASSERT(reporter, clip->fRect); 379 REPORTER_ASSERT(reporter, !clip->fPath); 380 REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == clip->fOp); 381 REPORTER_ASSERT(reporter, *clip->fRect == answer); 382 // now check that we only had one in our iterator 383 REPORTER_ASSERT(reporter, !iter.next()); 384 385 stack.reset(); 386 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 387 assert_count(reporter, stack, 0); 388 389 test_assign_and_comparison(reporter); 390 test_iterators(reporter); 391 test_bounds(reporter, true); 392 test_bounds(reporter, false); 393 test_isWideOpen(reporter); 394} 395 396#include "TestClassDef.h" 397DEFINE_TESTCLASS("ClipStack", TestClipStackClass, TestClipStack) 398