1/*
2 * Copyright (C) 2011 Igalia S.L.
3 * Portions Copyright (c) 2011 Motorola Mobility, Inc.  All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB.  If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "WebKitWebView.h"
23
24#include "APIData.h"
25#include "ImageOptions.h"
26#include "WebCertificateInfo.h"
27#include "WebContextMenuItem.h"
28#include "WebContextMenuItemData.h"
29#include "WebKitAuthenticationDialog.h"
30#include "WebKitAuthenticationRequestPrivate.h"
31#include "WebKitBackForwardListPrivate.h"
32#include "WebKitCertificateInfoPrivate.h"
33#include "WebKitContextMenuClient.h"
34#include "WebKitContextMenuItemPrivate.h"
35#include "WebKitContextMenuPrivate.h"
36#include "WebKitDownloadPrivate.h"
37#include "WebKitEnumTypes.h"
38#include "WebKitError.h"
39#include "WebKitFaviconDatabasePrivate.h"
40#include "WebKitFormClient.h"
41#include "WebKitFullscreenClient.h"
42#include "WebKitHitTestResultPrivate.h"
43#include "WebKitJavascriptResultPrivate.h"
44#include "WebKitLoaderClient.h"
45#include "WebKitMarshal.h"
46#include "WebKitPolicyClient.h"
47#include "WebKitPrintOperationPrivate.h"
48#include "WebKitPrivate.h"
49#include "WebKitResponsePolicyDecision.h"
50#include "WebKitScriptDialogPrivate.h"
51#include "WebKitUIClient.h"
52#include "WebKitURIRequestPrivate.h"
53#include "WebKitURIResponsePrivate.h"
54#include "WebKitWebContextPrivate.h"
55#include "WebKitWebInspectorPrivate.h"
56#include "WebKitWebResourcePrivate.h"
57#include "WebKitWebViewBasePrivate.h"
58#include "WebKitWebViewGroupPrivate.h"
59#include "WebKitWebViewPrivate.h"
60#include "WebKitWindowPropertiesPrivate.h"
61#include <JavaScriptCore/APICast.h>
62#include <WebCore/CertificateInfo.h>
63#include <WebCore/DragIcon.h>
64#include <WebCore/GUniquePtrGtk.h>
65#include <WebCore/GUniquePtrSoup.h>
66#include <WebCore/GtkUtilities.h>
67#include <WebCore/RefPtrCairo.h>
68#include <glib/gi18n-lib.h>
69#include <wtf/gobject/GRefPtr.h>
70#include <wtf/text/CString.h>
71
72using namespace WebKit;
73using namespace WebCore;
74
75/**
76 * SECTION: WebKitWebView
77 * @Short_description: The central class of the WebKit2GTK+ API
78 * @Title: WebKitWebView
79 *
80 * #WebKitWebView is the central class of the WebKit2GTK+ API. It is
81 * responsible for managing the drawing of the content and forwarding
82 * of events. You can load any URI into the #WebKitWebView or a data
83 * string. With #WebKitSettings you can control various aspects of the
84 * rendering and loading of the content.
85 *
86 * Note that #WebKitWebView is scrollable by itself, so you don't need
87 * to embed it in a #GtkScrolledWindow.
88 */
89
90enum {
91    LOAD_CHANGED,
92    LOAD_FAILED,
93    LOAD_FAILED_WITH_TLS_ERRORS,
94
95    CREATE,
96    READY_TO_SHOW,
97    RUN_AS_MODAL,
98    CLOSE,
99
100    SCRIPT_DIALOG,
101
102    DECIDE_POLICY,
103    PERMISSION_REQUEST,
104
105    MOUSE_TARGET_CHANGED,
106
107    PRINT,
108
109    RESOURCE_LOAD_STARTED,
110
111    ENTER_FULLSCREEN,
112    LEAVE_FULLSCREEN,
113
114    RUN_FILE_CHOOSER,
115
116    CONTEXT_MENU,
117    CONTEXT_MENU_DISMISSED,
118
119    SUBMIT_FORM,
120
121    INSECURE_CONTENT_DETECTED,
122
123    WEB_PROCESS_CRASHED,
124
125    AUTHENTICATE,
126
127    LAST_SIGNAL
128};
129
130enum {
131    PROP_0,
132
133    PROP_WEB_CONTEXT,
134    PROP_RELATED_VIEW,
135    PROP_GROUP,
136    PROP_USER_CONTENT_MANAGER,
137    PROP_TITLE,
138    PROP_ESTIMATED_LOAD_PROGRESS,
139    PROP_FAVICON,
140    PROP_URI,
141    PROP_ZOOM_LEVEL,
142    PROP_IS_LOADING
143};
144
145typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap;
146typedef HashMap<uint64_t, GRefPtr<GTask> > SnapshotResultsMap;
147
148struct _WebKitWebViewPrivate {
149    ~_WebKitWebViewPrivate()
150    {
151        if (javascriptGlobalContext)
152            JSGlobalContextRelease(javascriptGlobalContext);
153
154        // For modal dialogs, make sure the main loop is stopped when finalizing the webView.
155        if (modalLoop && g_main_loop_is_running(modalLoop.get()))
156            g_main_loop_quit(modalLoop.get());
157    }
158
159    WebKitWebContext* context;
160    WebKitWebView* relatedView;
161    CString title;
162    CString customTextEncoding;
163    double estimatedLoadProgress;
164    CString activeURI;
165    bool isLoading;
166
167    bool waitingForMainResource;
168    unsigned long mainResourceResponseHandlerID;
169    WebKitLoadEvent lastDelayedEvent;
170
171    GRefPtr<WebKitBackForwardList> backForwardList;
172    GRefPtr<WebKitSettings> settings;
173    unsigned long settingsChangedHandlerID;
174    GRefPtr<WebKitWebViewGroup> group;
175    GRefPtr<WebKitUserContentManager> userContentManager;
176    GRefPtr<WebKitWindowProperties> windowProperties;
177
178    GRefPtr<GMainLoop> modalLoop;
179
180    GRefPtr<WebKitHitTestResult> mouseTargetHitTestResult;
181    unsigned mouseTargetModifiers;
182
183    GRefPtr<WebKitFindController> findController;
184    JSGlobalContextRef javascriptGlobalContext;
185
186    GRefPtr<WebKitWebResource> mainResource;
187    LoadingResourcesMap loadingResourcesMap;
188
189    GRefPtr<WebKitWebInspector> inspector;
190
191    RefPtr<cairo_surface_t> favicon;
192    GRefPtr<GCancellable> faviconCancellable;
193    CString faviconURI;
194    unsigned long faviconChangedHandlerID;
195
196    SnapshotResultsMap snapshotResultsMap;
197    GRefPtr<WebKitAuthenticationRequest> authenticationRequest;
198};
199
200static guint signals[LAST_SIGNAL] = { 0, };
201
202WEBKIT_DEFINE_TYPE(WebKitWebView, webkit_web_view, WEBKIT_TYPE_WEB_VIEW_BASE)
203
204static inline WebPageProxy* getPage(WebKitWebView* webView)
205{
206    return webkitWebViewBaseGetPage(reinterpret_cast<WebKitWebViewBase*>(webView));
207}
208
209static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, const char* failingURI, GError* error)
210{
211    if (g_error_matches(error, WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED)
212        || g_error_matches(error, WEBKIT_POLICY_ERROR, WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE)
213        || g_error_matches(error, WEBKIT_PLUGIN_ERROR, WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD))
214        return FALSE;
215
216    GUniquePtr<char> htmlString(g_strdup_printf("<html><body>%s</body></html>", error->message));
217    webkit_web_view_load_alternate_html(webView, htmlString.get(), failingURI, 0);
218
219    return TRUE;
220}
221
222static GtkWidget* webkitWebViewCreate(WebKitWebView*, WebKitNavigationAction*)
223{
224    return nullptr;
225}
226
227static GtkWidget* webkitWebViewCreateJavaScriptDialog(WebKitWebView* webView, GtkMessageType type, GtkButtonsType buttons, int defaultResponse, const char* message)
228{
229    GtkWidget* parent = gtk_widget_get_toplevel(GTK_WIDGET(webView));
230    GtkWidget* dialog = gtk_message_dialog_new(widgetIsOnscreenToplevelWindow(parent) ? GTK_WINDOW(parent) : 0,
231                                               GTK_DIALOG_DESTROY_WITH_PARENT, type, buttons, "%s", message);
232    GUniquePtr<char> title(g_strdup_printf("JavaScript - %s", webkit_web_view_get_uri(webView)));
233    gtk_window_set_title(GTK_WINDOW(dialog), title.get());
234    gtk_dialog_set_default_response(GTK_DIALOG(dialog), defaultResponse);
235
236    return dialog;
237}
238
239static gboolean webkitWebViewScriptDialog(WebKitWebView* webView, WebKitScriptDialog* scriptDialog)
240{
241    GtkWidget* dialog = 0;
242
243    switch (scriptDialog->type) {
244    case WEBKIT_SCRIPT_DIALOG_ALERT:
245        dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, GTK_RESPONSE_CLOSE, scriptDialog->message.data());
246        gtk_dialog_run(GTK_DIALOG(dialog));
247        break;
248    case WEBKIT_SCRIPT_DIALOG_CONFIRM:
249        dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data());
250        scriptDialog->confirmed = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK;
251        break;
252    case WEBKIT_SCRIPT_DIALOG_PROMPT:
253        dialog = webkitWebViewCreateJavaScriptDialog(webView, GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK_CANCEL, GTK_RESPONSE_OK, scriptDialog->message.data());
254        GtkWidget* entry = gtk_entry_new();
255        gtk_entry_set_text(GTK_ENTRY(entry), scriptDialog->defaultText.data());
256        gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry);
257        gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
258        gtk_widget_show(entry);
259        if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
260            scriptDialog->text = gtk_entry_get_text(GTK_ENTRY(entry));
261        break;
262    }
263
264    gtk_widget_destroy(dialog);
265
266    return TRUE;
267}
268
269static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* decision, WebKitPolicyDecisionType decisionType)
270{
271    if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) {
272        webkit_policy_decision_use(decision);
273        return TRUE;
274    }
275
276    WebKitURIResponse* response = webkit_response_policy_decision_get_response(WEBKIT_RESPONSE_POLICY_DECISION(decision));
277    const ResourceResponse& resourceResponse = webkitURIResponseGetResourceResponse(response);
278    if (resourceResponse.isAttachment()) {
279        webkit_policy_decision_download(decision);
280        return TRUE;
281    }
282
283    if (webkit_response_policy_decision_is_mime_type_supported(WEBKIT_RESPONSE_POLICY_DECISION(decision)))
284        webkit_policy_decision_use(decision);
285    else
286        webkit_policy_decision_ignore(decision);
287
288    return TRUE;
289}
290
291static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request)
292{
293    webkit_permission_request_deny(request);
294    return TRUE;
295}
296
297static void allowModalDialogsChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
298{
299    WebPageProxy* page = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
300    if (!page)
301        return;
302    getPage(webView)->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
303}
304
305static void zoomTextOnlyChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
306{
307    WebPageProxy* page = getPage(webView);
308    gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(settings);
309    gdouble pageZoomLevel = zoomTextOnly ? 1 : page->textZoomFactor();
310    gdouble textZoomLevel = zoomTextOnly ? page->pageZoomFactor() : 1;
311    page->setPageAndTextZoomFactors(pageZoomLevel, textZoomLevel);
312}
313
314static void userAgentChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
315{
316    getPage(webView)->setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings)));
317}
318
319static void webkitWebViewUpdateFavicon(WebKitWebView* webView, cairo_surface_t* favicon)
320{
321    WebKitWebViewPrivate* priv = webView->priv;
322    if (priv->favicon.get() == favicon)
323        return;
324
325    priv->favicon = favicon;
326    g_object_notify(G_OBJECT(webView), "favicon");
327}
328
329static void webkitWebViewCancelFaviconRequest(WebKitWebView* webView)
330{
331    if (!webView->priv->faviconCancellable)
332        return;
333
334    g_cancellable_cancel(webView->priv->faviconCancellable.get());
335    webView->priv->faviconCancellable = 0;
336}
337
338static void gotFaviconCallback(GObject* object, GAsyncResult* result, gpointer userData)
339{
340    GUniqueOutPtr<GError> error;
341    RefPtr<cairo_surface_t> favicon = adoptRef(webkit_favicon_database_get_favicon_finish(WEBKIT_FAVICON_DATABASE(object), result, &error.outPtr()));
342    if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
343        return;
344
345    WebKitWebView* webView = WEBKIT_WEB_VIEW(userData);
346    webkitWebViewUpdateFavicon(webView, favicon.get());
347    webView->priv->faviconCancellable = 0;
348}
349
350static void webkitWebViewRequestFavicon(WebKitWebView* webView)
351{
352    webkitWebViewCancelFaviconRequest(webView);
353
354    WebKitWebViewPrivate* priv = webView->priv;
355    priv->faviconCancellable = adoptGRef(g_cancellable_new());
356    WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context);
357    webkit_favicon_database_get_favicon(database, priv->activeURI.data(), priv->faviconCancellable.get(), gotFaviconCallback, webView);
358}
359
360static void webkitWebViewUpdateFaviconURI(WebKitWebView* webView, const char* faviconURI)
361{
362    if (webView->priv->faviconURI == faviconURI)
363        return;
364
365    webView->priv->faviconURI = faviconURI;
366    webkitWebViewRequestFavicon(webView);
367}
368
369static void faviconChangedCallback(WebKitFaviconDatabase*, const char* pageURI, const char* faviconURI, WebKitWebView* webView)
370{
371    if (webView->priv->activeURI != pageURI)
372        return;
373
374    webkitWebViewUpdateFaviconURI(webView, faviconURI);
375}
376
377static void webkitWebViewUpdateSettings(WebKitWebView* webView)
378{
379    // We keep a ref of the current settings to disconnect the signals when settings change in the group.
380    webView->priv->settings = webkit_web_view_get_settings(webView);
381
382    WebKitSettings* settings = webView->priv->settings.get();
383    WebPageProxy* page = getPage(webView);
384    page->setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
385    page->setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings)));
386
387    webkitWebViewBaseUpdatePreferences(WEBKIT_WEB_VIEW_BASE(webView));
388
389    g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView);
390    g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView);
391    g_signal_connect(settings, "notify::user-agent", G_CALLBACK(userAgentChanged), webView);
392}
393
394static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView)
395{
396    WebKitSettings* settings = webView->priv->settings.get();
397    g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowModalDialogsChanged), webView);
398    g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView);
399    g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(userAgentChanged), webView);
400}
401
402static void webkitWebViewSettingsChanged(WebKitWebViewGroup*, GParamSpec*, WebKitWebView* webView)
403{
404    webkitWebViewDisconnectSettingsSignalHandlers(webView);
405    webkitWebViewUpdateSettings(webView);
406}
407
408static void webkitWebViewDisconnectSettingsChangedSignalHandler(WebKitWebView* webView)
409{
410    WebKitWebViewPrivate* priv = webView->priv;
411    if (priv->settingsChangedHandlerID)
412        g_signal_handler_disconnect(webkit_web_view_get_group(webView), priv->settingsChangedHandlerID);
413    priv->settingsChangedHandlerID = 0;
414}
415
416static void webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(WebKitWebView* webView)
417{
418    WebKitWebViewPrivate* priv = webView->priv;
419    if (priv->mainResourceResponseHandlerID)
420        g_signal_handler_disconnect(priv->mainResource.get(), priv->mainResourceResponseHandlerID);
421    priv->mainResourceResponseHandlerID = 0;
422}
423
424static void webkitWebViewWatchForChangesInFavicon(WebKitWebView* webView)
425{
426    WebKitWebViewPrivate* priv = webView->priv;
427    if (priv->faviconChangedHandlerID)
428        return;
429
430    WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context);
431    priv->faviconChangedHandlerID = g_signal_connect(database, "favicon-changed", G_CALLBACK(faviconChangedCallback), webView);
432}
433
434static void webkitWebViewDisconnectFaviconDatabaseSignalHandlers(WebKitWebView* webView)
435{
436    WebKitWebViewPrivate* priv = webView->priv;
437    if (priv->faviconChangedHandlerID)
438        g_signal_handler_disconnect(webkit_web_context_get_favicon_database(priv->context), priv->faviconChangedHandlerID);
439    priv->faviconChangedHandlerID = 0;
440}
441
442static gboolean webkitWebViewAuthenticate(WebKitWebView* webView, WebKitAuthenticationRequest* request)
443{
444    CredentialStorageMode credentialStorageMode = webkit_authentication_request_can_save_credentials(request) ? AllowPersistentStorage : DisallowPersistentStorage;
445    webkitWebViewBaseAddAuthenticationDialog(WEBKIT_WEB_VIEW_BASE(webView), webkitAuthenticationDialogNew(request, credentialStorageMode));
446
447    return TRUE;
448}
449
450static void fileChooserDialogResponseCallback(GtkDialog* dialog, gint responseID, WebKitFileChooserRequest* request)
451{
452    GRefPtr<WebKitFileChooserRequest> adoptedRequest = adoptGRef(request);
453    if (responseID == GTK_RESPONSE_ACCEPT) {
454        GUniquePtr<GSList> filesList(gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)));
455        GRefPtr<GPtrArray> filesArray = adoptGRef(g_ptr_array_new());
456        for (GSList* file = filesList.get(); file; file = g_slist_next(file))
457            g_ptr_array_add(filesArray.get(), file->data);
458        g_ptr_array_add(filesArray.get(), 0);
459        webkit_file_chooser_request_select_files(adoptedRequest.get(), reinterpret_cast<const gchar* const*>(filesArray->pdata));
460    } else
461        webkit_file_chooser_request_cancel(adoptedRequest.get());
462
463    gtk_widget_destroy(GTK_WIDGET(dialog));
464}
465
466static gboolean webkitWebViewRunFileChooser(WebKitWebView* webView, WebKitFileChooserRequest* request)
467{
468    GtkWidget* toplevel = gtk_widget_get_toplevel(GTK_WIDGET(webView));
469    if (!widgetIsOnscreenToplevelWindow(toplevel))
470        toplevel = 0;
471
472    gboolean allowsMultipleSelection = webkit_file_chooser_request_get_select_multiple(request);
473    GtkWidget* dialog = gtk_file_chooser_dialog_new(allowsMultipleSelection ? _("Select Files") : _("Select File"),
474                                                    toplevel ? GTK_WINDOW(toplevel) : 0,
475                                                    GTK_FILE_CHOOSER_ACTION_OPEN,
476                                                    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
477                                                    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
478                                                    NULL);
479
480    if (GtkFileFilter* filter = webkit_file_chooser_request_get_mime_types_filter(request))
481        gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
482    gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), allowsMultipleSelection);
483
484    if (const gchar* const* selectedFiles = webkit_file_chooser_request_get_selected_files(request))
485        gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), selectedFiles[0]);
486
487    g_signal_connect(dialog, "response", G_CALLBACK(fileChooserDialogResponseCallback), g_object_ref(request));
488    gtk_widget_show(dialog);
489
490    return TRUE;
491}
492
493static void webkitWebViewHandleDownloadRequest(WebKitWebViewBase* webViewBase, DownloadProxy* downloadProxy)
494{
495    GRefPtr<WebKitDownload> download = webkitWebContextGetOrCreateDownload(downloadProxy);
496    webkitDownloadSetWebView(download.get(), WEBKIT_WEB_VIEW(webViewBase));
497}
498
499static void webkitWebViewConstructed(GObject* object)
500{
501    if (G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed)
502        G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed(object);
503
504    WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
505    WebKitWebViewPrivate* priv = webView->priv;
506    webkitWebContextCreatePageForWebView(priv->context, webView, priv->group.get(), priv->userContentManager.get(), priv->relatedView);
507    // The related view is only valid during the construction.
508    priv->relatedView = nullptr;
509
510    webkitWebViewBaseSetDownloadRequestHandler(WEBKIT_WEB_VIEW_BASE(webView), webkitWebViewHandleDownloadRequest);
511
512    attachLoaderClientToView(webView);
513    attachUIClientToView(webView);
514    attachPolicyClientToView(webView);
515    attachFullScreenClientToView(webView);
516    attachContextMenuClientToView(webView);
517    attachFormClientToView(webView);
518
519    priv->backForwardList = adoptGRef(webkitBackForwardListCreate(&getPage(webView)->backForwardList()));
520    priv->windowProperties = adoptGRef(webkitWindowPropertiesCreate());
521
522    webkitWebViewUpdateSettings(webView);
523    priv->settingsChangedHandlerID =
524        g_signal_connect(webkit_web_view_get_group(webView), "notify::settings", G_CALLBACK(webkitWebViewSettingsChanged), webView);
525}
526
527static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
528{
529    WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
530
531    switch (propId) {
532    case PROP_WEB_CONTEXT: {
533        gpointer webContext = g_value_get_object(value);
534        webView->priv->context = webContext ? WEBKIT_WEB_CONTEXT(webContext) : webkit_web_context_get_default();
535        break;
536    }
537    case PROP_RELATED_VIEW: {
538        gpointer relatedView = g_value_get_object(value);
539        webView->priv->relatedView = relatedView ? WEBKIT_WEB_VIEW(relatedView) : nullptr;
540        break;
541    }
542    case PROP_GROUP: {
543        gpointer group = g_value_get_object(value);
544        webView->priv->group = group ? WEBKIT_WEB_VIEW_GROUP(group) : 0;
545        break;
546    }
547    case PROP_USER_CONTENT_MANAGER: {
548        gpointer userContentManager = g_value_get_object(value);
549        webView->priv->userContentManager = userContentManager ? WEBKIT_USER_CONTENT_MANAGER(userContentManager) : nullptr;
550        break;
551    }
552    case PROP_ZOOM_LEVEL:
553        webkit_web_view_set_zoom_level(webView, g_value_get_double(value));
554        break;
555    default:
556        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
557    }
558}
559
560static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
561{
562    WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
563
564    switch (propId) {
565    case PROP_WEB_CONTEXT:
566        g_value_set_object(value, webView->priv->context);
567        break;
568    case PROP_GROUP:
569        g_value_set_object(value, webkit_web_view_get_group(webView));
570        break;
571    case PROP_USER_CONTENT_MANAGER:
572        g_value_set_object(value, webkit_web_view_get_user_content_manager(webView));
573        break;
574    case PROP_TITLE:
575        g_value_set_string(value, webView->priv->title.data());
576        break;
577    case PROP_ESTIMATED_LOAD_PROGRESS:
578        g_value_set_double(value, webkit_web_view_get_estimated_load_progress(webView));
579        break;
580    case PROP_FAVICON:
581        g_value_set_pointer(value, webkit_web_view_get_favicon(webView));
582        break;
583    case PROP_URI:
584        g_value_set_string(value, webkit_web_view_get_uri(webView));
585        break;
586    case PROP_ZOOM_LEVEL:
587        g_value_set_double(value, webkit_web_view_get_zoom_level(webView));
588        break;
589    case PROP_IS_LOADING:
590        g_value_set_boolean(value, webkit_web_view_is_loading(webView));
591        break;
592    default:
593        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
594    }
595}
596
597static void webkitWebViewDispose(GObject* object)
598{
599    WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
600    webkitWebViewCancelFaviconRequest(webView);
601    webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
602    webkitWebViewDisconnectSettingsChangedSignalHandler(webView);
603    webkitWebViewDisconnectSettingsSignalHandlers(webView);
604    webkitWebViewDisconnectFaviconDatabaseSignalHandlers(webView);
605
606    webkitWebContextWebViewDestroyed(webView->priv->context, webView);
607
608    G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object);
609}
610
611static gboolean webkitWebViewAccumulatorObjectHandled(GSignalInvocationHint*, GValue* returnValue, const GValue* handlerReturn, gpointer)
612{
613    void* object = g_value_get_object(handlerReturn);
614    if (object)
615        g_value_set_object(returnValue, object);
616
617    return !object;
618}
619
620static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
621{
622    GObjectClass* gObjectClass = G_OBJECT_CLASS(webViewClass);
623
624    gObjectClass->constructed = webkitWebViewConstructed;
625    gObjectClass->set_property = webkitWebViewSetProperty;
626    gObjectClass->get_property = webkitWebViewGetProperty;
627    gObjectClass->dispose = webkitWebViewDispose;
628
629    webViewClass->load_failed = webkitWebViewLoadFail;
630    webViewClass->create = webkitWebViewCreate;
631    webViewClass->script_dialog = webkitWebViewScriptDialog;
632    webViewClass->decide_policy = webkitWebViewDecidePolicy;
633    webViewClass->permission_request = webkitWebViewPermissionRequest;
634    webViewClass->run_file_chooser = webkitWebViewRunFileChooser;
635    webViewClass->authenticate = webkitWebViewAuthenticate;
636
637    /**
638     * WebKitWebView:web-context:
639     *
640     * The #WebKitWebContext of the view.
641     */
642    g_object_class_install_property(gObjectClass,
643                                    PROP_WEB_CONTEXT,
644                                    g_param_spec_object("web-context",
645                                                        _("Web Context"),
646                                                        _("The web context for the view"),
647                                                        WEBKIT_TYPE_WEB_CONTEXT,
648                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
649    /**
650     * WebKitWebView:related-view:
651     *
652     * The related #WebKitWebView used when creating the view to share the
653     * same web process. This property is not readable because the related
654     * web view is only valid during the object construction.
655     *
656     * Since: 2.4
657     */
658    g_object_class_install_property(
659        gObjectClass,
660        PROP_RELATED_VIEW,
661        g_param_spec_object(
662            "related-view",
663            _("Related WebView"),
664            _("The related WebKitWebView used when creating the view to share the same web process"),
665            WEBKIT_TYPE_WEB_VIEW,
666            static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
667
668    /**
669     * WebKitWebView:group:
670     *
671     * The #WebKitWebViewGroup of the view.
672     */
673    g_object_class_install_property(
674        gObjectClass,
675        PROP_GROUP,
676        g_param_spec_object(
677            "group",
678            _("WebView Group"),
679            _("The WebKitWebViewGroup of the view"),
680            WEBKIT_TYPE_WEB_VIEW_GROUP,
681            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
682
683    /**
684     * WebKitWebView:user-content-manager:
685     *
686     * The #WebKitUserContentManager of the view.
687     *
688     * Since: 2.6
689     */
690    g_object_class_install_property(
691        gObjectClass,
692        PROP_USER_CONTENT_MANAGER,
693        g_param_spec_object(
694            "user-content-manager",
695            _("WebView user content manager"),
696            _("The WebKitUserContentManager of the view"),
697            WEBKIT_TYPE_USER_CONTENT_MANAGER,
698            static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
699
700    /**
701     * WebKitWebView:title:
702     *
703     * The main frame document title of this #WebKitWebView. If
704     * the title has not been received yet, it will be %NULL.
705     */
706    g_object_class_install_property(gObjectClass,
707                                    PROP_TITLE,
708                                    g_param_spec_string("title",
709                                                        _("Title"),
710                                                        _("Main frame document title"),
711                                                        0,
712                                                        WEBKIT_PARAM_READABLE));
713
714    /**
715     * WebKitWebView:estimated-load-progress:
716     *
717     * An estimate of the percent completion for the current loading operation.
718     * This value will range from 0.0 to 1.0 and, once a load completes,
719     * will remain at 1.0 until a new load starts, at which point it
720     * will be reset to 0.0.
721     * The value is an estimate based on the total number of bytes expected
722     * to be received for a document, including all its possible subresources
723     * and child documents.
724     */
725    g_object_class_install_property(gObjectClass,
726                                    PROP_ESTIMATED_LOAD_PROGRESS,
727                                    g_param_spec_double("estimated-load-progress",
728                                                        _("Estimated Load Progress"),
729                                                        _("An estimate of the percent completion for a document load"),
730                                                        0.0, 1.0, 0.0,
731                                                        WEBKIT_PARAM_READABLE));
732    /**
733     * WebKitWebView:favicon:
734     *
735     * The favicon currently associated to the #WebKitWebView.
736     * See webkit_web_view_get_favicon() for more details.
737     */
738    g_object_class_install_property(gObjectClass,
739                                    PROP_FAVICON,
740                                    g_param_spec_pointer("favicon",
741                                                         _("Favicon"),
742                                                         _("The favicon associated to the view, if any"),
743                                                         WEBKIT_PARAM_READABLE));
744    /**
745     * WebKitWebView:uri:
746     *
747     * The current active URI of the #WebKitWebView.
748     * See webkit_web_view_get_uri() for more details.
749     */
750    g_object_class_install_property(gObjectClass,
751                                    PROP_URI,
752                                    g_param_spec_string("uri",
753                                                        _("URI"),
754                                                        _("The current active URI of the view"),
755                                                        0,
756                                                        WEBKIT_PARAM_READABLE));
757
758    /**
759     * WebKitWebView:zoom-level:
760     *
761     * The zoom level of the #WebKitWebView content.
762     * See webkit_web_view_set_zoom_level() for more details.
763     */
764    g_object_class_install_property(gObjectClass,
765                                    PROP_ZOOM_LEVEL,
766                                    g_param_spec_double("zoom-level",
767                                                        "Zoom level",
768                                                        _("The zoom level of the view content"),
769                                                        0, G_MAXDOUBLE, 1,
770                                                        WEBKIT_PARAM_READWRITE));
771
772    /**
773     * WebKitWebView:is-loading:
774     *
775     * Whether the #WebKitWebView is currently loading a page. This property becomes
776     * %TRUE as soon as a new load operation is requested and before the
777     * #WebKitWebView::load-changed signal is emitted with %WEBKIT_LOAD_STARTED and
778     * at that point the active URI is the requested one.
779     * When the load operation finishes the property is set to %FALSE before
780     * #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_FINISHED.
781     */
782    g_object_class_install_property(gObjectClass,
783                                    PROP_IS_LOADING,
784                                    g_param_spec_boolean("is-loading",
785                                                         "Is Loading",
786                                                         _("Whether the view is loading a page"),
787                                                         FALSE,
788                                                         WEBKIT_PARAM_READABLE));
789
790    /**
791     * WebKitWebView::load-changed:
792     * @web_view: the #WebKitWebView on which the signal is emitted
793     * @load_event: the #WebKitLoadEvent
794     *
795     * Emitted when the a load operation in @web_view changes.
796     * The signal is always emitted with %WEBKIT_LOAD_STARTED when a
797     * new load request is made and %WEBKIT_LOAD_FINISHED when the load
798     * finishes successfully or due to an error. When the ongoing load
799     * operation fails #WebKitWebView::load-failed signal is emitted
800     * before #WebKitWebView::load-changed is emitted with
801     * %WEBKIT_LOAD_FINISHED.
802     * If a redirection is received from the server, this signal is emitted
803     * with %WEBKIT_LOAD_REDIRECTED after the initial emission with
804     * %WEBKIT_LOAD_STARTED and before %WEBKIT_LOAD_COMMITTED.
805     * When the page content starts arriving the signal is emitted with
806     * %WEBKIT_LOAD_COMMITTED event.
807     *
808     * You can handle this signal and use a switch to track any ongoing
809     * load operation.
810     *
811     * <informalexample><programlisting>
812     * static void web_view_load_changed (WebKitWebView  *web_view,
813     *                                    WebKitLoadEvent load_event,
814     *                                    gpointer        user_data)
815     * {
816     *     switch (load_event) {
817     *     case WEBKIT_LOAD_STARTED:
818     *         /<!-- -->* New load, we have now a provisional URI *<!-- -->/
819     *         provisional_uri = webkit_web_view_get_uri (web_view);
820     *         /<!-- -->* Here we could start a spinner or update the
821     *          <!-- -->* location bar with the provisional URI *<!-- -->/
822     *         break;
823     *     case WEBKIT_LOAD_REDIRECTED:
824     *         redirected_uri = webkit_web_view_get_uri (web_view);
825     *         break;
826     *     case WEBKIT_LOAD_COMMITTED:
827     *         /<!-- -->* The load is being performed. Current URI is
828     *          <!-- -->* the final one and it won't change unless a new
829     *          <!-- -->* load is requested or a navigation within the
830     *          <!-- -->* same page is performed *<!-- -->/
831     *         uri = webkit_web_view_get_uri (web_view);
832     *         break;
833     *     case WEBKIT_LOAD_FINISHED:
834     *         /<!-- -->* Load finished, we can now stop the spinner *<!-- -->/
835     *         break;
836     *     }
837     * }
838     * </programlisting></informalexample>
839     */
840    signals[LOAD_CHANGED] =
841        g_signal_new("load-changed",
842                     G_TYPE_FROM_CLASS(webViewClass),
843                     G_SIGNAL_RUN_LAST,
844                     G_STRUCT_OFFSET(WebKitWebViewClass, load_changed),
845                     0, 0,
846                     g_cclosure_marshal_VOID__ENUM,
847                     G_TYPE_NONE, 1,
848                     WEBKIT_TYPE_LOAD_EVENT);
849
850    /**
851     * WebKitWebView::load-failed:
852     * @web_view: the #WebKitWebView on which the signal is emitted
853     * @load_event: the #WebKitLoadEvent of the load operation
854     * @failing_uri: the URI that failed to load
855     * @error: the #GError that was triggered
856     *
857     * Emitted when an error occurs during a load operation.
858     * If the error happened when starting to load data for a page
859     * @load_event will be %WEBKIT_LOAD_STARTED. If it happened while
860     * loading a committed data source @load_event will be %WEBKIT_LOAD_COMMITTED.
861     * Since a load error causes the load operation to finish, the signal
862     * WebKitWebView::load-changed will always be emitted with
863     * %WEBKIT_LOAD_FINISHED event right after this one.
864     *
865     * By default, if the signal is not handled, a stock error page will be displayed.
866     * You need to handle the signal if you want to provide your own error page.
867     *
868     * Returns: %TRUE to stop other handlers from being invoked for the event.
869     *    %FALSE to propagate the event further.
870     */
871    signals[LOAD_FAILED] =
872        g_signal_new("load-failed",
873                     G_TYPE_FROM_CLASS(webViewClass),
874                     G_SIGNAL_RUN_LAST,
875                     G_STRUCT_OFFSET(WebKitWebViewClass, load_failed),
876                     g_signal_accumulator_true_handled, 0,
877                     webkit_marshal_BOOLEAN__ENUM_STRING_POINTER,
878                     G_TYPE_BOOLEAN, 3,
879                     WEBKIT_TYPE_LOAD_EVENT,
880                     G_TYPE_STRING,
881                     G_TYPE_POINTER);
882
883    /**
884     * WebKitWebView::load-failed-with-tls-errors:
885     * @web_view: the #WebKitWebView on which the signal is emitted
886     * @info: a #WebKitCertificateInfo
887     * @host: the host on which the error occurred
888     *
889     * Emitted when a TLS error occurs during a load operation. The @info
890     * object contains information about the error such as the #GTlsCertificate
891     * and the #GTlsCertificateFlags. To allow an exception for this certificate
892     * and this host use webkit_web_context_allow_tls_certificate_for_host().
893     *
894     * To handle this signal asynchronously you should copy the #WebKitCertificateInfo
895     * with webkit_certificate_info_copy() and return %TRUE.
896     *
897     * If %FALSE is returned, #WebKitWebView::load-failed will be emitted. The load
898     * will finish regardless of the returned value.
899     *
900     * Returns: %TRUE to stop other handlers from being invoked for the event.
901     *   %FALSE to propagate the event further.
902     *
903     * Since: 2.4
904     */
905    signals[LOAD_FAILED_WITH_TLS_ERRORS] =
906        g_signal_new("load-failed-with-tls-errors",
907            G_TYPE_FROM_CLASS(webViewClass),
908            G_SIGNAL_RUN_LAST,
909            G_STRUCT_OFFSET(WebKitWebViewClass, load_failed_with_tls_errors),
910            g_signal_accumulator_true_handled, 0 /* accumulator data */,
911            webkit_marshal_BOOLEAN__BOXED_STRING,
912            G_TYPE_BOOLEAN, 2, /* number of parameters */
913            WEBKIT_TYPE_CERTIFICATE_INFO  | G_SIGNAL_TYPE_STATIC_SCOPE,
914            G_TYPE_STRING);
915
916    /**
917     * WebKitWebView::create:
918     * @web_view: the #WebKitWebView on which the signal is emitted
919     * @navigation_action: a #WebKitNavigationAction
920     *
921     * Emitted when the creation of a new #WebKitWebView is requested.
922     * If this signal is handled the signal handler should return the
923     * newly created #WebKitWebView.
924     *
925     * The #WebKitNavigationAction parameter contains information about the
926     * navigation action that triggered this signal.
927     *
928     * When using %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES
929     * process model, the new #WebKitWebView should be related to
930     * @web_view to share the same web process, see webkit_web_view_new_with_related_view()
931     * for more details.
932     *
933     * The new #WebKitWebView should not be displayed to the user
934     * until the #WebKitWebView::ready-to-show signal is emitted.
935     *
936     * Returns: (transfer full): a newly allocated #WebKitWebView widget
937     *    or %NULL to propagate the event further.
938     */
939    signals[CREATE] = g_signal_new(
940        "create",
941        G_TYPE_FROM_CLASS(webViewClass),
942        G_SIGNAL_RUN_LAST,
943        G_STRUCT_OFFSET(WebKitWebViewClass, create),
944        webkitWebViewAccumulatorObjectHandled, 0,
945        g_cclosure_marshal_generic,
946        GTK_TYPE_WIDGET, 1,
947        WEBKIT_TYPE_NAVIGATION_ACTION | G_SIGNAL_TYPE_STATIC_SCOPE);
948
949    /**
950     * WebKitWebView::ready-to-show:
951     * @web_view: the #WebKitWebView on which the signal is emitted
952     *
953     * Emitted after #WebKitWebView::create on the newly created #WebKitWebView
954     * when it should be displayed to the user. When this signal is emitted
955     * all the information about how the window should look, including
956     * size, position, whether the location, status and scrollbars
957     * should be displayed, is already set on the #WebKitWindowProperties
958     * of @web_view. See also webkit_web_view_get_window_properties().
959     */
960    signals[READY_TO_SHOW] =
961        g_signal_new("ready-to-show",
962                     G_TYPE_FROM_CLASS(webViewClass),
963                     G_SIGNAL_RUN_LAST,
964                     G_STRUCT_OFFSET(WebKitWebViewClass, ready_to_show),
965                     0, 0,
966                     g_cclosure_marshal_VOID__VOID,
967                     G_TYPE_NONE, 0);
968
969     /**
970     * WebKitWebView::run-as-modal:
971     * @web_view: the #WebKitWebView on which the signal is emitted
972     *
973     * Emitted after #WebKitWebView::ready-to-show on the newly
974     * created #WebKitWebView when JavaScript code calls
975     * <function>window.showModalDialog</function>. The purpose of
976     * this signal is to allow the client application to prepare the
977     * new view to behave as modal. Once the signal is emitted a new
978     * mainloop will be run to block user interaction in the parent
979     * #WebKitWebView until the new dialog is closed.
980     */
981    signals[RUN_AS_MODAL] =
982            g_signal_new("run-as-modal",
983                         G_TYPE_FROM_CLASS(webViewClass),
984                         G_SIGNAL_RUN_LAST,
985                         G_STRUCT_OFFSET(WebKitWebViewClass, run_as_modal),
986                         0, 0,
987                         g_cclosure_marshal_VOID__VOID,
988                         G_TYPE_NONE, 0);
989
990    /**
991     * WebKitWebView::close:
992     * @webView: the #WebKitWebView on which the signal is emitted
993     *
994     * Emitted when closing a #WebKitWebView is requested. This occurs when a
995     * call is made from JavaScript's <function>window.close</function> function.
996     * It is the owner's responsibility to handle this signal to hide or
997     * destroy the #WebKitWebView, if necessary.
998     */
999    signals[CLOSE] =
1000        g_signal_new("close",
1001                     G_TYPE_FROM_CLASS(webViewClass),
1002                     G_SIGNAL_RUN_LAST,
1003                     G_STRUCT_OFFSET(WebKitWebViewClass, close),
1004                     0, 0,
1005                     g_cclosure_marshal_VOID__VOID,
1006                     G_TYPE_NONE, 0);
1007
1008    /**
1009     * WebKitWebView::script-dialog:
1010     * @web_view: the #WebKitWebView on which the signal is emitted
1011     * @dialog: the #WebKitScriptDialog to show
1012     *
1013     * Emitted when JavaScript code calls <function>window.alert</function>,
1014     * <function>window.confirm</function> or <function>window.prompt</function>.
1015     * The @dialog parameter should be used to build the dialog.
1016     * If the signal is not handled a different dialog will be built and shown depending
1017     * on the dialog type:
1018     * <itemizedlist>
1019     * <listitem><para>
1020     *  %WEBKIT_SCRIPT_DIALOG_ALERT: message dialog with a single Close button.
1021     * </para></listitem>
1022     * <listitem><para>
1023     *  %WEBKIT_SCRIPT_DIALOG_CONFIRM: message dialog with OK and Cancel buttons.
1024     * </para></listitem>
1025     * <listitem><para>
1026     *  %WEBKIT_SCRIPT_DIALOG_PROMPT: message dialog with OK and Cancel buttons and
1027     *  a text entry with the default text.
1028     * </para></listitem>
1029     * </itemizedlist>
1030     *
1031     * Returns: %TRUE to stop other handlers from being invoked for the event.
1032     *    %FALSE to propagate the event further.
1033     */
1034    signals[SCRIPT_DIALOG] =
1035        g_signal_new("script-dialog",
1036                     G_TYPE_FROM_CLASS(webViewClass),
1037                     G_SIGNAL_RUN_LAST,
1038                     G_STRUCT_OFFSET(WebKitWebViewClass, script_dialog),
1039                     g_signal_accumulator_true_handled, 0,
1040                     webkit_marshal_BOOLEAN__BOXED,
1041                     G_TYPE_BOOLEAN, 1,
1042                     WEBKIT_TYPE_SCRIPT_DIALOG | G_SIGNAL_TYPE_STATIC_SCOPE);
1043
1044    /**
1045     * WebKitWebView::decide-policy:
1046     * @web_view: the #WebKitWebView on which the signal is emitted
1047     * @decision: the #WebKitPolicyDecision
1048     * @decision_type: a #WebKitPolicyDecisionType denoting the type of @decision
1049     *
1050     * This signal is emitted when WebKit is requesting the client to decide a policy
1051     * decision, such as whether to navigate to a page, open a new window or whether or
1052     * not to download a resource. The #WebKitNavigationPolicyDecision passed in the
1053     * @decision argument is a generic type, but should be casted to a more
1054     * specific type when making the decision. For example:
1055     *
1056     * <informalexample><programlisting>
1057     * static gboolean
1058     * decide_policy_cb (WebKitWebView *web_view,
1059     *                   WebKitPolicyDecision *decision,
1060     *                   WebKitPolicyDecisionType type)
1061     * {
1062     *     switch (type) {
1063     *     case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
1064     *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1065     *         /<!-- -->* Make a policy decision here. *<!-- -->/
1066     *         break;
1067     *     case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
1068     *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1069     *         /<!-- -->* Make a policy decision here. *<!-- -->/
1070     *         break;
1071     *     case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
1072     *         WebKitResponsePolicyDecision *response = WEBKIT_RESPONSE_POLICY_DECISION (decision);
1073     *         /<!-- -->* Make a policy decision here. *<!-- -->/
1074     *         break;
1075     *     default:
1076     *         /<!-- -->* Making no decision results in webkit_policy_decision_use(). *<!-- -->/
1077     *         return FALSE;
1078     *     }
1079     *     return TRUE;
1080     * }
1081     * </programlisting></informalexample>
1082     *
1083     * It is possible to make policy decision asynchronously, by simply calling g_object_ref()
1084     * on the @decision argument and returning %TRUE to block the default signal handler.
1085     * If the last reference is removed on a #WebKitPolicyDecision and no decision has been
1086     * made explicitly, webkit_policy_decision_use() will be the default policy decision. The
1087     * default signal handler will simply call webkit_policy_decision_use(). Only the first
1088     * policy decision chosen for a given #WebKitPolicyDecision will have any affect.
1089     *
1090     * Returns: %TRUE to stop other handlers from being invoked for the event.
1091     *   %FALSE to propagate the event further.
1092     *
1093     */
1094    signals[DECIDE_POLICY] =
1095        g_signal_new("decide-policy",
1096                     G_TYPE_FROM_CLASS(webViewClass),
1097                     G_SIGNAL_RUN_LAST,
1098                     G_STRUCT_OFFSET(WebKitWebViewClass, decide_policy),
1099                     g_signal_accumulator_true_handled, 0 /* accumulator data */,
1100                     webkit_marshal_BOOLEAN__OBJECT_ENUM,
1101                     G_TYPE_BOOLEAN, 2, /* number of parameters */
1102                     WEBKIT_TYPE_POLICY_DECISION,
1103                     WEBKIT_TYPE_POLICY_DECISION_TYPE);
1104
1105    /**
1106     * WebKitWebView::permission-request:
1107     * @web_view: the #WebKitWebView on which the signal is emitted
1108     * @request: the #WebKitPermissionRequest
1109     *
1110     * This signal is emitted when WebKit is requesting the client to
1111     * decide about a permission request, such as allowing the browser
1112     * to switch to fullscreen mode, sharing its location or similar
1113     * operations.
1114     *
1115     * A possible way to use this signal could be through a dialog
1116     * allowing the user decide what to do with the request:
1117     *
1118     * <informalexample><programlisting>
1119     * static gboolean permission_request_cb (WebKitWebView *web_view,
1120     *                                        WebKitPermissionRequest *request,
1121     *                                        GtkWindow *parent_window)
1122     * {
1123     *     GtkWidget *dialog = gtk_message_dialog_new (parent_window,
1124     *                                                 GTK_DIALOG_MODAL,
1125     *                                                 GTK_MESSAGE_QUESTION,
1126     *                                                 GTK_BUTTONS_YES_NO,
1127     *                                                 "Allow Permission Request?");
1128     *     gtk_widget_show (dialog);
1129     *     gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1130     *
1131     *     switch (result) {
1132     *     case GTK_RESPONSE_YES:
1133     *         webkit_permission_request_allow (request);
1134     *         break;
1135     *     default:
1136     *         webkit_permission_request_deny (request);
1137     *         break;
1138     *     }
1139     *     gtk_widget_destroy (dialog);
1140     *
1141     *     return TRUE;
1142     * }
1143     * </programlisting></informalexample>
1144     *
1145     * It is possible to handle permission requests asynchronously, by
1146     * simply calling g_object_ref() on the @request argument and
1147     * returning %TRUE to block the default signal handler.  If the
1148     * last reference is removed on a #WebKitPermissionRequest and the
1149     * request has not been handled, webkit_permission_request_deny()
1150     * will be the default action.
1151     *
1152     * By default, if the signal is not handled,
1153     * webkit_permission_request_deny() will be called over the
1154     * #WebKitPermissionRequest.
1155     *
1156     * Returns: %TRUE to stop other handlers from being invoked for the event.
1157     *   %FALSE to propagate the event further.
1158     *
1159     */
1160    signals[PERMISSION_REQUEST] =
1161        g_signal_new("permission-request",
1162                     G_TYPE_FROM_CLASS(webViewClass),
1163                     G_SIGNAL_RUN_LAST,
1164                     G_STRUCT_OFFSET(WebKitWebViewClass, permission_request),
1165                     g_signal_accumulator_true_handled, 0 /* accumulator data */,
1166                     webkit_marshal_BOOLEAN__OBJECT,
1167                     G_TYPE_BOOLEAN, 1, /* number of parameters */
1168                     WEBKIT_TYPE_PERMISSION_REQUEST);
1169    /**
1170     * WebKitWebView::mouse-target-changed:
1171     * @web_view: the #WebKitWebView on which the signal is emitted
1172     * @hit_test_result: a #WebKitHitTestResult
1173     * @modifiers: a bitmask of #GdkModifierType
1174     *
1175     * This signal is emitted when the mouse cursor moves over an
1176     * element such as a link, image or a media element. To determine
1177     * what type of element the mouse cursor is over, a Hit Test is performed
1178     * on the current mouse coordinates and the result is passed in the
1179     * @hit_test_result argument. The @modifiers argument is a bitmask of
1180     * #GdkModifierType flags indicating the state of modifier keys.
1181     * The signal is emitted again when the mouse is moved out of the
1182     * current element with a new @hit_test_result.
1183     */
1184     signals[MOUSE_TARGET_CHANGED] =
1185         g_signal_new("mouse-target-changed",
1186                      G_TYPE_FROM_CLASS(webViewClass),
1187                      G_SIGNAL_RUN_LAST,
1188                      G_STRUCT_OFFSET(WebKitWebViewClass, mouse_target_changed),
1189                      0, 0,
1190                      webkit_marshal_VOID__OBJECT_UINT,
1191                      G_TYPE_NONE, 2,
1192                      WEBKIT_TYPE_HIT_TEST_RESULT,
1193                      G_TYPE_UINT);
1194    /**
1195     * WebKitWebView::print:
1196     * @web_view: the #WebKitWebView on which the signal is emitted
1197     * @print_operation: the #WebKitPrintOperation that will handle the print request
1198     *
1199     * Emitted when printing is requested on @web_view, usually by a javascript call,
1200     * before the print dialog is shown. This signal can be used to set the initial
1201     * print settings and page setup of @print_operation to be used as default values in
1202     * the print dialog. You can call webkit_print_operation_set_print_settings() and
1203     * webkit_print_operation_set_page_setup() and then return %FALSE to propagate the
1204     * event so that the print dialog is shown.
1205     *
1206     * You can connect to this signal and return %TRUE to cancel the print operation
1207     * or implement your own print dialog.
1208     *
1209     * Returns: %TRUE to stop other handlers from being invoked for the event.
1210     *    %FALSE to propagate the event further.
1211     */
1212    signals[PRINT] =
1213        g_signal_new("print",
1214                     G_TYPE_FROM_CLASS(webViewClass),
1215                     G_SIGNAL_RUN_LAST,
1216                     G_STRUCT_OFFSET(WebKitWebViewClass, print),
1217                     g_signal_accumulator_true_handled, 0,
1218                     webkit_marshal_BOOLEAN__OBJECT,
1219                     G_TYPE_BOOLEAN, 1,
1220                     WEBKIT_TYPE_PRINT_OPERATION);
1221
1222    /**
1223     * WebKitWebView::resource-load-started:
1224     * @web_view: the #WebKitWebView on which the signal is emitted
1225     * @resource: a #WebKitWebResource
1226     * @request: a #WebKitURIRequest
1227     *
1228     * Emitted when a new resource is going to be loaded. The @request parameter
1229     * contains the #WebKitURIRequest that will be sent to the server.
1230     * You can monitor the load operation by connecting to the different signals
1231     * of @resource.
1232     */
1233    signals[RESOURCE_LOAD_STARTED] =
1234        g_signal_new("resource-load-started",
1235                     G_TYPE_FROM_CLASS(webViewClass),
1236                     G_SIGNAL_RUN_LAST,
1237                     G_STRUCT_OFFSET(WebKitWebViewClass, resource_load_started),
1238                     0, 0,
1239                     webkit_marshal_VOID__OBJECT_OBJECT,
1240                     G_TYPE_NONE, 2,
1241                     WEBKIT_TYPE_WEB_RESOURCE,
1242                     WEBKIT_TYPE_URI_REQUEST);
1243
1244    /**
1245     * WebKitWebView::enter-fullscreen:
1246     * @web_view: the #WebKitWebView on which the signal is emitted.
1247     *
1248     * Emitted when JavaScript code calls
1249     * <function>element.webkitRequestFullScreen</function>. If the
1250     * signal is not handled the #WebKitWebView will proceed to full screen
1251     * its top level window. This signal can be used by client code to
1252     * request permission to the user prior doing the full screen
1253     * transition and eventually prepare the top-level window
1254     * (e.g. hide some widgets that would otherwise be part of the
1255     * full screen window).
1256     *
1257     * Returns: %TRUE to stop other handlers from being invoked for the event.
1258     *    %FALSE to continue emission of the event.
1259     */
1260    signals[ENTER_FULLSCREEN] =
1261        g_signal_new("enter-fullscreen",
1262                     G_TYPE_FROM_CLASS(webViewClass),
1263                     G_SIGNAL_RUN_LAST,
1264                     G_STRUCT_OFFSET(WebKitWebViewClass, enter_fullscreen),
1265                     g_signal_accumulator_true_handled, 0,
1266                     webkit_marshal_BOOLEAN__VOID,
1267                     G_TYPE_BOOLEAN, 0);
1268
1269    /**
1270     * WebKitWebView::leave-fullscreen:
1271     * @web_view: the #WebKitWebView on which the signal is emitted.
1272     *
1273     * Emitted when the #WebKitWebView is about to restore its top level
1274     * window out of its full screen state. This signal can be used by
1275     * client code to restore widgets hidden during the
1276     * #WebKitWebView::enter-fullscreen stage for instance.
1277     *
1278     * Returns: %TRUE to stop other handlers from being invoked for the event.
1279     *    %FALSE to continue emission of the event.
1280     */
1281    signals[LEAVE_FULLSCREEN] =
1282        g_signal_new("leave-fullscreen",
1283                     G_TYPE_FROM_CLASS(webViewClass),
1284                     G_SIGNAL_RUN_LAST,
1285                     G_STRUCT_OFFSET(WebKitWebViewClass, leave_fullscreen),
1286                     g_signal_accumulator_true_handled, 0,
1287                     webkit_marshal_BOOLEAN__VOID,
1288                     G_TYPE_BOOLEAN, 0);
1289     /**
1290     * WebKitWebView::run-file-chooser:
1291     * @web_view: the #WebKitWebView on which the signal is emitted
1292     * @request: a #WebKitFileChooserRequest
1293     *
1294     * This signal is emitted when the user interacts with a &lt;input
1295     * type='file' /&gt; HTML element, requesting from WebKit to show
1296     * a dialog to select one or more files to be uploaded. To let the
1297     * application know the details of the file chooser, as well as to
1298     * allow the client application to either cancel the request or
1299     * perform an actual selection of files, the signal will pass an
1300     * instance of the #WebKitFileChooserRequest in the @request
1301     * argument.
1302     *
1303     * The default signal handler will asynchronously run a regular
1304     * #GtkFileChooserDialog for the user to interact with.
1305     *
1306     * Returns: %TRUE to stop other handlers from being invoked for the event.
1307     *   %FALSE to propagate the event further.
1308     *
1309     */
1310    signals[RUN_FILE_CHOOSER] =
1311        g_signal_new("run-file-chooser",
1312                     G_TYPE_FROM_CLASS(webViewClass),
1313                     G_SIGNAL_RUN_LAST,
1314                     G_STRUCT_OFFSET(WebKitWebViewClass, run_file_chooser),
1315                     g_signal_accumulator_true_handled, 0 /* accumulator data */,
1316                     webkit_marshal_BOOLEAN__OBJECT,
1317                     G_TYPE_BOOLEAN, 1, /* number of parameters */
1318                     WEBKIT_TYPE_FILE_CHOOSER_REQUEST);
1319
1320    /**
1321     * WebKitWebView::context-menu:
1322     * @web_view: the #WebKitWebView on which the signal is emitted
1323     * @context_menu: the proposed #WebKitContextMenu
1324     * @event: the #GdkEvent that triggered the context menu
1325     * @hit_test_result: a #WebKitHitTestResult
1326     *
1327     * Emmited when a context menu is about to be displayed to give the application
1328     * a chance to customize the proposed menu, prevent the menu from being displayed
1329     * or build its own context menu.
1330     * <itemizedlist>
1331     * <listitem><para>
1332     *  To customize the proposed menu you can use webkit_context_menu_prepend(),
1333     *  webkit_context_menu_append() or webkit_context_menu_insert() to add new
1334     *  #WebKitContextMenuItem<!-- -->s to @context_menu, webkit_context_menu_move_item()
1335     *  to reorder existing items, or webkit_context_menu_remove() to remove an
1336     *  existing item. The signal handler should return %FALSE, and the menu represented
1337     *  by @context_menu will be shown.
1338     * </para></listitem>
1339     * <listitem><para>
1340     *  To prevent the menu from being displayed you can just connect to this signal
1341     *  and return %TRUE so that the proposed menu will not be shown.
1342     * </para></listitem>
1343     * <listitem><para>
1344     *  To build your own menu, you can remove all items from the proposed menu with
1345     *  webkit_context_menu_remove_all(), add your own items and return %FALSE so
1346     *  that the menu will be shown. You can also ignore the proposed #WebKitContextMenu,
1347     *  build your own #GtkMenu and return %TRUE to prevent the proposed menu from being shown.
1348     * </para></listitem>
1349     * <listitem><para>
1350     *  If you just want the default menu to be shown always, simply don't connect to this
1351     *  signal because showing the proposed context menu is the default behaviour.
1352     * </para></listitem>
1353     * </itemizedlist>
1354     *
1355     * If the signal handler returns %FALSE the context menu represented by @context_menu
1356     * will be shown, if it return %TRUE the context menu will not be shown.
1357     *
1358     * The proposed #WebKitContextMenu passed in @context_menu argument is only valid
1359     * during the signal emission.
1360     *
1361     * Returns: %TRUE to stop other handlers from being invoked for the event.
1362     *    %FALSE to propagate the event further.
1363     */
1364    signals[CONTEXT_MENU] =
1365        g_signal_new("context-menu",
1366                     G_TYPE_FROM_CLASS(webViewClass),
1367                     G_SIGNAL_RUN_LAST,
1368                     G_STRUCT_OFFSET(WebKitWebViewClass, context_menu),
1369                     g_signal_accumulator_true_handled, 0,
1370                     webkit_marshal_BOOLEAN__OBJECT_BOXED_OBJECT,
1371                     G_TYPE_BOOLEAN, 3,
1372                     WEBKIT_TYPE_CONTEXT_MENU,
1373                     GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1374                     WEBKIT_TYPE_HIT_TEST_RESULT);
1375
1376    /**
1377     * WebKitWebView::context-menu-dismissed:
1378     * @web_view: the #WebKitWebView on which the signal is emitted
1379     *
1380     * Emitted after #WebKitWebView::context-menu signal, if the context menu is shown,
1381     * to notify that the context menu is dismissed.
1382     */
1383    signals[CONTEXT_MENU_DISMISSED] =
1384        g_signal_new("context-menu-dismissed",
1385                     G_TYPE_FROM_CLASS(webViewClass),
1386                     G_SIGNAL_RUN_LAST,
1387                     G_STRUCT_OFFSET(WebKitWebViewClass, context_menu_dismissed),
1388                     0, 0,
1389                     g_cclosure_marshal_VOID__VOID,
1390                     G_TYPE_NONE, 0);
1391
1392    /**
1393     * WebKitWebView::submit-form:
1394     * @web_view: the #WebKitWebView on which the signal is emitted
1395     * @request: a #WebKitFormSubmissionRequest
1396     *
1397     * This signal is emitted when a form is about to be submitted. The @request
1398     * argument passed contains information about the text fields of the form. This
1399     * is typically used to store login information that can be used later to
1400     * pre-fill the form.
1401     * The form will not be submitted until webkit_form_submission_request_submit() is called.
1402     *
1403     * It is possible to handle the form submission request asynchronously, by
1404     * simply calling g_object_ref() on the @request argument and calling
1405     * webkit_form_submission_request_submit() when done to continue with the form submission.
1406     * If the last reference is removed on a #WebKitFormSubmissionRequest and the
1407     * form has not been submitted, webkit_form_submission_request_submit() will be called.
1408     */
1409    signals[SUBMIT_FORM] =
1410        g_signal_new("submit-form",
1411                     G_TYPE_FROM_CLASS(webViewClass),
1412                     G_SIGNAL_RUN_LAST,
1413                     G_STRUCT_OFFSET(WebKitWebViewClass, submit_form),
1414                     0, 0,
1415                     g_cclosure_marshal_VOID__OBJECT,
1416                     G_TYPE_NONE, 1,
1417                     WEBKIT_TYPE_FORM_SUBMISSION_REQUEST);
1418
1419    /**
1420     * WebKitWebView::insecure-content-detected:
1421     * @web_view: the #WebKitWebView on which the signal is emitted
1422     * @event: the #WebKitInsecureContentEvent
1423     *
1424     * This signal is emitted when insecure content has been detected
1425     * in a page loaded through a secure connection. This typically
1426     * means that a external resource from an unstrusted source has
1427     * been run or displayed, resulting in a mix of HTTPS and
1428     * non-HTTPS content.
1429     *
1430     * You can check the @event parameter to know exactly which kind
1431     * of event has been detected (see #WebKitInsecureContentEvent).
1432     */
1433    signals[INSECURE_CONTENT_DETECTED] =
1434        g_signal_new("insecure-content-detected",
1435            G_TYPE_FROM_CLASS(webViewClass),
1436            G_SIGNAL_RUN_LAST,
1437            G_STRUCT_OFFSET(WebKitWebViewClass, insecure_content_detected),
1438            0, 0,
1439            g_cclosure_marshal_VOID__ENUM,
1440            G_TYPE_NONE, 1,
1441            WEBKIT_TYPE_INSECURE_CONTENT_EVENT);
1442
1443    /**
1444     * WebKitWebView::web-process-crashed:
1445     * @web_view: the #WebKitWebView
1446     *
1447     * This signal is emitted when the web process crashes.
1448     *
1449     * Returns: %TRUE to stop other handlers from being invoked for the event.
1450     *    %FALSE to propagate the event further.
1451     */
1452    signals[WEB_PROCESS_CRASHED] = g_signal_new(
1453        "web-process-crashed",
1454        G_TYPE_FROM_CLASS(webViewClass),
1455        G_SIGNAL_RUN_LAST,
1456        G_STRUCT_OFFSET(WebKitWebViewClass, web_process_crashed),
1457        g_signal_accumulator_true_handled,
1458        0,
1459        webkit_marshal_BOOLEAN__VOID,
1460        G_TYPE_BOOLEAN, 0);
1461
1462    /**
1463     * WebKitWebView::authenticate:
1464     * @web_view: the #WebKitWebView on which the signal is emitted
1465     * @request: a #WebKitAuthenticationRequest
1466     *
1467     * This signal is emitted when the user is challenged with HTTP
1468     * authentication. To let the  application access or supply
1469     * the credentials as well as to allow the client application
1470     * to either cancel the request or perform the authentication,
1471     * the signal will pass an instance of the
1472     * #WebKitAuthenticationRequest in the @request argument.
1473     * To handle this signal asynchronously you should keep a ref
1474     * of the request and return %TRUE. To disable HTTP authentication
1475     * entirely, connect to this signal and simply return %TRUE.
1476     *
1477     * The default signal handler will run a default authentication
1478     * dialog asynchronously for the user to interact with.
1479     *
1480     * Returns: %TRUE to stop other handlers from being invoked for the event.
1481     *   %FALSE to propagate the event further.
1482     *
1483     * Since: 2.2
1484     */
1485    signals[AUTHENTICATE] =
1486        g_signal_new("authenticate",
1487            G_TYPE_FROM_CLASS(webViewClass),
1488            G_SIGNAL_RUN_LAST,
1489            G_STRUCT_OFFSET(WebKitWebViewClass, authenticate),
1490            g_signal_accumulator_true_handled, 0 /* accumulator data */,
1491            webkit_marshal_BOOLEAN__OBJECT,
1492            G_TYPE_BOOLEAN, 1, /* number of parameters */
1493            WEBKIT_TYPE_AUTHENTICATION_REQUEST);
1494}
1495
1496static void webkitWebViewSetIsLoading(WebKitWebView* webView, bool isLoading)
1497{
1498    if (webView->priv->isLoading == isLoading)
1499        return;
1500
1501    webView->priv->isLoading = isLoading;
1502    g_object_freeze_notify(G_OBJECT(webView));
1503    g_object_notify(G_OBJECT(webView), "is-loading");
1504
1505    // Update the URI if a new load has started.
1506    if (webView->priv->isLoading)
1507        webkitWebViewUpdateURI(webView);
1508    g_object_thaw_notify(G_OBJECT(webView));
1509}
1510
1511static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView)
1512{
1513    if (!webView->priv->authenticationRequest)
1514        return;
1515
1516    webkit_authentication_request_cancel(webView->priv->authenticationRequest.get());
1517    webView->priv->authenticationRequest.clear();
1518}
1519
1520static void webkitWebViewEmitLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
1521{
1522    if (loadEvent == WEBKIT_LOAD_STARTED) {
1523        webkitWebViewSetIsLoading(webView, true);
1524        webkitWebViewWatchForChangesInFavicon(webView);
1525        webkitWebViewCancelAuthenticationRequest(webView);
1526    } else if (loadEvent == WEBKIT_LOAD_FINISHED) {
1527        webkitWebViewSetIsLoading(webView, false);
1528        webkitWebViewCancelAuthenticationRequest(webView);
1529        webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1530    } else
1531        webkitWebViewUpdateURI(webView);
1532    g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent);
1533}
1534
1535static void webkitWebViewEmitDelayedLoadEvents(WebKitWebView* webView)
1536{
1537    WebKitWebViewPrivate* priv = webView->priv;
1538    if (!priv->waitingForMainResource)
1539        return;
1540    ASSERT(priv->lastDelayedEvent == WEBKIT_LOAD_COMMITTED || priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED);
1541
1542    if (priv->lastDelayedEvent == WEBKIT_LOAD_FINISHED)
1543        webkitWebViewEmitLoadChanged(webView, WEBKIT_LOAD_COMMITTED);
1544    webkitWebViewEmitLoadChanged(webView, priv->lastDelayedEvent);
1545    priv->waitingForMainResource = false;
1546}
1547
1548void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
1549{
1550    WebKitWebViewPrivate* priv = webView->priv;
1551    if (loadEvent == WEBKIT_LOAD_STARTED) {
1552        // Finish a possible previous load waiting for main resource.
1553        webkitWebViewEmitDelayedLoadEvents(webView);
1554
1555        webkitWebViewCancelFaviconRequest(webView);
1556        priv->loadingResourcesMap.clear();
1557        priv->mainResource = 0;
1558        priv->waitingForMainResource = false;
1559    } else if (loadEvent == WEBKIT_LOAD_COMMITTED) {
1560        WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context);
1561        GUniquePtr<char> faviconURI(webkit_favicon_database_get_favicon_uri(database, priv->activeURI.data()));
1562        webkitWebViewUpdateFaviconURI(webView, faviconURI.get());
1563
1564        if (!priv->mainResource) {
1565            // When a page is loaded from the history cache, the main resource load callbacks
1566            // are called when the main frame load is finished. We want to make sure there's a
1567            // main resource available when load has been committed, so we delay the emission of
1568            // load-changed signal until main resource object has been created.
1569            priv->waitingForMainResource = true;
1570        }
1571    }
1572
1573    if (priv->waitingForMainResource)
1574        priv->lastDelayedEvent = loadEvent;
1575    else
1576        webkitWebViewEmitLoadChanged(webView, loadEvent);
1577}
1578
1579void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error)
1580{
1581    webkitWebViewSetIsLoading(webView, false);
1582    webkitWebViewCancelAuthenticationRequest(webView);
1583
1584    gboolean returnValue;
1585    g_signal_emit(webView, signals[LOAD_FAILED], 0, loadEvent, failingURI, error, &returnValue);
1586    g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1587}
1588
1589void webkitWebViewLoadFailedWithTLSErrors(WebKitWebView* webView, const char* failingURI, GError* error, GTlsCertificateFlags tlsErrors, GTlsCertificate* certificate)
1590{
1591    webkitWebViewSetIsLoading(webView, false);
1592    webkitWebViewCancelAuthenticationRequest(webView);
1593
1594    WebKitTLSErrorsPolicy tlsErrorsPolicy = webkit_web_context_get_tls_errors_policy(webView->priv->context);
1595    if (tlsErrorsPolicy == WEBKIT_TLS_ERRORS_POLICY_FAIL) {
1596        GUniquePtr<SoupURI> soupURI(soup_uri_new(failingURI));
1597        WebKitCertificateInfo info(certificate, tlsErrors);
1598        gboolean returnValue;
1599        g_signal_emit(webView, signals[LOAD_FAILED_WITH_TLS_ERRORS], 0, &info, soupURI->host, &returnValue);
1600        if (!returnValue)
1601            g_signal_emit(webView, signals[LOAD_FAILED], 0, WEBKIT_LOAD_STARTED, failingURI, error, &returnValue);
1602    }
1603
1604    g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1605}
1606
1607void webkitWebViewSetTitle(WebKitWebView* webView, const CString& title)
1608{
1609    WebKitWebViewPrivate* priv = webView->priv;
1610    if (priv->title == title)
1611        return;
1612
1613    priv->title = title;
1614    g_object_notify(G_OBJECT(webView), "title");
1615}
1616
1617void webkitWebViewSetEstimatedLoadProgress(WebKitWebView* webView, double estimatedLoadProgress)
1618{
1619    if (webView->priv->estimatedLoadProgress == estimatedLoadProgress)
1620        return;
1621
1622    webView->priv->estimatedLoadProgress = estimatedLoadProgress;
1623    g_object_notify(G_OBJECT(webView), "estimated-load-progress");
1624}
1625
1626void webkitWebViewUpdateURI(WebKitWebView* webView)
1627{
1628    CString activeURI = getPage(webView)->pageLoadState().activeURL().utf8();
1629    if (webView->priv->activeURI == activeURI)
1630        return;
1631
1632    webView->priv->activeURI = activeURI;
1633    g_object_notify(G_OBJECT(webView), "uri");
1634}
1635
1636WebPageProxy* webkitWebViewCreateNewPage(WebKitWebView* webView, const WindowFeatures& windowFeatures, WebKitNavigationAction* navigationAction)
1637{
1638    WebKitWebView* newWebView;
1639    g_signal_emit(webView, signals[CREATE], 0, navigationAction, &newWebView);
1640    if (!newWebView)
1641        return 0;
1642
1643    webkitWindowPropertiesUpdateFromWebWindowFeatures(newWebView->priv->windowProperties.get(), windowFeatures);
1644
1645    RefPtr<WebPageProxy> newPage = getPage(newWebView);
1646    return newPage.release().leakRef();
1647}
1648
1649void webkitWebViewReadyToShowPage(WebKitWebView* webView)
1650{
1651    g_signal_emit(webView, signals[READY_TO_SHOW], 0, NULL);
1652}
1653
1654void webkitWebViewRunAsModal(WebKitWebView* webView)
1655{
1656    g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL);
1657
1658    webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE));
1659
1660// This is to suppress warnings about gdk_threads_leave and gdk_threads_enter.
1661#pragma GCC diagnostic push
1662#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1663    gdk_threads_leave();
1664    g_main_loop_run(webView->priv->modalLoop.get());
1665    gdk_threads_enter();
1666#pragma GCC diagnostic pop
1667}
1668
1669void webkitWebViewClosePage(WebKitWebView* webView)
1670{
1671    g_signal_emit(webView, signals[CLOSE], 0, NULL);
1672}
1673
1674void webkitWebViewRunJavaScriptAlert(WebKitWebView* webView, const CString& message)
1675{
1676    WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_ALERT, message);
1677    gboolean returnValue;
1678    g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1679}
1680
1681bool webkitWebViewRunJavaScriptConfirm(WebKitWebView* webView, const CString& message)
1682{
1683    WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_CONFIRM, message);
1684    gboolean returnValue;
1685    g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1686    return dialog.confirmed;
1687}
1688
1689CString webkitWebViewRunJavaScriptPrompt(WebKitWebView* webView, const CString& message, const CString& defaultText)
1690{
1691    WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_PROMPT, message, defaultText);
1692    gboolean returnValue;
1693    g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
1694    return dialog.text;
1695}
1696
1697void webkitWebViewMakePolicyDecision(WebKitWebView* webView, WebKitPolicyDecisionType type, WebKitPolicyDecision* decision)
1698{
1699    gboolean returnValue;
1700    g_signal_emit(webView, signals[DECIDE_POLICY], 0, decision, type, &returnValue);
1701}
1702
1703void webkitWebViewMakePermissionRequest(WebKitWebView* webView, WebKitPermissionRequest* request)
1704{
1705    gboolean returnValue;
1706    g_signal_emit(webView, signals[PERMISSION_REQUEST], 0, request, &returnValue);
1707}
1708
1709void webkitWebViewMouseTargetChanged(WebKitWebView* webView, const WebHitTestResult::Data& hitTestResult, unsigned modifiers)
1710{
1711    webkitWebViewBaseSetTooltipArea(WEBKIT_WEB_VIEW_BASE(webView), hitTestResult.elementBoundingBox);
1712
1713    WebKitWebViewPrivate* priv = webView->priv;
1714    if (priv->mouseTargetHitTestResult
1715        && priv->mouseTargetModifiers == modifiers
1716        && webkitHitTestResultCompare(priv->mouseTargetHitTestResult.get(), hitTestResult))
1717        return;
1718
1719    priv->mouseTargetModifiers = modifiers;
1720    priv->mouseTargetHitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResult));
1721    g_signal_emit(webView, signals[MOUSE_TARGET_CHANGED], 0, priv->mouseTargetHitTestResult.get(), modifiers);
1722}
1723
1724void webkitWebViewPrintFrame(WebKitWebView* webView, WebFrameProxy* frame)
1725{
1726    GRefPtr<WebKitPrintOperation> printOperation = adoptGRef(webkit_print_operation_new(webView));
1727    webkitPrintOperationSetPrintMode(printOperation.get(), PrintInfo::PrintModeSync);
1728    gboolean returnValue;
1729    g_signal_emit(webView, signals[PRINT], 0, printOperation.get(), &returnValue);
1730    if (returnValue)
1731        return;
1732
1733    WebKitPrintOperationResponse response = webkitPrintOperationRunDialogForFrame(printOperation.get(), 0, frame);
1734    if (response == WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL)
1735        return;
1736    g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0);
1737}
1738
1739static void mainResourceResponseChangedCallback(WebKitWebResource*, GParamSpec*, WebKitWebView* webView)
1740{
1741    webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1742    webkitWebViewEmitDelayedLoadEvents(webView);
1743}
1744
1745static void waitForMainResourceResponseIfWaitingForResource(WebKitWebView* webView)
1746{
1747    WebKitWebViewPrivate* priv = webView->priv;
1748    if (!priv->waitingForMainResource)
1749        return;
1750
1751    webkitWebViewDisconnectMainResourceResponseChangedSignalHandler(webView);
1752    priv->mainResourceResponseHandlerID =
1753        g_signal_connect(priv->mainResource.get(), "notify::response", G_CALLBACK(mainResourceResponseChangedCallback), webView);
1754}
1755
1756void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WebFrameProxy* frame, uint64_t resourceIdentifier, WebKitURIRequest* request)
1757{
1758    WebKitWebViewPrivate* priv = webView->priv;
1759    bool isMainResource = frame->isMainFrame() && !priv->mainResource;
1760    WebKitWebResource* resource = webkitWebResourceCreate(frame, request, isMainResource);
1761    if (isMainResource) {
1762        priv->mainResource = resource;
1763        waitForMainResourceResponseIfWaitingForResource(webView);
1764    }
1765    priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource));
1766    g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request);
1767}
1768
1769WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
1770{
1771    GRefPtr<WebKitWebResource> resource = webView->priv->loadingResourcesMap.get(resourceIdentifier);
1772    return resource.get();
1773}
1774
1775void webkitWebViewRemoveLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
1776{
1777    WebKitWebViewPrivate* priv = webView->priv;
1778    ASSERT(priv->loadingResourcesMap.contains(resourceIdentifier));
1779    priv->loadingResourcesMap.remove(resourceIdentifier);
1780}
1781
1782bool webkitWebViewEnterFullScreen(WebKitWebView* webView)
1783{
1784    gboolean returnValue;
1785    g_signal_emit(webView, signals[ENTER_FULLSCREEN], 0, &returnValue);
1786    return !returnValue;
1787}
1788
1789bool webkitWebViewLeaveFullScreen(WebKitWebView* webView)
1790{
1791    gboolean returnValue;
1792    g_signal_emit(webView, signals[LEAVE_FULLSCREEN], 0, &returnValue);
1793    return !returnValue;
1794}
1795
1796void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChooserRequest* request)
1797{
1798    gboolean returnValue;
1799    g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue);
1800}
1801
1802static bool webkitWebViewShouldShowInputMethodsMenu(WebKitWebView* webView)
1803{
1804    GtkSettings* settings = gtk_widget_get_settings(GTK_WIDGET(webView));
1805    if (!settings)
1806        return true;
1807
1808    gboolean showInputMethodMenu;
1809    g_object_get(settings, "gtk-show-input-method-menu", &showInputMethodMenu, NULL);
1810    return showInputMethodMenu;
1811}
1812
1813static int getUnicodeMenuItemPosition(WebKitContextMenu* contextMenu)
1814{
1815    GList* items = webkit_context_menu_get_items(contextMenu);
1816    GList* iter;
1817    int i = 0;
1818    for (iter = items, i = 0; iter; iter = g_list_next(iter), ++i) {
1819        WebKitContextMenuItem* item = WEBKIT_CONTEXT_MENU_ITEM(iter->data);
1820
1821        if (webkit_context_menu_item_is_separator(item))
1822            continue;
1823        if (webkit_context_menu_item_get_stock_action(item) == WEBKIT_CONTEXT_MENU_ACTION_UNICODE)
1824            return i;
1825    }
1826    return -1;
1827}
1828
1829static void webkitWebViewCreateAndAppendInputMethodsMenuItem(WebKitWebView* webView, WebKitContextMenu* contextMenu)
1830{
1831    if (!webkitWebViewShouldShowInputMethodsMenu(webView))
1832        return;
1833
1834    // Place the im context menu item right before the unicode menu item
1835    // if it's present.
1836    int unicodeMenuItemPosition = getUnicodeMenuItemPosition(contextMenu);
1837    if (unicodeMenuItemPosition == -1)
1838        webkit_context_menu_append(contextMenu, webkit_context_menu_item_new_separator());
1839
1840    GtkIMContext* imContext = webkitWebViewBaseGetIMContext(WEBKIT_WEB_VIEW_BASE(webView));
1841    GtkMenu* imContextMenu = GTK_MENU(gtk_menu_new());
1842    gtk_im_multicontext_append_menuitems(GTK_IM_MULTICONTEXT(imContext), GTK_MENU_SHELL(imContextMenu));
1843    WebKitContextMenuItem* menuItem = webkit_context_menu_item_new_from_stock_action(WEBKIT_CONTEXT_MENU_ACTION_INPUT_METHODS);
1844    webkitContextMenuItemSetSubMenuFromGtkMenu(menuItem, imContextMenu);
1845    webkit_context_menu_insert(contextMenu, menuItem, unicodeMenuItemPosition);
1846}
1847
1848static void contextMenuDismissed(GtkMenuShell*, WebKitWebView* webView)
1849{
1850    g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL);
1851}
1852
1853void webkitWebViewPopulateContextMenu(WebKitWebView* webView, API::Array* proposedMenu, WebHitTestResult* webHitTestResult)
1854{
1855    WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
1856    WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase);
1857    ASSERT(contextMenuProxy);
1858
1859    GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(proposedMenu));
1860    if (webHitTestResult->isContentEditable())
1861        webkitWebViewCreateAndAppendInputMethodsMenuItem(webView, contextMenu.get());
1862
1863    // FIXME: we should use a custom ContextMenuClient at some point, that will receive a
1864    // const WebHitTestResult::Data& that we can use directly here.
1865    WebHitTestResult::Data data;
1866    data.absoluteImageURL = webHitTestResult->absoluteImageURL();
1867    data.absoluteLinkURL = webHitTestResult->absoluteLinkURL();
1868    data.absoluteMediaURL = webHitTestResult->absoluteMediaURL();
1869    data.linkLabel = webHitTestResult->linkLabel();
1870    data.linkTitle = webHitTestResult->linkTitle();
1871    data.isContentEditable = webHitTestResult->isContentEditable();
1872    data.elementBoundingBox = webHitTestResult->elementBoundingBox();
1873    data.isScrollbar = webHitTestResult->isScrollbar();
1874
1875    GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(data));
1876    GUniquePtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase));
1877
1878    gboolean returnValue;
1879    g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue);
1880    if (returnValue)
1881        return;
1882
1883    Vector<ContextMenuItem> contextMenuItems;
1884    webkitContextMenuPopulate(contextMenu.get(), contextMenuItems);
1885    contextMenuProxy->populate(contextMenuItems);
1886
1887    g_signal_connect(contextMenuProxy->gtkMenu(), "deactivate", G_CALLBACK(contextMenuDismissed), webView);
1888
1889    // Clear the menu to make sure it's useless after signal emission.
1890    webkit_context_menu_remove_all(contextMenu.get());
1891}
1892
1893void webkitWebViewSubmitFormRequest(WebKitWebView* webView, WebKitFormSubmissionRequest* request)
1894{
1895    g_signal_emit(webView, signals[SUBMIT_FORM], 0, request);
1896}
1897
1898void webkitWebViewHandleAuthenticationChallenge(WebKitWebView* webView, AuthenticationChallengeProxy* authenticationChallenge)
1899{
1900    gboolean privateBrowsingEnabled = webkit_settings_get_enable_private_browsing(webkit_web_view_get_settings(webView));
1901    webView->priv->authenticationRequest = adoptGRef(webkitAuthenticationRequestCreate(authenticationChallenge, privateBrowsingEnabled));
1902    gboolean returnValue;
1903    g_signal_emit(webView, signals[AUTHENTICATE], 0, webView->priv->authenticationRequest.get(), &returnValue);
1904}
1905
1906void webkitWebViewInsecureContentDetected(WebKitWebView* webView, WebKitInsecureContentEvent type)
1907{
1908    g_signal_emit(webView, signals[INSECURE_CONTENT_DETECTED], 0, type);
1909}
1910
1911/**
1912 * webkit_web_view_new:
1913 *
1914 * Creates a new #WebKitWebView with the default #WebKitWebContext and the
1915 * default #WebKitWebViewGroup.
1916 * See also webkit_web_view_new_with_context() and webkit_web_view_new_with_group().
1917 *
1918 * Returns: The newly created #WebKitWebView widget
1919 */
1920GtkWidget* webkit_web_view_new()
1921{
1922    return webkit_web_view_new_with_context(webkit_web_context_get_default());
1923}
1924
1925/**
1926 * webkit_web_view_new_with_context:
1927 * @context: the #WebKitWebContext to be used by the #WebKitWebView
1928 *
1929 * Creates a new #WebKitWebView with the given #WebKitWebContext and the
1930 * default #WebKitWebViewGroup.
1931 * See also webkit_web_view_new_with_group().
1932 *
1933 * Returns: The newly created #WebKitWebView widget
1934 */
1935GtkWidget* webkit_web_view_new_with_context(WebKitWebContext* context)
1936{
1937    g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), 0);
1938
1939    return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", context, NULL));
1940}
1941
1942/**
1943 * webkit_web_view_new_with_related_view:
1944 * @web_view: the related #WebKitWebView
1945 *
1946 * Creates a new #WebKitWebView sharing the same web process with @web_view.
1947 * This method doesn't have any effect when %WEBKIT_PROCESS_MODEL_SHARED_SECONDARY_PROCESS
1948 * process model is used, because a single web process is shared for all the web views in the
1949 * same #WebKitWebContext. When using %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES process model,
1950 * this method should always be used when creating the #WebKitWebView in the #WebKitWebView::create signal.
1951 * You can also use this method to implement other process models based on %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES,
1952 * like for example, sharing the same web process for all the views in the same security domain.
1953 *
1954 * The newly created #WebKitWebView will also have the same #WebKitUserContentManager as @web_view.
1955 *
1956 * Returns: (transfer full): The newly created #WebKitWebView widget
1957 *
1958 * Since: 2.4
1959 */
1960GtkWidget* webkit_web_view_new_with_related_view(WebKitWebView* webView)
1961{
1962    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
1963
1964    return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW,
1965        "user-content-manager", webView->priv->userContentManager.get(),
1966        "related-view", webView,
1967        nullptr));
1968}
1969
1970/**
1971 * webkit_web_view_new_with_group:
1972 * @group: a #WebKitWebViewGroup
1973 *
1974 * Creates a new #WebKitWebView with the given #WebKitWebViewGroup.
1975 * The view will be part of @group and it will be affected by the
1976 * group properties like the settings.
1977 *
1978 * Returns: The newly created #WebKitWebView widget
1979 */
1980GtkWidget* webkit_web_view_new_with_group(WebKitWebViewGroup* group)
1981{
1982    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW_GROUP(group), 0);
1983
1984    return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "group", group, NULL));
1985}
1986
1987/**
1988 * webkit_web_view_new_with_user_content_manager:
1989 * @user_content_manager: a #WebKitUserContentManager.
1990 *
1991 * Creates a new #WebKitWebView with the given #WebKitUserContentManager.
1992 * The content loaded in the view may be affected by the content injected
1993 * in the view by the user content manager.
1994 *
1995 * Returns: The newly created #WebKitWebView widget
1996 *
1997 * Since: 2.6
1998 */
1999GtkWidget* webkit_web_view_new_with_user_content_manager(WebKitUserContentManager* userContentManager)
2000{
2001    g_return_val_if_fail(WEBKIT_IS_USER_CONTENT_MANAGER(userContentManager), nullptr);
2002
2003    return GTK_WIDGET(g_object_new(WEBKIT_TYPE_WEB_VIEW, "user-content-manager", userContentManager, nullptr));
2004}
2005
2006/**
2007 * webkit_web_view_get_context:
2008 * @web_view: a #WebKitWebView
2009 *
2010 * Gets the web context of @web_view.
2011 *
2012 * Returns: (transfer none): the #WebKitWebContext of the view
2013 */
2014WebKitWebContext* webkit_web_view_get_context(WebKitWebView *webView)
2015{
2016    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2017
2018    return webView->priv->context;
2019}
2020
2021/**
2022 * webkit_web_view_get_group:
2023 * @web_view: a #WebKitWebView
2024 *
2025 * Gets the group @web_view belongs to.
2026 *
2027 * Returns: (transfer none): the #WebKitWebViewGroup to which the view belongs
2028 */
2029WebKitWebViewGroup* webkit_web_view_get_group(WebKitWebView* webView)
2030{
2031    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2032
2033    if (webView->priv->group)
2034        return webView->priv->group.get();
2035
2036    return webkitWebContextGetDefaultWebViewGroup(webView->priv->context);
2037}
2038
2039/**
2040 * webkit_web_view_get_user_content_manager:
2041 * @web_view: a #WebKitWebView
2042 *
2043 * Gets the user content manager associated to @web_view, or %NULL if the
2044 * view does not have an user content manager.
2045 *
2046 * Returns: (transfer none): the #WebKitUserContentManager associated with the view
2047 *
2048 * Since: 2.6
2049 */
2050WebKitUserContentManager* webkit_web_view_get_user_content_manager(WebKitWebView* webView)
2051{
2052    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
2053
2054    return webView->priv->userContentManager.get();
2055}
2056
2057/**
2058 * webkit_web_view_load_uri:
2059 * @web_view: a #WebKitWebView
2060 * @uri: an URI string
2061 *
2062 * Requests loading of the specified URI string.
2063 * You can monitor the load operation by connecting to
2064 * #WebKitWebView::load-changed signal.
2065 */
2066void webkit_web_view_load_uri(WebKitWebView* webView, const gchar* uri)
2067{
2068    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2069    g_return_if_fail(uri);
2070
2071    GUniquePtr<SoupURI> soupURI(soup_uri_new(uri));
2072    getPage(webView)->loadRequest(URL(soupURI.get()));
2073}
2074
2075/**
2076 * webkit_web_view_load_html:
2077 * @web_view: a #WebKitWebView
2078 * @content: The HTML string to load
2079 * @base_uri: (allow-none): The base URI for relative locations or %NULL
2080 *
2081 * Load the given @content string with the specified @base_uri.
2082 * If @base_uri is not %NULL, relative URLs in the @content will be
2083 * resolved against @base_uri and absolute local paths must be children of the @base_uri.
2084 * For security reasons absolute local paths that are not children of @base_uri
2085 * will cause the web process to terminate.
2086 * If you need to include URLs in @content that are local paths in a different
2087 * directory than @base_uri you can build a data URI for them. When @base_uri is %NULL,
2088 * it defaults to "about:blank". The mime type of the document will be "text/html".
2089 * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal.
2090 */
2091void webkit_web_view_load_html(WebKitWebView* webView, const gchar* content, const gchar* baseURI)
2092{
2093    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2094    g_return_if_fail(content);
2095
2096    getPage(webView)->loadHTMLString(String::fromUTF8(content), String::fromUTF8(baseURI));
2097}
2098
2099/**
2100 * webkit_web_view_load_alternate_html:
2101 * @web_view: a #WebKitWebView
2102 * @content: the new content to display as the main page of the @web_view
2103 * @content_uri: the URI for the alternate page content
2104 * @base_uri: (allow-none): the base URI for relative locations or %NULL
2105 *
2106 * Load the given @content string for the URI @content_uri.
2107 * This allows clients to display page-loading errors in the #WebKitWebView itself.
2108 * When this method is called from #WebKitWebView::load-failed signal to show an
2109 * error page, the the back-forward list is maintained appropriately.
2110 * For everything else this method works the same way as webkit_web_view_load_html().
2111 */
2112void webkit_web_view_load_alternate_html(WebKitWebView* webView, const gchar* content, const gchar* contentURI, const gchar* baseURI)
2113{
2114    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2115    g_return_if_fail(content);
2116    g_return_if_fail(contentURI);
2117
2118    getPage(webView)->loadAlternateHTMLString(String::fromUTF8(content), String::fromUTF8(baseURI), String::fromUTF8(contentURI));
2119}
2120
2121/**
2122 * webkit_web_view_load_plain_text:
2123 * @web_view: a #WebKitWebView
2124 * @plain_text: The plain text to load
2125 *
2126 * Load the specified @plain_text string into @web_view. The mime type of
2127 * document will be "text/plain". You can monitor the load
2128 * operation by connecting to #WebKitWebView::load-changed signal.
2129 */
2130void webkit_web_view_load_plain_text(WebKitWebView* webView, const gchar* plainText)
2131{
2132    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2133    g_return_if_fail(plainText);
2134
2135    getPage(webView)->loadPlainTextString(String::fromUTF8(plainText));
2136}
2137
2138/**
2139 * webkit_web_view_load_request:
2140 * @web_view: a #WebKitWebView
2141 * @request: a #WebKitURIRequest to load
2142 *
2143 * Requests loading of the specified #WebKitURIRequest.
2144 * You can monitor the load operation by connecting to
2145 * #WebKitWebView::load-changed signal.
2146 */
2147void webkit_web_view_load_request(WebKitWebView* webView, WebKitURIRequest* request)
2148{
2149    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2150    g_return_if_fail(WEBKIT_IS_URI_REQUEST(request));
2151
2152    ResourceRequest resourceRequest;
2153    webkitURIRequestGetResourceRequest(request, resourceRequest);
2154    getPage(webView)->loadRequest(resourceRequest);
2155}
2156
2157/**
2158 * webkit_web_view_get_page_id:
2159 * @web_view: a #WebKitWebView
2160 *
2161 * Get the identifier of the #WebKitWebPage corresponding to
2162 * the #WebKitWebView
2163 *
2164 * Returns: the page ID of @web_view.
2165 */
2166guint64 webkit_web_view_get_page_id(WebKitWebView* webView)
2167{
2168    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2169
2170    return getPage(webView)->pageID();
2171}
2172
2173/**
2174 * webkit_web_view_get_title:
2175 * @web_view: a #WebKitWebView
2176 *
2177 * Gets the value of the #WebKitWebView:title property.
2178 * You can connect to notify::title signal of @web_view to
2179 * be notified when the title has been received.
2180 *
2181 * Returns: The main frame document title of @web_view.
2182 */
2183const gchar* webkit_web_view_get_title(WebKitWebView* webView)
2184{
2185    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2186
2187    return webView->priv->title.data();
2188}
2189
2190/**
2191 * webkit_web_view_reload:
2192 * @web_view: a #WebKitWebView
2193 *
2194 * Reloads the current contents of @web_view.
2195 * See also webkit_web_view_reload_bypass_cache().
2196 */
2197void webkit_web_view_reload(WebKitWebView* webView)
2198{
2199    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2200
2201    getPage(webView)->reload(false);
2202}
2203
2204/**
2205 * webkit_web_view_reload_bypass_cache:
2206 * @web_view: a #WebKitWebView
2207 *
2208 * Reloads the current contents of @web_view without
2209 * using any cached data.
2210 */
2211void webkit_web_view_reload_bypass_cache(WebKitWebView* webView)
2212{
2213    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2214
2215    getPage(webView)->reload(true);
2216}
2217
2218/**
2219 * webkit_web_view_stop_loading:
2220 * @web_view: a #WebKitWebView
2221 *
2222 * Stops any ongoing loading operation in @web_view.
2223 * This method does nothing if no content is being loaded.
2224 * If there is a loading operation in progress, it will be cancelled and
2225 * #WebKitWebView::load-failed signal will be emitted with
2226 * %WEBKIT_NETWORK_ERROR_CANCELLED error.
2227 */
2228void webkit_web_view_stop_loading(WebKitWebView* webView)
2229{
2230    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2231
2232    getPage(webView)->stopLoading();
2233}
2234
2235/**
2236 * webkit_web_view_is_loading:
2237 * @web_view: a #WebKitWebView
2238 *
2239 * Gets the value of the #WebKitWebView:is-loading property.
2240 * You can monitor when a #WebKitWebView is loading a page by connecting to
2241 * notify::is-loading signal of @web_view. This is useful when you are
2242 * interesting in knowing when the view is loding something but not in the
2243 * details about the status of the load operation, for example to start a spinner
2244 * when the view is loading a page and stop it when it finishes.
2245 *
2246 * Returns: %TRUE if @web_view is loading a page or %FALSE otherwise.
2247 */
2248gboolean webkit_web_view_is_loading(WebKitWebView* webView)
2249{
2250    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2251
2252    return webView->priv->isLoading;
2253}
2254
2255/**
2256 * webkit_web_view_go_back:
2257 * @web_view: a #WebKitWebView
2258 *
2259 * Loads the previous history item.
2260 * You can monitor the load operation by connecting to
2261 * #WebKitWebView::load-changed signal.
2262 */
2263void webkit_web_view_go_back(WebKitWebView* webView)
2264{
2265    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2266
2267    getPage(webView)->goBack();
2268}
2269
2270/**
2271 * webkit_web_view_can_go_back:
2272 * @web_view: a #WebKitWebView
2273 *
2274 * Determines whether @web_view has a previous history item.
2275 *
2276 * Returns: %TRUE if able to move back or %FALSE otherwise.
2277 */
2278gboolean webkit_web_view_can_go_back(WebKitWebView* webView)
2279{
2280    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2281
2282    return !!getPage(webView)->backForwardList().backItem();
2283}
2284
2285/**
2286 * webkit_web_view_go_forward:
2287 * @web_view: a #WebKitWebView
2288 *
2289 * Loads the next history item.
2290 * You can monitor the load operation by connecting to
2291 * #WebKitWebView::load-changed signal.
2292 */
2293void webkit_web_view_go_forward(WebKitWebView* webView)
2294{
2295    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2296
2297    getPage(webView)->goForward();
2298}
2299
2300/**
2301 * webkit_web_view_can_go_forward:
2302 * @web_view: a #WebKitWebView
2303 *
2304 * Determines whether @web_view has a next history item.
2305 *
2306 * Returns: %TRUE if able to move forward or %FALSE otherwise.
2307 */
2308gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
2309{
2310    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2311
2312    return !!getPage(webView)->backForwardList().forwardItem();
2313}
2314
2315/**
2316 * webkit_web_view_get_uri:
2317 * @web_view: a #WebKitWebView
2318 *
2319 * Returns the current active URI of @web_view. The active URI might change during
2320 * a load operation:
2321 *
2322 * <orderedlist>
2323 * <listitem><para>
2324 *   When nothing has been loaded yet on @web_view the active URI is %NULL.
2325 * </para></listitem>
2326 * <listitem><para>
2327 *   When a new load operation starts the active URI is the requested URI:
2328 *   <itemizedlist>
2329 *   <listitem><para>
2330 *     If the load operation was started by webkit_web_view_load_uri(),
2331 *     the requested URI is the given one.
2332 *   </para></listitem>
2333 *   <listitem><para>
2334 *     If the load operation was started by webkit_web_view_load_html(),
2335 *     the requested URI is "about:blank".
2336 *   </para></listitem>
2337 *   <listitem><para>
2338 *     If the load operation was started by webkit_web_view_load_alternate_html(),
2339 *     the requested URI is content URI provided.
2340 *   </para></listitem>
2341 *   <listitem><para>
2342 *     If the load operation was started by webkit_web_view_go_back() or
2343 *     webkit_web_view_go_forward(), the requested URI is the original URI
2344 *     of the previous/next item in the #WebKitBackForwardList of @web_view.
2345 *   </para></listitem>
2346 *   <listitem><para>
2347 *     If the load operation was started by
2348 *     webkit_web_view_go_to_back_forward_list_item(), the requested URI
2349 *     is the opriginal URI of the given #WebKitBackForwardListItem.
2350 *   </para></listitem>
2351 *   </itemizedlist>
2352 * </para></listitem>
2353 * <listitem><para>
2354 *   If there is a server redirection during the load operation,
2355 *   the active URI is the redirected URI. When the signal
2356 *   #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_REDIRECTED
2357 *   event, the active URI is already updated to the redirected URI.
2358 * </para></listitem>
2359 * <listitem><para>
2360 *   When the signal #WebKitWebView::load-changed is emitted
2361 *   with %WEBKIT_LOAD_COMMITTED event, the active URI is the final
2362 *   one and it will not change unless a new load operation is started
2363 *   or a navigation action within the same page is performed.
2364 * </para></listitem>
2365 * </orderedlist>
2366 *
2367 * You can monitor the active URI by connecting to the notify::uri
2368 * signal of @web_view.
2369 *
2370 * Returns: the current active URI of @web_view or %NULL
2371 *    if nothing has been loaded yet.
2372 */
2373const gchar* webkit_web_view_get_uri(WebKitWebView* webView)
2374{
2375    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2376
2377    return webView->priv->activeURI.data();
2378}
2379
2380/**
2381 * webkit_web_view_get_favicon:
2382 * @web_view: a #WebKitWebView
2383 *
2384 * Returns favicon currently associated to @web_view, if any. You can
2385 * connect to notify::favicon signal of @web_view to be notified when
2386 * the favicon is available.
2387 *
2388 * Returns: (transfer none): a pointer to a #cairo_surface_t with the
2389 *    favicon or %NULL if there's no icon associated with @web_view.
2390 */
2391cairo_surface_t* webkit_web_view_get_favicon(WebKitWebView* webView)
2392{
2393    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2394    if (webView->priv->activeURI.isNull())
2395        return 0;
2396
2397    return webView->priv->favicon.get();
2398}
2399
2400/**
2401 * webkit_web_view_get_custom_charset:
2402 * @web_view: a #WebKitWebView
2403 *
2404 * Returns the current custom character encoding name of @web_view.
2405 *
2406 * Returns: the current custom character encoding name or %NULL if no
2407 *    custom character encoding has been set.
2408 */
2409const gchar* webkit_web_view_get_custom_charset(WebKitWebView* webView)
2410{
2411    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2412
2413    String customTextEncoding = getPage(webView)->customTextEncodingName();
2414    if (customTextEncoding.isEmpty())
2415        return 0;
2416
2417    webView->priv->customTextEncoding = customTextEncoding.utf8();
2418    return webView->priv->customTextEncoding.data();
2419}
2420
2421/**
2422 * webkit_web_view_set_custom_charset:
2423 * @web_view: a #WebKitWebView
2424 * @charset: (allow-none): a character encoding name or %NULL
2425 *
2426 * Sets the current custom character encoding override of @web_view. The custom
2427 * character encoding will override any text encoding detected via HTTP headers or
2428 * META tags. Calling this method will stop any current load operation and reload the
2429 * current page. Setting the custom character encoding to %NULL removes the character
2430 * encoding override.
2431 */
2432void webkit_web_view_set_custom_charset(WebKitWebView* webView, const gchar* charset)
2433{
2434    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2435
2436    getPage(webView)->setCustomTextEncodingName(String::fromUTF8(charset));
2437}
2438
2439/**
2440 * webkit_web_view_get_estimated_load_progress:
2441 * @web_view: a #WebKitWebView
2442 *
2443 * Gets the value of the #WebKitWebView:estimated-load-progress property.
2444 * You can monitor the estimated progress of a load operation by
2445 * connecting to the notify::estimated-load-progress signal of @web_view.
2446 *
2447 * Returns: an estimate of the of the percent complete for a document
2448 *     load as a range from 0.0 to 1.0.
2449 */
2450gdouble webkit_web_view_get_estimated_load_progress(WebKitWebView* webView)
2451{
2452    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2453    return webView->priv->estimatedLoadProgress;
2454}
2455
2456/**
2457 * webkit_web_view_get_back_forward_list:
2458 * @web_view: a #WebKitWebView
2459 *
2460 * Obtains the #WebKitBackForwardList associated with the given #WebKitWebView. The
2461 * #WebKitBackForwardList is owned by the #WebKitWebView.
2462 *
2463 * Returns: (transfer none): the #WebKitBackForwardList
2464 */
2465WebKitBackForwardList* webkit_web_view_get_back_forward_list(WebKitWebView* webView)
2466{
2467    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2468
2469    return webView->priv->backForwardList.get();
2470}
2471
2472/**
2473 * webkit_web_view_go_to_back_forward_list_item:
2474 * @web_view: a #WebKitWebView
2475 * @list_item: a #WebKitBackForwardListItem
2476 *
2477 * Loads the specific history item @list_item.
2478 * You can monitor the load operation by connecting to
2479 * #WebKitWebView::load-changed signal.
2480 */
2481void webkit_web_view_go_to_back_forward_list_item(WebKitWebView* webView, WebKitBackForwardListItem* listItem)
2482{
2483    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2484    g_return_if_fail(WEBKIT_IS_BACK_FORWARD_LIST_ITEM(listItem));
2485
2486    getPage(webView)->goToBackForwardItem(webkitBackForwardListItemGetItem(listItem));
2487}
2488
2489/**
2490 * webkit_web_view_set_settings:
2491 * @web_view: a #WebKitWebView
2492 * @settings: a #WebKitSettings
2493 *
2494 * Sets the #WebKitSettings to be applied to @web_view.
2495 * This is a convenient method to set new settings to the
2496 * #WebKitWebViewGroup @web_view belongs to.
2497 * New settings are applied immediately on all #WebKitWebView<!-- -->s
2498 * in the @web_view group.
2499 * See also webkit_web_view_group_set_settings().
2500 */
2501void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settings)
2502{
2503    webkit_web_view_group_set_settings(webkit_web_view_get_group(webView), settings);
2504}
2505
2506/**
2507 * webkit_web_view_get_settings:
2508 * @web_view: a #WebKitWebView
2509 *
2510 * Gets the #WebKitSettings currently applied to @web_view.
2511 * This is a convenient method to get the settings of the
2512 * #WebKitWebViewGroup @web_view belongs to.
2513 * #WebKitSettings objects are shared by all the #WebKitWebView<!-- -->s
2514 * in the same #WebKitWebViewGroup, so modifying
2515 * the settings of a #WebKitWebView would affect other
2516 * #WebKitWebView<!-- -->s of the same group.
2517 * See also webkit_web_view_group_get_settings().
2518 *
2519 * Returns: (transfer none): the #WebKitSettings attached to @web_view
2520 */
2521WebKitSettings* webkit_web_view_get_settings(WebKitWebView* webView)
2522{
2523    return webkit_web_view_group_get_settings(webkit_web_view_get_group(webView));
2524}
2525
2526/**
2527 * webkit_web_view_get_window_properties:
2528 * @web_view: a #WebKitWebView
2529 *
2530 * Get the #WebKitWindowProperties object containing the properties
2531 * that the window containing @web_view should have.
2532 *
2533 * Returns: (transfer none): the #WebKitWindowProperties of @web_view
2534 */
2535WebKitWindowProperties* webkit_web_view_get_window_properties(WebKitWebView* webView)
2536{
2537    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2538
2539    return webView->priv->windowProperties.get();
2540}
2541
2542/**
2543 * webkit_web_view_set_zoom_level:
2544 * @web_view: a #WebKitWebView
2545 * @zoom_level: the zoom level
2546 *
2547 * Set the zoom level of @web_view, i.e. the factor by which the
2548 * view contents are scaled with respect to their original size.
2549 */
2550void webkit_web_view_set_zoom_level(WebKitWebView* webView, gdouble zoomLevel)
2551{
2552    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2553
2554    if (webkit_web_view_get_zoom_level(webView) == zoomLevel)
2555        return;
2556
2557    WebPageProxy* page = getPage(webView);
2558    if (webkit_settings_get_zoom_text_only(webkit_web_view_get_settings(webView)))
2559        page->setTextZoomFactor(zoomLevel);
2560    else
2561        page->setPageZoomFactor(zoomLevel);
2562    g_object_notify(G_OBJECT(webView), "zoom-level");
2563}
2564
2565/**
2566 * webkit_web_view_get_zoom_level:
2567 * @web_view: a #WebKitWebView
2568 *
2569 * Get the zoom level of @web_view, i.e. the factor by which the
2570 * view contents are scaled with respect to their original size.
2571 *
2572 * Returns: the current zoom level of @web_view
2573 */
2574gdouble webkit_web_view_get_zoom_level(WebKitWebView* webView)
2575{
2576    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1);
2577
2578    WebPageProxy* page = getPage(webView);
2579    gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webkit_web_view_get_settings(webView));
2580    return zoomTextOnly ? page->textZoomFactor() : page->pageZoomFactor();
2581}
2582
2583/**
2584 * webkit_web_view_can_execute_editing_command:
2585 * @web_view: a #WebKitWebView
2586 * @command: the command to check
2587 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2588 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
2589 * @user_data: (closure): the data to pass to callback function
2590 *
2591 * Asynchronously execute the given editing command.
2592 *
2593 * When the operation is finished, @callback will be called. You can then call
2594 * webkit_web_view_can_execute_editing_command_finish() to get the result of the operation.
2595 */
2596void webkit_web_view_can_execute_editing_command(WebKitWebView* webView, const char* command, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2597{
2598    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2599    g_return_if_fail(command);
2600
2601    GTask* task = g_task_new(webView, cancellable, callback, userData);
2602    getPage(webView)->validateCommand(String::fromUTF8(command), [task](const String&, bool isEnabled, int32_t, CallbackBase::Error) {
2603        g_task_return_boolean(adoptGRef(task).get(), isEnabled);
2604    });
2605}
2606
2607/**
2608 * webkit_web_view_can_execute_editing_command_finish:
2609 * @web_view: a #WebKitWebView
2610 * @result: a #GAsyncResult
2611 * @error: return location for error or %NULL to ignore
2612 *
2613 * Finish an asynchronous operation started with webkit_web_view_can_execute_editing_command().
2614 *
2615 * Returns: %TRUE if the editing command can be executed or %FALSE otherwise
2616 */
2617gboolean webkit_web_view_can_execute_editing_command_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2618{
2619    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2620    g_return_val_if_fail(g_task_is_valid(result, webView), FALSE);
2621
2622    return g_task_propagate_boolean(G_TASK(result), error);
2623}
2624
2625/**
2626 * webkit_web_view_execute_editing_command:
2627 * @web_view: a #WebKitWebView
2628 * @command: the command to execute
2629 *
2630 * Request to execute the given @command for @web_view. You can use
2631 * webkit_web_view_can_execute_editing_command() to check whether
2632 * it's possible to execute the command.
2633 */
2634void webkit_web_view_execute_editing_command(WebKitWebView* webView, const char* command)
2635{
2636    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2637    g_return_if_fail(command);
2638
2639    getPage(webView)->executeEditCommand(String::fromUTF8(command));
2640}
2641
2642/**
2643 * webkit_web_view_get_find_controller:
2644 * @web_view: the #WebKitWebView
2645 *
2646 * Gets the #WebKitFindController that will allow the caller to query
2647 * the #WebKitWebView for the text to look for.
2648 *
2649 * Returns: (transfer none): the #WebKitFindController associated to
2650 * this particular #WebKitWebView.
2651 */
2652WebKitFindController* webkit_web_view_get_find_controller(WebKitWebView* webView)
2653{
2654    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2655
2656    if (!webView->priv->findController)
2657        webView->priv->findController = adoptGRef(WEBKIT_FIND_CONTROLLER(g_object_new(WEBKIT_TYPE_FIND_CONTROLLER, "web-view", webView, NULL)));
2658
2659    return webView->priv->findController.get();
2660}
2661
2662/**
2663 * webkit_web_view_get_javascript_global_context:
2664 * @web_view: a #WebKitWebView
2665 *
2666 * Get the global JavaScript context used by @web_view to deserialize the
2667 * result values of scripts executed with webkit_web_view_run_javascript().
2668 *
2669 * Returns: the <function>JSGlobalContextRef</function> used by @web_view to deserialize
2670 *    the result values of scripts.
2671 */
2672JSGlobalContextRef webkit_web_view_get_javascript_global_context(WebKitWebView* webView)
2673{
2674    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2675
2676    if (!webView->priv->javascriptGlobalContext)
2677        webView->priv->javascriptGlobalContext = JSGlobalContextCreate(0);
2678    return webView->priv->javascriptGlobalContext;
2679}
2680
2681static void webkitWebViewRunJavaScriptCallback(WebSerializedScriptValue* wkSerializedScriptValue, GTask* task)
2682{
2683    if (g_task_return_error_if_cancelled(task))
2684        return;
2685
2686    if (!wkSerializedScriptValue) {
2687        g_task_return_new_error(task, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED,
2688            _("An exception was raised in JavaScript"));
2689        return;
2690    }
2691
2692    WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task));
2693    g_task_return_pointer(task, webkitJavascriptResultCreate(webView, wkSerializedScriptValue),
2694        reinterpret_cast<GDestroyNotify>(webkit_javascript_result_unref));
2695}
2696
2697/**
2698 * webkit_web_view_run_javascript:
2699 * @web_view: a #WebKitWebView
2700 * @script: the script to run
2701 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2702 * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
2703 * @user_data: (closure): the data to pass to callback function
2704 *
2705 * Asynchronously run @script in the context of the current page in @web_view. If
2706 * WebKitWebSettings:enable-javascript is FALSE, this method will do nothing.
2707 *
2708 * When the operation is finished, @callback will be called. You can then call
2709 * webkit_web_view_run_javascript_finish() to get the result of the operation.
2710 */
2711void webkit_web_view_run_javascript(WebKitWebView* webView, const gchar* script, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2712{
2713    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2714    g_return_if_fail(script);
2715
2716    GTask* task = g_task_new(webView, cancellable, callback, userData);
2717    getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(script), [task](WebSerializedScriptValue* serializedScriptValue, CallbackBase::Error) {
2718        webkitWebViewRunJavaScriptCallback(serializedScriptValue, adoptGRef(task).get());
2719    });
2720}
2721
2722/**
2723 * webkit_web_view_run_javascript_finish:
2724 * @web_view: a #WebKitWebView
2725 * @result: a #GAsyncResult
2726 * @error: return location for error or %NULL to ignore
2727 *
2728 * Finish an asynchronous operation started with webkit_web_view_run_javascript().
2729 *
2730 * This is an example of using webkit_web_view_run_javascript() with a script returning
2731 * a string:
2732 *
2733 * <informalexample><programlisting>
2734 * static void
2735 * web_view_javascript_finished (GObject      *object,
2736 *                               GAsyncResult *result,
2737 *                               gpointer      user_data)
2738 * {
2739 *     WebKitJavascriptResult *js_result;
2740 *     JSValueRef              value;
2741 *     JSGlobalContextRef      context;
2742 *     GError                 *error = NULL;
2743 *
2744 *     js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
2745 *     if (!js_result) {
2746 *         g_warning ("Error running javascript: %s", error->message);
2747 *         g_error_free (error);
2748 *         return;
2749 *     }
2750 *
2751 *     context = webkit_javascript_result_get_global_context (js_result);
2752 *     value = webkit_javascript_result_get_value (js_result);
2753 *     if (JSValueIsString (context, value)) {
2754 *         JSStringRef js_str_value;
2755 *         gchar      *str_value;
2756 *         gsize       str_length;
2757 *
2758 *         js_str_value = JSValueToStringCopy (context, value, NULL);
2759 *         str_length = JSStringGetMaximumUTF8CStringSize (js_str_value);
2760 *         str_value = (gchar *)g_malloc (str_length);
2761 *         JSStringGetUTF8CString (js_str_value, str_value, str_length);
2762 *         JSStringRelease (js_str_value);
2763 *         g_print ("Script result: %s\n", str_value);
2764 *         g_free (str_value);
2765 *     } else {
2766 *         g_warning ("Error running javascript: unexpected return value");
2767 *     }
2768 *     webkit_javascript_result_unref (js_result);
2769 * }
2770 *
2771 * static void
2772 * web_view_get_link_url (WebKitWebView *web_view,
2773 *                        const gchar   *link_id)
2774 * {
2775 *     gchar *script;
2776 *
2777 *     script = g_strdup_printf ("window.document.getElementById('%s').href;", link_id);
2778 *     webkit_web_view_run_javascript (web_view, script, NULL, web_view_javascript_finished, NULL);
2779 *     g_free (script);
2780 * }
2781 * </programlisting></informalexample>
2782 *
2783 * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
2784 *    or %NULL in case of error
2785 */
2786WebKitJavascriptResult* webkit_web_view_run_javascript_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2787{
2788    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2789    g_return_val_if_fail(g_task_is_valid(result, webView), 0);
2790
2791    return static_cast<WebKitJavascriptResult*>(g_task_propagate_pointer(G_TASK(result), error));
2792}
2793
2794static void resourcesStreamReadCallback(GObject* object, GAsyncResult* result, gpointer userData)
2795{
2796    GRefPtr<GTask> task = adoptGRef(G_TASK(userData));
2797
2798    GError* error = 0;
2799    g_output_stream_splice_finish(G_OUTPUT_STREAM(object), result, &error);
2800    if (error) {
2801        g_task_return_error(task.get(), error);
2802        return;
2803    }
2804
2805    WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task.get()));
2806    gpointer outputStreamData = g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(object));
2807    getPage(webView)->runJavaScriptInMainFrame(String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)),
2808        [task](WebSerializedScriptValue* serializedScriptValue, CallbackBase::Error) {
2809            webkitWebViewRunJavaScriptCallback(serializedScriptValue, task.get());
2810        });
2811}
2812
2813/**
2814 * webkit_web_view_run_javascript_from_gresource:
2815 * @web_view: a #WebKitWebView
2816 * @resource: the location of the resource to load
2817 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2818 * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
2819 * @user_data: (closure): the data to pass to callback function
2820 *
2821 * Asynchronously run the script from @resource in the context of the
2822 * current page in @web_view.
2823 *
2824 * When the operation is finished, @callback will be called. You can
2825 * then call webkit_web_view_run_javascript_from_gresource_finish() to get the result
2826 * of the operation.
2827 */
2828void webkit_web_view_run_javascript_from_gresource(WebKitWebView* webView, const gchar* resource, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2829{
2830    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2831    g_return_if_fail(resource);
2832
2833    GError* error = 0;
2834    GRefPtr<GInputStream> inputStream = adoptGRef(g_resources_open_stream(resource, G_RESOURCE_LOOKUP_FLAGS_NONE, &error));
2835    if (error) {
2836        g_task_report_error(webView, callback, userData, 0, error);
2837        return;
2838    }
2839
2840    GTask* task = g_task_new(webView, cancellable, callback, userData);
2841    GRefPtr<GOutputStream> outputStream = adoptGRef(g_memory_output_stream_new(0, 0, fastRealloc, fastFree));
2842    g_output_stream_splice_async(outputStream.get(), inputStream.get(),
2843        static_cast<GOutputStreamSpliceFlags>(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
2844        G_PRIORITY_DEFAULT, cancellable, resourcesStreamReadCallback, task);
2845}
2846
2847/**
2848 * webkit_web_view_run_javascript_from_gresource_finish:
2849 * @web_view: a #WebKitWebView
2850 * @result: a #GAsyncResult
2851 * @error: return location for error or %NULL to ignore
2852 *
2853 * Finish an asynchronous operation started with webkit_web_view_run_javascript_from_gresource().
2854 *
2855 * Check webkit_web_view_run_javascript_finish() for a usage example.
2856 *
2857 * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
2858 *    or %NULL in case of error
2859 */
2860WebKitJavascriptResult* webkit_web_view_run_javascript_from_gresource_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
2861{
2862    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2863    g_return_val_if_fail(g_task_is_valid(result, webView), 0);
2864
2865    return static_cast<WebKitJavascriptResult*>(g_task_propagate_pointer(G_TASK(result), error));
2866}
2867
2868/**
2869 * webkit_web_view_get_main_resource:
2870 * @web_view: a #WebKitWebView
2871 *
2872 * Return the main resource of @web_view.
2873 *
2874 * Returns: (transfer none): the main #WebKitWebResource of the view
2875 *    or %NULL if nothing has been loaded.
2876 */
2877WebKitWebResource* webkit_web_view_get_main_resource(WebKitWebView* webView)
2878{
2879    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2880
2881    return webView->priv->mainResource.get();
2882}
2883
2884/**
2885 * webkit_web_view_get_inspector:
2886 * @web_view: a #WebKitWebView
2887 *
2888 * Get the #WebKitWebInspector associated to @web_view
2889 *
2890 * Returns: (transfer none): the #WebKitWebInspector of @web_view
2891 */
2892WebKitWebInspector* webkit_web_view_get_inspector(WebKitWebView* webView)
2893{
2894    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2895
2896    if (!webView->priv->inspector)
2897        webView->priv->inspector = adoptGRef(webkitWebInspectorCreate(getPage(webView)->inspector()));
2898
2899    return webView->priv->inspector.get();
2900}
2901
2902/**
2903 * webkit_web_view_can_show_mime_type:
2904 * @web_view: a #WebKitWebView
2905 * @mime_type: a MIME type
2906 *
2907 * Whether or not a MIME type can be displayed in @web_view.
2908 *
2909 * Returns: %TRUE if the MIME type @mime_type can be displayed or %FALSE otherwise
2910 */
2911gboolean webkit_web_view_can_show_mime_type(WebKitWebView* webView, const char* mimeType)
2912{
2913    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2914    g_return_val_if_fail(mimeType, FALSE);
2915
2916    return getPage(webView)->canShowMIMEType(String::fromUTF8(mimeType));
2917}
2918
2919struct ViewSaveAsyncData {
2920    RefPtr<API::Data> webData;
2921    GRefPtr<GFile> file;
2922};
2923WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ViewSaveAsyncData)
2924
2925static void fileReplaceContentsCallback(GObject* object, GAsyncResult* result, gpointer data)
2926{
2927    GRefPtr<GTask> task = adoptGRef(G_TASK(data));
2928    GError* error = 0;
2929    if (!g_file_replace_contents_finish(G_FILE(object), result, 0, &error)) {
2930        g_task_return_error(task.get(), error);
2931        return;
2932    }
2933
2934    g_task_return_boolean(task.get(), TRUE);
2935}
2936
2937static void getContentsAsMHTMLDataCallback(API::Data* wkData, GTask* taskPtr)
2938{
2939    GRefPtr<GTask> task = adoptGRef(taskPtr);
2940    if (g_task_return_error_if_cancelled(task.get()))
2941        return;
2942
2943    ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task.get()));
2944    // We need to retain the data until the asyncronous process
2945    // initiated by the user has finished completely.
2946    data->webData = wkData;
2947
2948    // If we are saving to a file we need to write the data on disk before finishing.
2949    if (g_task_get_source_tag(task.get()) == webkit_web_view_save_to_file) {
2950        ASSERT(G_IS_FILE(data->file.get()));
2951        GCancellable* cancellable = g_task_get_cancellable(task.get());
2952        g_file_replace_contents_async(data->file.get(), reinterpret_cast<const gchar*>(data->webData->bytes()), data->webData->size(),
2953            0, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, cancellable, fileReplaceContentsCallback, task.leakRef());
2954        return;
2955    }
2956
2957    g_task_return_boolean(task.get(), TRUE);
2958}
2959
2960/**
2961 * webkit_web_view_save:
2962 * @web_view: a #WebKitWebView
2963 * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
2964 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
2965 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
2966 * @user_data: (closure): the data to pass to callback function
2967 *
2968 * Asynchronously save the current web page associated to the
2969 * #WebKitWebView into a self-contained format using the mode
2970 * specified in @save_mode.
2971 *
2972 * When the operation is finished, @callback will be called. You can
2973 * then call webkit_web_view_save_finish() to get the result of the
2974 * operation.
2975 */
2976void webkit_web_view_save(WebKitWebView* webView, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
2977{
2978    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2979
2980    // We only support MHTML at the moment.
2981    g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
2982
2983    GTask* task = g_task_new(webView, cancellable, callback, userData);
2984    g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save));
2985    g_task_set_task_data(task, createViewSaveAsyncData(), reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
2986    getPage(webView)->getContentsAsMHTMLData([task](API::Data* data, CallbackBase::Error) {
2987        getContentsAsMHTMLDataCallback(data, task);
2988    }, false);
2989}
2990
2991/**
2992 * webkit_web_view_save_finish:
2993 * @web_view: a #WebKitWebView
2994 * @result: a #GAsyncResult
2995 * @error: return location for error or %NULL to ignore
2996 *
2997 * Finish an asynchronous operation started with webkit_web_view_save().
2998 *
2999 * Returns: (transfer full): a #GInputStream with the result of saving
3000 *    the current web page or %NULL in case of error.
3001 */
3002GInputStream* webkit_web_view_save_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3003{
3004    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3005    g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3006
3007    GTask* task = G_TASK(result);
3008    if (!g_task_propagate_boolean(task, error))
3009        return 0;
3010
3011    GInputStream* dataStream = g_memory_input_stream_new();
3012    ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task));
3013    gsize length = data->webData->size();
3014    if (length)
3015        g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(dataStream), g_memdup(data->webData->bytes(), length), length, g_free);
3016
3017    return dataStream;
3018}
3019
3020/**
3021 * webkit_web_view_save_to_file:
3022 * @web_view: a #WebKitWebView
3023 * @file: the #GFile where the current web page should be saved to.
3024 * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
3025 * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3026 * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
3027 * @user_data: (closure): the data to pass to callback function
3028 *
3029 * Asynchronously save the current web page associated to the
3030 * #WebKitWebView into a self-contained format using the mode
3031 * specified in @save_mode and writing it to @file.
3032 *
3033 * When the operation is finished, @callback will be called. You can
3034 * then call webkit_web_view_save_to_file_finish() to get the result of the
3035 * operation.
3036 */
3037void webkit_web_view_save_to_file(WebKitWebView* webView, GFile* file, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3038{
3039    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3040    g_return_if_fail(G_IS_FILE(file));
3041
3042    // We only support MHTML at the moment.
3043    g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
3044
3045    GTask* task = g_task_new(webView, cancellable, callback, userData);
3046    g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save_to_file));
3047    ViewSaveAsyncData* data = createViewSaveAsyncData();
3048    data->file = file;
3049    g_task_set_task_data(task, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
3050
3051    getPage(webView)->getContentsAsMHTMLData([task](API::Data* data, CallbackBase::Error) {
3052        getContentsAsMHTMLDataCallback(data, task);
3053    }, false);
3054}
3055
3056/**
3057 * webkit_web_view_save_to_file_finish:
3058 * @web_view: a #WebKitWebView
3059 * @result: a #GAsyncResult
3060 * @error: return location for error or %NULL to ignore
3061 *
3062 * Finish an asynchronous operation started with webkit_web_view_save_to_file().
3063 *
3064 * Returns: %TRUE if the web page was successfully saved to a file or %FALSE otherwise.
3065 */
3066gboolean webkit_web_view_save_to_file_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3067{
3068    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3069    g_return_val_if_fail(g_task_is_valid(result, webView), FALSE);
3070
3071    return g_task_propagate_boolean(G_TASK(result), error);
3072}
3073
3074/**
3075 * webkit_web_view_download_uri:
3076 * @web_view: a #WebKitWebView
3077 * @uri: the URI to download
3078 *
3079 * Requests downloading of the specified URI string for @web_view.
3080 *
3081 * Returns: (transfer full): a new #WebKitDownload representing the
3082 *    the download operation.
3083 */
3084WebKitDownload* webkit_web_view_download_uri(WebKitWebView* webView, const char* uri)
3085{
3086    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3087    g_return_val_if_fail(uri, 0);
3088
3089    WebKitDownload* download = webkitWebContextStartDownload(webView->priv->context, uri, getPage(webView));
3090    webkitDownloadSetWebView(download, webView);
3091
3092    return download;
3093}
3094
3095/**
3096 * webkit_web_view_get_tls_info:
3097 * @web_view: a #WebKitWebView
3098 * @certificate: (out) (transfer none): return location for a #GTlsCertificate
3099 * @errors: (out): return location for a #GTlsCertificateFlags the verification status of @certificate
3100 *
3101 * Retrieves the #GTlsCertificate associated with the @web_view connection,
3102 * and the #GTlsCertificateFlags showing what problems, if any, have been found
3103 * with that certificate.
3104 * If the connection is not HTTPS, this function returns %FALSE.
3105 * This function should be called after a response has been received from the
3106 * server, so you can connect to #WebKitWebView::load-changed and call this function
3107 * when it's emitted with %WEBKIT_LOAD_COMMITTED event.
3108 *
3109 * Returns: %TRUE if the @web_view connection uses HTTPS and a response has been received
3110 *    from the server, or %FALSE otherwise.
3111 */
3112gboolean webkit_web_view_get_tls_info(WebKitWebView* webView, GTlsCertificate** certificate, GTlsCertificateFlags* errors)
3113{
3114    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3115
3116    WebFrameProxy* mainFrame = getPage(webView)->mainFrame();
3117    if (!mainFrame)
3118        return FALSE;
3119
3120    const WebCore::CertificateInfo& certificateInfo = mainFrame->certificateInfo()->certificateInfo();
3121    if (certificate)
3122        *certificate = certificateInfo.certificate();
3123    if (errors)
3124        *errors = certificateInfo.tlsErrors();
3125
3126    return !!certificateInfo.certificate();
3127}
3128
3129void webKitWebViewDidReceiveSnapshot(WebKitWebView* webView, uint64_t callbackID, WebImage* webImage)
3130{
3131    GRefPtr<GTask> task = webView->priv->snapshotResultsMap.take(callbackID);
3132    if (g_task_return_error_if_cancelled(task.get()))
3133        return;
3134
3135    if (!webImage) {
3136        g_task_return_new_error(task.get(), WEBKIT_SNAPSHOT_ERROR, WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE,
3137            _("There was an error creating the snapshot"));
3138        return;
3139    }
3140
3141    if (RefPtr<ShareableBitmap> image = webImage->bitmap())
3142        g_task_return_pointer(task.get(), image->createCairoSurface().leakRef(), reinterpret_cast<GDestroyNotify>(cairo_surface_destroy));
3143    else
3144        g_task_return_pointer(task.get(), 0, 0);
3145}
3146
3147static inline unsigned webKitSnapshotOptionsToSnapshotOptions(WebKitSnapshotOptions options)
3148{
3149    SnapshotOptions snapshotOptions = 0;
3150
3151    if (!(options & WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING))
3152        snapshotOptions |= SnapshotOptionsExcludeSelectionHighlighting;
3153
3154    return snapshotOptions;
3155}
3156
3157static inline SnapshotRegion toSnapshotRegion(WebKitSnapshotRegion region)
3158{
3159    switch (region) {
3160    case WEBKIT_SNAPSHOT_REGION_VISIBLE:
3161        return SnapshotRegionVisible;
3162    case WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT:
3163        return SnapshotRegionFullDocument;
3164    default:
3165        ASSERT_NOT_REACHED();
3166        return SnapshotRegionVisible;
3167    }
3168}
3169
3170static inline uint64_t generateSnapshotCallbackID()
3171{
3172    static uint64_t uniqueCallbackID = 1;
3173    return uniqueCallbackID++;
3174}
3175
3176/**
3177 * webkit_web_view_get_snapshot:
3178 * @web_view: a #WebKitWebView
3179 * @options: #WebKitSnapshotOptions for the snapshot
3180 * @region: the #WebKitSnapshotRegion for this snapshot
3181 * @cancellable: (allow-none): a #GCancellable
3182 * @callback: (scope async): a #GAsyncReadyCallback
3183 * @user_data: (closure): user data
3184 *
3185 * Asynchronously retrieves a snapshot of @web_view for @region.
3186 * @options specifies how the snapshot should be rendered.
3187 *
3188 * When the operation is finished, @callback will be called. You must
3189 * call webkit_web_view_get_snapshot_finish() to get the result of the
3190 * operation.
3191 */
3192void webkit_web_view_get_snapshot(WebKitWebView* webView, WebKitSnapshotRegion region, WebKitSnapshotOptions options, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3193{
3194    g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3195
3196    ImmutableDictionary::MapType message;
3197    uint64_t callbackID = generateSnapshotCallbackID();
3198    message.set(String::fromUTF8("SnapshotOptions"), API::UInt64::create(static_cast<uint64_t>(webKitSnapshotOptionsToSnapshotOptions(options))));
3199    message.set(String::fromUTF8("SnapshotRegion"), API::UInt64::create(static_cast<uint64_t>(toSnapshotRegion(region))));
3200    message.set(String::fromUTF8("CallbackID"), API::UInt64::create(callbackID));
3201
3202    webView->priv->snapshotResultsMap.set(callbackID, adoptGRef(g_task_new(webView, cancellable, callback, userData)));
3203    getPage(webView)->postMessageToInjectedBundle(String::fromUTF8("GetSnapshot"), ImmutableDictionary::create(WTF::move(message)).get());
3204}
3205
3206/**
3207 * webkit_web_view_get_snapshot_finish:
3208 * @web_view: a #WebKitWebView
3209 * @result: a #GAsyncResult
3210 * @error: return location for error or %NULL to ignore
3211 *
3212 * Finishes an asynchronous operation started with webkit_web_view_get_snapshot().
3213 *
3214 * Returns: (transfer full): a #cairo_surface_t with the retrieved snapshot or %NULL in error.
3215 */
3216cairo_surface_t* webkit_web_view_get_snapshot_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3217{
3218    g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3219    g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3220
3221    return static_cast<cairo_surface_t*>(g_task_propagate_pointer(G_TASK(result), error));
3222}
3223
3224void webkitWebViewWebProcessCrashed(WebKitWebView* webView)
3225{
3226    gboolean returnValue;
3227    g_signal_emit(webView, signals[WEB_PROCESS_CRASHED], 0, &returnValue);
3228}
3229
3230