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