Home | History | Annotate | Download | only in test
      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 "content/public/test/render_widget_test.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/file_util.h"
      9 #include "base/files/file_path.h"
     10 #include "base/memory/ref_counted_memory.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "content/common/view_messages.h"
     13 #include "content/renderer/render_view_impl.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "third_party/skia/include/core/SkBitmap.h"
     16 #include "third_party/WebKit/public/platform/WebSize.h"
     17 #include "third_party/WebKit/public/web/WebView.h"
     18 #include "ui/gfx/codec/jpeg_codec.h"
     19 #include "ui/gfx/size.h"
     20 #include "ui/surface/transport_dib.h"
     21 
     22 namespace content {
     23 
     24 const int RenderWidgetTest::kNumBytesPerPixel = 4;
     25 const int RenderWidgetTest::kLargeWidth = 1024;
     26 const int RenderWidgetTest::kLargeHeight = 768;
     27 const int RenderWidgetTest::kSmallWidth = 600;
     28 const int RenderWidgetTest::kSmallHeight = 450;
     29 const int RenderWidgetTest::kTextPositionX = 800;
     30 const int RenderWidgetTest::kTextPositionY = 600;
     31 const uint32 RenderWidgetTest::kRedARGB = 0xFFFF0000;
     32 
     33 RenderWidgetTest::RenderWidgetTest() {}
     34 
     35 void RenderWidgetTest::ResizeAndPaint(const gfx::Size& page_size,
     36                                       const gfx::Size& desired_size,
     37                                       SkBitmap* snapshot) {
     38   ASSERT_TRUE(snapshot);
     39   static int g_sequence_num = 0;
     40   // Use a new sequence number for each DIB.
     41   scoped_ptr<TransportDIB> pixels(
     42       TransportDIB::Create(
     43           page_size.width() * page_size.height() * kNumBytesPerPixel,
     44           ++g_sequence_num));
     45 
     46   // Go ahead and map the DIB into memory, so that we can use it below to fill
     47   // tmp_bitmap.  Note that we need to do this before calling OnPaintAtSize, or
     48   // the last reference to the shared memory will  be closed and the handle will
     49   // no longer be valid.
     50   scoped_ptr<TransportDIB> mapped_pixels(TransportDIB::Map(pixels->handle()));
     51 
     52   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
     53   impl->OnPaintAtSize(pixels->handle(), g_sequence_num, page_size,
     54                       desired_size);
     55   ProcessPendingMessages();
     56   const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
     57       ViewHostMsg_PaintAtSize_ACK::ID);
     58   ASSERT_NE(static_cast<IPC::Message*>(NULL), msg);
     59   ViewHostMsg_PaintAtSize_ACK::Param params;
     60   ViewHostMsg_PaintAtSize_ACK::Read(msg, &params);
     61   render_thread_->sink().ClearMessages();
     62   EXPECT_EQ(g_sequence_num, params.a);
     63   gfx::Size size = params.b;
     64   EXPECT_EQ(desired_size, size);
     65 
     66   SkBitmap tmp_bitmap;
     67   tmp_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
     68                        size.width(), size.height());
     69   tmp_bitmap.setPixels(mapped_pixels->memory());
     70   // Copy the pixels from the TransportDIB object to the given snapshot.
     71   ASSERT_TRUE(tmp_bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config));
     72 }
     73 
     74 void RenderWidgetTest::TestResizeAndPaint() {
     75   // Hello World message is only visible if the view size is at least
     76   // kTextPositionX x kTextPositionY
     77   LoadHTML(base::StringPrintf(
     78       "<html><body><div style='position: absolute; top: %d; left: "
     79       "%d; background-color: red;'>Hello World</div></body></html>",
     80       kTextPositionY, kTextPositionX).c_str());
     81   WebKit::WebSize old_size = view_->GetWebView()->size();
     82 
     83   SkBitmap bitmap;
     84   // If we re-size the view to something smaller than where the 'Hello World'
     85   // text is displayed we won't see any text in the snapshot.  Hence,
     86   // the snapshot should not contain any red.
     87   gfx::Size size(kSmallWidth, kSmallHeight);
     88   ResizeAndPaint(size, size, &bitmap);
     89   // Make sure that the view has been re-sized to its old size.
     90   EXPECT_TRUE(old_size == view_->GetWebView()->size());
     91   EXPECT_EQ(kSmallWidth, bitmap.width());
     92   EXPECT_EQ(kSmallHeight, bitmap.height());
     93   EXPECT_FALSE(ImageContainsColor(bitmap, kRedARGB));
     94 
     95   // Since we ask for the view to be re-sized to something larger than where the
     96   // 'Hello World' text is written the text should be visible in the snapshot.
     97   // Hence, the snapshot should contain some red.
     98   size.SetSize(kLargeWidth, kLargeHeight);
     99   ResizeAndPaint(size, size, &bitmap);
    100   EXPECT_TRUE(old_size == view_->GetWebView()->size());
    101   EXPECT_EQ(kLargeWidth, bitmap.width());
    102   EXPECT_EQ(kLargeHeight, bitmap.height());
    103   EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));
    104 
    105   // Even if the desired size is smaller than where the text is located we
    106   // should still see the 'Hello World' message since the view size is
    107   // still large enough.
    108   ResizeAndPaint(size, gfx::Size(kSmallWidth, kSmallHeight), &bitmap);
    109   EXPECT_TRUE(old_size == view_->GetWebView()->size());
    110   EXPECT_EQ(kSmallWidth, bitmap.width());
    111   EXPECT_EQ(kSmallHeight, bitmap.height());
    112   EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));
    113 }
    114 
    115 bool RenderWidgetTest::ImageContainsColor(const SkBitmap& bitmap,
    116                                           uint32 argb_color) {
    117   SkAutoLockPixels lock(bitmap);
    118   bool ready = bitmap.readyToDraw();
    119   EXPECT_TRUE(ready);
    120   if (!ready) {
    121     return false;
    122   }
    123   for (int x = 0; x < bitmap.width(); ++x) {
    124     for (int y = 0; y < bitmap.height(); ++y) {
    125       if (argb_color == *bitmap.getAddr32(x, y)) {
    126         return true;
    127       }
    128     }
    129   }
    130   return false;
    131 }
    132 
    133 void RenderWidgetTest::OutputBitmapToFile(const SkBitmap& bitmap,
    134                                           const base::FilePath& file_path) {
    135   scoped_refptr<base::RefCountedBytes> bitmap_data(new base::RefCountedBytes());
    136   SkAutoLockPixels lock(bitmap);
    137   ASSERT_TRUE(gfx::JPEGCodec::Encode(
    138       reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
    139       gfx::JPEGCodec::FORMAT_BGRA,
    140       bitmap.width(),
    141       bitmap.height(),
    142       static_cast<int>(bitmap.rowBytes()),
    143       90 /* quality */,
    144       &bitmap_data->data()));
    145   ASSERT_LT(0, file_util::WriteFile(
    146       file_path,
    147       reinterpret_cast<const char*>(bitmap_data->front()),
    148       bitmap_data->size()));
    149 }
    150 
    151 void RenderWidgetTest::TestOnResize() {
    152   RenderWidget* widget = static_cast<RenderViewImpl*>(view_);
    153 
    154   // The initial bounds is empty, so setting it to the same thing should do
    155   // nothing.
    156   ViewMsg_Resize_Params resize_params;
    157   resize_params.screen_info = WebKit::WebScreenInfo();
    158   resize_params.new_size = gfx::Size();
    159   resize_params.physical_backing_size = gfx::Size();
    160   resize_params.overdraw_bottom_height = 0.f;
    161   resize_params.resizer_rect = gfx::Rect();
    162   resize_params.is_fullscreen = false;
    163   widget->OnResize(resize_params);
    164   EXPECT_FALSE(widget->next_paint_is_resize_ack());
    165 
    166   // Setting empty physical backing size should not send the ack.
    167   resize_params.new_size = gfx::Size(10, 10);
    168   widget->OnResize(resize_params);
    169   EXPECT_FALSE(widget->next_paint_is_resize_ack());
    170 
    171   // Setting the bounds to a "real" rect should send the ack.
    172   render_thread_->sink().ClearMessages();
    173   gfx::Size size(100, 100);
    174   resize_params.new_size = size;
    175   resize_params.physical_backing_size = size;
    176   widget->OnResize(resize_params);
    177   EXPECT_TRUE(widget->next_paint_is_resize_ack());
    178   widget->DoDeferredUpdate();
    179   ProcessPendingMessages();
    180 
    181   const ViewHostMsg_UpdateRect* msg =
    182       static_cast<const ViewHostMsg_UpdateRect*>(
    183           render_thread_->sink().GetUniqueMessageMatching(
    184               ViewHostMsg_UpdateRect::ID));
    185   ASSERT_TRUE(msg);
    186   ViewHostMsg_UpdateRect::Schema::Param update_rect_params;
    187   EXPECT_TRUE(ViewHostMsg_UpdateRect::Read(msg, &update_rect_params));
    188   EXPECT_TRUE(ViewHostMsg_UpdateRect_Flags::is_resize_ack(
    189       update_rect_params.a.flags));
    190   EXPECT_EQ(size,
    191       update_rect_params.a.view_size);
    192   render_thread_->sink().ClearMessages();
    193 
    194   // Setting the same size again should not send the ack.
    195   widget->OnResize(resize_params);
    196   EXPECT_FALSE(widget->next_paint_is_resize_ack());
    197 
    198   // Resetting the rect to empty should not send the ack.
    199   resize_params.new_size = gfx::Size();
    200   resize_params.physical_backing_size = gfx::Size();
    201   widget->OnResize(resize_params);
    202   EXPECT_FALSE(widget->next_paint_is_resize_ack());
    203 }
    204 
    205 }  // namespace content
    206