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