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