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 | |
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')
22 files changed, 523 insertions, 74 deletions
diff --git a/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp index 8ecd480e5..5a6adae0a 100644 --- a/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/PageClientImpl.cpp @@ -142,6 +142,9 @@ void PageClientImpl::toolTipChanged(const String&, const String& newToolTip) void PageClientImpl::setCursor(const Cursor& cursor) { + if (!gtk_widget_get_realized(m_viewWidget)) + return; + // [GTK] Widget::setCursor() gets called frequently // http://bugs.webkit.org/show_bug.cgi?id=16388 // Setting the cursor may be an expensive operation in some backends, diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitBackForwardListPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitBackForwardListPrivate.h index e01909201..333e68d18 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitBackForwardListPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitBackForwardListPrivate.h @@ -28,7 +28,7 @@ #include "WebBackForwardList.h" #include "WebKitBackForwardList.h" -#include <WebKit2/WebKit2.h> +#include <WebKit2/WebKit2_C.h> WebKitBackForwardList* webkitBackForwardListCreate(WKBackForwardListRef); WebKitBackForwardListItem* webkitBackForwardListItemGetOrCreate(WKBackForwardListItemRef); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitLoaderClient.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitLoaderClient.cpp index 8cd149c5b..6c3bf920a 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitLoaderClient.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitLoaderClient.cpp @@ -65,16 +65,7 @@ static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef us if (!WKFrameIsMainFrame(frame)) return; - WebKitWebView* webView = WEBKIT_WEB_VIEW(clientInfo); - WebKitWebResource* resource = webkit_web_view_get_main_resource(webView); - if (resource) { - // We might not have a resource if this load is a content replacement. - // FIXME: For some reason, when going back/forward this callback is emitted even before - // didInitiateLoadForResource(), so we don't have a main resource at this point either. - webkitURIResponseSetCertificateInfo(webkit_web_resource_get_response(resource), WKFrameGetCertificateInfo(frame)); - } - - webkitWebViewLoadChanged(webView, WEBKIT_LOAD_COMMITTED); + webkitWebViewLoadChanged(WEBKIT_WEB_VIEW(clientInfo), WEBKIT_LOAD_COMMITTED); } static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo) diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitPolicyDecisionPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitPolicyDecisionPrivate.h index 62580c83e..e02caab64 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitPolicyDecisionPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitPolicyDecisionPrivate.h @@ -21,7 +21,7 @@ #define WebKitPolicyDecisionPrivate_h #include "WebKitPolicyDecision.h" -#include <WebKit2/WebKit2.h> +#include <WebKit2/WebKit2_C.h> void webkitPolicyDecisionSetListener(WebKitPolicyDecision*, WKFramePolicyListenerRef); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h index aa8a71bf9..8fede827f 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitPrivate.h @@ -41,7 +41,7 @@ #include <WebKit2/WKSoupRequestManager.h> #include <WebKit2/WKString.h> #include <WebKit2/WKTextChecker.h> -#include <WebKit2/WebKit2.h> +#include <WebKit2/WebKit2_C.h> #include <glib.h> #include <wtf/Assertions.h> diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitSettingsPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitSettingsPrivate.h index a47ac7f74..4e5d23217 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitSettingsPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitSettingsPrivate.h @@ -27,7 +27,7 @@ #define WebKitSettingsPrivate_h #include "WebKitSettings.h" -#include <WebKit2/WebKit2.h> +#include <WebKit2/WebKit2_C.h> void webkitSettingsAttachSettingsToPage(WebKitSettings*, WKPageRef); diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.cpp index 5676bb6d7..5ae62c6fd 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.cpp @@ -140,13 +140,15 @@ void WebKitTextChecker::setSpellCheckingEnabled(bool enabled) WKTextCheckerContinuousSpellCheckingEnabledStateChanged(enabled); } -void WebKitTextChecker::setSpellCheckingLanguages(const String& languages) +const CString& WebKitTextChecker::getSpellCheckingLanguages() { - if (m_spellCheckingLanguages == languages) - return; - m_spellCheckingLanguages = languages; + String spellCheckingLanguages = m_textChecker->getSpellCheckingLanguages(); + m_spellCheckingLanguages = spellCheckingLanguages.isEmpty() ? CString() : spellCheckingLanguages.utf8(); + return m_spellCheckingLanguages; +} - // We need to update the languages in the enchant-based checker too. - m_textChecker->updateSpellCheckingLanguages(languages); +void WebKitTextChecker::setSpellCheckingLanguages(const CString& languages) +{ + m_textChecker->updateSpellCheckingLanguages(String::fromUTF8(languages.data())); } #endif // ENABLE(SPELLCHECK) diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.h b/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.h index dd7583a3a..3cca5622a 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitTextChecker.h @@ -26,6 +26,7 @@ #include <wtf/FastAllocBase.h> #include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> +#include <wtf/text/CString.h> class WebKitTextChecker { WTF_MAKE_FAST_ALLOCATED; @@ -43,14 +44,14 @@ public: void ignoreWord(const String& word); // To be called from WebKitWebContext only. - const String getSpellCheckingLanguages() { return m_spellCheckingLanguages; } - void setSpellCheckingLanguages(const String& spellCheckingLanguages); + const CString& getSpellCheckingLanguages(); + void setSpellCheckingLanguages(const CString& spellCheckingLanguages); private: WebKitTextChecker(); OwnPtr<WebCore::TextCheckerEnchant> m_textChecker; - String m_spellCheckingLanguages; + CString m_spellCheckingLanguages; bool m_spellCheckingEnabled; }; diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp index 4008e865f..fe9df9f75 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp @@ -77,7 +77,6 @@ struct _WebKitWebContextPrivate { #endif #if ENABLE(SPELLCHECK) OwnPtr<WebKitTextChecker> textChecker; - GOwnPtr<gchar> spellCheckingLanguages; #endif }; @@ -125,7 +124,7 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass static gpointer createDefaultWebContext(gpointer) { static GRefPtr<WebKitWebContext> webContext = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, NULL))); - webContext->priv->context = WKContextGetSharedProcessContext(); + webContext->priv->context = WKContextCreate(); webContext->priv->requestManager = WKContextGetSoupRequestManager(webContext->priv->context.get()); WKContextSetCacheModel(webContext->priv->context.get(), kWKCacheModelPrimaryWebBrowser); attachDownloadClientToContext(webContext.get()); @@ -432,7 +431,7 @@ void webkit_web_context_register_uri_scheme(WebKitWebContext* context, const cha * webkit_web_context_get_spell_checking_enabled: * @context: a #WebKitWebContext * - * Get the current status of the spell checking feature. + * Get whether spell checking feature is currently enabled. * * Returns: %TRUE If spell checking is enabled, or %FALSE otherwise. */ @@ -468,18 +467,24 @@ void webkit_web_context_set_spell_checking_enabled(WebKitWebContext* context, gb * @context: a #WebKitWebContext * * Get the the list of spell checking languages associated with - * @context, separated by commas. See - * webkit_web_context_set_spell_checking_languages() for more details - * on the format of the languages in the list. + * @context separated by commas, or %NULL if no languages have been + * previously set. + + * See webkit_web_context_set_spell_checking_languages() for more + * details on the format of the languages in the list. * - * Returns: (transfer none): A comma separated list of languages. + * Returns: (transfer none): A comma separated list of languages if + * available, or %NULL otherwise. */ const gchar* webkit_web_context_get_spell_checking_languages(WebKitWebContext* context) { g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0); #if ENABLE(SPELLCHECK) - return context->priv->spellCheckingLanguages.get(); + CString spellCheckingLanguages = context->priv->textChecker->getSpellCheckingLanguages(); + if (spellCheckingLanguages.isNull()) + return 0; + return spellCheckingLanguages.data(); #else return 0; #endif @@ -488,25 +493,28 @@ const gchar* webkit_web_context_get_spell_checking_languages(WebKitWebContext* c /** * webkit_web_context_set_spell_checking_languages: * @context: a #WebKitWebContext - * @languages: (allow-none): new list of spell checking - * languages separated by commas, or %NULL + * @languages: new list of spell checking languages separated by + * commas * * Set the list of spell checking languages to be used for spell - * checking, separated by commas. In case %NULL is passed, the default - * value as returned by gtk_get_default_language() will be used. + * checking, separated by commas. * * The locale string typically is in the form lang_COUNTRY, where lang * is an ISO-639 language code, and COUNTRY is an ISO-3166 country code. * For instance, sv_FI for Swedish as written in Finland or pt_BR * for Portuguese as written in Brazil. + * + * You need to call this function with a valid list of languages at + * least once in order to properly enable the spell checking feature + * in WebKit. */ void webkit_web_context_set_spell_checking_languages(WebKitWebContext* context, const gchar* languages) { g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context)); + g_return_if_fail(languages); #if ENABLE(SPELLCHECK) - context->priv->textChecker->setSpellCheckingLanguages(String(languages)); - context->priv->spellCheckingLanguages.set(g_strdup(languages)); + context->priv->textChecker->setSpellCheckingLanguages(languages); #endif } diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebResource.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebResource.cpp index 7fbe28a0a..5ca5e989d 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebResource.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebResource.cpp @@ -243,6 +243,11 @@ void webkitWebResourceFailed(WebKitWebResource* resource, GError* error) g_signal_emit(resource, signals[FINISHED], 0, NULL); } +WKFrameRef webkitWebResourceGetFrame(WebKitWebResource* resource) +{ + return resource->priv->wkFrame.get(); +} + /** * webkit_web_resource_get_uri: * @resource: a #WebKitWebResource diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebResourcePrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebResourcePrivate.h index 5011ae4dd..ed1fe02f1 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebResourcePrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebResourcePrivate.h @@ -29,6 +29,7 @@ void webkitWebResourceSetResponse(WebKitWebResource*, WebKitURIResponse*); void webkitWebResourceNotifyProgress(WebKitWebResource*, guint64 bytesReceived); void webkitWebResourceFinished(WebKitWebResource*); void webkitWebResourceFailed(WebKitWebResource*, GError*); +WKFrameRef webkitWebResourceGetFrame(WebKitWebResource*); #endif // WebKitWebResourcePrivate_h 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; +} diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h index 2553b1840..6ebd17f04 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h @@ -118,6 +118,17 @@ typedef enum { WEBKIT_LOAD_FINISHED } WebKitLoadEvent; +/** + * WebKitSaveMode: + * @WEBKIT_SAVE_MODE_MHTML: Save the current page using the MHTML format. + * + * Enum values to specify the different ways in which a #WebKitWebView + * can save its current web page into a self-contained file. + */ +typedef enum { + WEBKIT_SAVE_MODE_MHTML +} WebKitSaveMode; + struct _WebKitWebView { WebKitWebViewBase parent; @@ -319,6 +330,31 @@ WEBKIT_API gboolean webkit_web_view_can_show_mime_type (WebKitWebView *web_view, const gchar *mime_type); +WEBKIT_API void +webkit_web_view_save (WebKitWebView *web_view, + WebKitSaveMode save_mode, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +WEBKIT_API GInputStream * +webkit_web_view_save_finish (WebKitWebView *web_view, + GAsyncResult *result, + GError **error); + +WEBKIT_API void +webkit_web_view_save_to_file (WebKitWebView *web_view, + GFile *file, + WebKitSaveMode save_mode, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +WEBKIT_API gboolean +webkit_web_view_save_to_file_finish (WebKitWebView *web_view, + GAsyncResult *result, + GError **error); + G_END_DECLS #endif diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp index f65fa97ed..4925b5a7c 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -101,9 +101,6 @@ struct _WebKitWebViewBasePrivate { G_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER) -// Keep this in sync with the value minimumAttachedHeight in WebInspectorProxy. -static const unsigned gMinimumAttachedInspectorHeight = 250; - static void webkitWebViewBaseNotifyResizerSizeForWindow(WebKitWebViewBase* webViewBase, GtkWindow* window) { gboolean resizerVisible; @@ -190,7 +187,6 @@ static void webkitWebViewBaseContainerAdd(GtkContainer* container, GtkWidget* wi && WebInspectorProxy::isInspectorPage(WEBKIT_WEB_VIEW_BASE(widget)->priv->pageProxy.get())) { ASSERT(!priv->inspectorView); priv->inspectorView = widget; - priv->inspectorViewHeight = gMinimumAttachedInspectorHeight; } else { GtkAllocation childAllocation; gtk_widget_get_allocation(widget, &childAllocation); @@ -773,12 +769,11 @@ void webkitWebViewBaseInitializeFullScreenClient(WebKitWebViewBase* webkitWebVie void webkitWebViewBaseSetInspectorViewHeight(WebKitWebViewBase* webkitWebViewBase, unsigned height) { - if (!webkitWebViewBase->priv->inspectorView) - return; if (webkitWebViewBase->priv->inspectorViewHeight == height) return; webkitWebViewBase->priv->inspectorViewHeight = height; - gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase)); + if (webkitWebViewBase->priv->inspectorView) + gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase)); } void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy) diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h index 1833fb111..f2986d1f9 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h @@ -28,7 +28,7 @@ #define WebKitWebViewPrivate_h #include "WebKitWebView.h" -#include <WebKit2/WebKit2.h> +#include <WebKit2/WebKit2_C.h> #include <wtf/text/CString.h> void webkitWebViewLoadChanged(WebKitWebView*, WebKitLoadEvent); diff --git a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt index 73f09d5d3..92da1ebe5 100644 --- a/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt +++ b/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-sections.txt @@ -62,6 +62,7 @@ webkit_web_context_get_type WebKitWebView WebKitLoadEvent WebKitPolicyDecisionType +WebKitSaveMode <SUBSECTION Editing Commands> WEBKIT_EDITING_COMMAND_CUT @@ -105,6 +106,10 @@ webkit_web_view_get_javascript_global_context webkit_web_view_run_javascript webkit_web_view_run_javascript_finish webkit_web_view_can_show_mime_type +webkit_web_view_save +webkit_web_view_save_finish +webkit_web_view_save_to_file +webkit_web_view_save_to_file_finish <SUBSECTION WebKitJavascriptResult> WebKitJavascriptResult diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.cpp index a35c8745b..d370de938 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.cpp @@ -35,10 +35,17 @@ static void loadChangedCallback(WebKitWebView* webView, WebKitLoadEvent loadEven g_assert_cmpstr(test->m_redirectURI.data(), ==, test->m_activeURI.data()); test->provisionalLoadReceivedServerRedirect(); break; - case WEBKIT_LOAD_COMMITTED: + case WEBKIT_LOAD_COMMITTED: { g_assert_cmpstr(test->m_activeURI.data(), ==, webkit_web_view_get_uri(webView)); + + // Check that on committed we always have a main resource with a response. + WebKitWebResource* resource = webkit_web_view_get_main_resource(webView); + g_assert(resource); + g_assert(webkit_web_resource_get_response(resource)); + test->loadCommitted(); break; + } case WEBKIT_LOAD_FINISHED: if (!test->m_loadFailed) g_assert_cmpstr(test->m_activeURI.data(), ==, webkit_web_view_get_uri(webView)); @@ -170,3 +177,17 @@ void LoadTrackingTest::reload() m_estimatedProgress = 0; webkit_web_view_reload(m_webView); } + +void LoadTrackingTest::goBack() +{ + m_loadEvents.clear(); + m_estimatedProgress = 0; + WebViewTest::goBack(); +} + +void LoadTrackingTest::goForward() +{ + m_loadEvents.clear(); + m_estimatedProgress = 0; + WebViewTest::goForward(); +} diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.h b/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.h index 2d95c48f4..562f7f038 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.h +++ b/Source/WebKit2/UIProcess/API/gtk/tests/LoadTrackingTest.h @@ -44,6 +44,8 @@ public: void loadPlainText(const char* plainText); void loadRequest(WebKitURIRequest*); void reload(); + void goBack(); + void goForward(); void setRedirectURI(const char* uri) { m_redirectURI = uri; } diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestInspector.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestInspector.cpp index 9b023f3ed..673749411 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestInspector.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestInspector.cpp @@ -22,8 +22,6 @@ #include "WebViewTest.h" #include <wtf/gobject/GRefPtr.h> -static const unsigned gMinimumAttachedInspectorHeight = 250; - class InspectorTest: public WebViewTest { public: MAKE_GLIB_TEST_FIXTURE(InspectorTest); @@ -181,6 +179,7 @@ static void testInspectorDefault(InspectorTest* test, gconstpointer) test->resizeViewAndAttach(); g_assert(webkit_web_inspector_is_attached(test->m_inspector)); + g_assert_cmpuint(webkit_web_inspector_get_attached_height(test->m_inspector), >=, InspectorTest::gMinimumAttachedInspectorHeight); events = test->m_events; g_assert_cmpint(events.size(), ==, 1); g_assert_cmpint(events[0], ==, InspectorTest::Attach); @@ -258,6 +257,7 @@ public: gtk_widget_show_all(pane); } else pane = gtk_bin_get_child(GTK_BIN(m_parentWindow)); + gtk_paned_set_position(GTK_PANED(pane), webkit_web_inspector_get_attached_height(m_inspector)); gtk_paned_add2(GTK_PANED(pane), GTK_WIDGET(inspectorView.get())); return InspectorTest::attach(); @@ -301,6 +301,7 @@ static void testInspectorManualAttachDetach(CustomInspectorTest* test, gconstpoi test->resizeViewAndAttach(); g_assert(webkit_web_inspector_is_attached(test->m_inspector)); + g_assert_cmpuint(webkit_web_inspector_get_attached_height(test->m_inspector), >=, InspectorTest::gMinimumAttachedInspectorHeight); events = test->m_events; g_assert_cmpint(events.size(), ==, 1); g_assert_cmpint(events[0], ==, InspectorTest::Attach); diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestLoaderClient.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestLoaderClient.cpp index 3afa2b96f..59eed7658 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestLoaderClient.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestLoaderClient.cpp @@ -144,6 +144,26 @@ static void testLoadProgress(LoadTrackingTest* test, gconstpointer) g_assert_cmpfloat(test->m_estimatedProgress, ==, 1); } +static void testWebViewHistoryLoad(LoadTrackingTest* test, gconstpointer) +{ + test->loadURI(kServer->getURIForPath("/normal").data()); + test->waitUntilLoadFinished(); + assertNormalLoadHappened(test->m_loadEvents); + + test->loadURI(kServer->getURIForPath("/normal2").data()); + test->waitUntilLoadFinished(); + assertNormalLoadHappened(test->m_loadEvents); + + // Check that load process is the same for pages loaded from history cache. + test->goBack(); + test->waitUntilLoadFinished(); + assertNormalLoadHappened(test->m_loadEvents); + + test->goForward(); + test->waitUntilLoadFinished(); + assertNormalLoadHappened(test->m_loadEvents); +} + class ViewURITrackingTest: public LoadTrackingTest { public: MAKE_GLIB_TEST_FIXTURE(ViewURITrackingTest); @@ -217,7 +237,7 @@ static void serverCallback(SoupServer* server, SoupMessage* message, const char* soup_message_set_status(message, SOUP_STATUS_OK); - if (g_str_equal(path, "/normal")) + if (g_str_has_prefix(path, "/normal")) soup_message_body_append(message->response_body, SOUP_MEMORY_STATIC, responseString, strlen(responseString)); else if (g_str_equal(path, "/error")) soup_message_set_status(message, SOUP_STATUS_CANT_CONNECT); @@ -248,6 +268,7 @@ void beforeAll() LoadTrackingTest::add("WebKitWebView", "title", testWebViewTitle); LoadTrackingTest::add("WebKitWebView", "progress", testLoadProgress); LoadTrackingTest::add("WebKitWebView", "reload", testWebViewReload); + LoadTrackingTest::add("WebKitWebView", "history-load", testWebViewHistoryLoad); // This test checks that web view notify::uri signal is correctly emitted // and the uri is already updated when loader client signals are emitted. diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebContext.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebContext.cpp index f42feafb7..1b172dfee 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebContext.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebContext.cpp @@ -233,28 +233,37 @@ static void testWebContextURIScheme(URISchemeTest* test, gconstpointer) static void testWebContextSpellChecker(Test* test, gconstpointer) { - GRefPtr<WebKitWebContext> webContext(webkit_web_context_get_default()); + WebKitWebContext* webContext = webkit_web_context_get_default(); - // Set the language to a specific one, an empty one and a list of them. - webkit_web_context_set_spell_checking_languages(webContext.get(), "en_US"); - const gchar* currentLanguage(webkit_web_context_get_spell_checking_languages(webContext.get())); + // Check what happens if no spell checking language has been set. + const gchar* currentLanguage = webkit_web_context_get_spell_checking_languages(webContext); + g_assert(!currentLanguage); + + // Set the language to a specific one. + webkit_web_context_set_spell_checking_languages(webContext, "en_US"); + currentLanguage = webkit_web_context_get_spell_checking_languages(webContext); g_assert_cmpstr(currentLanguage, ==, "en_US"); - webkit_web_context_set_spell_checking_languages(webContext.get(), 0); - currentLanguage = webkit_web_context_get_spell_checking_languages(webContext.get()); - g_assert_cmpstr(currentLanguage, ==, 0); + // Set the language string to list of valid languages. + webkit_web_context_set_spell_checking_languages(webContext, "en_GB,en_US"); + currentLanguage = webkit_web_context_get_spell_checking_languages(webContext); + g_assert_cmpstr(currentLanguage, ==, "en_GB,en_US"); + + // Try passing a wrong language along with good ones. + webkit_web_context_set_spell_checking_languages(webContext, "bd_WR,en_US,en_GB"); + currentLanguage = webkit_web_context_get_spell_checking_languages(webContext); + g_assert_cmpstr(currentLanguage, ==, "en_US,en_GB"); - webkit_web_context_set_spell_checking_languages(webContext.get(), "es_ES,en_US"); - currentLanguage = webkit_web_context_get_spell_checking_languages(webContext.get()); - g_assert_cmpstr(currentLanguage, ==, "es_ES,en_US"); + // Try passing a list with only wrong languages. + webkit_web_context_set_spell_checking_languages(webContext, "bd_WR,wr_BD"); + currentLanguage = webkit_web_context_get_spell_checking_languages(webContext); + g_assert(!currentLanguage); // Check disabling and re-enabling spell checking. - webkit_web_context_set_spell_checking_enabled(webContext.get(), FALSE); - gboolean isSpellCheckingEnabled = webkit_web_context_get_spell_checking_enabled(webContext.get()); - g_assert(!isSpellCheckingEnabled); - webkit_web_context_set_spell_checking_enabled(webContext.get(), TRUE); - isSpellCheckingEnabled = webkit_web_context_get_spell_checking_enabled(webContext.get()); - g_assert(isSpellCheckingEnabled); + webkit_web_context_set_spell_checking_enabled(webContext, FALSE); + g_assert(!webkit_web_context_get_spell_checking_enabled(webContext)); + webkit_web_context_set_spell_checking_enabled(webContext, TRUE); + g_assert(webkit_web_context_get_spell_checking_enabled(webContext)); } void beforeAll() diff --git a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp index eec6fc786..22796bf73 100644 --- a/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/tests/TestWebKitWebView.cpp @@ -21,6 +21,7 @@ #include "WebViewTest.h" #include <JavaScriptCore/JSStringRef.h> #include <JavaScriptCore/JSValueRef.h> +#include <glib/gstdio.h> #include <wtf/HashSet.h> #include <wtf/gobject/GRefPtr.h> #include <wtf/text/StringHash.h> @@ -946,6 +947,102 @@ static void testWebViewSubmitForm(FormClientTest* test, gconstpointer) g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(values, "password")), ==, "secret"); } +class SaveWebViewTest: public WebViewTest { +public: + MAKE_GLIB_TEST_FIXTURE(SaveWebViewTest); + + SaveWebViewTest() + : m_tempDirectory(g_dir_make_tmp("WebKit2SaveViewTest-XXXXXX", 0)) + { + } + + ~SaveWebViewTest() + { + if (G_IS_FILE(m_file.get())) + g_file_delete(m_file.get(), 0, 0); + + if (G_IS_INPUT_STREAM(m_inputStream.get())) + g_input_stream_close(m_inputStream.get(), 0, 0); + + if (m_tempDirectory) + g_rmdir(m_tempDirectory.get()); + } + + static void webViewSavedToStreamCallback(GObject* object, GAsyncResult* result, SaveWebViewTest* test) + { + GOwnPtr<GError> error; + test->m_inputStream = adoptGRef(webkit_web_view_save_finish(test->m_webView, result, &error.outPtr())); + g_assert(G_IS_INPUT_STREAM(test->m_inputStream.get())); + g_assert(!error); + + test->quitMainLoop(); + } + + static void webViewSavedToFileCallback(GObject* object, GAsyncResult* result, SaveWebViewTest* test) + { + GOwnPtr<GError> error; + g_assert(webkit_web_view_save_to_file_finish(test->m_webView, result, &error.outPtr())); + g_assert(!error); + + test->quitMainLoop(); + } + + void saveAndWaitForStream() + { + webkit_web_view_save(m_webView, WEBKIT_SAVE_MODE_MHTML, 0, reinterpret_cast<GAsyncReadyCallback>(webViewSavedToStreamCallback), this); + g_main_loop_run(m_mainLoop); + } + + void saveAndWaitForFile() + { + m_saveDestinationFilePath.set(g_build_filename(m_tempDirectory.get(), "testWebViewSaveResult.mht", NULL)); + m_file = adoptGRef(g_file_new_for_path(m_saveDestinationFilePath.get())); + webkit_web_view_save_to_file(m_webView, m_file.get(), WEBKIT_SAVE_MODE_MHTML, 0, reinterpret_cast<GAsyncReadyCallback>(webViewSavedToFileCallback), this); + g_main_loop_run(m_mainLoop); + } + + GOwnPtr<char> m_tempDirectory; + GOwnPtr<char> m_saveDestinationFilePath; + GRefPtr<GInputStream> m_inputStream; + GRefPtr<GFile> m_file; +}; + +static void testWebViewSave(SaveWebViewTest* test, gconstpointer) +{ + test->loadHtml("<html>" + "<body>" + " <p>A paragraph with plain text</p>" + " <p>" + " A red box: <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMVwnSZnwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12P8z8DAwMDAxMDAwMDAAAANHQEDK+mmyAAAAABJRU5ErkJggg=='></br>" + " A blue box: <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMvBHhALQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12Nk4PnPwMDAxMDAwMDAAAALrwEPPIs1pgAAAABJRU5ErkJggg=='>" + " </p>" + "</body>" + "</html>", 0); + test->waitUntilLoadFinished(); + + // Write to a file and to an input stream. + test->saveAndWaitForFile(); + test->saveAndWaitForStream(); + + // We should have exactly the same amount of bytes in the file + // than those coming from the GInputStream. We don't compare the + // strings read since the 'Date' field and the boundaries will be + // different on each case. MHTML functionality will be tested by + // Layout tests, so checking the amount of bytes is enough. + GOwnPtr<GError> error; + gchar buffer[512] = { 0 }; + gssize readBytes = 0; + gssize totalBytesFromStream = 0; + while (readBytes = g_input_stream_read(test->m_inputStream.get(), &buffer, 512, 0, &error.outPtr())) { + g_assert(!error); + totalBytesFromStream += readBytes; + } + + // Check that the file exists and that it contains the same amount of bytes. + GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(test->m_file.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), 0, 0)); + g_assert_cmpint(g_file_info_get_size(fileInfo.get()), ==, totalBytesFromStream); +} + void beforeAll() { WebViewTest::add("WebKitWebView", "default-context", testWebViewDefaultContext); @@ -965,6 +1062,7 @@ void beforeAll() FullScreenClientTest::add("WebKitWebView", "fullscreen", testWebViewFullScreen); WebViewTest::add("WebKitWebView", "can-show-mime-type", testWebViewCanShowMIMEType); FormClientTest::add("WebKitWebView", "submit-form", testWebViewSubmitForm); + SaveWebViewTest::add("WebKitWebView", "save", testWebViewSave); } void afterAll() |