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