Flutter Engine
The Flutter Engine
dl_region_unittests.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/display_list/geometry/dl_region.h"
6#include "gtest/gtest.h"
7
9
10#include <random>
11
12namespace flutter {
13namespace testing {
14
15TEST(DisplayListRegion, EmptyRegion) {
18 EXPECT_TRUE(region.getRects().empty());
19}
20
21TEST(DisplayListRegion, SingleRectangle) {
22 DlRegion region({SkIRect::MakeLTRB(10, 10, 50, 50)});
23 auto rects = region.getRects();
24 ASSERT_EQ(rects.size(), 1u);
25 EXPECT_EQ(rects.front(), SkIRect::MakeLTRB(10, 10, 50, 50));
26}
27
28TEST(DisplayListRegion, NonOverlappingRectangles1) {
29 std::vector<SkIRect> rects_in;
30 for (int i = 0; i < 10; ++i) {
31 SkIRect rect = SkIRect::MakeXYWH(50 * i, 50 * i, 50, 50);
32 rects_in.push_back(rect);
33 }
34 DlRegion region(rects_in);
35 auto rects = region.getRects();
36 std::vector<SkIRect> expected{
37 {0, 0, 50, 50}, {50, 50, 100, 100}, {100, 100, 150, 150},
38 {150, 150, 200, 200}, {200, 200, 250, 250}, {250, 250, 300, 300},
39 {300, 300, 350, 350}, {350, 350, 400, 400}, {400, 400, 450, 450},
40 {450, 450, 500, 500},
41 };
42 EXPECT_EQ(rects, expected);
43}
44
45TEST(DisplayListRegion, NonOverlappingRectangles2) {
47 SkIRect::MakeXYWH(5, 5, 10, 10),
48 SkIRect::MakeXYWH(25, 5, 10, 10),
49 SkIRect::MakeXYWH(5, 25, 10, 10),
50 SkIRect::MakeXYWH(25, 25, 10, 10),
51 });
52 auto rects = region.getRects();
53 std::vector<SkIRect> expected{
54 SkIRect::MakeXYWH(5, 5, 10, 10),
55 SkIRect::MakeXYWH(25, 5, 10, 10),
56 SkIRect::MakeXYWH(5, 25, 10, 10),
57 SkIRect::MakeXYWH(25, 25, 10, 10),
58 };
59 EXPECT_EQ(rects, expected);
60}
61
62TEST(DisplayListRegion, NonOverlappingRectangles3) {
64 SkIRect::MakeXYWH(0, 0, 10, 10),
65 SkIRect::MakeXYWH(-11, -11, 10, 10),
66 SkIRect::MakeXYWH(11, 11, 10, 10),
67 SkIRect::MakeXYWH(-11, 0, 10, 10),
68 SkIRect::MakeXYWH(0, 11, 10, 10),
69 SkIRect::MakeXYWH(0, -11, 10, 10),
70 SkIRect::MakeXYWH(11, 0, 10, 10),
71 SkIRect::MakeXYWH(11, -11, 10, 10),
72 SkIRect::MakeXYWH(-11, 11, 10, 10),
73 });
74 auto rects = region.getRects();
75 std::vector<SkIRect> expected{
76 SkIRect::MakeXYWH(-11, -11, 10, 10), //
77 SkIRect::MakeXYWH(0, -11, 10, 10), //
78 SkIRect::MakeXYWH(11, -11, 10, 10), //
79 SkIRect::MakeXYWH(-11, 0, 10, 10), //
80 SkIRect::MakeXYWH(0, 0, 10, 10), //
81 SkIRect::MakeXYWH(11, 0, 10, 10), //
82 SkIRect::MakeXYWH(-11, 11, 10, 10), //
83 SkIRect::MakeXYWH(0, 11, 10, 10), //
84 SkIRect::MakeXYWH(11, 11, 10, 10),
85 };
86 EXPECT_EQ(rects, expected);
87}
88
89TEST(DisplayListRegion, MergeTouchingRectangles) {
91 SkIRect::MakeXYWH(0, 0, 10, 10),
92 SkIRect::MakeXYWH(-10, -10, 10, 10),
93 SkIRect::MakeXYWH(10, 10, 10, 10),
94 SkIRect::MakeXYWH(-10, 0, 10, 10),
95 SkIRect::MakeXYWH(0, 10, 10, 10),
96 SkIRect::MakeXYWH(0, -10, 10, 10),
97 SkIRect::MakeXYWH(10, 0, 10, 10),
98 SkIRect::MakeXYWH(10, -10, 10, 10),
99 SkIRect::MakeXYWH(-10, 10, 10, 10),
100 });
101
102 auto rects = region.getRects();
103 std::vector<SkIRect> expected{
104 SkIRect::MakeXYWH(-10, -10, 30, 30),
105 };
106 EXPECT_EQ(rects, expected);
107}
108
109TEST(DisplayListRegion, OverlappingRectangles) {
110 std::vector<SkIRect> rects_in;
111 for (int i = 0; i < 10; ++i) {
112 SkIRect rect = SkIRect::MakeXYWH(10 * i, 10 * i, 50, 50);
113 rects_in.push_back(rect);
114 }
115 DlRegion region(rects_in);
116 auto rects = region.getRects();
117 std::vector<SkIRect> expected{
118 {0, 0, 50, 10}, {0, 10, 60, 20}, {0, 20, 70, 30},
119 {0, 30, 80, 40}, {0, 40, 90, 50}, {10, 50, 100, 60},
120 {20, 60, 110, 70}, {30, 70, 120, 80}, {40, 80, 130, 90},
121 {50, 90, 140, 100}, {60, 100, 140, 110}, {70, 110, 140, 120},
122 {80, 120, 140, 130}, {90, 130, 140, 140},
123 };
124
125 EXPECT_EQ(rects, expected);
126}
127
128TEST(DisplayListRegion, Deband) {
130 SkIRect::MakeXYWH(0, 0, 50, 50),
131 SkIRect::MakeXYWH(60, 0, 20, 20),
132 SkIRect::MakeXYWH(90, 0, 50, 50),
133 });
134
135 auto rects_with_deband = region.getRects(true);
136 std::vector<SkIRect> expected{
137 SkIRect::MakeXYWH(60, 0, 20, 20),
138 SkIRect::MakeXYWH(0, 0, 50, 50),
139 SkIRect::MakeXYWH(90, 0, 50, 50),
140 };
141 EXPECT_EQ(rects_with_deband, expected);
142
143 auto rects_without_deband = region.getRects(false);
144 std::vector<SkIRect> expected_without_deband{
145 SkIRect::MakeXYWH(0, 0, 50, 20), //
146 SkIRect::MakeXYWH(60, 0, 20, 20), //
147 SkIRect::MakeXYWH(90, 0, 50, 20), //
148 SkIRect::MakeXYWH(0, 20, 50, 30), //
149 SkIRect::MakeXYWH(90, 20, 50, 30),
150 };
151 EXPECT_EQ(rects_without_deband, expected_without_deband);
152}
153
154TEST(DisplayListRegion, Intersects1) {
155 DlRegion region1({
156 SkIRect::MakeXYWH(0, 0, 20, 20),
157 SkIRect::MakeXYWH(20, 20, 20, 20),
158 });
159 DlRegion region2({
160 SkIRect::MakeXYWH(20, 0, 20, 20),
161 SkIRect::MakeXYWH(0, 20, 20, 20),
162 });
163 EXPECT_FALSE(region1.intersects(region2));
164 EXPECT_FALSE(region2.intersects(region1));
165
166 EXPECT_TRUE(region1.intersects(region2.bounds()));
167 EXPECT_TRUE(region2.intersects(region1.bounds()));
168
169 EXPECT_TRUE(region1.intersects(SkIRect::MakeXYWH(0, 0, 20, 20)));
170 EXPECT_FALSE(region1.intersects(SkIRect::MakeXYWH(20, 0, 20, 20)));
171
172 EXPECT_TRUE(region1.intersects(
173 DlRegion(std::vector<SkIRect>{SkIRect::MakeXYWH(0, 0, 20, 20)})));
174 EXPECT_FALSE(region1.intersects(
175 DlRegion(std::vector<SkIRect>{SkIRect::MakeXYWH(20, 0, 20, 20)})));
176
177 EXPECT_FALSE(region1.intersects(SkIRect::MakeXYWH(-1, -1, 1, 1)));
178 EXPECT_TRUE(region1.intersects(SkIRect::MakeXYWH(0, 0, 1, 1)));
179
180 EXPECT_FALSE(region1.intersects(SkIRect::MakeXYWH(40, 40, 1, 1)));
181 EXPECT_TRUE(region1.intersects(SkIRect::MakeXYWH(39, 39, 1, 1)));
182}
183
184TEST(DisplayListRegion, Intersects2) {
185 DlRegion region1({
186 SkIRect::MakeXYWH(-10, -10, 20, 20),
187 SkIRect::MakeXYWH(-30, -30, 20, 20),
188 });
189 DlRegion region2({
190 SkIRect::MakeXYWH(20, 20, 5, 5),
191 SkIRect::MakeXYWH(0, 0, 20, 20),
192 });
193 EXPECT_TRUE(region1.intersects(region2));
194 EXPECT_TRUE(region2.intersects(region1));
195}
196
197TEST(DisplayListRegion, Intersection1) {
198 DlRegion region1({
199 SkIRect::MakeXYWH(0, 0, 20, 20),
200 SkIRect::MakeXYWH(20, 20, 20, 20),
201 });
202 DlRegion region2({
203 SkIRect::MakeXYWH(20, 0, 20, 20),
204 SkIRect::MakeXYWH(0, 20, 20, 20),
205 });
206 DlRegion i = DlRegion::MakeIntersection(region1, region2);
207 EXPECT_EQ(i.bounds(), SkIRect::MakeEmpty());
208 EXPECT_TRUE(i.isEmpty());
209 auto rects = i.getRects();
210 EXPECT_TRUE(rects.empty());
211}
212
213TEST(DisplayListRegion, Intersection2) {
214 DlRegion region1({
215 SkIRect::MakeXYWH(0, 0, 20, 20),
216 SkIRect::MakeXYWH(20, 20, 20, 20),
217 });
218 DlRegion region2({
219 SkIRect::MakeXYWH(0, 0, 20, 20),
220 SkIRect::MakeXYWH(20, 20, 20, 20),
221 });
222 DlRegion i = DlRegion::MakeIntersection(region1, region2);
223 EXPECT_EQ(i.bounds(), SkIRect::MakeXYWH(0, 0, 40, 40));
224 auto rects = i.getRects();
225 std::vector<SkIRect> expected{
226 SkIRect::MakeXYWH(0, 0, 20, 20),
227 SkIRect::MakeXYWH(20, 20, 20, 20),
228 };
229 EXPECT_EQ(rects, expected);
230}
231
232TEST(DisplayListRegion, Intersection3) {
233 DlRegion region1({
234 SkIRect::MakeXYWH(0, 0, 20, 20),
235 });
236 DlRegion region2({
237 SkIRect::MakeXYWH(-10, -10, 20, 20),
238 SkIRect::MakeXYWH(10, 10, 20, 20),
239 });
240 DlRegion i = DlRegion::MakeIntersection(region1, region2);
241 EXPECT_EQ(i.bounds(), SkIRect::MakeXYWH(0, 0, 20, 20));
242 auto rects = i.getRects();
243 std::vector<SkIRect> expected{
244 SkIRect::MakeXYWH(0, 0, 10, 10),
245 SkIRect::MakeXYWH(10, 10, 10, 10),
246 };
247 EXPECT_EQ(rects, expected);
248}
249
250TEST(DisplayListRegion, Union1) {
251 DlRegion region1({
252 SkIRect::MakeXYWH(0, 0, 20, 20),
253 SkIRect::MakeXYWH(20, 20, 20, 20),
254 });
255 DlRegion region2({
256 SkIRect::MakeXYWH(20, 0, 20, 20),
257 SkIRect::MakeXYWH(0, 20, 20, 20),
258 });
259 DlRegion u = DlRegion::MakeUnion(region1, region2);
260 EXPECT_EQ(u.bounds(), SkIRect::MakeXYWH(0, 0, 40, 40));
261 EXPECT_TRUE(u.isSimple());
262 auto rects = u.getRects();
263 std::vector<SkIRect> expected{
264 SkIRect::MakeXYWH(0, 0, 40, 40), //
265 };
266 EXPECT_EQ(rects, expected);
267}
268
269TEST(DisplayListRegion, Union2) {
270 DlRegion region1({
271 SkIRect::MakeXYWH(0, 0, 20, 20),
272 SkIRect::MakeXYWH(21, 21, 20, 20),
273 });
274 DlRegion region2({
275 SkIRect::MakeXYWH(21, 0, 20, 20),
276 SkIRect::MakeXYWH(0, 21, 20, 20),
277 });
278 DlRegion u = DlRegion::MakeUnion(region1, region2);
279 EXPECT_EQ(u.bounds(), SkIRect::MakeXYWH(0, 0, 41, 41));
280 auto rects = u.getRects();
281 std::vector<SkIRect> expected{
282 SkIRect::MakeXYWH(0, 0, 20, 20),
283 SkIRect::MakeXYWH(21, 0, 20, 20),
284 SkIRect::MakeXYWH(0, 21, 20, 20),
285 SkIRect::MakeXYWH(21, 21, 20, 20),
286 };
287 EXPECT_EQ(rects, expected);
288}
289
290TEST(DisplayListRegion, Union3) {
291 DlRegion region1({
292 SkIRect::MakeXYWH(-10, -10, 20, 20),
293 });
294 DlRegion region2({
295 SkIRect::MakeXYWH(0, 0, 20, 20),
296 });
297 DlRegion u = DlRegion::MakeUnion(region1, region2);
298 EXPECT_EQ(u.bounds(), SkIRect::MakeXYWH(-10, -10, 30, 30));
299 auto rects = u.getRects();
300 std::vector<SkIRect> expected{
301 SkIRect::MakeXYWH(-10, -10, 20, 10),
302 SkIRect::MakeXYWH(-10, 0, 30, 10),
303 SkIRect::MakeXYWH(0, 10, 20, 10),
304 };
305 EXPECT_EQ(rects, expected);
306}
307
308TEST(DisplayListRegion, UnionEmpty) {
309 {
310 DlRegion region1(std::vector<SkIRect>{});
311 DlRegion region2(std::vector<SkIRect>{});
312 DlRegion u = DlRegion::MakeUnion(region1, region2);
313 EXPECT_EQ(u.bounds(), SkIRect::MakeEmpty());
314 EXPECT_TRUE(u.isEmpty());
315 auto rects = u.getRects();
316 EXPECT_TRUE(rects.empty());
317 }
318 {
319 DlRegion region1(std::vector<SkIRect>{});
320 DlRegion region2({
321 SkIRect::MakeXYWH(0, 0, 20, 20),
322 });
323 DlRegion u = DlRegion::MakeUnion(region1, region2);
324 EXPECT_EQ(u.bounds(), SkIRect::MakeXYWH(0, 0, 20, 20));
325 auto rects = u.getRects();
326 std::vector<SkIRect> expected{
327 SkIRect::MakeXYWH(0, 0, 20, 20),
328 };
329 }
330 {
331 DlRegion region1({
332 SkIRect::MakeXYWH(0, 0, 20, 20),
333 });
334 DlRegion region2(std::vector<SkIRect>{});
335 DlRegion u = DlRegion::MakeUnion(region1, region2);
336 EXPECT_EQ(u.bounds(), SkIRect::MakeXYWH(0, 0, 20, 20));
337 auto rects = u.getRects();
338 std::vector<SkIRect> expected{
339 SkIRect::MakeXYWH(0, 0, 20, 20),
340 };
341 }
342}
343
344void CheckEquality(const DlRegion& dl_region, const SkRegion& sk_region) {
345 EXPECT_EQ(dl_region.bounds(), sk_region.getBounds());
346
347 // Do not deband the rectangles - identical to SkRegion::Iterator
348 auto rects = dl_region.getRects(false);
349
350 std::vector<SkIRect> skia_rects;
351
352 auto iterator = SkRegion::Iterator(sk_region);
353 while (!iterator.done()) {
354 skia_rects.push_back(iterator.rect());
355 iterator.next();
356 }
357
358 EXPECT_EQ(rects, skia_rects);
359}
360
361TEST(DisplayListRegion, TestAgainstSkRegion) {
362 struct Settings {
363 int max_size;
364 };
365 std::vector<Settings> all_settings{{100}, {400}, {800}};
366
367 std::vector<size_t> iterations{1, 10, 100, 1000};
368
369 for (const auto& settings : all_settings) {
370 for (const auto iterations_1 : iterations) {
371 for (const auto iterations_2 : iterations) {
372 std::random_device d;
373 std::seed_seq seed{::testing::UnitTest::GetInstance()->random_seed()};
374 std::mt19937 rng(seed);
375
376 SkRegion sk_region1;
377 SkRegion sk_region2;
378
379 std::uniform_int_distribution pos(0, 4000);
380 std::uniform_int_distribution size(1, settings.max_size);
381
382 std::vector<SkIRect> rects_in1;
383 std::vector<SkIRect> rects_in2;
384
385 for (size_t i = 0; i < iterations_1; ++i) {
386 SkIRect rect =
387 SkIRect::MakeXYWH(pos(rng), pos(rng), size(rng), size(rng));
388 rects_in1.push_back(rect);
389 }
390
391 for (size_t i = 0; i < iterations_2; ++i) {
392 SkIRect rect =
393 SkIRect::MakeXYWH(pos(rng), pos(rng), size(rng), size(rng));
394 rects_in2.push_back(rect);
395 }
396
397 DlRegion region1(rects_in1);
398 sk_region1.setRects(rects_in1.data(), rects_in1.size());
399 CheckEquality(region1, sk_region1);
400
401 DlRegion region2(rects_in2);
402 sk_region2.setRects(rects_in2.data(), rects_in2.size());
403 CheckEquality(region2, sk_region2);
404
405 auto intersects_1 = region1.intersects(region2);
406 auto intersects_2 = region2.intersects(region1);
407 auto sk_intesects = sk_region1.intersects(sk_region2);
408 EXPECT_EQ(intersects_1, intersects_2);
409 EXPECT_EQ(intersects_1, sk_intesects);
410
411 {
412 auto rects = region2.getRects(true);
413 for (const auto& r : rects) {
414 EXPECT_EQ(region1.intersects(r), sk_region1.intersects(r));
415 }
416 }
417
418 DlRegion dl_union = DlRegion::MakeUnion(region1, region2);
419 SkRegion sk_union(sk_region1);
420 sk_union.op(sk_region2, SkRegion::kUnion_Op);
421 CheckEquality(dl_union, sk_union);
422
423 DlRegion dl_intersection = DlRegion::MakeIntersection(region1, region2);
424 SkRegion sk_intersection(sk_region1);
425 sk_intersection.op(sk_region2, SkRegion::kIntersect_Op);
426 CheckEquality(dl_intersection, sk_intersection);
427 }
428 }
429 }
430}
431
432} // namespace testing
433} // namespace flutter
SkPoint pos
@ kUnion_Op
target unioned with operand
Definition: SkRegion.h:369
@ kIntersect_Op
target intersected with operand
Definition: SkRegion.h:368
bool setRects(const SkIRect rects[], int count)
Definition: SkRegion.cpp:657
const SkIRect & getBounds() const
Definition: SkRegion.h:165
bool op(const SkIRect &rect, Op op)
Definition: SkRegion.h:384
bool isEmpty() const
Definition: SkRegion.h:146
friend class Iterator
Definition: SkRegion.h:677
bool intersects(const SkIRect &rect) const
Definition: SkRegion.cpp:502
static DlRegion MakeIntersection(const DlRegion &a, const DlRegion &b)
Definition: dl_region.cc:497
const SkIRect & bounds() const
Definition: dl_region.h:53
std::vector< SkIRect > getRects(bool deband=true) const
Definition: dl_region.cc:563
bool intersects(const SkIRect &rect) const
Returns whether this region intersects with a rectangle.
Definition: dl_region.cc:617
static DlRegion MakeUnion(const DlRegion &a, const DlRegion &b)
Definition: dl_region.cc:405
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
ClipOpAndAA opAA SkRegion region
Definition: SkRecords.h:238
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
void CheckEquality(const DlRegion &dl_region, const SkRegion &sk_region)
TEST(DisplayListComplexity, EmptyDisplayList)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: SkRect.h:32
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
static constexpr SkIRect MakeEmpty()
Definition: SkRect.h:45
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition: SkRect.h:104
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678