2011-02-03 Martin Robinson <mrobinson@igalia.com>
[WebKit-https.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 "GOwnPtr.h"
40 #include "LayoutTestController.h"
41 #include "PixelDumpSupport.h"
42 #include "PlainTextController.h"
43 #include "TextInputController.h"
44 #include "WebCoreSupport/DumpRenderTreeSupportGtk.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
56 #if PLATFORM(X11)
57 #include <fontconfig/fontconfig.h>
58 #endif
59
60
61 using namespace std;
62
63 extern "C" {
64 // This API is not yet public.
65 extern G_CONST_RETURN gchar* webkit_web_history_item_get_target(WebKitWebHistoryItem*);
66 extern gboolean webkit_web_history_item_is_target_item(WebKitWebHistoryItem*);
67 extern GList* webkit_web_history_item_get_children(WebKitWebHistoryItem*);
68 extern void webkit_web_settings_add_extra_plugin_directory(WebKitWebView* view, const gchar* directory);
69 extern gchar* webkit_web_frame_get_response_mime_type(WebKitWebFrame* frame);
70 }
71
72 volatile bool done;
73 static bool printSeparators;
74 static int dumpPixels;
75 static int dumpTree = 1;
76
77 AccessibilityController* axController = 0;
78 RefPtr<LayoutTestController> gLayoutTestController;
79 static GCController* gcController = 0;
80 static WebKitWebView* webView;
81 static GtkWidget* window;
82 static GtkWidget* container;
83 static GtkWidget* webInspectorWindow;
84 WebKitWebFrame* mainFrame = 0;
85 WebKitWebFrame* topLoadingFrame = 0;
86 guint waitToDumpWatchdog = 0;
87 bool waitForPolicy = false;
88
89 // This is a list of opened webviews
90 GSList* webViewList = 0;
91
92 // current b/f item at the end of the previous test
93 static WebKitWebHistoryItem* prevTestBFItem = NULL;
94
95 const unsigned historyItemIndent = 8;
96
97 static void runTest(const string& testPathOrURL);
98
99 static bool shouldLogFrameLoadDelegates(const string& pathOrURL)
100 {
101     return pathOrURL.find("loading/") != string::npos;
102 }
103
104 static bool shouldOpenWebInspector(const string& pathOrURL)
105 {
106     return pathOrURL.find("inspector/") != string::npos;
107 }
108
109 static bool shouldDumpAsText(const string& pathOrURL)
110 {
111     return pathOrURL.find("dumpAsText/") != string::npos;
112 }
113
114 static bool shouldEnableDeveloperExtras(const string& pathOrURL)
115 {
116     return true;
117 }
118
119 void dumpFrameScrollPosition(WebKitWebFrame* frame)
120 {
121
122 }
123
124 void displayWebView()
125 {
126     gtk_widget_queue_draw(GTK_WIDGET(webView));
127 }
128
129 static void appendString(gchar*& target, gchar* string)
130 {
131     gchar* oldString = target;
132     target = g_strconcat(target, string, NULL);
133     g_free(oldString);
134 }
135
136 static void initializeGtkFontSettings(const char* testURL)
137 {
138     GtkSettings* settings = gtk_settings_get_default();
139     if (!settings)
140         return;
141     g_object_set(settings,
142                  "gtk-xft-dpi", 98304, // This is 96 * 1024 or 96 DPI according to the GTK+ docs.
143                  "gtk-xft-antialias", 1,
144                  "gtk-xft-hinting", 0,
145                  "gtk-font-name", "Liberation Sans 12",
146                  NULL);
147     gdk_screen_set_resolution(gdk_screen_get_default(), 96.0);
148
149     // One test needs subpixel anti-aliasing turned on, but generally we
150     // want all text in other tests to use to grayscale anti-aliasing.
151     if (testURL && strstr(testURL, "xsettings_antialias_settings.html"))
152         g_object_set(settings, "gtk-xft-rgba", "rgb", NULL);
153     else
154         g_object_set(settings, "gtk-xft-rgba", "none", NULL);
155 }
156
157 static void initializeFonts(const char* testURL = 0)
158 {
159 #if PLATFORM(X11)
160     initializeGtkFontSettings(testURL);
161
162     FcInit();
163
164     // If a test resulted a font being added or removed via the @font-face rule, then
165     // we want to reset the FontConfig configuration to prevent it from affecting other tests.
166     static int numFonts = 0;
167     FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication);
168     if (appFontSet && numFonts && appFontSet->nfont == numFonts)
169         return;
170
171     // Load our configuration file, which sets up proper aliases for family
172     // names like sans, serif and monospace.
173     FcConfig* config = FcConfigCreate();
174     GOwnPtr<gchar> fontConfigFilename(g_build_filename(FONTS_CONF_DIR, "fonts.conf", NULL));
175     if (!FcConfigParseAndLoad(config, reinterpret_cast<FcChar8*>(fontConfigFilename.get()), true))
176         g_error("Couldn't load font configuration file from: %s", fontConfigFilename.get());
177
178     static const char *const fontPaths[][2] = {
179         { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-BoldItalic.ttf",
180           "/usr/share/fonts/liberation/LiberationMono-BoldItalic.ttf", },
181         { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Bold.ttf",
182           "/usr/share/fonts/liberation/LiberationMono-Bold.ttf", },
183         { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Italic.ttf",
184           "/usr/share/fonts/liberation/LiberationMono-Italic.ttf", },
185         { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Regular.ttf",
186           "/usr/share/fonts/liberation/LiberationMono-Regular.ttf", },
187         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-BoldItalic.ttf",
188           "/usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf", },
189         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Bold.ttf",
190           "/usr/share/fonts/liberation/LiberationSans-Bold.ttf", },
191         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Italic.ttf",
192           "/usr/share/fonts/liberation/LiberationSans-Italic.ttf", },
193         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Regular.ttf",
194           "/usr/share/fonts/liberation/LiberationSans-Regular.ttf", },
195         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-BoldItalic.ttf",
196           "/usr/share/fonts/liberation/LiberationSerif-BoldItalic.ttf", },
197         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Bold.ttf",
198           "/usr/share/fonts/liberation/LiberationSerif-Bold.ttf", },
199         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Italic.ttf",
200           "/usr/share/fonts/liberation/LiberationSerif-Italic.ttf", },
201         { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Regular.ttf",
202           "/usr/share/fonts/liberation/LiberationSerif-Regular.ttf", },
203         { "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",
204           "/usr/share/fonts/dejavu/DejaVuSans.ttf", },
205         { "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif.ttf",
206           "/usr/share/fonts/dejavu/DejaVuSerif.ttf", },
207
208         // MathML tests require the STIX fonts.
209         { "/usr/share/fonts/opentype/stix/STIXGeneral.otf",
210           "/usr/share/fonts/stix/STIXGeneral.otf" },
211         { "/usr/share/fonts/opentype/stix/STIXGeneralBolIta.otf",
212           "/usr/share/fonts/stix/STIXGeneralBolIta.otf" },
213         { "/usr/share/fonts/opentype/stix/STIXGeneralBol.otf",
214           "/usr/share/fonts/stix/STIXGeneralBol.otf" },
215         { "/usr/share/fonts/opentype/stix/STIXGeneralItalic.otf",
216           "/usr/share/fonts/stix/STIXGeneralItalic.otf" }
217     };
218
219     // TODO: Some tests use Lucida. We should load these as well, once it becomes
220     // clear how to install these fonts easily on Fedora.
221     for (size_t font = 0; font < G_N_ELEMENTS(fontPaths); font++) {
222         bool found = false;
223         for (size_t path = 0; path < 2; path++) {
224
225             if (g_file_test(fontPaths[font][path], G_FILE_TEST_EXISTS)) {
226                 found = true;
227                 if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(fontPaths[font][path])))
228                     g_error("Could not load font at %s!", fontPaths[font][path]);
229                 else
230                     break;
231             }
232         }
233
234         if (!found)
235             g_error("Could not find font at %s. Either install this font or file a bug "
236                     "at http://bugs.webkit.org if it is installed in another location.",
237                     fontPaths[font][0]);
238     }
239
240     // Ahem is used by many layout tests.
241     GOwnPtr<gchar> ahemFontFilename(g_build_filename(FONTS_CONF_DIR, "AHEM____.TTF", NULL));
242     if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(ahemFontFilename.get())))
243         g_error("Could not load font at %s!", ahemFontFilename.get()); 
244
245     for (int i = 1; i <= 9; i++) {
246         GOwnPtr<gchar> fontFilename(g_strdup_printf("WebKitWeightWatcher%i00.ttf", i));
247         GOwnPtr<gchar> fontPath(g_build_filename(FONTS_CONF_DIR, "..", "..", "fonts", fontFilename.get(), NULL));
248         if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontPath.get())))
249             g_error("Could not load font at %s!", fontPath.get()); 
250     }
251
252     // A font with no valid Fontconfig encoding to test https://bugs.webkit.org/show_bug.cgi?id=47452
253     GOwnPtr<gchar> fontWithNoValidEncodingFilename(g_build_filename(FONTS_CONF_DIR, "FontWithNoValidEncoding.fon", NULL));
254     if (!FcConfigAppFontAddFile(config, reinterpret_cast<FcChar8*>(fontWithNoValidEncodingFilename.get())))
255         g_error("Could not load font at %s!", fontWithNoValidEncodingFilename.get()); 
256
257     if (!FcConfigSetCurrent(config))
258         g_error("Could not set the current font configuration!");
259
260     numFonts = FcConfigGetFonts(config, FcSetApplication)->nfont;
261 #endif
262 }
263
264 static gchar* dumpFramesAsText(WebKitWebFrame* frame)
265 {
266     gchar* result = 0;
267
268     // Add header for all but the main frame.
269     bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame);
270
271     CString innerText = DumpRenderTreeSupportGtk::getInnerText(frame);
272     if (isMainFrame)
273         result = g_strdup_printf("%s\n", innerText.data());
274     else {
275         const gchar* frameName = webkit_web_frame_get_name(frame);
276         result = g_strdup_printf("\n--------\nFrame: '%s'\n--------\n%s\n", frameName, innerText.data());
277     }
278
279     if (gLayoutTestController->dumpChildFramesAsText()) {
280         GSList* children = DumpRenderTreeSupportGtk::getFrameChildren(frame);
281         for (GSList* child = children; child; child = g_slist_next(child))
282             appendString(result, dumpFramesAsText(static_cast<WebKitWebFrame* >(child->data)));
283         g_slist_free(children);
284     }
285
286     return result;
287 }
288
289 static gint compareHistoryItems(gpointer* item1, gpointer* item2)
290 {
291     return g_ascii_strcasecmp(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1)),
292                               webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item2)));
293 }
294
295 static void dumpHistoryItem(WebKitWebHistoryItem* item, int indent, bool current)
296 {
297     ASSERT(item != NULL);
298     int start = 0;
299     g_object_ref(item);
300     if (current) {
301         printf("curr->");
302         start = 6;
303     }
304     for (int i = start; i < indent; i++)
305         putchar(' ');
306
307     // normalize file URLs.
308     const gchar* uri = webkit_web_history_item_get_uri(item);
309     gchar* uriScheme = g_uri_parse_scheme(uri);
310     if (g_strcmp0(uriScheme, "file") == 0) {
311         gchar* pos = g_strstr_len(uri, -1, "/LayoutTests/");
312         if (!pos)
313             return;
314
315         GString* result = g_string_sized_new(strlen(uri));
316         result = g_string_append(result, "(file test):");
317         result = g_string_append(result, pos + strlen("/LayoutTests/"));
318         printf("%s", result->str);
319         g_string_free(result, TRUE);
320     } else
321         printf("%s", uri);
322
323     g_free(uriScheme);
324
325     const gchar* target = webkit_web_history_item_get_target(item);
326     if (target && strlen(target) > 0)
327         printf(" (in frame \"%s\")", target);
328     if (webkit_web_history_item_is_target_item(item))
329         printf("  **nav target**");
330     putchar('\n');
331     GList* kids = webkit_web_history_item_get_children(item);
332     if (kids) {
333         // must sort to eliminate arbitrary result ordering which defeats reproducible testing
334         kids = g_list_sort(kids, (GCompareFunc) compareHistoryItems);
335         for (unsigned i = 0; i < g_list_length(kids); i++)
336             dumpHistoryItem(WEBKIT_WEB_HISTORY_ITEM(g_list_nth_data(kids, i)), indent+4, FALSE);
337     }
338     g_object_unref(item);
339 }
340
341 static void dumpBackForwardListForWebView(WebKitWebView* view)
342 {
343     printf("\n============== Back Forward List ==============\n");
344     WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(view);
345
346     // Print out all items in the list after prevTestBFItem, which was from the previous test
347     // Gather items from the end of the list, the print them out from oldest to newest
348     GList* itemsToPrint = NULL;
349     gint forwardListCount = webkit_web_back_forward_list_get_forward_length(bfList);
350     for (int i = forwardListCount; i > 0; i--) {
351         WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
352         // something is wrong if the item from the last test is in the forward part of the b/f list
353         ASSERT(item != prevTestBFItem);
354         g_object_ref(item);
355         itemsToPrint = g_list_append(itemsToPrint, item);
356     }
357
358     WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList);
359
360     g_object_ref(currentItem);
361     itemsToPrint = g_list_append(itemsToPrint, currentItem);
362
363     gint currentItemIndex = g_list_length(itemsToPrint) - 1;
364     gint backListCount = webkit_web_back_forward_list_get_back_length(bfList);
365     for (int i = -1; i >= -(backListCount); i--) {
366         WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_nth_item(bfList, i);
367         if (item == prevTestBFItem)
368             break;
369         g_object_ref(item);
370         itemsToPrint = g_list_append(itemsToPrint, item);
371     }
372
373     for (int i = g_list_length(itemsToPrint) - 1; i >= 0; i--) {
374         WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(g_list_nth_data(itemsToPrint, i));
375         dumpHistoryItem(item, historyItemIndent, i == currentItemIndex);
376         g_object_unref(item);
377     }
378     g_list_free(itemsToPrint);
379     printf("===============================================\n");
380 }
381
382 static void dumpBackForwardListForAllWebViews()
383 {
384     // Dump the back forward list of the main WebView first
385     dumpBackForwardListForWebView(webView);
386
387     // The view list is prepended. Reverse the list so we get the order right.
388     GSList* viewList = g_slist_reverse(webViewList);
389     for (unsigned i = 0; i < g_slist_length(viewList); ++i)
390         dumpBackForwardListForWebView(WEBKIT_WEB_VIEW(g_slist_nth_data(viewList, i)));
391 }
392
393 static void invalidateAnyPreviousWaitToDumpWatchdog()
394 {
395     if (waitToDumpWatchdog) {
396         g_source_remove(waitToDumpWatchdog);
397         waitToDumpWatchdog = 0;
398     }
399
400     waitForPolicy = false;
401 }
402
403 static void resetDefaultsToConsistentValues()
404 {
405     WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
406     g_object_set(G_OBJECT(settings),
407                  "enable-private-browsing", FALSE,
408                  "enable-developer-extras", FALSE,
409                  "enable-spell-checking", TRUE,
410                  "enable-html5-database", TRUE,
411                  "enable-html5-local-storage", TRUE,
412                  "enable-xss-auditor", FALSE,
413                  "enable-spatial-navigation", FALSE,
414                  "enable-frame-flattening", FALSE,
415                  "javascript-can-access-clipboard", TRUE,
416                  "javascript-can-open-windows-automatically", TRUE,
417                  "enable-offline-web-application-cache", TRUE,
418                  "enable-universal-access-from-file-uris", TRUE,
419                  "enable-scripts", TRUE,
420                  "enable-dom-paste", TRUE,
421                  "default-font-family", "Times",
422                  "monospace-font-family", "Courier",
423                  "serif-font-family", "Times",
424                  "sans-serif-font-family", "Helvetica",
425                  "cursive-font-family", "cursive",
426                  "fantasy-font-family", "fantasy",
427                  "default-font-size", 12,
428                  "default-monospace-font-size", 10,
429                  "minimum-font-size", 0,
430                  "enable-caret-browsing", FALSE,
431                  "enable-page-cache", FALSE,
432                  "auto-resize-window", TRUE,
433                  "enable-java-applet", FALSE,
434                  "enable-plugins", TRUE,
435                  "enable-hyperlink-auditing", FALSE,
436                  "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX,
437                  "enable-fullscreen", TRUE,
438                  NULL);
439     webkit_web_view_set_settings(webView, settings);
440     webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
441
442     DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
443
444     WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
445     g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL);
446
447     webkit_web_view_set_zoom_level(webView, 1.0);
448     DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, DumpRenderTreeSupportGtk::defaultMinimumTimerInterval());
449
450     DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists();
451
452     WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
453     webkit_web_back_forward_list_clear(list);
454
455     SoupSession* session = webkit_get_default_session();
456     SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
457
458     // We only create the jar when the soup backend needs to do
459     // HTTP. Should we initialize it earlier, perhaps?
460     if (jar)
461         g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
462
463     setlocale(LC_ALL, "");
464
465     DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(true);
466     webkit_icon_database_set_path(webkit_get_icon_database(), 0);
467     DumpRenderTreeSupportGtk::setSelectTrailingWhitespaceEnabled(false);
468
469     if (axController)
470         axController->resetToConsistentState();
471
472     DumpRenderTreeSupportGtk::clearOpener(mainFrame);
473 }
474
475 static bool useLongRunningServerMode(int argc, char *argv[])
476 {
477     // This assumes you've already called getopt_long
478     return (argc == optind+1 && !strcmp(argv[optind], "-"));
479 }
480
481 static void runTestingServerLoop()
482 {
483     // When DumpRenderTree runs in server mode, we just wait around for file names
484     // to be passed to us and read each in turn, passing the results back to the client
485     char filenameBuffer[2048];
486     while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
487         char* newLineCharacter = strchr(filenameBuffer, '\n');
488         if (newLineCharacter)
489             *newLineCharacter = '\0';
490
491         if (!strlen(filenameBuffer))
492             continue;
493
494         runTest(filenameBuffer);
495     }
496 }
497
498 static void initializeGlobalsFromCommandLineOptions(int argc, char *argv[])
499 {
500     struct option options[] = {
501         {"notree", no_argument, &dumpTree, false},
502         {"pixel-tests", no_argument, &dumpPixels, true},
503         {"tree", no_argument, &dumpTree, true},
504         {NULL, 0, NULL, 0}
505     };
506     
507     int option;
508     while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
509         switch (option) {
510         case '?': // unknown or ambiguous option
511         case ':': // missing argument
512             exit(1);
513             break;
514         }
515     }
516 }
517
518
519 void dump()
520 {
521     invalidateAnyPreviousWaitToDumpWatchdog();
522
523     if (dumpTree) {
524         char* result = 0;
525         gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame);
526
527         if (g_str_equal(responseMimeType, "text/plain")) {
528             gLayoutTestController->setDumpAsText(true);
529             gLayoutTestController->setGeneratePixelResults(false);
530         }
531         g_free(responseMimeType);
532
533         if (gLayoutTestController->dumpAsText())
534             result = dumpFramesAsText(mainFrame);
535         else {
536             // Widget resizing is done asynchronously in GTK+. We pump the main
537             // loop here, to flush any pending resize requests. This prevents
538             // timing issues which affect the size of elements in the output.
539             // We only enable this workaround for tests that print the render tree
540             // because this seems to break some dumpAsText tests: see bug 39988
541             // After fixing that test, we should apply this approach to all dumps.
542             while (gtk_events_pending())
543                 gtk_main_iteration();
544
545             result = g_strdup(DumpRenderTreeSupportGtk::dumpRenderTree(mainFrame).data());
546         }
547
548         if (!result) {
549             const char* errorMessage;
550             if (gLayoutTestController->dumpAsText())
551                 errorMessage = "[documentElement innerText]";
552             else if (gLayoutTestController->dumpDOMAsWebArchive())
553                 errorMessage = "[[mainFrame DOMDocument] webArchive]";
554             else if (gLayoutTestController->dumpSourceAsWebArchive())
555                 errorMessage = "[[mainFrame dataSource] webArchive]";
556             else
557                 errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
558             printf("ERROR: nil result from %s", errorMessage);
559         } else {
560             printf("%s", result);
561             g_free(result);
562             if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())
563                 dumpFrameScrollPosition(mainFrame);
564
565             if (gLayoutTestController->dumpBackForwardList())
566                 dumpBackForwardListForAllWebViews();
567         }
568
569         if (printSeparators) {
570             puts("#EOF"); // terminate the content block
571             fputs("#EOF\n", stderr);
572             fflush(stdout);
573             fflush(stderr);
574         }
575     }
576
577     if (dumpPixels
578      && gLayoutTestController->generatePixelResults()
579      && !gLayoutTestController->dumpDOMAsWebArchive()
580      && !gLayoutTestController->dumpSourceAsWebArchive())
581         dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
582
583     // FIXME: call displayWebView here when we support --paint
584
585     done = true;
586     gtk_main_quit();
587 }
588
589 static void setDefaultsToConsistentStateValuesForTesting()
590 {
591     resetDefaultsToConsistentValues();
592
593     /* Disable the default auth dialog for testing */
594     SoupSession* session = webkit_get_default_session();
595     soup_session_remove_feature_by_type(session, WEBKIT_TYPE_SOUP_AUTH_DIALOG);
596
597 #if PLATFORM(X11)
598     webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR);
599 #endif
600
601     gchar* databaseDirectory = g_build_filename(g_get_user_data_dir(), "gtkwebkitdrt", "databases", NULL);
602     webkit_set_web_database_directory_path(databaseDirectory);
603     g_free(databaseDirectory);
604
605 #if defined(GTK_API_VERSION_2)
606     gtk_rc_parse_string("style \"nix_scrollbar_spacing\"                    "
607                         "{                                                  "
608                         "    GtkScrolledWindow::scrollbar-spacing = 0       "
609                         "}                                                  "
610                         "class \"GtkWidget\" style \"nix_scrollbar_spacing\"");
611
612 #else
613     GtkCssProvider* cssProvider = gtk_css_provider_new();
614     gtk_css_provider_load_from_data(cssProvider,
615                                     " * {                                       "
616                                     "   -GtkScrolledWindow-scrollbar-spacing: 0;"
617                                     "}                                          ",
618                                     -1, 0);
619     gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()),
620                                               GTK_STYLE_PROVIDER(cssProvider),
621                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
622     g_object_unref(cssProvider);
623 #endif
624 }
625
626 static void sendPixelResultsEOF()
627 {
628     puts("#EOF");
629
630     fflush(stdout);
631     fflush(stderr);
632 }
633
634 static void runTest(const string& testPathOrURL)
635 {
636     ASSERT(!testPathOrURL.empty());
637
638     // Look for "'" as a separator between the path or URL, and the pixel dump hash that follows.
639     string testURL(testPathOrURL);
640     string expectedPixelHash;
641     size_t separatorPos = testURL.find("'");
642     if (separatorPos != string::npos) {
643         testURL = string(testPathOrURL, 0, separatorPos);
644         expectedPixelHash = string(testPathOrURL, separatorPos + 1);
645     }
646
647     // Convert the path into a full file URL if it does not look
648     // like an HTTP/S URL (doesn't start with http:// or https://).
649     if (testURL.find("http://") && testURL.find("https://")) {
650         GFile* testFile = g_file_new_for_path(testURL.c_str());
651         gchar* testURLCString = g_file_get_uri(testFile);
652         testURL = testURLCString;
653         g_free(testURLCString);
654         g_object_unref(testFile);
655     }
656
657     resetDefaultsToConsistentValues();
658
659     gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash);
660     topLoadingFrame = 0;
661     done = false;
662
663     gLayoutTestController->setIconDatabaseEnabled(false);
664
665     if (shouldLogFrameLoadDelegates(testURL))
666         gLayoutTestController->setDumpFrameLoadCallbacks(true);
667
668     if (shouldEnableDeveloperExtras(testURL)) {
669         gLayoutTestController->setDeveloperExtrasEnabled(true);
670         if (shouldOpenWebInspector(testURL))
671             gLayoutTestController->showWebInspector();
672         if (shouldDumpAsText(testURL)) {
673             gLayoutTestController->setDumpAsText(true);
674             gLayoutTestController->setGeneratePixelResults(false);
675         }
676     }
677
678     WorkQueue::shared()->clear();
679     WorkQueue::shared()->setFrozen(false);
680
681     bool isSVGW3CTest = (testURL.find("svg/W3C-SVG-1.1") != string::npos);
682     GtkAllocation size;
683     size.x = size.y = 0;
684     size.width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth;
685     size.height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight;
686     gtk_window_resize(GTK_WINDOW(window), size.width, size.height);
687     gtk_widget_size_allocate(container, &size);
688
689     if (prevTestBFItem)
690         g_object_unref(prevTestBFItem);
691     WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(webView);
692     prevTestBFItem = webkit_web_back_forward_list_get_current_item(bfList);
693     if (prevTestBFItem)
694         g_object_ref(prevTestBFItem);
695
696     initializeFonts(testURL.c_str());
697
698     // Focus the web view before loading the test to avoid focusing problems
699     gtk_widget_grab_focus(GTK_WIDGET(webView));
700     webkit_web_view_open(webView, testURL.c_str());
701
702     gtk_main();
703
704     // If developer extras enabled Web Inspector may have been open by the test.
705     if (shouldEnableDeveloperExtras(testURL)) {
706         gLayoutTestController->closeWebInspector();
707         gLayoutTestController->setDeveloperExtrasEnabled(false);
708     }
709
710     // Also check if we still have opened webViews and free them.
711     if (gLayoutTestController->closeRemainingWindowsWhenComplete() || webViewList) {
712         while (webViewList) {
713             g_object_unref(WEBKIT_WEB_VIEW(webViewList->data));
714             webViewList = g_slist_next(webViewList);
715         }
716         g_slist_free(webViewList);
717         webViewList = 0;
718     }
719
720     // A blank load seems to be necessary to reset state after certain tests.
721     webkit_web_view_open(webView, "about:blank");
722
723     gLayoutTestController.clear();
724
725     // terminate the (possibly empty) pixels block after all the state reset
726     sendPixelResultsEOF();
727 }
728
729 void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*)
730 {
731     // Make sure we only set this once per test.  If it gets cleared, and then set again, we might
732     // end up doing two dumps for one test.
733     if (!topLoadingFrame && !done)
734         topLoadingFrame = frame;
735 }
736
737 static gboolean processWork(void* data)
738 {
739     // if we finish all the commands, we're ready to dump state
740     if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump())
741         dump();
742
743     return FALSE;
744 }
745
746 static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFrame* frame)
747 {
748     char* frameName = g_strdup(webkit_web_frame_get_name(frame));
749
750     if (frame == webkit_web_view_get_main_frame(view)) {
751         // This is a bit strange. Shouldn't web_frame_get_name return NULL?
752         if (frameName && (frameName[0] != '\0')) {
753             char* tmp = g_strdup_printf("main frame \"%s\"", frameName);
754             g_free(frameName);
755             frameName = tmp;
756         } else {
757             g_free(frameName);
758             frameName = g_strdup("main frame");
759         }
760     } else if (!frameName || (frameName[0] == '\0')) {
761         g_free(frameName);
762         frameName = g_strdup("frame (anonymous)");
763     } else {
764         char* tmp = g_strdup_printf("frame \"%s\"", frameName);
765         g_free(frameName);
766         frameName = tmp;
767     }
768
769     return frameName;
770 }
771
772 static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
773 {
774     if (frame != topLoadingFrame)
775         return;
776
777     topLoadingFrame = 0;
778     WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
779     if (gLayoutTestController->waitToDump())
780         return;
781
782     if (WorkQueue::shared()->count())
783         g_timeout_add(0, processWork, 0);
784     else
785         dump();
786 }
787
788 static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer)
789 {
790     return TRUE; // Return true here to disable the default error page.
791 }
792
793 static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
794 {
795     if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
796         char* frameName = getFrameNameSuitableForTestResult(view, frame);
797         printf("%s - didFinishDocumentLoadForFrame\n", frameName);
798         g_free(frameName);
799     } else if (!done) {
800         guint pendingFrameUnloadEvents = DumpRenderTreeSupportGtk::getPendingUnloadEventCount(frame);
801         if (pendingFrameUnloadEvents) {
802             char* frameName = getFrameNameSuitableForTestResult(view, frame);
803             printf("%s - has %u onunload handler(s)\n", frameName, pendingFrameUnloadEvents);
804             g_free(frameName);
805         }
806     }
807 }
808
809 static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*)
810 {
811     if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
812         char* frameName = getFrameNameSuitableForTestResult(view, frame);
813         printf("%s - didHandleOnloadEventsForFrame\n", frameName);
814         g_free(frameName);
815     }
816 }
817
818 static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller)
819 {
820     JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName);
821     JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
822     JSStringRelease(controllerNameStr); 
823 }
824
825 static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data)
826 {
827     JSValueRef exception = 0;
828     ASSERT(gLayoutTestController);
829
830     gLayoutTestController->makeWindowObject(context, windowObject, &exception);
831     ASSERT(!exception);
832
833     gcController->makeWindowObject(context, windowObject, &exception);
834     ASSERT(!exception);
835
836     axController->makeWindowObject(context, windowObject, &exception);
837     ASSERT(!exception);
838
839     addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame)));
840     addControllerToWindow(context, windowObject, "plainText", makePlainTextController(context));
841     addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context));
842 }
843
844 static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
845 {
846     gchar* testMessage = 0;
847     const gchar* uriScheme;
848
849     // Tests expect only the filename part of local URIs
850     uriScheme = g_strstr_len(message, -1, "file://");
851     if (uriScheme) {
852         GString* tempString = g_string_sized_new(strlen(message));
853         gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S);
854
855         if (filename) {
856             filename += strlen(G_DIR_SEPARATOR_S);
857             tempString = g_string_append_len(tempString, message, (uriScheme - message));
858             tempString = g_string_append_len(tempString, filename, strlen(filename));
859             testMessage = g_string_free(tempString, FALSE);
860         }
861     }
862
863     fprintf(stdout, "CONSOLE MESSAGE: line %d: %s\n", line, testMessage ? testMessage : message);
864     g_free(testMessage);
865
866     return TRUE;
867 }
868
869
870 static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data)
871 {
872     fprintf(stdout, "ALERT: %s\n", message);
873     return TRUE;
874 }
875
876 static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data)
877 {
878     fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue);
879     *value = g_strdup(defaultValue);
880     return TRUE;
881 }
882
883 static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data)
884 {
885     fprintf(stdout, "CONFIRM: %s\n", message);
886     *didConfirm = TRUE;
887     return TRUE;
888 }
889
890 static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data)
891 {
892     if (gLayoutTestController->dumpTitleChanges() && !done)
893         printf("TITLE CHANGED: %s\n", title ? title : "");
894 }
895
896 static bool webViewNavigationPolicyDecisionRequested(WebKitWebView* view, WebKitWebFrame* frame,
897                                                      WebKitNetworkRequest* request,
898                                                      WebKitWebNavigationAction* navAction,
899                                                      WebKitWebPolicyDecision* policyDecision)
900 {
901     // Use the default handler if we're not waiting for policy,
902     // i.e., LayoutTestController::waitForPolicyDelegate
903     if (!waitForPolicy)
904         return FALSE;
905
906     gchar* typeDescription;
907     WebKitWebNavigationReason reason;
908     g_object_get(G_OBJECT(navAction), "reason", &reason, NULL);
909
910     switch(reason) {
911         case WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED:
912             typeDescription = g_strdup("link clicked");
913             break;
914         case WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED:
915             typeDescription = g_strdup("form submitted");
916             break;
917         case WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD:
918             typeDescription = g_strdup("back/forward");
919             break;
920         case WEBKIT_WEB_NAVIGATION_REASON_RELOAD:
921             typeDescription = g_strdup("reload");
922             break;
923         case WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED:
924             typeDescription = g_strdup("form resubmitted");
925             break;
926         case WEBKIT_WEB_NAVIGATION_REASON_OTHER:
927             typeDescription = g_strdup("other");
928             break;
929         default:
930             typeDescription = g_strdup("illegal value");
931     }
932
933     printf("Policy delegate: attempt to load %s with navigation type '%s'\n", webkit_network_request_get_uri(request), typeDescription);
934     g_free(typeDescription);
935
936     webkit_web_policy_decision_ignore(policyDecision);
937     gLayoutTestController->notifyDone();
938
939     return TRUE;
940 }
941
942 static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* message, gpointer data)
943 {
944     // Are we doing anything wrong? One test that does not call
945     // dumpStatusCallbacks gets true here
946     if (gLayoutTestController->dumpStatusCallbacks())
947         printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message);
948 }
949
950 static gboolean webViewClose(WebKitWebView* view)
951 {
952     ASSERT(view);
953
954     webViewList = g_slist_remove(webViewList, view);
955     g_object_unref(view);
956
957     return TRUE;
958 }
959
960 static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, WebKitWebDatabase *database)
961 {
962     ASSERT(view);
963     ASSERT(frame);
964     ASSERT(database);
965
966     WebKitSecurityOrigin* origin = webkit_web_database_get_security_origin(database);
967     if (gLayoutTestController->dumpDatabaseCallbacks()) {
968         printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n",
969             webkit_security_origin_get_protocol(origin),
970             webkit_security_origin_get_host(origin),
971             webkit_security_origin_get_port(origin),
972             webkit_web_database_get_name(database));
973     }
974     webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024);
975 }
976
977 static bool
978 geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision)
979 {
980     if (!gLayoutTestController->isGeolocationPermissionSet())
981         return FALSE;
982     if (gLayoutTestController->geolocationPermission())
983         webkit_geolocation_policy_allow(decision);
984     else
985         webkit_geolocation_policy_deny(decision);
986
987     return TRUE;
988 }
989
990
991 static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
992
993 static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data)
994 {
995     gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), 800, 600);
996     gtk_widget_show_all(webInspectorWindow);
997     return TRUE;
998 }
999
1000 static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data)
1001 {
1002     gtk_widget_destroy(webInspectorWindow);
1003     webInspectorWindow = 0;
1004     return TRUE;
1005 }
1006
1007 static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data)
1008 {
1009     webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1010
1011     GtkWidget* webView = webkit_web_view_new();
1012     gtk_container_add(GTK_CONTAINER(webInspectorWindow),
1013                       webView);
1014
1015     return WEBKIT_WEB_VIEW(webView);
1016 }
1017
1018 static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data)
1019 {
1020     WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame);
1021
1022     if (gLayoutTestController->dumpFrameLoadCallbacks()) {
1023         GOwnPtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame));
1024
1025         switch (loadStatus) {
1026         case WEBKIT_LOAD_PROVISIONAL:
1027             if (!done)
1028                 printf("%s - didStartProvisionalLoadForFrame\n", frameName.get());
1029             break;
1030         case WEBKIT_LOAD_COMMITTED:
1031             if (!done)
1032                 printf("%s - didCommitLoadForFrame\n", frameName.get());
1033             break;
1034         case WEBKIT_LOAD_FINISHED:
1035             if (frame != topLoadingFrame || !done)
1036                 printf("%s - didFinishLoadForFrame\n", frameName.get());
1037             break;
1038         default:
1039             break;
1040         }
1041     }
1042 }
1043
1044 static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data)
1045 {
1046     g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
1047 }
1048
1049 static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource*, WebKitNetworkRequest* request, WebKitNetworkResponse*)
1050 {
1051     if (!done && gLayoutTestController->willSendRequestReturnsNull())
1052         return;
1053
1054     SoupMessage* soupMessage = webkit_network_request_get_message(request);
1055     SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request));
1056
1057     if (SOUP_URI_VALID_FOR_HTTP(uri) && g_strcmp0(uri->host, "127.0.0.1")
1058         && g_strcmp0(uri->host, "255.255.255.255")
1059         && g_ascii_strncasecmp(uri->host, "localhost", 9)) {
1060         printf("Blocked access to external URL %s\n", soup_uri_to_string(uri, FALSE));
1061         soup_uri_free(uri);
1062         return;
1063     }
1064     if (uri)
1065         soup_uri_free(uri);
1066
1067     if (soupMessage) {
1068         const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders();
1069         for (set<string>::const_iterator header = clearHeaders.begin(); header != clearHeaders.end(); ++header)
1070             soup_message_headers_remove(soupMessage->request_headers, header->c_str());
1071     }
1072 }
1073
1074 static WebKitWebView* createWebView()
1075 {
1076     WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
1077
1078     DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true);
1079
1080     g_object_connect(G_OBJECT(view),
1081                      "signal::load-started", webViewLoadStarted, 0,
1082                      "signal::load-finished", webViewLoadFinished, 0,
1083                      "signal::load-error", webViewLoadError, 0,
1084                      "signal::window-object-cleared", webViewWindowObjectCleared, 0,
1085                      "signal::console-message", webViewConsoleMessage, 0,
1086                      "signal::script-alert", webViewScriptAlert, 0,
1087                      "signal::script-prompt", webViewScriptPrompt, 0,
1088                      "signal::script-confirm", webViewScriptConfirm, 0,
1089                      "signal::title-changed", webViewTitleChanged, 0,
1090                      "signal::navigation-policy-decision-requested", webViewNavigationPolicyDecisionRequested, 0,
1091                      "signal::status-bar-text-changed", webViewStatusBarTextChanged, 0,
1092                      "signal::create-web-view", webViewCreate, 0,
1093                      "signal::close-web-view", webViewClose, 0,
1094                      "signal::database-quota-exceeded", databaseQuotaExceeded, 0,
1095                      "signal::document-load-finished", webViewDocumentLoadFinished, 0,
1096                      "signal::geolocation-policy-decision-requested", geolocationPolicyDecisionRequested, 0,
1097                      "signal::onload-event", webViewOnloadEvent, 0,
1098                      "signal::drag-begin", dragBeginCallback, 0,
1099                      "signal::drag-end", dragEndCallback, 0,
1100                      "signal::drag-failed", dragFailedCallback, 0,
1101                      "signal::frame-created", frameCreatedCallback, 0,
1102                      "signal::resource-request-starting", willSendRequestCallback, 0,
1103
1104                      NULL);
1105     connectEditingCallbacks(view);
1106
1107     WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
1108     g_object_connect(G_OBJECT(inspector),
1109                      "signal::inspect-web-view", webInspectorInspectWebView, 0,
1110                      "signal::show-window", webInspectorShowWindow, 0,
1111                      "signal::close-window", webInspectorCloseWindow, 0,
1112                      NULL);
1113
1114     if (webView) {
1115         WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
1116         webkit_web_view_set_settings(view, settings);
1117     }
1118
1119     // frame-created is not issued for main frame. That's why we must do this here
1120     WebKitWebFrame* frame = webkit_web_view_get_main_frame(view);
1121     g_signal_connect(frame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
1122
1123     return view;
1124 }
1125
1126 static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame)
1127 {
1128     if (!gLayoutTestController->canOpenWindows())
1129         return 0;
1130
1131     // Make sure that waitUntilDone has been called.
1132     ASSERT(gLayoutTestController->waitToDump());
1133
1134     WebKitWebView* newWebView = createWebView();
1135     g_object_ref_sink(G_OBJECT(newWebView));
1136     webViewList = g_slist_prepend(webViewList, newWebView);
1137     return newWebView;
1138 }
1139
1140 static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data)
1141 {
1142     if (level < G_LOG_LEVEL_DEBUG)
1143         fprintf(stderr, "%s\n", message);
1144 }
1145
1146 int main(int argc, char* argv[])
1147 {
1148     g_thread_init(NULL);
1149     gtk_init(&argc, &argv);
1150
1151     // Some plugins might try to use the GLib logger for printing debug
1152     // messages. This will cause tests to fail because of unexpected output.
1153     // We squelch all debug messages sent to the logger.
1154     g_log_set_default_handler(logHandler, 0);
1155
1156     initializeGlobalsFromCommandLineOptions(argc, argv);
1157     initializeFonts();
1158
1159     window = gtk_window_new(GTK_WINDOW_POPUP);
1160     container = GTK_WIDGET(gtk_scrolled_window_new(NULL, NULL));
1161     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1162     gtk_container_add(GTK_CONTAINER(window), container);
1163     gtk_widget_show_all(window);
1164
1165     webView = createWebView();
1166     gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(webView));
1167     gtk_widget_realize(GTK_WIDGET(webView));
1168     gtk_widget_show_all(container);
1169     gtk_widget_grab_focus(GTK_WIDGET(webView));
1170     mainFrame = webkit_web_view_get_main_frame(webView);
1171
1172     setDefaultsToConsistentStateValuesForTesting();
1173
1174     gcController = new GCController();
1175     axController = new AccessibilityController();
1176
1177     if (useLongRunningServerMode(argc, argv)) {
1178         printSeparators = true;
1179         runTestingServerLoop();
1180     } else {
1181         printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));
1182         for (int i = optind; i != argc; ++i)
1183             runTest(argv[i]);
1184     }
1185
1186     delete gcController;
1187     gcController = 0;
1188
1189     delete axController;
1190     axController = 0;
1191
1192     gtk_widget_destroy(window);
1193
1194     return 0;
1195 }