| /* |
| * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include <memory> |
| |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "webrtc/base/constructormagic.h" |
| #include "webrtc/modules/desktop_capture/differ.h" |
| #include "webrtc/modules/desktop_capture/differ_block.h" |
| |
| namespace webrtc { |
| |
| // 96x96 screen gives a 4x4 grid of blocks. |
| const int kScreenWidth= 96; |
| const int kScreenHeight = 96; |
| |
| // To test partial blocks, we need a width and height that are not multiples |
| // of 16 (or 32, depending on current block size). |
| const int kPartialScreenWidth = 70; |
| const int kPartialScreenHeight = 70; |
| |
| class DifferTest : public testing::Test { |
| public: |
| DifferTest() { |
| } |
| |
| protected: |
| void InitDiffer(int width, int height) { |
| width_ = width; |
| height_ = height; |
| bytes_per_pixel_ = kBytesPerPixel; |
| stride_ = (kBytesPerPixel * width); |
| buffer_size_ = width_ * height_ * bytes_per_pixel_; |
| |
| differ_.reset(new Differ(width_, height_, bytes_per_pixel_, stride_)); |
| |
| prev_.reset(new uint8_t[buffer_size_]); |
| memset(prev_.get(), 0, buffer_size_); |
| |
| curr_.reset(new uint8_t[buffer_size_]); |
| memset(curr_.get(), 0, buffer_size_); |
| } |
| |
| void ClearBuffer(uint8_t* buffer) { |
| memset(buffer, 0, buffer_size_); |
| } |
| |
| // Here in DifferTest so that tests can access private methods of Differ. |
| void MarkDirtyBlocks(const uint8_t* prev_buffer, const uint8_t* curr_buffer) { |
| differ_->MarkDirtyBlocks(prev_buffer, curr_buffer); |
| } |
| |
| void MergeBlocks(DesktopRegion* dirty) { |
| differ_->MergeBlocks(dirty); |
| } |
| |
| // Convenience method to count rectangles in a region. |
| int RegionRectCount(const DesktopRegion& region) { |
| int count = 0; |
| for (DesktopRegion::Iterator iter(region); |
| !iter.IsAtEnd(); iter.Advance()) { |
| ++count; |
| } |
| return count; |
| } |
| |
| // Convenience wrapper for Differ's DiffBlock that calculates the appropriate |
| // offset to the start of the desired block. |
| bool DiffBlock(int block_x, int block_y) { |
| // Offset from upper-left of buffer to upper-left of requested block. |
| int block_offset = ((block_y * stride_) + (block_x * bytes_per_pixel_)) |
| * kBlockSize; |
| return BlockDifference(prev_.get() + block_offset, |
| curr_.get() + block_offset, |
| stride_); |
| } |
| |
| // Write the pixel |value| into the specified block in the |buffer|. |
| // This is a convenience wrapper around WritePixel(). |
| void WriteBlockPixel(uint8_t* buffer, int block_x, int block_y, |
| int pixel_x, int pixel_y, uint32_t value) { |
| WritePixel(buffer, (block_x * kBlockSize) + pixel_x, |
| (block_y * kBlockSize) + pixel_y, value); |
| } |
| |
| // Write the test pixel |value| into the |buffer| at the specified |x|,|y| |
| // location. |
| // Only the low-order bytes from |value| are written (assuming little-endian). |
| // So, for |value| = 0xaabbccdd: |
| // If bytes_per_pixel = 4, then ddccbbaa will be written as the pixel value. |
| // If = 3, ddccbb |
| // If = 2, ddcc |
| // If = 1, dd |
| void WritePixel(uint8_t* buffer, int x, int y, uint32_t value) { |
| uint8_t* pixel = reinterpret_cast<uint8_t*>(&value); |
| buffer += (y * stride_) + (x * bytes_per_pixel_); |
| for (int b = bytes_per_pixel_ - 1; b >= 0; b--) { |
| *buffer++ = pixel[b]; |
| } |
| } |
| |
| // DiffInfo utility routines. |
| // These are here so that we don't have to make each DifferText_Xxx_Test |
| // class a friend class to Differ. |
| |
| // Clear out the entire |diff_info_| buffer. |
| void ClearDiffInfo() { |
| memset(differ_->diff_info_.get(), 0, differ_->diff_info_size_); |
| } |
| |
| // Get the value in the |diff_info_| array at (x,y). |
| bool GetDiffInfo(int x, int y) { |
| bool* diff_info = differ_->diff_info_.get(); |
| return diff_info[(y * GetDiffInfoWidth()) + x]; |
| } |
| |
| // Width of |diff_info_| array. |
| int GetDiffInfoWidth() { |
| return differ_->diff_info_width_; |
| } |
| |
| // Height of |diff_info_| array. |
| int GetDiffInfoHeight() { |
| return differ_->diff_info_height_; |
| } |
| |
| // Size of |diff_info_| array. |
| int GetDiffInfoSize() { |
| return differ_->diff_info_size_; |
| } |
| |
| void SetDiffInfo(int x, int y, bool value) { |
| bool* diff_info = differ_->diff_info_.get(); |
| diff_info[(y * GetDiffInfoWidth()) + x] = value; |
| } |
| |
| // Mark the range of blocks specified. |
| void MarkBlocks(int x_origin, int y_origin, int width, int height) { |
| for (int y = 0; y < height; y++) { |
| for (int x = 0; x < width; x++) { |
| SetDiffInfo(x_origin + x, y_origin + y, true); |
| } |
| } |
| } |
| |
| // Verify that |region| contains a rectangle defined by |x|, |y|, |width| and |
| // |height|. |
| // |x|, |y|, |width| and |height| are specified in block (not pixel) units. |
| bool CheckDirtyRegionContainsRect(const DesktopRegion& region, |
| int x, int y, |
| int width, int height) { |
| DesktopRect r = |
| DesktopRect::MakeXYWH(x * kBlockSize, y * kBlockSize, |
| width * kBlockSize, height * kBlockSize); |
| for (DesktopRegion::Iterator i(region); !i.IsAtEnd(); i.Advance()) { |
| if (i.rect().equals(r)) |
| return true; |
| } |
| return false; |
| } |
| |
| // Mark the range of blocks specified and then verify that they are |
| // merged correctly. |
| // Only one rectangular region of blocks can be checked with this routine. |
| bool MarkBlocksAndCheckMerge(int x_origin, int y_origin, |
| int width, int height) { |
| ClearDiffInfo(); |
| MarkBlocks(x_origin, y_origin, width, height); |
| |
| DesktopRegion dirty; |
| MergeBlocks(&dirty); |
| |
| |
| DesktopRect expected_rect = DesktopRect::MakeXYWH( |
| x_origin * kBlockSize, y_origin * kBlockSize, |
| width * kBlockSize, height * kBlockSize); |
| |
| // Verify that the region contains expected_rect and it's the only |
| // rectangle. |
| DesktopRegion::Iterator it(dirty); |
| return !it.IsAtEnd() && expected_rect.equals(it.rect()) && |
| (it.Advance(), it.IsAtEnd()); |
| } |
| |
| // The differ class we're testing. |
| std::unique_ptr<Differ> differ_; |
| |
| // Screen/buffer info. |
| int width_; |
| int height_; |
| int bytes_per_pixel_; |
| int stride_; |
| |
| // Size of each screen buffer. |
| int buffer_size_; |
| |
| // Previous and current screen buffers. |
| std::unique_ptr<uint8_t[]> prev_; |
| std::unique_ptr<uint8_t[]> curr_; |
| |
| private: |
| RTC_DISALLOW_COPY_AND_ASSIGN(DifferTest); |
| }; |
| |
| TEST_F(DifferTest, Setup) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| // 96x96 pixels results in 3x3 array. Add 1 to each dimension as boundary. |
| // +---+---+---+---+ |
| // | o | o | o | _ | |
| // +---+---+---+---+ o = blocks mapped to screen pixels |
| // | o | o | o | _ | |
| // +---+---+---+---+ _ = boundary blocks |
| // | o | o | o | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| EXPECT_EQ(4, GetDiffInfoWidth()); |
| EXPECT_EQ(4, GetDiffInfoHeight()); |
| EXPECT_EQ(16, GetDiffInfoSize()); |
| } |
| |
| TEST_F(DifferTest, MarkDirtyBlocks_All) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| ClearDiffInfo(); |
| |
| // Update a pixel in each block. |
| for (int y = 0; y < GetDiffInfoHeight() - 1; y++) { |
| for (int x = 0; x < GetDiffInfoWidth() - 1; x++) { |
| WriteBlockPixel(curr_.get(), x, y, 10, 10, 0xff00ff); |
| } |
| } |
| |
| MarkDirtyBlocks(prev_.get(), curr_.get()); |
| |
| // Make sure each block is marked as dirty. |
| for (int y = 0; y < GetDiffInfoHeight() - 1; y++) { |
| for (int x = 0; x < GetDiffInfoWidth() - 1; x++) { |
| EXPECT_TRUE(GetDiffInfo(x, y)) |
| << "when x = " << x << ", and y = " << y; |
| } |
| } |
| } |
| |
| TEST_F(DifferTest, MarkDirtyBlocks_Sampling) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| ClearDiffInfo(); |
| |
| // Update some pixels in image. |
| WriteBlockPixel(curr_.get(), 1, 0, 10, 10, 0xff00ff); |
| WriteBlockPixel(curr_.get(), 2, 1, 10, 10, 0xff00ff); |
| WriteBlockPixel(curr_.get(), 0, 2, 10, 10, 0xff00ff); |
| |
| MarkDirtyBlocks(prev_.get(), curr_.get()); |
| |
| // Make sure corresponding blocks are updated. |
| EXPECT_FALSE(GetDiffInfo(0, 0)); |
| EXPECT_FALSE(GetDiffInfo(0, 1)); |
| EXPECT_TRUE(GetDiffInfo(0, 2)); |
| EXPECT_TRUE(GetDiffInfo(1, 0)); |
| EXPECT_FALSE(GetDiffInfo(1, 1)); |
| EXPECT_FALSE(GetDiffInfo(1, 2)); |
| EXPECT_FALSE(GetDiffInfo(2, 0)); |
| EXPECT_TRUE(GetDiffInfo(2, 1)); |
| EXPECT_FALSE(GetDiffInfo(2, 2)); |
| } |
| |
| TEST_F(DifferTest, DiffBlock) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| |
| // Verify no differences at start. |
| EXPECT_FALSE(DiffBlock(0, 0)); |
| EXPECT_FALSE(DiffBlock(1, 1)); |
| |
| // Write new data into the 4 corners of the middle block and verify that |
| // neighboring blocks are not affected. |
| int max = kBlockSize - 1; |
| WriteBlockPixel(curr_.get(), 1, 1, 0, 0, 0xffffff); |
| WriteBlockPixel(curr_.get(), 1, 1, 0, max, 0xffffff); |
| WriteBlockPixel(curr_.get(), 1, 1, max, 0, 0xffffff); |
| WriteBlockPixel(curr_.get(), 1, 1, max, max, 0xffffff); |
| EXPECT_FALSE(DiffBlock(0, 0)); |
| EXPECT_FALSE(DiffBlock(0, 1)); |
| EXPECT_FALSE(DiffBlock(0, 2)); |
| EXPECT_FALSE(DiffBlock(1, 0)); |
| EXPECT_TRUE(DiffBlock(1, 1)); // Only this block should change. |
| EXPECT_FALSE(DiffBlock(1, 2)); |
| EXPECT_FALSE(DiffBlock(2, 0)); |
| EXPECT_FALSE(DiffBlock(2, 1)); |
| EXPECT_FALSE(DiffBlock(2, 2)); |
| } |
| |
| TEST_F(DifferTest, Partial_Setup) { |
| InitDiffer(kPartialScreenWidth, kPartialScreenHeight); |
| // 70x70 pixels results in 3x3 array: 2x2 full blocks + partials around |
| // the edge. One more is added to each dimension as a boundary. |
| // +---+---+---+---+ |
| // | o | o | + | _ | |
| // +---+---+---+---+ o = blocks mapped to screen pixels |
| // | o | o | + | _ | |
| // +---+---+---+---+ + = partial blocks (top/left mapped to screen pixels) |
| // | + | + | + | _ | |
| // +---+---+---+---+ _ = boundary blocks |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| EXPECT_EQ(4, GetDiffInfoWidth()); |
| EXPECT_EQ(4, GetDiffInfoHeight()); |
| EXPECT_EQ(16, GetDiffInfoSize()); |
| } |
| |
| TEST_F(DifferTest, Partial_FirstPixel) { |
| InitDiffer(kPartialScreenWidth, kPartialScreenHeight); |
| ClearDiffInfo(); |
| |
| // Update the first pixel in each block. |
| for (int y = 0; y < GetDiffInfoHeight() - 1; y++) { |
| for (int x = 0; x < GetDiffInfoWidth() - 1; x++) { |
| WriteBlockPixel(curr_.get(), x, y, 0, 0, 0xff00ff); |
| } |
| } |
| |
| MarkDirtyBlocks(prev_.get(), curr_.get()); |
| |
| // Make sure each block is marked as dirty. |
| for (int y = 0; y < GetDiffInfoHeight() - 1; y++) { |
| for (int x = 0; x < GetDiffInfoWidth() - 1; x++) { |
| EXPECT_TRUE(GetDiffInfo(x, y)) |
| << "when x = " << x << ", and y = " << y; |
| } |
| } |
| } |
| |
| TEST_F(DifferTest, Partial_BorderPixel) { |
| InitDiffer(kPartialScreenWidth, kPartialScreenHeight); |
| ClearDiffInfo(); |
| |
| // Update the right/bottom border pixels. |
| for (int y = 0; y < height_; y++) { |
| WritePixel(curr_.get(), width_ - 1, y, 0xff00ff); |
| } |
| for (int x = 0; x < width_; x++) { |
| WritePixel(curr_.get(), x, height_ - 1, 0xff00ff); |
| } |
| |
| MarkDirtyBlocks(prev_.get(), curr_.get()); |
| |
| // Make sure last (partial) block in each row/column is marked as dirty. |
| int x_last = GetDiffInfoWidth() - 2; |
| for (int y = 0; y < GetDiffInfoHeight() - 1; y++) { |
| EXPECT_TRUE(GetDiffInfo(x_last, y)) |
| << "when x = " << x_last << ", and y = " << y; |
| } |
| int y_last = GetDiffInfoHeight() - 2; |
| for (int x = 0; x < GetDiffInfoWidth() - 1; x++) { |
| EXPECT_TRUE(GetDiffInfo(x, y_last)) |
| << "when x = " << x << ", and y = " << y_last; |
| } |
| // All other blocks are clean. |
| for (int y = 0; y < GetDiffInfoHeight() - 2; y++) { |
| for (int x = 0; x < GetDiffInfoWidth() - 2; x++) { |
| EXPECT_FALSE(GetDiffInfo(x, y)) << "when x = " << x << ", and y = " << y; |
| } |
| } |
| } |
| |
| TEST_F(DifferTest, MergeBlocks_Empty) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| |
| // No blocks marked: |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ClearDiffInfo(); |
| |
| DesktopRegion dirty; |
| MergeBlocks(&dirty); |
| |
| EXPECT_TRUE(dirty.is_empty()); |
| } |
| |
| TEST_F(DifferTest, MergeBlocks_SingleBlock) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| // Mark a single block and make sure that there is a single merged |
| // rect with the correct bounds. |
| for (int y = 0; y < GetDiffInfoHeight() - 1; y++) { |
| for (int x = 0; x < GetDiffInfoWidth() - 1; x++) { |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(x, y, 1, 1)) << "x: " << x |
| << "y: " << y; |
| } |
| } |
| } |
| |
| TEST_F(DifferTest, MergeBlocks_BlockRow) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| |
| // +---+---+---+---+ |
| // | X | X | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 2, 1)); |
| |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | X | X | X | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 1, 3, 1)); |
| |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | X | X | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 2, 2, 1)); |
| } |
| |
| TEST_F(DifferTest, MergeBlocks_BlockColumn) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| |
| // +---+---+---+---+ |
| // | X | | | _ | |
| // +---+---+---+---+ |
| // | X | | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 1, 2)); |
| |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | X | | _ | |
| // +---+---+---+---+ |
| // | | X | | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 1, 1, 2)); |
| |
| // +---+---+---+---+ |
| // | | | X | _ | |
| // +---+---+---+---+ |
| // | | | X | _ | |
| // +---+---+---+---+ |
| // | | | X | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(2, 0, 1, 3)); |
| } |
| |
| TEST_F(DifferTest, MergeBlocks_BlockRect) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| |
| // +---+---+---+---+ |
| // | X | X | | _ | |
| // +---+---+---+---+ |
| // | X | X | | _ | |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 2, 2)); |
| |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | | X | X | _ | |
| // +---+---+---+---+ |
| // | | X | X | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 1, 2, 2)); |
| |
| // +---+---+---+---+ |
| // | | X | X | _ | |
| // +---+---+---+---+ |
| // | | X | X | _ | |
| // +---+---+---+---+ |
| // | | X | X | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(1, 0, 2, 3)); |
| |
| // +---+---+---+---+ |
| // | | | | _ | |
| // +---+---+---+---+ |
| // | X | X | X | _ | |
| // +---+---+---+---+ |
| // | X | X | X | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 1, 3, 2)); |
| |
| // +---+---+---+---+ |
| // | X | X | X | _ | |
| // +---+---+---+---+ |
| // | X | X | X | _ | |
| // +---+---+---+---+ |
| // | X | X | X | _ | |
| // +---+---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ASSERT_TRUE(MarkBlocksAndCheckMerge(0, 0, 3, 3)); |
| } |
| |
| // This tests marked regions that require more than 1 single dirty rect. |
| // The exact rects returned depend on the current implementation, so these |
| // may need to be updated if we modify how we merge blocks. |
| TEST_F(DifferTest, MergeBlocks_MultiRect) { |
| InitDiffer(kScreenWidth, kScreenHeight); |
| DesktopRegion dirty; |
| |
| // +---+---+---+---+ +---+---+---+ |
| // | | X | | _ | | | 0 | | |
| // +---+---+---+---+ +---+---+---+ |
| // | X | | | _ | | 1 | | | |
| // +---+---+---+---+ => +---+---+---+ |
| // | | | X | _ | | | | 2 | |
| // +---+---+---+---+ +---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ClearDiffInfo(); |
| MarkBlocks(1, 0, 1, 1); |
| MarkBlocks(0, 1, 1, 1); |
| MarkBlocks(2, 2, 1, 1); |
| |
| dirty.Clear(); |
| MergeBlocks(&dirty); |
| |
| ASSERT_EQ(3, RegionRectCount(dirty)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 1, 0, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 2, 1, 1)); |
| |
| // +---+---+---+---+ +---+---+---+ |
| // | | | X | _ | | | | 0 | |
| // +---+---+---+---+ +---+---+---+ |
| // | X | X | X | _ | | 1 1 1 | |
| // +---+---+---+---+ => + + |
| // | X | X | X | _ | | 1 1 1 | |
| // +---+---+---+---+ +---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ClearDiffInfo(); |
| MarkBlocks(2, 0, 1, 1); |
| MarkBlocks(0, 1, 3, 2); |
| |
| dirty.Clear(); |
| MergeBlocks(&dirty); |
| |
| ASSERT_EQ(2, RegionRectCount(dirty)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 0, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 3, 2)); |
| |
| // +---+---+---+---+ +---+---+---+ |
| // | | | | _ | | | | | |
| // +---+---+---+---+ +---+---+---+ |
| // | X | | X | _ | | 0 | | 1 | |
| // +---+---+---+---+ => +---+---+---+ |
| // | X | X | X | _ | | 2 2 2 | |
| // +---+---+---+---+ +---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ClearDiffInfo(); |
| MarkBlocks(0, 1, 1, 1); |
| MarkBlocks(2, 1, 1, 1); |
| MarkBlocks(0, 2, 3, 1); |
| |
| dirty.Clear(); |
| MergeBlocks(&dirty); |
| |
| ASSERT_EQ(3, RegionRectCount(dirty)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 1, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 2, 3, 1)); |
| |
| // +---+---+---+---+ +---+---+---+ |
| // | X | X | X | _ | | 0 0 0 | |
| // +---+---+---+---+ +---+---+---+ |
| // | X | | X | _ | | 1 | | 2 | |
| // +---+---+---+---+ => +---+---+---+ |
| // | X | X | X | _ | | 3 3 3 | |
| // +---+---+---+---+ +---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ClearDiffInfo(); |
| MarkBlocks(0, 0, 3, 1); |
| MarkBlocks(0, 1, 1, 1); |
| MarkBlocks(2, 1, 1, 1); |
| MarkBlocks(0, 2, 3, 1); |
| |
| dirty.Clear(); |
| MergeBlocks(&dirty); |
| |
| ASSERT_EQ(4, RegionRectCount(dirty)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 0, 3, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 1, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 2, 1, 1, 1)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 2, 3, 1)); |
| |
| // +---+---+---+---+ +---+---+---+ |
| // | X | X | | _ | | 0 0 | | |
| // +---+---+---+---+ + +---+ |
| // | X | X | | _ | | 0 0 | | |
| // +---+---+---+---+ => +---+---+---+ |
| // | | X | | _ | | | 1 | | |
| // +---+---+---+---+ +---+---+---+ |
| // | _ | _ | _ | _ | |
| // +---+---+---+---+ |
| ClearDiffInfo(); |
| MarkBlocks(0, 0, 2, 2); |
| MarkBlocks(1, 2, 1, 1); |
| |
| dirty.Clear(); |
| MergeBlocks(&dirty); |
| |
| ASSERT_EQ(2, RegionRectCount(dirty)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 0, 0, 2, 2)); |
| ASSERT_TRUE(CheckDirtyRegionContainsRect(dirty, 1, 2, 1, 1)); |
| } |
| |
| } // namespace webrtc |