Flutter Engine
 
Loading...
Searching...
No Matches
dl_rtree_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
6#include "gtest/gtest.h"
7
8namespace flutter {
9namespace testing {
10
11#ifndef NDEBUG
12TEST(DisplayListRTree, NullRectListNonZeroCount) {
13 EXPECT_DEATH_IF_SUPPORTED(new DlRTree(nullptr, 1), "rects != nullptr");
14}
15
16TEST(DisplayListRTree, NegativeCount) {
17 EXPECT_DEATH_IF_SUPPORTED(new DlRTree(nullptr, -1), "N >= 0");
18}
19
20TEST(DisplayListRTree, NullSearchResultVector) {
21 DlRTree tree(nullptr, 0);
22 EXPECT_DEATH_IF_SUPPORTED(tree.search(DlRect::MakeLTRB(0, 0, 1, 1), nullptr),
23 "results != nullptr");
24}
25#endif
26
27TEST(DisplayListRTree, NullRectListZeroCount) {
28 DlRTree tree(nullptr, 0);
29 EXPECT_EQ(tree.leaf_count(), 0);
30 EXPECT_EQ(tree.node_count(), 0);
31 std::vector<int> results;
32 auto huge = DlRect::MakeLTRB(-1e6, -1e6, 1e6, 1e6);
33 tree.search(huge, &results);
34 EXPECT_EQ(results.size(), 0u);
35 auto list = tree.searchAndConsolidateRects(huge);
36 EXPECT_EQ(list.size(), 0u);
37}
38
39TEST(DisplayListRTree, ManySizes) {
40 // A diagonal of non-overlapping 10x10 rectangles spaced 20
41 // pixels apart.
42 // Rect 1 goes from 0 to 10
43 // Rect 2 goes from 20 to 30
44 // etc. in both dimensions
45 const int kMaxN = 250;
46 DlRect rects[kMaxN + 1];
47 int ids[kMaxN + 1];
48 for (int i = 0; i <= kMaxN; i++) {
49 rects[i] = DlRect::MakeXYWH(i * 20, i * 20, 10, 10);
50 ids[i] = i + 42;
51 }
52 std::vector<int> results;
53 for (int N = 0; N <= kMaxN; N++) {
54 DlRTree tree(rects, N, ids);
55 auto desc = "node count = " + std::to_string(N);
56 EXPECT_EQ(tree.leaf_count(), N) << desc;
57 EXPECT_GE(tree.node_count(), N) << desc;
58 EXPECT_EQ(tree.id(-1), -1) << desc;
59 EXPECT_EQ(tree.bounds(-1), DlRect()) << desc;
60 EXPECT_EQ(tree.id(N), -1) << desc;
61 EXPECT_EQ(tree.bounds(N), DlRect()) << desc;
62 results.clear();
63 tree.search(DlRect(), &results);
64 EXPECT_EQ(results.size(), 0u) << desc;
65 results.clear();
66 tree.search(DlRect::MakeLTRB(2, 2, 8, 8), &results);
67 if (N == 0) {
68 EXPECT_EQ(results.size(), 0u) << desc;
69 } else {
70 EXPECT_EQ(results.size(), 1u) << desc;
71 EXPECT_EQ(results[0], 0) << desc;
72 EXPECT_EQ(tree.id(results[0]), ids[0]) << desc;
73 EXPECT_EQ(tree.bounds(results[0]), rects[0]) << desc;
74 for (int i = 1; i < N; i++) {
75 results.clear();
76 auto query = DlRect::MakeXYWH(i * 20 + 2, i * 20 + 2, 6, 6);
77 tree.search(query, &results);
78 EXPECT_EQ(results.size(), 1u) << desc;
79 EXPECT_EQ(results[0], i) << desc;
80 EXPECT_EQ(tree.id(results[0]), ids[i]) << desc;
81 EXPECT_EQ(tree.bounds(results[0]), rects[i]) << desc;
82 auto list = tree.searchAndConsolidateRects(query);
83 EXPECT_EQ(list.size(), 1u);
84 EXPECT_EQ(list.front(), rects[i]);
85 }
86 }
87 }
88}
89
90TEST(DisplayListRTree, HugeSize) {
91 // A diagonal of non-overlapping 10x10 rectangles spaced 20
92 // pixels apart.
93 // Rect 1 goes from 0 to 10
94 // Rect 2 goes from 20 to 30
95 // etc. in both dimensions
96 const int N = 10000;
97 DlRect rects[N];
98 int ids[N];
99 for (int i = 0; i < N; i++) {
100 rects[i] = DlRect::MakeXYWH(i * 20, i * 20, 10, 10);
101 ids[i] = i + 42;
102 }
103 DlRTree tree(rects, N, ids);
104 EXPECT_EQ(tree.leaf_count(), N);
105 EXPECT_GE(tree.node_count(), N);
106 EXPECT_EQ(tree.id(-1), -1);
107 EXPECT_EQ(tree.bounds(-1), DlRect());
108 EXPECT_EQ(tree.id(N), -1);
109 EXPECT_EQ(tree.bounds(N), DlRect());
110 std::vector<int> results;
111 tree.search(DlRect(), &results);
112 EXPECT_EQ(results.size(), 0u);
113 for (int i = 0; i < N; i++) {
114 results.clear();
115 tree.search(DlRect::MakeXYWH(i * 20 + 2, i * 20 + 2, 6, 6), &results);
116 EXPECT_EQ(results.size(), 1u);
117 EXPECT_EQ(results[0], i);
118 EXPECT_EQ(tree.id(results[0]), ids[i]);
119 EXPECT_EQ(tree.bounds(results[0]), rects[i]);
120 }
121}
122
123TEST(DisplayListRTree, Grid) {
124 // Non-overlapping 10 x 10 rectangles starting at 5, 5 with
125 // 10 pixels between them.
126 // Rect 1 goes from 5 to 15
127 // Rect 2 goes from 25 to 35
128 // etc. in both dimensions
129 const int ROWS = 10;
130 const int COLS = 10;
131 const int N = ROWS * COLS;
132 DlRect rects[N];
133 int ids[N];
134 for (int r = 0; r < ROWS; r++) {
135 int y = r * 20 + 5;
136 for (int c = 0; c < COLS; c++) {
137 int x = c * 20 + 5;
138 int i = r * COLS + c;
139 rects[i] = DlRect::MakeXYWH(x, y, 10, 10);
140 ids[i] = i + 42;
141 }
142 }
143 DlRTree tree(rects, N, ids);
144 EXPECT_EQ(tree.leaf_count(), N);
145 EXPECT_GE(tree.node_count(), N);
146 EXPECT_EQ(tree.id(-1), -1);
147 EXPECT_EQ(tree.bounds(-1), DlRect());
148 EXPECT_EQ(tree.id(N), -1);
149 EXPECT_EQ(tree.bounds(N), DlRect());
150 std::vector<int> results;
151 tree.search(DlRect(), &results);
152 EXPECT_EQ(results.size(), 0u);
153 // Testing eqch rect for a single hit
154 for (int r = 0; r < ROWS; r++) {
155 int y = r * 20 + 5;
156 for (int c = 0; c < COLS; c++) {
157 int x = c * 20 + 5;
158 int i = r * COLS + c;
159 auto desc =
160 "row " + std::to_string(r + 1) + ", col " + std::to_string(c + 1);
161 results.clear();
162 auto query = DlRect::MakeXYWH(x + 2, y + 2, 6, 6);
163 tree.search(query, &results);
164 EXPECT_EQ(results.size(), 1u) << desc;
165 EXPECT_EQ(results[0], i) << desc;
166 EXPECT_EQ(tree.id(results[0]), ids[i]) << desc;
167 EXPECT_EQ(tree.bounds(results[0]), rects[i]) << desc;
168 auto list = tree.searchAndConsolidateRects(query);
169 EXPECT_EQ(list.size(), 1u);
170 EXPECT_EQ(list.front(), rects[i]);
171 }
172 }
173 // Testing inside each gap for no hits
174 for (int r = 1; r < ROWS; r++) {
175 int y = r * 20 + 5;
176 for (int c = 1; c < COLS; c++) {
177 int x = c * 20 + 5;
178 auto desc =
179 "row " + std::to_string(r + 1) + ", col " + std::to_string(c + 1);
180 results.clear();
181 auto query = DlRect::MakeXYWH(x - 8, y - 8, 6, 6);
182 tree.search(query, &results);
183 EXPECT_EQ(results.size(), 0u) << desc;
184 auto list = tree.searchAndConsolidateRects(query);
185 EXPECT_EQ(list.size(), 0u) << desc;
186 }
187 }
188 // Spanning each gap for a quad of hits
189 for (int r = 1; r < ROWS; r++) {
190 int y = r * 20 + 5;
191 for (int c = 1; c < COLS; c++) {
192 int x = c * 20 + 5;
193 // We will hit this rect and the ones above/left of us
194 int i = r * COLS + c;
195 auto desc =
196 "row " + std::to_string(r + 1) + ", col " + std::to_string(c + 1);
197 results.clear();
198 auto query = DlRect::MakeXYWH(x - 11, y - 11, 12, 12);
199 tree.search(query, &results);
200 EXPECT_EQ(results.size(), 4u) << desc;
201
202 // First rect is above and to the left
203 EXPECT_EQ(results[0], i - COLS - 1) << desc;
204 EXPECT_EQ(tree.id(results[0]), ids[i - COLS - 1]) << desc;
205 EXPECT_EQ(tree.bounds(results[0]), rects[i - COLS - 1]) << desc;
206
207 // Second rect is above
208 EXPECT_EQ(results[1], i - COLS) << desc;
209 EXPECT_EQ(tree.id(results[1]), ids[i - COLS]) << desc;
210 EXPECT_EQ(tree.bounds(results[1]), rects[i - COLS]) << desc;
211
212 // Third rect is left
213 EXPECT_EQ(results[2], i - 1) << desc;
214 EXPECT_EQ(tree.id(results[2]), ids[i - 1]) << desc;
215 EXPECT_EQ(tree.bounds(results[2]), rects[i - 1]) << desc;
216
217 // Fourth rect is us
218 EXPECT_EQ(results[3], i) << desc;
219 EXPECT_EQ(tree.id(results[3]), ids[i]) << desc;
220 EXPECT_EQ(tree.bounds(results[3]), rects[i]) << desc;
221
222 auto list = tree.searchAndConsolidateRects(query);
223 EXPECT_EQ(list.size(), 4u);
224 list.remove(rects[i - COLS - 1]);
225 list.remove(rects[i - COLS]);
226 list.remove(rects[i - 1]);
227 list.remove(rects[i]);
228 EXPECT_EQ(list.size(), 0u);
229 }
230 }
231}
232
233TEST(DisplayListRTree, OverlappingRects) {
234 // Rectangles are centered at coordinates 15, 35, and 55 and are 15 wide
235 // This gives them 10 pixels of overlap with the rectangles on either
236 // side of them and the 10 pixels around their center coordinate are
237 // exclusive to themselves.
238 // So, horizontally and vertically, they cover the following ranges:
239 // First row/col: 0 to 30
240 // Second row/col: 20 to 50
241 // Third row/col: 40 to 70
242 // Coords 0 to 20 are only the first row/col
243 // Coords 20 to 30 are both first and second row/col
244 // Coords 30 to 40 are only the second row/col
245 // Coords 40 to 50 are both second and third row/col
246 // Coords 50 to 70 are only the third row/col
247 //
248 // In either dimension:
249 // 0------------------20--------30--------40--------50------------------70
250 // | rect1 |
251 // | 1 & 2 |
252 // | rect2 |
253 // | 2 & 3 |
254 // | rect3 |
255 DlRect rects[9];
256 for (int r = 0; r < 3; r++) {
257 int y = 15 + 20 * r;
258 for (int c = 0; c < 3; c++) {
259 int x = 15 + 20 * c;
260 rects[r * 3 + c] = DlRect::MakeLTRB(x - 15, y - 15, x + 15, y + 15);
261 }
262 }
263 DlRTree tree(rects, 9);
264 // Tiny rects only intersecting a single source rect
265 for (int r = 0; r < 3; r++) {
266 int y = 15 + 20 * r;
267 for (int c = 0; c < 3; c++) {
268 int x = 15 + 20 * c;
269 auto query = DlRect::MakeLTRB(x - 1, y - 1, x + 1, y + 1);
270 auto list = tree.searchAndConsolidateRects(query);
271 EXPECT_EQ(list.size(), 1u);
272 EXPECT_EQ(list.front(), rects[r * 3 + c]);
273 }
274 }
275 // Wide rects intersecting 3 source rects horizontally
276 for (int r = 0; r < 3; r++) {
277 int c = 1;
278 int y = 15 + 20 * r;
279 int x = 15 + 20 * c;
280 auto query = DlRect::MakeLTRB(x - 6, y - 1, x + 6, y + 1);
281 auto list = tree.searchAndConsolidateRects(query);
282 EXPECT_EQ(list.size(), 1u);
283 EXPECT_EQ(list.front(), DlRect::MakeLTRB(x - 35, y - 15, x + 35, y + 15));
284 }
285 // Tall rects intersecting 3 source rects vertically
286 for (int c = 0; c < 3; c++) {
287 int r = 1;
288 int x = 15 + 20 * c;
289 int y = 15 + 20 * r;
290 auto query = DlRect::MakeLTRB(x - 1, y - 6, x + 1, y + 6);
291 auto list = tree.searchAndConsolidateRects(query);
292 EXPECT_EQ(list.size(), 1u);
293 EXPECT_EQ(list.front(), DlRect::MakeLTRB(x - 15, y - 35, x + 15, y + 35));
294 }
295 // Finally intersecting all 9 rects
296 auto query = DlRect::MakeLTRB(35 - 6, 35 - 6, 35 + 6, 35 + 6);
297 auto list = tree.searchAndConsolidateRects(query);
298 EXPECT_EQ(list.size(), 1u);
299 EXPECT_EQ(list.front(), DlRect::MakeLTRB(0, 0, 70, 70));
300}
301
302TEST(DisplayListRTree, Region) {
303 DlRect rect[9];
304 for (int i = 0; i < 9; i++) {
305 rect[i] = DlRect::MakeXYWH(i * 10, i * 10, 20, 20);
306 }
307 DlRTree rtree(rect, 9);
308 const auto& region = rtree.region();
309 auto rects = region.getRects(true);
310 std::vector<DlIRect> expected_rects{
311 DlIRect::MakeLTRB(0, 0, 20, 10), DlIRect::MakeLTRB(0, 10, 30, 20),
312 DlIRect::MakeLTRB(10, 20, 40, 30), DlIRect::MakeLTRB(20, 30, 50, 40),
313 DlIRect::MakeLTRB(30, 40, 60, 50), DlIRect::MakeLTRB(40, 50, 70, 60),
314 DlIRect::MakeLTRB(50, 60, 80, 70), DlIRect::MakeLTRB(60, 70, 90, 80),
315 DlIRect::MakeLTRB(70, 80, 100, 90), DlIRect::MakeLTRB(80, 90, 100, 100),
316 };
317 EXPECT_EQ(rects.size(), expected_rects.size());
318}
319
320} // namespace testing
321} // namespace flutter
int id(int result_index) const
Definition dl_rtree.h:83
int node_count() const
Definition dl_rtree.h:113
const DlRegion & region() const
Definition dl_rtree.cc:203
void search(const DlRect &query, std::vector< int > *results) const
Definition dl_rtree.cc:142
std::list< DlRect > searchAndConsolidateRects(const DlRect &query, bool deband=true) const
Definition dl_rtree.cc:163
int leaf_count() const
Definition dl_rtree.h:109
const DlRect & bounds() const
Definition dl_rtree.cc:215
std::vector< DlIRect > getRects(bool deband=true) const
Definition dl_region.cc:560
int32_t x
double y
TEST(NativeAssetsManagerTest, NoAvailableAssets)
impeller::Rect DlRect
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129