diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
commit | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch) | |
tree | 11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp | |
parent | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff) | |
download | external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp')
-rw-r--r-- | WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp new file mode 100644 index 0000000..13b914d --- /dev/null +++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2008 Alp Toker <alp@nuanti.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DumpRenderTree.h" + +#include "LayoutTestController.h" +#include "WorkQueue.h" +#include "WorkQueueItem.h" + +#include <gtk/gtk.h> +#include <webkit/webkit.h> +#include <JavaScriptCore/JavaScript.h> + +#include <wtf/Assertions.h> + +#include <cassert> +#include <getopt.h> +#include <stdlib.h> +#include <string.h> + +using namespace std; + +extern "C" { +// This API is not yet public. +extern GSList* webkit_web_frame_get_children(WebKitWebFrame* frame); +extern gchar* webkit_web_frame_get_inner_text(WebKitWebFrame* frame); +extern gchar* webkit_web_frame_dump_render_tree(WebKitWebFrame* frame); +} + +volatile bool done; +static bool printSeparators; +static int dumpPixels; +static int dumpTree = 1; + +LayoutTestController* gLayoutTestController = 0; +static WebKitWebView* webView; +WebKitWebFrame* mainFrame = 0; +WebKitWebFrame* topLoadingFrame = 0; +guint waitToDumpWatchdog = 0; + +const unsigned maxViewHeight = 600; +const unsigned maxViewWidth = 800; + +static gchar* autocorrectURL(const gchar* url) +{ + if (strncmp("http://", url, 7) != 0 && strncmp("https://", url, 8) != 0) { + GString* string = g_string_new("file://"); + g_string_append(string, url); + return g_string_free(string, FALSE); + } + + return g_strdup(url); +} + +static bool shouldLogFrameLoadDelegates(const char* pathOrURL) +{ + return strstr(pathOrURL, "loading/"); +} + +void dumpFrameScrollPosition(WebKitWebFrame* frame) +{ + +} + +void displayWebView() +{ + +} + +static void appendString(gchar*& target, gchar* string) +{ + gchar* oldString = target; + target = g_strconcat(target, string, NULL); + g_free(oldString); +} + +static gchar* dumpFramesAsText(WebKitWebFrame* frame) +{ + gchar* result = 0; + + // Add header for all but the main frame. + bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame); + + gchar* innerText = webkit_web_frame_get_inner_text(frame); + if (isMainFrame) + result = g_strdup_printf("%s\n", innerText); + else { + const gchar* frameName = webkit_web_frame_get_name(frame); + result = g_strdup_printf("\n--------\nFrame: '%s'\n--------\n%s\n", frameName, innerText); + } + g_free(innerText); + + if (gLayoutTestController->dumpChildFramesAsText()) { + GSList* children = webkit_web_frame_get_children(frame); + for (GSList* child = children; child; child = g_slist_next(child)) + appendString(result, dumpFramesAsText((WebKitWebFrame*)children->data)); + g_slist_free(children); + } + + return result; +} + +static void invalidateAnyPreviousWaitToDumpWatchdog() +{ + if (waitToDumpWatchdog) { + g_source_remove(waitToDumpWatchdog); + waitToDumpWatchdog = 0; + } +} + +void dump() +{ + invalidateAnyPreviousWaitToDumpWatchdog(); + if (dumpTree) { + char* result = 0; + + bool dumpAsText = gLayoutTestController->dumpAsText(); + // FIXME: Also dump text resuls as text. + gLayoutTestController->setDumpAsText(dumpAsText); + if (gLayoutTestController->dumpAsText()) + result = dumpFramesAsText(mainFrame); + else { + bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos); + GtkAllocation size; + size.width = isSVGW3CTest ? 480 : maxViewWidth; + size.height = isSVGW3CTest ? 360 : maxViewHeight; + gtk_widget_size_allocate(GTK_WIDGET(webView), &size); + + result = webkit_web_frame_dump_render_tree(mainFrame); + } + + if (!result) { + const char* errorMessage; + if (gLayoutTestController->dumpAsText()) + errorMessage = "[documentElement innerText]"; + else if (gLayoutTestController->dumpDOMAsWebArchive()) + errorMessage = "[[mainFrame DOMDocument] webArchive]"; + else if (gLayoutTestController->dumpSourceAsWebArchive()) + errorMessage = "[[mainFrame dataSource] webArchive]"; + else + errorMessage = "[mainFrame renderTreeAsExternalRepresentation]"; + printf("ERROR: nil result from %s", errorMessage); + } else { + printf("%s", result); + g_free(result); + if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) + dumpFrameScrollPosition(mainFrame); + } + + if (gLayoutTestController->dumpBackForwardList()) { + // FIXME: not implemented + } + + if (printSeparators) { + puts("#EOF"); // terminate the content block + fputs("#EOF\n", stderr); + fflush(stdout); + fflush(stderr); + } + } + + if (dumpPixels) { + if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive()) { + // FIXME: Add support for dumping pixels + } + } + + // FIXME: call displayWebView here when we support --paint + + puts("#EOF"); // terminate the (possibly empty) pixels block + + fflush(stdout); + fflush(stderr); + + done = true; +} + +static void setDefaultsToConsistentStateValuesForTesting() +{ + WebKitWebSettings *settings = webkit_web_view_get_settings(webView); + + g_object_set(G_OBJECT(settings), + "default-font-family", "Times", + "monospace-font-family", "Courier", + "serif-font-family", "Times", + "sans-serif-font-family", "Helvetica", + "default-font-size", 16, + "default-monospace-font-size", 13, + "minimum-font-size", 1, + NULL); +} + +static void runTest(const string& testPathOrURL) +{ + ASSERT(!testPathOrURL.empty()); + + // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows. + string pathOrURL(testPathOrURL); + string expectedPixelHash; + + size_t separatorPos = pathOrURL.find("'"); + if (separatorPos != string::npos) { + pathOrURL = string(testPathOrURL, 0, separatorPos); + expectedPixelHash = string(testPathOrURL, separatorPos + 1); + } + + gchar* url = autocorrectURL(pathOrURL.c_str()); + const string testURL(url); + + gLayoutTestController = new LayoutTestController(testURL, expectedPixelHash); + topLoadingFrame = 0; + done = false; + + if (shouldLogFrameLoadDelegates(pathOrURL.c_str())) + gLayoutTestController->setDumpFrameLoadCallbacks(true); + + WorkQueue::shared()->clear(); + WorkQueue::shared()->setFrozen(false); + + webkit_web_view_open(webView, url); + + g_free(url); + url = NULL; + + while (!done) + g_main_context_iteration(NULL, TRUE); + + // A blank load seems to be necessary to reset state after certain tests. + webkit_web_view_open(webView, "about:blank"); + + gLayoutTestController->deref(); + gLayoutTestController = 0; +} + +void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*) +{ + // Make sure we only set this once per test. If it gets cleared, and then set again, we might + // end up doing two dumps for one test. + if (!topLoadingFrame && !done) + topLoadingFrame = frame; +} + +static gboolean processWork(void* data) +{ + // quit doing work once a load is in progress + while (WorkQueue::shared()->count() > 0 && !topLoadingFrame) { + WorkQueueItem* item = WorkQueue::shared()->dequeue(); + ASSERT(item); + item->invoke(); + delete item; + } + + // if we didn't start a new load, then we finished all the commands, so we're ready to dump state + if (!topLoadingFrame && !gLayoutTestController->waitToDump()) + dump(); + + return FALSE; +} + +static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*) +{ + if (frame != topLoadingFrame) + return; + + topLoadingFrame = 0; + WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test + if (gLayoutTestController->waitToDump()) + return; + + if (WorkQueue::shared()->count()) + g_timeout_add(0, processWork, 0); + else + dump(); +} + +static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data) +{ + JSValueRef exception = 0; + assert(gLayoutTestController); + + gLayoutTestController->makeWindowObject(context, windowObject, &exception); + assert(!exception); +} + +static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data) +{ + fprintf(stdout, "CONSOLE MESSAGE: line %d: %s\n", line, message); + return TRUE; +} + + +static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data) +{ + fprintf(stdout, "ALERT: %s\n", message); + return TRUE; +} + +static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data) +{ + fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue); + *value = g_strdup(defaultValue); + return TRUE; +} + +static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data) +{ + fprintf(stdout, "CONFIRM: %s\n", message); + *didConfirm = TRUE; + return TRUE; +} + +static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data) +{ + if (gLayoutTestController->dumpTitleChanges() && !done) + printf("TITLE CHANGED: %s\n", title ? title : ""); +} + +int main(int argc, char* argv[]) +{ + g_thread_init(NULL); + gtk_init(&argc, &argv); + + struct option options[] = { + {"notree", no_argument, &dumpTree, false}, + {"pixel-tests", no_argument, &dumpPixels, true}, + {"tree", no_argument, &dumpTree, true}, + {NULL, 0, NULL, 0} + }; + + int option; + while ((option = getopt_long(argc, (char* const*)argv, "", options, NULL)) != -1) + switch (option) { + case '?': // unknown or ambiguous option + case ':': // missing argument + exit(1); + break; + } + + GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP); + GtkContainer* container = GTK_CONTAINER(gtk_fixed_new()); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(container)); + gtk_widget_realize(window); + + webView = WEBKIT_WEB_VIEW(webkit_web_view_new()); + gtk_container_add(container, GTK_WIDGET(webView)); + gtk_widget_realize(GTK_WIDGET(webView)); + mainFrame = webkit_web_view_get_main_frame(webView); + + g_signal_connect(G_OBJECT(webView), "load-started", G_CALLBACK(webViewLoadStarted), 0); + g_signal_connect(G_OBJECT(webView), "load-finished", G_CALLBACK(webViewLoadFinished), 0); + g_signal_connect(G_OBJECT(webView), "window-object-cleared", G_CALLBACK(webViewWindowObjectCleared), 0); + g_signal_connect(G_OBJECT(webView), "console-message", G_CALLBACK(webViewConsoleMessage), 0); + g_signal_connect(G_OBJECT(webView), "script-alert", G_CALLBACK(webViewScriptAlert), 0); + g_signal_connect(G_OBJECT(webView), "script-prompt", G_CALLBACK(webViewScriptPrompt), 0); + g_signal_connect(G_OBJECT(webView), "script-confirm", G_CALLBACK(webViewScriptConfirm), 0); + g_signal_connect(G_OBJECT(webView), "title-changed", G_CALLBACK(webViewTitleChanged), 0); + + setDefaultsToConsistentStateValuesForTesting(); + + if (argc == optind+1 && strcmp(argv[optind], "-") == 0) { + char filenameBuffer[2048]; + printSeparators = true; + while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) { + char* newLineCharacter = strchr(filenameBuffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (strlen(filenameBuffer) == 0) + continue; + + runTest(filenameBuffer); + } + } else { + printSeparators = (optind < argc-1 || (dumpPixels && dumpTree)); + for (int i = optind; i != argc; ++i) + runTest(argv[i]); + } + + return 0; +} |