diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-15 16:08:57 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2012-10-15 16:08:57 +0200 |
commit | 5466563f4b5b6b86523e3f89bb7f77e5b5270c78 (patch) | |
tree | 8caccf7cd03a15207cde3ba282c88bf132482a91 /Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | |
parent | 33b26980cb24288b5a9f2590ccf32a949281bb79 (diff) | |
download | qtwebkit-5466563f4b5b6b86523e3f89bb7f77e5b5270c78.tar.gz |
Imported WebKit commit 0dc6cd75e1d4836eaffbb520be96fac4847cc9d2 (http://svn.webkit.org/repository/webkit/trunk@131300)
WebKit update which introduces the QtWebKitWidgets module that contains the WK1
widgets based API. (In fact it renames QtWebKit to QtWebKitWidgets while we're
working on completing the entire split as part of
https://bugs.webkit.org/show_bug.cgi?id=99314
Diffstat (limited to 'Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | 236 |
1 files changed, 223 insertions, 13 deletions
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp index 301be899c..236a4f304 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp @@ -30,6 +30,7 @@ #include "WebKitContextMenuPrivate.h" #include "WebKitEnumTypes.h" #include "WebKitError.h" +#include "WebKitFaviconDatabasePrivate.h" #include "WebKitFormClient.h" #include "WebKitFullscreenClient.h" #include "WebKitHitTestResultPrivate.h" @@ -56,6 +57,7 @@ #include <WebCore/DragIcon.h> #include <WebCore/GOwnPtrGtk.h> #include <WebCore/GtkUtilities.h> +#include <WebCore/RefPtrCairo.h> #include <glib/gi18n-lib.h> #include <wtf/gobject/GOwnPtr.h> #include <wtf/gobject/GRefPtr.h> @@ -102,6 +104,7 @@ enum { PROP_WEB_CONTEXT, PROP_TITLE, PROP_ESTIMATED_LOAD_PROGRESS, + PROP_FAVICON, PROP_URI, PROP_ZOOM_LEVEL, PROP_IS_LOADING @@ -120,6 +123,7 @@ struct _WebKitWebViewPrivate { bool waitingForMainResource; gulong mainResourceResponseHandlerID; + gulong watchForChangesInFaviconHandlerID; WebKitLoadEvent lastDelayedEvent; GRefPtr<WebKitBackForwardList> backForwardList; @@ -139,6 +143,9 @@ struct _WebKitWebViewPrivate { ResourcesMap subresourcesMap; GRefPtr<WebKitWebInspector> inspector; + + RefPtr<cairo_surface_t> favicon; + GRefPtr<GCancellable> faviconCancellable; }; static guint signals[LAST_SIGNAL] = { 0, }; @@ -260,6 +267,37 @@ static void userAgentChanged(WebKitSettings* settings, GParamSpec*, WebKitWebVie getPage(webView)->setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings))); } +static void webkitWebViewCancelFaviconRequest(WebKitWebView* webView) +{ + if (!webView->priv->faviconCancellable) + return; + + g_cancellable_cancel(webView->priv->faviconCancellable.get()); + webView->priv->faviconCancellable = 0; +} + +static void webkitWebViewUpdateFavicon(WebKitWebView* webView, cairo_surface_t* favicon) +{ + if (webView->priv->favicon.get() == favicon) + return; + + webView->priv->favicon = favicon; + g_object_notify(G_OBJECT(webView), "favicon"); +} + +static void iconReadyCallback(WebKitFaviconDatabase* database, const char* uri, WebKitWebView* webView) +{ + // Consider only the icon matching the active URI for this webview. + if (webView->priv->activeURI != uri) + return; + + // Update the favicon only if we don't have one already. + if (!webView->priv->favicon) { + RefPtr<cairo_surface_t> favicon = adoptRef(webkitFaviconDatabaseGetFavicon(database, webView->priv->activeURI)); + webkitWebViewUpdateFavicon(webView, favicon.get()); + } +} + static void webkitWebViewSetSettings(WebKitWebView* webView, WebKitSettings* settings) { webView->priv->settings = settings; @@ -285,6 +323,29 @@ static void webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(WebK priv->mainResourceResponseHandlerID = 0; } +static void webkitWebViewWatchForChangesInFavicon(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context); + + // Make sure we only connect to this signal once per view. + if (priv->watchForChangesInFaviconHandlerID) + return; + + priv->watchForChangesInFaviconHandlerID = + g_signal_connect(database, "favicon-ready", G_CALLBACK(iconReadyCallback), webView); +} + +static void webkitWebViewDisconnectFaviconDatabaseSignalHandlers(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context); + + if (priv->watchForChangesInFaviconHandlerID) + g_signal_handler_disconnect(database, priv->watchForChangesInFaviconHandlerID); + priv->watchForChangesInFaviconHandlerID = 0; +} + static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request) { GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request); @@ -337,7 +398,7 @@ static void webkitWebViewConstructed(GObject* object) WebKitWebViewPrivate* priv = webView->priv; WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView); - webkitWebViewBaseCreateWebPage(webViewBase, toImpl(webkitWebContextGetWKContext(priv->context)), 0); + webkitWebViewBaseCreateWebPage(webViewBase, webkitWebContextGetContext(priv->context), 0); attachLoaderClientToView(webView); attachUIClientToView(webView); @@ -385,6 +446,9 @@ static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* valu case PROP_ESTIMATED_LOAD_PROGRESS: g_value_set_double(value, webkit_web_view_get_estimated_load_progress(webView)); break; + case PROP_FAVICON: + g_value_set_pointer(value, webkit_web_view_get_favicon(webView)); + break; case PROP_URI: g_value_set_string(value, webkit_web_view_get_uri(webView)); break; @@ -411,8 +475,10 @@ static void webkitWebViewFinalize(GObject* object) if (priv->modalLoop && g_main_loop_is_running(priv->modalLoop.get())) g_main_loop_quit(priv->modalLoop.get()); + webkitWebViewCancelFaviconRequest(webView); webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); webkitWebViewDisconnectSettingsSignalHandlers(webView); + webkitWebViewDisconnectFaviconDatabaseSignalHandlers(webView); priv->~WebKitWebViewPrivate(); G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object); @@ -500,6 +566,18 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) 0.0, 1.0, 0.0, WEBKIT_PARAM_READABLE)); /** + * WebKitWebView:favicon: + * + * The favicon currently associated to the #WebKitWebView. + * See webkit_web_view_get_favicon() for more details. + */ + g_object_class_install_property(gObjectClass, + PROP_FAVICON, + g_param_spec_pointer("favicon", + _("Favicon"), + _("The favicon associated to the view, if any"), + WEBKIT_PARAM_READABLE)); + /** * WebKitWebView:uri: * * The current active URI of the #WebKitWebView. @@ -1158,9 +1236,10 @@ static void setCertificateToMainResource(WebKitWebView* webView) static void webkitWebViewEmitLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) { - if (loadEvent == WEBKIT_LOAD_STARTED) + if (loadEvent == WEBKIT_LOAD_STARTED) { webkitWebViewSetIsLoading(webView, true); - else if (loadEvent == WEBKIT_LOAD_FINISHED) { + webkitWebViewWatchForChangesInFavicon(webView); + } else if (loadEvent == WEBKIT_LOAD_FINISHED) { webkitWebViewSetIsLoading(webView, false); webView->priv->waitingForMainResource = false; webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); @@ -1182,29 +1261,52 @@ static void webkitWebViewEmitDelayedLoadEvents(WebKitWebView* webView) priv->waitingForMainResource = false; } +static void getFaviconReadyCallback(GObject* object, GAsyncResult* result, gpointer userData) +{ + GOwnPtr<GError> error; + RefPtr<cairo_surface_t> favicon = adoptRef(webkit_favicon_database_get_favicon_finish(WEBKIT_FAVICON_DATABASE(object), result, &error.outPtr())); + if (!g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + WebKitWebView* webView = WEBKIT_WEB_VIEW(userData); + webkitWebViewUpdateFavicon(webView, favicon.get()); + webView->priv->faviconCancellable = 0; + } +} + +static void webkitWebViewRequestFavicon(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context); + priv->faviconCancellable = adoptGRef(g_cancellable_new()); + webkit_favicon_database_get_favicon(database, priv->activeURI.data(), priv->faviconCancellable.get(), getFaviconReadyCallback, webView); +} + void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) { + WebKitWebViewPrivate* priv = webView->priv; if (loadEvent == WEBKIT_LOAD_STARTED) { // Finish a possible previous load waiting for main resource. webkitWebViewEmitDelayedLoadEvents(webView); - webView->priv->loadingResourcesMap.clear(); - webView->priv->mainResource = 0; - webView->priv->waitingForMainResource = false; + webkitWebViewCancelFaviconRequest(webView); + priv->loadingResourcesMap.clear(); + priv->mainResource = 0; + priv->waitingForMainResource = false; } else if (loadEvent == WEBKIT_LOAD_COMMITTED) { - webView->priv->subresourcesMap.clear(); - if (!webView->priv->mainResource) { + webkitWebViewRequestFavicon(webView); + + priv->subresourcesMap.clear(); + if (!priv->mainResource) { // When a page is loaded from the history cache, the main resource load callbacks // are called when the main frame load is finished. We want to make sure there's a // main resource available when load has been committed, so we delay the emission of // load-changed signal until main resource object has been created. - webView->priv->waitingForMainResource = true; + priv->waitingForMainResource = true; } else setCertificateToMainResource(webView); } - if (webView->priv->waitingForMainResource) - webView->priv->lastDelayedEvent = loadEvent; + if (priv->waitingForMainResource) + priv->lastDelayedEvent = loadEvent; else webkitWebViewEmitLoadChanged(webView, loadEvent); } @@ -1850,6 +1952,26 @@ const gchar* webkit_web_view_get_uri(WebKitWebView* webView) } /** + * webkit_web_view_get_favicon: + * @web_view: a #WebKitWebView + * + * Returns favicon currently associated to @web_view, if any. You can + * connect to notify::favicon signal of @web_view to be notified when + * the favicon is available. + * + * Returns: (transfer none): a pointer to a #cairo_surface_t with the + * favicon or %NULL if there's no icon associated with @web_view. + */ +cairo_surface_t* webkit_web_view_get_favicon(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + if (webView->priv->activeURI.isNull()) + return 0; + + return webView->priv->favicon.get(); +} + +/** * webkit_web_view_get_custom_charset: * @web_view: a #WebKitWebView * @@ -2192,7 +2314,7 @@ static void webkitWebViewRunJavaScriptCallback(WKSerializedScriptValueRef wkSeri g_simple_async_result_take_error(result.get(), error); else if (wkSerializedScriptValue) { GRefPtr<WebKitWebView> webView = adoptGRef(WEBKIT_WEB_VIEW(g_async_result_get_source_object(G_ASYNC_RESULT(result.get())))); - data->scriptResult = webkitJavascriptResultCreate(webView.get(), wkSerializedScriptValue); + data->scriptResult = webkitJavascriptResultCreate(webView.get(), toImpl(wkSerializedScriptValue)); } else { g_set_error_literal(&error, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED, _("An exception was raised in JavaScript")); g_simple_async_result_take_error(result.get(), error); @@ -2307,6 +2429,94 @@ WebKitJavascriptResult* webkit_web_view_run_javascript_finish(WebKitWebView* web return data->scriptResult ? webkit_javascript_result_ref(data->scriptResult) : 0; } +static void resourcesStreamReadCallback(GObject* object, GAsyncResult* result, gpointer userData) +{ + GOutputStream* outputStream = G_OUTPUT_STREAM(object); + GRefPtr<GSimpleAsyncResult> runJavascriptResult = adoptGRef(G_SIMPLE_ASYNC_RESULT(userData)); + + GError* error = 0; + g_output_stream_splice_finish(outputStream, result, &error); + if (error) { + g_simple_async_result_take_error(runJavascriptResult.get(), error); + g_simple_async_result_complete(runJavascriptResult.get()); + return; + } + + GRefPtr<WebKitWebView> webView = adoptGRef(WEBKIT_WEB_VIEW(g_async_result_get_source_object(G_ASYNC_RESULT(runJavascriptResult.get())))); + gpointer outputStreamData = g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(outputStream)); + getPage(webView.get())->runJavaScriptInMainFrame(String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)), + ScriptValueCallback::create(runJavascriptResult.leakRef(), webkitWebViewRunJavaScriptCallback)); +} + +/** + * webkit_web_view_run_javascript_from_gresource: + * @web_view: a #WebKitWebView + * @resource: the location of the resource to load + * @cancellable: (allow-none): a #GCancellable or %NULL to ignore + * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously run the script from @resource in the context of the + * current page in @web_view. + * + * When the operation is finished, @callback will be called. You can + * then call webkit_web_view_run_javascript_from_gresource_finish() to get the result + * of the operation. + */ +void webkit_web_view_run_javascript_from_gresource(WebKitWebView* webView, const gchar* resource, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(resource); + + GRefPtr<GSimpleAsyncResult> result = adoptGRef(g_simple_async_result_new(G_OBJECT(webView), callback, userData, + reinterpret_cast<gpointer>(webkit_web_view_run_javascript_from_gresource))); + RunJavaScriptAsyncData* data = createRunJavaScriptAsyncData(); + data->cancellable = cancellable; + g_simple_async_result_set_op_res_gpointer(result.get(), data, reinterpret_cast<GDestroyNotify>(destroyRunJavaScriptAsyncData)); + + GError* error = 0; + GRefPtr<GInputStream> inputStream = adoptGRef(g_resources_open_stream(resource, G_RESOURCE_LOOKUP_FLAGS_NONE, &error)); + if (error) { + g_simple_async_result_take_error(result.get(), error); + g_simple_async_result_complete_in_idle(result.get()); + return; + } + + GRefPtr<GOutputStream> outputStream = adoptGRef(g_memory_output_stream_new(0, 0, fastRealloc, fastFree)); + g_output_stream_splice_async(outputStream.get(), inputStream.get(), + static_cast<GOutputStreamSpliceFlags>(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET), + G_PRIORITY_DEFAULT, + cancellable, resourcesStreamReadCallback, result.leakRef()); +} + +/** + * webkit_web_view_run_javascript_from_gresource_finish: + * @web_view: a #WebKitWebView + * @result: a #GAsyncResult + * @error: return location for error or %NULL to ignore + * + * Finish an asynchronous operation started with webkit_web_view_run_javascript_from_gresource(). + * + * Check webkit_web_view_run_javascript_finish() for a usage example. + * + * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script + * or %NULL in case of error + */ +WebKitJavascriptResult* webkit_web_view_run_javascript_from_gresource_finish(WebKitWebView* webView, GAsyncResult* result, GError** error) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + g_return_val_if_fail(G_IS_ASYNC_RESULT(result), 0); + + GSimpleAsyncResult* simpleResult = G_SIMPLE_ASYNC_RESULT(result); + g_warn_if_fail(g_simple_async_result_get_source_tag(simpleResult) == webkit_web_view_run_javascript_from_gresource); + + if (g_simple_async_result_propagate_error(simpleResult, error)) + return 0; + + RunJavaScriptAsyncData* data = static_cast<RunJavaScriptAsyncData*>(g_simple_async_result_get_op_res_gpointer(simpleResult)); + return data->scriptResult ? webkit_javascript_result_ref(data->scriptResult) : 0; +} + /** * webkit_web_view_get_main_resource: * @web_view: a #WebKitWebView @@ -2341,7 +2551,7 @@ GList* webkit_web_view_get_subresources(WebKitWebView* webView) WebKitWebViewPrivate* priv = webView->priv; ResourcesMap::const_iterator end = priv->subresourcesMap.end(); for (ResourcesMap::const_iterator it = priv->subresourcesMap.begin(); it != end; ++it) - subresources = g_list_prepend(subresources, it->second.get()); + subresources = g_list_prepend(subresources, it->value.get()); return g_list_reverse(subresources); } |