1 /* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTypes.h" 9 10 #if !defined(SK_BUILD_FOR_GOOGLE3) 11 12 #include "SkRect.h" 13 #include "SkRectPriv.h" 14 #include "SkSGColor.h" 15 #include "SkSGDraw.h" 16 #include "SkSGGroup.h" 17 #include "SkSGInvalidationController.h" 18 #include "SkSGRect.h" 19 #include "SkSGRenderEffect.h" 20 #include "SkSGTransform.h" 21 #include "SkTo.h" 22 23 #include "Test.h" 24 25 #include <vector> 26 27 static void check_inval(skiatest::Reporter* reporter, const sk_sp<sksg::Node>& root, 28 const SkRect& expected_bounds, 29 const SkRect& expected_inval_bounds, 30 const std::vector<SkRect>* expected_damage) { 31 sksg::InvalidationController ic; 32 const auto bbox = root->revalidate(&ic, SkMatrix::I()); 33 34 if (0) { 35 SkDebugf("** bbox: [%f %f %f %f], ibbox: [%f %f %f %f]\n", 36 bbox.fLeft, bbox.fTop, bbox.fRight, bbox.fBottom, 37 ic.bounds().left(), ic.bounds().top(), ic.bounds().right(), ic.bounds().bottom()); 38 } 39 40 REPORTER_ASSERT(reporter, bbox == expected_bounds); 41 REPORTER_ASSERT(reporter, ic.bounds() == expected_inval_bounds); 42 43 if (expected_damage) { 44 const auto damage_count = SkTo<size_t>(ic.end() - ic.begin()); 45 REPORTER_ASSERT(reporter, expected_damage->size() == damage_count); 46 for (size_t i = 0; i < std::min(expected_damage->size(), damage_count); ++i) { 47 const auto r1 = (*expected_damage)[i], 48 r2 = ic.begin()[i]; 49 if (0) { 50 SkDebugf("*** expected inval: [%f %f %f %f], actual: [%f %f %f %f]\n", 51 r1.left(), r1.top(), r1.right(), r1.bottom(), 52 r2.left(), r2.top(), r2.right(), r2.bottom()); 53 } 54 REPORTER_ASSERT(reporter, r1 == r2); 55 } 56 } 57 } 58 59 struct HitTest { 60 const SkPoint pt; 61 sk_sp<sksg::RenderNode> node; 62 }; 63 64 static void check_hittest(skiatest::Reporter* reporter, const sk_sp<sksg::RenderNode>& root, 65 const std::vector<HitTest>& tests) { 66 for (const auto& tst : tests) { 67 const auto* node = root->nodeAt(tst.pt); 68 if (node != tst.node.get()) { 69 SkDebugf("*** nodeAt(%f, %f) - expected %p, got %p\n", 70 tst.pt.x(), tst.pt.y(), tst.node.get(), node); 71 } 72 REPORTER_ASSERT(reporter, tst.node.get() == node); 73 } 74 } 75 76 static void inval_test1(skiatest::Reporter* reporter) { 77 auto color = sksg::Color::Make(0xff000000); 78 auto r1 = sksg::Rect::Make(SkRect::MakeWH(100, 100)), 79 r2 = sksg::Rect::Make(SkRect::MakeWH(100, 100)); 80 auto grp = sksg::Group::Make(); 81 auto matrix = sksg::Matrix<SkMatrix>::Make(SkMatrix::I()); 82 auto root = sksg::TransformEffect::Make(grp, matrix); 83 auto d1 = sksg::Draw::Make(r1, color), 84 d2 = sksg::Draw::Make(r2, color); 85 86 grp->addChild(d1); 87 grp->addChild(d2); 88 89 { 90 // Initial revalidation. 91 check_inval(reporter, root, 92 SkRect::MakeWH(100, 100), 93 SkRectPriv::MakeLargeS32(), 94 nullptr); 95 96 check_hittest(reporter, root, { 97 {{ -1, 0 }, nullptr }, 98 {{ 0, -1 }, nullptr }, 99 {{ 100, 0 }, nullptr }, 100 {{ 0, 100 }, nullptr }, 101 {{ 0, 0 }, d2 }, 102 {{ 99, 99 }, d2 }, 103 }); 104 } 105 106 { 107 // Move r2 to (200 100). 108 r2->setL(200); r2->setT(100); r2->setR(300); r2->setB(200); 109 std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} }; 110 check_inval(reporter, root, 111 SkRect::MakeWH(300, 200), 112 SkRect::MakeWH(300, 200), 113 &damage); 114 115 check_hittest(reporter, root, { 116 {{ -1, 0 }, nullptr }, 117 {{ 0, -1 }, nullptr }, 118 {{ 100, 0 }, nullptr }, 119 {{ 0, 100 }, nullptr }, 120 {{ 0, 0 }, d1 }, 121 {{ 99, 99 }, d1 }, 122 123 {{ 199, 100 }, nullptr }, 124 {{ 200, 99 }, nullptr }, 125 {{ 300, 100 }, nullptr }, 126 {{ 200, 200 }, nullptr }, 127 {{ 200, 100 }, d2 }, 128 {{ 299, 199 }, d2 }, 129 }); 130 } 131 132 { 133 // Update the common color. 134 color->setColor(0xffff0000); 135 std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} }; 136 check_inval(reporter, root, 137 SkRect::MakeWH(300, 200), 138 SkRect::MakeWH(300, 200), 139 &damage); 140 } 141 142 { 143 // Shrink r1. 144 r1->setR(50); 145 std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 50, 100} }; 146 check_inval(reporter, root, 147 SkRect::MakeWH(300, 200), 148 SkRect::MakeWH(100, 100), 149 &damage); 150 151 check_hittest(reporter, root, { 152 {{ -1, 0 }, nullptr }, 153 {{ 0, -1 }, nullptr }, 154 {{ 50, 0 }, nullptr }, 155 {{ 0, 100 }, nullptr }, 156 {{ 0, 0 }, d1 }, 157 {{ 49, 99 }, d1 }, 158 159 {{ 199, 100 }, nullptr }, 160 {{ 200, 99 }, nullptr }, 161 {{ 300, 100 }, nullptr }, 162 {{ 200, 200 }, nullptr }, 163 {{ 200, 100 }, d2 }, 164 {{ 299, 199 }, d2 }, 165 }); 166 } 167 168 { 169 // Update transform. 170 matrix->setMatrix(SkMatrix::MakeScale(2, 2)); 171 std::vector<SkRect> damage = { {0, 0, 300, 200}, { 0, 0, 600, 400} }; 172 check_inval(reporter, root, 173 SkRect::MakeWH(600, 400), 174 SkRect::MakeWH(600, 400), 175 &damage); 176 177 check_hittest(reporter, root, { 178 {{ -1, 0 }, nullptr }, 179 {{ 0, -1 }, nullptr }, 180 {{ 25, 0 }, nullptr }, 181 {{ 0, 50 }, nullptr }, 182 {{ 0, 0 }, d1 }, 183 {{ 24, 49 }, d1 }, 184 185 {{ 99, 50 }, nullptr }, 186 {{ 100, 49 }, nullptr }, 187 {{ 150, 50 }, nullptr }, 188 {{ 100, 100 }, nullptr }, 189 {{ 100, 50 }, d2 }, 190 {{ 149, 99 }, d2 }, 191 }); 192 } 193 194 { 195 // Shrink r2 under transform. 196 r2->setR(250); 197 std::vector<SkRect> damage = { {400, 200, 600, 400}, { 400, 200, 500, 400} }; 198 check_inval(reporter, root, 199 SkRect::MakeWH(500, 400), 200 SkRect::MakeLTRB(400, 200, 600, 400), 201 &damage); 202 203 check_hittest(reporter, root, { 204 {{ -1, 0 }, nullptr }, 205 {{ 0, -1 }, nullptr }, 206 {{ 25, 0 }, nullptr }, 207 {{ 0, 50 }, nullptr }, 208 {{ 0, 0 }, d1 }, 209 {{ 24, 49 }, d1 }, 210 211 {{ 99, 50 }, nullptr }, 212 {{ 100, 49 }, nullptr }, 213 {{ 125, 50 }, nullptr }, 214 {{ 100, 100 }, nullptr }, 215 {{ 100, 50 }, d2 }, 216 {{ 124, 99 }, d2 }, 217 }); 218 } 219 } 220 221 static void inval_test2(skiatest::Reporter* reporter) { 222 auto color = sksg::Color::Make(0xff000000); 223 auto rect = sksg::Rect::Make(SkRect::MakeWH(100, 100)); 224 auto m1 = sksg::Matrix<SkMatrix>::Make(SkMatrix::I()), 225 m2 = sksg::Matrix<SkMatrix>::Make(SkMatrix::I()); 226 auto t1 = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color), 227 sksg::Transform::MakeConcat(m1, m2)), 228 t2 = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color), m1); 229 auto root = sksg::Group::Make(); 230 root->addChild(t1); 231 root->addChild(t2); 232 233 { 234 // Initial revalidation. 235 check_inval(reporter, root, 236 SkRect::MakeWH(100, 100), 237 SkRectPriv::MakeLargeS32(), 238 nullptr); 239 } 240 241 { 242 // Update the shared color. 243 color->setColor(0xffff0000); 244 std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 100, 100} }; 245 check_inval(reporter, root, 246 SkRect::MakeWH(100, 100), 247 SkRect::MakeWH(100, 100), 248 &damage); 249 } 250 251 { 252 // Update m2. 253 m2->setMatrix(SkMatrix::MakeScale(2, 2)); 254 std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 200, 200} }; 255 check_inval(reporter, root, 256 SkRect::MakeWH(200, 200), 257 SkRect::MakeWH(200, 200), 258 &damage); 259 } 260 261 { 262 // Update shared m1. 263 m1->setMatrix(SkMatrix::MakeTrans(100, 100)); 264 std::vector<SkRect> damage = { { 0, 0, 200, 200}, // draw1 prev bounds 265 { 100, 100, 300, 300}, // draw1 new bounds 266 { 0, 0, 100, 100}, // draw2 prev bounds 267 { 100, 100, 200, 200} }; // draw2 new bounds 268 check_inval(reporter, root, 269 SkRect::MakeLTRB(100, 100, 300, 300), 270 SkRect::MakeLTRB( 0, 0, 300, 300), 271 &damage); 272 } 273 274 { 275 // Update shared rect. 276 rect->setR(50); 277 std::vector<SkRect> damage = { { 100, 100, 300, 300}, // draw1 prev bounds 278 { 100, 100, 200, 300}, // draw1 new bounds 279 { 100, 100, 200, 200}, // draw2 prev bounds 280 { 100, 100, 150, 200} }; // draw2 new bounds 281 check_inval(reporter, root, 282 SkRect::MakeLTRB(100, 100, 200, 300), 283 SkRect::MakeLTRB(100, 100, 300, 300), 284 &damage); 285 } 286 } 287 288 static void inval_test3(skiatest::Reporter* reporter) { 289 auto color1 = sksg::Color::Make(0xff000000), 290 color2 = sksg::Color::Make(0xff000000); 291 auto group = sksg::Group::Make(); 292 293 group->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)), 294 color1)); 295 group->addChild(sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeXYWH(200, 0, 100, 100)), 296 color2)); 297 auto filter = sksg::DropShadowImageFilter::Make(); 298 filter->setOffset({50, 75}); 299 auto root = sksg::ImageFilterEffect::Make(group, filter); 300 301 { 302 // Initial revalidation. 303 check_inval(reporter, root, 304 SkRect::MakeXYWH(0, 0, 350, 175), 305 SkRectPriv::MakeLargeS32(), 306 nullptr); 307 } 308 309 { 310 // Shadow-only. 311 filter->setMode(sksg::DropShadowImageFilter::Mode::kShadowOnly); 312 std::vector<SkRect> damage = { {0, 0, 350, 175}, { 50, 75, 350, 175} }; 313 check_inval(reporter, root, 314 SkRect::MakeLTRB(50, 75, 350, 175), 315 SkRect::MakeLTRB(0, 0, 350, 175), 316 &damage); 317 } 318 319 { 320 // Content change -> single/full filter bounds inval. 321 color1->setColor(0xffff0000); 322 std::vector<SkRect> damage = { { 50, 75, 350, 175} }; 323 check_inval(reporter, root, 324 SkRect::MakeLTRB(50, 75, 350, 175), 325 SkRect::MakeLTRB(50, 75, 350, 175), 326 &damage); 327 } 328 329 } 330 331 static void inval_group_remove(skiatest::Reporter* reporter) { 332 auto draw = sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)), 333 sksg::Color::Make(SK_ColorBLACK)); 334 auto grp = sksg::Group::Make(); 335 336 // Readding the child should not trigger asserts. 337 grp->addChild(draw); 338 grp->removeChild(draw); 339 grp->addChild(draw); 340 } 341 342 DEF_TEST(SGInvalidation, reporter) { 343 inval_test1(reporter); 344 inval_test2(reporter); 345 inval_test3(reporter); 346 inval_group_remove(reporter); 347 } 348 349 #endif // !defined(SK_BUILD_FOR_GOOGLE3) 350