| 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" | 9 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 #include "content/test/content_browser_test_utils_internal.h" | 42 #include "content/test/content_browser_test_utils_internal.h" |
| 43 #include "net/dns/mock_host_resolver.h" | 43 #include "net/dns/mock_host_resolver.h" |
| 44 #include "net/test/cert_test_util.h" | 44 #include "net/test/cert_test_util.h" |
| 45 #include "net/test/embedded_test_server/embedded_test_server.h" | 45 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 46 #include "net/test/test_data_directory.h" | 46 #include "net/test/test_data_directory.h" |
| 47 #include "testing/gmock/include/gmock/gmock.h" | 47 #include "testing/gmock/include/gmock/gmock.h" |
| 48 #include "third_party/skia/include/core/SkBitmap.h" | 48 #include "third_party/skia/include/core/SkBitmap.h" |
| 49 #include "third_party/skia/include/core/SkColor.h" | 49 #include "third_party/skia/include/core/SkColor.h" |
| 50 #include "ui/base/layout.h" | 50 #include "ui/base/layout.h" |
| 51 #include "ui/compositor/compositor_switches.h" | 51 #include "ui/compositor/compositor_switches.h" |
| 52 #include "ui/gfx/codec/jpeg_codec.h" |
| 52 #include "ui/gfx/codec/png_codec.h" | 53 #include "ui/gfx/codec/png_codec.h" |
| 53 #include "ui/gfx/geometry/rect.h" | 54 #include "ui/gfx/geometry/rect.h" |
| 54 #include "ui/gfx/geometry/size.h" | 55 #include "ui/gfx/geometry/size.h" |
| 55 #include "ui/gfx/skia_util.h" | 56 #include "ui/gfx/skia_util.h" |
| 56 | 57 |
| 57 #define EXPECT_SIZE_EQ(expected, actual) \ | 58 #define EXPECT_SIZE_EQ(expected, actual) \ |
| 58 do { \ | 59 do { \ |
| 59 EXPECT_EQ((expected).width(), (actual).width()); \ | 60 EXPECT_EQ((expected).width(), (actual).width()); \ |
| 60 EXPECT_EQ((expected).height(), (actual).height()); \ | 61 EXPECT_EQ((expected).height(), (actual).height()); \ |
| 61 } while (false) | 62 } while (false) |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 namespace { | 458 namespace { |
| 458 bool DecodePNG(std::string base64_data, SkBitmap* bitmap) { | 459 bool DecodePNG(std::string base64_data, SkBitmap* bitmap) { |
| 459 std::string png_data; | 460 std::string png_data; |
| 460 if (!base::Base64Decode(base64_data, &png_data)) | 461 if (!base::Base64Decode(base64_data, &png_data)) |
| 461 return false; | 462 return false; |
| 462 return gfx::PNGCodec::Decode( | 463 return gfx::PNGCodec::Decode( |
| 463 reinterpret_cast<unsigned const char*>(png_data.data()), png_data.size(), | 464 reinterpret_cast<unsigned const char*>(png_data.data()), png_data.size(), |
| 464 bitmap); | 465 bitmap); |
| 465 } | 466 } |
| 466 | 467 |
| 468 std::unique_ptr<SkBitmap> DecodeJPEG(std::string base64_data) { |
| 469 std::string jpeg_data; |
| 470 if (!base::Base64Decode(base64_data, &jpeg_data)) |
| 471 return nullptr; |
| 472 return gfx::JPEGCodec::Decode( |
| 473 reinterpret_cast<unsigned const char*>(jpeg_data.data()), |
| 474 jpeg_data.size()); |
| 475 } |
| 476 |
| 467 // Adapted from cc::ExactPixelComparator. | 477 // Adapted from cc::ExactPixelComparator. |
| 468 bool MatchesBitmap(const SkBitmap& expected_bmp, | 478 bool MatchesBitmap(const SkBitmap& expected_bmp, |
| 469 const SkBitmap& actual_bmp, | 479 const SkBitmap& actual_bmp, |
| 470 const gfx::Rect& matching_mask) { | 480 int error_limit) { |
| 471 // Number of pixels with an error | 481 // Number of pixels with an error |
| 472 int error_pixels_count = 0; | 482 int error_pixels_count = 0; |
| 473 | 483 |
| 474 gfx::Rect error_bounding_rect = gfx::Rect(); | 484 gfx::Rect error_bounding_rect = gfx::Rect(); |
| 475 | 485 |
| 476 // Check that bitmaps have identical dimensions. | 486 // Check that bitmaps have identical dimensions. |
| 477 EXPECT_EQ(expected_bmp.width(), actual_bmp.width()); | 487 EXPECT_EQ(expected_bmp.width(), actual_bmp.width()); |
| 478 EXPECT_EQ(expected_bmp.height(), actual_bmp.height()); | 488 EXPECT_EQ(expected_bmp.height(), actual_bmp.height()); |
| 479 if (expected_bmp.width() != actual_bmp.width() || | 489 if (expected_bmp.width() != actual_bmp.width() || |
| 480 expected_bmp.height() != actual_bmp.height()) { | 490 expected_bmp.height() != actual_bmp.height()) { |
| 481 return false; | 491 return false; |
| 482 } | 492 } |
| 483 | 493 |
| 484 SkAutoLockPixels lock_actual_bmp(actual_bmp); | 494 SkAutoLockPixels lock_actual_bmp(actual_bmp); |
| 485 SkAutoLockPixels lock_expected_bmp(expected_bmp); | 495 SkAutoLockPixels lock_expected_bmp(expected_bmp); |
| 486 | 496 |
| 487 DCHECK(gfx::SkIRectToRect(actual_bmp.bounds()).Contains(matching_mask)); | 497 for (int x = 0; x < actual_bmp.width(); ++x) { |
| 488 | 498 for (int y = 0; y < actual_bmp.height(); ++y) { |
| 489 for (int x = matching_mask.x(); x < matching_mask.width(); ++x) { | |
| 490 for (int y = matching_mask.y(); y < matching_mask.height(); ++y) { | |
| 491 SkColor actual_color = actual_bmp.getColor(x, y); | 499 SkColor actual_color = actual_bmp.getColor(x, y); |
| 492 SkColor expected_color = expected_bmp.getColor(x, y); | 500 SkColor expected_color = expected_bmp.getColor(x, y); |
| 493 if (actual_color != expected_color) { | 501 if (std::abs(static_cast<int32_t>(actual_color) - |
| 502 static_cast<int32_t>(expected_color)) > error_limit) { |
| 494 if (error_pixels_count < 10) { | 503 if (error_pixels_count < 10) { |
| 495 LOG(ERROR) << "Pixel (" << x << "," << y << "): expected " | 504 LOG(ERROR) << "Pixel (" << x << "," << y << "): expected " |
| 496 << expected_color << " actual " << actual_color; | 505 << expected_color << " actual " << actual_color; |
| 497 } | 506 } |
| 498 error_pixels_count++; | 507 error_pixels_count++; |
| 499 error_bounding_rect.Union(gfx::Rect(x, y, 1, 1)); | 508 error_bounding_rect.Union(gfx::Rect(x, y, 1, 1)); |
| 500 } | 509 } |
| 501 } | 510 } |
| 502 } | 511 } |
| 503 | 512 |
| 504 if (error_pixels_count != 0) { | 513 if (error_pixels_count != 0) { |
| 505 LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count; | 514 LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count; |
| 506 LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString(); | 515 LOG(ERROR) << "Error Bounding Box : " << error_bounding_rect.ToString(); |
| 507 return false; | 516 return false; |
| 508 } | 517 } |
| 509 | 518 |
| 510 return true; | 519 return true; |
| 511 } | 520 } |
| 512 } // namespace | 521 } // namespace |
| 513 | 522 |
| 514 class CaptureScreenshotTest : public DevToolsProtocolTest { | 523 class CaptureScreenshotTest : public DevToolsProtocolTest { |
| 515 protected: | 524 protected: |
| 516 void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap) { | 525 enum ScreenshotEncoding { ENCODING_PNG, ENCODING_JPEG }; |
| 517 SendCommand("Page.captureScreenshot", nullptr); | 526 void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap, |
| 527 ScreenshotEncoding encoding) { |
| 528 std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue()); |
| 529 params->SetString("format", encoding == ENCODING_PNG ? "png" : "jpeg"); |
| 530 params->SetInteger("quality", 100); |
| 531 SendCommand("Page.captureScreenshot", std::move(params)); |
| 532 |
| 518 std::string base64; | 533 std::string base64; |
| 519 EXPECT_TRUE(result_->GetString("data", &base64)); | 534 EXPECT_TRUE(result_->GetString("data", &base64)); |
| 520 SkBitmap result_bitmap; | 535 std::unique_ptr<SkBitmap> result_bitmap; |
| 521 EXPECT_TRUE(DecodePNG(base64, &result_bitmap)); | 536 int error_limit = 0; |
| 522 gfx::Rect matching_mask(gfx::SkIRectToRect(expected_bitmap.bounds())); | 537 if (encoding == ENCODING_PNG){ |
| 523 #if defined(OS_MACOSX) | 538 result_bitmap.reset(new SkBitmap()); |
| 524 // Mask out the corners, which may be drawn differently on Mac because of | 539 EXPECT_TRUE(DecodePNG(base64, result_bitmap.get())); |
| 525 // rounded corners. | 540 } else { |
| 526 matching_mask.Inset(4, 4, 4, 4); | 541 result_bitmap = DecodeJPEG(base64); |
| 527 #endif | 542 // Even with quality 100, jpeg isn't lossless. So, we allow some skew in |
| 528 EXPECT_TRUE(MatchesBitmap(expected_bitmap, result_bitmap, matching_mask)); | 543 // pixel values. Not that this assumes that there is no skew in pixel |
| 544 // positions, so will only work reliably if all pixels have equal values. |
| 545 error_limit = 3; |
| 546 } |
| 547 EXPECT_TRUE(result_bitmap); |
| 548 |
| 549 EXPECT_TRUE(MatchesBitmap(expected_bitmap, *result_bitmap, error_limit)); |
| 529 } | 550 } |
| 530 | 551 |
| 531 // Takes a screenshot of a colored box that is positioned inside the frame. | 552 // Takes a screenshot of a colored box that is positioned inside the frame. |
| 532 void PlaceAndCaptureBox(const gfx::Size& frame_size, | 553 void PlaceAndCaptureBox(const gfx::Size& frame_size, |
| 533 const gfx::Size& box_size, | 554 const gfx::Size& box_size, |
| 534 float screenshot_scale) { | 555 float screenshot_scale) { |
| 535 static const int kBoxOffsetHeight = 100; | 556 static const int kBoxOffsetHeight = 100; |
| 536 const gfx::Size scaled_box_size = | 557 const gfx::Size scaled_box_size = |
| 537 ScaleToFlooredSize(box_size, screenshot_scale); | 558 ScaleToFlooredSize(box_size, screenshot_scale); |
| 538 std::unique_ptr<base::DictionaryValue> params; | 559 std::unique_ptr<base::DictionaryValue> params; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 params->SetDouble("x", (frame_size.width() - box_size.width()) / 2.); | 598 params->SetDouble("x", (frame_size.width() - box_size.width()) / 2.); |
| 578 params->SetDouble("y", kBoxOffsetHeight); | 599 params->SetDouble("y", kBoxOffsetHeight); |
| 579 params->SetDouble("scale", screenshot_scale); | 600 params->SetDouble("scale", screenshot_scale); |
| 580 SendCommand("Emulation.forceViewport", std::move(params)); | 601 SendCommand("Emulation.forceViewport", std::move(params)); |
| 581 | 602 |
| 582 // Capture screenshot and verify that it is indeed blue. | 603 // Capture screenshot and verify that it is indeed blue. |
| 583 SkBitmap expected_bitmap; | 604 SkBitmap expected_bitmap; |
| 584 expected_bitmap.allocN32Pixels(scaled_box_size.width(), | 605 expected_bitmap.allocN32Pixels(scaled_box_size.width(), |
| 585 scaled_box_size.height()); | 606 scaled_box_size.height()); |
| 586 expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff)); | 607 expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff)); |
| 587 CaptureScreenshotAndCompareTo(expected_bitmap); | 608 CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG); |
| 588 | 609 |
| 589 // Reset for next screenshot. | 610 // Reset for next screenshot. |
| 590 SendCommand("Emulation.resetViewport", nullptr); | 611 SendCommand("Emulation.resetViewport", nullptr); |
| 591 SendCommand("Emulation.clearDeviceMetricsOverride", nullptr); | 612 SendCommand("Emulation.clearDeviceMetricsOverride", nullptr); |
| 592 } | 613 } |
| 593 | 614 |
| 594 private: | 615 private: |
| 595 #if !defined(OS_ANDROID) | 616 #if !defined(OS_ANDROID) |
| 596 void SetUpCommandLine(base::CommandLine* command_line) override { | 617 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 597 command_line->AppendSwitch(switches::kEnablePixelOutputInTests); | 618 command_line->AppendSwitch(switches::kEnablePixelOutputInTests); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 611 "document.body.style.background = '#123456'")); | 632 "document.body.style.background = '#123456'")); |
| 612 SkBitmap expected_bitmap; | 633 SkBitmap expected_bitmap; |
| 613 // We compare against the actual physical backing size rather than the | 634 // We compare against the actual physical backing size rather than the |
| 614 // view size, because the view size is stored adjusted for DPI and only in | 635 // view size, because the view size is stored adjusted for DPI and only in |
| 615 // integer precision. | 636 // integer precision. |
| 616 gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>( | 637 gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>( |
| 617 shell()->web_contents()->GetRenderWidgetHostView()) | 638 shell()->web_contents()->GetRenderWidgetHostView()) |
| 618 ->GetPhysicalBackingSize(); | 639 ->GetPhysicalBackingSize(); |
| 619 expected_bitmap.allocN32Pixels(view_size.width(), view_size.height()); | 640 expected_bitmap.allocN32Pixels(view_size.width(), view_size.height()); |
| 620 expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56)); | 641 expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56)); |
| 621 CaptureScreenshotAndCompareTo(expected_bitmap); | 642 CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG); |
| 643 } |
| 644 |
| 645 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshotJpeg) { |
| 646 // This test fails consistently on low-end Android devices. |
| 647 // See crbug.com/653637. |
| 648 if (base::SysInfo::IsLowEndDevice()) return; |
| 649 |
| 650 shell()->LoadURL(GURL("about:blank")); |
| 651 Attach(); |
| 652 EXPECT_TRUE( |
| 653 content::ExecuteScript(shell()->web_contents()->GetRenderViewHost(), |
| 654 "document.body.style.background = '#123456'")); |
| 655 SkBitmap expected_bitmap; |
| 656 // We compare against the actual physical backing size rather than the |
| 657 // view size, because the view size is stored adjusted for DPI and only in |
| 658 // integer precision. |
| 659 gfx::Size view_size = static_cast<RenderWidgetHostViewBase*>( |
| 660 shell()->web_contents()->GetRenderWidgetHostView()) |
| 661 ->GetPhysicalBackingSize(); |
| 662 expected_bitmap.allocN32Pixels(view_size.width(), view_size.height()); |
| 663 expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56)); |
| 664 CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_JPEG); |
| 622 } | 665 } |
| 623 | 666 |
| 624 // Setting frame size (through RWHV) is not supported on Android. | 667 // Setting frame size (through RWHV) is not supported on Android. |
| 625 #if defined(OS_ANDROID) | 668 #if defined(OS_ANDROID) |
| 626 #define MAYBE_CaptureScreenshotArea DISABLED_CaptureScreenshotArea | 669 #define MAYBE_CaptureScreenshotArea DISABLED_CaptureScreenshotArea |
| 627 #else | 670 #else |
| 628 #define MAYBE_CaptureScreenshotArea CaptureScreenshotArea | 671 #define MAYBE_CaptureScreenshotArea CaptureScreenshotArea |
| 629 #endif | 672 #endif |
| 630 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, | 673 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, |
| 631 MAYBE_CaptureScreenshotArea) { | 674 MAYBE_CaptureScreenshotArea) { |
| (...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1507 EXPECT_EQ("polyglottal", value); | 1550 EXPECT_EQ("polyglottal", value); |
| 1508 found++; | 1551 found++; |
| 1509 } else { | 1552 } else { |
| 1510 FAIL(); | 1553 FAIL(); |
| 1511 } | 1554 } |
| 1512 } | 1555 } |
| 1513 EXPECT_EQ(2u, found); | 1556 EXPECT_EQ(2u, found); |
| 1514 } | 1557 } |
| 1515 | 1558 |
| 1516 } // namespace content | 1559 } // namespace content |
| OLD | NEW |