Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / desktop_capture / differ_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 "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
16 namespace webrtc {
17
18 // 96x96 screen gives a 4x4 grid of blocks.
19 const int kScreenWidth= 96;
20 const 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).
24 const int kPartialScreenWidth = 70;
25 const int kPartialScreenHeight = 70;
26
27 class 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_ptr<uint8_t[]> prev_;
204   scoped_ptr<uint8_t[]> curr_;
205
206  private:
207   DISALLOW_COPY_AND_ASSIGN(DifferTest);
208 };
209
210 TEST_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
227 TEST_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
249 TEST_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
272 TEST_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
297 TEST_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
315 TEST_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
337 TEST_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
370 TEST_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
391 TEST_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
403 TEST_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
440 TEST_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
477 TEST_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.
539 TEST_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