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.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 #include "DumpRenderTree.h"
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>
53 #include <webkit/webkit.h>
54 #include <wtf/Assertions.h>
55 #include <wtf/gobject/GOwnPtr.h>
56 #include <wtf/gobject/GlibUtilities.h>
59 #include <fontconfig/fontconfig.h>
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);
75 static bool printSeparators;
76 static int dumpPixels;
77 static int dumpTree = 1;
78 static int useTimeoutWatchdog = 1;
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;
92 // This is a list of opened webviews
93 GSList* webViewList = 0;
95 // current b/f item at the end of the previous test
96 static WebKitWebHistoryItem* prevTestBFItem = NULL;
98 const unsigned historyItemIndent = 8;
100 static void runTest(const string& testPathOrURL);
102 static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url);
104 static bool shouldLogFrameLoadDelegates(const string& pathOrURL)
106 return pathOrURL.find("loading/") != string::npos;
109 static bool shouldOpenWebInspector(const string& pathOrURL)
111 return pathOrURL.find("inspector/") != string::npos;
114 static bool shouldDumpAsText(const string& pathOrURL)
116 return pathOrURL.find("dumpAsText/") != string::npos;
119 static bool shouldEnableDeveloperExtras(const string& pathOrURL)
124 void dumpFrameScrollPosition(WebKitWebFrame* frame)
126 WebKitDOMDocument* document = webkit_web_frame_get_dom_document(frame);
130 WebKitDOMDOMWindow* domWindow = webkit_dom_document_get_default_view(document);
134 glong x = webkit_dom_dom_window_get_page_x_offset(domWindow);
135 glong y = webkit_dom_dom_window_get_page_y_offset(domWindow);
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);
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);
151 void displayWebView()
153 DumpRenderTreeSupportGtk::forceWebViewPaint(webView);
154 DumpRenderTreeSupportGtk::setTracksRepaints(mainFrame, true);
155 DumpRenderTreeSupportGtk::resetTrackedRepaints(mainFrame);
158 static void appendString(gchar*& target, const gchar* string)
160 gchar* oldString = target;
161 target = g_strconcat(target, string, NULL);
165 static void initializeGtkFontSettings(const char* testURL)
167 GtkSettings* settings = gtk_settings_get_default();
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",
176 gdk_screen_set_resolution(gdk_screen_get_default(), 96.0);
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);
183 g_object_set(settings, "gtk-xft-rgba", "none", NULL);
186 CString getTopLevelPath()
188 if (!g_getenv("WEBKIT_TOP_LEVEL"))
189 g_setenv("WEBKIT_TOP_LEVEL", TOP_LEVEL_DIR, FALSE);
191 return TOP_LEVEL_DIR;
194 CString getOutputDir()
196 const char* webkitOutputDir = g_getenv("WEBKITOUTPUTDIR");
198 return webkitOutputDir;
200 CString topLevelPath = getTopLevelPath();
201 GOwnPtr<char> outputDir(g_build_filename(topLevelPath.data(), "WebKitBuild", NULL));
202 return outputDir.get();
205 static CString getFontsPath()
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();
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();
220 static void initializeFonts(const char* testURL = 0)
223 initializeGtkFontSettings(testURL);
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)
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());
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());
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"))
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());
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());
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());
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());
273 if (!FcConfigSetCurrent(config))
274 g_error("Could not set the current font configuration!");
276 numFonts = FcConfigGetFonts(config, FcSetApplication)->nfont;
280 static gchar* dumpFramesAsText(WebKitWebFrame* frame)
284 // Add header for all but the main frame.
285 bool isMainFrame = (webkit_web_view_get_main_frame(webView) == frame);
287 CString innerText = DumpRenderTreeSupportGtk::getInnerText(frame);
289 result = g_strdup_printf("%s\n", innerText.data());
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());
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());
301 g_slist_free(children);
307 static gint compareHistoryItems(gpointer* item1, gpointer* item2)
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());
314 static void dumpHistoryItem(WebKitWebHistoryItem* item, int indent, bool current)
316 ASSERT(item != NULL);
323 for (int i = start; i < indent; i++)
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/");
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);
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**");
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);
362 g_object_unref(item);
365 static void dumpBackForwardListForWebView(WebKitWebView* view)
367 printf("\n============== Back Forward List ==============\n");
368 WebKitWebBackForwardList* bfList = webkit_web_view_get_back_forward_list(view);
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);
379 itemsToPrint = g_list_prepend(itemsToPrint, item);
382 WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList);
383 g_object_ref(currentItem);
384 itemsToPrint = g_list_prepend(itemsToPrint, currentItem);
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)
392 itemsToPrint = g_list_prepend(itemsToPrint, item);
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);
401 g_list_free(itemsToPrint);
402 printf("===============================================\n");
405 static void dumpBackForwardListForAllWebViews()
407 // Dump the back forward list of the main WebView first
408 dumpBackForwardListForWebView(webView);
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));
415 void setWaitToDumpWatchdog(guint timer)
417 waitToDumpWatchdog = timer;
420 bool shouldSetWaitToDumpWatchdog()
422 return !waitToDumpWatchdog && useTimeoutWatchdog;
425 static void invalidateAnyPreviousWaitToDumpWatchdog()
427 if (waitToDumpWatchdog) {
428 g_source_remove(waitToDumpWatchdog);
429 waitToDumpWatchdog = 0;
432 waitForPolicy = false;
435 static void resetDefaultsToConsistentValues()
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,
474 webkit_web_view_set_settings(webView, settings);
475 webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
477 DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
478 DumpRenderTreeSupportGtk::scalePageBy(webView, 1, 0, 0);
480 WebKitWebInspector* inspector = webkit_web_view_get_inspector(webView);
481 g_object_set(G_OBJECT(inspector), "javascript-profiling-enabled", FALSE, NULL);
483 webkit_web_view_set_zoom_level(webView, 1.0);
484 DumpRenderTreeSupportGtk::setMinimumTimerInterval(webView, DumpRenderTreeSupportGtk::defaultMinimumTimerInterval());
486 DumpRenderTreeSupportGtk::resetOriginAccessWhiteLists();
488 WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
489 webkit_web_back_forward_list_clear(list);
491 SoupSession* session = webkit_get_default_session();
492 SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
494 // We only create the jar when the soup backend needs to do
495 // HTTP. Should we initialize it earlier, perhaps?
497 g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
499 setlocale(LC_ALL, "");
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);
509 axController->resetToConsistentState();
511 DumpRenderTreeSupportGtk::clearOpener(mainFrame);
512 DumpRenderTreeSupportGtk::setTracksRepaints(mainFrame, false);
514 DumpRenderTreeSupportGtk::resetGeolocationClientMock(webView);
516 DumpRenderTreeSupportGtk::setCSSGridLayoutEnabled(webView, false);
517 DumpRenderTreeSupportGtk::setCSSRegionsEnabled(webView, true);
520 static bool useLongRunningServerMode(int argc, char *argv[])
522 // This assumes you've already called getopt_long
523 return (argc == optind+1 && !strcmp(argv[optind], "-"));
526 static void runTestingServerLoop()
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';
536 if (!strlen(filenameBuffer))
539 runTest(filenameBuffer);
543 static void initializeGlobalsFromCommandLineOptions(int argc, char *argv[])
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},
554 while ((option = getopt_long(argc, (char * const *)argv, "", options, NULL)) != -1) {
556 case '?': // unknown or ambiguous option
557 case ':': // missing argument
567 invalidateAnyPreviousWaitToDumpWatchdog();
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));
575 gchar* responseMimeType = webkit_web_frame_get_response_mime_type(mainFrame);
577 if (g_str_equal(responseMimeType, "text/plain")) {
578 gLayoutTestController->setDumpAsText(true);
579 gLayoutTestController->setGeneratePixelResults(false);
581 g_free(responseMimeType);
583 if (gLayoutTestController->dumpAsText())
584 result = dumpFramesAsText(mainFrame);
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();
595 result = g_strdup(DumpRenderTreeSupportGtk::dumpRenderTree(mainFrame).data());
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]";
607 errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
608 printf("ERROR: nil result from %s", errorMessage);
610 printf("%s", result);
612 if (!gLayoutTestController->dumpAsText() && !gLayoutTestController->dumpDOMAsWebArchive() && !gLayoutTestController->dumpSourceAsWebArchive())
613 dumpFrameScrollPosition(mainFrame);
615 if (gLayoutTestController->dumpBackForwardList())
616 dumpBackForwardListForAllWebViews();
619 if (printSeparators) {
620 puts("#EOF"); // terminate the content block
621 fputs("#EOF\n", stderr);
628 && gLayoutTestController->generatePixelResults()
629 && !gLayoutTestController->dumpDOMAsWebArchive()
630 && !gLayoutTestController->dumpSourceAsWebArchive()) {
631 DumpRenderTreeSupportGtk::forceWebViewPaint(webView);
632 dumpWebViewAsPixelsAndCompareWithExpected(gLayoutTestController->expectedPixelHash());
635 // FIXME: call displayWebView here when we support --paint
641 static void setDefaultsToConsistentStateValuesForTesting()
643 resetDefaultsToConsistentValues();
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);
650 webkit_web_settings_add_extra_plugin_directory(webView, TEST_PLUGIN_DIR);
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);
657 #if defined(GTK_API_VERSION_2)
658 gtk_rc_parse_string("style \"nix_scrollbar_spacing\" "
660 " GtkScrolledWindow::scrollbar-spacing = 0 "
662 "class \"GtkWidget\" style \"nix_scrollbar_spacing\"");
665 GtkCssProvider* cssProvider = gtk_css_provider_new();
666 gtk_css_provider_load_from_data(cssProvider,
667 "@binding-set NoKeyboardNavigation { "
668 " unbind \"<shift>F10\"; "
671 " -GtkScrolledWindow-scrollbar-spacing: 0;"
672 " gtk-key-bindings: NoKeyboardNavigation; "
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);
682 static void sendPixelResultsEOF()
690 static void runTest(const string& testPathOrURL)
692 ASSERT(!testPathOrURL.empty());
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);
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);
713 resetDefaultsToConsistentValues();
715 gLayoutTestController = LayoutTestController::create(testURL, expectedPixelHash);
719 gLayoutTestController->setIconDatabaseEnabled(false);
721 if (shouldLogFrameLoadDelegates(testURL))
722 gLayoutTestController->setDumpFrameLoadCallbacks(true);
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);
734 WorkQueue::shared()->clear();
735 WorkQueue::shared()->setFrozen(false);
737 bool isSVGW3CTest = (testURL.find("svg/W3C-SVG-1.1") != string::npos);
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);
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);
750 g_object_ref(prevTestBFItem);
752 initializeFonts(testURL.c_str());
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());
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);
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);
772 g_slist_free(webViewList);
776 WebCoreTestSupport::resetInternalsObject(webkit_web_frame_get_global_context(mainFrame));
778 // A blank load seems to be necessary to reset state after certain tests.
779 webkit_web_view_open(webView, "about:blank");
781 gLayoutTestController.clear();
783 // terminate the (possibly empty) pixels block after all the state reset
784 sendPixelResultsEOF();
787 void webViewLoadStarted(WebKitWebView* view, WebKitWebFrame* frame, void*)
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;
795 static gboolean processWork(void* data)
797 // if we finish all the commands, we're ready to dump state
798 if (WorkQueue::shared()->processWork() && !gLayoutTestController->waitToDump())
804 static char* getFrameNameSuitableForTestResult(WebKitWebView* view, WebKitWebFrame* frame)
806 char* frameName = g_strdup(webkit_web_frame_get_name(frame));
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);
816 frameName = g_strdup("main frame");
818 } else if (!frameName || (frameName[0] == '\0')) {
820 frameName = g_strdup("frame (anonymous)");
822 char* tmp = g_strdup_printf("frame \"%s\"", frameName);
830 static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
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)
836 if (gLayoutTestController->dumpProgressFinishedCallback())
837 printf("postProgressFinishedNotification\n");
840 static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer)
842 return TRUE; // Return true here to disable the default error page.
845 static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
847 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
848 char* frameName = getFrameNameSuitableForTestResult(view, frame);
849 printf("%s - didFinishDocumentLoadForFrame\n", frameName);
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);
861 static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void*)
863 if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
864 char* frameName = getFrameNameSuitableForTestResult(view, frame);
865 printf("%s - didHandleOnloadEventsForFrame\n", frameName);
870 static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller)
872 JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName);
873 JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
874 JSStringRelease(controllerNameStr);
877 static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data)
879 JSValueRef exception = 0;
880 ASSERT(gLayoutTestController);
882 gLayoutTestController->makeWindowObject(context, windowObject, &exception);
885 gcController->makeWindowObject(context, windowObject, &exception);
888 axController->makeWindowObject(context, windowObject, &exception);
891 addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame)));
892 addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context));
893 WebCoreTestSupport::injectInternalsObject(context);
896 static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
898 gchar* testMessage = 0;
899 const gchar* uriScheme;
901 // Tests expect only the filename part of local URIs
902 uriScheme = g_strstr_len(message, -1, "file://");
904 GString* tempString = g_string_sized_new(strlen(message));
905 gchar* filename = g_strrstr(uriScheme, G_DIR_SEPARATOR_S);
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);
917 fprintf(stdout, "CONSOLE MESSAGE: ");
919 fprintf(stdout, "line %d: ", line);
920 fprintf(stdout, "%s\n", testMessage ? testMessage : message);
927 static gboolean webViewScriptAlert(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gpointer data)
929 fprintf(stdout, "ALERT: %s\n", message);
933 static gboolean webViewScriptPrompt(WebKitWebView* webView, WebKitWebFrame* frame, const gchar* message, const gchar* defaultValue, gchar** value, gpointer data)
935 fprintf(stdout, "PROMPT: %s, default text: %s\n", message, defaultValue);
936 *value = g_strdup(defaultValue);
940 static gboolean webViewScriptConfirm(WebKitWebView* view, WebKitWebFrame* frame, const gchar* message, gboolean* didConfirm, gpointer data)
942 fprintf(stdout, "CONFIRM: %s\n", message);
947 static void webViewTitleChanged(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer data)
949 if (gLayoutTestController->dumpTitleChanges() && !done)
950 printf("TITLE CHANGED: %s\n", title ? title : "");
953 static bool webViewNavigationPolicyDecisionRequested(WebKitWebView* view, WebKitWebFrame* frame,
954 WebKitNetworkRequest* request,
955 WebKitWebNavigationAction* navAction,
956 WebKitWebPolicyDecision* policyDecision)
958 // Use the default handler if we're not waiting for policy,
959 // i.e., LayoutTestController::waitForPolicyDelegate
963 gchar* typeDescription;
964 WebKitWebNavigationReason reason;
965 g_object_get(G_OBJECT(navAction), "reason", &reason, NULL);
968 case WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED:
969 typeDescription = g_strdup("link clicked");
971 case WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED:
972 typeDescription = g_strdup("form submitted");
974 case WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD:
975 typeDescription = g_strdup("back/forward");
977 case WEBKIT_WEB_NAVIGATION_REASON_RELOAD:
978 typeDescription = g_strdup("reload");
980 case WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED:
981 typeDescription = g_strdup("form resubmitted");
983 case WEBKIT_WEB_NAVIGATION_REASON_OTHER:
984 typeDescription = g_strdup("other");
987 typeDescription = g_strdup("illegal value");
990 printf("Policy delegate: attempt to load %s with navigation type '%s'\n", webkit_network_request_get_uri(request), typeDescription);
991 g_free(typeDescription);
993 webkit_web_policy_decision_ignore(policyDecision);
994 gLayoutTestController->notifyDone();
999 static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* message, gpointer data)
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);
1007 static gboolean webViewClose(WebKitWebView* view)
1011 webViewList = g_slist_remove(webViewList, view);
1012 g_object_unref(view);
1017 static void databaseQuotaExceeded(WebKitWebView* view, WebKitWebFrame* frame, WebKitWebDatabase *database)
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));
1031 webkit_security_origin_set_web_database_quota(origin, 5 * 1024 * 1024);
1035 geolocationPolicyDecisionRequested(WebKitWebView*, WebKitWebFrame*, WebKitGeolocationPolicyDecision* decision)
1037 if (!gLayoutTestController->isGeolocationPermissionSet())
1039 if (gLayoutTestController->geolocationPermission())
1040 webkit_geolocation_policy_allow(decision);
1042 webkit_geolocation_policy_deny(decision);
1048 static WebKitWebView* webViewCreate(WebKitWebView*, WebKitWebFrame*);
1050 static gboolean webInspectorShowWindow(WebKitWebInspector*, gpointer data)
1052 gtk_window_set_default_size(GTK_WINDOW(webInspectorWindow), 800, 600);
1053 gtk_widget_show_all(webInspectorWindow);
1057 static gboolean webInspectorCloseWindow(WebKitWebInspector*, gpointer data)
1059 gtk_widget_destroy(webInspectorWindow);
1060 webInspectorWindow = 0;
1064 static WebKitWebView* webInspectorInspectWebView(WebKitWebInspector*, gpointer data)
1066 webInspectorWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1068 GtkWidget* webView = self_scrolling_webkit_web_view_new();
1069 gtk_container_add(GTK_CONTAINER(webInspectorWindow),
1072 return WEBKIT_WEB_VIEW(webView);
1075 static void topLoadingFrameLoadFinished()
1077 topLoadingFrame = 0;
1078 WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
1079 if (gLayoutTestController->waitToDump())
1082 if (WorkQueue::shared()->count())
1083 g_timeout_add(0, processWork, 0);
1088 static void webFrameLoadStatusNotified(WebKitWebFrame* frame, gpointer user_data)
1090 WebKitLoadStatus loadStatus = webkit_web_frame_get_load_status(frame);
1092 if (gLayoutTestController->dumpFrameLoadCallbacks()) {
1093 GOwnPtr<char> frameName(getFrameNameSuitableForTestResult(webkit_web_frame_get_web_view(frame), frame));
1095 switch (loadStatus) {
1096 case WEBKIT_LOAD_PROVISIONAL:
1098 printf("%s - didStartProvisionalLoadForFrame\n", frameName.get());
1100 case WEBKIT_LOAD_COMMITTED:
1102 printf("%s - didCommitLoadForFrame\n", frameName.get());
1104 case WEBKIT_LOAD_FINISHED:
1106 printf("%s - didFinishLoadForFrame\n", frameName.get());
1113 if ((loadStatus == WEBKIT_LOAD_FINISHED || loadStatus == WEBKIT_LOAD_FAILED)
1114 && frame == topLoadingFrame)
1115 topLoadingFrameLoadFinished();
1118 static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data)
1120 g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
1121 g_signal_connect(webFrame, "insecure-content-run", G_CALLBACK(didRunInsecureContent), NULL);
1125 static CString pathFromSoupURI(SoupURI* uri)
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());
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());
1141 static CString convertSoupMessageToURLPath(SoupMessage* soupMessage)
1145 if (SoupURI* requestURI = soup_message_get_uri(soupMessage))
1146 return pathFromSoupURI(requestURI);
1150 static CString convertNetworkRequestToURLPath(WebKitNetworkRequest* request)
1152 return convertSoupMessageToURLPath(webkit_network_request_get_message(request));
1155 static CString convertWebResourceToURLPath(WebKitWebResource* webResource)
1157 SoupURI* uri = soup_uri_new(webkit_web_resource_get_uri(webResource));
1158 CString urlPath(pathFromSoupURI(uri));
1163 static CString urlSuitableForTestResult(const char* uriString)
1165 if (!g_str_has_prefix(uriString, "file://"))
1166 return CString(uriString);
1168 GOwnPtr<gchar> basename(g_path_get_basename(uriString));
1169 return CString(basename.get());
1172 static CString descriptionSuitableForTestResult(SoupURI* uri)
1177 GOwnPtr<char> uriString(soup_uri_to_string(uri, false));
1178 return urlSuitableForTestResult(uriString.get());
1181 static CString descriptionSuitableForTestResult(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource)
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);
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>");
1191 description = convertWebResourceToURLPath(webResource);
1199 static CString descriptionSuitableForTestResult(GError* error, WebKitWebResource* webResource)
1201 const gchar* errorDomain = g_quark_to_string(error->domain);
1202 CString resourceURIString(urlSuitableForTestResult(webkit_web_resource_get_uri(webResource)));
1204 if (g_str_equal(errorDomain, "webkit-network-error-quark") || g_str_equal(errorDomain, "soup_http_error_quark"))
1205 errorDomain = "NSURLErrorDomain";
1207 if (g_str_equal(errorDomain, "WebKitPolicyError"))
1208 errorDomain = "WebKitErrorDomain";
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());
1216 static CString descriptionSuitableForTestResult(WebKitNetworkRequest* request)
1218 SoupMessage* soupMessage = webkit_network_request_get_message(request);
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());
1234 static CString descriptionSuitableForTestResult(WebKitNetworkResponse* response)
1237 return CString("(null)");
1240 CString responseURIString(urlSuitableForTestResult(webkit_network_response_get_uri(response)));
1241 SoupMessage* soupMessage = webkit_network_response_get_message(response);
1245 statusCode = soupMessage->status_code;
1246 path = convertSoupMessageToURLPath(soupMessage);
1250 GOwnPtr<char> description(g_strdup_printf("<NSURLResponse %s, http status code %d>", path.data(), statusCode));
1251 return CString(description.get());
1254 static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* resource, WebKitNetworkRequest* request, WebKitNetworkResponse* response)
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");
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());
1270 SoupMessage* soupMessage = webkit_network_request_get_message(request);
1271 SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request));
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");
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());
1295 static void didReceiveResponse(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource* webResource, WebKitNetworkResponse* response)
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());
1303 // TODO: add "has MIME type" whenever dumpResourceResponseMIMETypes() is supported.
1304 // See https://bugs.webkit.org/show_bug.cgi?id=58222.
1307 static void didFinishLoading(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource)
1309 if (!done && gLayoutTestController->dumpResourceLoadCallbacks())
1310 printf("%s - didFinishLoading\n", descriptionSuitableForTestResult(webView, webFrame, webResource).data());
1313 static void didFailLoadingWithError(WebKitWebView* webView, WebKitWebFrame* webFrame, WebKitWebResource* webResource, GError* webError)
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());
1322 static void didRunInsecureContent(WebKitWebFrame*, WebKitSecurityOrigin*, const char* url)
1324 if (!done && gLayoutTestController->dumpFrameLoadCallbacks())
1325 printf("didRunInsecureContent\n");
1328 static gboolean webViewRunFileChooser(WebKitWebView*, WebKitFileChooserRequest*)
1330 // We return TRUE to not propagate the event further so the
1331 // default file chooser dialog is not shown.
1335 static WebKitWebView* createWebView()
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);
1341 WebKitWebView* view = WEBKIT_WEB_VIEW(self_scrolling_webkit_web_view_new());
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,
1371 connectEditingCallbacks(view);
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,
1381 WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
1382 webkit_web_view_set_settings(view, settings);
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);
1393 static WebKitWebView* webViewCreate(WebKitWebView* view, WebKitWebFrame* frame)
1395 if (!gLayoutTestController->canOpenWindows())
1398 // Make sure that waitUntilDone has been called.
1399 ASSERT(gLayoutTestController->waitToDump());
1401 WebKitWebView* newWebView = createWebView();
1402 g_object_ref_sink(G_OBJECT(newWebView));
1403 webViewList = g_slist_prepend(webViewList, newWebView);
1407 static void logHandler(const gchar* domain, GLogLevelFlags level, const gchar* message, gpointer data)
1409 if (level < G_LOG_LEVEL_DEBUG)
1410 fprintf(stderr, "%s\n", message);
1413 int main(int argc, char* argv[])
1415 gtk_init(&argc, &argv);
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);
1422 initializeGlobalsFromCommandLineOptions(argc, argv);
1425 window = gtk_window_new(GTK_WINDOW_POPUP);
1426 #ifdef GTK_API_VERSION_2
1427 container = gtk_hbox_new(TRUE, 0);
1429 container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
1430 gtk_box_set_homogeneous(GTK_BOX(container), TRUE);
1432 gtk_container_add(GTK_CONTAINER(window), container);
1433 gtk_widget_show_all(window);
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);
1441 setDefaultsToConsistentStateValuesForTesting();
1443 gcController = new GCController();
1444 axController = new AccessibilityController();
1446 if (useLongRunningServerMode(argc, argv)) {
1447 printSeparators = true;
1448 runTestingServerLoop();
1450 printSeparators = (optind < argc-1 || (dumpPixels && dumpTree));
1451 for (int i = optind; i != argc; ++i)
1455 delete gcController;
1458 delete axController;
1461 gtk_widget_destroy(window);