ClipStackTest.cpp revision 4c2a2f7c5e8ec77771153f94c454adf21fd33805
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 stack.getConservativeBounds(0, 0, 100, 100, &bound, 264 &isIntersectionOfRects); 265 266 if (useRects) { 267 REPORTER_ASSERT(reporter, isIntersectionOfRects == 268 (gOps[op] == SkRegion::kIntersect_Op)); 269 } else { 270 REPORTER_ASSERT(reporter, !isIntersectionOfRects); 271 } 272 273 SkASSERT(testCase < gNumCases); 274 REPORTER_ASSERT(reporter, bound == gAnswerRectsBW[testCase]); 275 ++testCase; 276 277 stack.restore(); 278 } 279 } 280} 281 282static void TestClipStack(skiatest::Reporter* reporter) { 283 SkClipStack stack; 284 285 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 286 assert_count(reporter, stack, 0); 287 288 static const SkIRect gRects[] = { 289 { 0, 0, 100, 100 }, 290 { 25, 25, 125, 125 }, 291 { 0, 0, 1000, 1000 }, 292 { 0, 0, 75, 75 } 293 }; 294 for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 295 stack.clipDevRect(gRects[i], SkRegion::kIntersect_Op); 296 } 297 298 // all of the above rects should have been intersected, leaving only 1 rect 299 SkClipStack::B2TIter iter(stack); 300 const SkClipStack::B2TIter::Clip* clip = iter.next(); 301 SkRect answer; 302 answer.iset(25, 25, 75, 75); 303 304 REPORTER_ASSERT(reporter, clip); 305 REPORTER_ASSERT(reporter, clip->fRect); 306 REPORTER_ASSERT(reporter, !clip->fPath); 307 REPORTER_ASSERT(reporter, SkRegion::kIntersect_Op == clip->fOp); 308 REPORTER_ASSERT(reporter, *clip->fRect == answer); 309 // now check that we only had one in our iterator 310 REPORTER_ASSERT(reporter, !iter.next()); 311 312 stack.reset(); 313 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 314 assert_count(reporter, stack, 0); 315 316 test_assign_and_comparison(reporter); 317 test_iterators(reporter); 318 test_bounds(reporter, true); 319 test_bounds(reporter, false); 320} 321 322#include "TestClassDef.h" 323DEFINE_TESTCLASS("ClipStack", TestClipStackClass, TestClipStack) 324