Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / desktop_capture / desktop_region_unittest.cc
1 /*
2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include "webrtc/modules/desktop_capture/desktop_region.h"
12
13 #include <algorithm>
14
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace webrtc {
18
19 namespace {
20
21 int RadmonInt(int max) {
22   return (rand() / 256) % max;
23 }
24
25 void CompareRegion(const DesktopRegion& region,
26                    const DesktopRect rects[], int rects_size) {
27   DesktopRegion::Iterator it(region);
28   for (int i = 0; i < rects_size; ++i) {
29     SCOPED_TRACE(i);
30     ASSERT_FALSE(it.IsAtEnd());
31     EXPECT_TRUE(it.rect().equals(rects[i]))
32         << it.rect().left() << "-" << it.rect().right() << "."
33         << it.rect().top() << "-" << it.rect().bottom() << " "
34         << rects[i].left() << "-" << rects[i].right() << "."
35         << rects[i].top() << "-" << rects[i].bottom();
36     it.Advance();
37   }
38   EXPECT_TRUE(it.IsAtEnd());
39 }
40
41 }  // namespace
42
43 // Verify that regions are empty when created.
44 TEST(DesktopRegionTest, Empty) {
45   DesktopRegion r;
46   CompareRegion(r, NULL, 0);
47 }
48
49 // Verify that empty rectangles are ignored.
50 TEST(DesktopRegionTest, AddEmpty) {
51   DesktopRegion r;
52   DesktopRect rect = DesktopRect::MakeXYWH(1, 2, 0, 0);
53   r.AddRect(rect);
54   CompareRegion(r, NULL, 0);
55 }
56
57 // Verify that regions with a single rectangles are handled properly.
58 TEST(DesktopRegionTest, SingleRect) {
59   DesktopRegion r;
60   DesktopRect rect = DesktopRect::MakeXYWH(1, 2, 3, 4);
61   r.AddRect(rect);
62   CompareRegion(r, &rect, 1);
63 }
64
65 // Verify that non-overlapping rectangles are not merged.
66 TEST(DesktopRegionTest, NonOverlappingRects) {
67   struct Case {
68     int count;
69     DesktopRect rects[4];
70   } cases[] = {
71     { 1, { DesktopRect::MakeXYWH(10, 10, 10, 10) } },
72     { 2, { DesktopRect::MakeXYWH(10, 10, 10, 10),
73            DesktopRect::MakeXYWH(30, 10, 10, 15) } },
74     { 2, { DesktopRect::MakeXYWH(10, 10, 10, 10),
75            DesktopRect::MakeXYWH(10, 30, 10, 5) } },
76     { 3, { DesktopRect::MakeXYWH(10, 10, 10, 9),
77            DesktopRect::MakeXYWH(30, 10, 15, 10),
78            DesktopRect::MakeXYWH(10, 30, 8, 10) } },
79     { 4, { DesktopRect::MakeXYWH(0, 0, 30, 10),
80            DesktopRect::MakeXYWH(40, 0, 10, 30),
81            DesktopRect::MakeXYWH(0, 20, 10, 30),
82            DesktopRect::MakeXYWH(20, 40, 30, 10) } },
83     { 4, { DesktopRect::MakeXYWH(0, 0, 10, 100),
84            DesktopRect::MakeXYWH(20, 10, 30, 10),
85            DesktopRect::MakeXYWH(20, 30, 30, 10),
86            DesktopRect::MakeXYWH(20, 50, 30, 10) } },
87   };
88
89   for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
90     SCOPED_TRACE(i);
91
92     DesktopRegion r;
93
94     for (int j = 0; j < cases[i].count; ++j) {
95       r.AddRect(cases[i].rects[j]);
96     }
97     CompareRegion(r, cases[i].rects, cases[i].count);
98
99     SCOPED_TRACE("Reverse");
100
101     // Try inserting rects in reverse order.
102     r.Clear();
103     for (int j = cases[i].count - 1; j >= 0; --j) {
104       r.AddRect(cases[i].rects[j]);
105     }
106     CompareRegion(r, cases[i].rects, cases[i].count);
107   }
108 }
109
110 TEST(DesktopRegionTest, TwoRects) {
111   struct Case {
112     DesktopRect input_rect1;
113     DesktopRect input_rect2;
114     int expected_count;
115     DesktopRect expected_rects[3];
116   } cases[] = {
117     // Touching rectangles that merge into one.
118     { DesktopRect::MakeLTRB(100, 100, 200, 200),
119       DesktopRect::MakeLTRB(0, 100, 100, 200),
120       1, { DesktopRect::MakeLTRB(0, 100, 200, 200) } },
121     { DesktopRect::MakeLTRB(100, 100, 200, 200),
122       DesktopRect::MakeLTRB(100, 0, 200, 100),
123       1, { DesktopRect::MakeLTRB(100, 0, 200, 200) } },
124
125     // Rectangles touching on the vertical edge.
126     { DesktopRect::MakeLTRB(100, 100, 200, 200),
127       DesktopRect::MakeLTRB(0, 150, 100, 250),
128       3, { DesktopRect::MakeLTRB(100, 100, 200, 150),
129            DesktopRect::MakeLTRB(0, 150, 200, 200),
130            DesktopRect::MakeLTRB(0, 200, 100, 250) } },
131     { DesktopRect::MakeLTRB(100, 100, 200, 200),
132       DesktopRect::MakeLTRB(0, 50, 100, 150),
133       3, { DesktopRect::MakeLTRB(0, 50, 100, 100),
134            DesktopRect::MakeLTRB(0, 100, 200, 150),
135            DesktopRect::MakeLTRB(100, 150, 200, 200) } },
136     { DesktopRect::MakeLTRB(100, 100, 200, 200),
137       DesktopRect::MakeLTRB(0, 120, 100, 180),
138       3, { DesktopRect::MakeLTRB(100, 100, 200, 120),
139            DesktopRect::MakeLTRB(0, 120, 200, 180),
140            DesktopRect::MakeLTRB(100, 180, 200, 200) } },
141
142     // Rectangles touching on the horizontal edge.
143     { DesktopRect::MakeLTRB(100, 100, 200, 200),
144       DesktopRect::MakeLTRB(150, 0, 250, 100),
145       2, { DesktopRect::MakeLTRB(150, 0, 250, 100),
146            DesktopRect::MakeLTRB(100, 100, 200, 200) } },
147     { DesktopRect::MakeLTRB(100, 100, 200, 200),
148       DesktopRect::MakeLTRB(50, 0, 150, 100),
149       2, { DesktopRect::MakeLTRB(50, 0, 150, 100),
150            DesktopRect::MakeLTRB(100, 100, 200, 200) } },
151     { DesktopRect::MakeLTRB(100, 100, 200, 200),
152       DesktopRect::MakeLTRB(120, 0, 180, 100),
153       2, { DesktopRect::MakeLTRB(120, 0, 180, 100),
154            DesktopRect::MakeLTRB(100, 100, 200, 200) } },
155
156     // Overlapping rectangles.
157     { DesktopRect::MakeLTRB(100, 100, 200, 200),
158       DesktopRect::MakeLTRB(50, 50, 150, 150),
159       3, { DesktopRect::MakeLTRB(50, 50, 150, 100),
160            DesktopRect::MakeLTRB(50, 100, 200, 150),
161            DesktopRect::MakeLTRB(100, 150, 200, 200) } },
162     { DesktopRect::MakeLTRB(100, 100, 200, 200),
163       DesktopRect::MakeLTRB(150, 50, 250, 150),
164       3, { DesktopRect::MakeLTRB(150, 50, 250, 100),
165            DesktopRect::MakeLTRB(100, 100, 250, 150),
166            DesktopRect::MakeLTRB(100, 150, 200, 200) } },
167     { DesktopRect::MakeLTRB(100, 100, 200, 200),
168       DesktopRect::MakeLTRB(0, 120, 150, 180),
169       3, { DesktopRect::MakeLTRB(100, 100, 200, 120),
170            DesktopRect::MakeLTRB(0, 120, 200, 180),
171            DesktopRect::MakeLTRB(100, 180, 200, 200) } },
172     { DesktopRect::MakeLTRB(100, 100, 200, 200),
173       DesktopRect::MakeLTRB(120, 0, 180, 150),
174       2, { DesktopRect::MakeLTRB(120, 0, 180, 100),
175            DesktopRect::MakeLTRB(100, 100, 200, 200) } },
176     { DesktopRect::MakeLTRB(100, 0, 200, 300),
177       DesktopRect::MakeLTRB(0, 100, 300, 200),
178       3, { DesktopRect::MakeLTRB(100, 0, 200, 100),
179            DesktopRect::MakeLTRB(0, 100, 300, 200),
180            DesktopRect::MakeLTRB(100, 200, 200, 300)} },
181
182     // One rectangle enclosing another.
183     { DesktopRect::MakeLTRB(100, 100, 200, 200),
184       DesktopRect::MakeLTRB(150, 150, 180, 180),
185       1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
186     { DesktopRect::MakeLTRB(100, 100, 200, 200),
187       DesktopRect::MakeLTRB(100, 100, 180, 180),
188       1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
189     { DesktopRect::MakeLTRB(100, 100, 200, 200),
190       DesktopRect::MakeLTRB(150, 150, 200, 200),
191       1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
192   };
193
194   for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
195     SCOPED_TRACE(i);
196
197     DesktopRegion r;
198
199     r.AddRect(cases[i].input_rect1);
200     r.AddRect(cases[i].input_rect2);
201     CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
202
203     SCOPED_TRACE("Reverse");
204
205     // Run the same test with rectangles inserted in reverse order.
206     r.Clear();
207     r.AddRect(cases[i].input_rect2);
208     r.AddRect(cases[i].input_rect1);
209     CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
210   }
211 }
212
213 // Verify that DesktopRegion::AddRectToRow() works correctly by creating a row
214 // of not overlapping rectangles and insert an overlapping rectangle into the
215 // row at different positions. Result is verified by building a map of the
216 // region in an array and comparing it with the expected values.
217 TEST(DesktopRegionTest, SameRow) {
218   const int kMapWidth = 50;
219   const int kLastRectSizes[] = {3, 27};
220
221   DesktopRegion base_region;
222   bool base_map[kMapWidth] = { false, };
223
224   base_region.AddRect(DesktopRect::MakeXYWH(5, 0, 5, 1));
225   std::fill_n(base_map + 5, 5, true);
226   base_region.AddRect(DesktopRect::MakeXYWH(15, 0, 5, 1));
227   std::fill_n(base_map + 15, 5, true);
228   base_region.AddRect(DesktopRect::MakeXYWH(25, 0, 5, 1));
229   std::fill_n(base_map + 25, 5, true);
230   base_region.AddRect(DesktopRect::MakeXYWH(35, 0, 5, 1));
231   std::fill_n(base_map + 35, 5, true);
232   base_region.AddRect(DesktopRect::MakeXYWH(45, 0, 5, 1));
233   std::fill_n(base_map + 45, 5, true);
234
235   for (size_t i = 0; i < sizeof(kLastRectSizes) / sizeof(kLastRectSizes[0]);
236        i++) {
237     int last_rect_size = kLastRectSizes[i];
238     for (int x = 0; x < kMapWidth - last_rect_size; x++) {
239       SCOPED_TRACE(x);
240
241       DesktopRegion r = base_region;
242       r.AddRect(DesktopRect::MakeXYWH(x, 0,  last_rect_size, 1));
243
244       bool expected_map[kMapWidth];
245       std::copy(base_map, base_map + kMapWidth, expected_map);
246       std::fill_n(expected_map + x, last_rect_size, true);
247
248       bool map[kMapWidth] = { false, };
249
250       int pos = -1;
251       for (DesktopRegion::Iterator it(r); !it.IsAtEnd(); it.Advance()) {
252         EXPECT_GT(it.rect().left(), pos);
253         pos = it.rect().right();
254         std::fill_n(map + it.rect().left(), it.rect().width(), true);
255       }
256
257       EXPECT_TRUE(std::equal(map, map + kMapWidth, expected_map));
258     }
259   }
260 }
261
262 TEST(DesktopRegionTest, ComplexRegions) {
263   struct Case {
264     int input_count;
265     DesktopRect input_rects[4];
266     int expected_count;
267     DesktopRect expected_rects[6];
268   } cases[] = {
269     { 3, { DesktopRect::MakeLTRB(100, 100, 200, 200),
270            DesktopRect::MakeLTRB(0, 100, 100, 200),
271            DesktopRect::MakeLTRB(310, 110, 320, 120), },
272       2, { DesktopRect::MakeLTRB(0, 100, 200, 200),
273            DesktopRect::MakeLTRB(310, 110, 320, 120) } },
274     { 3, { DesktopRect::MakeLTRB(100, 100, 200, 200),
275            DesktopRect::MakeLTRB(50, 50, 150, 150),
276            DesktopRect::MakeLTRB(300, 125, 350, 175) },
277       4, { DesktopRect::MakeLTRB(50, 50, 150, 100),
278            DesktopRect::MakeLTRB(50, 100, 200, 150),
279            DesktopRect::MakeLTRB(300, 125, 350, 175),
280            DesktopRect::MakeLTRB(100, 150, 200, 200) } },
281     { 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
282            DesktopRect::MakeLTRB(10, 10, 40, 40),
283            DesktopRect::MakeLTRB(20, 20, 50, 50),
284            DesktopRect::MakeLTRB(50, 0, 65, 15) },
285       6, { DesktopRect::MakeLTRB(0, 0, 30, 10),
286            DesktopRect::MakeLTRB(50, 0, 65, 15),
287            DesktopRect::MakeLTRB(0, 10, 40, 20),
288            DesktopRect::MakeLTRB(0, 20, 50, 30),
289            DesktopRect::MakeLTRB(10, 30, 50, 40),
290            DesktopRect::MakeLTRB(20, 40, 50, 50) } },
291     { 3, { DesktopRect::MakeLTRB(10, 10, 40, 20),
292            DesktopRect::MakeLTRB(10, 30, 40, 40),
293            DesktopRect::MakeLTRB(10, 20, 40, 30) },
294       1, { DesktopRect::MakeLTRB(10, 10, 40, 40) } },
295   };
296
297   for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
298     SCOPED_TRACE(i);
299
300     DesktopRegion r;
301     r.AddRects(cases[i].input_rects, cases[i].input_count);
302     CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
303
304     // Try inserting rectangles in reverse order.
305     r.Clear();
306     for (int j = cases[i].input_count - 1; j >= 0; --j) {
307       r.AddRect(cases[i].input_rects[j]);
308     }
309     CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
310   }
311 }
312
313 TEST(DesktopRegionTest, Equals) {
314   struct Region {
315     int count;
316     DesktopRect rects[4];
317     int id;
318   } regions[] = {
319     // Same region with one of the rectangles 1 pixel wider/taller.
320     { 2, { DesktopRect::MakeLTRB(0, 100, 200, 200),
321            DesktopRect::MakeLTRB(310, 110, 320, 120) }, 0 },
322     { 2, { DesktopRect::MakeLTRB(0, 100, 201, 200),
323            DesktopRect::MakeLTRB(310, 110, 320, 120) }, 1 },
324     { 2, { DesktopRect::MakeLTRB(0, 100, 200, 201),
325            DesktopRect::MakeLTRB(310, 110, 320, 120) }, 2 },
326
327     // Same region with one of the rectangles shifted horizontally and
328     // vertically.
329     { 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
330            DesktopRect::MakeLTRB(10, 10, 40, 40),
331            DesktopRect::MakeLTRB(20, 20, 50, 50),
332            DesktopRect::MakeLTRB(50, 0, 65, 15) }, 3 },
333     { 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
334            DesktopRect::MakeLTRB(10, 10, 40, 40),
335            DesktopRect::MakeLTRB(20, 20, 50, 50),
336            DesktopRect::MakeLTRB(50, 1, 65, 16) }, 4 },
337     { 4, { DesktopRect::MakeLTRB(0, 0, 30, 30),
338            DesktopRect::MakeLTRB(10, 10, 40, 40),
339            DesktopRect::MakeLTRB(20, 20, 50, 50),
340            DesktopRect::MakeLTRB(51, 0, 66, 15) }, 5 },
341
342     // Same region defined by a different set of rectangles - one of the
343     // rectangle is split horizontally into two.
344     { 3, { DesktopRect::MakeLTRB(100, 100, 200, 200),
345            DesktopRect::MakeLTRB(50, 50, 150, 150),
346            DesktopRect::MakeLTRB(300, 125, 350, 175) }, 6 },
347     { 4, { DesktopRect::MakeLTRB(100, 100, 200, 200),
348            DesktopRect::MakeLTRB(50, 50, 100, 150),
349            DesktopRect::MakeLTRB(100, 50, 150, 150),
350            DesktopRect::MakeLTRB(300, 125, 350, 175) }, 6 },
351
352     // Rectangle region defined by a set of rectangles that merge into one.
353     { 3, { DesktopRect::MakeLTRB(10, 10, 40, 20),
354            DesktopRect::MakeLTRB(10, 30, 40, 40),
355            DesktopRect::MakeLTRB(10, 20, 40, 30) }, 7 },
356     { 1, { DesktopRect::MakeLTRB(10, 10, 40, 40) }, 7 },
357   };
358   int kTotalRegions = sizeof(regions) / sizeof(Region);
359
360   for (int i = 0; i < kTotalRegions; ++i) {
361     SCOPED_TRACE(i);
362
363     DesktopRegion r1(regions[i].rects, regions[i].count);
364     for (int j = 0; j < kTotalRegions; ++j) {
365       SCOPED_TRACE(j);
366
367       DesktopRegion r2(regions[j].rects, regions[j].count);
368       EXPECT_EQ(regions[i].id == regions[j].id, r1.Equals(r2));
369     }
370   }
371 }
372
373 TEST(DesktopRegionTest, Translate) {
374   struct Case {
375     int input_count;
376     DesktopRect input_rects[4];
377     int dx;
378     int dy;
379     int expected_count;
380     DesktopRect expected_rects[5];
381   } cases[] = {
382     { 3, { DesktopRect::MakeLTRB(0, 0, 30, 30),
383            DesktopRect::MakeLTRB(10, 10, 40, 40),
384            DesktopRect::MakeLTRB(20, 20, 50, 50) },
385       3, 5,
386       5, { DesktopRect::MakeLTRB(3, 5, 33, 15),
387            DesktopRect::MakeLTRB(3, 15, 43, 25),
388            DesktopRect::MakeLTRB(3, 25, 53, 35),
389            DesktopRect::MakeLTRB(13, 35, 53, 45),
390            DesktopRect::MakeLTRB(23, 45, 53, 55) } },
391   };
392
393   for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
394     SCOPED_TRACE(i);
395
396     DesktopRegion r(cases[i].input_rects, cases[i].input_count);
397     r.Translate(cases[i].dx, cases[i].dy);
398     CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
399   }
400 }
401
402 TEST(DesktopRegionTest, Intersect) {
403   struct Case {
404     int input1_count;
405     DesktopRect input1_rects[4];
406     int input2_count;
407     DesktopRect input2_rects[4];
408     int expected_count;
409     DesktopRect expected_rects[5];
410   } cases[] = {
411     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
412       1, { DesktopRect::MakeLTRB(50, 50, 150, 150) },
413       1, { DesktopRect::MakeLTRB(50, 50, 100, 100) } },
414
415     { 1, { DesktopRect::MakeLTRB(100, 0, 200, 300) },
416       1, { DesktopRect::MakeLTRB(0, 100, 300, 200) },
417       1, { DesktopRect::MakeLTRB(100, 100, 200, 200) } },
418
419     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
420       2, { DesktopRect::MakeLTRB(50, 10, 150, 30),
421            DesktopRect::MakeLTRB(50, 30, 160, 50) },
422       1, { DesktopRect::MakeLTRB(50, 10, 100, 50) } },
423
424     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
425       2, { DesktopRect::MakeLTRB(50, 10, 150, 30),
426            DesktopRect::MakeLTRB(50, 30,  90, 50) },
427       2, { DesktopRect::MakeLTRB(50, 10, 100, 30),
428            DesktopRect::MakeLTRB(50, 30, 90, 50) } },
429     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
430       1, { DesktopRect::MakeLTRB(100, 50, 200, 200) },
431       0, {} },
432   };
433
434   for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
435     SCOPED_TRACE(i);
436
437     DesktopRegion r1(cases[i].input1_rects, cases[i].input1_count);
438     DesktopRegion r2(cases[i].input2_rects, cases[i].input2_count);
439
440     DesktopRegion r;
441     r.Intersect(r1, r2);
442
443     CompareRegion(r, cases[i].expected_rects, cases[i].expected_count);
444   }
445 }
446
447 TEST(DesktopRegionTest, Subtract) {
448   struct Case {
449     int input1_count;
450     DesktopRect input1_rects[4];
451     int input2_count;
452     DesktopRect input2_rects[4];
453     int expected_count;
454     DesktopRect expected_rects[5];
455   } cases[] = {
456     // Subtract one rect from another.
457     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
458       1, { DesktopRect::MakeLTRB(50, 50, 150, 150) },
459       2, { DesktopRect::MakeLTRB(0, 0, 100, 50),
460            DesktopRect::MakeLTRB(0, 50, 50, 100)  } },
461
462     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
463       1, { DesktopRect::MakeLTRB(-50, -50, 50, 50) },
464       2, { DesktopRect::MakeLTRB(50, 0, 100, 50),
465            DesktopRect::MakeLTRB(0, 50, 100, 100)  } },
466
467     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
468       1, { DesktopRect::MakeLTRB(-50, 50, 50, 150) },
469       2, { DesktopRect::MakeLTRB(0, 0, 100, 50),
470            DesktopRect::MakeLTRB(50, 50, 100, 100)  } },
471
472     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
473       1, { DesktopRect::MakeLTRB(50, 50, 150, 70) },
474       3, { DesktopRect::MakeLTRB(0, 0, 100, 50),
475            DesktopRect::MakeLTRB(0, 50, 50, 70),
476            DesktopRect::MakeLTRB(0, 70, 100, 100) } },
477
478     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
479       1, { DesktopRect::MakeLTRB(50, 50, 70, 70) },
480       4, { DesktopRect::MakeLTRB(0, 0, 100, 50),
481            DesktopRect::MakeLTRB(0, 50, 50, 70),
482            DesktopRect::MakeLTRB(70, 50, 100, 70),
483            DesktopRect::MakeLTRB(0, 70, 100, 100) } },
484
485     // Empty result.
486     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
487       1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
488       0, {} },
489
490     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
491       1, { DesktopRect::MakeLTRB(-10, -10, 110, 110) },
492       0, {} },
493
494     { 2, { DesktopRect::MakeLTRB(0, 0, 100, 100),
495            DesktopRect::MakeLTRB(50, 50, 150, 150) },
496       2, { DesktopRect::MakeLTRB(0, 0, 100, 100),
497            DesktopRect::MakeLTRB(50, 50, 150, 150) },
498       0, {} },
499
500     // One rect out of disjoint set.
501     { 3, { DesktopRect::MakeLTRB(0, 0, 10, 10),
502            DesktopRect::MakeLTRB(20, 20, 30, 30),
503            DesktopRect::MakeLTRB(40, 0, 50, 10) },
504       1, { DesktopRect::MakeLTRB(20, 20, 30, 30) },
505       2, { DesktopRect::MakeLTRB(0, 0, 10, 10),
506            DesktopRect::MakeLTRB(40, 0, 50, 10) } },
507
508     // Row merging.
509     { 3, { DesktopRect::MakeLTRB(0, 0, 100, 50),
510            DesktopRect::MakeLTRB(0, 50, 150, 70),
511            DesktopRect::MakeLTRB(0, 70, 100, 100) },
512       1, { DesktopRect::MakeLTRB(100, 50, 150, 70) },
513       1, { DesktopRect::MakeLTRB(0, 0, 100, 100) } },
514
515     // No-op subtraction.
516     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
517       1, { DesktopRect::MakeLTRB(100, 0, 200, 100) },
518       1, { DesktopRect::MakeLTRB(0, 0, 100, 100) } },
519
520     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
521       1, { DesktopRect::MakeLTRB(-100, 0, 0, 100) },
522       1, { DesktopRect::MakeLTRB(0, 0, 100, 100) } },
523
524     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
525       1, { DesktopRect::MakeLTRB(0, 100, 0, 200) },
526       1, { DesktopRect::MakeLTRB(0, 0, 100, 100) } },
527
528     { 1, { DesktopRect::MakeLTRB(0, 0, 100, 100) },
529       1, { DesktopRect::MakeLTRB(0, -100, 100, 0) },
530       1, { DesktopRect::MakeLTRB(0, 0, 100, 100) } },
531   };
532
533   for (size_t i = 0; i < (sizeof(cases) / sizeof(Case)); ++i) {
534     SCOPED_TRACE(i);
535
536     DesktopRegion r1(cases[i].input1_rects, cases[i].input1_count);
537     DesktopRegion r2(cases[i].input2_rects, cases[i].input2_count);
538
539     r1.Subtract(r2);
540
541     CompareRegion(r1, cases[i].expected_rects, cases[i].expected_count);
542   }
543 }
544
545 // Verify that DesktopRegion::SubtractRows() works correctly by creating a row
546 // of not overlapping rectangles and subtracting a set of rectangle. Result
547 // is verified by building a map of the region in an array and comparing it with
548 // the expected values.
549 TEST(DesktopRegionTest, SubtractRectOnSameRow) {
550   const int kMapWidth = 50;
551
552   struct SpanSet {
553     int count;
554     struct Range {
555      int start;
556      int end;
557     } spans[3];
558   } span_sets[] = {
559     {1, { {0, 3} } },
560     {1, { {0, 5} } },
561     {1, { {0, 7} } },
562     {1, { {0, 12} } },
563     {2, { {0, 3}, {4, 5}, {6, 16} } },
564   };
565
566   DesktopRegion base_region;
567   bool base_map[kMapWidth] = { false, };
568
569   base_region.AddRect(DesktopRect::MakeXYWH(5, 0, 5, 1));
570   std::fill_n(base_map + 5, 5, true);
571   base_region.AddRect(DesktopRect::MakeXYWH(15, 0, 5, 1));
572   std::fill_n(base_map + 15, 5, true);
573   base_region.AddRect(DesktopRect::MakeXYWH(25, 0, 5, 1));
574   std::fill_n(base_map + 25, 5, true);
575   base_region.AddRect(DesktopRect::MakeXYWH(35, 0, 5, 1));
576   std::fill_n(base_map + 35, 5, true);
577   base_region.AddRect(DesktopRect::MakeXYWH(45, 0, 5, 1));
578   std::fill_n(base_map + 45, 5, true);
579
580   for (size_t i = 0; i < sizeof(span_sets) / sizeof(span_sets[0]); i++) {
581     SCOPED_TRACE(i);
582     SpanSet& span_set = span_sets[i];
583     int span_set_end = span_set.spans[span_set.count - 1].end;
584     for (int x = 0; x < kMapWidth - span_set_end; ++x) {
585       SCOPED_TRACE(x);
586
587       DesktopRegion r = base_region;
588
589       bool expected_map[kMapWidth];
590       std::copy(base_map, base_map + kMapWidth, expected_map);
591
592       DesktopRegion region2;
593       for (int span = 0; span < span_set.count; span++) {
594         std::fill_n(x + expected_map + span_set.spans[span].start,
595                     span_set.spans[span].end - span_set.spans[span].start,
596                     false);
597         region2.AddRect(DesktopRect::MakeLTRB(x + span_set.spans[span].start, 0,
598                                               x + span_set.spans[span].end, 1));
599       }
600       r.Subtract(region2);
601
602       bool map[kMapWidth] = { false, };
603
604       int pos = -1;
605       for (DesktopRegion::Iterator it(r); !it.IsAtEnd(); it.Advance()) {
606         EXPECT_GT(it.rect().left(), pos);
607         pos = it.rect().right();
608         std::fill_n(map + it.rect().left(), it.rect().width(), true);
609       }
610
611       EXPECT_TRUE(std::equal(map, map + kMapWidth, expected_map));
612     }
613   }
614 }
615
616 // Verify that DesktopRegion::Subtract() works correctly by creating a column of
617 // not overlapping rectangles and subtracting a set of rectangle on the same
618 // column. Result is verified by building a map of the region in an array and
619 // comparing it with the expected values.
620 TEST(DesktopRegionTest, SubtractRectOnSameCol) {
621   const int kMapHeight = 50;
622
623   struct SpanSet {
624     int count;
625     struct Range {
626      int start;
627      int end;
628     } spans[3];
629   } span_sets[] = {
630     {1, { {0, 3} } },
631     {1, { {0, 5} } },
632     {1, { {0, 7} } },
633     {1, { {0, 12} } },
634     {2, { {0, 3}, {4, 5}, {6, 16} } },
635   };
636
637   DesktopRegion base_region;
638   bool base_map[kMapHeight] = { false, };
639
640   base_region.AddRect(DesktopRect::MakeXYWH(0, 5, 1, 5));
641   std::fill_n(base_map + 5, 5, true);
642   base_region.AddRect(DesktopRect::MakeXYWH(0, 15, 1, 5));
643   std::fill_n(base_map + 15, 5, true);
644   base_region.AddRect(DesktopRect::MakeXYWH(0, 25, 1, 5));
645   std::fill_n(base_map + 25, 5, true);
646   base_region.AddRect(DesktopRect::MakeXYWH(0, 35, 1, 5));
647   std::fill_n(base_map + 35, 5, true);
648   base_region.AddRect(DesktopRect::MakeXYWH(0, 45, 1, 5));
649   std::fill_n(base_map + 45, 5, true);
650
651   for (size_t i = 0; i < sizeof(span_sets) / sizeof(span_sets[0]); i++) {
652     SCOPED_TRACE(i);
653     SpanSet& span_set = span_sets[i];
654     int span_set_end = span_set.spans[span_set.count - 1].end;
655     for (int y = 0; y < kMapHeight - span_set_end; ++y) {
656       SCOPED_TRACE(y);
657
658       DesktopRegion r = base_region;
659
660       bool expected_map[kMapHeight];
661       std::copy(base_map, base_map + kMapHeight, expected_map);
662
663       DesktopRegion region2;
664       for (int span = 0; span < span_set.count; span++) {
665         std::fill_n(y + expected_map + span_set.spans[span].start,
666                     span_set.spans[span].end - span_set.spans[span].start,
667                     false);
668         region2.AddRect(DesktopRect::MakeLTRB(0, y + span_set.spans[span].start,
669                                               1, y + span_set.spans[span].end));
670       }
671       r.Subtract(region2);
672
673       bool map[kMapHeight] = { false, };
674
675       int pos = -1;
676       for (DesktopRegion::Iterator it(r); !it.IsAtEnd(); it.Advance()) {
677         EXPECT_GT(it.rect().top(), pos);
678         pos = it.rect().bottom();
679         std::fill_n(map + it.rect().top(), it.rect().height(), true);
680       }
681
682       for (int j = 0; j < kMapHeight; j++) {
683         EXPECT_EQ(expected_map[j], map[j]) << "j = " << j;
684       }
685     }
686   }
687 }
688
689
690 TEST(DesktopRegionTest, DISABLED_Performance) {
691   for (int c = 0; c < 1000; ++c) {
692     DesktopRegion r;
693     for (int i = 0; i < 10; ++i) {
694       r.AddRect(DesktopRect::MakeXYWH(
695           RadmonInt(1000), RadmonInt(1000), 200, 200));
696     }
697
698     for (int i = 0; i < 1000; ++i) {
699       r.AddRect(DesktopRect::MakeXYWH(
700           RadmonInt(1000), RadmonInt(1000),
701           5 + RadmonInt(10) * 5, 5 + RadmonInt(10) * 5));
702     }
703
704     // Iterate over the rectangles.
705     for (DesktopRegion::Iterator it(r); !it.IsAtEnd(); it.Advance()) {
706     }
707   }
708 }
709
710 }  // namespace webrtc