diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
commit | 2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch) | |
tree | 988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | |
parent | dd91e772430dc294e3bf478c119ef8d43c0a3358 (diff) | |
download | qtwebkit-2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47.tar.gz |
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | 422 |
1 files changed, 421 insertions, 1 deletions
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp index 4f17d4669..56b21df49 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp @@ -24,20 +24,25 @@ #include "WebKitBackForwardListPrivate.h" #include "WebKitEnumTypes.h" #include "WebKitError.h" +#include "WebKitFullscreenClient.h" #include "WebKitHitTestResultPrivate.h" +#include "WebKitJavascriptResultPrivate.h" #include "WebKitLoaderClient.h" #include "WebKitMarshal.h" #include "WebKitPolicyClient.h" #include "WebKitPrintOperationPrivate.h" #include "WebKitPrivate.h" +#include "WebKitResourceLoadClient.h" #include "WebKitScriptDialogPrivate.h" #include "WebKitSettingsPrivate.h" #include "WebKitUIClient.h" #include "WebKitWebContextPrivate.h" +#include "WebKitWebResourcePrivate.h" #include "WebKitWebViewBasePrivate.h" #include "WebKitWebViewPrivate.h" #include "WebKitWindowPropertiesPrivate.h" #include "WebPageProxy.h" +#include <JavaScriptCore/APICast.h> #include <WebCore/DragIcon.h> #include <WebCore/GtkUtilities.h> #include <glib/gi18n-lib.h> @@ -64,6 +69,13 @@ enum { PRINT_REQUESTED, + RESOURCE_LOAD_STARTED, + + ENTER_FULLSCREEN, + LEAVE_FULLSCREEN, + + RUN_FILE_CHOOSER, + LAST_SIGNAL }; @@ -84,6 +96,9 @@ typedef enum { DidReplaceContent } ReplaceContentStatus; +typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap; +typedef HashMap<String, GRefPtr<WebKitWebResource> > ResourcesMap; + struct _WebKitWebViewPrivate { WebKitWebContext* context; CString title; @@ -100,6 +115,11 @@ struct _WebKitWebViewPrivate { unsigned mouseTargetModifiers; GRefPtr<WebKitFindController> findController; + JSGlobalContextRef javascriptGlobalContext; + + GRefPtr<WebKitWebResource> mainResource; + LoadingResourcesMap loadingResourcesMap; + ResourcesMap subresourcesMap; }; static guint signals[LAST_SIGNAL] = { 0, }; @@ -188,6 +208,49 @@ static void webkitWebViewSetSettings(WebKitWebView* webView, WebKitSettings* set g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView); } +static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request) +{ + GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request); + if (responseID == GTK_RESPONSE_ACCEPT) { + GOwnPtr<GSList> filesList(gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog))); + GRefPtr<GPtrArray> filesArray = adoptGRef(g_ptr_array_new()); + for (GSList* file = filesList.get(); file; file = g_slist_next(file)) + g_ptr_array_add(filesArray.get(), file->data); + g_ptr_array_add(filesArray.get(), 0); + webkit_file_chooser_request_select_files(adoptedRequest.get(), reinterpret_cast<const gchar* const*>(filesArray->pdata)); + } else + webkit_file_chooser_request_cancel(adoptedRequest.get()); + + gtk_widget_destroy(GTK_WIDGET(dialog)); +} + +static gboolean webkitWebViewRunFileChooser(WebKitWebView* webView, WebKitFileChooserRequest* request) +{ + GtkWidget* toplevel = gtk_widget_get_toplevel(GTK_WIDGET(webView)); + if (!widgetIsOnscreenToplevelWindow(toplevel)) + toplevel = 0; + + gboolean allowsMultipleSelection = webkit_file_chooser_request_get_select_multiple(request); + GtkWidget* dialog = gtk_file_chooser_dialog_new(allowsMultipleSelection ? _("Select Files") : _("Select File"), + toplevel ? GTK_WINDOW(toplevel) : 0, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + + if (GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request)) + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), allowsMultipleSelection); + + if (const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request)) + gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), selectedFiles[0]); + + g_signal_connect(dialog, "response", G_CALLBACK(fileChooserDialogResponseCallback), g_object_ref(request)); + gtk_widget_show(dialog); + + return TRUE; +} + static void webkitWebViewConstructed(GObject* object) { if (G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed) @@ -202,6 +265,8 @@ static void webkitWebViewConstructed(GObject* object) attachLoaderClientToView(webView); attachUIClientToView(webView); attachPolicyClientToPage(webView); + attachResourceLoadClientToView(webView); + attachFullScreenClientToView(webView); WebPageProxy* page = webkitWebViewBaseGetPage(webViewBase); priv->backForwardList = adoptGRef(webkitBackForwardListCreate(WKPageGetBackForwardList(toAPI(page)))); @@ -255,7 +320,10 @@ static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* valu static void webkitWebViewFinalize(GObject* object) { - WEBKIT_WEB_VIEW(object)->priv->~WebKitWebViewPrivate(); + WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW(object)->priv; + if (priv->javascriptGlobalContext) + JSGlobalContextRelease(priv->javascriptGlobalContext); + priv->~WebKitWebViewPrivate(); G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object); } @@ -290,6 +358,7 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) webViewClass->create = webkitWebViewCreate; webViewClass->script_dialog = webkitWebViewScriptDialog; webViewClass->decide_policy = webkitWebViewDecidePolicy; + webViewClass->run_file_chooser = webkitWebViewRunFileChooser; g_type_class_add_private(webViewClass, sizeof(WebKitWebViewPrivate)); @@ -666,6 +735,104 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) webkit_marshal_BOOLEAN__OBJECT, G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_PRINT_OPERATION); + + /** + * WebKitWebView::resource-load-started: + * @web_view: the #WebKitWebView on which the signal is emitted + * @resource: a #WebKitWebResource + * @request: a #WebKitURIRequest + * + * Emitted when a new resource is going to be loaded. The @request parameter + * contains the #WebKitURIRequest that will be sent to the server. + * You can monitor the load operation by connecting to the different signals + * of @resource. + */ + signals[RESOURCE_LOAD_STARTED] = + g_signal_new("resource-load-started", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, resource_load_started), + 0, 0, + webkit_marshal_VOID__OBJECT_OBJECT, + G_TYPE_NONE, 2, + WEBKIT_TYPE_WEB_RESOURCE, + WEBKIT_TYPE_URI_REQUEST); + + /** + * WebKitWebView::enter-fullscreen: + * @web_view: the #WebKitWebView on which the signal is emitted. + * + * Emitted when JavaScript code calls + * <function>element.webkitRequestFullScreen</function>. If the + * signal is not handled the #WebKitWebView will proceed to full screen + * its top level window. This signal can be used by client code to + * request permission to the user prior doing the full screen + * transition and eventually prepare the top-level window + * (e.g. hide some widgets that would otherwise be part of the + * full screen window). + * + * Returns: %TRUE to stop other handlers from being invoked for the event. + * %FALSE to continue emission of the event. + */ + signals[ENTER_FULLSCREEN] = + g_signal_new("enter-fullscreen", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, enter_fullscreen), + g_signal_accumulator_true_handled, 0, + webkit_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, 0); + + /** + * WebKitWebView::leave-fullscreen: + * @web_view: the #WebKitWebView on which the signal is emitted. + * + * Emitted when the #WebKitWebView is about to restore its top level + * window out of its full screen state. This signal can be used by + * client code to restore widgets hidden during the + * #WebKitWebView::enter-fullscreen stage for instance. + * + * Returns: %TRUE to stop other handlers from being invoked for the event. + * %FALSE to continue emission of the event. + */ + signals[LEAVE_FULLSCREEN] = + g_signal_new("leave-fullscreen", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, leave_fullscreen), + g_signal_accumulator_true_handled, 0, + webkit_marshal_BOOLEAN__VOID, + G_TYPE_BOOLEAN, 0); + /** + * WebKitWebView::run-file-chooser: + * @web_view: the #WebKitWebView on which the signal is emitted + * @request: a #WebKitFileChooserRequest + * + * This signal is emitted when the user interacts with a <input + * type='file' /> HTML element, requesting from WebKit to show + * a dialog to select one or more files to be uploaded. To let the + * application know the details of the file chooser, as well as to + * allow the client application to either cancel the request or + * perform an actual selection of files, the signal will pass an + * instance of the #WebKitFileChooserRequest in the @request + * argument. + * + * The default signal handler will asynchronously run a regular + * #GtkFileChooserDialog for the user to interact with. + * + * Returns: %TRUE to stop other handlers from being invoked for the event. + * %FALSE to propagate the event further. + * + */ + signals[RUN_FILE_CHOOSER] = + g_signal_new("run-file-chooser", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, run_file_chooser), + g_signal_accumulator_true_handled, 0 /* accumulator data */, + webkit_marshal_BOOLEAN__OBJECT, + G_TYPE_BOOLEAN, 1, /* number of parameters */ + WEBKIT_TYPE_FILE_CHOOSER_REQUEST); } static bool updateReplaceContentStatus(WebKitWebView* webView, WebKitLoadEvent loadEvent) @@ -689,6 +856,12 @@ static bool updateReplaceContentStatus(WebKitWebView* webView, WebKitLoadEvent l void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) { + if (loadEvent == WEBKIT_LOAD_STARTED) { + webView->priv->loadingResourcesMap.clear(); + webView->priv->mainResource = 0; + } else if (loadEvent == WEBKIT_LOAD_COMMITTED) + webView->priv->subresourcesMap.clear(); + if (updateReplaceContentStatus(webView, loadEvent)) return; @@ -822,6 +995,77 @@ void webkitWebViewPrintFrame(WebKitWebView* webView, WKFrameRef wkFrame) g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0); } +static inline bool webkitWebViewIsReplacingContentOrDidReplaceContent(WebKitWebView* webView) +{ + return (webView->priv->replaceContentStatus == ReplacingContent || webView->priv->replaceContentStatus == DidReplaceContent); +} + +void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WKFrameRef wkFrame, uint64_t resourceIdentifier, WebKitURIRequest* request, bool isMainResource) +{ + if (webkitWebViewIsReplacingContentOrDidReplaceContent(webView)) + return; + + WebKitWebViewPrivate* priv = webView->priv; + WebKitWebResource* resource = webkitWebResourceCreate(wkFrame, request, isMainResource); + if (WKFrameIsMainFrame(wkFrame) && isMainResource) + priv->mainResource = resource; + priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource)); + g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request); +} + +WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier) +{ + if (webkitWebViewIsReplacingContentOrDidReplaceContent(webView)) + return 0; + + GRefPtr<WebKitWebResource> resource = webView->priv->loadingResourcesMap.get(resourceIdentifier); + ASSERT(resource.get()); + return resource.get(); +} + +void webkitWebViewRemoveLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier) +{ + if (webkitWebViewIsReplacingContentOrDidReplaceContent(webView)) + return; + + WebKitWebViewPrivate* priv = webView->priv; + ASSERT(priv->loadingResourcesMap.contains(resourceIdentifier)); + priv->loadingResourcesMap.remove(resourceIdentifier); +} + +WebKitWebResource* webkitWebViewResourceLoadFinished(WebKitWebView* webView, uint64_t resourceIdentifier) +{ + if (webkitWebViewIsReplacingContentOrDidReplaceContent(webView)) + return 0; + + WebKitWebViewPrivate* priv = webView->priv; + WebKitWebResource* resource = webkitWebViewGetLoadingWebResource(webView, resourceIdentifier); + if (resource != priv->mainResource) + priv->subresourcesMap.set(String::fromUTF8(webkit_web_resource_get_uri(resource)), resource); + webkitWebViewRemoveLoadingWebResource(webView, resourceIdentifier); + return resource; +} + +bool webkitWebViewEnterFullScreen(WebKitWebView* webView) +{ + gboolean returnValue; + g_signal_emit(webView, signals[ENTER_FULLSCREEN], 0, &returnValue); + return !returnValue; +} + +bool webkitWebViewLeaveFullScreen(WebKitWebView* webView) +{ + gboolean returnValue; + g_signal_emit(webView, signals[LEAVE_FULLSCREEN], 0, &returnValue); + return !returnValue; +} + +void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChooserRequest* request) +{ + gboolean returnValue; + g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue); +} + /** * webkit_web_view_new: * @@ -1466,3 +1710,179 @@ WebKitFindController* webkit_web_view_get_find_controller(WebKitWebView* webView return webView->priv->findController.get(); } + +/** + * webkit_web_view_get_javascript_global_context: + * @web_view: a #WebKitWebView + * + * Get the global JavaScript context used by @web_view to deserialize the + * result values of scripts executed with webkit_web_view_run_javascript(). + * + * Returns: the <function>JSGlobalContextRef</function> used by @web_view to deserialize + * the result values of scripts. + */ +JSGlobalContextRef webkit_web_view_get_javascript_global_context(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + + if (!webView->priv->javascriptGlobalContext) + webView->priv->javascriptGlobalContext = JSGlobalContextCreate(0); + return webView->priv->javascriptGlobalContext; +} + +static void webkitWebViewRunJavaScriptCallback(WKSerializedScriptValueRef wkSerializedScriptValue, WKErrorRef, void* context) +{ + GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context)); + if (wkSerializedScriptValue) { + GRefPtr<WebKitWebView> webView = adoptGRef(WEBKIT_WEB_VIEW(g_async_result_get_source_object(G_ASYNC_RESULT(result.get())))); + WebKitJavascriptResult* scriptResult = webkitJavascriptResultCreate(webView.get(), wkSerializedScriptValue); + g_simple_async_result_set_op_res_gpointer(result.get(), scriptResult, reinterpret_cast<GDestroyNotify>(webkit_javascript_result_unref)); + } else { + GError* error = 0; + 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); + } + g_simple_async_result_complete(result.get()); +} + +/** + * webkit_web_view_run_javascript: + * @web_view: a #WebKitWebView + * @script: the script to run + * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously run @script 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_finish() to get the result of the operation. + */ +void webkit_web_view_run_javascript(WebKitWebView* webView, const gchar* script, GAsyncReadyCallback callback, gpointer userData) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(script); + + WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))); + WKRetainPtr<WKStringRef> wkScript = adoptWK(WKStringCreateWithUTF8CString(script)); + GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData, + reinterpret_cast<gpointer>(webkit_web_view_run_javascript)); + WKPageRunJavaScriptInMainFrame(wkPage, wkScript.get(), result, webkitWebViewRunJavaScriptCallback); +} + +/** + * webkit_web_view_run_javascript_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(). + * + * This is an example of using webkit_web_view_run_javascript() with a script returning + * a string: + * + * <informalexample><programlisting> + * static void + * web_view_javascript_finished (GObject *object, + * GAsyncResult *result, + * gpointer user_data) + * { + * WebKitJavascriptResult *js_result; + * JSValueRef value; + * JSGlobalContextRef context; + * GError *error = NULL; + * + * js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error); + * if (!js_result) { + * g_warning ("Error running javascript: %s", error->message); + * g_error_free (error); + * return; + * } + * + * context = webkit_javascript_result_get_global_context (js_result); + * value = webkit_javascript_result_get_value (js_result); + * if (JSValueIsString (context, value)) { + * JSStringRef *js_str_value; + * gchar *str_value; + * gsize str_length; + * + * js_str_value = JSValueToStringCopy (context, value, NULL)); + * str_length = JSStringGetMaximumUTF8CStringSize (js_str_value); + * str_value = (gchar *)g_malloc (str_length)); + * JSStringGetUTF8CString (js_str_value, str_value, str_length); + * JSStringRelease (js_str_value); + * g_print ("Script result: %s\n", str_value); + * g_free (str_value); + * } else { + * g_warning ("Error running javascript: unexpected return value"); + * } + * webkit_javascript_result_unref (js_result); + * } + * + * static void + * web_view_get_link_url (WebKitWebView *web_view, + * const gchar *link_id) + * { + * gchar *script; + * + * script = g_strdup_printf ("window.document.getElementById('%s').href;", link_id); + * webkit_web_view_run_javascript (web_view, script, web_view_javascript_finished, NULL); + * g_free (script); + * } + * </programlisting></informalexample> + * + * 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_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); + + if (g_simple_async_result_propagate_error(simpleResult, error)) + return 0; + + WebKitJavascriptResult* scriptResult = static_cast<WebKitJavascriptResult*>(g_simple_async_result_get_op_res_gpointer(simpleResult)); + return scriptResult ? webkit_javascript_result_ref(scriptResult) : 0; +} + +/** + * webkit_web_view_get_main_resource: + * @web_view: a #WebKitWebView + * + * Return the main resource of @web_view. + * See also webkit_web_view_get_subresources(): + * + * Returns: (transfer none): the main #WebKitWebResource of the view + * or %NULL if nothing has been loaded. + */ +WebKitWebResource* webkit_web_view_get_main_resource(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + + return webView->priv->mainResource.get(); +} + +/** + * webkit_web_view_get_subresources: + * @web_view: a #WebKitWebView + * + * Return the list of subresources of @web_view. + * See also webkit_web_view_get_main_resource(). + * + * Returns: (element-type WebKitWebResource) (transfer container): a list of #WebKitWebResource. + */ +GList* webkit_web_view_get_subresources(WebKitWebView* webView) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0); + + GList* subresources = 0; + 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()); + + return g_list_reverse(subresources); +} |