OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stddef.h> | 5 #include <stddef.h> |
6 #include <utility> | 6 #include <utility> |
7 | 7 |
8 #include "base/base64.h" | 8 #include "base/base64.h" |
| 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" |
9 #include "base/command_line.h" | 11 #include "base/command_line.h" |
10 #include "base/json/json_reader.h" | 12 #include "base/json/json_reader.h" |
11 #include "base/json/json_writer.h" | 13 #include "base/json/json_writer.h" |
| 14 #include "base/logging.h" |
12 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
13 #include "base/run_loop.h" | 16 #include "base/run_loop.h" |
| 17 #include "base/strings/stringprintf.h" |
14 #include "base/strings/utf_string_conversions.h" | 18 #include "base/strings/utf_string_conversions.h" |
15 #include "base/values.h" | 19 #include "base/values.h" |
16 #include "build/build_config.h" | 20 #include "build/build_config.h" |
17 #include "content/browser/frame_host/interstitial_page_impl.h" | 21 #include "content/browser/frame_host/interstitial_page_impl.h" |
| 22 #include "content/browser/renderer_host/render_widget_host_view_base.h" |
18 #include "content/browser/web_contents/web_contents_impl.h" | 23 #include "content/browser/web_contents/web_contents_impl.h" |
19 #include "content/public/browser/devtools_agent_host.h" | 24 #include "content/public/browser/devtools_agent_host.h" |
20 #include "content/public/browser/interstitial_page_delegate.h" | 25 #include "content/public/browser/interstitial_page_delegate.h" |
21 #include "content/public/browser/javascript_dialog_manager.h" | 26 #include "content/public/browser/javascript_dialog_manager.h" |
22 #include "content/public/browser/navigation_controller.h" | 27 #include "content/public/browser/navigation_controller.h" |
23 #include "content/public/browser/navigation_entry.h" | 28 #include "content/public/browser/navigation_entry.h" |
24 #include "content/public/browser/navigation_handle.h" | 29 #include "content/public/browser/navigation_handle.h" |
25 #include "content/public/browser/render_frame_host.h" | 30 #include "content/public/browser/render_frame_host.h" |
26 #include "content/public/browser/render_view_host.h" | 31 #include "content/public/browser/render_view_host.h" |
27 #include "content/public/browser/render_widget_host_view.h" | 32 #include "content/public/browser/render_widget_host_view.h" |
28 #include "content/public/browser/ssl_status.h" | 33 #include "content/public/browser/ssl_status.h" |
29 #include "content/public/browser/web_contents.h" | 34 #include "content/public/browser/web_contents.h" |
30 #include "content/public/common/url_constants.h" | 35 #include "content/public/common/url_constants.h" |
31 #include "content/public/test/browser_test_utils.h" | 36 #include "content/public/test/browser_test_utils.h" |
32 #include "content/public/test/content_browser_test.h" | 37 #include "content/public/test/content_browser_test.h" |
33 #include "content/public/test/content_browser_test_utils.h" | 38 #include "content/public/test/content_browser_test_utils.h" |
34 #include "content/public/test/test_navigation_observer.h" | 39 #include "content/public/test/test_navigation_observer.h" |
35 #include "content/shell/browser/shell.h" | 40 #include "content/shell/browser/shell.h" |
36 #include "net/dns/mock_host_resolver.h" | 41 #include "net/dns/mock_host_resolver.h" |
37 #include "net/test/cert_test_util.h" | 42 #include "net/test/cert_test_util.h" |
38 #include "net/test/embedded_test_server/embedded_test_server.h" | 43 #include "net/test/embedded_test_server/embedded_test_server.h" |
39 #include "net/test/test_data_directory.h" | 44 #include "net/test/test_data_directory.h" |
40 #include "testing/gmock/include/gmock/gmock.h" | 45 #include "testing/gmock/include/gmock/gmock.h" |
41 #include "third_party/skia/include/core/SkBitmap.h" | 46 #include "third_party/skia/include/core/SkBitmap.h" |
| 47 #include "third_party/skia/include/core/SkColor.h" |
| 48 #include "ui/base/layout.h" |
42 #include "ui/compositor/compositor_switches.h" | 49 #include "ui/compositor/compositor_switches.h" |
43 #include "ui/gfx/codec/png_codec.h" | 50 #include "ui/gfx/codec/png_codec.h" |
| 51 #include "ui/gfx/geometry/rect.h" |
| 52 #include "ui/gfx/geometry/size.h" |
| 53 #include "ui/gfx/skia_util.h" |
44 | 54 |
45 #define EXPECT_SIZE_EQ(expected, actual) \ | 55 #define EXPECT_SIZE_EQ(expected, actual) \ |
46 do { \ | 56 do { \ |
47 EXPECT_EQ((expected).width(), (actual).width()); \ | 57 EXPECT_EQ((expected).width(), (actual).width()); \ |
48 EXPECT_EQ((expected).height(), (actual).height()); \ | 58 EXPECT_EQ((expected).height(), (actual).height()); \ |
49 } while (false) | 59 } while (false) |
50 | 60 |
51 using testing::ElementsAre; | 61 using testing::ElementsAre; |
52 | 62 |
53 namespace content { | 63 namespace content { |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 // Send escape (keycode 27). | 419 // Send escape (keycode 27). |
410 SendKeyEvent("rawKeyDown", 0, 27, 27, "Escape"); | 420 SendKeyEvent("rawKeyDown", 0, 27, 27, "Escape"); |
411 SendKeyEvent("keyUp", 0, 27, 27, "Escape"); | 421 SendKeyEvent("keyUp", 0, 27, 27, "Escape"); |
412 | 422 |
413 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key)); | 423 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key)); |
414 EXPECT_EQ("\"Escape\"", key); | 424 EXPECT_EQ("\"Escape\"", key); |
415 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key)); | 425 ASSERT_TRUE(dom_message_queue.WaitForMessage(&key)); |
416 EXPECT_EQ("\"Escape\"", key); | 426 EXPECT_EQ("\"Escape\"", key); |
417 } | 427 } |
418 | 428 |
| 429 namespace { |
| 430 bool DecodePNG(std::string base64_data, SkBitmap* bitmap) { |
| 431 std::string png_data; |
| 432 if (!base::Base64Decode(base64_data, &png_data)) |
| 433 return false; |
| 434 return gfx::PNGCodec::Decode( |
| 435 reinterpret_cast<unsigned const char*>(png_data.data()), png_data.size(), |
| 436 bitmap); |
| 437 } |
| 438 |
| 439 // Adapted from cc::ExactPixelComparator. |
| 440 bool MatchesBitmap(const SkBitmap& expected_bmp, |
| 441 const SkBitmap& actual_bmp, |
| 442 const gfx::Rect& matching_mask) { |
| 443 // Number of pixels with an error |
| 444 int error_pixels_count = 0; |
| 445 |
| 446 gfx::Rect error_bounding_rect = gfx::Rect(); |
| 447 |
| 448 // Check that bitmaps have identical dimensions. |
| 449 EXPECT_EQ(expected_bmp.width(), actual_bmp.width()); |
| 450 EXPECT_EQ(expected_bmp.height(), actual_bmp.height()); |
| 451 if (expected_bmp.width() != actual_bmp.width() || |
| 452 expected_bmp.height() != actual_bmp.height()) { |
| 453 return false; |
| 454 } |
| 455 |
| 456 SkAutoLockPixels lock_actual_bmp(actual_bmp); |
| 457 SkAutoLockPixels lock_expected_bmp(expected_bmp); |
| 458 |
| 459 DCHECK(gfx::SkIRectToRect(actual_bmp.bounds()).Contains(matching_mask)); |
| 460 |
| 461 for (int x = matching_mask.x(); x < matching_mask.width(); ++x) { |
| 462 for (int y = matching_mask.y(); y < matching_mask.height(); ++y) { |
| 463 SkColor actual_color = actual_bmp.getColor(x, y); |
| 464 SkColor expected_color = expected_bmp.getColor(x, y); |
| 465 if (actual_color != expected_color) { |
| 466 if (error_pixels_count < 10) { |
| 467 LOG(ERROR) << "Pixel (" << x << "," << y << "): expected " |
| 468 << expected_color << " actual " << actual_color; |
| 469 } |
| 470 error_pixels_count++; |
| 471 error_bounding_rect.Union(gfx::Rect(x, y, 1, 1)); |
| 472 } |
| 473 } |
| 474 } |
| 475 |
| 476 if (error_pixels_count != 0) { |
| 477 LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count; |
| 478 LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString(); |
| 479 return false; |
| 480 } |
| 481 |
| 482 return true; |
| 483 } |
| 484 } // namespace |
| 485 |
419 class CaptureScreenshotTest : public DevToolsProtocolTest { | 486 class CaptureScreenshotTest : public DevToolsProtocolTest { |
| 487 protected: |
| 488 void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap) { |
| 489 SendCommand("Page.captureScreenshot", nullptr); |
| 490 std::string base64; |
| 491 EXPECT_TRUE(result_->GetString("data", &base64)); |
| 492 SkBitmap result_bitmap; |
| 493 EXPECT_TRUE(DecodePNG(base64, &result_bitmap)); |
| 494 gfx::Rect matching_mask(gfx::SkIRectToRect(expected_bitmap.bounds())); |
| 495 #if defined(OS_MACOSX) |
| 496 // Mask out the corners, which may be drawn differently on Mac because of |
| 497 // rounded corners. |
| 498 matching_mask.Inset(4, 4, 4, 4); |
| 499 #endif |
| 500 EXPECT_TRUE(MatchesBitmap(expected_bitmap, result_bitmap, matching_mask)); |
| 501 } |
| 502 |
| 503 // Takes a screenshot of a colored box that is positioned inside the frame. |
| 504 void PlaceAndCaptureBox(const gfx::Size& frame_size, |
| 505 const gfx::Size& box_size, |
| 506 float screenshot_scale) { |
| 507 static const int kBoxOffsetHeight = 100; |
| 508 const gfx::Size scaled_box_size = |
| 509 ScaleToFlooredSize(box_size, screenshot_scale); |
| 510 std::unique_ptr<base::DictionaryValue> params; |
| 511 |
| 512 VLOG(1) << "Testing screenshot of box with size " << box_size.width() << "x" |
| 513 << box_size.height() << "px at scale " << screenshot_scale |
| 514 << " ..."; |
| 515 |
| 516 // Draw a blue box of provided size in the horizontal center of the page. |
| 517 EXPECT_TRUE(content::ExecuteScript( |
| 518 shell()->web_contents()->GetRenderViewHost(), |
| 519 base::StringPrintf( |
| 520 "var style = document.body.style; " |
| 521 "style.overflow = 'hidden'; " |
| 522 "style.minHeight = '%dpx'; " |
| 523 "style.backgroundImage = 'linear-gradient(#0000ff, #0000ff)'; " |
| 524 "style.backgroundSize = '%dpx %dpx'; " |
| 525 "style.backgroundPosition = '50%% %dpx'; " |
| 526 "style.backgroundRepeat = 'no-repeat'; ", |
| 527 box_size.height() + kBoxOffsetHeight, box_size.width(), |
| 528 box_size.height(), kBoxOffsetHeight))); |
| 529 |
| 530 // Force frame size: The offset of the blue box within the frame shouldn't |
| 531 // change during screenshotting. This verifies that the page doesn't observe |
| 532 // a change in frame size as a side effect of screenshotting. |
| 533 params.reset(new base::DictionaryValue()); |
| 534 params->SetInteger("width", frame_size.width()); |
| 535 params->SetInteger("height", frame_size.height()); |
| 536 params->SetDouble("deviceScaleFactor", 0); |
| 537 params->SetBoolean("mobile", false); |
| 538 params->SetBoolean("fitWindow", false); |
| 539 SendCommand("Emulation.setDeviceMetricsOverride", std::move(params)); |
| 540 |
| 541 // Resize frame to scaled blue box size. |
| 542 params.reset(new base::DictionaryValue()); |
| 543 params->SetInteger("width", scaled_box_size.width()); |
| 544 params->SetInteger("height", scaled_box_size.height()); |
| 545 SendCommand("Emulation.setVisibleSize", std::move(params)); |
| 546 |
| 547 // Force viewport to match scaled blue box. |
| 548 params.reset(new base::DictionaryValue()); |
| 549 params->SetDouble("x", (frame_size.width() - box_size.width()) / 2.); |
| 550 params->SetDouble("y", kBoxOffsetHeight); |
| 551 params->SetDouble("scale", screenshot_scale); |
| 552 SendCommand("Emulation.forceViewport", std::move(params)); |
| 553 |
| 554 // Capture screenshot and verify that it is indeed blue. |
| 555 SkBitmap expected_bitmap; |
| 556 expected_bitmap.allocN32Pixels(scaled_box_size.width(), |
| 557 scaled_box_size.height()); |
| 558 expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff)); |
| 559 CaptureScreenshotAndCompareTo(expected_bitmap); |
| 560 |
| 561 // Reset for next screenshot. |
| 562 SendCommand("Emulation.resetViewport", nullptr); |
| 563 SendCommand("Emulation.clearDeviceMetricsOverride", nullptr); |
| 564 } |
| 565 |
420 private: | 566 private: |
421 #if !defined(OS_ANDROID) | 567 #if !defined(OS_ANDROID) |
422 void SetUpCommandLine(base::CommandLine* command_line) override { | 568 void SetUpCommandLine(base::CommandLine* command_line) override { |
423 command_line->AppendSwitch(switches::kEnablePixelOutputInTests); | 569 command_line->AppendSwitch(switches::kEnablePixelOutputInTests); |
424 } | 570 } |
425 #endif | 571 #endif |
426 }; | 572 }; |
427 | 573 |
428 // Does not link on Android | |
429 #if !defined(OS_ANDROID) | |
430 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshot) { | 574 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshot) { |
431 shell()->LoadURL(GURL("about:blank")); | 575 shell()->LoadURL(GURL("about:blank")); |
432 Attach(); | 576 Attach(); |
433 EXPECT_TRUE(content::ExecuteScript( | 577 EXPECT_TRUE( |
434 shell()->web_contents()->GetRenderViewHost(), | 578 content::ExecuteScript(shell()->web_contents()->GetRenderViewHost(), |
435 "document.body.style.background = '#123456'")); | 579 "document.body.style.background = '#123456'")); |
436 SendCommand("Page.captureScreenshot", nullptr); | 580 SkBitmap expected_bitmap; |
437 std::string base64; | 581 // We compare against the actual physical backing size rather than the |
438 EXPECT_TRUE(result_->GetString("data", &base64)); | 582 // view size, because the view size is stored adjusted for DPI and only in |
439 std::string png; | 583 // integer precision. |
440 EXPECT_TRUE(base::Base64Decode(base64, &png)); | 584 gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>( |
441 SkBitmap bitmap; | 585 shell()->web_contents()->GetRenderWidgetHostView()) |
442 gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()), | 586 ->GetPhysicalBackingSize(); |
443 png.size(), &bitmap); | 587 expected_bitmap.allocN32Pixels(view_size.width(), view_size.height()); |
444 SkColor color(bitmap.getColor(0, 0)); | 588 expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56)); |
445 EXPECT_GE(1, std::abs(0x12-(int)SkColorGetR(color))); | 589 CaptureScreenshotAndCompareTo(expected_bitmap); |
446 EXPECT_GE(1, std::abs(0x34-(int)SkColorGetG(color))); | |
447 EXPECT_GE(1, std::abs(0x56-(int)SkColorGetB(color))); | |
448 color = bitmap.getColor(1, 1); | |
449 EXPECT_GE(1, std::abs(0x12-(int)SkColorGetR(color))); | |
450 EXPECT_GE(1, std::abs(0x34-(int)SkColorGetG(color))); | |
451 EXPECT_GE(1, std::abs(0x56-(int)SkColorGetB(color))); | |
452 } | 590 } |
| 591 |
| 592 // Setting frame size (through RWHV) is not supported on Android. |
| 593 #if defined(OS_ANDROID) |
| 594 #define MAYBE_CaptureScreenshotArea DISABLED_CaptureScreenshotArea |
| 595 #else |
| 596 #define MAYBE_CaptureScreenshotArea CaptureScreenshotArea |
453 #endif | 597 #endif |
| 598 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, |
| 599 MAYBE_CaptureScreenshotArea) { |
| 600 static const gfx::Size kFrameSize(800, 600); |
| 601 |
| 602 shell()->LoadURL(GURL("about:blank")); |
| 603 Attach(); |
| 604 |
| 605 // Test capturing a subarea inside the emulated frame at different scales. |
| 606 PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 1.0); |
| 607 PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 2.0); |
| 608 PlaceAndCaptureBox(kFrameSize, gfx::Size(100, 200), 0.5); |
| 609 |
| 610 // Ensure that content outside the emulated frame is painted, too. |
| 611 PlaceAndCaptureBox(kFrameSize, gfx::Size(10, 10000), 1.0); |
| 612 } |
454 | 613 |
455 #if defined(OS_ANDROID) | 614 #if defined(OS_ANDROID) |
456 // Disabled, see http://crbug.com/469947. | 615 // Disabled, see http://crbug.com/469947. |
457 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizePinchGesture) { | 616 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizePinchGesture) { |
458 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html"); | 617 GURL test_url = GetTestUrl("devtools", "synthetic_gesture_tests.html"); |
459 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1); | 618 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1); |
460 Attach(); | 619 Attach(); |
461 | 620 |
462 int old_width; | 621 int old_width; |
463 ASSERT_TRUE(content::ExecuteScriptAndExtractInt( | 622 ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
(...skipping 562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1026 ASSERT_TRUE(transient_entry); | 1185 ASSERT_TRUE(transient_entry); |
1027 transient_entry->GetSSL().certificate = expired_cert(); | 1186 transient_entry->GetSSL().certificate = expired_cert(); |
1028 ASSERT_TRUE(transient_entry->GetSSL().certificate); | 1187 ASSERT_TRUE(transient_entry->GetSSL().certificate); |
1029 | 1188 |
1030 std::unique_ptr<base::DictionaryValue> params2(new base::DictionaryValue()); | 1189 std::unique_ptr<base::DictionaryValue> params2(new base::DictionaryValue()); |
1031 SendCommand("Security.showCertificateViewer", std::move(params2), true); | 1190 SendCommand("Security.showCertificateViewer", std::move(params2), true); |
1032 EXPECT_EQ(transient_entry->GetSSL().certificate, last_shown_certificate()); | 1191 EXPECT_EQ(transient_entry->GetSSL().certificate, last_shown_certificate()); |
1033 } | 1192 } |
1034 | 1193 |
1035 } // namespace content | 1194 } // namespace content |
OLD | NEW |