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