| Index: remoting/host/differ_unittest.cc
|
| ===================================================================
|
| --- remoting/host/differ_unittest.cc (revision 0)
|
| +++ remoting/host/differ_unittest.cc (revision 0)
|
| @@ -0,0 +1,530 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/scoped_ptr.h"
|
| +#include "remoting/host/differ.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +
|
| +namespace remoting {
|
| +
|
| +// 96x96 screen gives a 3x3 grid of blocks.
|
| +const int kScreenWidth = 96;
|
| +const int kScreenHeight = 96;
|
| +const int kBytesPerPixel = 3;
|
| +
|
| +class DifferTest : public testing::Test {
|
| + public:
|
| + DifferTest() {
|
| + }
|
| +
|
| + protected:
|
| + virtual void SetUp() {
|
| + InitDiffer(kScreenWidth, kScreenHeight, kBytesPerPixel);
|
| + }
|
| +
|
| + void InitDiffer(int width, int height, int bpp) {
|
| + width_ = width;
|
| + height_ = height;
|
| + bytes_per_pixel_ = bpp;
|
| +
|
| + stride_ = width_ * bytes_per_pixel_;
|
| + buffer_size_ = width_ * height_ * bytes_per_pixel_;
|
| +
|
| + differ_.reset(new Differ(width_, height_, bytes_per_pixel_));
|
| +
|
| + prev_.reset(new uint8[buffer_size_]);
|
| + memset(prev_.get(), 0, buffer_size_);
|
| +
|
| + curr_.reset(new uint8[buffer_size_]);
|
| + memset(curr_.get(), 0, buffer_size_);
|
| + }
|
| +
|
| + void ClearBuffer(uint8* buffer) {
|
| + memset(buffer, 0, buffer_size_);
|
| + }
|
| +
|
| + // Convenience wrapper for Differ's DiffBlock that calculates the appropriate
|
| + // offset to the start of the desired block.
|
| + DiffInfo 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;
|
| + differ_->DiffBlock(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* buffer, int block_x, int block_y,
|
| + int pixel_x, int pixel_y, uint32 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* buffer, int x, int y, uint32 value) {
|
| + uint8* pixel = reinterpret_cast<uint8*>(&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).
|
| + DiffInfo GetDiffInfo(int x, int y) {
|
| + DiffInfo* 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, const DiffInfo& value) {
|
| + DiffInfo* 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, 1);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Verify that the given dirty rect matches the expected |x|, |y|, |width|
|
| + // and |height|.
|
| + // |x|, |y|, |width| and |height| are specified in block (not pixel) units.
|
| + void CheckDirtyRect(const gfx::Rect& rect, int x, int y,
|
| + int width, int height) {
|
| + EXPECT_EQ(x * kBlockSize, rect.x());
|
| + EXPECT_EQ(y * kBlockSize, rect.y());
|
| + EXPECT_EQ(width * kBlockSize, rect.width());
|
| + EXPECT_EQ(height * kBlockSize, rect.height());
|
| + }
|
| +
|
| + // 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.
|
| + void MarkBlocksAndCheckMerge(int x_origin, int y_origin,
|
| + int width, int height) {
|
| + ClearDiffInfo();
|
| + MarkBlocks(x_origin, y_origin, width, height);
|
| +
|
| + DirtyRects* dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + ASSERT_EQ(1, dirty->size());
|
| + CheckDirtyRect(dirty->at(0), x_origin, y_origin, width, height);
|
| + }
|
| +
|
| + // The differ class we're testing.
|
| + scoped_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.
|
| + scoped_ptr<uint8> prev_;
|
| + scoped_ptr<uint8> curr_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(DifferTest);
|
| +};
|
| +
|
| +TEST_F(DifferTest, Setup) {
|
| + // 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) {
|
| + 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);
|
| + }
|
| + }
|
| +
|
| + differ_->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_EQ(1, GetDiffInfo(x, y))
|
| + << "when x = " << x << ", and y = " << y;
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(DifferTest, MarkDirtyBlocks_Sampling) {
|
| + 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);
|
| +
|
| + differ_->MarkDirtyBlocks(prev_.get(), curr_.get());
|
| +
|
| + // Make sure corresponding blocks are updated.
|
| + EXPECT_EQ(0, GetDiffInfo(0, 0));
|
| + EXPECT_EQ(0, GetDiffInfo(0, 1));
|
| + EXPECT_EQ(1, GetDiffInfo(0, 2));
|
| + EXPECT_EQ(1, GetDiffInfo(1, 0));
|
| + EXPECT_EQ(0, GetDiffInfo(1, 1));
|
| + EXPECT_EQ(0, GetDiffInfo(1, 2));
|
| + EXPECT_EQ(0, GetDiffInfo(2, 0));
|
| + EXPECT_EQ(1, GetDiffInfo(2, 1));
|
| + EXPECT_EQ(0, GetDiffInfo(2, 2));
|
| +}
|
| +
|
| +TEST_F(DifferTest, DiffBlock) {
|
| + // Verify no differences at start.
|
| + EXPECT_EQ(0, DiffBlock(0, 0));
|
| + EXPECT_EQ(0, 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_EQ(0, DiffBlock(0, 0));
|
| + EXPECT_EQ(0, DiffBlock(0, 1));
|
| + EXPECT_EQ(0, DiffBlock(0, 2));
|
| + EXPECT_EQ(0, DiffBlock(1, 0));
|
| + EXPECT_EQ(1, DiffBlock(1, 1)); // Only this block should change.
|
| + EXPECT_EQ(0, DiffBlock(1, 2));
|
| + EXPECT_EQ(0, DiffBlock(2, 0));
|
| + EXPECT_EQ(0, DiffBlock(2, 1));
|
| + EXPECT_EQ(0, DiffBlock(2, 2));
|
| +}
|
| +
|
| +TEST_F(DifferTest, DiffPartialBlocks) {
|
| + // TODO(garykac): Add tests for DiffPartialBlock
|
| +}
|
| +
|
| +
|
| +TEST_F(DifferTest, MergeBlocks_Empty) {
|
| + // No blocks marked:
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + ClearDiffInfo();
|
| +
|
| + DirtyRects* dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + EXPECT_EQ(0, dirty->size());
|
| +}
|
| +
|
| +TEST_F(DifferTest, MergeBlocks_SingleBlock) {
|
| + // 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++) {
|
| + MarkBlocksAndCheckMerge(x, y, 1, 1);
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST_F(DifferTest, MergeBlocks_BlockRow) {
|
| + // +---+---+---+---+
|
| + // | X | X | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(0, 0, 2, 1);
|
| +
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | X | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(0, 1, 3, 1);
|
| +
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(1, 2, 2, 1);
|
| +}
|
| +
|
| +TEST_F(DifferTest, MergeBlocks_BlockColumn) {
|
| + // +---+---+---+---+
|
| + // | X | | | _ |
|
| + // +---+---+---+---+
|
| + // | X | | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(0, 0, 1, 2);
|
| +
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | X | | _ |
|
| + // +---+---+---+---+
|
| + // | | X | | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(1, 1, 1, 2);
|
| +
|
| + // +---+---+---+---+
|
| + // | | | X | _ |
|
| + // +---+---+---+---+
|
| + // | | | X | _ |
|
| + // +---+---+---+---+
|
| + // | | | X | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(2, 0, 1, 3);
|
| +}
|
| +
|
| +TEST_F(DifferTest, MergeBlocks_BlockRect) {
|
| + // +---+---+---+---+
|
| + // | X | X | | _ |
|
| + // +---+---+---+---+
|
| + // | X | X | | _ |
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(0, 0, 2, 2);
|
| +
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(1, 1, 2, 2);
|
| +
|
| + // +---+---+---+---+
|
| + // | | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(1, 0, 2, 3);
|
| +
|
| + // +---+---+---+---+
|
| + // | | | | _ |
|
| + // +---+---+---+---+
|
| + // | X | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | X | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + MarkBlocksAndCheckMerge(0, 1, 3, 2);
|
| +
|
| + // +---+---+---+---+
|
| + // | X | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | X | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | X | X | X | _ |
|
| + // +---+---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + 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) {
|
| + DirtyRects* dirty;
|
| +
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | | X | | _ | | | 0 | |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | X | | | _ | | 1 | | |
|
| + // +---+---+---+---+ => +---+---+---+
|
| + // | | | X | _ | | | | 2 |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + ClearDiffInfo();
|
| + MarkBlocks(1, 0, 1, 1);
|
| + MarkBlocks(0, 1, 1, 1);
|
| + MarkBlocks(2, 2, 1, 1);
|
| +
|
| + dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + ASSERT_EQ(3, dirty->size());
|
| + CheckDirtyRect(dirty->at(0), 1, 0, 1, 1);
|
| + CheckDirtyRect(dirty->at(1), 0, 1, 1, 1);
|
| + CheckDirtyRect(dirty->at(2), 2, 2, 1, 1);
|
| +
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | | | X | _ | | | | 0 |
|
| + // +---+---+---+---+ +---+---+ +
|
| + // | X | X | X | _ | | 1 1 | 0 |
|
| + // +---+---+---+---+ => + + +
|
| + // | X | X | X | _ | | 1 1 | 0 |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + ClearDiffInfo();
|
| + MarkBlocks(2, 0, 1, 3);
|
| + MarkBlocks(0, 1, 2, 2);
|
| +
|
| + dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + ASSERT_EQ(2, dirty->size());
|
| + CheckDirtyRect(dirty->at(0), 2, 0, 1, 3);
|
| + CheckDirtyRect(dirty->at(1), 0, 1, 2, 2);
|
| +
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | | | | _ | | | | |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | X | | X | _ | | 0 | | 1 |
|
| + // +---+---+---+---+ => + +---+ +
|
| + // | X | X | X | _ | | 0 | 2 | 1 |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + ClearDiffInfo();
|
| + MarkBlocks(0, 1, 1, 1);
|
| + MarkBlocks(2, 1, 1, 1);
|
| + MarkBlocks(0, 2, 3, 1);
|
| +
|
| + dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + ASSERT_EQ(3, dirty->size());
|
| + CheckDirtyRect(dirty->at(0), 0, 1, 1, 2);
|
| + CheckDirtyRect(dirty->at(1), 2, 1, 1, 2);
|
| + CheckDirtyRect(dirty->at(2), 1, 2, 1, 1);
|
| +
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | X | X | X | _ | | 0 0 0 |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | X | | X | _ | | 1 | | 2 |
|
| + // +---+---+---+---+ => + +---+ +
|
| + // | X | X | X | _ | | 1 | 3 | 2 |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + ClearDiffInfo();
|
| + MarkBlocks(0, 0, 3, 1);
|
| + MarkBlocks(0, 1, 1, 1);
|
| + MarkBlocks(2, 1, 1, 1);
|
| + MarkBlocks(0, 2, 3, 1);
|
| +
|
| + dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + ASSERT_EQ(4, dirty->size());
|
| + CheckDirtyRect(dirty->at(0), 0, 0, 3, 1);
|
| + CheckDirtyRect(dirty->at(1), 0, 1, 1, 2);
|
| + CheckDirtyRect(dirty->at(2), 2, 1, 1, 2);
|
| + CheckDirtyRect(dirty->at(3), 1, 2, 1, 1);
|
| +
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | X | X | | _ | | 0 0 | |
|
| + // +---+---+---+---+ + +---+
|
| + // | X | X | | _ | | 0 0 | |
|
| + // +---+---+---+---+ => +---+---+---+
|
| + // | | X | | _ | | | 1 | |
|
| + // +---+---+---+---+ +---+---+---+
|
| + // | _ | _ | _ | _ |
|
| + // +---+---+---+---+
|
| + ClearDiffInfo();
|
| + MarkBlocks(0, 0, 2, 2);
|
| + MarkBlocks(1, 2, 1, 1);
|
| +
|
| + dirty = new DirtyRects();
|
| + differ_->MergeBlocks(dirty);
|
| +
|
| + ASSERT_EQ(2, dirty->size());
|
| + CheckDirtyRect(dirty->at(0), 0, 0, 2, 2);
|
| + CheckDirtyRect(dirty->at(1), 1, 2, 1, 1);
|
| +}
|
| +
|
| +} // namespace remoting
|
|
|
| Property changes on: remoting/host/differ_unittest.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|