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