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 "include/core/SkTypes.h"
9
10 #if !defined(SK_BUILD_FOR_GOOGLE3)
11
12 #include "include/core/SkRect.h"
13 #include "include/private/SkTo.h"
14 #include "modules/sksg/include/SkSGDraw.h"
15 #include "modules/sksg/include/SkSGGroup.h"
16 #include "modules/sksg/include/SkSGInvalidationController.h"
17 #include "modules/sksg/include/SkSGPaint.h"
18 #include "modules/sksg/include/SkSGRect.h"
19 #include "modules/sksg/include/SkSGRenderEffect.h"
20 #include "modules/sksg/include/SkSGTransform.h"
21 #include "src/core/SkRectPriv.h"
22
23 #include "tests/Test.h"
24
25 #include <vector>
26
check_inval(skiatest::Reporter * reporter,const sk_sp<sksg::Node> & root,const SkRect & expected_bounds,const SkRect & expected_inval_bounds,const std::vector<SkRect> * expected_damage)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
check_hittest(skiatest::Reporter * reporter,const sk_sp<sksg::RenderNode> & root,const std::vector<HitTest> & tests)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
inval_test1(skiatest::Reporter * reporter)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::Scale(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
inval_test2(skiatest::Reporter * reporter)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::Scale(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::Translate(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
inval_test3(skiatest::Reporter * reporter)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 // Visibility change -> full inval.
331 group->setVisible(false);
332 std::vector<SkRect> damage = { { 50, 75, 350, 175} };
333 check_inval(reporter, root,
334 SkRect::MakeLTRB(50, 75, 350, 175),
335 SkRect::MakeLTRB(50, 75, 350, 175),
336 &damage);
337 }
338 }
339
inval_group_remove(skiatest::Reporter * reporter)340 static void inval_group_remove(skiatest::Reporter* reporter) {
341 auto draw = sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)),
342 sksg::Color::Make(SK_ColorBLACK));
343 auto grp = sksg::Group::Make();
344
345 // Readding the child should not trigger asserts.
346 grp->addChild(draw);
347 grp->removeChild(draw);
348 grp->addChild(draw);
349 }
350
DEF_TEST(SGInvalidation,reporter)351 DEF_TEST(SGInvalidation, reporter) {
352 inval_test1(reporter);
353 inval_test2(reporter);
354 inval_test3(reporter);
355 inval_group_remove(reporter);
356 }
357
358 #endif // !defined(SK_BUILD_FOR_GOOGLE3)
359