Home | History | Annotate | Download | only in gtk
      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