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, ¶ms); 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 blink::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 = blink::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