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