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