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