Index: content/browser/devtools/protocol/devtools_protocol_browsertest.cc |
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc |
index e80582222fe74cca51e8deb44f12a85e7daddd5c..2a6d27ca3a82a21143552e519ab5b80f0f226c47 100644 |
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc |
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc |
@@ -6,15 +6,20 @@ |
#include <utility> |
#include "base/base64.h" |
+#include "base/bind.h" |
+#include "base/bind_helpers.h" |
#include "base/command_line.h" |
#include "base/json/json_reader.h" |
#include "base/json/json_writer.h" |
+#include "base/logging.h" |
#include "base/memory/ptr_util.h" |
#include "base/run_loop.h" |
+#include "base/strings/stringprintf.h" |
#include "base/strings/utf_string_conversions.h" |
#include "base/values.h" |
#include "build/build_config.h" |
#include "content/browser/frame_host/interstitial_page_impl.h" |
+#include "content/browser/renderer_host/render_widget_host_view_base.h" |
#include "content/browser/web_contents/web_contents_impl.h" |
#include "content/public/browser/devtools_agent_host.h" |
#include "content/public/browser/interstitial_page_delegate.h" |
@@ -39,8 +44,13 @@ |
#include "net/test/test_data_directory.h" |
#include "testing/gmock/include/gmock/gmock.h" |
#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/skia/include/core/SkColor.h" |
+#include "ui/base/layout.h" |
#include "ui/compositor/compositor_switches.h" |
#include "ui/gfx/codec/png_codec.h" |
+#include "ui/gfx/geometry/rect.h" |
+#include "ui/gfx/geometry/size.h" |
+#include "ui/gfx/skia_util.h" |
#define EXPECT_SIZE_EQ(expected, actual) \ |
do { \ |
@@ -416,7 +426,143 @@ IN_PROC_BROWSER_TEST_F(SyntheticKeyEventTest, KeyEventSynthesizeKey) { |
EXPECT_EQ("\"Escape\"", key); |
} |
+namespace { |
+bool DecodePNG(std::string base64_data, SkBitmap* bitmap) { |
+ std::string png_data; |
+ if (!base::Base64Decode(base64_data, &png_data)) |
+ return false; |
+ return gfx::PNGCodec::Decode( |
+ reinterpret_cast<unsigned const char*>(png_data.data()), png_data.size(), |
+ bitmap); |
+} |
+ |
+// Adapted from cc::ExactPixelComparator. |
+bool MatchesBitmap(const SkBitmap& expected_bmp, |
+ const SkBitmap& actual_bmp, |
+ const gfx::Rect& matching_mask) { |
+ // Number of pixels with an error |
+ int error_pixels_count = 0; |
+ |
+ gfx::Rect error_bounding_rect = gfx::Rect(); |
+ |
+ // Check that bitmaps have identical dimensions. |
+ EXPECT_EQ(expected_bmp.width(), actual_bmp.width()); |
+ EXPECT_EQ(expected_bmp.height(), actual_bmp.height()); |
+ if (expected_bmp.width() != actual_bmp.width() || |
+ expected_bmp.height() != actual_bmp.height()) { |
+ return false; |
+ } |
+ |
+ SkAutoLockPixels lock_actual_bmp(actual_bmp); |
+ SkAutoLockPixels lock_expected_bmp(expected_bmp); |
+ |
+ DCHECK(gfx::SkIRectToRect(actual_bmp.bounds()).Contains(matching_mask)); |
+ |
+ for (int x = matching_mask.x(); x < matching_mask.width(); ++x) { |
+ for (int y = matching_mask.y(); y < matching_mask.height(); ++y) { |
+ SkColor actual_color = actual_bmp.getColor(x, y); |
+ SkColor expected_color = expected_bmp.getColor(x, y); |
+ if (actual_color != expected_color) { |
+ if (error_pixels_count < 10) { |
+ LOG(ERROR) << "Pixel (" << x << "," << y << "): expected " |
+ << expected_color << " actual " << actual_color; |
+ } |
+ error_pixels_count++; |
+ error_bounding_rect.Union(gfx::Rect(x, y, 1, 1)); |
+ } |
+ } |
+ } |
+ |
+ if (error_pixels_count != 0) { |
+ LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count; |
+ LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString(); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+} // namespace |
+ |
class CaptureScreenshotTest : public DevToolsProtocolTest { |
+ protected: |
+ void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap) { |
+ SendCommand("Page.captureScreenshot", nullptr); |
+ std::string base64; |
+ EXPECT_TRUE(result_->GetString("data", &base64)); |
+ SkBitmap result_bitmap; |
+ EXPECT_TRUE(DecodePNG(base64, &result_bitmap)); |
+ gfx::Rect matching_mask(gfx::SkIRectToRect(expected_bitmap.bounds())); |
+#if defined(OS_MACOSX) |
+ // Mask out the corners, which may be drawn differently on Mac because of |
+ // rounded corners. |
+ matching_mask.Inset(4, 4, 4, 4); |
+#endif |
+ EXPECT_TRUE(MatchesBitmap(expected_bitmap, result_bitmap, matching_mask)); |
+ } |
+ |
+ // Takes a screenshot of a colored box that is positioned inside the frame. |
+ void PlaceAndCaptureBox(const gfx::Size& frame_size, |
+ const gfx::Size& box_size, |
+ float screenshot_scale) { |
+ static const int kBoxOffsetHeight = 100; |
+ const gfx::Size scaled_box_size = |
+ ScaleToFlooredSize(box_size, screenshot_scale); |
+ std::unique_ptr<base::DictionaryValue> params; |
+ |
+ VLOG(1) << "Testing screenshot of box with size " << box_size.width() << "x" |
+ << box_size.height() << "px at scale " << screenshot_scale |
+ << " ..."; |
+ |
+ // Draw a blue box of provided size in the horizontal center of the page. |
+ EXPECT_TRUE(content::ExecuteScript( |
+ shell()->web_contents()->GetRenderViewHost(), |
+ base::StringPrintf( |
+ "var style = document.body.style; " |
+ "style.overflow = 'hidden'; " |
+ "style.minHeight = '%dpx'; " |
+ "style.backgroundImage = 'linear-gradient(#0000ff, #0000ff)'; " |
+ "style.backgroundSize = '%dpx %dpx'; " |
+ "style.backgroundPosition = '50%% %dpx'; " |
+ "style.backgroundRepeat = 'no-repeat'; ", |
+ box_size.height() + kBoxOffsetHeight, box_size.width(), |
+ box_size.height(), kBoxOffsetHeight))); |
+ |
+ // Force frame size: The offset of the blue box within the frame shouldn't |
+ // change during screenshotting. This verifies that the page doesn't observe |
+ // a change in frame size as a side effect of screenshotting. |
+ params.reset(new base::DictionaryValue()); |
+ params->SetInteger("width", frame_size.width()); |
+ params->SetInteger("height", frame_size.height()); |
+ params->SetDouble("deviceScaleFactor", 0); |
+ params->SetBoolean("mobile", false); |
+ params->SetBoolean("fitWindow", false); |
+ SendCommand("Emulation.setDeviceMetricsOverride", std::move(params)); |
+ |
+ // Resize frame to scaled blue box size. |
+ params.reset(new base::DictionaryValue()); |
+ params->SetInteger("width", scaled_box_size.width()); |
+ params->SetInteger("height", scaled_box_size.height()); |
+ SendCommand("Emulation.setVisibleSize", std::move(params)); |
+ |
+ // Force viewport to match scaled blue box. |
+ params.reset(new base::DictionaryValue()); |
+ params->SetDouble("x", (frame_size.width() - box_size.width()) / 2.); |
+ params->SetDouble("y", kBoxOffsetHeight); |
+ params->SetDouble("scale", screenshot_scale); |
+ SendCommand("Emulation.forceViewport", std::move(params)); |
+ |
+ // Capture screenshot and verify that it is indeed blue. |
+ SkBitmap expected_bitmap; |
+ expected_bitmap.allocN32Pixels(scaled_box_size.width(), |
+ scaled_box_size.height()); |
+ expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff)); |
+ CaptureScreenshotAndCompareTo(expected_bitmap); |
+ |
+ // Reset for next screenshot. |
+ SendCommand("Emulation.resetViewport", nullptr); |
+ SendCommand("Emulation.clearDeviceMetricsOverride", nullptr); |
+ } |
+ |
private: |
#if !defined(OS_ANDROID) |
void SetUpCommandLine(base::CommandLine* command_line) override { |
@@ -425,32 +571,45 @@ class CaptureScreenshotTest : public DevToolsProtocolTest { |
#endif |
}; |
-// Does not link on Android |
-#if !defined(OS_ANDROID) |
IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshot) { |
shell()->LoadURL(GURL("about:blank")); |
Attach(); |
- EXPECT_TRUE(content::ExecuteScript( |
- shell()->web_contents()->GetRenderViewHost(), |
- "document.body.style.background = '#123456'")); |
- SendCommand("Page.captureScreenshot", nullptr); |
- std::string base64; |
- EXPECT_TRUE(result_->GetString("data", &base64)); |
- std::string png; |
- EXPECT_TRUE(base::Base64Decode(base64, &png)); |
- SkBitmap bitmap; |
- gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()), |
- png.size(), &bitmap); |
- SkColor color(bitmap.getColor(0, 0)); |
- EXPECT_GE(1, std::abs(0x12-(int)SkColorGetR(color))); |
- EXPECT_GE(1, std::abs(0x34-(int)SkColorGetG(color))); |
- EXPECT_GE(1, std::abs(0x56-(int)SkColorGetB(color))); |
- color = bitmap.getColor(1, 1); |
- EXPECT_GE(1, std::abs(0x12-(int)SkColorGetR(color))); |
- EXPECT_GE(1, std::abs(0x34-(int)SkColorGetG(color))); |
- EXPECT_GE(1, std::abs(0x56-(int)SkColorGetB(color))); |
+ EXPECT_TRUE( |
+ content::ExecuteScript(shell()->web_contents()->GetRenderViewHost(), |
+ "document.body.style.background = '#123456'")); |
+ SkBitmap expected_bitmap; |
+ // We compare against the actual physical backing size rather than the |
+ // view size, because the view size is stored adjusted for DPI and only in |
+ // integer precision. |
+ gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>( |
+ shell()->web_contents()->GetRenderWidgetHostView()) |
+ ->GetPhysicalBackingSize(); |
+ expected_bitmap.allocN32Pixels(view_size.width(), view_size.height()); |
+ expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56)); |
+ CaptureScreenshotAndCompareTo(expected_bitmap); |
} |
+ |
+// Setting frame size (through RWHV) is not supported on Android. |
+#if defined(OS_ANDROID) |
+#define MAYBE_CaptureScreenshotArea DISABLED_CaptureScreenshotArea |
+#else |
+#define MAYBE_CaptureScreenshotArea CaptureScreenshotArea |
#endif |
+IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, |
+ MAYBE_CaptureScreenshotArea) { |
+ static const gfx::Size kFrameSize(800, 600); |
+ |
+ shell()->LoadURL(GURL("about:blank")); |
+ Attach(); |
+ |
+ // Test capturing a subarea inside the emulated frame at different scales. |
+ PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 1.0); |
+ PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 2.0); |
+ PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 0.5); |
+ |
+ // Ensure that content outside the emulated frame is painted, too. |
+ PlaceAndCaptureBox(kFrameSize, gfx::Size(10, 10000), 1.0); |
+} |
#if defined(OS_ANDROID) |
// Disabled, see http://crbug.com/469947. |