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 "SkSGTransform.h"
20 #include "SkTo.h"
21 
22 #include "Test.h"
23 
24 #include <vector>
25 
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)26 static void check_inval(skiatest::Reporter* reporter, const sk_sp<sksg::Node>& root,
27                         const SkRect& expected_bounds,
28                         const SkRect& expected_inval_bounds,
29                         const std::vector<SkRect>* expected_damage) {
30     sksg::InvalidationController ic;
31     const auto bbox = root->revalidate(&ic, SkMatrix::I());
32 
33     if (0) {
34         SkDebugf("** bbox: [%f %f %f %f], ibbox: [%f %f %f %f]\n",
35                  bbox.fLeft, bbox.fTop, bbox.fRight, bbox.fBottom,
36                  ic.bounds().left(), ic.bounds().top(), ic.bounds().right(), ic.bounds().bottom());
37     }
38 
39     REPORTER_ASSERT(reporter, bbox == expected_bounds);
40     REPORTER_ASSERT(reporter, ic.bounds() == expected_inval_bounds);
41 
42     if (expected_damage) {
43         const auto damage_count = SkTo<size_t>(ic.end() - ic.begin());
44         REPORTER_ASSERT(reporter, expected_damage->size() == damage_count);
45         for (size_t i = 0; i < std::min(expected_damage->size(), damage_count); ++i) {
46             const auto r1 = (*expected_damage)[i],
47                        r2 = ic.begin()[i];
48             if (0) {
49                 SkDebugf("*** expected inval: [%f %f %f %f], actual: [%f %f %f %f]\n",
50                          r1.left(), r1.top(), r1.right(), r1.bottom(),
51                          r2.left(), r2.top(), r2.right(), r2.bottom());
52             }
53             REPORTER_ASSERT(reporter, r1 == r2);
54         }
55     }
56 }
57 
inval_test1(skiatest::Reporter * reporter)58 static void inval_test1(skiatest::Reporter* reporter) {
59     auto color  = sksg::Color::Make(0xff000000);
60     auto r1     = sksg::Rect::Make(SkRect::MakeWH(100, 100)),
61          r2     = sksg::Rect::Make(SkRect::MakeWH(100, 100));
62     auto grp    = sksg::Group::Make();
63     auto matrix = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
64     auto root   = sksg::TransformEffect::Make(grp, matrix);
65 
66     grp->addChild(sksg::Draw::Make(r1, color));
67     grp->addChild(sksg::Draw::Make(r2, color));
68 
69     {
70         // Initial revalidation.
71         check_inval(reporter, root,
72                     SkRect::MakeWH(100, 100),
73                     SkRectPriv::MakeLargeS32(),
74                     nullptr);
75     }
76 
77     {
78         // Move r2 to (200 100).
79         r2->setL(200); r2->setT(100); r2->setR(300); r2->setB(200);
80         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} };
81         check_inval(reporter, root,
82                     SkRect::MakeWH(300, 200),
83                     SkRect::MakeWH(300, 200),
84                     &damage);
85     }
86 
87     {
88         // Update the common color.
89         color->setColor(0xffff0000);
90         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 200, 100, 300, 200} };
91         check_inval(reporter, root,
92                     SkRect::MakeWH(300, 200),
93                     SkRect::MakeWH(300, 200),
94                     &damage);
95     }
96 
97     {
98         // Shrink r1.
99         r1->setR(50);
100         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 50, 100} };
101         check_inval(reporter, root,
102                     SkRect::MakeWH(300, 200),
103                     SkRect::MakeWH(100, 100),
104                     &damage);
105     }
106 
107     {
108         // Update transform.
109         matrix->setMatrix(SkMatrix::MakeScale(2, 2));
110         std::vector<SkRect> damage = { {0, 0, 300, 200}, { 0, 0, 600, 400} };
111         check_inval(reporter, root,
112                     SkRect::MakeWH(600, 400),
113                     SkRect::MakeWH(600, 400),
114                     &damage);
115     }
116 
117     {
118         // Shrink r2 under transform.
119         r2->setR(250);
120         std::vector<SkRect> damage = { {400, 200, 600, 400}, { 400, 200, 500, 400} };
121         check_inval(reporter, root,
122                     SkRect::MakeWH(500, 400),
123                     SkRect::MakeLTRB(400, 200, 600, 400),
124                     &damage);
125     }
126 }
127 
inval_test2(skiatest::Reporter * reporter)128 static void inval_test2(skiatest::Reporter* reporter) {
129     auto color = sksg::Color::Make(0xff000000);
130     auto rect  = sksg::Rect::Make(SkRect::MakeWH(100, 100));
131     auto m1    = sksg::Matrix<SkMatrix>::Make(SkMatrix::I()),
132          m2    = sksg::Matrix<SkMatrix>::Make(SkMatrix::I());
133     auto t1    = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color),
134                                              sksg::Transform::MakeConcat(m1, m2)),
135          t2    = sksg::TransformEffect::Make(sksg::Draw::Make(rect, color), m1);
136     auto root  = sksg::Group::Make();
137     root->addChild(t1);
138     root->addChild(t2);
139 
140     {
141         // Initial revalidation.
142         check_inval(reporter, root,
143                     SkRect::MakeWH(100, 100),
144                     SkRectPriv::MakeLargeS32(),
145                     nullptr);
146     }
147 
148     {
149         // Update the shared color.
150         color->setColor(0xffff0000);
151         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 100, 100} };
152         check_inval(reporter, root,
153                     SkRect::MakeWH(100, 100),
154                     SkRect::MakeWH(100, 100),
155                     &damage);
156     }
157 
158     {
159         // Update m2.
160         m2->setMatrix(SkMatrix::MakeScale(2, 2));
161         std::vector<SkRect> damage = { {0, 0, 100, 100}, { 0, 0, 200, 200} };
162         check_inval(reporter, root,
163                     SkRect::MakeWH(200, 200),
164                     SkRect::MakeWH(200, 200),
165                     &damage);
166     }
167 
168     {
169         // Update shared m1.
170         m1->setMatrix(SkMatrix::MakeTrans(100, 100));
171         std::vector<SkRect> damage = { {   0,   0, 200, 200},   // draw1 prev bounds
172                                        { 100, 100, 300, 300},   // draw1 new bounds
173                                        {   0,   0, 100, 100},   // draw2 prev bounds
174                                        { 100, 100, 200, 200} }; // draw2 new bounds
175         check_inval(reporter, root,
176                     SkRect::MakeLTRB(100, 100, 300, 300),
177                     SkRect::MakeLTRB(  0,   0, 300, 300),
178                     &damage);
179     }
180 
181     {
182         // Update shared rect.
183         rect->setR(50);
184         std::vector<SkRect> damage = { { 100, 100, 300, 300},   // draw1 prev bounds
185                                        { 100, 100, 200, 300},   // draw1 new bounds
186                                        { 100, 100, 200, 200},   // draw2 prev bounds
187                                        { 100, 100, 150, 200} }; // draw2 new bounds
188         check_inval(reporter, root,
189                     SkRect::MakeLTRB(100, 100, 200, 300),
190                     SkRect::MakeLTRB(100, 100, 300, 300),
191                     &damage);
192     }
193 }
194 
inval_group_remove(skiatest::Reporter * reporter)195 static void inval_group_remove(skiatest::Reporter* reporter) {
196     auto draw = sksg::Draw::Make(sksg::Rect::Make(SkRect::MakeWH(100, 100)),
197                                  sksg::Color::Make(SK_ColorBLACK));
198     auto grp = sksg::Group::Make();
199 
200     // Readding the child should not trigger asserts.
201     grp->addChild(draw);
202     grp->removeChild(draw);
203     grp->addChild(draw);
204 }
205 
DEF_TEST(SGInvalidation,reporter)206 DEF_TEST(SGInvalidation, reporter) {
207     inval_test1(reporter);
208     inval_test2(reporter);
209     inval_group_remove(reporter);
210 }
211 
212 #endif // !defined(SK_BUILD_FOR_GOOGLE3)
213