diff options
Diffstat (limited to 'Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp')
-rw-r--r-- | Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp | 518 |
1 files changed, 518 insertions, 0 deletions
diff --git a/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp new file mode 100644 index 000000000..14f2c1466 --- /dev/null +++ b/Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * Portions Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebViewTest.h" + +#include <JavaScriptCore/JSRetainPtr.h> +#include <WebCore/GUniquePtrGtk.h> +#include <wtf/glib/GMainLoopSource.h> + +WebViewTest::WebViewTest(WebKitUserContentManager* userContentManager) + : m_webView(WEBKIT_WEB_VIEW(g_object_ref_sink(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", m_webContext.get(), "user-content-manager", userContentManager, nullptr)))) + , m_mainLoop(g_main_loop_new(nullptr, TRUE)) + , m_parentWindow(nullptr) + , m_javascriptResult(nullptr) + , m_resourceDataSize(0) + , m_surface(nullptr) + , m_expectedWebProcessCrash(false) +{ + assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_webView)); + g_signal_connect(m_webView, "web-process-crashed", G_CALLBACK(WebViewTest::webProcessCrashed), this); +} + +WebViewTest::~WebViewTest() +{ + if (m_parentWindow) + gtk_widget_destroy(m_parentWindow); + if (m_javascriptResult) + webkit_javascript_result_unref(m_javascriptResult); + if (m_surface) + cairo_surface_destroy(m_surface); + g_object_unref(m_webView); + g_main_loop_unref(m_mainLoop); +} + +gboolean WebViewTest::webProcessCrashed(WebKitWebView*, WebViewTest* test) +{ + if (test->m_expectedWebProcessCrash) { + test->m_expectedWebProcessCrash = false; + return FALSE; + } + g_assert_not_reached(); + return TRUE; +} + +void WebViewTest::loadURI(const char* uri) +{ + m_activeURI = uri; + webkit_web_view_load_uri(m_webView, uri); + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +} + +void WebViewTest::loadHtml(const char* html, const char* baseURI) +{ + if (!baseURI) + m_activeURI = "about:blank"; + else + m_activeURI = baseURI; + webkit_web_view_load_html(m_webView, html, baseURI); + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +} + +void WebViewTest::loadPlainText(const char* plainText) +{ + m_activeURI = "about:blank"; + webkit_web_view_load_plain_text(m_webView, plainText); +#if 0 + // FIXME: Pending API request URL no set when loading plain text. + // See https://bugs.webkit.org/show_bug.cgi?id=136916. + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +#endif +} + +void WebViewTest::loadBytes(GBytes* bytes, const char* mimeType, const char* encoding, const char* baseURI) +{ + if (!baseURI) + m_activeURI = "about:blank"; + else + m_activeURI = baseURI; + webkit_web_view_load_bytes(m_webView, bytes, mimeType, encoding, baseURI); +#if 0 + // FIXME: Pending API request URL no set when loading data. + // See https://bugs.webkit.org/show_bug.cgi?id=136916. + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +#endif +} + +void WebViewTest::loadRequest(WebKitURIRequest* request) +{ + m_activeURI = webkit_uri_request_get_uri(request); + webkit_web_view_load_request(m_webView, request); + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +} + +void WebViewTest::loadAlternateHTML(const char* html, const char* contentURI, const char* baseURI) +{ + m_activeURI = contentURI; + webkit_web_view_load_alternate_html(m_webView, html, contentURI, baseURI); +#if 0 + // FIXME: Pending API request URL no set when loading Alternate HTML. + // See https://bugs.webkit.org/show_bug.cgi?id=136916. + g_assert(webkit_web_view_is_loading(m_webView)); +#endif + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +} + +void WebViewTest::goBack() +{ + bool canGoBack = webkit_web_view_can_go_back(m_webView); + if (canGoBack) { + WebKitBackForwardList* list = webkit_web_view_get_back_forward_list(m_webView); + WebKitBackForwardListItem* item = webkit_back_forward_list_get_nth_item(list, -1); + m_activeURI = webkit_back_forward_list_item_get_original_uri(item); + } + + // Call go_back even when can_go_back returns FALSE to check nothing happens. + webkit_web_view_go_back(m_webView); + if (canGoBack) { + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); + } +} + +void WebViewTest::goForward() +{ + bool canGoForward = webkit_web_view_can_go_forward(m_webView); + if (canGoForward) { + WebKitBackForwardList* list = webkit_web_view_get_back_forward_list(m_webView); + WebKitBackForwardListItem* item = webkit_back_forward_list_get_nth_item(list, 1); + m_activeURI = webkit_back_forward_list_item_get_original_uri(item); + } + + // Call go_forward even when can_go_forward returns FALSE to check nothing happens. + webkit_web_view_go_forward(m_webView); + if (canGoForward) { + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); + } +} + +void WebViewTest::goToBackForwardListItem(WebKitBackForwardListItem* item) +{ + m_activeURI = webkit_back_forward_list_item_get_original_uri(item); + webkit_web_view_go_to_back_forward_list_item(m_webView, item); + g_assert(webkit_web_view_is_loading(m_webView)); + g_assert_cmpstr(webkit_web_view_get_uri(m_webView), ==, m_activeURI.data()); +} + +void WebViewTest::quitMainLoop() +{ + g_main_loop_quit(m_mainLoop); +} + +void WebViewTest::quitMainLoopAfterProcessingPendingEvents() +{ + while (gtk_events_pending()) + gtk_main_iteration(); + quitMainLoop(); +} + +void WebViewTest::wait(double seconds) +{ + GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy("WebViewTest wait", [this] { quitMainLoop(); }, + std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::duration<double>(seconds))); + g_main_loop_run(m_mainLoop); +} + +static void loadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test) +{ + if (loadEvent != WEBKIT_LOAD_FINISHED) + return; + g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(loadChanged), test); + g_main_loop_quit(test->m_mainLoop); +} + +void WebViewTest::waitUntilLoadFinished() +{ + g_signal_connect(m_webView, "load-changed", G_CALLBACK(loadChanged), this); + g_main_loop_run(m_mainLoop); +} + +static void titleChanged(WebKitWebView* webView, GParamSpec*, WebViewTest* test) +{ + if (!test->m_expectedTitle.isNull() && test->m_expectedTitle != webkit_web_view_get_title(webView)) + return; + + g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(titleChanged), test); + g_main_loop_quit(test->m_mainLoop); +} + +void WebViewTest::waitUntilTitleChangedTo(const char* expectedTitle) +{ + m_expectedTitle = expectedTitle; + g_signal_connect(m_webView, "notify::title", G_CALLBACK(titleChanged), this); + g_main_loop_run(m_mainLoop); + m_expectedTitle = CString(); +} + +void WebViewTest::waitUntilTitleChanged() +{ + waitUntilTitleChangedTo(0); +} + +static gboolean parentWindowMapped(GtkWidget* widget, GdkEvent*, WebViewTest* test) +{ + g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(parentWindowMapped), test); + g_main_loop_quit(test->m_mainLoop); + + return FALSE; +} + +void WebViewTest::showInWindow(GtkWindowType windowType) +{ + g_assert(!m_parentWindow); + m_parentWindow = gtk_window_new(windowType); + gtk_container_add(GTK_CONTAINER(m_parentWindow), GTK_WIDGET(m_webView)); + gtk_widget_show(GTK_WIDGET(m_webView)); + gtk_widget_show(m_parentWindow); +} + +void WebViewTest::showInWindowAndWaitUntilMapped(GtkWindowType windowType, int width, int height) +{ + g_assert(!m_parentWindow); + m_parentWindow = gtk_window_new(windowType); + if (width && height) + gtk_window_resize(GTK_WINDOW(m_parentWindow), width, height); + gtk_container_add(GTK_CONTAINER(m_parentWindow), GTK_WIDGET(m_webView)); + gtk_widget_show(GTK_WIDGET(m_webView)); + + g_signal_connect(m_parentWindow, "map-event", G_CALLBACK(parentWindowMapped), this); + gtk_widget_show(m_parentWindow); + g_main_loop_run(m_mainLoop); +} + +void WebViewTest::resizeView(int width, int height) +{ + GtkAllocation allocation; + gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation); + if (width != -1) + allocation.width = width; + if (height != -1) + allocation.height = height; + gtk_widget_size_allocate(GTK_WIDGET(m_webView), &allocation); +} + +void WebViewTest::selectAll() +{ + webkit_web_view_execute_editing_command(m_webView, "SelectAll"); +} + +bool WebViewTest::isEditable() +{ + return webkit_web_view_is_editable(m_webView); +} + +void WebViewTest::setEditable(bool editable) +{ + webkit_web_view_set_editable(m_webView, editable); +} + +static void resourceGetDataCallback(GObject* object, GAsyncResult* result, gpointer userData) +{ + size_t dataSize; + GUniqueOutPtr<GError> error; + unsigned char* data = webkit_web_resource_get_data_finish(WEBKIT_WEB_RESOURCE(object), result, &dataSize, &error.outPtr()); + g_assert(data); + + WebViewTest* test = static_cast<WebViewTest*>(userData); + test->m_resourceData.reset(reinterpret_cast<char*>(data)); + test->m_resourceDataSize = dataSize; + g_main_loop_quit(test->m_mainLoop); +} + +const char* WebViewTest::mainResourceData(size_t& mainResourceDataSize) +{ + m_resourceDataSize = 0; + m_resourceData.reset(); + WebKitWebResource* resource = webkit_web_view_get_main_resource(m_webView); + g_assert(resource); + + webkit_web_resource_get_data(resource, 0, resourceGetDataCallback, this); + g_main_loop_run(m_mainLoop); + + mainResourceDataSize = m_resourceDataSize; + return m_resourceData.get(); +} + +void WebViewTest::mouseMoveTo(int x, int y, unsigned mouseModifiers) +{ + g_assert(m_parentWindow); + GtkWidget* viewWidget = GTK_WIDGET(m_webView); + g_assert(gtk_widget_get_realized(viewWidget)); + + GUniquePtr<GdkEvent> event(gdk_event_new(GDK_MOTION_NOTIFY)); + event->motion.x = x; + event->motion.y = y; + + event->motion.time = GDK_CURRENT_TIME; + event->motion.window = gtk_widget_get_window(viewWidget); + g_object_ref(event->motion.window); + event->motion.device = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gtk_widget_get_display(viewWidget))); + event->motion.state = mouseModifiers; + event->motion.axes = 0; + + int xRoot, yRoot; + gdk_window_get_root_coords(gtk_widget_get_window(viewWidget), x, y, &xRoot, &yRoot); + event->motion.x_root = xRoot; + event->motion.y_root = yRoot; + gtk_main_do_event(event.get()); +} + +void WebViewTest::clickMouseButton(int x, int y, unsigned button, unsigned mouseModifiers) +{ + doMouseButtonEvent(GDK_BUTTON_PRESS, x, y, button, mouseModifiers); + doMouseButtonEvent(GDK_BUTTON_RELEASE, x, y, button, mouseModifiers); +} + +void WebViewTest::keyStroke(unsigned keyVal, unsigned keyModifiers) +{ + g_assert(m_parentWindow); + GtkWidget* viewWidget = GTK_WIDGET(m_webView); + g_assert(gtk_widget_get_realized(viewWidget)); + + GUniquePtr<GdkEvent> event(gdk_event_new(GDK_KEY_PRESS)); + event->key.keyval = keyVal; + + event->key.time = GDK_CURRENT_TIME; + event->key.window = gtk_widget_get_window(viewWidget); + g_object_ref(event->key.window); + gdk_event_set_device(event.get(), gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gtk_widget_get_display(viewWidget)))); + event->key.state = keyModifiers; + + // When synthesizing an event, an invalid hardware_keycode value can cause it to be badly processed by GTK+. + GUniqueOutPtr<GdkKeymapKey> keys; + int keysCount; + if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyVal, &keys.outPtr(), &keysCount)) + event->key.hardware_keycode = keys.get()[0].keycode; + + gtk_main_do_event(event.get()); + event->key.type = GDK_KEY_RELEASE; + gtk_main_do_event(event.get()); +} + +void WebViewTest::doMouseButtonEvent(GdkEventType eventType, int x, int y, unsigned button, unsigned mouseModifiers) +{ + g_assert(m_parentWindow); + GtkWidget* viewWidget = GTK_WIDGET(m_webView); + g_assert(gtk_widget_get_realized(viewWidget)); + + GUniquePtr<GdkEvent> event(gdk_event_new(eventType)); + event->button.window = gtk_widget_get_window(viewWidget); + g_object_ref(event->button.window); + + event->button.time = GDK_CURRENT_TIME; + event->button.x = x; + event->button.y = y; + event->button.axes = 0; + event->button.state = mouseModifiers; + event->button.button = button; + + event->button.device = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gtk_widget_get_display(viewWidget))); + + int xRoot, yRoot; + gdk_window_get_root_coords(gtk_widget_get_window(viewWidget), x, y, &xRoot, &yRoot); + event->button.x_root = xRoot; + event->button.y_root = yRoot; + gtk_main_do_event(event.get()); +} + +static void runJavaScriptReadyCallback(GObject*, GAsyncResult* result, WebViewTest* test) +{ + test->m_javascriptResult = webkit_web_view_run_javascript_finish(test->m_webView, result, test->m_javascriptError); + g_main_loop_quit(test->m_mainLoop); +} + +static void runJavaScriptFromGResourceReadyCallback(GObject*, GAsyncResult* result, WebViewTest* test) +{ + test->m_javascriptResult = webkit_web_view_run_javascript_from_gresource_finish(test->m_webView, result, test->m_javascriptError); + g_main_loop_quit(test->m_mainLoop); +} + +WebKitJavascriptResult* WebViewTest::runJavaScriptAndWaitUntilFinished(const char* javascript, GError** error) +{ + if (m_javascriptResult) + webkit_javascript_result_unref(m_javascriptResult); + m_javascriptResult = 0; + m_javascriptError = error; + webkit_web_view_run_javascript(m_webView, javascript, 0, reinterpret_cast<GAsyncReadyCallback>(runJavaScriptReadyCallback), this); + g_main_loop_run(m_mainLoop); + + return m_javascriptResult; +} + +WebKitJavascriptResult* WebViewTest::runJavaScriptFromGResourceAndWaitUntilFinished(const char* resource, GError** error) +{ + if (m_javascriptResult) + webkit_javascript_result_unref(m_javascriptResult); + m_javascriptResult = 0; + m_javascriptError = error; + webkit_web_view_run_javascript_from_gresource(m_webView, resource, 0, reinterpret_cast<GAsyncReadyCallback>(runJavaScriptFromGResourceReadyCallback), this); + g_main_loop_run(m_mainLoop); + + return m_javascriptResult; +} + +static char* jsValueToCString(JSGlobalContextRef context, JSValueRef value) +{ + g_assert(value); + g_assert(JSValueIsString(context, value)); + + JSRetainPtr<JSStringRef> stringValue(Adopt, JSValueToStringCopy(context, value, 0)); + g_assert(stringValue); + + size_t cStringLength = JSStringGetMaximumUTF8CStringSize(stringValue.get()); + char* cString = static_cast<char*>(g_malloc(cStringLength)); + JSStringGetUTF8CString(stringValue.get(), cString, cStringLength); + return cString; +} + +char* WebViewTest::javascriptResultToCString(WebKitJavascriptResult* javascriptResult) +{ + JSGlobalContextRef context = webkit_javascript_result_get_global_context(javascriptResult); + g_assert(context); + return jsValueToCString(context, webkit_javascript_result_get_value(javascriptResult)); +} + +double WebViewTest::javascriptResultToNumber(WebKitJavascriptResult* javascriptResult) +{ + JSGlobalContextRef context = webkit_javascript_result_get_global_context(javascriptResult); + g_assert(context); + JSValueRef value = webkit_javascript_result_get_value(javascriptResult); + g_assert(value); + g_assert(JSValueIsNumber(context, value)); + + return JSValueToNumber(context, value, 0); +} + +bool WebViewTest::javascriptResultToBoolean(WebKitJavascriptResult* javascriptResult) +{ + JSGlobalContextRef context = webkit_javascript_result_get_global_context(javascriptResult); + g_assert(context); + JSValueRef value = webkit_javascript_result_get_value(javascriptResult); + g_assert(value); + g_assert(JSValueIsBoolean(context, value)); + + return JSValueToBoolean(context, value); +} + +bool WebViewTest::javascriptResultIsNull(WebKitJavascriptResult* javascriptResult) +{ + JSGlobalContextRef context = webkit_javascript_result_get_global_context(javascriptResult); + g_assert(context); + JSValueRef value = webkit_javascript_result_get_value(javascriptResult); + g_assert(value); + + return JSValueIsNull(context, value); +} + +bool WebViewTest::javascriptResultIsUndefined(WebKitJavascriptResult* javascriptResult) +{ + JSGlobalContextRef context = webkit_javascript_result_get_global_context(javascriptResult); + g_assert(context); + JSValueRef value = webkit_javascript_result_get_value(javascriptResult); + g_assert(value); + + return JSValueIsUndefined(context, value); +} + +static void onSnapshotReady(WebKitWebView* web_view, GAsyncResult* res, WebViewTest* test) +{ + GUniqueOutPtr<GError> error; + test->m_surface = webkit_web_view_get_snapshot_finish(web_view, res, &error.outPtr()); + g_assert(!test->m_surface || !error.get()); + if (error) + g_assert_error(error.get(), WEBKIT_SNAPSHOT_ERROR, WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE); + test->quitMainLoop(); +} + +cairo_surface_t* WebViewTest::getSnapshotAndWaitUntilReady(WebKitSnapshotRegion region, WebKitSnapshotOptions options) +{ + if (m_surface) + cairo_surface_destroy(m_surface); + m_surface = 0; + webkit_web_view_get_snapshot(m_webView, region, options, 0, reinterpret_cast<GAsyncReadyCallback>(onSnapshotReady), this); + g_main_loop_run(m_mainLoop); + return m_surface; +} + +bool WebViewTest::runWebProcessTest(const char* suiteName, const char* testName) +{ + GUniquePtr<char> script(g_strdup_printf("WebProcessTestRunner.runTest('%s/%s');", suiteName, testName)); + GUniqueOutPtr<GError> error; + WebKitJavascriptResult* javascriptResult = runJavaScriptAndWaitUntilFinished(script.get(), &error.outPtr()); + g_assert(!error); + return javascriptResultToBoolean(javascriptResult); +} |