Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <algorithm>
      6 
      7 #include "remoting/base/util.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 #include "third_party/libyuv/include/libyuv/convert_from_argb.h"
     10 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
     11 
     12 static const int kWidth = 32 ;
     13 static const int kHeight = 24 ;
     14 static const int kBytesPerPixel = 4;
     15 static const int kYStride = kWidth;
     16 static const int kUvStride = kWidth / 2;
     17 static const int kRgbStride = kWidth * kBytesPerPixel;
     18 static const uint32 kFillColor = 0xffffff;
     19 
     20 namespace remoting {
     21 
     22 class YuvToRgbTester {
     23  public:
     24   YuvToRgbTester() {
     25     yuv_buffer_size_ = (kYStride + kUvStride) * kHeight;
     26     yuv_buffer_.reset(new uint8[yuv_buffer_size_]);
     27     yplane_ = yuv_buffer_.get();
     28     uplane_ = yplane_ + (kYStride * kHeight);
     29     vplane_ = uplane_ + (kUvStride * kHeight / 2);
     30 
     31     rgb_buffer_size_ = kWidth * kHeight * kBytesPerPixel;
     32     rgb_buffer_.reset(new uint8[rgb_buffer_size_]);
     33 
     34     ResetYuvBuffer();
     35     ResetRgbBuffer();
     36   }
     37 
     38   ~YuvToRgbTester() {}
     39 
     40   void ResetYuvBuffer() {
     41     memset(yuv_buffer_.get(), 0, yuv_buffer_size_);
     42   }
     43 
     44   void ResetRgbBuffer() {
     45     memset(rgb_buffer_.get(), 0, rgb_buffer_size_);
     46   }
     47 
     48   void FillRgbBuffer(const webrtc::DesktopRect& rect) {
     49     uint32* ptr = reinterpret_cast<uint32*>(
     50         rgb_buffer_.get() + (rect.top() * kRgbStride) +
     51         (rect.left() * kBytesPerPixel));
     52     int width = rect.width();
     53     for (int height = rect.height(); height > 0; --height) {
     54       std::fill(ptr, ptr + width, kFillColor);
     55       ptr += kRgbStride / kBytesPerPixel;
     56     }
     57   }
     58 
     59   // Check the the desination buffer is filled within expected bounds.
     60   void  CheckRgbBuffer(const webrtc::DesktopRect& rect) {
     61     uint32* ptr = reinterpret_cast<uint32*>(rgb_buffer_.get());
     62     for (int y = 0; y < kHeight; ++y) {
     63       if (y < rect.top() || rect.bottom() <= y) {
     64         // The whole line should be intact.
     65         EXPECT_EQ((ptrdiff_t)kWidth,
     66                   std::count(ptr, ptr + kWidth, 0u));
     67       } else {
     68         // The space before the painted rectangle should be intact.
     69         EXPECT_EQ((ptrdiff_t)rect.left(),
     70                   std::count(ptr, ptr + rect.left(), 0u));
     71 
     72         // All pixels of the target rectangle should be touched.
     73         EXPECT_EQ(ptr + rect.right(),
     74                   std::find(ptr + rect.left(), ptr + rect.right(), 0u));
     75 
     76         // The space after the painted rectangle should be intact.
     77         EXPECT_EQ((ptrdiff_t)kWidth - rect.right(),
     78                   std::count(ptr + rect.right(), ptr + kWidth, 0u));
     79       }
     80       ptr += kRgbStride / kBytesPerPixel;
     81     }
     82   }
     83 
     84   void RunTest(const webrtc::DesktopSize dest_size,
     85                const webrtc::DesktopRect& rect) {
     86     ASSERT_TRUE(
     87         DoesRectContain(webrtc::DesktopRect::MakeSize(dest_size), rect));
     88 
     89     // Reset buffers.
     90     ResetYuvBuffer();
     91     ResetRgbBuffer();
     92     FillRgbBuffer(rect);
     93 
     94     // RGB -> YUV
     95     libyuv::ARGBToI420(rgb_buffer_.get(),
     96                        kRgbStride,
     97                        yplane_,
     98                        kYStride,
     99                        uplane_,
    100                        kUvStride,
    101                        vplane_,
    102                        kUvStride,
    103                        kWidth,
    104                        kHeight);
    105 
    106     // Reset RGB buffer and do opposite conversion.
    107     ResetRgbBuffer();
    108     ConvertAndScaleYUVToRGB32Rect(yplane_,
    109                                   uplane_,
    110                                   vplane_,
    111                                   kYStride,
    112                                   kUvStride,
    113                                   webrtc::DesktopSize(kWidth, kHeight),
    114                                   webrtc::DesktopRect::MakeWH(kWidth, kHeight),
    115                                   rgb_buffer_.get(),
    116                                   kRgbStride,
    117                                   dest_size,
    118                                   webrtc::DesktopRect::MakeSize(dest_size),
    119                                   rect);
    120 
    121     // Check if it worked out.
    122     CheckRgbBuffer(rect);
    123   }
    124 
    125   void TestBasicConversion() {
    126     // Whole buffer.
    127     RunTest(webrtc::DesktopSize(kWidth, kHeight),
    128             webrtc::DesktopRect::MakeWH(kWidth, kHeight));
    129   }
    130 
    131  private:
    132   size_t yuv_buffer_size_;
    133   scoped_ptr<uint8[]> yuv_buffer_;
    134   uint8* yplane_;
    135   uint8* uplane_;
    136   uint8* vplane_;
    137 
    138   size_t rgb_buffer_size_;
    139   scoped_ptr<uint8[]> rgb_buffer_;
    140 
    141   DISALLOW_COPY_AND_ASSIGN(YuvToRgbTester);
    142 };
    143 
    144 TEST(YuvToRgbTest, BasicConversion) {
    145   YuvToRgbTester tester;
    146   tester.TestBasicConversion();
    147 }
    148 
    149 TEST(YuvToRgbTest, Clipping) {
    150   YuvToRgbTester tester;
    151 
    152   webrtc::DesktopSize dest_size = webrtc::DesktopSize(kWidth, kHeight);
    153   webrtc::DesktopRect rect =
    154       webrtc::DesktopRect::MakeLTRB(0, 0, kWidth - 1, kHeight - 1);
    155   // TODO(fbarchard): Allow top/left clipping to odd boundary.
    156   for (int i = 0; i < 16; ++i) {
    157     webrtc::DesktopRect dest_rect = webrtc::DesktopRect::MakeLTRB(
    158         rect.left() + ((i & 1) ? 2 : 0),
    159         rect.top() + ((i & 2) ? 2 : 0),
    160         rect.right() - ((i & 4) ? 1 : 0),
    161         rect.bottom() - ((i & 8) ? 1 : 0));
    162 
    163     tester.RunTest(dest_size, dest_rect);
    164   }
    165 }
    166 
    167 TEST(YuvToRgbTest, ClippingAndScaling) {
    168   YuvToRgbTester tester;
    169 
    170   webrtc::DesktopSize dest_size =
    171       webrtc::DesktopSize(kWidth - 10, kHeight - 10);
    172   webrtc::DesktopRect rect =
    173       webrtc::DesktopRect::MakeLTRB(6, 6, kWidth - 11, kHeight - 11);
    174   for (int i = 0; i < 16; ++i) {
    175     webrtc::DesktopRect dest_rect = webrtc::DesktopRect::MakeLTRB(
    176         rect.left() + ((i & 1) ? 2 : 0),
    177         rect.top() + ((i & 2) ? 2 : 0),
    178         rect.right() - ((i & 4) ? 1 : 0),
    179         rect.bottom() - ((i & 8) ? 1 : 0));
    180 
    181     tester.RunTest(dest_size, dest_rect);
    182   }
    183 }
    184 
    185 TEST(ReplaceLfByCrLfTest, Basic) {
    186   EXPECT_EQ("ab", ReplaceLfByCrLf("ab"));
    187   EXPECT_EQ("\r\nab", ReplaceLfByCrLf("\nab"));
    188   EXPECT_EQ("\r\nab\r\n", ReplaceLfByCrLf("\nab\n"));
    189   EXPECT_EQ("\r\nab\r\ncd", ReplaceLfByCrLf("\nab\ncd"));
    190   EXPECT_EQ("\r\nab\r\ncd\r\n", ReplaceLfByCrLf("\nab\ncd\n"));
    191   EXPECT_EQ("\r\n\r\nab\r\n\r\ncd\r\n\r\n",
    192       ReplaceLfByCrLf("\n\nab\n\ncd\n\n"));
    193 }
    194 
    195 TEST(ReplaceLfByCrLfTest, Speed) {
    196   int kLineSize = 128;
    197   std::string line(kLineSize, 'a');
    198   line[kLineSize - 1] = '\n';
    199   // Make a 10M string.
    200   int kLineNum = 10 * 1024 * 1024 / kLineSize;
    201   std::string buffer;
    202   buffer.resize(kLineNum * kLineSize);
    203   for (int i = 0; i < kLineNum; ++i) {
    204     memcpy(&buffer[i * kLineSize], &line[0], kLineSize);
    205   }
    206   // Convert the string.
    207   buffer = ReplaceLfByCrLf(buffer);
    208   // Check the converted string.
    209   EXPECT_EQ(static_cast<size_t>((kLineSize + 1) * kLineNum), buffer.size());
    210   const char* p = &buffer[0];
    211   for (int i = 0; i < kLineNum; ++i) {
    212     EXPECT_EQ(0, memcmp(&line[0], p, kLineSize - 1));
    213     p += kLineSize - 1;
    214     EXPECT_EQ('\r', *p++);
    215     EXPECT_EQ('\n', *p++);
    216   }
    217 }
    218 
    219 TEST(ReplaceCrLfByLfTest, Basic) {
    220   EXPECT_EQ("ab", ReplaceCrLfByLf("ab"));
    221   EXPECT_EQ("\nab", ReplaceCrLfByLf("\r\nab"));
    222   EXPECT_EQ("\nab\n", ReplaceCrLfByLf("\r\nab\r\n"));
    223   EXPECT_EQ("\nab\ncd", ReplaceCrLfByLf("\r\nab\r\ncd"));
    224   EXPECT_EQ("\nab\ncd\n", ReplaceCrLfByLf("\r\nab\r\ncd\n"));
    225   EXPECT_EQ("\n\nab\n\ncd\n\n",
    226       ReplaceCrLfByLf("\r\n\r\nab\r\n\r\ncd\r\n\r\n"));
    227   EXPECT_EQ("\rab\rcd\r", ReplaceCrLfByLf("\rab\rcd\r"));
    228 }
    229 
    230 TEST(ReplaceCrLfByLfTest, Speed) {
    231   int kLineSize = 128;
    232   std::string line(kLineSize, 'a');
    233   line[kLineSize - 2] = '\r';
    234   line[kLineSize - 1] = '\n';
    235   // Make a 10M string.
    236   int kLineNum = 10 * 1024 * 1024 / kLineSize;
    237   std::string buffer;
    238   buffer.resize(kLineNum * kLineSize);
    239   for (int i = 0; i < kLineNum; ++i) {
    240     memcpy(&buffer[i * kLineSize], &line[0], kLineSize);
    241   }
    242   // Convert the string.
    243   buffer = ReplaceCrLfByLf(buffer);
    244   // Check the converted string.
    245   EXPECT_EQ(static_cast<size_t>((kLineSize - 1) * kLineNum), buffer.size());
    246   const char* p = &buffer[0];
    247   for (int i = 0; i < kLineNum; ++i) {
    248     EXPECT_EQ(0, memcmp(&line[0], p, kLineSize - 2));
    249     p += kLineSize - 2;
    250     EXPECT_EQ('\n', *p++);
    251   }
    252 }
    253 
    254 TEST(StringIsUtf8Test, Basic) {
    255   EXPECT_TRUE(StringIsUtf8("", 0));
    256   EXPECT_TRUE(StringIsUtf8("\0", 1));
    257   EXPECT_TRUE(StringIsUtf8("abc", 3));
    258   EXPECT_TRUE(StringIsUtf8("\xc0\x80", 2));
    259   EXPECT_TRUE(StringIsUtf8("\xe0\x80\x80", 3));
    260   EXPECT_TRUE(StringIsUtf8("\xf0\x80\x80\x80", 4));
    261   EXPECT_TRUE(StringIsUtf8("\xf8\x80\x80\x80\x80", 5));
    262   EXPECT_TRUE(StringIsUtf8("\xfc\x80\x80\x80\x80\x80", 6));
    263 
    264   // Not enough continuation characters
    265   EXPECT_FALSE(StringIsUtf8("\xc0", 1));
    266   EXPECT_FALSE(StringIsUtf8("\xe0\x80", 2));
    267   EXPECT_FALSE(StringIsUtf8("\xf0\x80\x80", 3));
    268   EXPECT_FALSE(StringIsUtf8("\xf8\x80\x80\x80", 4));
    269   EXPECT_FALSE(StringIsUtf8("\xfc\x80\x80\x80\x80", 5));
    270 
    271   // One more continuation character than needed
    272   EXPECT_FALSE(StringIsUtf8("\xc0\x80\x80", 3));
    273   EXPECT_FALSE(StringIsUtf8("\xe0\x80\x80\x80", 4));
    274   EXPECT_FALSE(StringIsUtf8("\xf0\x80\x80\x80\x80", 5));
    275   EXPECT_FALSE(StringIsUtf8("\xf8\x80\x80\x80\x80\x80", 6));
    276   EXPECT_FALSE(StringIsUtf8("\xfc\x80\x80\x80\x80\x80\x80", 7));
    277 
    278   // Invalid first byte
    279   EXPECT_FALSE(StringIsUtf8("\xfe\x80\x80\x80\x80\x80\x80", 7));
    280   EXPECT_FALSE(StringIsUtf8("\xff\x80\x80\x80\x80\x80\x80", 7));
    281 
    282   // Invalid continuation byte
    283   EXPECT_FALSE(StringIsUtf8("\xc0\x00", 2));
    284   EXPECT_FALSE(StringIsUtf8("\xc0\x40", 2));
    285   EXPECT_FALSE(StringIsUtf8("\xc0\xc0", 2));
    286 }
    287 
    288 }  // namespace remoting
    289