blob: 40fde4dbc4e0f1be2036265a15c9c3c733078d86 [file] [log] [blame]
sergeyu@chromium.org3d34f662013-06-04 18:51:23 +00001/*
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 "testing/gmock/include/gmock/gmock.h"
12#include "webrtc/modules/desktop_capture/differ.h"
13#include "webrtc/modules/desktop_capture/differ_block.h"
14#include "webrtc/system_wrappers/interface/scoped_ptr.h"
15
16namespace webrtc {
17
18// 96x96 screen gives a 4x4 grid of blocks.
19const int kScreenWidth= 96;
20const int kScreenHeight = 96;
21
22// To test partial blocks, we need a width and height that are not multiples
23// of 16 (or 32, depending on current block size).
24const int kPartialScreenWidth = 70;
25const int kPartialScreenHeight = 70;
26
27class DifferTest : public testing::Test {
28 public:
29 DifferTest() {
30 }
31
32 protected:
33 void InitDiffer(int width, int height) {
34 width_ = width;
35 height_ = height;
36 bytes_per_pixel_ = kBytesPerPixel;
37 stride_ = (kBytesPerPixel * width);
38 buffer_size_ = width_ * height_ * bytes_per_pixel_;
39
40 differ_.reset(new Differ(width_, height_, bytes_per_pixel_, stride_));
41
42 prev_.reset(new uint8_t[buffer_size_]);
43 memset(prev_.get(), 0, buffer_size_);
44
45 curr_.reset(new uint8_t[buffer_size_]);
46 memset(curr_.get(), 0, buffer_size_);
47 }
48
49 void ClearBuffer(uint8_t* buffer) {
50 memset(buffer, 0, buffer_size_);
51 }
52
53 // Here in DifferTest so that tests can access private methods of Differ.
54 void MarkDirtyBlocks(const void* prev_buffer, const void* curr_buffer) {
55 differ_->MarkDirtyBlocks(prev_buffer, curr_buffer);
56 }
57
58 void MergeBlocks(DesktopRegion* dirty) {
59 differ_->MergeBlocks(dirty);
60 }
61
62 // Convenience method to count rectangles in a region.
63 int RegionRectCount(const DesktopRegion& region) {
64 int count = 0;
65 for (DesktopRegion::Iterator iter(region);
66 !iter.IsAtEnd(); iter.Advance()) {
67 ++count;
68 }
69 return count;
70 }
71
72 // Convenience wrapper for Differ's DiffBlock that calculates the appropriate
73 // offset to the start of the desired block.
74 DiffInfo DiffBlock(int block_x, int block_y) {
75 // Offset from upper-left of buffer to upper-left of requested block.
76 int block_offset = ((block_y * stride_) + (block_x * bytes_per_pixel_))
77 * kBlockSize;
78 return BlockDifference(prev_.get() + block_offset,
79 curr_.get() + block_offset,
80 stride_);
81 }
82
83 // Write the pixel |value| into the specified block in the |buffer|.
84 // This is a convenience wrapper around WritePixel().
85 void WriteBlockPixel(uint8_t* buffer, int block_x, int block_y,
86 int pixel_x, int pixel_y, uint32_t value) {
87 WritePixel(buffer, (block_x * kBlockSize) + pixel_x,
88 (block_y * kBlockSize) + pixel_y, value);
89 }
90
91 // Write the test pixel |value| into the |buffer| at the specified |x|,|y|
92 // location.
93 // Only the low-order bytes from |value| are written (assuming little-endian).
94 // So, for |value| = 0xaabbccdd:
95 // If bytes_per_pixel = 4, then ddccbbaa will be written as the pixel value.
96 // If = 3, ddccbb
97 // If = 2, ddcc
98 // If = 1, dd
99 void WritePixel(uint8_t* buffer, int x, int y, uint32_t value) {
100 uint8_t* pixel = reinterpret_cast<uint8_t*>(&value);
101 buffer += (y * stride_) + (x * bytes_per_pixel_);
102 for (int b = bytes_per_pixel_ - 1; b >= 0; b--) {
103 *buffer++ = pixel[b];
104 }
105 }
106
107 // DiffInfo utility routines.
108 // These are here so that we don't have to make each DifferText_Xxx_Test
109 // class a friend class to Differ.
110
111 // Clear out the entire |diff_info_| buffer.
112 void ClearDiffInfo() {
113 memset(differ_->diff_info_.get(), 0, differ_->diff_info_size_);
114 }
115
116 // Get the value in the |diff_info_| array at (x,y).
117 DiffInfo GetDiffInfo(int x, int y) {
118 DiffInfo* diff_info = differ_->diff_info_.get();
119 return diff_info[(y * GetDiffInfoWidth()) + x];
120 }
121
122 // Width of |diff_info_| array.
123 int GetDiffInfoWidth() {
124 return differ_->diff_info_width_;
125 }
126
127 // Height of |diff_info_| array.
128 int GetDiffInfoHeight() {
129 return differ_->diff_info_height_;
130 }
131
132 // Size of |diff_info_| array.
133 int GetDiffInfoSize() {
134 return differ_->diff_info_size_;
135 }
136
137 void SetDiffInfo(int x, int y, const DiffInfo& value) {
138 DiffInfo* diff_info = differ_->diff_info_.get();
139 diff_info[(y * GetDiffInfoWidth()) + x] = value;
140 }
141
142 // Mark the range of blocks specified.
143 void MarkBlocks(int x_origin, int y_origin, int width, int height) {
144 for (int y = 0; y < height; y++) {
145 for (int x = 0; x < width; x++) {
146 SetDiffInfo(x_origin + x, y_origin + y, 1);
147 }
148 }
149 }
150
151 // Verify that |region| contains a rectangle defined by |x|, |y|, |width| and
152 // |height|.
153 // |x|, |y|, |width| and |height| are specified in block (not pixel) units.
154 bool CheckDirtyRegionContainsRect(const DesktopRegion& region,
155 int x, int y,
156 int width, int height) {
157 DesktopRect r =
158 DesktopRect::MakeXYWH(x * kBlockSize, y * kBlockSize,
159 width * kBlockSize, height * kBlockSize);
160 for (DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) {
161 if (i.rect().equals(r))
162 return true;
163 }
164 return false;
165 }
166
167 // Mark the range of blocks specified and then verify that they are
168 // merged correctly.
169 // Only one rectangular region of blocks can be checked with this routine.
170 bool MarkBlocksAndCheckMerge(int x_origin, int y_origin,
171 int width, int height) {
172 ClearDiffInfo();
173 MarkBlocks(x_origin, y_origin, width, height);
174
175 DesktopRegion dirty;
176 MergeBlocks(&dirty);
177
178
179 DesktopRect expected_rect = DesktopRect::MakeXYWH(
180 x_origin * kBlockSize, y_origin * kBlockSize,
181 width * kBlockSize, height * kBlockSize);
182
183 // Verify that the region contains expected_rect and it's the only
184 // rectangle.
185 DesktopRegion::Iterator it(dirty);
186 return !it.IsAtEnd() && expected_rect.equals(it.rect()) &&
187 (it.Advance(), it.IsAtEnd());
188 }
189
190 // The differ class we're testing.
191 scoped_ptr<Differ> differ_;
192
193 // Screen/buffer info.
194 int width_;
195 int height_;
196 int bytes_per_pixel_;
197 int stride_;
198
199 // Size of each screen buffer.
200 int buffer_size_;
201
202 // Previous and current screen buffers.
203 scoped_array<uint8_t> prev_;
204 scoped_array<uint8_t> curr_;
205
206 private:
207 DISALLOW_COPY_AND_ASSIGN(DifferTest);
208};
209
210TEST_F(DifferTest, Setup) {
211 InitDiffer(kScreenWidth, kScreenHeight);
212 // 96x96 pixels results in 3x3 array. Add 1 to each dimension as boundary.
213 // +---+---+---+---+
214 // | o | o | o | _ |
215 // +---+---+---+---+ o = blocks mapped to screen pixels
216 // | o | o | o | _ |
217 // +---+---+---+---+ _ = boundary blocks
218 // | o | o | o | _ |
219 // +---+---+---+---+
220 // | _ | _ | _ | _ |
221 // +---+---+---+---+
222 EXPECT_EQ(4, GetDiffInfoWidth());
223 EXPECT_EQ(4, GetDiffInfoHeight());
224 EXPECT_EQ(16, GetDiffInfoSize());
225}
226
227TEST_F(DifferTest, MarkDirtyBlocks_All) {
228 InitDiffer(kScreenWidth, kScreenHeight);
229 ClearDiffInfo();
230
231 // Update a pixel in each block.
232 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
233 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
234 WriteBlockPixel(curr_.get(), x, y, 10, 10, 0xff00ff);
235 }
236 }
237
238 MarkDirtyBlocks(prev_.get(), curr_.get());
239
240 // Make sure each block is marked as dirty.
241 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
242 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
243 EXPECT_EQ(1, GetDiffInfo(x, y))
244 << "when x = " << x << ", and y = " << y;
245 }
246 }
247}
248
249TEST_F(DifferTest, MarkDirtyBlocks_Sampling) {
250 InitDiffer(kScreenWidth, kScreenHeight);
251 ClearDiffInfo();
252
253 // Update some pixels in image.
254 WriteBlockPixel(curr_.get(), 1, 0, 10, 10, 0xff00ff);
255 WriteBlockPixel(curr_.get(), 2, 1, 10, 10, 0xff00ff);
256 WriteBlockPixel(curr_.get(), 0, 2, 10, 10, 0xff00ff);
257
258 MarkDirtyBlocks(prev_.get(), curr_.get());
259
260 // Make sure corresponding blocks are updated.
261 EXPECT_EQ(0, GetDiffInfo(0, 0));
262 EXPECT_EQ(0, GetDiffInfo(0, 1));
263 EXPECT_EQ(1, GetDiffInfo(0, 2));
264 EXPECT_EQ(1, GetDiffInfo(1, 0));
265 EXPECT_EQ(0, GetDiffInfo(1, 1));
266 EXPECT_EQ(0, GetDiffInfo(1, 2));
267 EXPECT_EQ(0, GetDiffInfo(2, 0));
268 EXPECT_EQ(1, GetDiffInfo(2, 1));
269 EXPECT_EQ(0, GetDiffInfo(2, 2));
270}
271
272TEST_F(DifferTest, DiffBlock) {
273 InitDiffer(kScreenWidth, kScreenHeight);
274
275 // Verify no differences at start.
276 EXPECT_EQ(0, DiffBlock(0, 0));
277 EXPECT_EQ(0, DiffBlock(1, 1));
278
279 // Write new data into the 4 corners of the middle block and verify that
280 // neighboring blocks are not affected.
281 int max = kBlockSize - 1;
282 WriteBlockPixel(curr_.get(), 1, 1, 0, 0, 0xffffff);
283 WriteBlockPixel(curr_.get(), 1, 1, 0, max, 0xffffff);
284 WriteBlockPixel(curr_.get(), 1, 1, max, 0, 0xffffff);
285 WriteBlockPixel(curr_.get(), 1, 1, max, max, 0xffffff);
286 EXPECT_EQ(0, DiffBlock(0, 0));
287 EXPECT_EQ(0, DiffBlock(0, 1));
288 EXPECT_EQ(0, DiffBlock(0, 2));
289 EXPECT_EQ(0, DiffBlock(1, 0));
290 EXPECT_EQ(1, DiffBlock(1, 1)); // Only this block should change.
291 EXPECT_EQ(0, DiffBlock(1, 2));
292 EXPECT_EQ(0, DiffBlock(2, 0));
293 EXPECT_EQ(0, DiffBlock(2, 1));
294 EXPECT_EQ(0, DiffBlock(2, 2));
295}
296
297TEST_F(DifferTest, Partial_Setup) {
298 InitDiffer(kPartialScreenWidth, kPartialScreenHeight);
299 // 70x70 pixels results in 3x3 array: 2x2 full blocks + partials around
300 // the edge. One more is added to each dimension as a boundary.
301 // +---+---+---+---+
302 // | o | o | + | _ |
303 // +---+---+---+---+ o = blocks mapped to screen pixels
304 // | o | o | + | _ |
305 // +---+---+---+---+ + = partial blocks (top/left mapped to screen pixels)
306 // | + | + | + | _ |
307 // +---+---+---+---+ _ = boundary blocks
308 // | _ | _ | _ | _ |
309 // +---+---+---+---+
310 EXPECT_EQ(4, GetDiffInfoWidth());
311 EXPECT_EQ(4, GetDiffInfoHeight());
312 EXPECT_EQ(16, GetDiffInfoSize());
313}
314
315TEST_F(DifferTest, Partial_FirstPixel) {
316 InitDiffer(kPartialScreenWidth, kPartialScreenHeight);
317 ClearDiffInfo();
318
319 // Update the first pixel in each block.
320 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
321 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
322 WriteBlockPixel(curr_.get(), x, y, 0, 0, 0xff00ff);
323 }
324 }
325
326 MarkDirtyBlocks(prev_.get(), curr_.get());
327
328 // Make sure each block is marked as dirty.
329 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
330 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
331 EXPECT_EQ(1, GetDiffInfo(x, y))
332 << "when x = " << x << ", and y = " << y;
333 }
334 }
335}
336
337TEST_F(DifferTest, Partial_BorderPixel) {
338 InitDiffer(kPartialScreenWidth, kPartialScreenHeight);
339 ClearDiffInfo();
340
341 // Update the right/bottom border pixels.
342 for (int y = 0; y < height_; y++) {
343 WritePixel(curr_.get(), width_ - 1, y, 0xff00ff);
344 }
345 for (int x = 0; x < width_; x++) {
346 WritePixel(curr_.get(), x, height_ - 1, 0xff00ff);
347 }
348
349 MarkDirtyBlocks(prev_.get(), curr_.get());
350
351 // Make sure last (partial) block in each row/column is marked as dirty.
352 int x_last = GetDiffInfoWidth() - 2;
353 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
354 EXPECT_EQ(1, GetDiffInfo(x_last, y))
355 << "when x = " << x_last << ", and y = " << y;
356 }
357 int y_last = GetDiffInfoHeight() - 2;
358 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
359 EXPECT_EQ(1, GetDiffInfo(x, y_last))
360 << "when x = " << x << ", and y = " << y_last;
361 }
362 // All other blocks are clean.
363 for (int y = 0; y < GetDiffInfoHeight() - 2; y++) {
364 for (int x = 0; x < GetDiffInfoWidth() - 2; x++) {
365 EXPECT_EQ(0, GetDiffInfo(x, y)) << "when x = " << x << ", and y = " << y;
366 }
367 }
368}
369
370TEST_F(DifferTest, MergeBlocks_Empty) {
371 InitDiffer(kScreenWidth, kScreenHeight);
372
373 // No blocks marked:
374 // +---+---+---+---+
375 // | | | | _ |
376 // +---+---+---+---+
377 // | | | | _ |
378 // +---+---+---+---+
379 // | | | | _ |
380 // +---+---+---+---+
381 // | _ | _ | _ | _ |
382 // +---+---+---+---+
383 ClearDiffInfo();
384
385 DesktopRegion dirty;
386 MergeBlocks(&dirty);
387
388 EXPECT_TRUE(dirty.is_empty());
389}
390
391TEST_F(DifferTest, MergeBlocks_SingleBlock) {
392 InitDiffer(kScreenWidth, kScreenHeight);
393 // Mark a single block and make sure that there is a single merged
394 // rect with the correct bounds.
395 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
396 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
397 ASSERT_TRUE(MarkBlocksAndCheckMerge(x, y, 1, 1)) << "x: " << x
398 << "y: " << y;
399 }
400 }
401}
402
403TEST_F(DifferTest, MergeBlocks_BlockRow) {
404 InitDiffer(kScreenWidth, kScreenHeight);
405
406 // +---+---+---+---+
407 // | X | X | | _ |
408 // +---+---+---+---+
409 // | | | | _ |
410 // +---+---+---+---+
411 // | | | | _ |
412 // +---+---+---+---+
413 // | _ | _ | _ | _ |
414 // +---+---+---+---+
415 ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 2, 1));
416
417 // +---+---+---+---+
418 // | | | | _ |
419 // +---+---+---+---+
420 // | X | X | X | _ |
421 // +---+---+---+---+
422 // | | | | _ |
423 // +---+---+---+---+
424 // | _ | _ | _ | _ |
425 // +---+---+---+---+
426 ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 1, 3, 1));
427
428 // +---+---+---+---+
429 // | | | | _ |
430 // +---+---+---+---+
431 // | | | | _ |
432 // +---+---+---+---+
433 // | | X | X | _ |
434 // +---+---+---+---+
435 // | _ | _ | _ | _ |
436 // +---+---+---+---+
437 ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 2, 2, 1));
438}
439
440TEST_F(DifferTest, MergeBlocks_BlockColumn) {
441 InitDiffer(kScreenWidth, kScreenHeight);
442
443 // +---+---+---+---+
444 // | X | | | _ |
445 // +---+---+---+---+
446 // | X | | | _ |
447 // +---+---+---+---+
448 // | | | | _ |
449 // +---+---+---+---+
450 // | _ | _ | _ | _ |
451 // +---+---+---+---+
452 ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 1, 2));
453
454 // +---+---+---+---+
455 // | | | | _ |
456 // +---+---+---+---+
457 // | | X | | _ |
458 // +---+---+---+---+
459 // | | X | | _ |
460 // +---+---+---+---+
461 // | _ | _ | _ | _ |
462 // +---+---+---+---+
463 ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 1, 1, 2));
464
465 // +---+---+---+---+
466 // | | | X | _ |
467 // +---+---+---+---+
468 // | | | X | _ |
469 // +---+---+---+---+
470 // | | | X | _ |
471 // +---+---+---+---+
472 // | _ | _ | _ | _ |
473 // +---+---+---+---+
474 ASSERT_TRUE(MarkBlocksAndCheckMerge(2, 0, 1, 3));
475}
476
477TEST_F(DifferTest, MergeBlocks_BlockRect) {
478 InitDiffer(kScreenWidth, kScreenHeight);
479
480 // +---+---+---+---+
481 // | X | X | | _ |
482 // +---+---+---+---+
483 // | X | X | | _ |
484 // +---+---+---+---+
485 // | | | | _ |
486 // +---+---+---+---+
487 // | _ | _ | _ | _ |
488 // +---+---+---+---+
489 ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 2, 2));
490
491 // +---+---+---+---+
492 // | | | | _ |
493 // +---+---+---+---+
494 // | | X | X | _ |
495 // +---+---+---+---+
496 // | | X | X | _ |
497 // +---+---+---+---+
498 // | _ | _ | _ | _ |
499 // +---+---+---+---+
500 ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 1, 2, 2));
501
502 // +---+---+---+---+
503 // | | X | X | _ |
504 // +---+---+---+---+
505 // | | X | X | _ |
506 // +---+---+---+---+
507 // | | X | X | _ |
508 // +---+---+---+---+
509 // | _ | _ | _ | _ |
510 // +---+---+---+---+
511 ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 0, 2, 3));
512
513 // +---+---+---+---+
514 // | | | | _ |
515 // +---+---+---+---+
516 // | X | X | X | _ |
517 // +---+---+---+---+
518 // | X | X | X | _ |
519 // +---+---+---+---+
520 // | _ | _ | _ | _ |
521 // +---+---+---+---+
522 ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 1, 3, 2));
523
524 // +---+---+---+---+
525 // | X | X | X | _ |
526 // +---+---+---+---+
527 // | X | X | X | _ |
528 // +---+---+---+---+
529 // | X | X | X | _ |
530 // +---+---+---+---+
531 // | _ | _ | _ | _ |
532 // +---+---+---+---+
533 ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 3, 3));
534}
535
536// This tests marked regions that require more than 1 single dirty rect.
537// The exact rects returned depend on the current implementation, so these
538// may need to be updated if we modify how we merge blocks.
539TEST_F(DifferTest, MergeBlocks_MultiRect) {
540 InitDiffer(kScreenWidth, kScreenHeight);
541 DesktopRegion dirty;
542
543 // +---+---+---+---+ +---+---+---+
544 // | | X | | _ | | | 0 | |
545 // +---+---+---+---+ +---+---+---+
546 // | X | | | _ | | 1 | | |
547 // +---+---+---+---+ => +---+---+---+
548 // | | | X | _ | | | | 2 |
549 // +---+---+---+---+ +---+---+---+
550 // | _ | _ | _ | _ |
551 // +---+---+---+---+
552 ClearDiffInfo();
553 MarkBlocks(1, 0, 1, 1);
554 MarkBlocks(0, 1, 1, 1);
555 MarkBlocks(2, 2, 1, 1);
556
557 dirty.Clear();
558 MergeBlocks(&dirty);
559
560 ASSERT_EQ(3, RegionRectCount(dirty));
561 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 1, 0, 1, 1));
562 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 1, 1));
563 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 2, 1, 1));
564
565 // +---+---+---+---+ +---+---+---+
566 // | | | X | _ | | | | 0 |
567 // +---+---+---+---+ +---+---+---+
568 // | X | X | X | _ | | 1 1 1 |
569 // +---+---+---+---+ => + +
570 // | X | X | X | _ | | 1 1 1 |
571 // +---+---+---+---+ +---+---+---+
572 // | _ | _ | _ | _ |
573 // +---+---+---+---+
574 ClearDiffInfo();
575 MarkBlocks(2, 0, 1, 1);
576 MarkBlocks(0, 1, 3, 2);
577
578 dirty.Clear();
579 MergeBlocks(&dirty);
580
581 ASSERT_EQ(2, RegionRectCount(dirty));
582 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 0, 1, 1));
583 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 3, 2));
584
585 // +---+---+---+---+ +---+---+---+
586 // | | | | _ | | | | |
587 // +---+---+---+---+ +---+---+---+
588 // | X | | X | _ | | 0 | | 1 |
589 // +---+---+---+---+ => +---+---+---+
590 // | X | X | X | _ | | 2 2 2 |
591 // +---+---+---+---+ +---+---+---+
592 // | _ | _ | _ | _ |
593 // +---+---+---+---+
594 ClearDiffInfo();
595 MarkBlocks(0, 1, 1, 1);
596 MarkBlocks(2, 1, 1, 1);
597 MarkBlocks(0, 2, 3, 1);
598
599 dirty.Clear();
600 MergeBlocks(&dirty);
601
602 ASSERT_EQ(3, RegionRectCount(dirty));
603 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 1, 1));
604 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 1, 1, 1));
605 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 2, 3, 1));
606
607 // +---+---+---+---+ +---+---+---+
608 // | X | X | X | _ | | 0 0 0 |
609 // +---+---+---+---+ +---+---+---+
610 // | X | | X | _ | | 1 | | 2 |
611 // +---+---+---+---+ => +---+---+---+
612 // | X | X | X | _ | | 3 3 3 |
613 // +---+---+---+---+ +---+---+---+
614 // | _ | _ | _ | _ |
615 // +---+---+---+---+
616 ClearDiffInfo();
617 MarkBlocks(0, 0, 3, 1);
618 MarkBlocks(0, 1, 1, 1);
619 MarkBlocks(2, 1, 1, 1);
620 MarkBlocks(0, 2, 3, 1);
621
622 dirty.Clear();
623 MergeBlocks(&dirty);
624
625 ASSERT_EQ(4, RegionRectCount(dirty));
626 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 0, 3, 1));
627 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 1, 1));
628 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 1, 1, 1));
629 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 2, 3, 1));
630
631 // +---+---+---+---+ +---+---+---+
632 // | X | X | | _ | | 0 0 | |
633 // +---+---+---+---+ + +---+
634 // | X | X | | _ | | 0 0 | |
635 // +---+---+---+---+ => +---+---+---+
636 // | | X | | _ | | | 1 | |
637 // +---+---+---+---+ +---+---+---+
638 // | _ | _ | _ | _ |
639 // +---+---+---+---+
640 ClearDiffInfo();
641 MarkBlocks(0, 0, 2, 2);
642 MarkBlocks(1, 2, 1, 1);
643
644 dirty.Clear();
645 MergeBlocks(&dirty);
646
647 ASSERT_EQ(2, RegionRectCount(dirty));
648 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 0, 2, 2));
649 ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 1, 2, 1, 1));
650}
651
652} // namespace webrtc