[Release] Webkit-EFL Ver. 2.0_beta_118996_0.6.24
[framework/web/webkit-efl.git] / Tools / DumpRenderTree / gtk / DumpRenderTree.cpp
1 /*
2  * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3  * Copyright (C) 2008 Alp Toker <alp@nuanti.com>
4  * Copyright (C) 2009 Jan Alonzo <jmalonzo@gmail.com>
5  * Copyright (C) 2010, 2011 Igalia S.L.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1.  Redistributions of source code must retain the above copyright
12  *     notice, this list of conditions and the following disclaimer.
13  * 2.  Redistributions in binary form must reproduce the above copyright
14  *     notice, this list of conditions and the following disclaimer in the
15  *     documentation and/or other materials provided with the distribution.
16  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
17  *     its contributors may be used to endorse or promote products derived
18  *     from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
24  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "DumpRenderTree.h"
34
35 #include "AccessibilityController.h"
36 #include "EditingCallbacks.h"
37 #include "EventSender.h"
38 #include "GCController.h"
39 #include "LayoutTestController.h"
40 #include "PixelDumpSupport.h"
41 #include "SelfScrollingWebKitWebView.h"
42 #include "TextInputController.h"
43 #include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
44 #include "WebCoreTestSupport.h"
45 #include "WorkQueue.h"
46 #include "WorkQueueItem.h"
47 #include <JavaScriptCore/JavaScript.h>
48 #include <cassert>
49 #include <cstdlib>
50 #include <cstring>
51 #include <getopt.h>
52 #include <gtk/gtk.h>
53 #include <webkit/webkit.h>
54 #include <wtf/Assertions.h>
55 #include <wtf/gobject/GOwnPtr.h>
56 #include <wtf/gobject/GlibUtilities.h>
57
58 #if PLATFORM(X11)
59 #include <fontconfig/fontconfig.h>
60 #endif
61
62
63 using namespace std;
64
65 extern "C" {
66 // This API is not yet public.
67 extern gchar* webkit_web_history_item_get_target(WebKitWebHistoryItem*);
68 extern gboolean webkit_web_history_item_is_target_item(WebKitWebHistoryItem*);
69 extern GList* webkit_web_history_item_get_children(WebKitWebHistoryItem*);
70 extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view, const gchar* directory);
71 extern gchar* webkit_web_frame_get_response_mime_type(WebKitWebFrame* frame);
72 }
73
74 volatile bool done;
75 static bool printSeparators;
76 static int dumpPixels;
77 static int dumpTree = 1;
78 static int useTimeoutWatchdog = 1;
79
80 AccessibilityController* axController = 0;
81 RefPtr<LayoutTestController> gLayoutTestController;
82 static GCController* gcController = 0;
83 static WebKitWebView* webView;
84 static GtkWidget* window;
85 static GtkWidget* container;
86 static GtkWidget* webInspectorWindow;
87 WebKitWebFrame* mainFrame = 0;
88 WebKitWebFrame* topLoadingFrame = 0;
89 guint waitToDumpWatchdog = 0;
90 bool waitForPolicy = false;
91
92 // This is a list of opened webviews
93 GSList* webViewList = 0;
94
95 // current b/f item at the end of the previous test
96 static WebKitWebHistoryItem* prevTestBFItem = NULL;
97
98 const unsigned historyItemIndent = 8;
99
100 static void runTest(const string& testPathOrURL);
101
102 static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url);
103
104 static bool shouldLogFrameLoadDelegates(const string& pathOrURL)
105 {
106     return pathOrURL.find("loading/") != string::npos;
107 }
108
109 static bool shouldOpenWebInspector(const string& pathOrURL)
110 {
111     return pathOrURL.find("inspector/") != string::npos;
112 }
113
114 static bool shouldDumpAsText(const string& pathOrURL)
115 {
116     return pathOrURL.find("dumpAsText/") != string::npos;
117 }
118
119 static bool shouldEnableDeveloperExtras(const string& pathOrURL)
120 {
121     return true;
122 }
123
124 void dumpFrameScrollPosition(WebKitWebFrame* frame)
125 {
126
127 }
128
129 void displayWebView()
130 {
131     gtk_widget_queue_draw(GTK_WIDGET(webView));
132 }
133
134 static void appendString(gchar*& target, gchar* string)
135 {
136     gchar* oldString = target;
137     target = g_strconcat(target, string, NULL);
138     g_free(oldString);
139 }
140
141 static void initializeGtkFontSettings(const char* testURL)
142 {
143     GtkSettings* settings = gtk_settings_get_default();
144     if (!settings)
145         return;
146     g_object_set(settings,
147                  "gtk-xft-dpi", 98304, // This is 96 * 1024 or 96 DPI according to the GTK+ docs.
148                  "gtk-xft-antialias", 1,
149                  "gtk-xft-hinting", 0,
150                  "gtk-font-name", "Liberation Sans 12",
151                  NULL);
152     gdk_screen_set_resolution(gdk_screen_get_default(), 96.0);
153
154     // One test needs subpixel anti-aliasing turned on, but generally we
155     // want all text in other tests to use to grayscale anti-aliasing.
156     if (testURL && strstr(testURL, "xsettings_antialias_settings.html"))
157         g_object_set(settings, "gtk-xft-rgba", "rgb", NULL);
158     else
159         g_object_set(settings, "gtk-xft-rgba", "none", NULL);
160 }
161
162 CString getTopLevelPath()
163 {
164     if (!g_getenv("WEBKIT_TOP_LEVEL"))
165         g_setenv("WEBKIT_TOP_LEVEL", TOP_LEVEL_DIR, FALSE);
166
167     return TOP_LEVEL_DIR;
168 }
169
170 static void initializeFonts(const char* testURL = 0)
171 {
172 #if PLATFORM(X11)
173     initializeGtkFontSettings(testURL);
174
175     FcInit();
176
177     // If a test resulted a font being added or removed via the @font-face rule, then
178     // we want to reset the FontConfig configuration to prevent it from affecting other tests.
179     static int numFonts = 0;
180     FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication);
181     if (appFontSet && numFonts && appFontSet->nfont == numFonts)
182         return;
183
184     // Load our configuration file, which sets up proper aliases for family
185     // names like sans, serif and monospace.
186     FcConfig* config = FcConfigCreate();
187     GOwnPtr<gchar> fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", NULL));
188     if (!FcConfigParseAndLoad(config, reinterpret_cast<FcChar8*>(fontConfigFilename.get()), true))
189         g_error("Couldn't load font configuration file from: %s", fontConfigFilename.get());
190
191     CString topLevelPath = getTopLevelPath();
192     GOwnPtr<char> fontsPath(g_build_filename(topLevelPath.data(), "WebKitBuild", "Dependencies",
193                                              "Root", "webkitgtk-test-fonts", NULL));
194     if (!g_file_test(fontsPath.get(), static_cast<GFileTest>(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
195         g_error("Could not locate test fonts at %s. Is WEBKIT_TOP_LEVEL set?", fontsPath.get());
196
197     GOwnPtr<GError> error;
198     GOwnPtr<GDir> fontsDirectory(g_dir_open(fontsPath.get(), 0, &error.outPtr()));
199     while (const char* directoryEntry = g_dir_read_name(fontsDirectory.get())) {
200         if (!g_str_has_suffix(directoryEntry, ".ttf") && !g_str_has_suffix(directoryEntry, ".otf"))
201             continue;
202         GOwnPtr<gchar> fontPath(g_build_filename(fontsPath.get(), directoryEntry, NULL));
203         if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(fontPath.get())))
204             g_error("Could not load font at %s!", fontPath.get());
205
206     }
207
208     // Ahem is used by many layout tests.
209     GOwnPtr<gchar> ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", NULL));
210     if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(ahemFontFilename.get())))
211         g_error("Could not load font at %s!", ahemFontFilename.get()); 
212
213     for (int i = 1; i <= 9; i++) {
214         GOwnPtr<gchar> fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i));
215         GOwnPtr<gchar> fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), NULL));
216         if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontPath.get())))
217             g_error("Could not load font at %s!", fontPath.get()); 
218     }
219
220     // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452
221     GOwnPtr<gchar> fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", NULL));
222     if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontWithNoValidEncodingFilename.get())))
223         g_error("Could not load font at %s!", fontWithNoValidEncodingFilename.get()); 
224
225     if (!FcConfigSetCurrent(config))
226         g_error("Could not set the current font configuration!");
227
228     numFonts = FcConfigGetFonts(config, FcSetApplication)->nfont;
229 #endif
230 }
231
232 static gchar* dumpFramesAsText(WebKitWebFrame* frame)
233 {
234     gchar* result = 0;
235
236     // Add header for all but the main frame.
237     bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame);
238
239     CString innerText = DumpRenderTreeSupportGtk::getInnerText(frame);
240     if (isMainFrame)
241         result = g_strdup_printf("%s\n", innerText.data());
242     else {
243         const gchar* frameName = webkit_web_frame_get_name(frame);
244         result = g_strdup_printf("\n--------\nFrame: '%s'\n--------\n%s\n", frameName, innerText.data());
245     }
246
247     if (gLayoutTestController->dumpChildFramesAsText()) {
248         GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame);
249         for (GSList* child = children; child; child = g_slist_next(child))
250             appendString(result, dumpFramesAsText(static_cast<WebKitWebFrame* >(child->data)));
251         g_slist_free(children);
252     }
253
254     return result;
255 }
256
257 static gint compareHistoryItems(gpointer* item1, gpointer* item2)
258 {
259     GOwnPtr<gchar> firstItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1)));
260     GOwnPtr<gchar> secondItemTarget(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item2)));
261     return g_ascii_strcasecmp(firstItemTarget.get(), secondItemTarget.get());
262 }
263
264 static void dumpHistoryItem(WebKitWebHistoryItem* item, int indent, bool current)
265 {
266     ASSERT(item != NULL);
267     int start = 0;
268     g_object_ref(item);
269     if (current) {
270         printf("curr->");
271         start = 6;
272     }
273     for (int i = start; i < indent; i++)
274         putchar(' ');
275
276     // normalize file URLs.
277     const gchar* uri = webkit_web_history_item_get_uri(item);
278     gchar* uriScheme = g_uri_parse_scheme(uri);
279     if (g_strcmp0(uriScheme, "file") == 0) {
280         gchar* pos = g_strstr_len(uri, -1, "/LayoutTests/");
281         if (!pos)
282             return;
283
284         GString* result = g_string_sized_new(strlen(uri));
285         result = g_string_append(result, "(file test):");
286         result = g_string_append(result, pos + strlen("/LayoutTests/"));
287         printf("%s", result->str);
288         g_string_free(result, TRUE);
289     } else
290         printf("%s", uri);
291
292     g_free(uriScheme);
293
294     const gchar* target = webkit_web_history_item_get_target(item);
295     if (target && strlen(target) > 0)
296         printf(" (in frame \"%s\")", target);
297     if (webkit_web_history_item_is_target_item(item))
298         printf("  **nav target**");
299     putchar('\n');
300
301     if (GList* kids = webkit_web_history_item_get_children(item)) {
302         // must sort to eliminate arbitrary result ordering which defeats reproducible testing
303         for (GList* kid = g_list_sort(kids, (GCompareFunc) compareHistoryItems); kid; kid = g_list_next(kid)) {
304             WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(kid->data);
305             dumpHistoryItem(item, indent + 4, FALSE);
306             g_object_unref(item);
307         }
308         g_list_free(kids);
309     }
310     g_object_unref(item);
311 }
312
313 static void dumpBackForwardListForWebView(WebKitWebView* view)
314 {
315     printf("\n============== Back Forward List ==============\n");
316     WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(view);
317
318     // Print out all items in the list after prevTestBFItem, which was from the previous test
319     // Gather items from the end of the list, the print them out from oldest to newest
320     GList* itemsToPrint = NULL;
321     gint forwardListCount = webkit_web_back_forward_list_get_forward_length(bfList);
322     for (int i = forwardListCount; i > 0; i--) {
323         WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
324         // something is wrong if the item from the last test is in the forward part of the b/f list
325         ASSERT(item != prevTestBFItem);
326         g_object_ref(item);
327         itemsToPrint = g_list_prepend(itemsToPrint, item);
328     }
329
330     WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList);
331     g_object_ref(currentItem);
332     itemsToPrint = g_list_prepend(itemsToPrint, currentItem);
333
334     gint backListCount = webkit_web_back_forward_list_get_back_length(bfList);
335     for (int i = -1; i >= -(backListCount); i--) {
336         WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
337         if (item == prevTestBFItem)
338             break;
339         g_object_ref(item);
340         itemsToPrint = g_list_prepend(itemsToPrint, item);
341     }
342
343     for (GList* itemToPrint = itemsToPrint; itemToPrint; itemToPrint = g_list_next(itemToPrint)) {
344         WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(itemToPrint->data);
345         dumpHistoryItem(item, historyItemIndent, item == currentItem);
346         g_object_unref(item);
347     }
348
349     g_list_free(itemsToPrint);
350     printf("===============================================\n");
351 }
352
353 static void dumpBackForwardListForAllWebViews()
354 {
355     // Dump the back forward list of the main WebView first
356     dumpBackForwardListForWebView(webView);
357
358     // The view list is prepended. Reverse the list so we get the order right.
359     for (GSList* currentView = g_slist_reverse(webViewList); currentView; currentView = g_slist_next(currentView))
360         dumpBackForwardListForWebView(WEBKIT_WEB_VIEW(currentView->data));
361 }
362
363 void setWaitToDumpWatchdog(guint timer)
364 {
365     waitToDumpWatchdog = timer;
366 }
367
368 bool shouldSetWaitToDumpWatchdog()
369 {
370     return !waitToDumpWatchdog && useTimeoutWatchdog;
371 }
372
373 static void invalidateAnyPreviousWaitToDumpWatchdog()
374 {
375     if (waitToDumpWatchdog) {
376         g_source_remove(waitToDumpWatchdog);
377         waitToDumpWatchdog = 0;
378     }
379
380     waitForPolicy = false;
381 }
382
383 static void resetDefaultsToConsistentValues()
384 {
385     WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
386     GOwnPtr<gchar> localStoragePath(g_build_filename(g_get_user_data_dir(), "DumpRenderTreeGtk", "databases", NULL));
387     g_object_set(G_OBJECT(settings),
388                  "enable-private-browsing", FALSE,
389                  "enable-developer-extras", FALSE,
390                  "enable-spell-checking", TRUE,
391                  "enable-html5-database", TRUE,
392                  "enable-html5-local-storage", TRUE,
393                  "html5-local-storage-database-path", localStoragePath.get(),
394                  "enable-xss-auditor", FALSE,
395                  "enable-spatial-navigation", FALSE,
396                  "enable-frame-flattening", FALSE,
397                  "javascript-can-access-clipboard", TRUE,
398                  "javascript-can-open-windows-automatically", TRUE,
399                  "enable-offline-web-application-cache", TRUE,
400                  "enable-universal-access-from-file-uris", TRUE,
401                  "enable-scripts", TRUE,
402                  "enable-dom-paste", TRUE,
403                  "default-font-family", "Times",
404                  "monospace-font-family", "Courier",
405                  "serif-font-family", "Times",
406                  "sans-serif-font-family", "Helvetica",
407                  "cursive-font-family", "cursive",
408                  "fantasy-font-family", "fantasy",
409                  "default-font-size", 12,
410                  "default-monospace-font-size", 10,
411                  "minimum-font-size", 0,
412                  "enable-caret-browsing", FALSE,
413                  "enable-page-cache", FALSE,
414                  "auto-resize-window", TRUE,
415                  "enable-java-applet", FALSE,
416                  "enable-plugins", TRUE,
417                  "enable-hyperlink-auditing", FALSE,
418                  "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX,
419                  "enable-fullscreen", TRUE,
420                  NULL);
421     webkit_web_view_set_settings(webView, settings);
422     webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
423
424     DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
425     DumpRenderTreeSupportGtk::scalePageBy(webView, 1, 0, 0);
426
427     WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
428     g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL);
429
430     webkit_web_view_set_zoom_level(webView, 1.0);
431     DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, DumpRenderTreeSupportGtk::defaultMinimumTimerInterval());
432
433     DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists();
434
435     WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
436     webkit_web_back_forward_list_clear(list);
437
438     SoupSession* session = webkit_get_default_session();
439     SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
440
441     // We only create the jar when the soup backend needs to do
442     // HTTP. Should we initialize it earlier, perhaps?
443     if (jar)
444         g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
445
446     setlocale(LC_ALL, "");
447
448     DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(true);
449     webkit_icon_database_set_path(webkit_get_icon_database(), 0);
450     DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(false);
451     DumpRenderTreeSupportGtk::setSmartInsertDeleteEnabled(webView, true);
452     DumpRenderTreeSupportGtk::setDefersLoading(webView, false);
453     DumpRenderTreeSupportGtk::setSerializeHTTPLoads(false);
454
455     if (axController)
456         axController->resetToConsistentState();
457
458     DumpRenderTreeSupportGtk::clearOpener(mainFrame);
459
460     DumpRenderTreeSupportGtk::resetGeolocationClientMock(webView);
461
462     DumpRenderTreeSupportGtk::setHixie76WebSocketProtocolEnabled(webView, true);
463 }
464
465 static bool useLongRunningServerMode(int argc, char *argv[])
466 {
467     // This assumes you've already called getopt_long
468     return (argc == optind+1 && !strcmp(argv[optind], "-"));
469 }
470
471 static void runTestingServerLoop()
472 {
473     // When DumpRenderTree runs in server mode, we just wait around for file names
474     // to be passed to us and read each in turn, passing the results back to the client
475     char filenameBuffer[2048];
476     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
477         char* newLineCharacter = strchr(filenameBuffer, '\n');
478         if (newLineCharacter)
479             *newLineCharacter = '\0';
480
481         if (!strlen(filenameBuffer))
482             continue;
483
484         runTest(filenameBuffer);
485     }
486 }
487
488 static void initializeGlobalsFromCommandLineOptions(int argc, char *argv[])
489 {
490     struct option options[] = {
491         {"notree", no_argument, &dumpTree, false},
492         {"pixel-tests", no_argument, &dumpPixels, true},
493         {"tree", no_argument, &dumpTree, true},
494         {"no-timeout", no_argument, &useTimeoutWatchdog, false},
495         {NULL, 0, NULL, 0}
496     };
497     
498     int option;
499     while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
500         switch (option) {
501         case '?': // unknown or ambiguous option
502         case ':': // missing argument
503             exit(1);
504             break;
505         }
506     }
507 }
508
509
510 void dump()
511 {
512     invalidateAnyPreviousWaitToDumpWatchdog();
513
514     // Grab widget focus before dumping the contents of a widget, in
515     // case it was lost in the course of the test.
516     gtk_widget_grab_focus(GTK_WIDGET(webView));
517
518     if (dumpTree) {
519         char* result = 0;
520         gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame);
521
522         if (g_str_equal(responseMimeType, "text/plain")) {
523             gLayoutTestController->setDumpAsText(true);
524             gLayoutTestController->setGeneratePixelResults(false);
525         }
526         g_free(responseMimeType);
527
528         if (gLayoutTestController->dumpAsText())
529             result = dumpFramesAsText(mainFrame);
530         else {
531             // Widget resizing is done asynchronously in GTK+. We pump the main
532             // loop here, to flush any pending resize requests. This prevents
533             // timing issues which affect the size of elements in the output.
534             // We only enable this workaround for tests that print the render tree
535             // because this seems to break some dumpAsText tests: see bug 39988
536             // After fixing that test, we should apply this approach to all dumps.
537             while (gtk_events_pending())
538                 gtk_main_iteration();
539
540             result = g_strdup(DumpRenderTreeSupportGtk::dumpRenderTree(mainFrame).data());
541         }
542
543         if (!result) {
544             const char* errorMessage;
545             if (gLayoutTestController->dumpAsText())
546                 errorMessage = "[documentElement innerText]";
547             else if (gLayoutTestController->dumpDOMAsWebArchive())
548                 errorMessage = "[[mainFrame DOMDocument] webArchive]";
549             else if (gLayoutTestController->dumpSourceAsWebArchive())
550                 errorMessage = "[[mainFrame dataSource] webArchive]";
551             else
552                 errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
553             printf("ERROR: nil result from %s", errorMessage);
554         } else {
555             printf("%s", result);
556             g_free(result);
557             if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())
558                 dumpFrameScrollPosition(mainFrame);
559
560             if (gLayoutTestController->dumpBackForwardList())
561                 dumpBackForwardListForAllWebViews();
562         }
563
564         if (printSeparators) {
565             puts("#EOF"); // terminate the content block
566             fputs("#EOF\n", stderr);
567             fflush(stdout);
568             fflush(stderr);
569         }
570     }
571
572     if (dumpPixels
573      && gLayoutTestController->generatePixelResults()
574      && !gLayoutTestController->dumpDOMAsWebArchive()
575      && !gLayoutTestController->dumpSourceAsWebArchive()) {
576         DumpRenderTreeSupportGtk::forceWebViewPaint(webView);
577         dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
578     }
579
580     // FIXME: call displayWebView here when we support --paint
581
582     done = true;
583     gtk_main_quit();
584 }
585
586 static void setDefaultsToConsistentStateValuesForTesting()
587 {
588     resetDefaultsToConsistentValues();
589
590     /* Disable the default auth dialog for testing */
591     SoupSession* session = webkit_get_default_session();
592     soup_session_remove_feature_by_type(session, WEBKIT_TYPE_SOUP_AUTH_DIALOG);
593
594 #if PLATFORM(X11)
595     webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR);
596 #endif
597
598     gchar* databaseDirectory = g_build_filename(g_get_user_data_dir(), "gtkwebkitdrt", "databases", NULL);
599     webkit_set_web_database_directory_path(databaseDirectory);
600     g_free(databaseDirectory);
601
602 #if defined(GTK_API_VERSION_2)
603     gtk_rc_parse_string("style \"nix_scrollbar_spacing\"                    "
604                         "{                                                  "
605                         "    GtkScrolledWindow::scrollbar-spacing = 0       "
606                         "}                                                  "
607                         "class \"GtkWidget\" style \"nix_scrollbar_spacing\"");
608
609 #else
610     GtkCssProvider* cssProvider = gtk_css_provider_new();
611     gtk_css_provider_load_from_data(cssProvider,
612                                     " * {                                       "
613                                     "   -GtkScrolledWindow-scrollbar-spacing: 0;"
614                                     "}                                          ",
615                                     -1, 0);
616     gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
617                                               GTK_STYLE_PROVIDER(cssProvider),
618                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
619     g_object_unref(cssProvider);
620 #endif
621 }
622
623 static void sendPixelResultsEOF()
624 {
625     puts("#EOF");
626
627     fflush(stdout);
628     fflush(stderr);
629 }
630
631 static void runTest(const string& testPathOrURL)
632 {
633     ASSERT(!testPathOrURL.empty());
634
635     // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
636     string testURL(testPathOrURL);
637     string expectedPixelHash;
638     size_t separatorPos = testURL.find("'");
639     if (separatorPos != string::npos) {
640         testURL = string(testPathOrURL, 0, separatorPos);
641         expectedPixelHash = string(testPathOrURL, separatorPos + 1);
642     }
643
644     // Convert the path into a full file URL if it does not look
645     // like an HTTP/S URL (doesn't start with http:// or https://).
646     if (testURL.find("http://") && testURL.find("https://")) {
647         GFile* testFile = g_file_new_for_path(testURL.c_str());
648         gchar* testURLCString = g_file_get_uri(testFile);
649         testURL = testURLCString;
650         g_free(testURLCString);
651         g_object_unref(testFile);
652     }
653
654     resetDefaultsToConsistentValues();
655
656     gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash);
657     topLoadingFrame = 0;
658     done = false;
659
660     gLayoutTestController->setIconDatabaseEnabled(false);
661
662     if (shouldLogFrameLoadDelegates(testURL))
663         gLayoutTestController->setDumpFrameLoadCallbacks(true);
664
665     if (shouldEnableDeveloperExtras(testURL)) {
666         gLayoutTestController->setDeveloperExtrasEnabled(true);
667         if (shouldOpenWebInspector(testURL))
668             gLayoutTestController->showWebInspector();
669         if (shouldDumpAsText(testURL)) {
670             gLayoutTestController->setDumpAsText(true);
671             gLayoutTestController->setGeneratePixelResults(false);
672         }
673     }
674
675     WorkQueue::shared()->clear();
676     WorkQueue::shared()->setFrozen(false);
677
678     bool isSVGW3CTest = (testURL.find("svg/W3C-SVG-1.1") != string::npos);
679     GtkAllocation size;
680     size.x = size.y = 0;
681     size.width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth;
682     size.height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight;
683     gtk_window_resize(GTK_WINDOW(window), size.width, size.height);
684     gtk_widget_size_allocate(container, &size);
685
686     if (prevTestBFItem)
687         g_object_unref(prevTestBFItem);
688     WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(webView);
689     prevTestBFItem = webkit_web_back_forward_list_get_current_item(bfList);
690     if (prevTestBFItem)
691         g_object_ref(prevTestBFItem);
692
693     initializeFonts(testURL.c_str());
694
695     // Focus the web view before loading the test to avoid focusing problems
696     gtk_widget_grab_focus(GTK_WIDGET(webView));
697     webkit_web_view_open(webView, testURL.c_str());
698
699     gtk_main();
700
701     // If developer extras enabled Web Inspector may have been open by the test.
702     if (shouldEnableDeveloperExtras(testURL)) {
703         gLayoutTestController->closeWebInspector();
704         gLayoutTestController->setDeveloperExtrasEnabled(false);
705     }
706
707     // Also check if we still have opened webViews and free them.
708     if (gLayoutTestController->closeRemainingWindowsWhenComplete() || webViewList) {
709         while (webViewList) {
710             g_object_unref(WEBKIT_WEB_VIEW(webViewList->data));
711             webViewList = g_slist_next(webViewList);
712         }
713         g_slist_free(webViewList);
714         webViewList = 0;
715     }
716
717     WebCoreTestSupport::resetInternalsObject(webkit_web_frame_get_global_context(mainFrame));
718
719     // A blank load seems to be necessary to reset state after certain tests.
720     webkit_web_view_open(webView, "about:blank");
721
722     gLayoutTestController.clear();
723
724     // terminate the (possibly empty) pixels block after all the state reset
725     sendPixelResultsEOF();
726 }
727
728 void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*)
729 {
730     // Make sure we only set this once per test.  If it gets cleared, and then set again, we might
731     // end up doing two dumps for one test.
732     if (!topLoadingFrame && !done)
733         topLoadingFrame = frame;
734 }
735
736 static gboolean processWork(void* data)
737 {
738     // if we finish all the commands, we're ready to dump state
739     if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump())
740         dump();
741
742     return FALSE;
743 }
744
745 static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFrame* frame)
746 {
747     char* frameName = g_strdup(webkit_web_frame_get_name(frame));
748
749     if (frame == webkit_web_view_get_main_frame(view)) {
750         // This is a bit strange. Shouldn't web_frame_get_name return NULL?
751         if (frameName && (frameName[0] != '\0')) {
752             char* tmp = g_strdup_printf("main frame \"%s\"", frameName);
753             g_free(frameName);
754             frameName = tmp;
755         } else {
756             g_free(frameName);
757             frameName = g_strdup("main frame");
758         }
759     } else if (!frameName || (frameName[0] == '\0')) {
760         g_free(frameName);
761         frameName = g_strdup("frame (anonymous)");
762     } else {
763         char* tmp = g_strdup_printf("frame \"%s\"", frameName);
764         g_free(frameName);
765         frameName = tmp;
766     }
767
768     return frameName;
769 }
770
771 static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
772 {
773     // The deprecated "load-finished" signal is triggered by postProgressFinishedNotification(),
774     // so we can use it here in the DRT to provide the correct dump.
775     if (frame != topLoadingFrame)
776         return;
777     if (gLayoutTestController->dumpProgressFinishedCallback())
778         printf("postProgressFinishedNotification\n");
779 }
780
781 static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer)
782 {
783     return TRUE; // Return true here to disable the default error page.
784 }
785
786 static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
787 {
788     if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
789         char* frameName = getFrameNameSuitableForTestResult(view, frame);
790         printf("%s - didFinishDocumentLoadForFrame\n", frameName);
791         g_free(frameName);
792     } else if (!done) {
793         guint pendingFrameUnloadEvents = DumpRenderTreeSupportGtk::getPendingUnloadEventCount(frame);
794         if (pendingFrameUnloadEvents) {
795             char* frameName = getFrameNameSuitableForTestResult(view, frame);
796             printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);
797             g_free(frameName);
798         }
799     }
800 }
801
802 static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*)
803 {
804     if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
805         char* frameName = getFrameNameSuitableForTestResult(view, frame);
806         printf("%s - didHandleOnloadEventsForFrame\n", frameName);
807         g_free(frameName);
808     }
809 }
810
811 static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller)
812 {
813     JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName);
814     JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
815     JSStringRelease(controllerNameStr); 
816 }
817
818 static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data)
819 {
820     JSValueRef exception = 0;
821     ASSERT(gLayoutTestController);
822
823     gLayoutTestController->makeWindowObject(context, windowObject, &exception);
824     ASSERT(!exception);
825
826     gcController->makeWindowObject(context, windowObject, &exception);
827     ASSERT(!exception);
828
829     axController->makeWindowObject(context, windowObject, &exception);
830     ASSERT(!exception);
831
832     addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame)));
833     addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context));
834     WebCoreTestSupport::injectInternalsObject(context);
835 }
836
837 static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
838 {
839     gchar* testMessage = 0;
840     const gchar* uriScheme;
841
842     // Tests expect only the filename part of local URIs
843     uriScheme = g_strstr_len(message, -1, "file://");
844     if (uriScheme) {
845         GString* tempString = g_string_sized_new(strlen(message));
846         gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S);
847
848         if (filename) {
849             // If the path is a lone slash, keep it to avoid empty output.
850             if (strlen(filename) > 1)
851                 filename += strlen(G_DIR_SEPARATOR_S);
852             tempString = g_string_append_len(tempString, message, (uriScheme - message));
853             tempString = g_string_append_len(tempString, filename, strlen(filename));
854             testMessage = g_string_free(tempString, FALSE);
855         }
856     }
857
858     fprintf(stdout, "CONSOLE MESSAGE: ");
859     if (line)
860         fprintf(stdout, "line %d: ", line);
861     fprintf(stdout, "%s\n", testMessage ? testMessage : message);
862     g_free(testMessage);
863
864     return TRUE;
865 }
866
867
868 static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data)
869 {
870     fprintf(stdout, "ALERT: %s\n", message);
871     return TRUE;
872 }
873
874 static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data)
875 {
876     fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue);
877     *value = g_strdup(defaultValue);
878     return TRUE;
879 }
880
881 static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data)
882 {
883     fprintf(stdout, "CONFIRM: %s\n", message);
884     *didConfirm = TRUE;
885     return TRUE;
886 }
887
888 static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data)
889 {
890     if (gLayoutTestController->dumpTitleChanges() && !done)
891         printf("TITLE CHANGED: %s\n", title ? title : "");
892 }
893
894 static bool webViewNavigationPolicyDecisionRequested(WebKitWebView* view, WebKitWebFrame* frame,
895                                                      WebKitNetworkRequest* request,
896                                                      WebKitWebNavigationAction* navAction,
897                                                      WebKitWebPolicyDecision* policyDecision)
898 {
899     // Use the default handler if we're not waiting for policy,
900     // i.e., LayoutTestController::waitForPolicyDelegate
901     if (!waitForPolicy)
902         return FALSE;
903
904     gchar* typeDescription;
905     WebKitWebNavigationReason reason;
906     g_object_get(G_OBJECT(navAction), "reason", &reason, NULL);
907
908     switch(reason) {
909         case WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED:
910             typeDescription = g_strdup("link clicked");
911             break;
912         case WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED:
913             typeDescription = g_strdup("form submitted");
914             break;
915         case WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD:
916             typeDescription = g_strdup("back/forward");
917             break;
918         case WEBKIT_WEB_NAVIGATION_REASON_RELOAD:
919             typeDescription = g_strdup("reload");
920             break;
921         case WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED:
922             typeDescription = g_strdup("form resubmitted");
923             break;
924         case WEBKIT_WEB_NAVIGATION_REASON_OTHER:
925             typeDescription = g_strdup("other");
926             break;
927         default:
928             typeDescription = g_strdup("illegal value");
929     }
930
931     printf("Policy delegate: attempt to load %s with navigation type '%s'\n", webkit_network_request_get_uri(request), typeDescription);
932     g_free(typeDescription);
933
934     webkit_web_policy_decision_ignore(policyDecision);
935     gLayoutTestController->notifyDone();
936
937     return TRUE;
938 }
939
940 static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* message, gpointer data)
941 {
942     // Are we doing anything wrong? One test that does not call
943     // dumpStatusCallbacks gets true here
944     if (gLayoutTestController->dumpStatusCallbacks())
945         printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message);
946 }
947
948 static gboolean webViewClose(WebKitWebView* view)
949 {
950     ASSERT(view);
951
952     webViewList = g_slist_remove(webViewList, view);
953     g_object_unref(view);
954
955     return TRUE;
956 }
957
958 static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, WebKitWebDatabase *database)
959 {
960     ASSERT(view);
961     ASSERT(frame);
962     ASSERT(database);
963
964     WebKitSecurityOrigin* origin = webkit_web_database_get_security_origin(database);
965     if (gLayoutTestController->dumpDatabaseCallbacks()) {
966         printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n",
967             webkit_security_origin_get_protocol(origin),
968             webkit_security_origin_get_host(origin),
969             webkit_security_origin_get_port(origin),
970             webkit_web_database_get_name(database));
971     }
972     webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024);
973 }
974
975 static bool
976 geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision)
977 {
978     if (!gLayoutTestController->isGeolocationPermissionSet())
979         return FALSE;
980     if (gLayoutTestController->geolocationPermission())
981         webkit_geolocation_policy_allow(decision);
982     else
983         webkit_geolocation_policy_deny(decision);
984
985     return TRUE;
986 }
987
988
989 static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
990
991 static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data)
992 {
993     gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), 800, 600);
994     gtk_widget_show_all(webInspectorWindow);
995     return TRUE;
996 }
997
998 static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data)
999 {
1000     gtk_widget_destroy(webInspectorWindow);
1001     webInspectorWindow = 0;
1002     return TRUE;
1003 }
1004
1005 static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data)
1006 {
1007     webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1008
1009     GtkWidget* webView = self_scrolling_webkit_web_view_new();
1010     gtk_container_add(GTK_CONTAINER(webInspectorWindow),
1011                       webView);
1012
1013     return WEBKIT_WEB_VIEW(webView);
1014 }
1015
1016 static void topLoadingFrameLoadFinished()
1017 {
1018     topLoadingFrame = 0;
1019     WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
1020     if (gLayoutTestController->waitToDump())
1021         return;
1022
1023     if (WorkQueue::shared()->count())
1024         g_timeout_add(0, processWork, 0);
1025     else
1026         dump();
1027 }
1028
1029 static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data)
1030 {
1031     WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame);
1032
1033     if (gLayoutTestController->dumpFrameLoadCallbacks()) {
1034         GOwnPtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame));
1035
1036         switch (loadStatus) {
1037         case WEBKIT_LOAD_PROVISIONAL:
1038             if (!done)
1039                 printf("%s - didStartProvisionalLoadForFrame\n", frameName.get());
1040             break;
1041         case WEBKIT_LOAD_COMMITTED:
1042             if (!done)
1043                 printf("%s - didCommitLoadForFrame\n", frameName.get());
1044             break;
1045         case WEBKIT_LOAD_FINISHED:
1046             if (!done)
1047                 printf("%s - didFinishLoadForFrame\n", frameName.get());
1048             break;
1049         default:
1050             break;
1051         }
1052     }
1053
1054     if ((loadStatus == WEBKIT_LOAD_FINISHED || loadStatus == WEBKIT_LOAD_FAILED)
1055         && frame == topLoadingFrame)
1056         topLoadingFrameLoadFinished();
1057 }
1058
1059 static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data)
1060 {
1061     g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
1062     g_signal_connect(webFrame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL);
1063 }
1064
1065
1066 static CString pathFromSoupURI(SoupURI* uri)
1067 {
1068     if (!uri)
1069         return CString();
1070
1071     if (g_str_equal(uri->scheme, "http") || g_str_equal(uri->scheme, "ftp")) {
1072         GOwnPtr<char> uriString(soup_uri_to_string(uri, FALSE));
1073         return CString(uriString.get());
1074     }
1075
1076     GOwnPtr<gchar> pathDirname(g_path_get_basename(g_path_get_dirname(uri->path)));
1077     GOwnPtr<gchar> pathBasename(g_path_get_basename(uri->path));
1078     GOwnPtr<gchar> urlPath(g_strdup_printf("%s/%s", pathDirname.get(), pathBasename.get()));
1079     return CString(urlPath.get());
1080 }
1081
1082 static CString convertSoupMessageToURLPath(SoupMessage* soupMessage)
1083 {
1084     if (!soupMessage)
1085         return CString();
1086     if (SoupURI* requestURI = soup_message_get_uri(soupMessage))
1087         return pathFromSoupURI(requestURI);
1088     return CString();
1089 }
1090
1091 static CString convertNetworkRequestToURLPath(WebKitNetworkRequest* request)
1092 {
1093     return convertSoupMessageToURLPath(webkit_network_request_get_message(request));
1094 }
1095
1096 static CString convertWebResourceToURLPath(WebKitWebResource* webResource)
1097 {
1098     SoupURI* uri = soup_uri_new(webkit_web_resource_get_uri(webResource));
1099     CString urlPath(pathFromSoupURI(uri));
1100     soup_uri_free(uri);
1101     return urlPath;
1102 }
1103
1104 static CString urlSuitableForTestResult(const char* uriString)
1105 {
1106     if (!g_str_has_prefix(uriString, "file://"))
1107         return CString(uriString);
1108
1109     GOwnPtr<gchar> basename(g_path_get_basename(uriString));
1110     return CString(basename.get());
1111 }
1112
1113 static CString descriptionSuitableForTestResult(SoupURI* uri)
1114 {
1115     if (!uri)
1116         return CString("");
1117
1118     GOwnPtr<char> uriString(soup_uri_to_string(uri, false));
1119     return urlSuitableForTestResult(uriString.get());
1120 }
1121
1122 static CString descriptionSuitableForTestResult(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource)
1123 {
1124     SoupURI* uri = soup_uri_new(webkit_web_resource_get_uri(webResource));
1125     CString description;
1126     WebKitWebDataSource* dataSource = webkit_web_frame_get_data_source(webFrame);
1127
1128     if (webResource == webkit_web_data_source_get_main_resource(dataSource)
1129         && (!webkit_web_view_get_progress(webView) || g_str_equal(uri->scheme, "file")))
1130         description = CString("<unknown>");
1131     else
1132         description = convertWebResourceToURLPath(webResource);
1133
1134     if (uri)
1135         soup_uri_free(uri);
1136
1137     return description;
1138 }
1139
1140 static CString descriptionSuitableForTestResult(GError* error, WebKitWebResource* webResource)
1141 {
1142     const gchar* errorDomain = g_quark_to_string(error->domain);
1143     CString resourceURIString(urlSuitableForTestResult(webkit_web_resource_get_uri(webResource)));
1144
1145     if (g_str_equal(errorDomain, "webkit-network-error-quark") || g_str_equal(errorDomain, "soup_http_error_quark"))
1146         errorDomain = "NSURLErrorDomain";
1147
1148     if (g_str_equal(errorDomain, "WebKitPolicyError"))
1149         errorDomain = "WebKitErrorDomain";
1150
1151     // TODO: the other ports get the failingURL from the ResourceError
1152     GOwnPtr<char> errorString(g_strdup_printf("<NSError domain %s, code %d, failing URL \"%s\">",
1153                                               errorDomain, error->code, resourceURIString.data()));
1154     return CString(errorString.get());
1155 }
1156
1157 static CString descriptionSuitableForTestResult(WebKitNetworkRequest* request)
1158 {
1159     SoupMessage* soupMessage = webkit_network_request_get_message(request);
1160
1161     if (!soupMessage)
1162         return CString("");
1163
1164     SoupURI* requestURI = soup_message_get_uri(soupMessage);
1165     SoupURI* mainDocumentURI = soup_message_get_first_party(soupMessage);
1166     CString requestURIString(descriptionSuitableForTestResult(requestURI));
1167     CString mainDocumentURIString(descriptionSuitableForTestResult(mainDocumentURI));
1168     CString path(convertNetworkRequestToURLPath(request));
1169     GOwnPtr<char> description(g_strdup_printf("<NSURLRequest URL %s, main document URL %s, http method %s>",
1170                                               path.data(), mainDocumentURIString.data(),
1171                                               soupMessage ? soupMessage->method : "(none)"));
1172     return CString(description.get());
1173 }
1174
1175 static CString descriptionSuitableForTestResult(WebKitNetworkResponse* response)
1176 {
1177     if (!response)
1178         return CString("(null)");
1179
1180     int statusCode = 0;
1181     CString responseURIString(urlSuitableForTestResult(webkit_network_response_get_uri(response)));
1182     SoupMessage* soupMessage = webkit_network_response_get_message(response);
1183     CString path;
1184
1185     if (soupMessage) {
1186         statusCode = soupMessage->status_code;
1187         path = convertSoupMessageToURLPath(soupMessage);
1188     } else
1189         path = CString("");
1190
1191     GOwnPtr<char> description(g_strdup_printf("<NSURLResponse %s, http status code %d>", path.data(), statusCode));
1192     return CString(description.get());
1193 }
1194
1195 static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* resource, WebKitNetworkRequest* request, WebKitNetworkResponse* response)
1196 {
1197
1198
1199     if (!done && gLayoutTestController->willSendRequestReturnsNull()) {
1200         // As requested by the LayoutTestController, don't perform the request.
1201         webkit_network_request_set_uri(request, "about:blank");
1202         return;
1203     }
1204
1205     if (!done && gLayoutTestController->dumpResourceLoadCallbacks())
1206         printf("%s - willSendRequest %s redirectResponse %s\n",
1207                convertNetworkRequestToURLPath(request).data(),
1208                descriptionSuitableForTestResult(request).data(),
1209                descriptionSuitableForTestResult(response).data());
1210
1211     SoupMessage* soupMessage = webkit_network_request_get_message(request);
1212     SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request));
1213
1214     if (SOUP_URI_VALID_FOR_HTTP(uri) && g_strcmp0(uri->host, "127.0.0.1")
1215         && g_strcmp0(uri->host, "255.255.255.255")
1216         && g_ascii_strncasecmp(uri->host, "localhost", 9)) {
1217         printf("Blocked access to external URL %s\n", soup_uri_to_string(uri, FALSE));
1218         // Cancel load of blocked resource to avoid potential
1219         // network-related timeouts in tests.
1220         webkit_network_request_set_uri(request, "about:blank");
1221         soup_uri_free(uri);
1222         return;
1223     }
1224
1225     if (uri)
1226         soup_uri_free(uri);
1227
1228     if (soupMessage) {
1229         const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
1230         for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header)
1231             soup_message_headers_remove(soupMessage->request_headers, header->c_str());
1232     }
1233 }
1234
1235
1236 static void didReceiveResponse(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource* webResource, WebKitNetworkResponse* response)
1237 {
1238     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
1239         CString responseDescription(descriptionSuitableForTestResult(response));
1240         CString path(convertWebResourceToURLPath(webResource));
1241         printf("%s - didReceiveResponse %s\n", path.data(), responseDescription.data());
1242     }
1243
1244     // TODO: add "has MIME type" whenever dumpResourceResponseMIMETypes() is supported.
1245     // See https://bugs.webkit.org/show_bug.cgi?id=58222.
1246 }
1247
1248 static void didFinishLoading(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource)
1249 {
1250     if (!done && gLayoutTestController->dumpResourceLoadCallbacks())
1251         printf("%s - didFinishLoading\n", descriptionSuitableForTestResult(webView, webFrame, webResource).data());
1252 }
1253
1254 static void didFailLoadingWithError(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource, GError* webError)
1255 {
1256     if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) {
1257         CString webErrorString(descriptionSuitableForTestResult(webError, webResource));
1258         printf("%s - didFailLoadingWithError: %s\n", descriptionSuitableForTestResult(webView, webFrame, webResource).data(),
1259                webErrorString.data());
1260     }
1261 }
1262
1263 static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url)
1264 {
1265     if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
1266         printf("didRunInsecureContent\n");
1267 }
1268
1269 static WebKitWebView* createWebView()
1270 {
1271     // It is important to declare DRT is running early so when creating
1272     // web view mock clients are used instead of proper ones.
1273     DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true);
1274
1275     WebKitWebView* view = WEBKIT_WEB_VIEW(self_scrolling_webkit_web_view_new());
1276
1277     g_object_connect(G_OBJECT(view),
1278                      "signal::load-started", webViewLoadStarted, 0,
1279                      "signal::load-finished", webViewLoadFinished, 0,
1280                      "signal::load-error", webViewLoadError, 0,
1281                      "signal::window-object-cleared", webViewWindowObjectCleared, 0,
1282                      "signal::console-message", webViewConsoleMessage, 0,
1283                      "signal::script-alert", webViewScriptAlert, 0,
1284                      "signal::script-prompt", webViewScriptPrompt, 0,
1285                      "signal::script-confirm", webViewScriptConfirm, 0,
1286                      "signal::title-changed", webViewTitleChanged, 0,
1287                      "signal::navigation-policy-decision-requested", webViewNavigationPolicyDecisionRequested, 0,
1288                      "signal::status-bar-text-changed", webViewStatusBarTextChanged, 0,
1289                      "signal::create-web-view", webViewCreate, 0,
1290                      "signal::close-web-view", webViewClose, 0,
1291                      "signal::database-quota-exceeded", databaseQuotaExceeded, 0,
1292                      "signal::document-load-finished", webViewDocumentLoadFinished, 0,
1293                      "signal::geolocation-policy-decision-requested", geolocationPolicyDecisionRequested, 0,
1294                      "signal::onload-event", webViewOnloadEvent, 0,
1295                      "signal::drag-begin", dragBeginCallback, 0,
1296                      "signal::drag-end", dragEndCallback, 0,
1297                      "signal::drag-failed", dragFailedCallback, 0,
1298                      "signal::frame-created", frameCreatedCallback, 0,
1299                      "signal::resource-request-starting", willSendRequestCallback, 0,
1300                      "signal::resource-response-received", didReceiveResponse, 0,
1301                      "signal::resource-load-finished", didFinishLoading, 0,
1302                      "signal::resource-load-failed", didFailLoadingWithError, 0,
1303                      NULL);
1304     connectEditingCallbacks(view);
1305
1306     WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
1307     g_object_connect(G_OBJECT(inspector),
1308                      "signal::inspect-web-view", webInspectorInspectWebView, 0,
1309                      "signal::show-window", webInspectorShowWindow, 0,
1310                      "signal::close-window", webInspectorCloseWindow, 0,
1311                      NULL);
1312
1313     if (webView) {
1314         WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
1315         webkit_web_view_set_settings(view, settings);
1316     }
1317
1318     // frame-created is not issued for main frame. That's why we must do this here
1319     WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
1320     g_signal_connect(frame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
1321     g_signal_connect(frame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL);
1322
1323     return view;
1324 }
1325
1326 static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame)
1327 {
1328     if (!gLayoutTestController->canOpenWindows())
1329         return 0;
1330
1331     // Make sure that waitUntilDone has been called.
1332     ASSERT(gLayoutTestController->waitToDump());
1333
1334     WebKitWebView* newWebView = createWebView();
1335     g_object_ref_sink(G_OBJECT(newWebView));
1336     webViewList = g_slist_prepend(webViewList, newWebView);
1337     return newWebView;
1338 }
1339
1340 static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data)
1341 {
1342     if (level < G_LOG_LEVEL_DEBUG)
1343         fprintf(stderr, "%s\n", message);
1344 }
1345
1346 int main(int argc, char* argv[])
1347 {
1348     gtk_init(&argc, &argv);
1349
1350     // Some plugins might try to use the GLib logger for printing debug
1351     // messages. This will cause tests to fail because of unexpected output.
1352     // We squelch all debug messages sent to the logger.
1353     g_log_set_default_handler(logHandler, 0);
1354
1355     initializeGlobalsFromCommandLineOptions(argc, argv);
1356     initializeFonts();
1357
1358     window = gtk_window_new(GTK_WINDOW_POPUP);
1359 #ifdef GTK_API_VERSION_2
1360     container = gtk_hbox_new(TRUE, 0);
1361 #else
1362     container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1363     gtk_box_set_homogeneous(GTK_BOX(container), TRUE);
1364 #endif
1365     gtk_container_add(GTK_CONTAINER(window), container);
1366     gtk_widget_show_all(window);
1367
1368     webView = createWebView();
1369     gtk_box_pack_start(GTK_BOX(container), GTK_WIDGET(webView), TRUE, TRUE, 0);
1370     gtk_widget_realize(GTK_WIDGET(webView));
1371     gtk_widget_show_all(container);
1372     mainFrame = webkit_web_view_get_main_frame(webView);
1373
1374     setDefaultsToConsistentStateValuesForTesting();
1375
1376     gcController = new GCController();
1377     axController = new AccessibilityController();
1378
1379     if (useLongRunningServerMode(argc, argv)) {
1380         printSeparators = true;
1381         runTestingServerLoop();
1382     } else {
1383         printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));
1384         for (int i = optind; i != argc; ++i)
1385             runTest(argv[i]);
1386     }
1387
1388     delete gcController;
1389     gcController = 0;
1390
1391     delete axController;
1392     axController = 0;
1393
1394     gtk_widget_destroy(window);
1395
1396     return 0;
1397 }