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