1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 9cb93a386Sopenharmony_ci#include "include/core/SkClipOp.h" 10cb93a386Sopenharmony_ci#include "include/core/SkImageInfo.h" 11cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h" 12cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPoint.h" 14cb93a386Sopenharmony_ci#include "include/core/SkRRect.h" 15cb93a386Sopenharmony_ci#include "include/core/SkRect.h" 16cb93a386Sopenharmony_ci#include "include/core/SkRefCnt.h" 17cb93a386Sopenharmony_ci#include "include/core/SkRegion.h" 18cb93a386Sopenharmony_ci#include "include/core/SkScalar.h" 19cb93a386Sopenharmony_ci#include "include/core/SkSize.h" 20cb93a386Sopenharmony_ci#include "include/core/SkString.h" 21cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 22cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 23cb93a386Sopenharmony_ci#include "include/effects/SkGradientShader.h" 24cb93a386Sopenharmony_ci#include "include/private/GrResourceKey.h" 25cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 26cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 27cb93a386Sopenharmony_ci#include "src/core/SkClipStack.h" 28cb93a386Sopenharmony_ci#include "tests/Test.h" 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ci#include <cstring> 31cb93a386Sopenharmony_ci#include <initializer_list> 32cb93a386Sopenharmony_ci#include <new> 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cistatic void test_assign_and_comparison(skiatest::Reporter* reporter) { 35cb93a386Sopenharmony_ci SkClipStack s; 36cb93a386Sopenharmony_ci bool doAA = false; 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 39cb93a386Sopenharmony_ci 40cb93a386Sopenharmony_ci // Build up a clip stack with a path, an empty clip, and a rect. 41cb93a386Sopenharmony_ci s.save(); 42cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci SkPath p; 45cb93a386Sopenharmony_ci p.moveTo(5, 6); 46cb93a386Sopenharmony_ci p.lineTo(7, 8); 47cb93a386Sopenharmony_ci p.lineTo(5, 9); 48cb93a386Sopenharmony_ci p.close(); 49cb93a386Sopenharmony_ci s.clipPath(p, SkMatrix::I(), SkClipOp::kIntersect, doAA); 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci s.save(); 52cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_ci SkRect r = SkRect::MakeLTRB(1, 2, 103, 104); 55cb93a386Sopenharmony_ci s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA); 56cb93a386Sopenharmony_ci r = SkRect::MakeLTRB(4, 5, 56, 57); 57cb93a386Sopenharmony_ci s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA); 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci s.save(); 60cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci r = SkRect::MakeLTRB(14, 15, 16, 17); 63cb93a386Sopenharmony_ci s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA); 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci // Test that assignment works. 66cb93a386Sopenharmony_ci SkClipStack copy = s; 67cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s == copy); 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci // Test that different save levels triggers not equal. 70cb93a386Sopenharmony_ci s.restore(); 71cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 72cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s != copy); 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci // Test that an equal, but not copied version is equal. 75cb93a386Sopenharmony_ci s.save(); 76cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 77cb93a386Sopenharmony_ci r = SkRect::MakeLTRB(14, 15, 16, 17); 78cb93a386Sopenharmony_ci s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA); 79cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s == copy); 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci // Test that a different op on one level triggers not equal. 82cb93a386Sopenharmony_ci s.restore(); 83cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 84cb93a386Sopenharmony_ci s.save(); 85cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 86cb93a386Sopenharmony_ci r = SkRect::MakeLTRB(14, 15, 16, 17); 87cb93a386Sopenharmony_ci s.clipRect(r, SkMatrix::I(), SkClipOp::kIntersect, doAA); 88cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s != copy); 89cb93a386Sopenharmony_ci 90cb93a386Sopenharmony_ci // Test that version constructed with rect-path rather than a rect is still considered equal. 91cb93a386Sopenharmony_ci s.restore(); 92cb93a386Sopenharmony_ci s.save(); 93cb93a386Sopenharmony_ci SkPath rp; 94cb93a386Sopenharmony_ci rp.addRect(r); 95cb93a386Sopenharmony_ci s.clipPath(rp, SkMatrix::I(), SkClipOp::kDifference, doAA); 96cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s == copy); 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci // Test that different rects triggers not equal. 99cb93a386Sopenharmony_ci s.restore(); 100cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 101cb93a386Sopenharmony_ci s.save(); 102cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 3 == s.getSaveCount()); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci r = SkRect::MakeLTRB(24, 25, 26, 27); 105cb93a386Sopenharmony_ci s.clipRect(r, SkMatrix::I(), SkClipOp::kDifference, doAA); 106cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s != copy); 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci s.restore(); 109cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == s.getSaveCount()); 110cb93a386Sopenharmony_ci 111cb93a386Sopenharmony_ci copy.restore(); 112cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == copy.getSaveCount()); 113cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s == copy); 114cb93a386Sopenharmony_ci s.restore(); 115cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 116cb93a386Sopenharmony_ci copy.restore(); 117cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == copy.getSaveCount()); 118cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s == copy); 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ci // Test that different paths triggers not equal. 121cb93a386Sopenharmony_ci s.restore(); 122cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 123cb93a386Sopenharmony_ci s.save(); 124cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 125cb93a386Sopenharmony_ci 126cb93a386Sopenharmony_ci p.addRect(r); 127cb93a386Sopenharmony_ci s.clipPath(p, SkMatrix::I(), SkClipOp::kIntersect, doAA); 128cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, s != copy); 129cb93a386Sopenharmony_ci} 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_cistatic void assert_count(skiatest::Reporter* reporter, const SkClipStack& stack, 132cb93a386Sopenharmony_ci int count) { 133cb93a386Sopenharmony_ci SkClipStack::B2TIter iter(stack); 134cb93a386Sopenharmony_ci int counter = 0; 135cb93a386Sopenharmony_ci while (iter.next()) { 136cb93a386Sopenharmony_ci counter += 1; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, count == counter); 139cb93a386Sopenharmony_ci} 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci// Exercise the SkClipStack's bottom to top and bidirectional iterators 142cb93a386Sopenharmony_ci// (including the skipToTopmost functionality) 143cb93a386Sopenharmony_cistatic void test_iterators(skiatest::Reporter* reporter) { 144cb93a386Sopenharmony_ci SkClipStack stack; 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci static const SkRect gRects[] = { 147cb93a386Sopenharmony_ci { 0, 0, 40, 40 }, 148cb93a386Sopenharmony_ci { 60, 0, 100, 40 }, 149cb93a386Sopenharmony_ci { 0, 60, 40, 100 }, 150cb93a386Sopenharmony_ci { 60, 60, 100, 100 } 151cb93a386Sopenharmony_ci }; 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 154cb93a386Sopenharmony_ci // the difference op will prevent these from being fused together 155cb93a386Sopenharmony_ci stack.clipRect(gRects[i], SkMatrix::I(), SkClipOp::kDifference, false); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci assert_count(reporter, stack, 4); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci // bottom to top iteration 161cb93a386Sopenharmony_ci { 162cb93a386Sopenharmony_ci const SkClipStack::Element* element = nullptr; 163cb93a386Sopenharmony_ci 164cb93a386Sopenharmony_ci SkClipStack::B2TIter iter(stack); 165cb93a386Sopenharmony_ci int i; 166cb93a386Sopenharmony_ci 167cb93a386Sopenharmony_ci for (i = 0, element = iter.next(); element; ++i, element = iter.next()) { 168cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect == 169cb93a386Sopenharmony_ci element->getDeviceSpaceType()); 170cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]); 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci SkASSERT(i == 4); 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci // top to bottom iteration 177cb93a386Sopenharmony_ci { 178cb93a386Sopenharmony_ci const SkClipStack::Element* element = nullptr; 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 181cb93a386Sopenharmony_ci int i; 182cb93a386Sopenharmony_ci 183cb93a386Sopenharmony_ci for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) { 184cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect == 185cb93a386Sopenharmony_ci element->getDeviceSpaceType()); 186cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci SkASSERT(i == -1); 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci // skipToTopmost 193cb93a386Sopenharmony_ci { 194cb93a386Sopenharmony_ci const SkClipStack::Element* element = nullptr; 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 197cb93a386Sopenharmony_ci 198cb93a386Sopenharmony_ci element = iter.skipToTopmost(SkClipOp::kDifference); 199cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect == 200cb93a386Sopenharmony_ci element->getDeviceSpaceType()); 201cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[3]); 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci} 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci// Exercise the SkClipStack's getConservativeBounds computation 206cb93a386Sopenharmony_cistatic void test_bounds(skiatest::Reporter* reporter, 207cb93a386Sopenharmony_ci SkClipStack::Element::DeviceSpaceType primType) { 208cb93a386Sopenharmony_ci static const int gNumCases = 8; 209cb93a386Sopenharmony_ci static const SkRect gAnswerRectsBW[gNumCases] = { 210cb93a386Sopenharmony_ci // A op B 211cb93a386Sopenharmony_ci { 40, 40, 50, 50 }, 212cb93a386Sopenharmony_ci { 10, 10, 50, 50 }, 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci // invA op B 215cb93a386Sopenharmony_ci { 40, 40, 80, 80 }, 216cb93a386Sopenharmony_ci { 0, 0, 100, 100 }, 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci // A op invB 219cb93a386Sopenharmony_ci { 10, 10, 50, 50 }, 220cb93a386Sopenharmony_ci { 40, 40, 50, 50 }, 221cb93a386Sopenharmony_ci 222cb93a386Sopenharmony_ci // invA op invB 223cb93a386Sopenharmony_ci { 0, 0, 100, 100 }, 224cb93a386Sopenharmony_ci { 40, 40, 80, 80 }, 225cb93a386Sopenharmony_ci }; 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci static const SkClipOp gOps[] = { 228cb93a386Sopenharmony_ci SkClipOp::kIntersect, 229cb93a386Sopenharmony_ci SkClipOp::kDifference 230cb93a386Sopenharmony_ci }; 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci SkRect rectA, rectB; 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci rectA.setLTRB(10, 10, 50, 50); 235cb93a386Sopenharmony_ci rectB.setLTRB(40, 40, 80, 80); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci SkRRect rrectA, rrectB; 238cb93a386Sopenharmony_ci rrectA.setOval(rectA); 239cb93a386Sopenharmony_ci rrectB.setRectXY(rectB, SkIntToScalar(1), SkIntToScalar(2)); 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci SkPath pathA, pathB; 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci pathA.addRoundRect(rectA, SkIntToScalar(5), SkIntToScalar(5)); 244cb93a386Sopenharmony_ci pathB.addRoundRect(rectB, SkIntToScalar(5), SkIntToScalar(5)); 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci SkClipStack stack; 247cb93a386Sopenharmony_ci SkRect devClipBound; 248cb93a386Sopenharmony_ci bool isIntersectionOfRects = false; 249cb93a386Sopenharmony_ci 250cb93a386Sopenharmony_ci int testCase = 0; 251cb93a386Sopenharmony_ci int numBitTests = SkClipStack::Element::DeviceSpaceType::kPath == primType ? 4 : 1; 252cb93a386Sopenharmony_ci for (int invBits = 0; invBits < numBitTests; ++invBits) { 253cb93a386Sopenharmony_ci for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci stack.save(); 256cb93a386Sopenharmony_ci bool doInvA = SkToBool(invBits & 1); 257cb93a386Sopenharmony_ci bool doInvB = SkToBool(invBits & 2); 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci pathA.setFillType(doInvA ? SkPathFillType::kInverseEvenOdd : 260cb93a386Sopenharmony_ci SkPathFillType::kEvenOdd); 261cb93a386Sopenharmony_ci pathB.setFillType(doInvB ? SkPathFillType::kInverseEvenOdd : 262cb93a386Sopenharmony_ci SkPathFillType::kEvenOdd); 263cb93a386Sopenharmony_ci 264cb93a386Sopenharmony_ci switch (primType) { 265cb93a386Sopenharmony_ci case SkClipStack::Element::DeviceSpaceType::kShader: 266cb93a386Sopenharmony_ci case SkClipStack::Element::DeviceSpaceType::kEmpty: 267cb93a386Sopenharmony_ci SkDEBUGFAIL("Don't call this with kEmpty or kShader."); 268cb93a386Sopenharmony_ci break; 269cb93a386Sopenharmony_ci case SkClipStack::Element::DeviceSpaceType::kRect: 270cb93a386Sopenharmony_ci stack.clipRect(rectA, SkMatrix::I(), SkClipOp::kIntersect, false); 271cb93a386Sopenharmony_ci stack.clipRect(rectB, SkMatrix::I(), gOps[op], false); 272cb93a386Sopenharmony_ci break; 273cb93a386Sopenharmony_ci case SkClipStack::Element::DeviceSpaceType::kRRect: 274cb93a386Sopenharmony_ci stack.clipRRect(rrectA, SkMatrix::I(), SkClipOp::kIntersect, false); 275cb93a386Sopenharmony_ci stack.clipRRect(rrectB, SkMatrix::I(), gOps[op], false); 276cb93a386Sopenharmony_ci break; 277cb93a386Sopenharmony_ci case SkClipStack::Element::DeviceSpaceType::kPath: 278cb93a386Sopenharmony_ci stack.clipPath(pathA, SkMatrix::I(), SkClipOp::kIntersect, false); 279cb93a386Sopenharmony_ci stack.clipPath(pathB, SkMatrix::I(), gOps[op], false); 280cb93a386Sopenharmony_ci break; 281cb93a386Sopenharmony_ci } 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !stack.isWideOpen()); 284cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID()); 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci stack.getConservativeBounds(0, 0, 100, 100, &devClipBound, 287cb93a386Sopenharmony_ci &isIntersectionOfRects); 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci if (SkClipStack::Element::DeviceSpaceType::kRect == primType) { 290cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isIntersectionOfRects == 291cb93a386Sopenharmony_ci (gOps[op] == SkClipOp::kIntersect)); 292cb93a386Sopenharmony_ci } else { 293cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !isIntersectionOfRects); 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci SkASSERT(testCase < gNumCases); 297cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, devClipBound == gAnswerRectsBW[testCase]); 298cb93a386Sopenharmony_ci ++testCase; 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci stack.restore(); 301cb93a386Sopenharmony_ci } 302cb93a386Sopenharmony_ci } 303cb93a386Sopenharmony_ci} 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci// Test out 'isWideOpen' entry point 306cb93a386Sopenharmony_cistatic void test_isWideOpen(skiatest::Reporter* reporter) { 307cb93a386Sopenharmony_ci { 308cb93a386Sopenharmony_ci // Empty stack is wide open. Wide open stack means that gen id is wide open. 309cb93a386Sopenharmony_ci SkClipStack stack; 310cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, stack.isWideOpen()); 311cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID()); 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci SkRect rectA, rectB; 315cb93a386Sopenharmony_ci 316cb93a386Sopenharmony_ci rectA.setLTRB(10, 10, 40, 40); 317cb93a386Sopenharmony_ci rectB.setLTRB(50, 50, 80, 80); 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci // Stack should initially be wide open 320cb93a386Sopenharmony_ci { 321cb93a386Sopenharmony_ci SkClipStack stack; 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, stack.isWideOpen()); 324cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID()); 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci // Test out empty difference from a wide open clip 328cb93a386Sopenharmony_ci { 329cb93a386Sopenharmony_ci SkClipStack stack; 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci SkRect emptyRect; 332cb93a386Sopenharmony_ci emptyRect.setEmpty(); 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci stack.clipRect(emptyRect, SkMatrix::I(), SkClipOp::kDifference, false); 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, stack.isWideOpen()); 337cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID()); 338cb93a386Sopenharmony_ci } 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci // Test out return to wide open 341cb93a386Sopenharmony_ci { 342cb93a386Sopenharmony_ci SkClipStack stack; 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci stack.save(); 345cb93a386Sopenharmony_ci 346cb93a386Sopenharmony_ci stack.clipRect(rectA, SkMatrix::I(), SkClipOp::kIntersect, false); 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !stack.isWideOpen()); 349cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID != stack.getTopmostGenID()); 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci stack.restore(); 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, stack.isWideOpen()); 354cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kWideOpenGenID == stack.getTopmostGenID()); 355cb93a386Sopenharmony_ci } 356cb93a386Sopenharmony_ci} 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_cistatic int count(const SkClipStack& stack) { 359cb93a386Sopenharmony_ci 360cb93a386Sopenharmony_ci SkClipStack::Iter iter(stack, SkClipStack::Iter::kTop_IterStart); 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci const SkClipStack::Element* element = nullptr; 363cb93a386Sopenharmony_ci int count = 0; 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci for (element = iter.prev(); element; element = iter.prev(), ++count) { 366cb93a386Sopenharmony_ci } 367cb93a386Sopenharmony_ci 368cb93a386Sopenharmony_ci return count; 369cb93a386Sopenharmony_ci} 370cb93a386Sopenharmony_ci 371cb93a386Sopenharmony_cistatic void test_rect_inverse_fill(skiatest::Reporter* reporter) { 372cb93a386Sopenharmony_ci // non-intersecting rectangles 373cb93a386Sopenharmony_ci SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10); 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci SkPath path; 376cb93a386Sopenharmony_ci path.addRect(rect); 377cb93a386Sopenharmony_ci path.toggleInverseFillType(); 378cb93a386Sopenharmony_ci SkClipStack stack; 379cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ci SkRect bounds; 382cb93a386Sopenharmony_ci SkClipStack::BoundsType boundsType; 383cb93a386Sopenharmony_ci stack.getBounds(&bounds, &boundsType); 384cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kInsideOut_BoundsType == boundsType); 385cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bounds == rect); 386cb93a386Sopenharmony_ci} 387cb93a386Sopenharmony_ci 388cb93a386Sopenharmony_cistatic void test_rect_replace(skiatest::Reporter* reporter) { 389cb93a386Sopenharmony_ci SkRect rect = SkRect::MakeWH(100, 100); 390cb93a386Sopenharmony_ci SkRect rect2 = SkRect::MakeXYWH(50, 50, 100, 100); 391cb93a386Sopenharmony_ci 392cb93a386Sopenharmony_ci SkRect bound; 393cb93a386Sopenharmony_ci SkClipStack::BoundsType type; 394cb93a386Sopenharmony_ci bool isIntersectionOfRects; 395cb93a386Sopenharmony_ci 396cb93a386Sopenharmony_ci // Adding a new rect with the replace operator should not increase 397cb93a386Sopenharmony_ci // the stack depth. BW replacing BW. 398cb93a386Sopenharmony_ci { 399cb93a386Sopenharmony_ci SkClipStack stack; 400cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == count(stack)); 401cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 402cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 403cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 404cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci // Adding a new rect with the replace operator should not increase 408cb93a386Sopenharmony_ci // the stack depth. AA replacing AA. 409cb93a386Sopenharmony_ci { 410cb93a386Sopenharmony_ci SkClipStack stack; 411cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == count(stack)); 412cb93a386Sopenharmony_ci stack.replaceClip(rect, true); 413cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 414cb93a386Sopenharmony_ci stack.replaceClip(rect, true); 415cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ci // Adding a new rect with the replace operator should not increase 419cb93a386Sopenharmony_ci // the stack depth. BW replacing AA replacing BW. 420cb93a386Sopenharmony_ci { 421cb93a386Sopenharmony_ci SkClipStack stack; 422cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == count(stack)); 423cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 424cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 425cb93a386Sopenharmony_ci stack.replaceClip(rect, true); 426cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 427cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 428cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 429cb93a386Sopenharmony_ci } 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci // Make sure replace clip rects don't collapse too much. 432cb93a386Sopenharmony_ci { 433cb93a386Sopenharmony_ci SkClipStack stack; 434cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 435cb93a386Sopenharmony_ci stack.clipRect(rect2, SkMatrix::I(), SkClipOp::kIntersect, false); 436cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_ci stack.save(); 439cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 440cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 441cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 442cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, bound == rect); 443cb93a386Sopenharmony_ci stack.restore(); 444cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ci stack.save(); 447cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 448cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 449cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 450cb93a386Sopenharmony_ci stack.restore(); 451cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 452cb93a386Sopenharmony_ci 453cb93a386Sopenharmony_ci stack.save(); 454cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 455cb93a386Sopenharmony_ci stack.clipRect(rect2, SkMatrix::I(), SkClipOp::kIntersect, false); 456cb93a386Sopenharmony_ci stack.replaceClip(rect, false); 457cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 458cb93a386Sopenharmony_ci stack.restore(); 459cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 460cb93a386Sopenharmony_ci } 461cb93a386Sopenharmony_ci} 462cb93a386Sopenharmony_ci 463cb93a386Sopenharmony_ci// Simplified path-based version of test_rect_replace. 464cb93a386Sopenharmony_cistatic void test_path_replace(skiatest::Reporter* reporter) { 465cb93a386Sopenharmony_ci auto replacePath = [](SkClipStack* stack, const SkPath& path, bool doAA) { 466cb93a386Sopenharmony_ci const SkRect wideOpen = SkRect::MakeLTRB(-1000, -1000, 1000, 1000); 467cb93a386Sopenharmony_ci stack->replaceClip(wideOpen, false); 468cb93a386Sopenharmony_ci stack->clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, doAA); 469cb93a386Sopenharmony_ci }; 470cb93a386Sopenharmony_ci SkRect rect = SkRect::MakeWH(100, 100); 471cb93a386Sopenharmony_ci SkPath path; 472cb93a386Sopenharmony_ci path.addCircle(50, 50, 50); 473cb93a386Sopenharmony_ci 474cb93a386Sopenharmony_ci // Emulating replace operations with more complex geometry is not atomic, it's a replace 475cb93a386Sopenharmony_ci // with a wide-open rect and then an intersection with the complex geometry. The replace can 476cb93a386Sopenharmony_ci // combine with prior elements, but the subsequent intersect cannot be combined so the stack 477cb93a386Sopenharmony_ci // continues to grow. 478cb93a386Sopenharmony_ci { 479cb93a386Sopenharmony_ci SkClipStack stack; 480cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == count(stack)); 481cb93a386Sopenharmony_ci replacePath(&stack, path, false); 482cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 483cb93a386Sopenharmony_ci replacePath(&stack, path, false); 484cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 485cb93a386Sopenharmony_ci } 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ci // Replacing rect with path. 488cb93a386Sopenharmony_ci { 489cb93a386Sopenharmony_ci SkClipStack stack; 490cb93a386Sopenharmony_ci stack.replaceClip(rect, true); 491cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 492cb93a386Sopenharmony_ci replacePath(&stack, path, true); 493cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 494cb93a386Sopenharmony_ci } 495cb93a386Sopenharmony_ci} 496cb93a386Sopenharmony_ci 497cb93a386Sopenharmony_ci// Test out SkClipStack's merging of rect clips. In particular exercise 498cb93a386Sopenharmony_ci// merging of aa vs. bw rects. 499cb93a386Sopenharmony_cistatic void test_rect_merging(skiatest::Reporter* reporter) { 500cb93a386Sopenharmony_ci 501cb93a386Sopenharmony_ci SkRect overlapLeft = SkRect::MakeLTRB(10, 10, 50, 50); 502cb93a386Sopenharmony_ci SkRect overlapRight = SkRect::MakeLTRB(40, 40, 80, 80); 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_ci SkRect nestedParent = SkRect::MakeLTRB(10, 10, 90, 90); 505cb93a386Sopenharmony_ci SkRect nestedChild = SkRect::MakeLTRB(40, 40, 60, 60); 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci SkRect bound; 508cb93a386Sopenharmony_ci SkClipStack::BoundsType type; 509cb93a386Sopenharmony_ci bool isIntersectionOfRects; 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ci // all bw overlapping - should merge 512cb93a386Sopenharmony_ci { 513cb93a386Sopenharmony_ci SkClipStack stack; 514cb93a386Sopenharmony_ci stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, false); 515cb93a386Sopenharmony_ci stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, false); 516cb93a386Sopenharmony_ci 517cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 520cb93a386Sopenharmony_ci 521cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isIntersectionOfRects); 522cb93a386Sopenharmony_ci } 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ci // all aa overlapping - should merge 525cb93a386Sopenharmony_ci { 526cb93a386Sopenharmony_ci SkClipStack stack; 527cb93a386Sopenharmony_ci stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, true); 528cb93a386Sopenharmony_ci stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, true); 529cb93a386Sopenharmony_ci 530cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 531cb93a386Sopenharmony_ci 532cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isIntersectionOfRects); 535cb93a386Sopenharmony_ci } 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci // mixed overlapping - should _not_ merge 538cb93a386Sopenharmony_ci { 539cb93a386Sopenharmony_ci SkClipStack stack; 540cb93a386Sopenharmony_ci stack.clipRect(overlapLeft, SkMatrix::I(), SkClipOp::kIntersect, true); 541cb93a386Sopenharmony_ci stack.clipRect(overlapRight, SkMatrix::I(), SkClipOp::kIntersect, false); 542cb93a386Sopenharmony_ci 543cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 544cb93a386Sopenharmony_ci 545cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !isIntersectionOfRects); 548cb93a386Sopenharmony_ci } 549cb93a386Sopenharmony_ci 550cb93a386Sopenharmony_ci // mixed nested (bw inside aa) - should merge 551cb93a386Sopenharmony_ci { 552cb93a386Sopenharmony_ci SkClipStack stack; 553cb93a386Sopenharmony_ci stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, true); 554cb93a386Sopenharmony_ci stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, false); 555cb93a386Sopenharmony_ci 556cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 557cb93a386Sopenharmony_ci 558cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isIntersectionOfRects); 561cb93a386Sopenharmony_ci } 562cb93a386Sopenharmony_ci 563cb93a386Sopenharmony_ci // mixed nested (aa inside bw) - should merge 564cb93a386Sopenharmony_ci { 565cb93a386Sopenharmony_ci SkClipStack stack; 566cb93a386Sopenharmony_ci stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, false); 567cb93a386Sopenharmony_ci stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, true); 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 1 == count(stack)); 570cb93a386Sopenharmony_ci 571cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 572cb93a386Sopenharmony_ci 573cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, isIntersectionOfRects); 574cb93a386Sopenharmony_ci } 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ci // reverse nested (aa inside bw) - should _not_ merge 577cb93a386Sopenharmony_ci { 578cb93a386Sopenharmony_ci SkClipStack stack; 579cb93a386Sopenharmony_ci stack.clipRect(nestedChild, SkMatrix::I(), SkClipOp::kIntersect, false); 580cb93a386Sopenharmony_ci stack.clipRect(nestedParent, SkMatrix::I(), SkClipOp::kIntersect, true); 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 2 == count(stack)); 583cb93a386Sopenharmony_ci 584cb93a386Sopenharmony_ci stack.getBounds(&bound, &type, &isIntersectionOfRects); 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !isIntersectionOfRects); 587cb93a386Sopenharmony_ci } 588cb93a386Sopenharmony_ci} 589cb93a386Sopenharmony_ci 590cb93a386Sopenharmony_cistatic void test_quickContains(skiatest::Reporter* reporter) { 591cb93a386Sopenharmony_ci SkRect testRect = SkRect::MakeLTRB(10, 10, 40, 40); 592cb93a386Sopenharmony_ci SkRect insideRect = SkRect::MakeLTRB(20, 20, 30, 30); 593cb93a386Sopenharmony_ci SkRect intersectingRect = SkRect::MakeLTRB(25, 25, 50, 50); 594cb93a386Sopenharmony_ci SkRect outsideRect = SkRect::MakeLTRB(0, 0, 50, 50); 595cb93a386Sopenharmony_ci SkRect nonIntersectingRect = SkRect::MakeLTRB(100, 100, 110, 110); 596cb93a386Sopenharmony_ci 597cb93a386Sopenharmony_ci SkPath insideCircle; 598cb93a386Sopenharmony_ci insideCircle.addCircle(25, 25, 5); 599cb93a386Sopenharmony_ci SkPath intersectingCircle; 600cb93a386Sopenharmony_ci intersectingCircle.addCircle(25, 40, 10); 601cb93a386Sopenharmony_ci SkPath outsideCircle; 602cb93a386Sopenharmony_ci outsideCircle.addCircle(25, 25, 50); 603cb93a386Sopenharmony_ci SkPath nonIntersectingCircle; 604cb93a386Sopenharmony_ci nonIntersectingCircle.addCircle(100, 100, 5); 605cb93a386Sopenharmony_ci 606cb93a386Sopenharmony_ci { 607cb93a386Sopenharmony_ci SkClipStack stack; 608cb93a386Sopenharmony_ci stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kDifference, false); 609cb93a386Sopenharmony_ci // return false because quickContains currently does not care for kDifference 610cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_ci // Replace Op tests 614cb93a386Sopenharmony_ci { 615cb93a386Sopenharmony_ci SkClipStack stack; 616cb93a386Sopenharmony_ci stack.replaceClip(outsideRect, false); 617cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, true == stack.quickContains(testRect)); 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci 620cb93a386Sopenharmony_ci { 621cb93a386Sopenharmony_ci SkClipStack stack; 622cb93a386Sopenharmony_ci stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false); 623cb93a386Sopenharmony_ci stack.save(); // To prevent in-place substitution by replace OP 624cb93a386Sopenharmony_ci stack.replaceClip(outsideRect, false); 625cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, true == stack.quickContains(testRect)); 626cb93a386Sopenharmony_ci stack.restore(); 627cb93a386Sopenharmony_ci } 628cb93a386Sopenharmony_ci 629cb93a386Sopenharmony_ci { 630cb93a386Sopenharmony_ci SkClipStack stack; 631cb93a386Sopenharmony_ci stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kIntersect, false); 632cb93a386Sopenharmony_ci stack.save(); // To prevent in-place substitution by replace OP 633cb93a386Sopenharmony_ci stack.replaceClip(insideRect, false); 634cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 635cb93a386Sopenharmony_ci stack.restore(); 636cb93a386Sopenharmony_ci } 637cb93a386Sopenharmony_ci 638cb93a386Sopenharmony_ci // Verify proper traversal of multi-element clip 639cb93a386Sopenharmony_ci { 640cb93a386Sopenharmony_ci SkClipStack stack; 641cb93a386Sopenharmony_ci stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false); 642cb93a386Sopenharmony_ci // Use a path for second clip to prevent in-place intersection 643cb93a386Sopenharmony_ci stack.clipPath(outsideCircle, SkMatrix::I(), SkClipOp::kIntersect, false); 644cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci // Intersect Op tests with rectangles 648cb93a386Sopenharmony_ci { 649cb93a386Sopenharmony_ci SkClipStack stack; 650cb93a386Sopenharmony_ci stack.clipRect(outsideRect, SkMatrix::I(), SkClipOp::kIntersect, false); 651cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, true == stack.quickContains(testRect)); 652cb93a386Sopenharmony_ci } 653cb93a386Sopenharmony_ci 654cb93a386Sopenharmony_ci { 655cb93a386Sopenharmony_ci SkClipStack stack; 656cb93a386Sopenharmony_ci stack.clipRect(insideRect, SkMatrix::I(), SkClipOp::kIntersect, false); 657cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 658cb93a386Sopenharmony_ci } 659cb93a386Sopenharmony_ci 660cb93a386Sopenharmony_ci { 661cb93a386Sopenharmony_ci SkClipStack stack; 662cb93a386Sopenharmony_ci stack.clipRect(intersectingRect, SkMatrix::I(), SkClipOp::kIntersect, false); 663cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 664cb93a386Sopenharmony_ci } 665cb93a386Sopenharmony_ci 666cb93a386Sopenharmony_ci { 667cb93a386Sopenharmony_ci SkClipStack stack; 668cb93a386Sopenharmony_ci stack.clipRect(nonIntersectingRect, SkMatrix::I(), SkClipOp::kIntersect, false); 669cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 670cb93a386Sopenharmony_ci } 671cb93a386Sopenharmony_ci 672cb93a386Sopenharmony_ci // Intersect Op tests with circle paths 673cb93a386Sopenharmony_ci { 674cb93a386Sopenharmony_ci SkClipStack stack; 675cb93a386Sopenharmony_ci stack.clipPath(outsideCircle, SkMatrix::I(), SkClipOp::kIntersect, false); 676cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, true == stack.quickContains(testRect)); 677cb93a386Sopenharmony_ci } 678cb93a386Sopenharmony_ci 679cb93a386Sopenharmony_ci { 680cb93a386Sopenharmony_ci SkClipStack stack; 681cb93a386Sopenharmony_ci stack.clipPath(insideCircle, SkMatrix::I(), SkClipOp::kIntersect, false); 682cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 683cb93a386Sopenharmony_ci } 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci { 686cb93a386Sopenharmony_ci SkClipStack stack; 687cb93a386Sopenharmony_ci stack.clipPath(intersectingCircle, SkMatrix::I(), SkClipOp::kIntersect, false); 688cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 689cb93a386Sopenharmony_ci } 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ci { 692cb93a386Sopenharmony_ci SkClipStack stack; 693cb93a386Sopenharmony_ci stack.clipPath(nonIntersectingCircle, SkMatrix::I(), SkClipOp::kIntersect, false); 694cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 695cb93a386Sopenharmony_ci } 696cb93a386Sopenharmony_ci 697cb93a386Sopenharmony_ci // Intersect Op tests with inverse filled rectangles 698cb93a386Sopenharmony_ci { 699cb93a386Sopenharmony_ci SkClipStack stack; 700cb93a386Sopenharmony_ci SkPath path; 701cb93a386Sopenharmony_ci path.addRect(outsideRect); 702cb93a386Sopenharmony_ci path.toggleInverseFillType(); 703cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 704cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 705cb93a386Sopenharmony_ci } 706cb93a386Sopenharmony_ci 707cb93a386Sopenharmony_ci { 708cb93a386Sopenharmony_ci SkClipStack stack; 709cb93a386Sopenharmony_ci SkPath path; 710cb93a386Sopenharmony_ci path.addRect(insideRect); 711cb93a386Sopenharmony_ci path.toggleInverseFillType(); 712cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 713cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 714cb93a386Sopenharmony_ci } 715cb93a386Sopenharmony_ci 716cb93a386Sopenharmony_ci { 717cb93a386Sopenharmony_ci SkClipStack stack; 718cb93a386Sopenharmony_ci SkPath path; 719cb93a386Sopenharmony_ci path.addRect(intersectingRect); 720cb93a386Sopenharmony_ci path.toggleInverseFillType(); 721cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 722cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 723cb93a386Sopenharmony_ci } 724cb93a386Sopenharmony_ci 725cb93a386Sopenharmony_ci { 726cb93a386Sopenharmony_ci SkClipStack stack; 727cb93a386Sopenharmony_ci SkPath path; 728cb93a386Sopenharmony_ci path.addRect(nonIntersectingRect); 729cb93a386Sopenharmony_ci path.toggleInverseFillType(); 730cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 731cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, true == stack.quickContains(testRect)); 732cb93a386Sopenharmony_ci } 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ci // Intersect Op tests with inverse filled circles 735cb93a386Sopenharmony_ci { 736cb93a386Sopenharmony_ci SkClipStack stack; 737cb93a386Sopenharmony_ci SkPath path = outsideCircle; 738cb93a386Sopenharmony_ci path.toggleInverseFillType(); 739cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 740cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 741cb93a386Sopenharmony_ci } 742cb93a386Sopenharmony_ci 743cb93a386Sopenharmony_ci { 744cb93a386Sopenharmony_ci SkClipStack stack; 745cb93a386Sopenharmony_ci SkPath path = insideCircle; 746cb93a386Sopenharmony_ci path.toggleInverseFillType(); 747cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 748cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 749cb93a386Sopenharmony_ci } 750cb93a386Sopenharmony_ci 751cb93a386Sopenharmony_ci { 752cb93a386Sopenharmony_ci SkClipStack stack; 753cb93a386Sopenharmony_ci SkPath path = intersectingCircle; 754cb93a386Sopenharmony_ci path.toggleInverseFillType(); 755cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 756cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, false == stack.quickContains(testRect)); 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci 759cb93a386Sopenharmony_ci { 760cb93a386Sopenharmony_ci SkClipStack stack; 761cb93a386Sopenharmony_ci SkPath path = nonIntersectingCircle; 762cb93a386Sopenharmony_ci path.toggleInverseFillType(); 763cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kIntersect, false); 764cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, true == stack.quickContains(testRect)); 765cb93a386Sopenharmony_ci } 766cb93a386Sopenharmony_ci} 767cb93a386Sopenharmony_ci 768cb93a386Sopenharmony_cistatic void set_region_to_stack(const SkClipStack& stack, const SkIRect& bounds, SkRegion* region) { 769cb93a386Sopenharmony_ci region->setRect(bounds); 770cb93a386Sopenharmony_ci SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart); 771cb93a386Sopenharmony_ci while (const SkClipStack::Element *element = iter.next()) { 772cb93a386Sopenharmony_ci SkRegion elemRegion; 773cb93a386Sopenharmony_ci SkRegion boundsRgn(bounds); 774cb93a386Sopenharmony_ci SkPath path; 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci switch (element->getDeviceSpaceType()) { 777cb93a386Sopenharmony_ci case SkClipStack::Element::DeviceSpaceType::kEmpty: 778cb93a386Sopenharmony_ci elemRegion.setEmpty(); 779cb93a386Sopenharmony_ci break; 780cb93a386Sopenharmony_ci default: 781cb93a386Sopenharmony_ci element->asDeviceSpacePath(&path); 782cb93a386Sopenharmony_ci elemRegion.setPath(path, boundsRgn); 783cb93a386Sopenharmony_ci break; 784cb93a386Sopenharmony_ci } 785cb93a386Sopenharmony_ci 786cb93a386Sopenharmony_ci region->op(elemRegion, element->isReplaceOp() ? SkRegion::kReplace_Op 787cb93a386Sopenharmony_ci : (SkRegion::Op) element->getOp()); 788cb93a386Sopenharmony_ci } 789cb93a386Sopenharmony_ci} 790cb93a386Sopenharmony_ci 791cb93a386Sopenharmony_cistatic void test_invfill_diff_bug(skiatest::Reporter* reporter) { 792cb93a386Sopenharmony_ci SkClipStack stack; 793cb93a386Sopenharmony_ci stack.clipRect({10, 10, 20, 20}, SkMatrix::I(), SkClipOp::kIntersect, false); 794cb93a386Sopenharmony_ci 795cb93a386Sopenharmony_ci SkPath path; 796cb93a386Sopenharmony_ci path.addRect({30, 10, 40, 20}); 797cb93a386Sopenharmony_ci path.setFillType(SkPathFillType::kInverseWinding); 798cb93a386Sopenharmony_ci stack.clipPath(path, SkMatrix::I(), SkClipOp::kDifference, false); 799cb93a386Sopenharmony_ci 800cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kEmptyGenID == stack.getTopmostGenID()); 801cb93a386Sopenharmony_ci 802cb93a386Sopenharmony_ci SkRect stackBounds; 803cb93a386Sopenharmony_ci SkClipStack::BoundsType stackBoundsType; 804cb93a386Sopenharmony_ci stack.getBounds(&stackBounds, &stackBoundsType); 805cb93a386Sopenharmony_ci 806cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, stackBounds.isEmpty()); 807cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipStack::kNormal_BoundsType == stackBoundsType); 808cb93a386Sopenharmony_ci 809cb93a386Sopenharmony_ci SkRegion region; 810cb93a386Sopenharmony_ci set_region_to_stack(stack, {0, 0, 50, 30}, ®ion); 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, region.isEmpty()); 813cb93a386Sopenharmony_ci} 814cb93a386Sopenharmony_ci 815cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 816cb93a386Sopenharmony_ci 817cb93a386Sopenharmony_cistatic void test_is_rrect_deep_rect_stack(skiatest::Reporter* reporter) { 818cb93a386Sopenharmony_ci static constexpr SkRect kTargetBounds = SkRect::MakeWH(1000, 500); 819cb93a386Sopenharmony_ci // All antialiased or all not antialiased. 820cb93a386Sopenharmony_ci for (bool aa : {false, true}) { 821cb93a386Sopenharmony_ci SkClipStack stack; 822cb93a386Sopenharmony_ci for (int i = 0; i <= 100; ++i) { 823cb93a386Sopenharmony_ci stack.save(); 824cb93a386Sopenharmony_ci stack.clipRect(SkRect::MakeLTRB(i, 0.5, kTargetBounds.width(), kTargetBounds.height()), 825cb93a386Sopenharmony_ci SkMatrix::I(), SkClipOp::kIntersect, aa); 826cb93a386Sopenharmony_ci } 827cb93a386Sopenharmony_ci SkRRect rrect; 828cb93a386Sopenharmony_ci bool isAA; 829cb93a386Sopenharmony_ci SkRRect expected = SkRRect::MakeRect( 830cb93a386Sopenharmony_ci SkRect::MakeLTRB(100, 0.5, kTargetBounds.width(), kTargetBounds.height())); 831cb93a386Sopenharmony_ci if (stack.isRRect(kTargetBounds, &rrect, &isAA)) { 832cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rrect == expected); 833cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, aa == isAA); 834cb93a386Sopenharmony_ci } else { 835cb93a386Sopenharmony_ci ERRORF(reporter, "Expected to be an rrect."); 836cb93a386Sopenharmony_ci } 837cb93a386Sopenharmony_ci } 838cb93a386Sopenharmony_ci // Mixed AA and non-AA without simple containment. 839cb93a386Sopenharmony_ci SkClipStack stack; 840cb93a386Sopenharmony_ci for (int i = 0; i <= 100; ++i) { 841cb93a386Sopenharmony_ci bool aa = i & 0b1; 842cb93a386Sopenharmony_ci int j = 100 - i; 843cb93a386Sopenharmony_ci stack.save(); 844cb93a386Sopenharmony_ci stack.clipRect(SkRect::MakeLTRB(i, j + 0.5, kTargetBounds.width(), kTargetBounds.height()), 845cb93a386Sopenharmony_ci SkMatrix::I(), SkClipOp::kIntersect, aa); 846cb93a386Sopenharmony_ci } 847cb93a386Sopenharmony_ci SkRRect rrect; 848cb93a386Sopenharmony_ci bool isAA; 849cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !stack.isRRect(kTargetBounds, &rrect, &isAA)); 850cb93a386Sopenharmony_ci} 851cb93a386Sopenharmony_ci 852cb93a386Sopenharmony_ciDEF_TEST(ClipStack, reporter) { 853cb93a386Sopenharmony_ci SkClipStack stack; 854cb93a386Sopenharmony_ci 855cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 856cb93a386Sopenharmony_ci assert_count(reporter, stack, 0); 857cb93a386Sopenharmony_ci 858cb93a386Sopenharmony_ci static const SkIRect gRects[] = { 859cb93a386Sopenharmony_ci { 0, 0, 100, 100 }, 860cb93a386Sopenharmony_ci { 25, 25, 125, 125 }, 861cb93a386Sopenharmony_ci { 0, 0, 1000, 1000 }, 862cb93a386Sopenharmony_ci { 0, 0, 75, 75 } 863cb93a386Sopenharmony_ci }; 864cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(gRects); i++) { 865cb93a386Sopenharmony_ci stack.clipDevRect(gRects[i], SkClipOp::kIntersect); 866cb93a386Sopenharmony_ci } 867cb93a386Sopenharmony_ci 868cb93a386Sopenharmony_ci // all of the above rects should have been intersected, leaving only 1 rect 869cb93a386Sopenharmony_ci SkClipStack::B2TIter iter(stack); 870cb93a386Sopenharmony_ci const SkClipStack::Element* element = iter.next(); 871cb93a386Sopenharmony_ci SkRect answer; 872cb93a386Sopenharmony_ci answer.setLTRB(25, 25, 75, 75); 873cb93a386Sopenharmony_ci 874cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, element); 875cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 876cb93a386Sopenharmony_ci SkClipStack::Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()); 877cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkClipOp::kIntersect == element->getOp()); 878cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == answer); 879cb93a386Sopenharmony_ci // now check that we only had one in our iterator 880cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !iter.next()); 881cb93a386Sopenharmony_ci 882cb93a386Sopenharmony_ci stack.reset(); 883cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 884cb93a386Sopenharmony_ci assert_count(reporter, stack, 0); 885cb93a386Sopenharmony_ci 886cb93a386Sopenharmony_ci test_assign_and_comparison(reporter); 887cb93a386Sopenharmony_ci test_iterators(reporter); 888cb93a386Sopenharmony_ci test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kRect); 889cb93a386Sopenharmony_ci test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kRRect); 890cb93a386Sopenharmony_ci test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kPath); 891cb93a386Sopenharmony_ci test_isWideOpen(reporter); 892cb93a386Sopenharmony_ci test_rect_merging(reporter); 893cb93a386Sopenharmony_ci test_rect_replace(reporter); 894cb93a386Sopenharmony_ci test_rect_inverse_fill(reporter); 895cb93a386Sopenharmony_ci test_path_replace(reporter); 896cb93a386Sopenharmony_ci test_quickContains(reporter); 897cb93a386Sopenharmony_ci test_invfill_diff_bug(reporter); 898cb93a386Sopenharmony_ci test_is_rrect_deep_rect_stack(reporter); 899cb93a386Sopenharmony_ci} 900