diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-12 09:27:39 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-12 09:27:39 +0200 |
commit | 3749d61e1f7a59f5ec5067e560af1eb610c82015 (patch) | |
tree | 73dc228333948738bbe02976cacca8cd382bc978 /Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | |
parent | b32b4dcd9a51ab8de6afc53d9e17f8707e1f7a5e (diff) | |
download | qtwebkit-3749d61e1f7a59f5ec5067e560af1eb610c82015.tar.gz |
Imported WebKit commit a77350243e054f3460d1137301d8b3faee3d2052 (http://svn.webkit.org/repository/webkit/trunk@125365)
New snapshot with build fixes for latest API changes in Qt and all WK1 Win MSVC fixes upstream
Diffstat (limited to 'Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp | 268 |
1 files changed, 259 insertions, 9 deletions
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp index 8bf4d8fe0..80e5fff23 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp @@ -124,6 +124,10 @@ struct _WebKitWebViewPrivate { CString activeURI; ReplaceContentStatus replaceContentStatus; + bool waitingForMainResource; + gulong mainResourceResponseHandlerID; + WebKitLoadEvent lastDelayedEvent; + GRefPtr<WebKitBackForwardList> backForwardList; GRefPtr<WebKitSettings> settings; GRefPtr<WebKitWindowProperties> windowProperties; @@ -268,6 +272,14 @@ static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView } +static void webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + if (priv->mainResourceResponseHandlerID) + g_signal_handler_disconnect(priv->mainResource.get(), priv->mainResourceResponseHandlerID); + priv->mainResourceResponseHandlerID = 0; +} + static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request) { GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request); @@ -382,7 +394,8 @@ static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* valu static void webkitWebViewFinalize(GObject* object) { - WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW(object)->priv; + WebKitWebView* webView = WEBKIT_WEB_VIEW(object); + WebKitWebViewPrivate* priv = webView->priv; if (priv->javascriptGlobalContext) JSGlobalContextRelease(priv->javascriptGlobalContext); @@ -391,7 +404,8 @@ static void webkitWebViewFinalize(GObject* object) if (priv->modalLoop && g_main_loop_is_running(priv->modalLoop.get())) g_main_loop_quit(priv->modalLoop.get()); - webkitWebViewDisconnectSettingsSignalHandlers(WEBKIT_WEB_VIEW(object)); + webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); + webkitWebViewDisconnectSettingsSignalHandlers(webView); priv->~WebKitWebViewPrivate(); G_OBJECT_CLASS(webkit_web_view_parent_class)->finalize(object); @@ -1112,20 +1126,68 @@ static bool updateReplaceContentStatus(WebKitWebView* webView, WebKitLoadEvent l return false; } +static void setCertificateToMainResource(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + ASSERT(priv->mainResource.get()); + + webkitURIResponseSetCertificateInfo(webkit_web_resource_get_response(priv->mainResource.get()), + WKFrameGetCertificateInfo(webkitWebResourceGetFrame(priv->mainResource.get()))); +} + +static void webkitWebViewEmitLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) +{ + if (loadEvent == WEBKIT_LOAD_FINISHED) { + webView->priv->waitingForMainResource = false; + webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); + } else + webkitWebViewUpdateURI(webView); + g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent); +} + +static void webkitWebViewEmitDelayedLoadEvents(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + if (!priv->waitingForMainResource) + return; + ASSERT(priv->lastDelayedEvent == WEBKIT_LOAD_COMMITTED || priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED); + + if (priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED) + webkitWebViewEmitLoadChanged(webView, WEBKIT_LOAD_COMMITTED); + webkitWebViewEmitLoadChanged(webView, priv->lastDelayedEvent); + priv->waitingForMainResource = false; +} + void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent) { if (loadEvent == WEBKIT_LOAD_STARTED) { + // Finish a possible previous load waiting for main resource. + webkitWebViewEmitDelayedLoadEvents(webView); + webView->priv->loadingResourcesMap.clear(); webView->priv->mainResource = 0; - } else if (loadEvent == WEBKIT_LOAD_COMMITTED) + webView->priv->waitingForMainResource = false; + } else if (loadEvent == WEBKIT_LOAD_COMMITTED) { webView->priv->subresourcesMap.clear(); + if (webView->priv->replaceContentStatus != ReplacingContent) { + if (!webView->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; + } else + setCertificateToMainResource(webView); + } + } if (updateReplaceContentStatus(webView, loadEvent)) return; - if (loadEvent != WEBKIT_LOAD_FINISHED) - webkitWebViewUpdateURI(webView); - g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent); + if (webView->priv->waitingForMainResource) + webView->priv->lastDelayedEvent = loadEvent; + else + webkitWebViewEmitLoadChanged(webView, loadEvent); } void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error) @@ -1197,9 +1259,9 @@ void webkitWebViewRunAsModal(WebKitWebView* webView) g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL); webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE)); - GDK_THREADS_ENTER(); + gdk_threads_leave(); g_main_loop_run(webView->priv->modalLoop.get()); - GDK_THREADS_LEAVE(); + gdk_threads_enter(); } void webkitWebViewClosePage(WebKitWebView* webView) @@ -1269,6 +1331,24 @@ void webkitWebViewPrintFrame(WebKitWebView* webView, WKFrameRef wkFrame) g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0); } +static void mainResourceResponseChangedCallback(WebKitWebResource*, GParamSpec*, WebKitWebView* webView) +{ + webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); + setCertificateToMainResource(webView); + webkitWebViewEmitDelayedLoadEvents(webView); +} + +static void waitForMainResourceResponseIfWaitingForResource(WebKitWebView* webView) +{ + WebKitWebViewPrivate* priv = webView->priv; + if (!priv->waitingForMainResource) + return; + + webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView); + priv->mainResourceResponseHandlerID = + g_signal_connect(priv->mainResource.get(), "notify::response", G_CALLBACK(mainResourceResponseChangedCallback), webView); +} + static inline bool webkitWebViewIsReplacingContentOrDidReplaceContent(WebKitWebView* webView) { return (webView->priv->replaceContentStatus == ReplacingContent || webView->priv->replaceContentStatus == DidReplaceContent); @@ -1281,8 +1361,10 @@ void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WKFrameRef wkFrame WebKitWebViewPrivate* priv = webView->priv; WebKitWebResource* resource = webkitWebResourceCreate(wkFrame, request, isMainResource); - if (WKFrameIsMainFrame(wkFrame) && (isMainResource || !priv->mainResource)) + if (WKFrameIsMainFrame(wkFrame) && (isMainResource || !priv->mainResource)) { priv->mainResource = resource; + waitForMainResourceResponseIfWaitingForResource(webView); + } priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource)); g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request); } @@ -2318,3 +2400,171 @@ gboolean webkit_web_view_can_show_mime_type(WebKitWebView* webView, const char* WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView)); return page->canShowMIMEType(String::fromUTF8(mimeType)); } + +struct ViewSaveAsyncData { + WKRetainPtr<WKDataRef> wkData; + GRefPtr<GFile> file; + GRefPtr<GCancellable> cancellable; +}; +WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ViewSaveAsyncData) + +static void fileReplaceContentsCallback(GObject* object, GAsyncResult* result, gpointer data) +{ + GFile* file = G_FILE(object); + GRefPtr<GSimpleAsyncResult> savedToFileResult = adoptGRef(G_SIMPLE_ASYNC_RESULT(data)); + + GError* error = 0; + if (!g_file_replace_contents_finish(file, result, 0, &error)) + g_simple_async_result_take_error(savedToFileResult.get(), error); + + g_simple_async_result_complete(savedToFileResult.get()); +} + +static void getContentsAsMHTMLDataCallback(WKDataRef wkData, WKErrorRef, void* context) +{ + GRefPtr<GSimpleAsyncResult> result = adoptGRef(G_SIMPLE_ASYNC_RESULT(context)); + ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_simple_async_result_get_op_res_gpointer(result.get())); + GError* error = 0; + + if (g_cancellable_set_error_if_cancelled(data->cancellable.get(), &error)) + g_simple_async_result_take_error(result.get(), error); + else { + // We need to retain the data until the asyncronous process + // initiated by the user has finished completely. + data->wkData = wkData; + + // If we are saving to a file we need to write the data on disk before finishing. + if (g_simple_async_result_get_source_tag(result.get()) == webkit_web_view_save_to_file) { + ASSERT(G_IS_FILE(data->file.get())); + g_file_replace_contents_async(data->file.get(), reinterpret_cast<const gchar*>(WKDataGetBytes(data->wkData.get())), WKDataGetSize(data->wkData.get()), 0, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, + data->cancellable.get(), fileReplaceContentsCallback, g_object_ref(result.get())); + return; + } + } + + g_simple_async_result_complete(result.get()); +} + +/** + * webkit_web_view_save: + * @web_view: a #WebKitWebView + * @save_mode: the #WebKitSaveMode specifying how the web page should be saved. + * @cancellable: (allow-none): a #GCancellable or %NULL to ignore + * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously save the current web page associated to the + * #WebKitWebView into a self-contained format using the mode + * specified in @save_mode. + * + * When the operation is finished, @callback will be called. You can + * then call webkit_web_view_save_finish() to get the result of the + * operation. + */ +void webkit_web_view_save(WebKitWebView* webView, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + + // We only support MHTML at the moment. + g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML); + + GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData, + reinterpret_cast<gpointer>(webkit_web_view_save)); + ViewSaveAsyncData* data = createViewSaveAsyncData(); + data->cancellable = cancellable; + g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData)); + + WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))); + WKPageGetContentsAsMHTMLData(wkPage, false, result, getContentsAsMHTMLDataCallback); +} + +/** + * webkit_web_view_save_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_save(). + * + * Returns: (transfer full): a #GInputStream with the result of saving + * the current web page or %NULL in case of error. + */ +GInputStream* webkit_web_view_save_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* simple = G_SIMPLE_ASYNC_RESULT(result); + g_warn_if_fail(g_simple_async_result_get_source_tag(simple) == webkit_web_view_save); + + if (g_simple_async_result_propagate_error(simple, error)) + return 0; + + GInputStream* dataStream = g_memory_input_stream_new(); + ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_simple_async_result_get_op_res_gpointer(simple)); + gsize length = WKDataGetSize(data->wkData.get()); + if (length) + g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(dataStream), g_memdup(WKDataGetBytes(data->wkData.get()), length), length, g_free); + + return dataStream; +} + +/** + * webkit_web_view_save_to_file: + * @web_view: a #WebKitWebView + * @file: the #GFile where the current web page should be saved to. + * @save_mode: the #WebKitSaveMode specifying how the web page should be saved. + * @cancellable: (allow-none): a #GCancellable or %NULL to ignore + * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied + * @user_data: (closure): the data to pass to callback function + * + * Asynchronously save the current web page associated to the + * #WebKitWebView into a self-contained format using the mode + * specified in @save_mode and writing it to @file. + * + * When the operation is finished, @callback will be called. You can + * then call webkit_web_view_save_to_file_finish() to get the result of the + * operation. + */ +void webkit_web_view_save_to_file(WebKitWebView* webView, GFile* file, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData) +{ + g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView)); + g_return_if_fail(G_IS_FILE(file)); + + // We only support MHTML at the moment. + g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML); + + GSimpleAsyncResult* result = g_simple_async_result_new(G_OBJECT(webView), callback, userData, + reinterpret_cast<gpointer>(webkit_web_view_save_to_file)); + ViewSaveAsyncData* data = createViewSaveAsyncData(); + data->file = file; + data->cancellable = cancellable; + g_simple_async_result_set_op_res_gpointer(result, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData)); + + WKPageRef wkPage = toAPI(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView))); + WKPageGetContentsAsMHTMLData(wkPage, false, result, getContentsAsMHTMLDataCallback); +} + +/** + * webkit_web_view_save_to_file_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_save_to_file(). + * + * Returns: %TRUE if the web page was successfully saved to a file or %FALSE otherwise. + */ +gboolean webkit_web_view_save_to_file_finish(WebKitWebView* webView, GAsyncResult* result, GError** error) +{ + g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE); + g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE); + + GSimpleAsyncResult* simple = G_SIMPLE_ASYNC_RESULT(result); + g_warn_if_fail(g_simple_async_result_get_source_tag(simple) == webkit_web_view_save_to_file); + + if (g_simple_async_result_propagate_error(simple, error)) + return FALSE; + + return TRUE; +} |