diff options
author | jochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-27 10:58:51 +0000 |
---|---|---|
committer | jochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-27 10:58:51 +0000 |
commit | 0799da03522c8fe06136710ea409c4e8d468f45c (patch) | |
tree | dbe61f3d30738e185f67a0cecbe43f90579c0c38 /content/shell | |
parent | c91bb26fa85807df212657eb025c2c69be100b9f (diff) | |
download | chromium_src-0799da03522c8fe06136710ea409c4e8d468f45c.zip chromium_src-0799da03522c8fe06136710ea409c4e8d468f45c.tar.gz chromium_src-0799da03522c8fe06136710ea409c4e8d468f45c.tar.bz2 |
Add basic support to dump pixel results
BUG=111316
TEST="webkit/tools/layout_tests/run_webkit_tests.py --chromium --debug --driver-name=content_shell --additional-drt-flag=--dump-render-tree css3/css3-modsel-33.html" should pass
Review URL: https://chromiumcodereview.appspot.com/10656044
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144436 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/shell')
-rw-r--r-- | content/shell/layout_test_controller.cc | 68 | ||||
-rw-r--r-- | content/shell/layout_test_controller.h | 1 | ||||
-rw-r--r-- | content/shell/layout_test_controller_host.cc | 59 | ||||
-rw-r--r-- | content/shell/layout_test_controller_host.h | 7 | ||||
-rw-r--r-- | content/shell/shell_browser_main.cc | 31 | ||||
-rw-r--r-- | content/shell/shell_messages.h | 12 |
6 files changed, 163 insertions, 15 deletions
diff --git a/content/shell/layout_test_controller.cc b/content/shell/layout_test_controller.cc index faef0cd..3a7439f 100644 --- a/content/shell/layout_test_controller.cc +++ b/content/shell/layout_test_controller.cc @@ -4,19 +4,26 @@ #include "content/shell/layout_test_controller.h" +#include "base/md5.h" #include "base/stringprintf.h" #include "content/public/renderer/render_view.h" #include "content/shell/shell_messages.h" +#include "skia/ext/platform_canvas.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCString.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "webkit/glue/webkit_glue.h" using WebKit::WebFrame; using WebKit::WebElement; +using WebKit::WebRect; using WebKit::WebSize; +using WebKit::WebView; namespace content { @@ -84,6 +91,47 @@ std::string DumpFrameScrollPosition(WebFrame* frame, bool recursive) { return result; } +bool PaintViewIntoCanvas(WebView* view, skia::PlatformCanvas& canvas) { + view->layout(); + const WebSize& size = view->size(); + + if (!canvas.initialize(size.width, size.height, true)) + return false; + + view->paint(webkit_glue::ToWebCanvas(&canvas), + WebRect(0, 0, size.width, size.height)); + return true; +} + +#if !defined(OS_MACOSX) +void MakeBitmapOpaque(SkBitmap* bitmap) { + SkAutoLockPixels lock(*bitmap); + DCHECK(bitmap->config() == SkBitmap::kARGB_8888_Config); + for (int y = 0; y < bitmap->height(); ++y) { + uint32_t* row = bitmap->getAddr32(0, y); + for (int x = 0; x < bitmap->width(); ++x) + row[x] |= 0xFF000000; // Set alpha bits to 1. + } +} +#endif + +void CaptureSnapshot(WebView* view, SkBitmap* snapshot) { + skia::PlatformCanvas canvas; + if (!PaintViewIntoCanvas(view, canvas)) + return; + + SkDevice* device = skia::GetTopDevice(canvas); + + const SkBitmap& bitmap = device->accessBitmap(false); + bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config); + +#if !defined(OS_MACOSX) + // Only the expected PNGs for Mac have a valid alpha channel. + MakeBitmapOpaque(snapshot); +#endif + +} + } // namespace LayoutTestController::LayoutTestController(RenderView* render_view) @@ -102,6 +150,7 @@ bool LayoutTestController::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(LayoutTestController, message) IPC_MESSAGE_HANDLER(ShellViewMsg_CaptureTextDump, OnCaptureTextDump) + IPC_MESSAGE_HANDLER(ShellViewMsg_CaptureImageDump, OnCaptureImageDump) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -126,4 +175,23 @@ void LayoutTestController::OnCaptureTextDump(bool as_text, Send(new ShellViewHostMsg_TextDump(routing_id(), dump)); } +void LayoutTestController::OnCaptureImageDump( + const std::string& expected_pixel_hash) { + SkBitmap snapshot; + CaptureSnapshot(render_view()->GetWebView(), &snapshot); + + SkAutoLockPixels snapshot_lock(snapshot); + base::MD5Digest digest; + base::MD5Sum(snapshot.getPixels(), snapshot.getSize(), &digest); + std::string actual_pixel_hash = base::MD5DigestToBase16(digest); + + if (actual_pixel_hash == expected_pixel_hash) { + SkBitmap empty_image; + Send(new ShellViewHostMsg_ImageDump( + routing_id(), actual_pixel_hash, empty_image)); + } + Send(new ShellViewHostMsg_ImageDump( + routing_id(), actual_pixel_hash, snapshot)); +} + } // namespace content diff --git a/content/shell/layout_test_controller.h b/content/shell/layout_test_controller.h index b8e06b5..1b3faae 100644 --- a/content/shell/layout_test_controller.h +++ b/content/shell/layout_test_controller.h @@ -23,6 +23,7 @@ class LayoutTestController : public RenderViewObserver { private: // Message handlers. void OnCaptureTextDump(bool as_text, bool printing, bool recursive); + void OnCaptureImageDump(const std::string& expected_pixel_hash); DISALLOW_COPY_AND_ASSIGN(LayoutTestController); }; diff --git a/content/shell/layout_test_controller_host.cc b/content/shell/layout_test_controller_host.cc index ade2c98..5b52cbd 100644 --- a/content/shell/layout_test_controller_host.cc +++ b/content/shell/layout_test_controller_host.cc @@ -9,6 +9,7 @@ #include "base/message_loop.h" #include "content/public/browser/render_view_host.h" #include "content/shell/shell_messages.h" +#include "webkit/support/webkit_support_gfx.h" namespace content { @@ -18,6 +19,7 @@ const int kTestTimeoutMilliseconds = 30 * 1000; std::map<RenderViewHost*, LayoutTestControllerHost*> LayoutTestControllerHost::controllers_; +std::string LayoutTestControllerHost::expected_pixel_hash_; // static LayoutTestControllerHost* LayoutTestControllerHost::FromRenderViewHost( @@ -29,6 +31,12 @@ LayoutTestControllerHost* LayoutTestControllerHost::FromRenderViewHost( return it->second; } +// static +void LayoutTestControllerHost::Init(const std::string& expected_pixel_hash) { + // TODO(jochen): We should only dump the results for the "main window". + expected_pixel_hash_ = expected_pixel_hash; +} + LayoutTestControllerHost::LayoutTestControllerHost( RenderViewHost* render_view_host) : RenderViewHostObserver(render_view_host), @@ -56,6 +64,11 @@ void LayoutTestControllerHost::CaptureDump() { dump_as_text_, is_printing_, dump_child_frames_)); + if (!dump_as_text_) { + render_view_host()->Send( + new ShellViewMsg_CaptureImageDump(render_view_host()->GetRoutingID(), + expected_pixel_hash_)); + } } void LayoutTestControllerHost::TimeoutHandler() { @@ -70,6 +83,7 @@ bool LayoutTestControllerHost::OnMessageReceived( IPC_BEGIN_MESSAGE_MAP(LayoutTestControllerHost, message) IPC_MESSAGE_HANDLER(ShellViewHostMsg_DidFinishLoad, OnDidFinishLoad) IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump) + IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump) IPC_MESSAGE_HANDLER(ShellViewHostMsg_NotifyDone, OnNotifyDone) IPC_MESSAGE_HANDLER(ShellViewHostMsg_DumpAsText, OnDumpAsText) IPC_MESSAGE_HANDLER(ShellViewHostMsg_DumpChildFramesAsText, @@ -97,7 +111,52 @@ void LayoutTestControllerHost::OnTextDump(const std::string& dump) { std::cout << "#EOF\n"; std::cerr << "#EOF\n"; + if (dump_as_text_) + MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); +} + +void LayoutTestControllerHost::OnImageDump( + const std::string& actual_pixel_hash, + const SkBitmap& image) { +#if !defined(OS_ANDROID) + // DumpRenderTree is not currently supported for Android. Also, on Android + // the required webkit_support methods are not defined, so this method just + // doesn't compile. + + SkAutoLockPixels image_lock(image); + + std::cout << "\nActualHash: " << actual_pixel_hash << "\n"; + if (!expected_pixel_hash_.empty()) + std::cout << "\nExpectedHash: " << expected_pixel_hash_ << "\n"; + + // Only encode and dump the png if the hashes don't match. Encoding the + // image is really expensive. + if (actual_pixel_hash != expected_pixel_hash_) { + std::vector<unsigned char> png; + + // Only the expected PNGs for Mac have a valid alpha channel. +#if defined(OS_MACOSX) + bool discard_transparency = false; +#else + bool discard_transparency = true; +#endif + + webkit_support::EncodeBGRAPNGWithChecksum( + reinterpret_cast<const unsigned char*>(image.getPixels()), + image.width(), + image.height(), + static_cast<int>(image.rowBytes()), + discard_transparency, + actual_pixel_hash, + &png); + + std::cout << "Content-Type: image/png\n"; + std::cout << "Content-Length: " << png.size() << "\n"; + std::cout.write(reinterpret_cast<const char*>(&png[0]), png.size()); + } + MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); +#endif } void LayoutTestControllerHost::OnNotifyDone() { diff --git a/content/shell/layout_test_controller_host.h b/content/shell/layout_test_controller_host.h index 7ff3d45..e31f610 100644 --- a/content/shell/layout_test_controller_host.h +++ b/content/shell/layout_test_controller_host.h @@ -12,6 +12,8 @@ #include "base/cancelable_callback.h" #include "content/public/browser/render_view_host_observer.h" +class SkBitmap; + namespace content { class LayoutTestControllerHost : public RenderViewHostObserver { @@ -19,6 +21,9 @@ class LayoutTestControllerHost : public RenderViewHostObserver { static LayoutTestControllerHost* FromRenderViewHost( RenderViewHost* render_view_host); + // Initialize the LayoutTestControllerHost for a given test. + static void Init(const std::string& expected_pixel_hash); + explicit LayoutTestControllerHost(RenderViewHost* render_view_host); virtual ~LayoutTestControllerHost(); @@ -36,6 +41,7 @@ class LayoutTestControllerHost : public RenderViewHostObserver { // Message handlers. void OnDidFinishLoad(); void OnTextDump(const std::string& dump); + void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image); // layoutTestController handlers. void OnNotifyDone(); @@ -46,6 +52,7 @@ class LayoutTestControllerHost : public RenderViewHostObserver { void OnWaitUntilDone(); static std::map<RenderViewHost*, LayoutTestControllerHost*> controllers_; + static std::string expected_pixel_hash_; bool captured_dump_; diff --git a/content/shell/shell_browser_main.cc b/content/shell/shell_browser_main.cc index f56af33..597f1a0 100644 --- a/content/shell/shell_browser_main.cc +++ b/content/shell/shell_browser_main.cc @@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "base/threading/thread_restrictions.h" #include "content/public/browser/browser_main_runner.h" +#include "content/shell/layout_test_controller_host.h" #include "content/shell/shell.h" #include "content/shell/shell_browser_context.h" #include "content/shell/shell_content_browser_client.h" @@ -19,7 +20,8 @@ namespace { -GURL GetURLForLayoutTest(const char* test_name) { +GURL GetURLForLayoutTest(const char* test_name, + std::string* expected_pixel_hash) { #if defined(OS_ANDROID) // DumpRenderTree is not currently supported for Android using the content // shell. @@ -28,18 +30,13 @@ GURL GetURLForLayoutTest(const char* test_name) { #else std::string path_or_url = test_name; std::string pixel_hash; - std::string timeout; - std::string::size_type separator_position = path_or_url.find(' '); + std::string::size_type separator_position = path_or_url.find('\''); if (separator_position != std::string::npos) { - timeout = path_or_url.substr(separator_position + 1); + pixel_hash = path_or_url.substr(separator_position + 1); path_or_url.erase(separator_position); - separator_position = path_or_url.find(' '); - if (separator_position != std::string::npos) { - pixel_hash = timeout.substr(separator_position + 1); - timeout.erase(separator_position); - } } - // TODO(jochen): use pixel_hash and timeout. + if (expected_pixel_hash) + *expected_pixel_hash = pixel_hash; GURL test_url = webkit_support::CreateURLForPathOrURL(path_or_url); { // We're outside of the message loop here, and this is a test. @@ -86,11 +83,15 @@ int ShellBrowserMain(const content::MainFunctionParams& parameters) { // Test header. std::cout << "Content-Type: text/plain\n"; - content::Shell::CreateNewWindow(browser_context, - GetURLForLayoutTest(test_string), - NULL, - MSG_ROUTING_NONE, - NULL); + std::string pixel_hash; + content::Shell::CreateNewWindow( + browser_context, + GetURLForLayoutTest(test_string, &pixel_hash), + NULL, + MSG_ROUTING_NONE, + NULL); + content::LayoutTestControllerHost::Init(pixel_hash); + main_runner_->Run(); content::Shell::CloseAllWindows(); diff --git a/content/shell/shell_messages.h b/content/shell/shell_messages.h index 50ce122..ddf2a4a 100644 --- a/content/shell/shell_messages.h +++ b/content/shell/shell_messages.h @@ -5,7 +5,9 @@ // Multiply-included file, no traditional include guard. #include <string> +#include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" +#include "third_party/skia/include/core/SkBitmap.h" #define IPC_MESSAGE_START ShellMsgStart @@ -16,10 +18,20 @@ IPC_MESSAGE_ROUTED3(ShellViewMsg_CaptureTextDump, bool /* printing */, bool /* recursive */) +// Tells the render view to capture an image of the page. The render view +// responds with a ShelLViewHostMsg_ImageDump. +IPC_MESSAGE_ROUTED1(ShellViewMsg_CaptureImageDump, + std::string /* expected pixel hash */) + // Send a text dump of the WebContents to the render host. IPC_MESSAGE_ROUTED1(ShellViewHostMsg_TextDump, std::string /* dump */) +// Send an image dump of the WebContents to the render host. +IPC_MESSAGE_ROUTED2(ShellViewHostMsg_ImageDump, + std::string /* actual pixel hash */, + SkBitmap /* image */) + // The main frame of the render view finished loading. IPC_MESSAGE_ROUTED0(ShellViewHostMsg_DidFinishLoad) |