79b90d020d8f9a7b1a86fcefc876dec7263c4ceb
[WebKit-https.git] / Source / WebKit / UIProcess / API / glib / WebKitWebView.cpp
1 /*
2  * Copyright (C) 2011 Igalia S.L.
3  * Portions Copyright (c) 2011 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2014 Collabora Ltd.
5  * Copyright (C) 2017 Igalia S.L.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "WebKitWebView.h"
25
26 #include "APIData.h"
27 #include "APISerializedScriptValue.h"
28 #include "ImageOptions.h"
29 #include "WebCertificateInfo.h"
30 #include "WebContextMenuItem.h"
31 #include "WebContextMenuItemData.h"
32 #include "WebKitAuthenticationRequestPrivate.h"
33 #include "WebKitBackForwardListPrivate.h"
34 #include "WebKitContextMenuClient.h"
35 #include "WebKitContextMenuItemPrivate.h"
36 #include "WebKitContextMenuPrivate.h"
37 #include "WebKitDownloadPrivate.h"
38 #include "WebKitEditingCommands.h"
39 #include "WebKitEditorStatePrivate.h"
40 #include "WebKitEnumTypes.h"
41 #include "WebKitError.h"
42 #include "WebKitFaviconDatabasePrivate.h"
43 #include "WebKitFormClient.h"
44 #include "WebKitHitTestResultPrivate.h"
45 #include "WebKitIconLoadingClient.h"
46 #include "WebKitInstallMissingMediaPluginsPermissionRequestPrivate.h"
47 #include "WebKitJavascriptResultPrivate.h"
48 #include "WebKitLoaderClient.h"
49 #include "WebKitNotificationPrivate.h"
50 #include "WebKitPolicyClient.h"
51 #include "WebKitPrivate.h"
52 #include "WebKitResponsePolicyDecision.h"
53 #include "WebKitScriptDialogPrivate.h"
54 #include "WebKitSettingsPrivate.h"
55 #include "WebKitUIClient.h"
56 #include "WebKitURIRequestPrivate.h"
57 #include "WebKitURIResponsePrivate.h"
58 #include "WebKitWebContextPrivate.h"
59 #include "WebKitWebResourcePrivate.h"
60 #include "WebKitWebViewPrivate.h"
61 #include "WebKitWebViewSessionStatePrivate.h"
62 #include "WebKitWebsiteDataManagerPrivate.h"
63 #include "WebKitWindowPropertiesPrivate.h"
64 #include <JavaScriptCore/APICast.h>
65 #include <JavaScriptCore/JSRetainPtr.h>
66 #include <WebCore/CertificateInfo.h>
67 #include <WebCore/GUniquePtrSoup.h>
68 #include <WebCore/JSDOMExceptionHandling.h>
69 #include <WebCore/RefPtrCairo.h>
70 #include <WebCore/URL.h>
71 #include <glib/gi18n-lib.h>
72 #include <wtf/SetForScope.h>
73 #include <wtf/glib/GRefPtr.h>
74 #include <wtf/glib/WTFGType.h>
75 #include <wtf/text/CString.h>
76 #include <wtf/text/StringBuilder.h>
77
78 #if PLATFORM(GTK)
79 #include "WebKitPrintOperationPrivate.h"
80 #include "WebKitWebInspectorPrivate.h"
81 #include "WebKitWebViewBasePrivate.h"
82 #include <WebCore/GUniquePtrGtk.h>
83 #endif
84
85 #if PLATFORM(WPE)
86 #include "APIViewClient.h"
87 #include "WPEView.h"
88 #endif
89
90 #if USE(LIBNOTIFY)
91 #include <libnotify/notify.h>
92 #endif
93
94 using namespace WebKit;
95 using namespace WebCore;
96
97 /**
98  * SECTION: WebKitWebView
99  * @Short_description: The central class of the WebKit2GTK+ API
100  * @Title: WebKitWebView
101  *
102  * #WebKitWebView is the central class of the WebKit2GTK+ API. It is
103  * responsible for managing the drawing of the content and forwarding
104  * of events. You can load any URI into the #WebKitWebView or a data
105  * string. With #WebKitSettings you can control various aspects of the
106  * rendering and loading of the content.
107  *
108  * Note that #WebKitWebView is scrollable by itself, so you don't need
109  * to embed it in a #GtkScrolledWindow.
110  */
111
112 enum {
113     LOAD_CHANGED,
114     LOAD_FAILED,
115     LOAD_FAILED_WITH_TLS_ERRORS,
116
117     CREATE,
118     READY_TO_SHOW,
119     RUN_AS_MODAL,
120     CLOSE,
121
122     SCRIPT_DIALOG,
123
124     DECIDE_POLICY,
125     PERMISSION_REQUEST,
126
127     MOUSE_TARGET_CHANGED,
128
129 #if PLATFORM(GTK)
130     PRINT,
131 #endif
132
133     RESOURCE_LOAD_STARTED,
134
135     ENTER_FULLSCREEN,
136     LEAVE_FULLSCREEN,
137
138     RUN_FILE_CHOOSER,
139
140     CONTEXT_MENU,
141     CONTEXT_MENU_DISMISSED,
142
143     SUBMIT_FORM,
144
145     INSECURE_CONTENT_DETECTED,
146
147     WEB_PROCESS_CRASHED,
148
149     AUTHENTICATE,
150
151     SHOW_NOTIFICATION,
152
153 #if PLATFORM(GTK)
154     RUN_COLOR_CHOOSER,
155
156     SHOW_OPTION_MENU,
157 #endif
158
159     LAST_SIGNAL
160 };
161
162 enum {
163     PROP_0,
164
165     PROP_WEB_CONTEXT,
166     PROP_RELATED_VIEW,
167     PROP_SETTINGS,
168     PROP_USER_CONTENT_MANAGER,
169     PROP_TITLE,
170     PROP_ESTIMATED_LOAD_PROGRESS,
171
172 #if PLATFORM(GTK)
173     PROP_FAVICON,
174 #endif
175
176     PROP_URI,
177     PROP_ZOOM_LEVEL,
178     PROP_IS_LOADING,
179     PROP_IS_PLAYING_AUDIO,
180     PROP_IS_EPHEMERAL,
181     PROP_IS_CONTROLLED_BY_AUTOMATION,
182     PROP_EDITABLE
183 };
184
185 typedef HashMap<uint64_t, GRefPtr<WebKitWebResource> > LoadingResourcesMap;
186 typedef HashMap<uint64_t, GRefPtr<GTask> > SnapshotResultsMap;
187
188 class PageLoadStateObserver;
189
190 struct _WebKitWebViewPrivate {
191     ~_WebKitWebViewPrivate()
192     {
193         // For modal dialogs, make sure the main loop is stopped when finalizing the webView.
194         if (modalLoop && g_main_loop_is_running(modalLoop.get()))
195             g_main_loop_quit(modalLoop.get());
196     }
197
198 #if PLATFORM(WPE)
199     std::unique_ptr<WKWPE::View> view;
200 #endif
201
202     WebKitWebView* relatedView;
203     CString title;
204     CString customTextEncoding;
205     CString activeURI;
206     bool isLoading;
207     bool isEphemeral;
208     bool isControlledByAutomation;
209
210     std::unique_ptr<PageLoadStateObserver> loadObserver;
211
212     GRefPtr<WebKitBackForwardList> backForwardList;
213     GRefPtr<WebKitSettings> settings;
214     GRefPtr<WebKitUserContentManager> userContentManager;
215     GRefPtr<WebKitWebContext> context;
216     GRefPtr<WebKitWindowProperties> windowProperties;
217     GRefPtr<WebKitEditorState> editorState;
218
219     GRefPtr<GMainLoop> modalLoop;
220
221     GRefPtr<WebKitHitTestResult> mouseTargetHitTestResult;
222     WebEvent::Modifiers mouseTargetModifiers;
223
224     GRefPtr<WebKitFindController> findController;
225     JSRetainPtr<JSGlobalContextRef> javascriptGlobalContext;
226
227     GRefPtr<WebKitWebResource> mainResource;
228     LoadingResourcesMap loadingResourcesMap;
229
230     WebKitScriptDialog* currentScriptDialog;
231
232 #if PLATFORM(GTK)
233     GRefPtr<WebKitWebInspector> inspector;
234
235     RefPtr<cairo_surface_t> favicon;
236     GRefPtr<GCancellable> faviconCancellable;
237
238     CString faviconURI;
239     unsigned long faviconChangedHandlerID;
240
241     SnapshotResultsMap snapshotResultsMap;
242 #endif
243
244     GRefPtr<WebKitAuthenticationRequest> authenticationRequest;
245
246     GRefPtr<WebKitWebsiteDataManager> websiteDataManager;
247 };
248
249 static guint signals[LAST_SIGNAL] = { 0, };
250
251 #if PLATFORM(GTK)
252 WEBKIT_DEFINE_TYPE(WebKitWebView, webkit_web_view, WEBKIT_TYPE_WEB_VIEW_BASE)
253 #elif PLATFORM(WPE)
254 WEBKIT_DEFINE_TYPE(WebKitWebView, webkit_web_view, G_TYPE_OBJECT)
255 #endif
256
257 static inline WebPageProxy& getPage(WebKitWebView* webView)
258 {
259 #if PLATFORM(GTK)
260     auto* page = webkitWebViewBaseGetPage(reinterpret_cast<WebKitWebViewBase*>(webView));
261     ASSERT(page);
262     return *page;
263 #elif PLATFORM(WPE)
264     ASSERT(webView->priv->view);
265     return webView->priv->view->page();
266 #endif
267 }
268
269 static void webkitWebViewSetIsLoading(WebKitWebView* webView, bool isLoading)
270 {
271     if (webView->priv->isLoading == isLoading)
272         return;
273
274     webView->priv->isLoading = isLoading;
275     g_object_notify(G_OBJECT(webView), "is-loading");
276 }
277
278 void webkitWebViewIsPlayingAudioChanged(WebKitWebView* webView)
279 {
280     g_object_notify(G_OBJECT(webView), "is-playing-audio");
281 }
282
283 class PageLoadStateObserver final : public PageLoadState::Observer {
284 public:
285     PageLoadStateObserver(WebKitWebView* webView)
286         : m_webView(webView)
287     {
288     }
289
290 private:
291     void willChangeIsLoading() override
292     {
293         g_object_freeze_notify(G_OBJECT(m_webView));
294     }
295     void didChangeIsLoading() override
296     {
297         webkitWebViewSetIsLoading(m_webView, getPage(m_webView).pageLoadState().isLoading());
298         g_object_thaw_notify(G_OBJECT(m_webView));
299     }
300
301     void willChangeTitle() override
302     {
303         g_object_freeze_notify(G_OBJECT(m_webView));
304     }
305     void didChangeTitle() override
306     {
307         m_webView->priv->title = getPage(m_webView).pageLoadState().title().utf8();
308         g_object_notify(G_OBJECT(m_webView), "title");
309         g_object_thaw_notify(G_OBJECT(m_webView));
310     }
311
312     void willChangeActiveURL() override
313     {
314         g_object_freeze_notify(G_OBJECT(m_webView));
315     }
316     void didChangeActiveURL() override
317     {
318         m_webView->priv->activeURI = getPage(m_webView).pageLoadState().activeURL().utf8();
319         g_object_notify(G_OBJECT(m_webView), "uri");
320         g_object_thaw_notify(G_OBJECT(m_webView));
321     }
322
323     void willChangeHasOnlySecureContent() override { }
324     void didChangeHasOnlySecureContent() override { }
325
326     void willChangeEstimatedProgress() override
327     {
328         g_object_freeze_notify(G_OBJECT(m_webView));
329     }
330     void didChangeEstimatedProgress() override
331     {
332         g_object_notify(G_OBJECT(m_webView), "estimated-load-progress");
333         g_object_thaw_notify(G_OBJECT(m_webView));
334     }
335
336     void willChangeCanGoBack() override { }
337     void didChangeCanGoBack() override { }
338     void willChangeCanGoForward() override { }
339     void didChangeCanGoForward() override { }
340     void willChangeNetworkRequestsInProgress() override { }
341     void didChangeNetworkRequestsInProgress() override { }
342     void willChangeCertificateInfo() override { }
343     void didChangeCertificateInfo() override { }
344     void willChangeWebProcessIsResponsive() override { }
345     void didChangeWebProcessIsResponsive() override { }
346
347     WebKitWebView* m_webView;
348 };
349
350 #if PLATFORM(WPE)
351 class WebViewClient final : public API::ViewClient {
352 public:
353     explicit WebViewClient(WebKitWebView* webView)
354         : m_webView(webView)
355     {
356     }
357
358 private:
359     void handleDownloadRequest(WKWPE::View&, DownloadProxy& downloadProxy) override
360     {
361         webkitWebViewHandleDownloadRequest(m_webView, &downloadProxy);
362     }
363
364     JSGlobalContextRef javascriptGlobalContext() override
365     {
366         return webkit_web_view_get_javascript_global_context(m_webView);
367     }
368
369     WebKitWebView* m_webView;
370 };
371 #endif
372
373 static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, const char* failingURI, GError* error)
374 {
375     if (g_error_matches(error, WEBKIT_NETWORK_ERROR, WEBKIT_NETWORK_ERROR_CANCELLED)
376         || g_error_matches(error, WEBKIT_POLICY_ERROR, WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE)
377         || g_error_matches(error, WEBKIT_PLUGIN_ERROR, WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD))
378         return FALSE;
379
380     GUniquePtr<char> htmlString(g_strdup_printf("<html><body>%s</body></html>", error->message));
381     webkit_web_view_load_alternate_html(webView, htmlString.get(), failingURI, 0);
382
383     return TRUE;
384 }
385
386 #if PLATFORM(GTK)
387 static GtkWidget* webkitWebViewCreate(WebKitWebView*, WebKitNavigationAction*)
388 {
389     return nullptr;
390 }
391 #else
392 static WebKitWebView* webkitWebViewCreate(WebKitWebView*, WebKitNavigationAction*)
393 {
394     return nullptr;
395 }
396 #endif
397
398 static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* decision, WebKitPolicyDecisionType decisionType)
399 {
400     if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) {
401         webkit_policy_decision_use(decision);
402         return TRUE;
403     }
404
405     WebKitURIResponse* response = webkit_response_policy_decision_get_response(WEBKIT_RESPONSE_POLICY_DECISION(decision));
406     const ResourceResponse& resourceResponse = webkitURIResponseGetResourceResponse(response);
407     if (resourceResponse.isAttachment()) {
408         webkit_policy_decision_download(decision);
409         return TRUE;
410     }
411
412     if (webkit_response_policy_decision_is_mime_type_supported(WEBKIT_RESPONSE_POLICY_DECISION(decision)))
413         webkit_policy_decision_use(decision);
414     else
415         webkit_policy_decision_ignore(decision);
416
417     return TRUE;
418 }
419
420 static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request)
421 {
422     webkit_permission_request_deny(request);
423     return TRUE;
424 }
425
426 static void allowModalDialogsChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
427 {
428     getPage(webView).setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
429 }
430
431 static void zoomTextOnlyChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
432 {
433     auto& page = getPage(webView);
434     gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(settings);
435     gdouble pageZoomLevel = zoomTextOnly ? 1 : page.textZoomFactor();
436     gdouble textZoomLevel = zoomTextOnly ? page.pageZoomFactor() : 1;
437     page.setPageAndTextZoomFactors(pageZoomLevel, textZoomLevel);
438 }
439
440 static void userAgentChanged(WebKitSettings* settings, GParamSpec*, WebKitWebView* webView)
441 {
442     getPage(webView).setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings)));
443 }
444
445 #if PLATFORM(GTK)
446 static void webkitWebViewUpdateFavicon(WebKitWebView* webView, cairo_surface_t* favicon)
447 {
448     WebKitWebViewPrivate* priv = webView->priv;
449     if (priv->favicon.get() == favicon)
450         return;
451
452     priv->favicon = favicon;
453     g_object_notify(G_OBJECT(webView), "favicon");
454 }
455
456 static void webkitWebViewCancelFaviconRequest(WebKitWebView* webView)
457 {
458     if (!webView->priv->faviconCancellable)
459         return;
460
461     g_cancellable_cancel(webView->priv->faviconCancellable.get());
462     webView->priv->faviconCancellable = 0;
463 }
464
465 static void gotFaviconCallback(GObject* object, GAsyncResult* result, gpointer userData)
466 {
467     GUniqueOutPtr<GError> error;
468     RefPtr<cairo_surface_t> favicon = adoptRef(webkit_favicon_database_get_favicon_finish(WEBKIT_FAVICON_DATABASE(object), result, &error.outPtr()));
469     if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED))
470         return;
471
472     WebKitWebView* webView = WEBKIT_WEB_VIEW(userData);
473     webkitWebViewUpdateFavicon(webView, favicon.get());
474     webView->priv->faviconCancellable = 0;
475 }
476
477 static void webkitWebViewRequestFavicon(WebKitWebView* webView)
478 {
479     webkitWebViewCancelFaviconRequest(webView);
480
481     WebKitWebViewPrivate* priv = webView->priv;
482     priv->faviconCancellable = adoptGRef(g_cancellable_new());
483     WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get());
484     webkit_favicon_database_get_favicon(database, priv->activeURI.data(), priv->faviconCancellable.get(), gotFaviconCallback, webView);
485 }
486
487 static void webkitWebViewUpdateFaviconURI(WebKitWebView* webView, const char* faviconURI)
488 {
489     if (webView->priv->faviconURI == faviconURI)
490         return;
491
492     webView->priv->faviconURI = faviconURI;
493     webkitWebViewRequestFavicon(webView);
494 }
495
496 static void faviconChangedCallback(WebKitFaviconDatabase*, const char* pageURI, const char* faviconURI, WebKitWebView* webView)
497 {
498     if (webView->priv->activeURI != pageURI)
499         return;
500
501     webkitWebViewUpdateFaviconURI(webView, faviconURI);
502 }
503 #endif
504
505 static bool webkitWebViewIsConstructed(WebKitWebView* webView)
506 {
507     // The loadObserver is set in webkitWebViewConstructed, right after the
508     // WebPageProxy is created, so we use it to check if the view has been
509     // constructed instead of adding a boolean member only for that.
510     return !!webView->priv->loadObserver;
511 }
512
513 static void webkitWebViewUpdateSettings(WebKitWebView* webView)
514 {
515     // The "settings" property is set on construction, and in that
516     // case webkit_web_view_set_settings() will be called *before* the
517     // WebPageProxy has been created so we should do an early return.
518     if (!webkitWebViewIsConstructed(webView))
519         return;
520
521     auto& page = getPage(webView);
522     WebKitSettings* settings = webView->priv->settings.get();
523     page.setPreferences(*webkitSettingsGetPreferences(settings));
524     page.setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings));
525     page.setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings)));
526
527     g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView);
528     g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView);
529     g_signal_connect(settings, "notify::user-agent", G_CALLBACK(userAgentChanged), webView);
530 }
531
532 static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView)
533 {
534     if (!webkitWebViewIsConstructed(webView))
535         return;
536
537     WebKitSettings* settings = webView->priv->settings.get();
538     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowModalDialogsChanged), webView);
539     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView);
540     g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(userAgentChanged), webView);
541 }
542
543 #if PLATFORM(GTK)
544 static void webkitWebViewWatchForChangesInFavicon(WebKitWebView* webView)
545 {
546     WebKitWebViewPrivate* priv = webView->priv;
547     if (priv->faviconChangedHandlerID)
548         return;
549
550     WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get());
551     priv->faviconChangedHandlerID = g_signal_connect(database, "favicon-changed", G_CALLBACK(faviconChangedCallback), webView);
552 }
553
554 static void webkitWebViewDisconnectFaviconDatabaseSignalHandlers(WebKitWebView* webView)
555 {
556     WebKitWebViewPrivate* priv = webView->priv;
557     if (priv->faviconChangedHandlerID)
558         g_signal_handler_disconnect(webkit_web_context_get_favicon_database(priv->context.get()), priv->faviconChangedHandlerID);
559     priv->faviconChangedHandlerID = 0;
560 }
561 #endif
562
563 #if USE(LIBNOTIFY)
564 static const char* gNotifyNotificationID = "wk-notify-notification";
565
566 static void notifyNotificationClosed(NotifyNotification*, WebKitNotification* webNotification)
567 {
568     g_object_set_data(G_OBJECT(webNotification), gNotifyNotificationID, nullptr);
569     webkit_notification_close(webNotification);
570 }
571
572 static void notifyNotificationClicked(NotifyNotification*, char*, WebKitNotification* webNotification)
573 {
574     webkit_notification_clicked(webNotification);
575 }
576
577 static void webNotificationClosed(WebKitNotification* webNotification)
578 {
579     NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID));
580     if (!notification)
581         return;
582
583     notify_notification_close(notification, nullptr);
584     g_object_set_data(G_OBJECT(webNotification), gNotifyNotificationID, nullptr);
585 }
586 #endif // USE(LIBNOTIFY)
587
588 static gboolean webkitWebViewShowNotification(WebKitWebView*, WebKitNotification* webNotification)
589 {
590 #if USE(LIBNOTIFY)
591     if (!notify_is_initted())
592         notify_init(g_get_prgname());
593
594     NotifyNotification* notification = NOTIFY_NOTIFICATION(g_object_get_data(G_OBJECT(webNotification), gNotifyNotificationID));
595     if (!notification) {
596         notification = notify_notification_new(webkit_notification_get_title(webNotification),
597             webkit_notification_get_body(webNotification), nullptr);
598
599         notify_notification_add_action(notification, "default", _("Acknowledge"), NOTIFY_ACTION_CALLBACK(notifyNotificationClicked), webNotification, nullptr);
600
601         g_signal_connect_object(notification, "closed", G_CALLBACK(notifyNotificationClosed), webNotification, static_cast<GConnectFlags>(0));
602         g_signal_connect(webNotification, "closed", G_CALLBACK(webNotificationClosed), nullptr);
603         g_object_set_data_full(G_OBJECT(webNotification), gNotifyNotificationID, notification, static_cast<GDestroyNotify>(g_object_unref));
604     } else {
605         notify_notification_update(notification, webkit_notification_get_title(webNotification),
606             webkit_notification_get_body(webNotification), nullptr);
607     }
608
609     notify_notification_show(notification, nullptr);
610     return TRUE;
611 #else
612     UNUSED_PARAM(webNotification);
613     return FALSE;
614 #endif
615 }
616
617 static void webkitWebViewConstructed(GObject* object)
618 {
619     G_OBJECT_CLASS(webkit_web_view_parent_class)->constructed(object);
620
621     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
622     WebKitWebViewPrivate* priv = webView->priv;
623     if (priv->relatedView) {
624         priv->context = webkit_web_view_get_context(priv->relatedView);
625         priv->isEphemeral = webkit_web_view_is_ephemeral(priv->relatedView);
626         priv->isControlledByAutomation = webkit_web_view_is_controlled_by_automation(priv->relatedView);
627     } else if (!priv->context)
628         priv->context = webkit_web_context_get_default();
629     else if (!priv->isEphemeral)
630         priv->isEphemeral = webkit_web_context_is_ephemeral(priv->context.get());
631
632     if (!priv->settings)
633         priv->settings = adoptGRef(webkit_settings_new());
634
635     if (!priv->userContentManager)
636         priv->userContentManager = adoptGRef(webkit_user_content_manager_new());
637
638     if (priv->isEphemeral && !webkit_web_context_is_ephemeral(priv->context.get())) {
639         priv->websiteDataManager = adoptGRef(webkit_website_data_manager_new_ephemeral());
640         webkitWebsiteDataManagerAddProcessPool(priv->websiteDataManager.get(), webkitWebContextGetProcessPool(priv->context.get()));
641     }
642
643     webkitWebContextCreatePageForWebView(priv->context.get(), webView, priv->userContentManager.get(), priv->relatedView);
644
645     priv->loadObserver = std::make_unique<PageLoadStateObserver>(webView);
646     getPage(webView).pageLoadState().addObserver(*priv->loadObserver);
647
648     // The related view is only valid during the construction.
649     priv->relatedView = nullptr;
650
651     attachLoaderClientToView(webView);
652     attachUIClientToView(webView);
653     attachPolicyClientToView(webView);
654     attachContextMenuClientToView(webView);
655     attachFormClientToView(webView);
656
657 #if PLATFORM(GTK)
658     attachIconLoadingClientToView(webView);
659 #endif
660
661 #if PLATFORM(WPE)
662     priv->view->setClient(std::make_unique<WebViewClient>(webView));
663 #endif
664
665     // This needs to be after attachUIClientToView() because WebPageProxy::setUIClient() calls setCanRunModal() with true.
666     // See https://bugs.webkit.org/show_bug.cgi?id=135412.
667     webkitWebViewUpdateSettings(webView);
668
669     priv->backForwardList = adoptGRef(webkitBackForwardListCreate(&getPage(webView).backForwardList()));
670     priv->windowProperties = adoptGRef(webkitWindowPropertiesCreate());
671 }
672
673 static void webkitWebViewSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec)
674 {
675     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
676
677     switch (propId) {
678     case PROP_WEB_CONTEXT: {
679         gpointer webContext = g_value_get_object(value);
680         webView->priv->context = webContext ? WEBKIT_WEB_CONTEXT(webContext) : nullptr;
681         break;
682     }
683     case PROP_RELATED_VIEW: {
684         gpointer relatedView = g_value_get_object(value);
685         webView->priv->relatedView = relatedView ? WEBKIT_WEB_VIEW(relatedView) : nullptr;
686         break;
687     }
688     case PROP_SETTINGS: {
689         if (gpointer settings = g_value_get_object(value))
690             webkit_web_view_set_settings(webView, WEBKIT_SETTINGS(settings));
691         break;
692     }
693     case PROP_USER_CONTENT_MANAGER: {
694         gpointer userContentManager = g_value_get_object(value);
695         webView->priv->userContentManager = userContentManager ? WEBKIT_USER_CONTENT_MANAGER(userContentManager) : nullptr;
696         break;
697     }
698     case PROP_ZOOM_LEVEL:
699         webkit_web_view_set_zoom_level(webView, g_value_get_double(value));
700         break;
701     case PROP_IS_EPHEMERAL:
702         webView->priv->isEphemeral = g_value_get_boolean(value);
703         break;
704     case PROP_IS_CONTROLLED_BY_AUTOMATION:
705         webView->priv->isControlledByAutomation = g_value_get_boolean(value);
706         break;
707     case PROP_EDITABLE:
708         webkit_web_view_set_editable(webView, g_value_get_boolean(value));
709         break;
710     default:
711         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
712     }
713 }
714
715 static void webkitWebViewGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec)
716 {
717     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
718
719     switch (propId) {
720     case PROP_WEB_CONTEXT:
721         g_value_set_object(value, webView->priv->context.get());
722         break;
723     case PROP_SETTINGS:
724         g_value_set_object(value, webkit_web_view_get_settings(webView));
725         break;
726     case PROP_USER_CONTENT_MANAGER:
727         g_value_set_object(value, webkit_web_view_get_user_content_manager(webView));
728         break;
729     case PROP_TITLE:
730         g_value_set_string(value, webView->priv->title.data());
731         break;
732     case PROP_ESTIMATED_LOAD_PROGRESS:
733         g_value_set_double(value, webkit_web_view_get_estimated_load_progress(webView));
734         break;
735 #if PLATFORM(GTK)
736     case PROP_FAVICON:
737         g_value_set_pointer(value, webkit_web_view_get_favicon(webView));
738         break;
739 #endif
740     case PROP_URI:
741         g_value_set_string(value, webkit_web_view_get_uri(webView));
742         break;
743     case PROP_ZOOM_LEVEL:
744         g_value_set_double(value, webkit_web_view_get_zoom_level(webView));
745         break;
746     case PROP_IS_LOADING:
747         g_value_set_boolean(value, webkit_web_view_is_loading(webView));
748         break;
749     case PROP_IS_PLAYING_AUDIO:
750         g_value_set_boolean(value, webkit_web_view_is_playing_audio(webView));
751         break;
752     case PROP_IS_EPHEMERAL:
753         g_value_set_boolean(value, webkit_web_view_is_ephemeral(webView));
754         break;
755     case PROP_IS_CONTROLLED_BY_AUTOMATION:
756         g_value_set_boolean(value, webkit_web_view_is_controlled_by_automation(webView));
757         break;
758     case PROP_EDITABLE:
759         g_value_set_boolean(value, webkit_web_view_is_editable(webView));
760         break;
761     default:
762         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec);
763     }
764 }
765
766 static void webkitWebViewDispose(GObject* object)
767 {
768     WebKitWebView* webView = WEBKIT_WEB_VIEW(object);
769
770 #if PLATFORM(GTK)
771     webkitWebViewCancelFaviconRequest(webView);
772     webkitWebViewDisconnectFaviconDatabaseSignalHandlers(webView);
773 #endif
774
775     webkitWebViewDisconnectSettingsSignalHandlers(webView);
776
777     if (webView->priv->loadObserver) {
778         getPage(webView).pageLoadState().removeObserver(*webView->priv->loadObserver);
779         webView->priv->loadObserver.reset();
780
781         // We notify the context here to ensure it's called only once. Ideally we should
782         // call this in finalize, not dispose, but finalize is used internally and we don't
783         // have access to the instance pointer from the private struct destructor.
784         webkitWebContextWebViewDestroyed(webView->priv->context.get(), webView);
785     }
786
787     if (webView->priv->websiteDataManager) {
788         webkitWebsiteDataManagerRemoveProcessPool(webView->priv->websiteDataManager.get(), webkitWebContextGetProcessPool(webView->priv->context.get()));
789         webView->priv->websiteDataManager = nullptr;
790     }
791
792 #if PLATFORM(WPE)
793     webView->priv->view->close();
794 #endif
795
796     G_OBJECT_CLASS(webkit_web_view_parent_class)->dispose(object);
797 }
798
799 static gboolean webkitWebViewAccumulatorObjectHandled(GSignalInvocationHint*, GValue* returnValue, const GValue* handlerReturn, gpointer)
800 {
801     void* object = g_value_get_object(handlerReturn);
802     if (object)
803         g_value_set_object(returnValue, object);
804
805     return !object;
806 }
807
808 static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass)
809 {
810     GObjectClass* gObjectClass = G_OBJECT_CLASS(webViewClass);
811
812     gObjectClass->constructed = webkitWebViewConstructed;
813     gObjectClass->set_property = webkitWebViewSetProperty;
814     gObjectClass->get_property = webkitWebViewGetProperty;
815     gObjectClass->dispose = webkitWebViewDispose;
816
817     webViewClass->load_failed = webkitWebViewLoadFail;
818     webViewClass->create = webkitWebViewCreate;
819     webViewClass->script_dialog = webkitWebViewScriptDialog;
820     webViewClass->decide_policy = webkitWebViewDecidePolicy;
821     webViewClass->permission_request = webkitWebViewPermissionRequest;
822     webViewClass->run_file_chooser = webkitWebViewRunFileChooser;
823     webViewClass->authenticate = webkitWebViewAuthenticate;
824     webViewClass->show_notification = webkitWebViewShowNotification;
825
826     /**
827      * WebKitWebView:web-context:
828      *
829      * The #WebKitWebContext of the view.
830      */
831     g_object_class_install_property(gObjectClass,
832                                     PROP_WEB_CONTEXT,
833                                     g_param_spec_object("web-context",
834                                                         _("Web Context"),
835                                                         _("The web context for the view"),
836                                                         WEBKIT_TYPE_WEB_CONTEXT,
837                                                         static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
838     /**
839      * WebKitWebView:related-view:
840      *
841      * The related #WebKitWebView used when creating the view to share the
842      * same web process. This property is not readable because the related
843      * web view is only valid during the object construction.
844      *
845      * Since: 2.4
846      */
847     g_object_class_install_property(
848         gObjectClass,
849         PROP_RELATED_VIEW,
850         g_param_spec_object(
851             "related-view",
852             _("Related WebView"),
853             _("The related WebKitWebView used when creating the view to share the same web process"),
854             WEBKIT_TYPE_WEB_VIEW,
855             static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
856
857     /**
858      * WebKitWebView:settings:
859      *
860      * The #WebKitSettings of the view.
861      *
862      * Since: 2.6
863      */
864     g_object_class_install_property(
865         gObjectClass,
866         PROP_SETTINGS,
867         g_param_spec_object(
868             "settings",
869             _("WebView settings"),
870             _("The WebKitSettings of the view"),
871             WEBKIT_TYPE_SETTINGS,
872             static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT)));
873
874     /**
875      * WebKitWebView:user-content-manager:
876      *
877      * The #WebKitUserContentManager of the view.
878      *
879      * Since: 2.6
880      */
881     g_object_class_install_property(
882         gObjectClass,
883         PROP_USER_CONTENT_MANAGER,
884         g_param_spec_object(
885             "user-content-manager",
886             _("WebView user content manager"),
887             _("The WebKitUserContentManager of the view"),
888             WEBKIT_TYPE_USER_CONTENT_MANAGER,
889             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
890
891     /**
892      * WebKitWebView:title:
893      *
894      * The main frame document title of this #WebKitWebView. If
895      * the title has not been received yet, it will be %NULL.
896      */
897     g_object_class_install_property(gObjectClass,
898                                     PROP_TITLE,
899                                     g_param_spec_string("title",
900                                                         _("Title"),
901                                                         _("Main frame document title"),
902                                                         0,
903                                                         WEBKIT_PARAM_READABLE));
904
905     /**
906      * WebKitWebView:estimated-load-progress:
907      *
908      * An estimate of the percent completion for the current loading operation.
909      * This value will range from 0.0 to 1.0 and, once a load completes,
910      * will remain at 1.0 until a new load starts, at which point it
911      * will be reset to 0.0.
912      * The value is an estimate based on the total number of bytes expected
913      * to be received for a document, including all its possible subresources
914      * and child documents.
915      */
916     g_object_class_install_property(gObjectClass,
917                                     PROP_ESTIMATED_LOAD_PROGRESS,
918                                     g_param_spec_double("estimated-load-progress",
919                                                         _("Estimated Load Progress"),
920                                                         _("An estimate of the percent completion for a document load"),
921                                                         0.0, 1.0, 0.0,
922                                                         WEBKIT_PARAM_READABLE));
923 #if PLATFORM(GTK)
924     /**
925      * WebKitWebView:favicon:
926      *
927      * The favicon currently associated to the #WebKitWebView.
928      * See webkit_web_view_get_favicon() for more details.
929      */
930     g_object_class_install_property(gObjectClass,
931                                     PROP_FAVICON,
932                                     g_param_spec_pointer("favicon",
933                                                          _("Favicon"),
934                                                          _("The favicon associated to the view, if any"),
935                                                          WEBKIT_PARAM_READABLE));
936 #endif
937
938     /**
939      * WebKitWebView:uri:
940      *
941      * The current active URI of the #WebKitWebView.
942      * See webkit_web_view_get_uri() for more details.
943      */
944     g_object_class_install_property(gObjectClass,
945                                     PROP_URI,
946                                     g_param_spec_string("uri",
947                                                         _("URI"),
948                                                         _("The current active URI of the view"),
949                                                         0,
950                                                         WEBKIT_PARAM_READABLE));
951
952     /**
953      * WebKitWebView:zoom-level:
954      *
955      * The zoom level of the #WebKitWebView content.
956      * See webkit_web_view_set_zoom_level() for more details.
957      */
958     g_object_class_install_property(
959         gObjectClass,
960         PROP_ZOOM_LEVEL,
961         g_param_spec_double(
962             "zoom-level",
963             _("Zoom level"),
964             _("The zoom level of the view content"),
965             0, G_MAXDOUBLE, 1,
966             WEBKIT_PARAM_READWRITE));
967
968     /**
969      * WebKitWebView:is-loading:
970      *
971      * Whether the #WebKitWebView is currently loading a page. This property becomes
972      * %TRUE as soon as a new load operation is requested and before the
973      * #WebKitWebView::load-changed signal is emitted with %WEBKIT_LOAD_STARTED and
974      * at that point the active URI is the requested one.
975      * When the load operation finishes the property is set to %FALSE before
976      * #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_FINISHED.
977      */
978     g_object_class_install_property(
979         gObjectClass,
980         PROP_IS_LOADING,
981         g_param_spec_boolean(
982             "is-loading",
983             _("Is Loading"),
984             _("Whether the view is loading a page"),
985             FALSE,
986             WEBKIT_PARAM_READABLE));
987
988     /**
989      * WebKitWebView:is-playing-audio:
990      *
991      * Whether the #WebKitWebView is currently playing audio from a page.
992      * This property becomes %TRUE as soon as web content starts playing any
993      * kind of audio. When a page is no longer playing any kind of sound,
994      * the property is set back to %FALSE.
995      *
996      * Since: 2.8
997      */
998     g_object_class_install_property(
999         gObjectClass,
1000         PROP_IS_PLAYING_AUDIO,
1001         g_param_spec_boolean(
1002             "is-playing-audio",
1003             "Is Playing Audio",
1004             _("Whether the view is playing audio"),
1005             FALSE,
1006             WEBKIT_PARAM_READABLE));
1007
1008     /**
1009      * WebKitWebView:is-ephemeral:
1010      *
1011      * Whether the #WebKitWebView is ephemeral. An ephemeral web view never writes
1012      * website data to the client storage, no matter what #WebKitWebsiteDataManager
1013      * its context is using. This is normally used to implement private browsing mode.
1014      * This is a %G_PARAM_CONSTRUCT_ONLY property, so you have to create a ephemeral
1015      * #WebKitWebView and it can't be changed. Note that all #WebKitWebView<!-- -->s
1016      * created with an ephemeral #WebKitWebContext will be ephemeral automatically.
1017      * See also webkit_web_context_new_ephemeral().
1018      *
1019      * Since: 2.16
1020      */
1021     g_object_class_install_property(
1022         gObjectClass,
1023         PROP_IS_EPHEMERAL,
1024         g_param_spec_boolean(
1025             "is-ephemeral",
1026             "Is Ephemeral",
1027             _("Whether the web view is ephemeral"),
1028             FALSE,
1029             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
1030
1031     /**
1032      * WebKitWebView:is-controlled-by-automation:
1033      *
1034      * Whether the #WebKitWebView is controlled by automation. This should only be used when
1035      * creating a new #WebKitWebView as a response to #WebKitAutomationSession::create-web-view
1036      * signal request.
1037      *
1038      * Since: 2.18
1039      */
1040     g_object_class_install_property(
1041         gObjectClass,
1042         PROP_IS_CONTROLLED_BY_AUTOMATION,
1043         g_param_spec_boolean(
1044             "is-controlled-by-automation",
1045             "Is Controlled By Automation",
1046             _("Whether the web view is controlled by automation"),
1047             FALSE,
1048             static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
1049
1050     /**
1051      * WebKitWebView:editable:
1052      *
1053      * Whether the pages loaded inside #WebKitWebView are editable. For more
1054      * information see webkit_web_view_set_editable().
1055      *
1056      * Since: 2.8
1057      */
1058     g_object_class_install_property(
1059         gObjectClass,
1060         PROP_EDITABLE,
1061         g_param_spec_boolean(
1062             "editable",
1063             _("Editable"),
1064             _("Whether the content can be modified by the user."),
1065             FALSE,
1066             WEBKIT_PARAM_READWRITE));
1067
1068     /**
1069      * WebKitWebView::load-changed:
1070      * @web_view: the #WebKitWebView on which the signal is emitted
1071      * @load_event: the #WebKitLoadEvent
1072      *
1073      * Emitted when a load operation in @web_view changes.
1074      * The signal is always emitted with %WEBKIT_LOAD_STARTED when a
1075      * new load request is made and %WEBKIT_LOAD_FINISHED when the load
1076      * finishes successfully or due to an error. When the ongoing load
1077      * operation fails #WebKitWebView::load-failed signal is emitted
1078      * before #WebKitWebView::load-changed is emitted with
1079      * %WEBKIT_LOAD_FINISHED.
1080      * If a redirection is received from the server, this signal is emitted
1081      * with %WEBKIT_LOAD_REDIRECTED after the initial emission with
1082      * %WEBKIT_LOAD_STARTED and before %WEBKIT_LOAD_COMMITTED.
1083      * When the page content starts arriving the signal is emitted with
1084      * %WEBKIT_LOAD_COMMITTED event.
1085      *
1086      * You can handle this signal and use a switch to track any ongoing
1087      * load operation.
1088      *
1089      * <informalexample><programlisting>
1090      * static void web_view_load_changed (WebKitWebView  *web_view,
1091      *                                    WebKitLoadEvent load_event,
1092      *                                    gpointer        user_data)
1093      * {
1094      *     switch (load_event) {
1095      *     case WEBKIT_LOAD_STARTED:
1096      *         /<!-- -->* New load, we have now a provisional URI *<!-- -->/
1097      *         provisional_uri = webkit_web_view_get_uri (web_view);
1098      *         /<!-- -->* Here we could start a spinner or update the
1099      *          <!-- -->* location bar with the provisional URI *<!-- -->/
1100      *         break;
1101      *     case WEBKIT_LOAD_REDIRECTED:
1102      *         redirected_uri = webkit_web_view_get_uri (web_view);
1103      *         break;
1104      *     case WEBKIT_LOAD_COMMITTED:
1105      *         /<!-- -->* The load is being performed. Current URI is
1106      *          <!-- -->* the final one and it won't change unless a new
1107      *          <!-- -->* load is requested or a navigation within the
1108      *          <!-- -->* same page is performed *<!-- -->/
1109      *         uri = webkit_web_view_get_uri (web_view);
1110      *         break;
1111      *     case WEBKIT_LOAD_FINISHED:
1112      *         /<!-- -->* Load finished, we can now stop the spinner *<!-- -->/
1113      *         break;
1114      *     }
1115      * }
1116      * </programlisting></informalexample>
1117      */
1118     signals[LOAD_CHANGED] =
1119         g_signal_new("load-changed",
1120                      G_TYPE_FROM_CLASS(webViewClass),
1121                      G_SIGNAL_RUN_LAST,
1122                      G_STRUCT_OFFSET(WebKitWebViewClass, load_changed),
1123                      0, 0,
1124                      g_cclosure_marshal_VOID__ENUM,
1125                      G_TYPE_NONE, 1,
1126                      WEBKIT_TYPE_LOAD_EVENT);
1127
1128     /**
1129      * WebKitWebView::load-failed:
1130      * @web_view: the #WebKitWebView on which the signal is emitted
1131      * @load_event: the #WebKitLoadEvent of the load operation
1132      * @failing_uri: the URI that failed to load
1133      * @error: the #GError that was triggered
1134      *
1135      * Emitted when an error occurs during a load operation.
1136      * If the error happened when starting to load data for a page
1137      * @load_event will be %WEBKIT_LOAD_STARTED. If it happened while
1138      * loading a committed data source @load_event will be %WEBKIT_LOAD_COMMITTED.
1139      * Since a load error causes the load operation to finish, the signal
1140      * WebKitWebView::load-changed will always be emitted with
1141      * %WEBKIT_LOAD_FINISHED event right after this one.
1142      *
1143      * By default, if the signal is not handled, a stock error page will be displayed.
1144      * You need to handle the signal if you want to provide your own error page.
1145      *
1146      * Returns: %TRUE to stop other handlers from being invoked for the event.
1147      *    %FALSE to propagate the event further.
1148      */
1149     signals[LOAD_FAILED] =
1150         g_signal_new(
1151             "load-failed",
1152             G_TYPE_FROM_CLASS(webViewClass),
1153             G_SIGNAL_RUN_LAST,
1154             G_STRUCT_OFFSET(WebKitWebViewClass, load_failed),
1155             g_signal_accumulator_true_handled, 0,
1156             g_cclosure_marshal_generic,
1157             G_TYPE_BOOLEAN, 3,
1158             WEBKIT_TYPE_LOAD_EVENT,
1159             G_TYPE_STRING,
1160             G_TYPE_ERROR | G_SIGNAL_TYPE_STATIC_SCOPE);
1161
1162     /**
1163      * WebKitWebView::load-failed-with-tls-errors:
1164      * @web_view: the #WebKitWebView on which the signal is emitted
1165      * @failing_uri: the URI that failed to load
1166      * @certificate: a #GTlsCertificate
1167      * @errors: a #GTlsCertificateFlags with the verification status of @certificate
1168      *
1169      * Emitted when a TLS error occurs during a load operation.
1170      * To allow an exception for this @certificate
1171      * and the host of @failing_uri use webkit_web_context_allow_tls_certificate_for_host().
1172      *
1173      * To handle this signal asynchronously you should call g_object_ref() on @certificate
1174      * and return %TRUE.
1175      *
1176      * If %FALSE is returned, #WebKitWebView::load-failed will be emitted. The load
1177      * will finish regardless of the returned value.
1178      *
1179      * Returns: %TRUE to stop other handlers from being invoked for the event.
1180      *   %FALSE to propagate the event further.
1181      *
1182      * Since: 2.6
1183      */
1184     signals[LOAD_FAILED_WITH_TLS_ERRORS] =
1185         g_signal_new("load-failed-with-tls-errors",
1186             G_TYPE_FROM_CLASS(webViewClass),
1187             G_SIGNAL_RUN_LAST,
1188             G_STRUCT_OFFSET(WebKitWebViewClass, load_failed_with_tls_errors),
1189             g_signal_accumulator_true_handled, 0 /* accumulator data */,
1190             g_cclosure_marshal_generic,
1191             G_TYPE_BOOLEAN, 3,
1192             G_TYPE_STRING,
1193             G_TYPE_TLS_CERTIFICATE,
1194             G_TYPE_TLS_CERTIFICATE_FLAGS);
1195
1196     /**
1197      * WebKitWebView::create:
1198      * @web_view: the #WebKitWebView on which the signal is emitted
1199      * @navigation_action: a #WebKitNavigationAction
1200      *
1201      * Emitted when the creation of a new #WebKitWebView is requested.
1202      * If this signal is handled the signal handler should return the
1203      * newly created #WebKitWebView.
1204      *
1205      * The #WebKitNavigationAction parameter contains information about the
1206      * navigation action that triggered this signal.
1207      *
1208      * When using %WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES
1209      * process model, the new #WebKitWebView should be related to
1210      * @web_view to share the same web process, see webkit_web_view_new_with_related_view()
1211      * for more details.
1212      *
1213      * The new #WebKitWebView should not be displayed to the user
1214      * until the #WebKitWebView::ready-to-show signal is emitted.
1215      *
1216      * Returns: (transfer full): a newly allocated #WebKitWebView widget
1217      *    or %NULL to propagate the event further.
1218      */
1219     signals[CREATE] = g_signal_new(
1220         "create",
1221         G_TYPE_FROM_CLASS(webViewClass),
1222         G_SIGNAL_RUN_LAST,
1223         G_STRUCT_OFFSET(WebKitWebViewClass, create),
1224         webkitWebViewAccumulatorObjectHandled, 0,
1225         g_cclosure_marshal_generic,
1226 #if PLATFORM(GTK)
1227         GTK_TYPE_WIDGET,
1228 #else
1229         WEBKIT_TYPE_WEB_VIEW,
1230 #endif
1231         1,
1232         WEBKIT_TYPE_NAVIGATION_ACTION | G_SIGNAL_TYPE_STATIC_SCOPE);
1233
1234     /**
1235      * WebKitWebView::ready-to-show:
1236      * @web_view: the #WebKitWebView on which the signal is emitted
1237      *
1238      * Emitted after #WebKitWebView::create on the newly created #WebKitWebView
1239      * when it should be displayed to the user. When this signal is emitted
1240      * all the information about how the window should look, including
1241      * size, position, whether the location, status and scrollbars
1242      * should be displayed, is already set on the #WebKitWindowProperties
1243      * of @web_view. See also webkit_web_view_get_window_properties().
1244      */
1245     signals[READY_TO_SHOW] =
1246         g_signal_new("ready-to-show",
1247                      G_TYPE_FROM_CLASS(webViewClass),
1248                      G_SIGNAL_RUN_LAST,
1249                      G_STRUCT_OFFSET(WebKitWebViewClass, ready_to_show),
1250                      0, 0,
1251                      g_cclosure_marshal_VOID__VOID,
1252                      G_TYPE_NONE, 0);
1253
1254      /**
1255      * WebKitWebView::run-as-modal:
1256      * @web_view: the #WebKitWebView on which the signal is emitted
1257      *
1258      * Emitted after #WebKitWebView::ready-to-show on the newly
1259      * created #WebKitWebView when JavaScript code calls
1260      * <function>window.showModalDialog</function>. The purpose of
1261      * this signal is to allow the client application to prepare the
1262      * new view to behave as modal. Once the signal is emitted a new
1263      * main loop will be run to block user interaction in the parent
1264      * #WebKitWebView until the new dialog is closed.
1265      */
1266     signals[RUN_AS_MODAL] =
1267             g_signal_new("run-as-modal",
1268                          G_TYPE_FROM_CLASS(webViewClass),
1269                          G_SIGNAL_RUN_LAST,
1270                          G_STRUCT_OFFSET(WebKitWebViewClass, run_as_modal),
1271                          0, 0,
1272                          g_cclosure_marshal_VOID__VOID,
1273                          G_TYPE_NONE, 0);
1274
1275     /**
1276      * WebKitWebView::close:
1277      * @web_view: the #WebKitWebView on which the signal is emitted
1278      *
1279      * Emitted when closing a #WebKitWebView is requested. This occurs when a
1280      * call is made from JavaScript's <function>window.close</function> function or
1281      * after trying to close the @web_view with webkit_web_view_try_close().
1282      * It is the owner's responsibility to handle this signal to hide or
1283      * destroy the #WebKitWebView, if necessary.
1284      */
1285     signals[CLOSE] =
1286         g_signal_new("close",
1287                      G_TYPE_FROM_CLASS(webViewClass),
1288                      G_SIGNAL_RUN_LAST,
1289                      G_STRUCT_OFFSET(WebKitWebViewClass, close),
1290                      0, 0,
1291                      g_cclosure_marshal_VOID__VOID,
1292                      G_TYPE_NONE, 0);
1293
1294     /**
1295      * WebKitWebView::script-dialog:
1296      * @web_view: the #WebKitWebView on which the signal is emitted
1297      * @dialog: the #WebKitScriptDialog to show
1298      *
1299      * Emitted when JavaScript code calls <function>window.alert</function>,
1300      * <function>window.confirm</function> or <function>window.prompt</function>,
1301      * or when <function>onbeforeunload</function> event is fired.
1302      * The @dialog parameter should be used to build the dialog.
1303      * If the signal is not handled a different dialog will be built and shown depending
1304      * on the dialog type:
1305      * <itemizedlist>
1306      * <listitem><para>
1307      *  %WEBKIT_SCRIPT_DIALOG_ALERT: message dialog with a single Close button.
1308      * </para></listitem>
1309      * <listitem><para>
1310      *  %WEBKIT_SCRIPT_DIALOG_CONFIRM: message dialog with OK and Cancel buttons.
1311      * </para></listitem>
1312      * <listitem><para>
1313      *  %WEBKIT_SCRIPT_DIALOG_PROMPT: message dialog with OK and Cancel buttons and
1314      *  a text entry with the default text.
1315      * </para></listitem>
1316      * <listitem><para>
1317      *  %WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM: message dialog with Stay and Leave buttons.
1318      * </para></listitem>
1319      * </itemizedlist>
1320      *
1321      * Returns: %TRUE to stop other handlers from being invoked for the event.
1322      *    %FALSE to propagate the event further.
1323      */
1324     signals[SCRIPT_DIALOG] = g_signal_new(
1325         "script-dialog",
1326         G_TYPE_FROM_CLASS(webViewClass),
1327         G_SIGNAL_RUN_LAST,
1328         G_STRUCT_OFFSET(WebKitWebViewClass, script_dialog),
1329         g_signal_accumulator_true_handled, nullptr,
1330         g_cclosure_marshal_generic,
1331         G_TYPE_BOOLEAN, 1,
1332         WEBKIT_TYPE_SCRIPT_DIALOG | G_SIGNAL_TYPE_STATIC_SCOPE);
1333
1334     /**
1335      * WebKitWebView::decide-policy:
1336      * @web_view: the #WebKitWebView on which the signal is emitted
1337      * @decision: the #WebKitPolicyDecision
1338      * @decision_type: a #WebKitPolicyDecisionType denoting the type of @decision
1339      *
1340      * This signal is emitted when WebKit is requesting the client to decide a policy
1341      * decision, such as whether to navigate to a page, open a new window or whether or
1342      * not to download a resource. The #WebKitNavigationPolicyDecision passed in the
1343      * @decision argument is a generic type, but should be casted to a more
1344      * specific type when making the decision. For example:
1345      *
1346      * <informalexample><programlisting>
1347      * static gboolean
1348      * decide_policy_cb (WebKitWebView *web_view,
1349      *                   WebKitPolicyDecision *decision,
1350      *                   WebKitPolicyDecisionType type)
1351      * {
1352      *     switch (type) {
1353      *     case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
1354      *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1355      *         /<!-- -->* Make a policy decision here. *<!-- -->/
1356      *         break;
1357      *     case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
1358      *         WebKitNavigationPolicyDecision *navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION (decision);
1359      *         /<!-- -->* Make a policy decision here. *<!-- -->/
1360      *         break;
1361      *     case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
1362      *         WebKitResponsePolicyDecision *response = WEBKIT_RESPONSE_POLICY_DECISION (decision);
1363      *         /<!-- -->* Make a policy decision here. *<!-- -->/
1364      *         break;
1365      *     default:
1366      *         /<!-- -->* Making no decision results in webkit_policy_decision_use(). *<!-- -->/
1367      *         return FALSE;
1368      *     }
1369      *     return TRUE;
1370      * }
1371      * </programlisting></informalexample>
1372      *
1373      * It is possible to make policy decision asynchronously, by simply calling g_object_ref()
1374      * on the @decision argument and returning %TRUE to block the default signal handler.
1375      * If the last reference is removed on a #WebKitPolicyDecision and no decision has been
1376      * made explicitly, webkit_policy_decision_use() will be the default policy decision. The
1377      * default signal handler will simply call webkit_policy_decision_use(). Only the first
1378      * policy decision chosen for a given #WebKitPolicyDecision will have any affect.
1379      *
1380      * Returns: %TRUE to stop other handlers from being invoked for the event.
1381      *   %FALSE to propagate the event further.
1382      *
1383      */
1384     signals[DECIDE_POLICY] = g_signal_new(
1385         "decide-policy",
1386         G_TYPE_FROM_CLASS(webViewClass),
1387         G_SIGNAL_RUN_LAST,
1388         G_STRUCT_OFFSET(WebKitWebViewClass, decide_policy),
1389         g_signal_accumulator_true_handled, nullptr /* accumulator data */,
1390         g_cclosure_marshal_generic,
1391         G_TYPE_BOOLEAN, 2, /* number of parameters */
1392         WEBKIT_TYPE_POLICY_DECISION,
1393         WEBKIT_TYPE_POLICY_DECISION_TYPE);
1394
1395     /**
1396      * WebKitWebView::permission-request:
1397      * @web_view: the #WebKitWebView on which the signal is emitted
1398      * @request: the #WebKitPermissionRequest
1399      *
1400      * This signal is emitted when WebKit is requesting the client to
1401      * decide about a permission request, such as allowing the browser
1402      * to switch to fullscreen mode, sharing its location or similar
1403      * operations.
1404      *
1405      * A possible way to use this signal could be through a dialog
1406      * allowing the user decide what to do with the request:
1407      *
1408      * <informalexample><programlisting>
1409      * static gboolean permission_request_cb (WebKitWebView *web_view,
1410      *                                        WebKitPermissionRequest *request,
1411      *                                        GtkWindow *parent_window)
1412      * {
1413      *     GtkWidget *dialog = gtk_message_dialog_new (parent_window,
1414      *                                                 GTK_DIALOG_MODAL,
1415      *                                                 GTK_MESSAGE_QUESTION,
1416      *                                                 GTK_BUTTONS_YES_NO,
1417      *                                                 "Allow Permission Request?");
1418      *     gtk_widget_show (dialog);
1419      *     gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1420      *
1421      *     switch (result) {
1422      *     case GTK_RESPONSE_YES:
1423      *         webkit_permission_request_allow (request);
1424      *         break;
1425      *     default:
1426      *         webkit_permission_request_deny (request);
1427      *         break;
1428      *     }
1429      *     gtk_widget_destroy (dialog);
1430      *
1431      *     return TRUE;
1432      * }
1433      * </programlisting></informalexample>
1434      *
1435      * It is possible to handle permission requests asynchronously, by
1436      * simply calling g_object_ref() on the @request argument and
1437      * returning %TRUE to block the default signal handler.  If the
1438      * last reference is removed on a #WebKitPermissionRequest and the
1439      * request has not been handled, webkit_permission_request_deny()
1440      * will be the default action.
1441      *
1442      * If the signal is not handled, the @request will be completed automatically
1443      * by the specific #WebKitPermissionRequest that could allow or deny it. Check the
1444      * documentation of classes implementing #WebKitPermissionRequest interface to know
1445      * their default action.
1446      *
1447      * Returns: %TRUE to stop other handlers from being invoked for the event.
1448      *   %FALSE to propagate the event further.
1449      *
1450      */
1451     signals[PERMISSION_REQUEST] = g_signal_new(
1452         "permission-request",
1453         G_TYPE_FROM_CLASS(webViewClass),
1454         G_SIGNAL_RUN_LAST,
1455         G_STRUCT_OFFSET(WebKitWebViewClass, permission_request),
1456         g_signal_accumulator_true_handled, nullptr /* accumulator data */,
1457         g_cclosure_marshal_generic,
1458         G_TYPE_BOOLEAN, 1, /* number of parameters */
1459         WEBKIT_TYPE_PERMISSION_REQUEST);
1460     /**
1461      * WebKitWebView::mouse-target-changed:
1462      * @web_view: the #WebKitWebView on which the signal is emitted
1463      * @hit_test_result: a #WebKitHitTestResult
1464      * @modifiers: a bitmask of #GdkModifierType
1465      *
1466      * This signal is emitted when the mouse cursor moves over an
1467      * element such as a link, image or a media element. To determine
1468      * what type of element the mouse cursor is over, a Hit Test is performed
1469      * on the current mouse coordinates and the result is passed in the
1470      * @hit_test_result argument. The @modifiers argument is a bitmask of
1471      * #GdkModifierType flags indicating the state of modifier keys.
1472      * The signal is emitted again when the mouse is moved out of the
1473      * current element with a new @hit_test_result.
1474      */
1475     signals[MOUSE_TARGET_CHANGED] = g_signal_new(
1476         "mouse-target-changed",
1477         G_TYPE_FROM_CLASS(webViewClass),
1478         G_SIGNAL_RUN_LAST,
1479         G_STRUCT_OFFSET(WebKitWebViewClass, mouse_target_changed),
1480         nullptr, nullptr,
1481         g_cclosure_marshal_generic,
1482         G_TYPE_NONE, 2,
1483         WEBKIT_TYPE_HIT_TEST_RESULT,
1484         G_TYPE_UINT);
1485
1486 #if PLATFORM(GTK)
1487     /**
1488      * WebKitWebView::print:
1489      * @web_view: the #WebKitWebView on which the signal is emitted
1490      * @print_operation: the #WebKitPrintOperation that will handle the print request
1491      *
1492      * Emitted when printing is requested on @web_view, usually by a JavaScript call,
1493      * before the print dialog is shown. This signal can be used to set the initial
1494      * print settings and page setup of @print_operation to be used as default values in
1495      * the print dialog. You can call webkit_print_operation_set_print_settings() and
1496      * webkit_print_operation_set_page_setup() and then return %FALSE to propagate the
1497      * event so that the print dialog is shown.
1498      *
1499      * You can connect to this signal and return %TRUE to cancel the print operation
1500      * or implement your own print dialog.
1501      *
1502      * Returns: %TRUE to stop other handlers from being invoked for the event.
1503      *    %FALSE to propagate the event further.
1504      */
1505     signals[PRINT] = g_signal_new(
1506         "print",
1507         G_TYPE_FROM_CLASS(webViewClass),
1508         G_SIGNAL_RUN_LAST,
1509         G_STRUCT_OFFSET(WebKitWebViewClass, print),
1510         g_signal_accumulator_true_handled, nullptr,
1511         g_cclosure_marshal_generic,
1512         G_TYPE_BOOLEAN, 1,
1513         WEBKIT_TYPE_PRINT_OPERATION);
1514 #endif // PLATFORM(GTK)
1515
1516     /**
1517      * WebKitWebView::resource-load-started:
1518      * @web_view: the #WebKitWebView on which the signal is emitted
1519      * @resource: a #WebKitWebResource
1520      * @request: a #WebKitURIRequest
1521      *
1522      * Emitted when a new resource is going to be loaded. The @request parameter
1523      * contains the #WebKitURIRequest that will be sent to the server.
1524      * You can monitor the load operation by connecting to the different signals
1525      * of @resource.
1526      */
1527     signals[RESOURCE_LOAD_STARTED] = g_signal_new(
1528         "resource-load-started",
1529         G_TYPE_FROM_CLASS(webViewClass),
1530         G_SIGNAL_RUN_LAST,
1531         G_STRUCT_OFFSET(WebKitWebViewClass, resource_load_started),
1532         nullptr, nullptr,
1533         g_cclosure_marshal_generic,
1534         G_TYPE_NONE, 2,
1535         WEBKIT_TYPE_WEB_RESOURCE,
1536                      WEBKIT_TYPE_URI_REQUEST);
1537
1538     /**
1539      * WebKitWebView::enter-fullscreen:
1540      * @web_view: the #WebKitWebView on which the signal is emitted.
1541      *
1542      * Emitted when JavaScript code calls
1543      * <function>element.webkitRequestFullScreen</function>. If the
1544      * signal is not handled the #WebKitWebView will proceed to full screen
1545      * its top level window. This signal can be used by client code to
1546      * request permission to the user prior doing the full screen
1547      * transition and eventually prepare the top-level window
1548      * (e.g. hide some widgets that would otherwise be part of the
1549      * full screen window).
1550      *
1551      * Returns: %TRUE to stop other handlers from being invoked for the event.
1552      *    %FALSE to continue emission of the event.
1553      */
1554     signals[ENTER_FULLSCREEN] = g_signal_new(
1555         "enter-fullscreen",
1556         G_TYPE_FROM_CLASS(webViewClass),
1557         G_SIGNAL_RUN_LAST,
1558         G_STRUCT_OFFSET(WebKitWebViewClass, enter_fullscreen),
1559         g_signal_accumulator_true_handled, nullptr,
1560         g_cclosure_marshal_generic,
1561         G_TYPE_BOOLEAN, 0);
1562
1563     /**
1564      * WebKitWebView::leave-fullscreen:
1565      * @web_view: the #WebKitWebView on which the signal is emitted.
1566      *
1567      * Emitted when the #WebKitWebView is about to restore its top level
1568      * window out of its full screen state. This signal can be used by
1569      * client code to restore widgets hidden during the
1570      * #WebKitWebView::enter-fullscreen stage for instance.
1571      *
1572      * Returns: %TRUE to stop other handlers from being invoked for the event.
1573      *    %FALSE to continue emission of the event.
1574      */
1575     signals[LEAVE_FULLSCREEN] = g_signal_new(
1576         "leave-fullscreen",
1577         G_TYPE_FROM_CLASS(webViewClass),
1578         G_SIGNAL_RUN_LAST,
1579         G_STRUCT_OFFSET(WebKitWebViewClass, leave_fullscreen),
1580         g_signal_accumulator_true_handled, nullptr,
1581         g_cclosure_marshal_generic,
1582         G_TYPE_BOOLEAN, 0);
1583
1584      /**
1585      * WebKitWebView::run-file-chooser:
1586      * @web_view: the #WebKitWebView on which the signal is emitted
1587      * @request: a #WebKitFileChooserRequest
1588      *
1589      * This signal is emitted when the user interacts with a &lt;input
1590      * type='file' /&gt; HTML element, requesting from WebKit to show
1591      * a dialog to select one or more files to be uploaded. To let the
1592      * application know the details of the file chooser, as well as to
1593      * allow the client application to either cancel the request or
1594      * perform an actual selection of files, the signal will pass an
1595      * instance of the #WebKitFileChooserRequest in the @request
1596      * argument.
1597      *
1598      * The default signal handler will asynchronously run a regular
1599      * #GtkFileChooserDialog for the user to interact with.
1600      *
1601      * Returns: %TRUE to stop other handlers from being invoked for the event.
1602      *   %FALSE to propagate the event further.
1603      *
1604      */
1605     signals[RUN_FILE_CHOOSER] = g_signal_new(
1606         "run-file-chooser",
1607         G_TYPE_FROM_CLASS(webViewClass),
1608         G_SIGNAL_RUN_LAST,
1609         G_STRUCT_OFFSET(WebKitWebViewClass, run_file_chooser),
1610         g_signal_accumulator_true_handled, nullptr /* accumulator data */,
1611         g_cclosure_marshal_generic,
1612         G_TYPE_BOOLEAN, 1, /* number of parameters */
1613         WEBKIT_TYPE_FILE_CHOOSER_REQUEST);
1614
1615     /**
1616      * WebKitWebView::context-menu:
1617      * @web_view: the #WebKitWebView on which the signal is emitted
1618      * @context_menu: the proposed #WebKitContextMenu
1619      * @event: the #GdkEvent that triggered the context menu
1620      * @hit_test_result: a #WebKitHitTestResult
1621      *
1622      * Emitted when a context menu is about to be displayed to give the application
1623      * a chance to customize the proposed menu, prevent the menu from being displayed,
1624      * or build its own context menu.
1625      * <itemizedlist>
1626      * <listitem><para>
1627      *  To customize the proposed menu you can use webkit_context_menu_prepend(),
1628      *  webkit_context_menu_append() or webkit_context_menu_insert() to add new
1629      *  #WebKitContextMenuItem<!-- -->s to @context_menu, webkit_context_menu_move_item()
1630      *  to reorder existing items, or webkit_context_menu_remove() to remove an
1631      *  existing item. The signal handler should return %FALSE, and the menu represented
1632      *  by @context_menu will be shown.
1633      * </para></listitem>
1634      * <listitem><para>
1635      *  To prevent the menu from being displayed you can just connect to this signal
1636      *  and return %TRUE so that the proposed menu will not be shown.
1637      * </para></listitem>
1638      * <listitem><para>
1639      *  To build your own menu, you can remove all items from the proposed menu with
1640      *  webkit_context_menu_remove_all(), add your own items and return %FALSE so
1641      *  that the menu will be shown. You can also ignore the proposed #WebKitContextMenu,
1642      *  build your own #GtkMenu and return %TRUE to prevent the proposed menu from being shown.
1643      * </para></listitem>
1644      * <listitem><para>
1645      *  If you just want the default menu to be shown always, simply don't connect to this
1646      *  signal because showing the proposed context menu is the default behaviour.
1647      * </para></listitem>
1648      * </itemizedlist>
1649      *
1650      * The @event is expected to be one of the following types:
1651      * <itemizedlist>
1652      * <listitem><para>
1653      * a #GdkEventButton of type %GDK_BUTTON_PRESS when the context menu
1654      * was triggered with mouse.
1655      * </para></listitem>
1656      * <listitem><para>
1657      * a #GdkEventKey of type %GDK_KEY_PRESS if the keyboard was used to show
1658      * the menu.
1659      * </para></listitem>
1660      * <listitem><para>
1661      * a generic #GdkEvent of type %GDK_NOTHING when the #GtkWidget::popup-menu
1662      * signal was used to show the context menu.
1663      * </para></listitem>
1664      * </itemizedlist>
1665      *
1666      * If the signal handler returns %FALSE the context menu represented by @context_menu
1667      * will be shown, if it return %TRUE the context menu will not be shown.
1668      *
1669      * The proposed #WebKitContextMenu passed in @context_menu argument is only valid
1670      * during the signal emission.
1671      *
1672      * Returns: %TRUE to stop other handlers from being invoked for the event.
1673      *    %FALSE to propagate the event further.
1674      */
1675     signals[CONTEXT_MENU] = g_signal_new(
1676         "context-menu",
1677         G_TYPE_FROM_CLASS(webViewClass),
1678         G_SIGNAL_RUN_LAST,
1679         G_STRUCT_OFFSET(WebKitWebViewClass, context_menu),
1680         g_signal_accumulator_true_handled, nullptr,
1681         g_cclosure_marshal_generic,
1682         G_TYPE_BOOLEAN, 3,
1683         WEBKIT_TYPE_CONTEXT_MENU,
1684 #if PLATFORM(GTK)
1685         GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1686 #elif PLATFORM(WPE)
1687         G_TYPE_POINTER, // FIXME: use a wpe thing here. I'm not sure we want to expose libwpe in the API.
1688 #endif
1689         WEBKIT_TYPE_HIT_TEST_RESULT);
1690
1691     /**
1692      * WebKitWebView::context-menu-dismissed:
1693      * @web_view: the #WebKitWebView on which the signal is emitted
1694      *
1695      * Emitted after #WebKitWebView::context-menu signal, if the context menu is shown,
1696      * to notify that the context menu is dismissed.
1697      */
1698     signals[CONTEXT_MENU_DISMISSED] =
1699         g_signal_new("context-menu-dismissed",
1700                      G_TYPE_FROM_CLASS(webViewClass),
1701                      G_SIGNAL_RUN_LAST,
1702                      G_STRUCT_OFFSET(WebKitWebViewClass, context_menu_dismissed),
1703                      0, 0,
1704                      g_cclosure_marshal_VOID__VOID,
1705                      G_TYPE_NONE, 0);
1706
1707     /**
1708      * WebKitWebView::submit-form:
1709      * @web_view: the #WebKitWebView on which the signal is emitted
1710      * @request: a #WebKitFormSubmissionRequest
1711      *
1712      * This signal is emitted when a form is about to be submitted. The @request
1713      * argument passed contains information about the text fields of the form. This
1714      * is typically used to store login information that can be used later to
1715      * pre-fill the form.
1716      * The form will not be submitted until webkit_form_submission_request_submit() is called.
1717      *
1718      * It is possible to handle the form submission request asynchronously, by
1719      * simply calling g_object_ref() on the @request argument and calling
1720      * webkit_form_submission_request_submit() when done to continue with the form submission.
1721      * If the last reference is removed on a #WebKitFormSubmissionRequest and the
1722      * form has not been submitted, webkit_form_submission_request_submit() will be called.
1723      */
1724     signals[SUBMIT_FORM] =
1725         g_signal_new("submit-form",
1726                      G_TYPE_FROM_CLASS(webViewClass),
1727                      G_SIGNAL_RUN_LAST,
1728                      G_STRUCT_OFFSET(WebKitWebViewClass, submit_form),
1729                      0, 0,
1730                      g_cclosure_marshal_VOID__OBJECT,
1731                      G_TYPE_NONE, 1,
1732                      WEBKIT_TYPE_FORM_SUBMISSION_REQUEST);
1733
1734     /**
1735      * WebKitWebView::insecure-content-detected:
1736      * @web_view: the #WebKitWebView on which the signal is emitted
1737      * @event: the #WebKitInsecureContentEvent
1738      *
1739      * This signal is emitted when insecure content has been detected
1740      * in a page loaded through a secure connection. This typically
1741      * means that a external resource from an unstrusted source has
1742      * been run or displayed, resulting in a mix of HTTPS and
1743      * non-HTTPS content.
1744      *
1745      * You can check the @event parameter to know exactly which kind
1746      * of event has been detected (see #WebKitInsecureContentEvent).
1747      */
1748     signals[INSECURE_CONTENT_DETECTED] =
1749         g_signal_new("insecure-content-detected",
1750             G_TYPE_FROM_CLASS(webViewClass),
1751             G_SIGNAL_RUN_LAST,
1752             G_STRUCT_OFFSET(WebKitWebViewClass, insecure_content_detected),
1753             0, 0,
1754             g_cclosure_marshal_VOID__ENUM,
1755             G_TYPE_NONE, 1,
1756             WEBKIT_TYPE_INSECURE_CONTENT_EVENT);
1757
1758     /**
1759      * WebKitWebView::web-process-crashed:
1760      * @web_view: the #WebKitWebView
1761      *
1762      * This signal is emitted when the web process crashes.
1763      *
1764      * Returns: %TRUE to stop other handlers from being invoked for the event.
1765      *    %FALSE to propagate the event further.
1766      */
1767     signals[WEB_PROCESS_CRASHED] = g_signal_new(
1768         "web-process-crashed",
1769         G_TYPE_FROM_CLASS(webViewClass),
1770         G_SIGNAL_RUN_LAST,
1771         G_STRUCT_OFFSET(WebKitWebViewClass, web_process_crashed),
1772         g_signal_accumulator_true_handled, nullptr,
1773         g_cclosure_marshal_generic,
1774         G_TYPE_BOOLEAN, 0);
1775
1776     /**
1777      * WebKitWebView::authenticate:
1778      * @web_view: the #WebKitWebView on which the signal is emitted
1779      * @request: a #WebKitAuthenticationRequest
1780      *
1781      * This signal is emitted when the user is challenged with HTTP
1782      * authentication. To let the  application access or supply
1783      * the credentials as well as to allow the client application
1784      * to either cancel the request or perform the authentication,
1785      * the signal will pass an instance of the
1786      * #WebKitAuthenticationRequest in the @request argument.
1787      * To handle this signal asynchronously you should keep a ref
1788      * of the request and return %TRUE. To disable HTTP authentication
1789      * entirely, connect to this signal and simply return %TRUE.
1790      *
1791      * The default signal handler will run a default authentication
1792      * dialog asynchronously for the user to interact with.
1793      *
1794      * Returns: %TRUE to stop other handlers from being invoked for the event.
1795      *   %FALSE to propagate the event further.
1796      *
1797      * Since: 2.2
1798      */
1799     signals[AUTHENTICATE] = g_signal_new(
1800         "authenticate",
1801         G_TYPE_FROM_CLASS(webViewClass),
1802         G_SIGNAL_RUN_LAST,
1803         G_STRUCT_OFFSET(WebKitWebViewClass, authenticate),
1804         g_signal_accumulator_true_handled, nullptr /* accumulator data */,
1805         g_cclosure_marshal_generic,
1806         G_TYPE_BOOLEAN, 1, /* number of parameters */
1807         WEBKIT_TYPE_AUTHENTICATION_REQUEST);
1808
1809     /**
1810      * WebKitWebView::show-notification:
1811      * @web_view: the #WebKitWebView
1812      * @notification: a #WebKitNotification
1813      *
1814      * This signal is emitted when a notification should be presented to the
1815      * user. The @notification is kept alive until either: 1) the web page cancels it
1816      * or 2) a navigation happens.
1817      *
1818      * The default handler will emit a notification using libnotify, if built with
1819      * support for it.
1820      *
1821      * Returns: %TRUE to stop other handlers from being invoked. %FALSE otherwise.
1822      *
1823      * Since: 2.8
1824      */
1825     signals[SHOW_NOTIFICATION] = g_signal_new(
1826         "show-notification",
1827         G_TYPE_FROM_CLASS(gObjectClass),
1828         G_SIGNAL_RUN_LAST,
1829         G_STRUCT_OFFSET(WebKitWebViewClass, show_notification),
1830         g_signal_accumulator_true_handled, nullptr /* accumulator data */,
1831         g_cclosure_marshal_generic,
1832         G_TYPE_BOOLEAN, 1,
1833         WEBKIT_TYPE_NOTIFICATION);
1834
1835 #if PLATFORM(GTK)
1836      /**
1837       * WebKitWebView::run-color-chooser:
1838       * @web_view: the #WebKitWebView on which the signal is emitted
1839       * @request: a #WebKitColorChooserRequest
1840       *
1841       * This signal is emitted when the user interacts with a &lt;input
1842       * type='color' /&gt; HTML element, requesting from WebKit to show
1843       * a dialog to select a color. To let the application know the details of
1844       * the color chooser, as well as to allow the client application to either
1845       * cancel the request or perform an actual color selection, the signal will
1846       * pass an instance of the #WebKitColorChooserRequest in the @request
1847       * argument.
1848       *
1849       * It is possible to handle this request asynchronously by increasing the
1850       * reference count of the request.
1851       *
1852       * The default signal handler will asynchronously run a regular
1853       * #GtkColorChooser for the user to interact with.
1854       *
1855       * Returns: %TRUE to stop other handlers from being invoked for the event.
1856       *   %FALSE to propagate the event further.
1857       *
1858       * Since: 2.8
1859       */
1860     signals[RUN_COLOR_CHOOSER] = g_signal_new(
1861         "run-color-chooser",
1862         G_TYPE_FROM_CLASS(webViewClass),
1863         G_SIGNAL_RUN_LAST,
1864         G_STRUCT_OFFSET(WebKitWebViewClass, run_color_chooser),
1865         g_signal_accumulator_true_handled, nullptr,
1866         g_cclosure_marshal_generic,
1867         G_TYPE_BOOLEAN, 1,
1868         WEBKIT_TYPE_COLOR_CHOOSER_REQUEST);
1869
1870     /**
1871      * WebKitWebView::show-option-menu:
1872      * @web_view: the #WebKitWebView on which the signal is emitted
1873      * @menu: the #WebKitOptionMenu
1874      * @event: the #GdkEvent that triggered the menu, or %NULL
1875      * @rectangle: the option element area
1876      *
1877      * This signal is emitted when a select element in @web_view needs to display a
1878      * dropdown menu. This signal can be used to show a custom menu, using @menu to get
1879      * the details of all items that should be displayed. The area of the element in the
1880      * #WebKitWebView is given as @rectangle parameter, it can be used to position the
1881      * menu. If this was triggered by a user interaction, like a mouse click,
1882      * @event parameter provides the #GdkEvent.
1883      * To handle this signal asynchronously you should keep a ref of the @menu.
1884      *
1885      * The default signal handler will pop up a #GtkMenu.
1886      *
1887      * Returns: %TRUE to stop other handlers from being invoked for the event.
1888      *   %FALSE to propagate the event further.
1889      *
1890      * Since: 2.18
1891      */
1892     signals[SHOW_OPTION_MENU] = g_signal_new(
1893         "show-option-menu",
1894         G_TYPE_FROM_CLASS(webViewClass),
1895         G_SIGNAL_RUN_LAST,
1896         G_STRUCT_OFFSET(WebKitWebViewClass, show_option_menu),
1897         g_signal_accumulator_true_handled, nullptr,
1898         g_cclosure_marshal_generic,
1899         G_TYPE_BOOLEAN, 3,
1900         WEBKIT_TYPE_OPTION_MENU,
1901         GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE,
1902         GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
1903 #endif // PLATFORM(GTK)
1904 }
1905
1906 static void webkitWebViewCancelAuthenticationRequest(WebKitWebView* webView)
1907 {
1908     if (!webView->priv->authenticationRequest)
1909         return;
1910
1911     webkit_authentication_request_cancel(webView->priv->authenticationRequest.get());
1912     webView->priv->authenticationRequest.clear();
1913 }
1914
1915 void webkitWebViewCreatePage(WebKitWebView* webView, Ref<API::PageConfiguration>&& configuration)
1916 {
1917 #if PLATFORM(GTK)
1918     webkitWebViewBaseCreateWebPage(WEBKIT_WEB_VIEW_BASE(webView), WTFMove(configuration));
1919 #elif PLATFORM(WPE)
1920     webView->priv->view.reset(WKWPE::View::create(nullptr, configuration.get()));
1921 #endif
1922 }
1923
1924 WebPageProxy& webkitWebViewGetPage(WebKitWebView* webView)
1925 {
1926     return getPage(webView);
1927 }
1928
1929 void webkitWebViewLoadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent)
1930 {
1931     WebKitWebViewPrivate* priv = webView->priv;
1932     switch (loadEvent) {
1933     case WEBKIT_LOAD_STARTED:
1934 #if PLATFORM(GTK)
1935         webkitWebViewCancelFaviconRequest(webView);
1936         webkitWebViewWatchForChangesInFavicon(webView);
1937 #endif
1938         webkitWebViewCancelAuthenticationRequest(webView);
1939         priv->loadingResourcesMap.clear();
1940         priv->mainResource = nullptr;
1941         break;
1942 #if PLATFORM(GTK)
1943     case WEBKIT_LOAD_COMMITTED: {
1944         WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(priv->context.get());
1945         GUniquePtr<char> faviconURI(webkit_favicon_database_get_favicon_uri(database, priv->activeURI.data()));
1946         webkitWebViewUpdateFaviconURI(webView, faviconURI.get());
1947         break;
1948     }
1949 #endif
1950     case WEBKIT_LOAD_FINISHED:
1951         webkitWebViewCancelAuthenticationRequest(webView);
1952         break;
1953     default:
1954         break;
1955     }
1956
1957     g_signal_emit(webView, signals[LOAD_CHANGED], 0, loadEvent);
1958 }
1959
1960 void webkitWebViewLoadFailed(WebKitWebView* webView, WebKitLoadEvent loadEvent, const char* failingURI, GError *error)
1961 {
1962     webkitWebViewCancelAuthenticationRequest(webView);
1963
1964     gboolean returnValue;
1965     g_signal_emit(webView, signals[LOAD_FAILED], 0, loadEvent, failingURI, error, &returnValue);
1966     g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1967 }
1968
1969 void webkitWebViewLoadFailedWithTLSErrors(WebKitWebView* webView, const char* failingURI, GError* error, GTlsCertificateFlags tlsErrors, GTlsCertificate* certificate)
1970 {
1971     webkitWebViewCancelAuthenticationRequest(webView);
1972
1973     WebKitTLSErrorsPolicy tlsErrorsPolicy = webkit_web_context_get_tls_errors_policy(webView->priv->context.get());
1974     if (tlsErrorsPolicy == WEBKIT_TLS_ERRORS_POLICY_FAIL) {
1975         gboolean returnValue;
1976         g_signal_emit(webView, signals[LOAD_FAILED_WITH_TLS_ERRORS], 0, failingURI, certificate, tlsErrors, &returnValue);
1977         if (!returnValue)
1978             g_signal_emit(webView, signals[LOAD_FAILED], 0, WEBKIT_LOAD_STARTED, failingURI, error, &returnValue);
1979     }
1980
1981     g_signal_emit(webView, signals[LOAD_CHANGED], 0, WEBKIT_LOAD_FINISHED);
1982 }
1983
1984 #if PLATFORM(GTK)
1985 void webkitWebViewGetLoadDecisionForIcon(WebKitWebView* webView, const LinkIcon& icon, Function<void(bool)>&& completionHandler)
1986 {
1987     WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(webView->priv->context.get());
1988     webkitFaviconDatabaseGetLoadDecisionForIcon(database, icon, getPage(webView).pageLoadState().activeURL(), WTFMove(completionHandler));
1989 }
1990
1991 void webkitWebViewSetIcon(WebKitWebView* webView, const LinkIcon& icon, API::Data& iconData)
1992 {
1993     WebKitFaviconDatabase* database = webkit_web_context_get_favicon_database(webView->priv->context.get());
1994     webkitFaviconDatabaseSetIconForPageURL(database, icon, iconData, getPage(webView).pageLoadState().activeURL());
1995 }
1996 #endif
1997
1998 WebPageProxy* webkitWebViewCreateNewPage(WebKitWebView* webView, const WindowFeatures& windowFeatures, WebKitNavigationAction* navigationAction)
1999 {
2000     WebKitWebView* newWebView;
2001     g_signal_emit(webView, signals[CREATE], 0, navigationAction, &newWebView);
2002     if (!newWebView)
2003         return 0;
2004
2005     webkitWindowPropertiesUpdateFromWebWindowFeatures(newWebView->priv->windowProperties.get(), windowFeatures);
2006
2007     RefPtr<WebPageProxy> newPage = &getPage(newWebView);
2008     return newPage.leakRef();
2009 }
2010
2011 void webkitWebViewReadyToShowPage(WebKitWebView* webView)
2012 {
2013     g_signal_emit(webView, signals[READY_TO_SHOW], 0, NULL);
2014 }
2015
2016 void webkitWebViewRunAsModal(WebKitWebView* webView)
2017 {
2018     g_signal_emit(webView, signals[RUN_AS_MODAL], 0, NULL);
2019
2020     webView->priv->modalLoop = adoptGRef(g_main_loop_new(0, FALSE));
2021
2022 #if PLATFORM(GTK)
2023 // This is to suppress warnings about gdk_threads_leave and gdk_threads_enter.
2024 #pragma GCC diagnostic push
2025 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2026     gdk_threads_leave();
2027 #endif
2028
2029     g_main_loop_run(webView->priv->modalLoop.get());
2030
2031 #if PLATFORM(GTK)
2032     gdk_threads_enter();
2033 #pragma GCC diagnostic pop
2034 #endif
2035 }
2036
2037 void webkitWebViewClosePage(WebKitWebView* webView)
2038 {
2039     g_signal_emit(webView, signals[CLOSE], 0, NULL);
2040 }
2041
2042 void webkitWebViewRunJavaScriptAlert(WebKitWebView* webView, const CString& message)
2043 {
2044     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_ALERT, message);
2045     SetForScope<WebKitScriptDialog*> change(webView->priv->currentScriptDialog, &dialog);
2046     gboolean returnValue;
2047     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
2048 }
2049
2050 bool webkitWebViewRunJavaScriptConfirm(WebKitWebView* webView, const CString& message)
2051 {
2052     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_CONFIRM, message);
2053     SetForScope<WebKitScriptDialog*> change(webView->priv->currentScriptDialog, &dialog);
2054     gboolean returnValue;
2055     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
2056     return dialog.confirmed;
2057 }
2058
2059 CString webkitWebViewRunJavaScriptPrompt(WebKitWebView* webView, const CString& message, const CString& defaultText)
2060 {
2061     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_PROMPT, message, defaultText);
2062     SetForScope<WebKitScriptDialog*> change(webView->priv->currentScriptDialog, &dialog);
2063     gboolean returnValue;
2064     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
2065     return dialog.text;
2066 }
2067
2068 bool webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const CString& message)
2069 {
2070     WebKitScriptDialog dialog(WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM, message);
2071     SetForScope<WebKitScriptDialog*> change(webView->priv->currentScriptDialog, &dialog);
2072     gboolean returnValue;
2073     g_signal_emit(webView, signals[SCRIPT_DIALOG], 0, &dialog, &returnValue);
2074     return dialog.confirmed;
2075 }
2076
2077 bool webkitWebViewIsShowingScriptDialog(WebKitWebView* webView)
2078 {
2079     if (!webView->priv->currentScriptDialog)
2080         return false;
2081
2082     // FIXME: Add API to ask the user in case default implementation is not being used.
2083     return webkitScriptDialogIsRunning(webView->priv->currentScriptDialog);
2084 }
2085
2086 String webkitWebViewGetCurrentScriptDialogMessage(WebKitWebView* webView)
2087 {
2088     if (!webView->priv->currentScriptDialog)
2089         return { };
2090
2091     return String::fromUTF8(webView->priv->currentScriptDialog->message);
2092 }
2093
2094 void webkitWebViewSetCurrentScriptDialogUserInput(WebKitWebView* webView, const String& userInput)
2095 {
2096     if (!webView->priv->currentScriptDialog)
2097         return;
2098
2099     // FIXME: Add API to ask the user in case default implementation is not being used.
2100     if (webkitScriptDialogIsRunning(webView->priv->currentScriptDialog))
2101         webkitScriptDialogSetUserInput(webView->priv->currentScriptDialog, userInput);
2102 }
2103
2104 void webkitWebViewAcceptCurrentScriptDialog(WebKitWebView* webView)
2105 {
2106     if (!webView->priv->currentScriptDialog)
2107         return;
2108
2109     // FIXME: Add API to ask the user in case default implementation is not being used.
2110     if (webkitScriptDialogIsRunning(webView->priv->currentScriptDialog))
2111         webkitScriptDialogAccept(webView->priv->currentScriptDialog);
2112 }
2113
2114 void webkitWebViewDismissCurrentScriptDialog(WebKitWebView* webView)
2115 {
2116     if (!webView->priv->currentScriptDialog)
2117         return;
2118
2119     // FIXME: Add API to ask the user in case default implementation is not being used.
2120     if (webkitScriptDialogIsRunning(webView->priv->currentScriptDialog))
2121         webkitScriptDialogDismiss(webView->priv->currentScriptDialog);
2122 }
2123
2124 std::optional<WebKitScriptDialogType> webkitWebViewGetCurrentScriptDialogType(WebKitWebView* webView)
2125 {
2126     if (!webView->priv->currentScriptDialog)
2127         return std::nullopt;
2128
2129     return static_cast<WebKitScriptDialogType>(webView->priv->currentScriptDialog->type);
2130 }
2131
2132 void webkitWebViewMakePolicyDecision(WebKitWebView* webView, WebKitPolicyDecisionType type, WebKitPolicyDecision* decision)
2133 {
2134     gboolean returnValue;
2135     g_signal_emit(webView, signals[DECIDE_POLICY], 0, decision, type, &returnValue);
2136 }
2137
2138 void webkitWebViewMakePermissionRequest(WebKitWebView* webView, WebKitPermissionRequest* request)
2139 {
2140     gboolean returnValue;
2141     g_signal_emit(webView, signals[PERMISSION_REQUEST], 0, request, &returnValue);
2142 }
2143
2144 void webkitWebViewMouseTargetChanged(WebKitWebView* webView, const WebHitTestResultData& hitTestResult, WebEvent::Modifiers modifiers)
2145 {
2146 #if PLATFORM(GTK)
2147     webkitWebViewBaseSetTooltipArea(WEBKIT_WEB_VIEW_BASE(webView), hitTestResult.elementBoundingBox);
2148 #endif
2149
2150     WebKitWebViewPrivate* priv = webView->priv;
2151     if (priv->mouseTargetHitTestResult
2152         && priv->mouseTargetModifiers == modifiers
2153         && webkitHitTestResultCompare(priv->mouseTargetHitTestResult.get(), hitTestResult))
2154         return;
2155
2156     priv->mouseTargetModifiers = modifiers;
2157     priv->mouseTargetHitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResult));
2158     g_signal_emit(webView, signals[MOUSE_TARGET_CHANGED], 0, priv->mouseTargetHitTestResult.get(), toPlatformModifiers(modifiers));
2159 }
2160
2161 void webkitWebViewHandleDownloadRequest(WebKitWebView* webView, DownloadProxy* downloadProxy)
2162 {
2163     ASSERT(downloadProxy);
2164     GRefPtr<WebKitDownload> download = webkitWebContextGetOrCreateDownload(downloadProxy);
2165     webkitDownloadSetWebView(download.get(), webView);
2166 }
2167
2168 #if PLATFORM(GTK)
2169 void webkitWebViewPrintFrame(WebKitWebView* webView, WebFrameProxy* frame)
2170 {
2171     auto printOperation = adoptGRef(webkit_print_operation_new(webView));
2172     webkitPrintOperationSetPrintMode(printOperation.get(), PrintInfo::PrintModeSync);
2173     gboolean returnValue;
2174     g_signal_emit(webView, signals[PRINT], 0, printOperation.get(), &returnValue);
2175     if (returnValue)
2176         return;
2177
2178     WebKitPrintOperationResponse response = webkitPrintOperationRunDialogForFrame(printOperation.get(), 0, frame);
2179     if (response == WEBKIT_PRINT_OPERATION_RESPONSE_CANCEL)
2180         return;
2181     g_signal_connect(printOperation.leakRef(), "finished", G_CALLBACK(g_object_unref), 0);
2182 }
2183 #endif
2184
2185 void webkitWebViewResourceLoadStarted(WebKitWebView* webView, WebFrameProxy* frame, uint64_t resourceIdentifier, WebKitURIRequest* request)
2186 {
2187     WebKitWebViewPrivate* priv = webView->priv;
2188     bool isMainResource = frame->isMainFrame() && !priv->mainResource;
2189     WebKitWebResource* resource = webkitWebResourceCreate(frame, request, isMainResource);
2190     if (isMainResource)
2191         priv->mainResource = resource;
2192     priv->loadingResourcesMap.set(resourceIdentifier, adoptGRef(resource));
2193     g_signal_emit(webView, signals[RESOURCE_LOAD_STARTED], 0, resource, request);
2194 }
2195
2196 WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
2197 {
2198     GRefPtr<WebKitWebResource> resource = webView->priv->loadingResourcesMap.get(resourceIdentifier);
2199     return resource.get();
2200 }
2201
2202 void webkitWebViewRemoveLoadingWebResource(WebKitWebView* webView, uint64_t resourceIdentifier)
2203 {
2204     WebKitWebViewPrivate* priv = webView->priv;
2205     ASSERT(priv->loadingResourcesMap.contains(resourceIdentifier));
2206     priv->loadingResourcesMap.remove(resourceIdentifier);
2207 }
2208
2209 void webkitWebViewEnterFullScreen(WebKitWebView* webView)
2210 {
2211 #if ENABLE(FULLSCREEN_API)
2212     gboolean returnValue;
2213     g_signal_emit(webView, signals[ENTER_FULLSCREEN], 0, &returnValue);
2214 #if PLATFORM(GTK)
2215     if (!returnValue)
2216         webkitWebViewBaseEnterFullScreen(WEBKIT_WEB_VIEW_BASE(webView));
2217 #endif
2218 #endif
2219 }
2220
2221 void webkitWebViewExitFullScreen(WebKitWebView* webView)
2222 {
2223 #if ENABLE(FULLSCREEN_API)
2224     gboolean returnValue;
2225     g_signal_emit(webView, signals[LEAVE_FULLSCREEN], 0, &returnValue);
2226 #if PLATFORM(GTK)
2227     if (!returnValue)
2228         webkitWebViewBaseExitFullScreen(WEBKIT_WEB_VIEW_BASE(webView));
2229 #endif
2230 #endif
2231 }
2232
2233 void webkitWebViewRunFileChooserRequest(WebKitWebView* webView, WebKitFileChooserRequest* request)
2234 {
2235     gboolean returnValue;
2236     g_signal_emit(webView, signals[RUN_FILE_CHOOSER], 0, request, &returnValue);
2237 }
2238
2239 #if PLATFORM(GTK)
2240 static void contextMenuDismissed(GtkMenuShell*, WebKitWebView* webView)
2241 {
2242     g_signal_emit(webView, signals[CONTEXT_MENU_DISMISSED], 0, NULL);
2243 }
2244
2245 void webkitWebViewPopulateContextMenu(WebKitWebView* webView, const Vector<WebContextMenuItemData>& proposedMenu, const WebHitTestResultData& hitTestResultData, GVariant* userData)
2246 {
2247     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(webView);
2248     WebContextMenuProxyGtk* contextMenuProxy = webkitWebViewBaseGetActiveContextMenuProxy(webViewBase);
2249     ASSERT(contextMenuProxy);
2250
2251     GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(proposedMenu));
2252     if (userData)
2253         webkit_context_menu_set_user_data(WEBKIT_CONTEXT_MENU(contextMenu.get()), userData);
2254
2255     GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResultData));
2256     GUniquePtr<GdkEvent> contextMenuEvent(webkitWebViewBaseTakeContextMenuEvent(webViewBase));
2257     gboolean returnValue;
2258     g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), contextMenuEvent.get(), hitTestResult.get(), &returnValue);
2259     if (returnValue)
2260         return;
2261
2262     Vector<WebContextMenuItemGlib> contextMenuItems;
2263     webkitContextMenuPopulate(contextMenu.get(), contextMenuItems);
2264     contextMenuProxy->populate(contextMenuItems);
2265
2266     g_signal_connect(contextMenuProxy->gtkMenu(), "deactivate", G_CALLBACK(contextMenuDismissed), webView);
2267
2268     // Clear the menu to make sure it's useless after signal emission.
2269     webkit_context_menu_remove_all(contextMenu.get());
2270 }
2271 #elif PLATFORM(WPE)
2272 void webkitWebViewPopulateContextMenu(WebKitWebView* webView, const Vector<WebContextMenuItemData>& proposedMenu, const WebHitTestResultData& hitTestResultData, GVariant* userData)
2273 {
2274     GRefPtr<WebKitContextMenu> contextMenu = adoptGRef(webkitContextMenuCreate(proposedMenu));
2275     if (userData)
2276         webkit_context_menu_set_user_data(WEBKIT_CONTEXT_MENU(contextMenu.get()), userData);
2277     GRefPtr<WebKitHitTestResult> hitTestResult = adoptGRef(webkitHitTestResultCreate(hitTestResultData));
2278     gboolean returnValue;
2279     g_signal_emit(webView, signals[CONTEXT_MENU], 0, contextMenu.get(), nullptr, hitTestResult.get(), &returnValue);
2280 }
2281 #endif
2282
2283 void webkitWebViewSubmitFormRequest(WebKitWebView* webView, WebKitFormSubmissionRequest* request)
2284 {
2285     g_signal_emit(webView, signals[SUBMIT_FORM], 0, request);
2286 }
2287
2288 void webkitWebViewHandleAuthenticationChallenge(WebKitWebView* webView, AuthenticationChallengeProxy* authenticationChallenge)
2289 {
2290     G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2291     gboolean privateBrowsingEnabled = webView->priv->isEphemeral || webkit_settings_get_enable_private_browsing(webView->priv->settings.get());
2292     G_GNUC_END_IGNORE_DEPRECATIONS;
2293     webView->priv->authenticationRequest = adoptGRef(webkitAuthenticationRequestCreate(authenticationChallenge, privateBrowsingEnabled));
2294     gboolean returnValue;
2295     g_signal_emit(webView, signals[AUTHENTICATE], 0, webView->priv->authenticationRequest.get(), &returnValue);
2296 }
2297
2298 void webkitWebViewInsecureContentDetected(WebKitWebView* webView, WebKitInsecureContentEvent type)
2299 {
2300     g_signal_emit(webView, signals[INSECURE_CONTENT_DETECTED], 0, type);
2301 }
2302
2303 bool webkitWebViewEmitShowNotification(WebKitWebView* webView, WebKitNotification* webNotification)
2304 {
2305     gboolean handled;
2306     g_signal_emit(webView, signals[SHOW_NOTIFICATION], 0, webNotification, &handled);
2307     return handled;
2308 }
2309
2310 #if PLATFORM(GTK)
2311 bool webkitWebViewEmitRunColorChooser(WebKitWebView* webView, WebKitColorChooserRequest* request)
2312 {
2313     gboolean handled;
2314     g_signal_emit(webView, signals[RUN_COLOR_CHOOSER], 0, request, &handled);
2315     return handled;
2316 }
2317 #endif
2318
2319 void webkitWebViewSelectionDidChange(WebKitWebView* webView)
2320 {
2321     if (!webView->priv->editorState)
2322         return;
2323
2324     webkitEditorStateChanged(webView->priv->editorState.get(), getPage(webView).editorState());
2325 }
2326
2327 void webkitWebViewRequestInstallMissingMediaPlugins(WebKitWebView* webView, InstallMissingMediaPluginsPermissionRequest& request)
2328 {
2329 #if ENABLE(VIDEO)
2330     GRefPtr<WebKitInstallMissingMediaPluginsPermissionRequest> installMediaPluginsPermissionRequest = adoptGRef(webkitInstallMissingMediaPluginsPermissionRequestCreate(request));
2331     webkitWebViewMakePermissionRequest(webView, WEBKIT_PERMISSION_REQUEST(installMediaPluginsPermissionRequest.get()));
2332 #else
2333     ASSERT_NOT_REACHED();
2334 #endif
2335 }
2336
2337 WebKitWebsiteDataManager* webkitWebViewGetWebsiteDataManager(WebKitWebView* webView)
2338 {
2339     return webView->priv->websiteDataManager.get();
2340 }
2341
2342 #if PLATFORM(GTK)
2343 bool webkitWebViewShowOptionMenu(WebKitWebView* webView, const IntRect& rect, WebKitOptionMenu* menu, const GdkEvent* event)
2344 {
2345     GdkRectangle menuRect = rect;
2346     gboolean handled;
2347     g_signal_emit(webView, signals[SHOW_OPTION_MENU], 0, menu, event, &menuRect, &handled);
2348     return handled;
2349 }
2350 #endif
2351
2352 /**
2353  * webkit_web_view_get_context:
2354  * @web_view: a #WebKitWebView
2355  *
2356  * Gets the web context of @web_view.
2357  *
2358  * Returns: (transfer none): the #WebKitWebContext of the view
2359  */
2360 WebKitWebContext* webkit_web_view_get_context(WebKitWebView *webView)
2361 {
2362     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2363
2364     return webView->priv->context.get();
2365 }
2366
2367 /**
2368  * webkit_web_view_get_user_content_manager:
2369  * @web_view: a #WebKitWebView
2370  *
2371  * Gets the user content manager associated to @web_view.
2372  *
2373  * Returns: (transfer none): the #WebKitUserContentManager associated with the view
2374  *
2375  * Since: 2.6
2376  */
2377 WebKitUserContentManager* webkit_web_view_get_user_content_manager(WebKitWebView* webView)
2378 {
2379     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
2380
2381     return webView->priv->userContentManager.get();
2382 }
2383
2384 /**
2385  * webkit_web_view_is_ephemeral:
2386  * @web_view: a #WebKitWebView
2387  *
2388  * Get whether a #WebKitWebView is ephemeral. To create an ephemeral #WebKitWebView you need to
2389  * use g_object_new() and pass is-ephemeral property with %TRUE value. See
2390  * #WebKitWebView:is-ephemeral for more details.
2391  * If @web_view was created with a ephemeral #WebKitWebView:related-view or an
2392  * ephemeral #WebKitWebView:web-context it will also be ephemeral.
2393  *
2394  * Returns: %TRUE if @web_view is ephemeral or %FALSE otherwise.
2395  *
2396  * Since: 2.16
2397  */
2398 gboolean webkit_web_view_is_ephemeral(WebKitWebView* webView)
2399 {
2400     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2401
2402     return webView->priv->isEphemeral;
2403 }
2404
2405 /**
2406  * webkit_web_view_is_controlled_by_automation:
2407  * @web_view: a #WebKitWebView
2408  *
2409  * Get whether a #WebKitWebView was created with #WebKitWebView:is-controlled-by-automation
2410  * property enabled. Only #WebKitWebView<!-- -->s controlled by automation can be used in an
2411  * automation session.
2412  *
2413  * Returns: %TRUE if @web_view is controlled by automation, or %FALSE otherwise.
2414  *
2415  * Since: 2.18
2416  */
2417 gboolean webkit_web_view_is_controlled_by_automation(WebKitWebView* webView)
2418 {
2419     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2420
2421     return webView->priv->isControlledByAutomation;
2422 }
2423
2424 /**
2425  * webkit_web_view_get_website_data_manager:
2426  * @web_view: a #WebKitWebView
2427  *
2428  * Get the #WebKitWebsiteDataManager associated to @web_view. If @web_view is not ephemeral,
2429  * the returned #WebKitWebsiteDataManager will be the same as the #WebKitWebsiteDataManager
2430  * of @web_view's #WebKitWebContext.
2431  *
2432  * Returns: (transfer none): a #WebKitWebsiteDataManager
2433  *
2434  * Since: 2.16
2435  */
2436 WebKitWebsiteDataManager* webkit_web_view_get_website_data_manager(WebKitWebView* webView)
2437 {
2438     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
2439
2440     if (webView->priv->websiteDataManager)
2441         return webView->priv->websiteDataManager.get();
2442
2443     return webkit_web_context_get_website_data_manager(webView->priv->context.get());
2444 }
2445
2446 /**
2447  * webkit_web_view_try_close:
2448  * @web_view: a #WebKitWebView
2449  *
2450  * Tries to close the @web_view. This will fire the onbeforeunload event
2451  * to ask the user for confirmation to close the page. If there isn't an
2452  * onbeforeunload event handler or the user confirms to close the page,
2453  * the #WebKitWebView::close signal is emitted, otherwise nothing happens.
2454  *
2455  * Since: 2.12
2456  */
2457 void webkit_web_view_try_close(WebKitWebView *webView)
2458 {
2459     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2460     if (getPage(webView).tryClose())
2461         webkitWebViewClosePage(webView);
2462 }
2463
2464 /**
2465  * webkit_web_view_load_uri:
2466  * @web_view: a #WebKitWebView
2467  * @uri: an URI string
2468  *
2469  * Requests loading of the specified URI string.
2470  * You can monitor the load operation by connecting to
2471  * #WebKitWebView::load-changed signal.
2472  */
2473 void webkit_web_view_load_uri(WebKitWebView* webView, const gchar* uri)
2474 {
2475     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2476     g_return_if_fail(uri);
2477
2478     GUniquePtr<SoupURI> soupURI(soup_uri_new(uri));
2479     getPage(webView).loadRequest(URL(soupURI.get()));
2480 }
2481
2482 /**
2483  * webkit_web_view_load_html:
2484  * @web_view: a #WebKitWebView
2485  * @content: The HTML string to load
2486  * @base_uri: (allow-none): The base URI for relative locations or %NULL
2487  *
2488  * Load the given @content string with the specified @base_uri.
2489  * If @base_uri is not %NULL, relative URLs in the @content will be
2490  * resolved against @base_uri and absolute local paths must be children of the @base_uri.
2491  * For security reasons absolute local paths that are not children of @base_uri
2492  * will cause the web process to terminate.
2493  * If you need to include URLs in @content that are local paths in a different
2494  * directory than @base_uri you can build a data URI for them. When @base_uri is %NULL,
2495  * it defaults to "about:blank". The mime type of the document will be "text/html".
2496  * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal.
2497  */
2498 void webkit_web_view_load_html(WebKitWebView* webView, const gchar* content, const gchar* baseURI)
2499 {
2500     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2501     g_return_if_fail(content);
2502
2503     getPage(webView).loadHTMLString(String::fromUTF8(content), String::fromUTF8(baseURI));
2504 }
2505
2506 /**
2507  * webkit_web_view_load_alternate_html:
2508  * @web_view: a #WebKitWebView
2509  * @content: the new content to display as the main page of the @web_view
2510  * @content_uri: the URI for the alternate page content
2511  * @base_uri: (allow-none): the base URI for relative locations or %NULL
2512  *
2513  * Load the given @content string for the URI @content_uri.
2514  * This allows clients to display page-loading errors in the #WebKitWebView itself.
2515  * When this method is called from #WebKitWebView::load-failed signal to show an
2516  * error page, then the back-forward list is maintained appropriately.
2517  * For everything else this method works the same way as webkit_web_view_load_html().
2518  */
2519 void webkit_web_view_load_alternate_html(WebKitWebView* webView, const gchar* content, const gchar* contentURI, const gchar* baseURI)
2520 {
2521     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2522     g_return_if_fail(content);
2523     g_return_if_fail(contentURI);
2524
2525     getPage(webView).loadAlternateHTMLString(String::fromUTF8(content), URL(URL(), String::fromUTF8(baseURI)), URL(URL(), String::fromUTF8(contentURI)));
2526 }
2527
2528 /**
2529  * webkit_web_view_load_plain_text:
2530  * @web_view: a #WebKitWebView
2531  * @plain_text: The plain text to load
2532  *
2533  * Load the specified @plain_text string into @web_view. The mime type of
2534  * document will be "text/plain". You can monitor the load
2535  * operation by connecting to #WebKitWebView::load-changed signal.
2536  */
2537 void webkit_web_view_load_plain_text(WebKitWebView* webView, const gchar* plainText)
2538 {
2539     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2540     g_return_if_fail(plainText);
2541
2542     getPage(webView).loadPlainTextString(String::fromUTF8(plainText));
2543 }
2544
2545 static void releaseGBytes(unsigned char*, const void* bytes)
2546 {
2547     // Balanced by g_bytes_ref in webkit_web_view_load_bytes().
2548     g_bytes_unref(static_cast<GBytes*>(const_cast<void*>(bytes)));
2549 }
2550
2551 /**
2552  * webkit_web_view_load_bytes:
2553  * @web_view: a #WebKitWebView
2554  * @bytes: input data to load
2555  * @mime_type: (allow-none): the MIME type of @bytes, or %NULL
2556  * @encoding: (allow-none): the character encoding of @bytes, or %NULL
2557  * @base_uri: (allow-none): the base URI for relative locations or %NULL
2558  *
2559  * Load the specified @bytes into @web_view using the given @mime_type and @encoding.
2560  * When @mime_type is %NULL, it defaults to "text/html".
2561  * When @encoding is %NULL, it defaults to "UTF-8".
2562  * When @base_uri is %NULL, it defaults to "about:blank".
2563  * You can monitor the load operation by connecting to #WebKitWebView::load-changed signal.
2564  *
2565  * Since: 2.6
2566  */
2567 void webkit_web_view_load_bytes(WebKitWebView* webView, GBytes* bytes, const char* mimeType, const char* encoding, const char* baseURI)
2568 {
2569     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2570     g_return_if_fail(bytes);
2571
2572     gsize bytesDataSize;
2573     gconstpointer bytesData = g_bytes_get_data(bytes, &bytesDataSize);
2574     g_return_if_fail(bytesDataSize);
2575
2576     // Balanced by g_bytes_unref in releaseGBytes.
2577     g_bytes_ref(bytes);
2578
2579     Ref<API::Data> data = API::Data::createWithoutCopying(static_cast<const unsigned char*>(bytesData), bytesDataSize, releaseGBytes, bytes);
2580     getPage(webView).loadData(data.ptr(), mimeType ? String::fromUTF8(mimeType) : String::fromUTF8("text/html"),
2581         encoding ? String::fromUTF8(encoding) : String::fromUTF8("UTF-8"), String::fromUTF8(baseURI));
2582 }
2583
2584 /**
2585  * webkit_web_view_load_request:
2586  * @web_view: a #WebKitWebView
2587  * @request: a #WebKitURIRequest to load
2588  *
2589  * Requests loading of the specified #WebKitURIRequest.
2590  * You can monitor the load operation by connecting to
2591  * #WebKitWebView::load-changed signal.
2592  */
2593 void webkit_web_view_load_request(WebKitWebView* webView, WebKitURIRequest* request)
2594 {
2595     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2596     g_return_if_fail(WEBKIT_IS_URI_REQUEST(request));
2597
2598     ResourceRequest resourceRequest;
2599     webkitURIRequestGetResourceRequest(request, resourceRequest);
2600     getPage(webView).loadRequest(WTFMove(resourceRequest));
2601 }
2602
2603 /**
2604  * webkit_web_view_get_page_id:
2605  * @web_view: a #WebKitWebView
2606  *
2607  * Get the identifier of the #WebKitWebPage corresponding to
2608  * the #WebKitWebView
2609  *
2610  * Returns: the page ID of @web_view.
2611  */
2612 guint64 webkit_web_view_get_page_id(WebKitWebView* webView)
2613 {
2614     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2615
2616     return getPage(webView).pageID();
2617 }
2618
2619 /**
2620  * webkit_web_view_get_title:
2621  * @web_view: a #WebKitWebView
2622  *
2623  * Gets the value of the #WebKitWebView:title property.
2624  * You can connect to notify::title signal of @web_view to
2625  * be notified when the title has been received.
2626  *
2627  * Returns: The main frame document title of @web_view.
2628  */
2629 const gchar* webkit_web_view_get_title(WebKitWebView* webView)
2630 {
2631     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2632
2633     return webView->priv->title.data();
2634 }
2635
2636 /**
2637  * webkit_web_view_reload:
2638  * @web_view: a #WebKitWebView
2639  *
2640  * Reloads the current contents of @web_view.
2641  * See also webkit_web_view_reload_bypass_cache().
2642  */
2643 void webkit_web_view_reload(WebKitWebView* webView)
2644 {
2645     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2646
2647     getPage(webView).reload({ });
2648 }
2649
2650 /**
2651  * webkit_web_view_reload_bypass_cache:
2652  * @web_view: a #WebKitWebView
2653  *
2654  * Reloads the current contents of @web_view without
2655  * using any cached data.
2656  */
2657 void webkit_web_view_reload_bypass_cache(WebKitWebView* webView)
2658 {
2659     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2660
2661     getPage(webView).reload(ReloadOption::FromOrigin);
2662 }
2663
2664 /**
2665  * webkit_web_view_stop_loading:
2666  * @web_view: a #WebKitWebView
2667  *
2668  * Stops any ongoing loading operation in @web_view.
2669  * This method does nothing if no content is being loaded.
2670  * If there is a loading operation in progress, it will be cancelled and
2671  * #WebKitWebView::load-failed signal will be emitted with
2672  * %WEBKIT_NETWORK_ERROR_CANCELLED error.
2673  */
2674 void webkit_web_view_stop_loading(WebKitWebView* webView)
2675 {
2676     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2677
2678     getPage(webView).stopLoading();
2679 }
2680
2681 /**
2682  * webkit_web_view_is_loading:
2683  * @web_view: a #WebKitWebView
2684  *
2685  * Gets the value of the #WebKitWebView:is-loading property.
2686  * You can monitor when a #WebKitWebView is loading a page by connecting to
2687  * notify::is-loading signal of @web_view. This is useful when you are
2688  * interesting in knowing when the view is loading something but not in the
2689  * details about the status of the load operation, for example to start a spinner
2690  * when the view is loading a page and stop it when it finishes.
2691  *
2692  * Returns: %TRUE if @web_view is loading a page or %FALSE otherwise.
2693  */
2694 gboolean webkit_web_view_is_loading(WebKitWebView* webView)
2695 {
2696     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2697
2698     return webView->priv->isLoading;
2699 }
2700
2701 /**
2702  * webkit_web_view_is_playing_audio:
2703  * @web_view: a #WebKitWebView
2704  *
2705  * Gets the value of the #WebKitWebView:is-playing-audio property.
2706  * You can monitor when a page in a #WebKitWebView is playing audio by
2707  * connecting to the notify::is-playing-audio signal of @web_view. This
2708  * is useful when the application wants to provide visual feedback when a
2709  * page is producing sound.
2710  *
2711  * Returns: %TRUE if a page in @web_view is playing audio or %FALSE otherwise.
2712  *
2713  * Since: 2.8
2714  */
2715 gboolean webkit_web_view_is_playing_audio(WebKitWebView* webView)
2716 {
2717     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2718
2719     return getPage(webView).isPlayingAudio();
2720 }
2721
2722 /**
2723  * webkit_web_view_go_back:
2724  * @web_view: a #WebKitWebView
2725  *
2726  * Loads the previous history item.
2727  * You can monitor the load operation by connecting to
2728  * #WebKitWebView::load-changed signal.
2729  */
2730 void webkit_web_view_go_back(WebKitWebView* webView)
2731 {
2732     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2733
2734     getPage(webView).goBack();
2735 }
2736
2737 /**
2738  * webkit_web_view_can_go_back:
2739  * @web_view: a #WebKitWebView
2740  *
2741  * Determines whether @web_view has a previous history item.
2742  *
2743  * Returns: %TRUE if able to move back or %FALSE otherwise.
2744  */
2745 gboolean webkit_web_view_can_go_back(WebKitWebView* webView)
2746 {
2747     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2748
2749     return !!getPage(webView).backForwardList().backItem();
2750 }
2751
2752 /**
2753  * webkit_web_view_go_forward:
2754  * @web_view: a #WebKitWebView
2755  *
2756  * Loads the next history item.
2757  * You can monitor the load operation by connecting to
2758  * #WebKitWebView::load-changed signal.
2759  */
2760 void webkit_web_view_go_forward(WebKitWebView* webView)
2761 {
2762     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2763
2764     getPage(webView).goForward();
2765 }
2766
2767 /**
2768  * webkit_web_view_can_go_forward:
2769  * @web_view: a #WebKitWebView
2770  *
2771  * Determines whether @web_view has a next history item.
2772  *
2773  * Returns: %TRUE if able to move forward or %FALSE otherwise.
2774  */
2775 gboolean webkit_web_view_can_go_forward(WebKitWebView* webView)
2776 {
2777     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
2778
2779     return !!getPage(webView).backForwardList().forwardItem();
2780 }
2781
2782 /**
2783  * webkit_web_view_get_uri:
2784  * @web_view: a #WebKitWebView
2785  *
2786  * Returns the current active URI of @web_view. The active URI might change during
2787  * a load operation:
2788  *
2789  * <orderedlist>
2790  * <listitem><para>
2791  *   When nothing has been loaded yet on @web_view the active URI is %NULL.
2792  * </para></listitem>
2793  * <listitem><para>
2794  *   When a new load operation starts the active URI is the requested URI:
2795  *   <itemizedlist>
2796  *   <listitem><para>
2797  *     If the load operation was started by webkit_web_view_load_uri(),
2798  *     the requested URI is the given one.
2799  *   </para></listitem>
2800  *   <listitem><para>
2801  *     If the load operation was started by webkit_web_view_load_html(),
2802  *     the requested URI is "about:blank".
2803  *   </para></listitem>
2804  *   <listitem><para>
2805  *     If the load operation was started by webkit_web_view_load_alternate_html(),
2806  *     the requested URI is content URI provided.
2807  *   </para></listitem>
2808  *   <listitem><para>
2809  *     If the load operation was started by webkit_web_view_go_back() or
2810  *     webkit_web_view_go_forward(), the requested URI is the original URI
2811  *     of the previous/next item in the #WebKitBackForwardList of @web_view.
2812  *   </para></listitem>
2813  *   <listitem><para>
2814  *     If the load operation was started by
2815  *     webkit_web_view_go_to_back_forward_list_item(), the requested URI
2816  *     is the opriginal URI of the given #WebKitBackForwardListItem.
2817  *   </para></listitem>
2818  *   </itemizedlist>
2819  * </para></listitem>
2820  * <listitem><para>
2821  *   If there is a server redirection during the load operation,
2822  *   the active URI is the redirected URI. When the signal
2823  *   #WebKitWebView::load-changed is emitted with %WEBKIT_LOAD_REDIRECTED
2824  *   event, the active URI is already updated to the redirected URI.
2825  * </para></listitem>
2826  * <listitem><para>
2827  *   When the signal #WebKitWebView::load-changed is emitted
2828  *   with %WEBKIT_LOAD_COMMITTED event, the active URI is the final
2829  *   one and it will not change unless a new load operation is started
2830  *   or a navigation action within the same page is performed.
2831  * </para></listitem>
2832  * </orderedlist>
2833  *
2834  * You can monitor the active URI by connecting to the notify::uri
2835  * signal of @web_view.
2836  *
2837  * Returns: the current active URI of @web_view or %NULL
2838  *    if nothing has been loaded yet.
2839  */
2840 const gchar* webkit_web_view_get_uri(WebKitWebView* webView)
2841 {
2842     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2843
2844     return webView->priv->activeURI.data();
2845 }
2846
2847 #if PLATFORM(GTK)
2848 /**
2849  * webkit_web_view_get_favicon:
2850  * @web_view: a #WebKitWebView
2851  *
2852  * Returns favicon currently associated to @web_view, if any. You can
2853  * connect to notify::favicon signal of @web_view to be notified when
2854  * the favicon is available.
2855  *
2856  * Returns: (transfer none): a pointer to a #cairo_surface_t with the
2857  *    favicon or %NULL if there's no icon associated with @web_view.
2858  */
2859 cairo_surface_t* webkit_web_view_get_favicon(WebKitWebView* webView)
2860 {
2861     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2862     if (webView->priv->activeURI.isNull())
2863         return 0;
2864
2865     return webView->priv->favicon.get();
2866 }
2867 #endif
2868
2869 /**
2870  * webkit_web_view_get_custom_charset:
2871  * @web_view: a #WebKitWebView
2872  *
2873  * Returns the current custom character encoding name of @web_view.
2874  *
2875  * Returns: the current custom character encoding name or %NULL if no
2876  *    custom character encoding has been set.
2877  */
2878 const gchar* webkit_web_view_get_custom_charset(WebKitWebView* webView)
2879 {
2880     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2881
2882     String customTextEncoding = getPage(webView).customTextEncodingName();
2883     if (customTextEncoding.isEmpty())
2884         return 0;
2885
2886     webView->priv->customTextEncoding = customTextEncoding.utf8();
2887     return webView->priv->customTextEncoding.data();
2888 }
2889
2890 /**
2891  * webkit_web_view_set_custom_charset:
2892  * @web_view: a #WebKitWebView
2893  * @charset: (allow-none): a character encoding name or %NULL
2894  *
2895  * Sets the current custom character encoding override of @web_view. The custom
2896  * character encoding will override any text encoding detected via HTTP headers or
2897  * META tags. Calling this method will stop any current load operation and reload the
2898  * current page. Setting the custom character encoding to %NULL removes the character
2899  * encoding override.
2900  */
2901 void webkit_web_view_set_custom_charset(WebKitWebView* webView, const gchar* charset)
2902 {
2903     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2904
2905     getPage(webView).setCustomTextEncodingName(String::fromUTF8(charset));
2906 }
2907
2908 /**
2909  * webkit_web_view_get_estimated_load_progress:
2910  * @web_view: a #WebKitWebView
2911  *
2912  * Gets the value of the #WebKitWebView:estimated-load-progress property.
2913  * You can monitor the estimated progress of a load operation by
2914  * connecting to the notify::estimated-load-progress signal of @web_view.
2915  *
2916  * Returns: an estimate of the of the percent complete for a document
2917  *     load as a range from 0.0 to 1.0.
2918  */
2919 gdouble webkit_web_view_get_estimated_load_progress(WebKitWebView* webView)
2920 {
2921     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2922     return getPage(webView).pageLoadState().estimatedProgress();
2923 }
2924
2925 /**
2926  * webkit_web_view_get_back_forward_list:
2927  * @web_view: a #WebKitWebView
2928  *
2929  * Obtains the #WebKitBackForwardList associated with the given #WebKitWebView. The
2930  * #WebKitBackForwardList is owned by the #WebKitWebView.
2931  *
2932  * Returns: (transfer none): the #WebKitBackForwardList
2933  */
2934 WebKitBackForwardList* webkit_web_view_get_back_forward_list(WebKitWebView* webView)
2935 {
2936     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
2937
2938     return webView->priv->backForwardList.get();
2939 }
2940
2941 /**
2942  * webkit_web_view_go_to_back_forward_list_item:
2943  * @web_view: a #WebKitWebView
2944  * @list_item: a #WebKitBackForwardListItem
2945  *
2946  * Loads the specific history item @list_item.
2947  * You can monitor the load operation by connecting to
2948  * #WebKitWebView::load-changed signal.
2949  */
2950 void webkit_web_view_go_to_back_forward_list_item(WebKitWebView* webView, WebKitBackForwardListItem* listItem)
2951 {
2952     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2953     g_return_if_fail(WEBKIT_IS_BACK_FORWARD_LIST_ITEM(listItem));
2954
2955     getPage(webView).goToBackForwardItem(webkitBackForwardListItemGetItem(listItem));
2956 }
2957
2958 /**
2959  * webkit_web_view_set_settings:
2960  * @web_view: a #WebKitWebView
2961  * @settings: a #WebKitSettings
2962  *
2963  * Sets the #WebKitSettings to be applied to @web_view. The
2964  * existing #WebKitSettings of @web_view will be replaced by
2965  * @settings. New settings are applied immediately on @web_view.
2966  * The same #WebKitSettings object can be shared
2967  * by multiple #WebKitWebView<!-- -->s.
2968  */
2969 void webkit_web_view_set_settings(WebKitWebView* webView, WebKitSettings* settings)
2970 {
2971     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
2972     g_return_if_fail(WEBKIT_IS_SETTINGS(settings));
2973
2974     if (webView->priv->settings == settings)
2975         return;
2976
2977     // The "settings" property is set on construction, and in that
2978     // case webkit_web_view_set_settings() will be called *before*
2979     // any settings have been assigned. In that case there are no
2980     // signal handlers to disconnect.
2981     if (webView->priv->settings)
2982         webkitWebViewDisconnectSettingsSignalHandlers(webView);
2983
2984     webView->priv->settings = settings;
2985     webkitWebViewUpdateSettings(webView);
2986     g_object_notify(G_OBJECT(webView), "settings");
2987 }
2988
2989 /**
2990  * webkit_web_view_get_settings:
2991  * @web_view: a #WebKitWebView
2992  *
2993  * Gets the #WebKitSettings currently applied to @web_view.
2994  * If no other #WebKitSettings have been explicitly applied to
2995  * @web_view with webkit_web_view_set_settings(), the default
2996  * #WebKitSettings will be returned. This method always returns
2997  * a valid #WebKitSettings object.
2998  * To modify any of the @web_view settings, you can either create
2999  * a new #WebKitSettings object with webkit_settings_new(), setting
3000  * the desired preferences, and then replace the existing @web_view
3001  * settings with webkit_web_view_set_settings() or get the existing
3002  * @web_view settings and update it directly. #WebKitSettings objects
3003  * can be shared by multiple #WebKitWebView<!-- -->s, so modifying
3004  * the settings of a #WebKitWebView would affect other
3005  * #WebKitWebView<!-- -->s using the same #WebKitSettings.
3006  *
3007  * Returns: (transfer none): the #WebKitSettings attached to @web_view
3008  */
3009 WebKitSettings* webkit_web_view_get_settings(WebKitWebView* webView)
3010 {
3011     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
3012     return webView->priv->settings.get();
3013 }
3014
3015 /**
3016  * webkit_web_view_get_window_properties:
3017  * @web_view: a #WebKitWebView
3018  *
3019  * Get the #WebKitWindowProperties object containing the properties
3020  * that the window containing @web_view should have.
3021  *
3022  * Returns: (transfer none): the #WebKitWindowProperties of @web_view
3023  */
3024 WebKitWindowProperties* webkit_web_view_get_window_properties(WebKitWebView* webView)
3025 {
3026     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3027
3028     return webView->priv->windowProperties.get();
3029 }
3030
3031 /**
3032  * webkit_web_view_set_zoom_level:
3033  * @web_view: a #WebKitWebView
3034  * @zoom_level: the zoom level
3035  *
3036  * Set the zoom level of @web_view, i.e. the factor by which the
3037  * view contents are scaled with respect to their original size.
3038  */
3039 void webkit_web_view_set_zoom_level(WebKitWebView* webView, gdouble zoomLevel)
3040 {
3041     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3042
3043     if (webkit_web_view_get_zoom_level(webView) == zoomLevel)
3044         return;
3045
3046     auto& page = getPage(webView);
3047     if (webkit_settings_get_zoom_text_only(webView->priv->settings.get()))
3048         page.setTextZoomFactor(zoomLevel);
3049     else
3050         page.setPageZoomFactor(zoomLevel);
3051     g_object_notify(G_OBJECT(webView), "zoom-level");
3052 }
3053
3054 /**
3055  * webkit_web_view_get_zoom_level:
3056  * @web_view: a #WebKitWebView
3057  *
3058  * Get the zoom level of @web_view, i.e. the factor by which the
3059  * view contents are scaled with respect to their original size.
3060  *
3061  * Returns: the current zoom level of @web_view
3062  */
3063 gdouble webkit_web_view_get_zoom_level(WebKitWebView* webView)
3064 {
3065     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 1);
3066
3067     auto& page = getPage(webView);
3068     gboolean zoomTextOnly = webkit_settings_get_zoom_text_only(webView->priv->settings.get());
3069     return zoomTextOnly ? page.textZoomFactor() : page.pageZoomFactor();
3070 }
3071
3072 /**
3073  * webkit_web_view_can_execute_editing_command:
3074  * @web_view: a #WebKitWebView
3075  * @command: the command to check
3076  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3077  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
3078  * @user_data: (closure): the data to pass to callback function
3079  *
3080  * Asynchronously check if it is possible to execute the given editing command.
3081  *
3082  * When the operation is finished, @callback will be called. You can then call
3083  * webkit_web_view_can_execute_editing_command_finish() to get the result of the operation.
3084  */
3085 void webkit_web_view_can_execute_editing_command(WebKitWebView* webView, const char* command, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3086 {
3087     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3088     g_return_if_fail(command);
3089
3090     GTask* task = g_task_new(webView, cancellable, callback, userData);
3091     WebKitEditorState* state = webkit_web_view_get_editor_state(webView);
3092
3093     if (!strcmp(command, WEBKIT_EDITING_COMMAND_CUT))
3094         g_task_return_boolean(adoptGRef(task).get(), webkit_editor_state_is_cut_available(state));
3095     else if (!strcmp(command, WEBKIT_EDITING_COMMAND_COPY))
3096         g_task_return_boolean(adoptGRef(task).get(), webkit_editor_state_is_copy_available(state));
3097     else if (!strcmp(command, WEBKIT_EDITING_COMMAND_PASTE))
3098         g_task_return_boolean(adoptGRef(task).get(), webkit_editor_state_is_paste_available(state));
3099     else if (!strcmp(command, WEBKIT_EDITING_COMMAND_UNDO))
3100         g_task_return_boolean(adoptGRef(task).get(), webkit_editor_state_is_undo_available(state));
3101     else if (!strcmp(command, WEBKIT_EDITING_COMMAND_REDO))
3102         g_task_return_boolean(adoptGRef(task).get(), webkit_editor_state_is_redo_available(state));
3103     else {
3104         getPage(webView).validateCommand(String::fromUTF8(command), [task](const String&, bool isEnabled, int32_t, WebKit::CallbackBase::Error) {
3105             g_task_return_boolean(adoptGRef(task).get(), isEnabled);        
3106         });
3107     }
3108 }
3109
3110 /**
3111  * webkit_web_view_can_execute_editing_command_finish:
3112  * @web_view: a #WebKitWebView
3113  * @result: a #GAsyncResult
3114  * @error: return location for error or %NULL to ignore
3115  *
3116  * Finish an asynchronous operation started with webkit_web_view_can_execute_editing_command().
3117  *
3118  * Returns: %TRUE if the editing command can be executed or %FALSE otherwise
3119  */
3120 gboolean webkit_web_view_can_execute_editing_command_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3121 {
3122     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3123     g_return_val_if_fail(g_task_is_valid(result, webView), FALSE);
3124
3125     return g_task_propagate_boolean(G_TASK(result), error);
3126 }
3127
3128 /**
3129  * webkit_web_view_execute_editing_command:
3130  * @web_view: a #WebKitWebView
3131  * @command: the command to execute
3132  *
3133  * Request to execute the given @command for @web_view. You can use
3134  * webkit_web_view_can_execute_editing_command() to check whether
3135  * it's possible to execute the command.
3136  */
3137 void webkit_web_view_execute_editing_command(WebKitWebView* webView, const char* command)
3138 {
3139     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3140     g_return_if_fail(command);
3141
3142     getPage(webView).executeEditCommand(String::fromUTF8(command));
3143 }
3144
3145 /**
3146  * webkit_web_view_execute_editing_command_with_argument:
3147  * @web_view: a #WebKitWebView
3148  * @command: the command to execute
3149  * @argument: the command argument
3150  *
3151  * Request to execute the given @command with @argument for @web_view. You can use
3152  * webkit_web_view_can_execute_editing_command() to check whether
3153  * it's possible to execute the command.
3154  *
3155  * Since: 2.10
3156  */
3157 void webkit_web_view_execute_editing_command_with_argument(WebKitWebView* webView, const char* command, const char* argument)
3158 {
3159     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3160     g_return_if_fail(command);
3161     g_return_if_fail(argument);
3162
3163     getPage(webView).executeEditCommand(String::fromUTF8(command), String::fromUTF8(argument));
3164 }
3165
3166 /**
3167  * webkit_web_view_get_find_controller:
3168  * @web_view: the #WebKitWebView
3169  *
3170  * Gets the #WebKitFindController that will allow the caller to query
3171  * the #WebKitWebView for the text to look for.
3172  *
3173  * Returns: (transfer none): the #WebKitFindController associated to
3174  * this particular #WebKitWebView.
3175  */
3176 WebKitFindController* webkit_web_view_get_find_controller(WebKitWebView* webView)
3177 {
3178     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3179
3180     if (!webView->priv->findController)
3181         webView->priv->findController = adoptGRef(WEBKIT_FIND_CONTROLLER(g_object_new(WEBKIT_TYPE_FIND_CONTROLLER, "web-view", webView, NULL)));
3182
3183     return webView->priv->findController.get();
3184 }
3185
3186 /**
3187  * webkit_web_view_get_javascript_global_context:
3188  * @web_view: a #WebKitWebView
3189  *
3190  * Get the global JavaScript context used by @web_view to deserialize the
3191  * result values of scripts executed with webkit_web_view_run_javascript().
3192  *
3193  * Returns: the <function>JSGlobalContextRef</function> used by @web_view to deserialize
3194  *    the result values of scripts.
3195  */
3196 JSGlobalContextRef webkit_web_view_get_javascript_global_context(WebKitWebView* webView)
3197 {
3198     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
3199
3200     if (!webView->priv->javascriptGlobalContext)
3201         webView->priv->javascriptGlobalContext = adopt(JSGlobalContextCreate(nullptr));
3202     return webView->priv->javascriptGlobalContext.get();
3203 }
3204
3205 static void webkitWebViewRunJavaScriptCallback(API::SerializedScriptValue* wkSerializedScriptValue, const ExceptionDetails& exceptionDetails, GTask* task)
3206 {
3207     if (g_task_return_error_if_cancelled(task))
3208         return;
3209
3210     if (!wkSerializedScriptValue) {
3211         StringBuilder builder;
3212         if (!exceptionDetails.sourceURL.isEmpty()) {
3213             builder.append(exceptionDetails.sourceURL);
3214             if (exceptionDetails.lineNumber > 0) {
3215                 builder.append(':');
3216                 builder.appendNumber(exceptionDetails.lineNumber);
3217             }
3218             if (exceptionDetails.columnNumber > 0) {
3219                 builder.append(':');
3220                 builder.appendNumber(exceptionDetails.columnNumber);
3221             }
3222             builder.appendLiteral(": ");
3223         }
3224         builder.append(exceptionDetails.message);
3225         g_task_return_new_error(task, WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED,
3226             "%s", builder.toString().utf8().data());
3227         return;
3228     }
3229
3230     auto* jsContext = webkit_web_view_get_javascript_global_context(WEBKIT_WEB_VIEW(g_task_get_source_object(task)));
3231     g_task_return_pointer(task, webkitJavascriptResultCreate(jsContext,
3232         *wkSerializedScriptValue->internalRepresentation()),
3233         reinterpret_cast<GDestroyNotify>(webkit_javascript_result_unref));
3234 }
3235
3236 /**
3237  * webkit_web_view_run_javascript:
3238  * @web_view: a #WebKitWebView
3239  * @script: the script to run
3240  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3241  * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
3242  * @user_data: (closure): the data to pass to callback function
3243  *
3244  * Asynchronously run @script in the context of the current page in @web_view. If
3245  * WebKitSettings:enable-javascript is FALSE, this method will do nothing.
3246  *
3247  * When the operation is finished, @callback will be called. You can then call
3248  * webkit_web_view_run_javascript_finish() to get the result of the operation.
3249  */
3250 void webkit_web_view_run_javascript(WebKitWebView* webView, const gchar* script, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3251 {
3252     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3253     g_return_if_fail(script);
3254
3255     GTask* task = g_task_new(webView, cancellable, callback, userData);
3256     getPage(webView).runJavaScriptInMainFrame(String::fromUTF8(script), true, [task](API::SerializedScriptValue* serializedScriptValue, bool, const ExceptionDetails& exceptionDetails, WebKit::CallbackBase::Error) {
3257         webkitWebViewRunJavaScriptCallback(serializedScriptValue, exceptionDetails, adoptGRef(task).get());
3258     });
3259 }
3260
3261 /**
3262  * webkit_web_view_run_javascript_finish:
3263  * @web_view: a #WebKitWebView
3264  * @result: a #GAsyncResult
3265  * @error: return location for error or %NULL to ignore
3266  *
3267  * Finish an asynchronous operation started with webkit_web_view_run_javascript().
3268  *
3269  * This is an example of using webkit_web_view_run_javascript() with a script returning
3270  * a string:
3271  *
3272  * <informalexample><programlisting>
3273  * static void
3274  * web_view_javascript_finished (GObject      *object,
3275  *                               GAsyncResult *result,
3276  *                               gpointer      user_data)
3277  * {
3278  *     WebKitJavascriptResult *js_result;
3279  *     JSValueRef              value;
3280  *     JSGlobalContextRef      context;
3281  *     GError                 *error = NULL;
3282  *
3283  *     js_result = webkit_web_view_run_javascript_finish (WEBKIT_WEB_VIEW (object), result, &error);
3284  *     if (!js_result) {
3285  *         g_warning ("Error running javascript: %s", error->message);
3286  *         g_error_free (error);
3287  *         return;
3288  *     }
3289  *
3290  *     context = webkit_javascript_result_get_global_context (js_result);
3291  *     value = webkit_javascript_result_get_value (js_result);
3292  *     if (JSValueIsString (context, value)) {
3293  *         JSStringRef js_str_value;
3294  *         gchar      *str_value;
3295  *         gsize       str_length;
3296  *
3297  *         js_str_value = JSValueToStringCopy (context, value, NULL);
3298  *         str_length = JSStringGetMaximumUTF8CStringSize (js_str_value);
3299  *         str_value = (gchar *)g_malloc (str_length);
3300  *         JSStringGetUTF8CString (js_str_value, str_value, str_length);
3301  *         JSStringRelease (js_str_value);
3302  *         g_print ("Script result: %s\n", str_value);
3303  *         g_free (str_value);
3304  *     } else {
3305  *         g_warning ("Error running javascript: unexpected return value");
3306  *     }
3307  *     webkit_javascript_result_unref (js_result);
3308  * }
3309  *
3310  * static void
3311  * web_view_get_link_url (WebKitWebView *web_view,
3312  *                        const gchar   *link_id)
3313  * {
3314  *     gchar *script;
3315  *
3316  *     script = g_strdup_printf ("window.document.getElementById('%s').href;", link_id);
3317  *     webkit_web_view_run_javascript (web_view, script, NULL, web_view_javascript_finished, NULL);
3318  *     g_free (script);
3319  * }
3320  * </programlisting></informalexample>
3321  *
3322  * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
3323  *    or %NULL in case of error
3324  */
3325 WebKitJavascriptResult* webkit_web_view_run_javascript_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3326 {
3327     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3328     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3329
3330     return static_cast<WebKitJavascriptResult*>(g_task_propagate_pointer(G_TASK(result), error));
3331 }
3332
3333 static void resourcesStreamReadCallback(GObject* object, GAsyncResult* result, gpointer userData)
3334 {
3335     GRefPtr<GTask> task = adoptGRef(G_TASK(userData));
3336
3337     GError* error = 0;
3338     g_output_stream_splice_finish(G_OUTPUT_STREAM(object), result, &error);
3339     if (error) {
3340         g_task_return_error(task.get(), error);
3341         return;
3342     }
3343
3344     WebKitWebView* webView = WEBKIT_WEB_VIEW(g_task_get_source_object(task.get()));
3345     gpointer outputStreamData = g_memory_output_stream_get_data(G_MEMORY_OUTPUT_STREAM(object));
3346     getPage(webView).runJavaScriptInMainFrame(String::fromUTF8(reinterpret_cast<const gchar*>(outputStreamData)), true,
3347         [task](API::SerializedScriptValue* serializedScriptValue, bool, const ExceptionDetails& exceptionDetails, WebKit::CallbackBase::Error) {
3348             webkitWebViewRunJavaScriptCallback(serializedScriptValue, exceptionDetails, task.get());
3349         });
3350 }
3351
3352 /**
3353  * webkit_web_view_run_javascript_from_gresource:
3354  * @web_view: a #WebKitWebView
3355  * @resource: the location of the resource to load
3356  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3357  * @callback: (scope async): a #GAsyncReadyCallback to call when the script finished
3358  * @user_data: (closure): the data to pass to callback function
3359  *
3360  * Asynchronously run the script from @resource in the context of the
3361  * current page in @web_view.
3362  *
3363  * When the operation is finished, @callback will be called. You can
3364  * then call webkit_web_view_run_javascript_from_gresource_finish() to get the result
3365  * of the operation.
3366  */
3367 void webkit_web_view_run_javascript_from_gresource(WebKitWebView* webView, const gchar* resource, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3368 {
3369     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3370     g_return_if_fail(resource);
3371
3372     GError* error = 0;
3373     GRefPtr<GInputStream> inputStream = adoptGRef(g_resources_open_stream(resource, G_RESOURCE_LOOKUP_FLAGS_NONE, &error));
3374     if (error) {
3375         g_task_report_error(webView, callback, userData, 0, error);
3376         return;
3377     }
3378
3379     GTask* task = g_task_new(webView, cancellable, callback, userData);
3380     GRefPtr<GOutputStream> outputStream = adoptGRef(g_memory_output_stream_new(0, 0, fastRealloc, fastFree));
3381     g_output_stream_splice_async(outputStream.get(), inputStream.get(),
3382         static_cast<GOutputStreamSpliceFlags>(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
3383         G_PRIORITY_DEFAULT, cancellable, resourcesStreamReadCallback, task);
3384 }
3385
3386 /**
3387  * webkit_web_view_run_javascript_from_gresource_finish:
3388  * @web_view: a #WebKitWebView
3389  * @result: a #GAsyncResult
3390  * @error: return location for error or %NULL to ignore
3391  *
3392  * Finish an asynchronous operation started with webkit_web_view_run_javascript_from_gresource().
3393  *
3394  * Check webkit_web_view_run_javascript_finish() for a usage example.
3395  *
3396  * Returns: (transfer full): a #WebKitJavascriptResult with the result of the last executed statement in @script
3397  *    or %NULL in case of error
3398  */
3399 WebKitJavascriptResult* webkit_web_view_run_javascript_from_gresource_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3400 {
3401     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3402     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3403
3404     return static_cast<WebKitJavascriptResult*>(g_task_propagate_pointer(G_TASK(result), error));
3405 }
3406
3407 /**
3408  * webkit_web_view_get_main_resource:
3409  * @web_view: a #WebKitWebView
3410  *
3411  * Return the main resource of @web_view.
3412  *
3413  * Returns: (transfer none): the main #WebKitWebResource of the view
3414  *    or %NULL if nothing has been loaded.
3415  */
3416 WebKitWebResource* webkit_web_view_get_main_resource(WebKitWebView* webView)
3417 {
3418     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3419
3420     return webView->priv->mainResource.get();
3421 }
3422
3423 #if PLATFORM(GTK)
3424 /**
3425  * webkit_web_view_get_inspector:
3426  * @web_view: a #WebKitWebView
3427  *
3428  * Get the #WebKitWebInspector associated to @web_view
3429  *
3430  * Returns: (transfer none): the #WebKitWebInspector of @web_view
3431  */
3432 WebKitWebInspector* webkit_web_view_get_inspector(WebKitWebView* webView)
3433 {
3434     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3435
3436     if (!webView->priv->inspector)
3437         webView->priv->inspector = adoptGRef(webkitWebInspectorCreate(getPage(webView).inspector()));
3438
3439     return webView->priv->inspector.get();
3440 }
3441 #endif
3442
3443 /**
3444  * webkit_web_view_can_show_mime_type:
3445  * @web_view: a #WebKitWebView
3446  * @mime_type: a MIME type
3447  *
3448  * Whether or not a MIME type can be displayed in @web_view.
3449  *
3450  * Returns: %TRUE if the MIME type @mime_type can be displayed or %FALSE otherwise
3451  */
3452 gboolean webkit_web_view_can_show_mime_type(WebKitWebView* webView, const char* mimeType)
3453 {
3454     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3455     g_return_val_if_fail(mimeType, FALSE);
3456
3457     return getPage(webView).canShowMIMEType(String::fromUTF8(mimeType));
3458 }
3459
3460 struct ViewSaveAsyncData {
3461     RefPtr<API::Data> webData;
3462     GRefPtr<GFile> file;
3463 };
3464 WEBKIT_DEFINE_ASYNC_DATA_STRUCT(ViewSaveAsyncData)
3465
3466 static void fileReplaceContentsCallback(GObject* object, GAsyncResult* result, gpointer data)
3467 {
3468     GRefPtr<GTask> task = adoptGRef(G_TASK(data));
3469     GError* error = 0;
3470     if (!g_file_replace_contents_finish(G_FILE(object), result, 0, &error)) {
3471         g_task_return_error(task.get(), error);
3472         return;
3473     }
3474
3475     g_task_return_boolean(task.get(), TRUE);
3476 }
3477
3478 static void getContentsAsMHTMLDataCallback(API::Data* wkData, GTask* taskPtr)
3479 {
3480     auto task = adoptGRef(taskPtr);
3481     if (g_task_return_error_if_cancelled(task.get()))
3482         return;
3483
3484     ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task.get()));
3485     // We need to retain the data until the asyncronous process
3486     // initiated by the user has finished completely.
3487     data->webData = wkData;
3488
3489     // If we are saving to a file we need to write the data on disk before finishing.
3490     if (g_task_get_source_tag(task.get()) == webkit_web_view_save_to_file) {
3491         ASSERT(G_IS_FILE(data->file.get()));
3492         GCancellable* cancellable = g_task_get_cancellable(task.get());
3493         g_file_replace_contents_async(data->file.get(), reinterpret_cast<const gchar*>(data->webData->bytes()), data->webData->size(),
3494             0, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, cancellable, fileReplaceContentsCallback, task.leakRef());
3495         return;
3496     }
3497
3498     g_task_return_boolean(task.get(), TRUE);
3499 }
3500
3501 /**
3502  * webkit_web_view_save:
3503  * @web_view: a #WebKitWebView
3504  * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
3505  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3506  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
3507  * @user_data: (closure): the data to pass to callback function
3508  *
3509  * Asynchronously save the current web page associated to the
3510  * #WebKitWebView into a self-contained format using the mode
3511  * specified in @save_mode.
3512  *
3513  * When the operation is finished, @callback will be called. You can
3514  * then call webkit_web_view_save_finish() to get the result of the
3515  * operation.
3516  */
3517 void webkit_web_view_save(WebKitWebView* webView, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3518 {
3519     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3520
3521     // We only support MHTML at the moment.
3522     g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
3523
3524     GTask* task = g_task_new(webView, cancellable, callback, userData);
3525     g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save));
3526     g_task_set_task_data(task, createViewSaveAsyncData(), reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
3527     getPage(webView).getContentsAsMHTMLData([task](API::Data* data, WebKit::CallbackBase::Error) {
3528         getContentsAsMHTMLDataCallback(data, task);
3529     });
3530 }
3531
3532 /**
3533  * webkit_web_view_save_finish:
3534  * @web_view: a #WebKitWebView
3535  * @result: a #GAsyncResult
3536  * @error: return location for error or %NULL to ignore
3537  *
3538  * Finish an asynchronous operation started with webkit_web_view_save().
3539  *
3540  * Returns: (transfer full): a #GInputStream with the result of saving
3541  *    the current web page or %NULL in case of error.
3542  */
3543 GInputStream* webkit_web_view_save_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3544 {
3545     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3546     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3547
3548     GTask* task = G_TASK(result);
3549     if (!g_task_propagate_boolean(task, error))
3550         return 0;
3551
3552     GInputStream* dataStream = g_memory_input_stream_new();
3553     ViewSaveAsyncData* data = static_cast<ViewSaveAsyncData*>(g_task_get_task_data(task));
3554     gsize length = data->webData->size();
3555     if (length)
3556         g_memory_input_stream_add_data(G_MEMORY_INPUT_STREAM(dataStream), g_memdup(data->webData->bytes(), length), length, g_free);
3557
3558     return dataStream;
3559 }
3560
3561 /**
3562  * webkit_web_view_save_to_file:
3563  * @web_view: a #WebKitWebView
3564  * @file: the #GFile where the current web page should be saved to.
3565  * @save_mode: the #WebKitSaveMode specifying how the web page should be saved.
3566  * @cancellable: (allow-none): a #GCancellable or %NULL to ignore
3567  * @callback: (scope async): a #GAsyncReadyCallback to call when the request is satisfied
3568  * @user_data: (closure): the data to pass to callback function
3569  *
3570  * Asynchronously save the current web page associated to the
3571  * #WebKitWebView into a self-contained format using the mode
3572  * specified in @save_mode and writing it to @file.
3573  *
3574  * When the operation is finished, @callback will be called. You can
3575  * then call webkit_web_view_save_to_file_finish() to get the result of the
3576  * operation.
3577  */
3578 void webkit_web_view_save_to_file(WebKitWebView* webView, GFile* file, WebKitSaveMode saveMode, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3579 {
3580     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3581     g_return_if_fail(G_IS_FILE(file));
3582
3583     // We only support MHTML at the moment.
3584     g_return_if_fail(saveMode == WEBKIT_SAVE_MODE_MHTML);
3585
3586     GTask* task = g_task_new(webView, cancellable, callback, userData);
3587     g_task_set_source_tag(task, reinterpret_cast<gpointer>(webkit_web_view_save_to_file));
3588     ViewSaveAsyncData* data = createViewSaveAsyncData();
3589     data->file = file;
3590     g_task_set_task_data(task, data, reinterpret_cast<GDestroyNotify>(destroyViewSaveAsyncData));
3591
3592     getPage(webView).getContentsAsMHTMLData([task](API::Data* data, WebKit::CallbackBase::Error) {
3593         getContentsAsMHTMLDataCallback(data, task);
3594     });
3595 }
3596
3597 /**
3598  * webkit_web_view_save_to_file_finish:
3599  * @web_view: a #WebKitWebView
3600  * @result: a #GAsyncResult
3601  * @error: return location for error or %NULL to ignore
3602  *
3603  * Finish an asynchronous operation started with webkit_web_view_save_to_file().
3604  *
3605  * Returns: %TRUE if the web page was successfully saved to a file or %FALSE otherwise.
3606  */
3607 gboolean webkit_web_view_save_to_file_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3608 {
3609     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3610     g_return_val_if_fail(g_task_is_valid(result, webView), FALSE);
3611
3612     return g_task_propagate_boolean(G_TASK(result), error);
3613 }
3614
3615 /**
3616  * webkit_web_view_download_uri:
3617  * @web_view: a #WebKitWebView
3618  * @uri: the URI to download
3619  *
3620  * Requests downloading of the specified URI string for @web_view.
3621  *
3622  * Returns: (transfer full): a new #WebKitDownload representing
3623  *    the download operation.
3624  */
3625 WebKitDownload* webkit_web_view_download_uri(WebKitWebView* webView, const char* uri)
3626 {
3627     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), nullptr);
3628     g_return_val_if_fail(uri, nullptr);
3629
3630     GRefPtr<WebKitDownload> download = webkitWebContextStartDownload(webView->priv->context.get(), uri, &getPage(webView));
3631     return download.leakRef();
3632 }
3633
3634 /**
3635  * webkit_web_view_get_tls_info:
3636  * @web_view: a #WebKitWebView
3637  * @certificate: (out) (transfer none): return location for a #GTlsCertificate
3638  * @errors: (out): return location for a #GTlsCertificateFlags the verification status of @certificate
3639  *
3640  * Retrieves the #GTlsCertificate associated with the main resource of @web_view,
3641  * and the #GTlsCertificateFlags showing what problems, if any, have been found
3642  * with that certificate.
3643  * If the connection is not HTTPS, this function returns %FALSE.
3644  * This function should be called after a response has been received from the
3645  * server, so you can connect to #WebKitWebView::load-changed and call this function
3646  * when it's emitted with %WEBKIT_LOAD_COMMITTED event.
3647  *
3648  * Note that this function provides no information about the security of the web
3649  * page if the current #WebKitTLSErrorsPolicy is @WEBKIT_TLS_ERRORS_POLICY_IGNORE,
3650  * as subresources of the page may be controlled by an attacker. This function
3651  * may safely be used to determine the security status of the current page only
3652  * if the current #WebKitTLSErrorsPolicy is @WEBKIT_TLS_ERRORS_POLICY_FAIL, in
3653  * which case subresources that fail certificate verification will be blocked.
3654  *
3655  * Returns: %TRUE if the @web_view connection uses HTTPS and a response has been received
3656  *    from the server, or %FALSE otherwise.
3657  */
3658 gboolean webkit_web_view_get_tls_info(WebKitWebView* webView, GTlsCertificate** certificate, GTlsCertificateFlags* errors)
3659 {
3660     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3661
3662     WebFrameProxy* mainFrame = getPage(webView).mainFrame();
3663     if (!mainFrame)
3664         return FALSE;
3665
3666     auto* wkCertificateInfo = mainFrame->certificateInfo();
3667     g_return_val_if_fail(wkCertificateInfo, FALSE);
3668
3669     const auto& certificateInfo = wkCertificateInfo->certificateInfo();
3670     if (certificate)
3671         *certificate = certificateInfo.certificate();
3672     if (errors)
3673         *errors = certificateInfo.tlsErrors();
3674
3675     return !!certificateInfo.certificate();
3676 }
3677
3678 #if PLATFORM(GTK)
3679 void webKitWebViewDidReceiveSnapshot(WebKitWebView* webView, uint64_t callbackID, WebImage* webImage)
3680 {
3681     GRefPtr<GTask> task = webView->priv->snapshotResultsMap.take(callbackID);
3682     if (g_task_return_error_if_cancelled(task.get()))
3683         return;
3684
3685     if (!webImage) {
3686         g_task_return_new_error(task.get(), WEBKIT_SNAPSHOT_ERROR, WEBKIT_SNAPSHOT_ERROR_FAILED_TO_CREATE,
3687             _("There was an error creating the snapshot"));
3688         return;
3689     }
3690
3691     g_task_return_pointer(task.get(), webImage->bitmap().createCairoSurface().leakRef(), reinterpret_cast<GDestroyNotify>(cairo_surface_destroy));
3692 }
3693
3694 static inline unsigned webKitSnapshotOptionsToSnapshotOptions(WebKitSnapshotOptions options)
3695 {
3696     SnapshotOptions snapshotOptions = 0;
3697
3698     if (!(options & WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING))
3699         snapshotOptions |= SnapshotOptionsExcludeSelectionHighlighting;
3700
3701     return snapshotOptions;
3702 }
3703
3704 static inline SnapshotRegion toSnapshotRegion(WebKitSnapshotRegion region)
3705 {
3706     switch (region) {
3707     case WEBKIT_SNAPSHOT_REGION_VISIBLE:
3708         return SnapshotRegionVisible;
3709     case WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT:
3710         return SnapshotRegionFullDocument;
3711     default:
3712         ASSERT_NOT_REACHED();
3713         return SnapshotRegionVisible;
3714     }
3715 }
3716
3717 static inline uint64_t generateSnapshotCallbackID()
3718 {
3719     static uint64_t uniqueCallbackID = 1;
3720     return uniqueCallbackID++;
3721 }
3722
3723 /**
3724  * webkit_web_view_get_snapshot:
3725  * @web_view: a #WebKitWebView
3726  * @region: the #WebKitSnapshotRegion for this snapshot
3727  * @options: #WebKitSnapshotOptions for the snapshot
3728  * @cancellable: (allow-none): a #GCancellable
3729  * @callback: (scope async): a #GAsyncReadyCallback
3730  * @user_data: (closure): user data
3731  *
3732  * Asynchronously retrieves a snapshot of @web_view for @region.
3733  * @options specifies how the snapshot should be rendered.
3734  *
3735  * When the operation is finished, @callback will be called. You must
3736  * call webkit_web_view_get_snapshot_finish() to get the result of the
3737  * operation.
3738  */
3739 void webkit_web_view_get_snapshot(WebKitWebView* webView, WebKitSnapshotRegion region, WebKitSnapshotOptions options, GCancellable* cancellable, GAsyncReadyCallback callback, gpointer userData)
3740 {
3741     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3742
3743     API::Dictionary::MapType message;
3744     uint64_t callbackID = generateSnapshotCallbackID();
3745     message.set(String::fromUTF8("SnapshotOptions"), API::UInt64::create(static_cast<uint64_t>(webKitSnapshotOptionsToSnapshotOptions(options))));
3746     message.set(String::fromUTF8("SnapshotRegion"), API::UInt64::create(static_cast<uint64_t>(toSnapshotRegion(region))));
3747     message.set(String::fromUTF8("CallbackID"), API::UInt64::create(callbackID));
3748     message.set(String::fromUTF8("TransparentBackground"), API::Boolean::create(options & WEBKIT_SNAPSHOT_OPTIONS_TRANSPARENT_BACKGROUND));
3749
3750     webView->priv->snapshotResultsMap.set(callbackID, adoptGRef(g_task_new(webView, cancellable, callback, userData)));
3751     getPage(webView).postMessageToInjectedBundle(String::fromUTF8("GetSnapshot"), API::Dictionary::create(WTFMove(message)).ptr());
3752 }
3753
3754 /**
3755  * webkit_web_view_get_snapshot_finish:
3756  * @web_view: a #WebKitWebView
3757  * @result: a #GAsyncResult
3758  * @error: return location for error or %NULL to ignore
3759  *
3760  * Finishes an asynchronous operation started with webkit_web_view_get_snapshot().
3761  *
3762  * Returns: (transfer full): a #cairo_surface_t with the retrieved snapshot or %NULL in error.
3763  */
3764 cairo_surface_t* webkit_web_view_get_snapshot_finish(WebKitWebView* webView, GAsyncResult* result, GError** error)
3765 {
3766     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), 0);
3767     g_return_val_if_fail(g_task_is_valid(result, webView), 0);
3768
3769     return static_cast<cairo_surface_t*>(g_task_propagate_pointer(G_TASK(result), error));
3770 }
3771 #endif
3772
3773 void webkitWebViewWebProcessCrashed(WebKitWebView* webView)
3774 {
3775     gboolean returnValue;
3776     g_signal_emit(webView, signals[WEB_PROCESS_CRASHED], 0, &returnValue);
3777 }
3778
3779 #if PLATFORM(GTK)
3780 /**
3781  * webkit_web_view_set_background_color:
3782  * @web_view: a #WebKitWebView
3783  * @rgba: a #GdkRGBA
3784  *
3785  * Sets the color that will be used to draw the @web_view background before
3786  * the actual contents are rendered. Note that if the web page loaded in @web_view
3787  * specifies a background color, it will take precedence over the @rgba color.
3788  * By default the @web_view background color is opaque white.
3789  * Note that the parent window must have a RGBA visual and
3790  * #GtkWidget:app-paintable property set to %TRUE for backgrounds colors to work.
3791  *
3792  * <informalexample><programlisting>
3793  * static void browser_window_set_background_color (BrowserWindow *window,
3794  *                                                  const GdkRGBA *rgba)
3795  * {
3796  *     WebKitWebView *web_view;
3797  *     GdkScreen *screen = gtk_window_get_screen (GTK_WINDOW (window));
3798  *     GdkVisual *rgba_visual = gdk_screen_get_rgba_visual (screen);
3799  *
3800  *     if (!rgba_visual)
3801  *          return;
3802  *
3803  *     gtk_widget_set_visual (GTK_WIDGET (window), rgba_visual);
3804  *     gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
3805  *
3806  *     web_view = browser_window_get_web_view (window);
3807  *     webkit_web_view_set_background_color (web_view, rgba);
3808  * }
3809  * </programlisting></informalexample>
3810  *
3811  * Since: 2.8
3812  */
3813 void webkit_web_view_set_background_color(WebKitWebView* webView, const GdkRGBA* rgba)
3814 {
3815     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3816     g_return_if_fail(rgba);
3817
3818     Color color(*rgba);
3819     auto& page = getPage(webView);
3820     if (page.backgroundColor() == color)
3821         return;
3822
3823     page.setBackgroundColor(color);
3824     page.setDrawsBackground(color == Color::white);
3825 }
3826
3827 /**
3828  * webkit_web_view_get_background_color:
3829  * @web_view: a #WebKitWebView
3830  * @rgba: (out): a #GdkRGBA to fill in with the background color
3831  *
3832  * Gets the color that is used to draw the @web_view background before
3833  * the actual contents are rendered.
3834  * For more information see also webkit_web_view_set_background_color()
3835  *
3836  * Since: 2.8
3837  */
3838 void webkit_web_view_get_background_color(WebKitWebView* webView, GdkRGBA* rgba)
3839 {
3840     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3841     g_return_if_fail(rgba);
3842
3843     *rgba = getPage(webView).backgroundColor();
3844 }
3845 #endif // PLATFORM(GTK)
3846
3847 /*
3848  * webkit_web_view_is_editable:
3849  * @web_view: a #WebKitWebView
3850  *
3851  * Gets whether the user is allowed to edit the HTML document. When @web_view
3852  * is not editable an element in the HTML document can only be edited if the
3853  * CONTENTEDITABLE attribute has been set on the element or one of its parent
3854  * elements. By default a #WebKitWebView is not editable.
3855  *
3856  * Returns: %TRUE if the user is allowed to edit the HTML document, or %FALSE otherwise.
3857  *
3858  * Since: 2.8
3859  */
3860 gboolean webkit_web_view_is_editable(WebKitWebView* webView)
3861 {
3862     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
3863
3864     return getPage(webView).isEditable();
3865 }
3866
3867 /**
3868  * webkit_web_view_set_editable:
3869  * @web_view: a #WebKitWebView
3870  * @editable: a #gboolean indicating the editable state
3871  *
3872  * Sets whether the user is allowed to edit the HTML document.
3873  *
3874  * If @editable is %TRUE, @web_view allows the user to edit the HTML document. If
3875  * @editable is %FALSE, an element in @web_view's document can only be edited if the
3876  * CONTENTEDITABLE attribute has been set on the element or one of its parent
3877  * elements. By default a #WebKitWebView is not editable.
3878  *
3879  * Normally, a HTML document is not editable unless the elements within the
3880  * document are editable. This function provides a way to make the contents
3881  * of a #WebKitWebView editable without altering the document or DOM structure.
3882  *
3883  * Since: 2.8
3884  */
3885 void webkit_web_view_set_editable(WebKitWebView* webView, gboolean editable)
3886 {
3887     g_return_if_fail(WEBKIT_IS_WEB_VIEW(webView));
3888
3889     if (editable == getPage(webView).isEditable())