1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/gtk/webview_webkit.cpp
3 // Purpose:     GTK WebKit backend for web view component
4 // Author:      Marianne Gagnon, Robert Roebling
5 // Copyright:   (c) 2010 Marianne Gagnon, 1998 Robert Roebling
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 #if wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT
13 
14 #include "wx/stockitem.h"
15 #include "wx/gtk/webview_webkit.h"
16 #include "wx/gtk/control.h"
17 #include "wx/gtk/private.h"
18 #include "wx/filesys.h"
19 #include "wx/base64.h"
20 #include "wx/log.h"
21 #include <webkit/webkit.h>
22 
23 // ----------------------------------------------------------------------------
24 // GTK callbacks
25 // ----------------------------------------------------------------------------
26 
27 extern "C"
28 {
29 
30 static void
wxgtk_webview_webkit_load_status(GtkWidget * widget,GParamSpec *,wxWebViewWebKit * webKitCtrl)31 wxgtk_webview_webkit_load_status(GtkWidget* widget,
32                                  GParamSpec*,
33                                  wxWebViewWebKit *webKitCtrl)
34 {
35     wxString url = webKitCtrl->GetCurrentURL();
36 
37     WebKitLoadStatus status;
38     g_object_get(G_OBJECT(widget), "load-status", &status, NULL);
39 
40     wxString target; // TODO: get target (if possible)
41 
42     if (status == WEBKIT_LOAD_FINISHED)
43     {
44         WebKitWebBackForwardList* hist = webkit_web_view_get_back_forward_list(WEBKIT_WEB_VIEW(widget));
45         WebKitWebHistoryItem* item = webkit_web_back_forward_list_get_current_item(hist);
46         //We have to check if we are actually storing history
47         //If the item isn't added we add it ourselves, it isn't added otherwise
48         //with a custom scheme.
49         if(!item || (WEBKIT_IS_WEB_HISTORY_ITEM(item) &&
50                      webkit_web_history_item_get_uri(item) != url))
51         {
52             WebKitWebHistoryItem*
53                 newitem = webkit_web_history_item_new_with_data
54                           (
55                             url.utf8_str(),
56                             webKitCtrl->GetCurrentTitle().utf8_str()
57                           );
58             webkit_web_back_forward_list_add_item(hist, newitem);
59         }
60 
61         webKitCtrl->m_busy = false;
62         wxWebViewEvent event(wxEVT_WEBVIEW_LOADED,
63                              webKitCtrl->GetId(),
64                              url, target);
65 
66         webKitCtrl->HandleWindowEvent(event);
67     }
68     else if (status ==  WEBKIT_LOAD_COMMITTED)
69     {
70         webKitCtrl->m_busy = true;
71         wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATED,
72                              webKitCtrl->GetId(),
73                              url, target);
74 
75         webKitCtrl->HandleWindowEvent(event);
76     }
77 }
78 
79 static gboolean
wxgtk_webview_webkit_navigation(WebKitWebView *,WebKitWebFrame * frame,WebKitNetworkRequest * request,WebKitWebNavigationAction * action,WebKitWebPolicyDecision * policy_decision,wxWebViewWebKit * webKitCtrl)80 wxgtk_webview_webkit_navigation(WebKitWebView *,
81                                 WebKitWebFrame *frame,
82                                 WebKitNetworkRequest *request,
83                                 WebKitWebNavigationAction *action,
84                                 WebKitWebPolicyDecision *policy_decision,
85                                 wxWebViewWebKit *webKitCtrl)
86 {
87     const gchar* uri = webkit_network_request_get_uri(request);
88     wxString target = webkit_web_frame_get_name (frame);
89 
90     //If m_creating is true then we are the result of a new window
91     //and so we need to send the event and veto the load
92     if(webKitCtrl->m_creating)
93     {
94         webKitCtrl->m_creating = false;
95 
96         WebKitWebNavigationReason reason =
97                                   webkit_web_navigation_action_get_reason(action);
98         wxWebViewNavigationActionFlags flags = wxWEBVIEW_NAV_ACTION_USER;
99 
100         if(reason == WEBKIT_WEB_NAVIGATION_REASON_OTHER)
101             flags = wxWEBVIEW_NAV_ACTION_OTHER;
102 
103         wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
104                              webKitCtrl->GetId(),
105                              wxString(uri, wxConvUTF8),
106                              target, flags);
107 
108         webKitCtrl->HandleWindowEvent(event);
109 
110         webkit_web_policy_decision_ignore(policy_decision);
111         return TRUE;
112     }
113 
114     if(webKitCtrl->m_guard)
115     {
116         webKitCtrl->m_guard = false;
117         //We set this to make sure that we don't try to load the page again from
118         //the resource request callback
119         webKitCtrl->m_vfsurl = webkit_network_request_get_uri(request);
120         webkit_web_policy_decision_use(policy_decision);
121         return FALSE;
122     }
123 
124     webKitCtrl->m_busy = true;
125 
126     wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
127                          webKitCtrl->GetId(),
128                          wxString( uri, wxConvUTF8 ),
129                          target);
130 
131     webKitCtrl->HandleWindowEvent(event);
132 
133     if (!event.IsAllowed())
134     {
135         webKitCtrl->m_busy = false;
136         webkit_web_policy_decision_ignore(policy_decision);
137         return TRUE;
138     }
139     else
140     {
141         wxString wxuri = uri;
142         wxSharedPtr<wxWebViewHandler> handler;
143         wxVector<wxSharedPtr<wxWebViewHandler> > handlers = webKitCtrl->GetHandlers();
144         //We are not vetoed so see if we match one of the additional handlers
145         for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = handlers.begin();
146             it != handlers.end(); ++it)
147         {
148             if(wxuri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
149             {
150                 handler = (*it);
151             }
152         }
153         //If we found a handler we can then use it to load the file directly
154         //ourselves
155         if(handler)
156         {
157             webKitCtrl->m_guard = true;
158             wxFSFile* file = handler->GetFile(wxuri);
159             if(file)
160             {
161                 webKitCtrl->SetPage(*file->GetStream(), wxuri);
162             }
163             //We need to throw some sort of error here if file is NULL
164             webkit_web_policy_decision_ignore(policy_decision);
165             return TRUE;
166         }
167         return FALSE;
168     }
169 }
170 
171 static gboolean
wxgtk_webview_webkit_error(WebKitWebView *,WebKitWebFrame *,gchar * uri,gpointer web_error,wxWebViewWebKit * webKitWindow)172 wxgtk_webview_webkit_error(WebKitWebView*,
173                            WebKitWebFrame*,
174                            gchar *uri,
175                            gpointer web_error,
176                            wxWebViewWebKit* webKitWindow)
177 {
178     webKitWindow->m_busy = false;
179     wxWebViewNavigationError type = wxWEBVIEW_NAV_ERR_OTHER;
180 
181     GError* error = (GError*)web_error;
182     wxString description(error->message, wxConvUTF8);
183 
184     if (strcmp(g_quark_to_string(error->domain), "soup_http_error_quark") == 0)
185     {
186         switch (error->code)
187         {
188             case SOUP_STATUS_CANCELLED:
189                 type = wxWEBVIEW_NAV_ERR_USER_CANCELLED;
190                 break;
191 
192             case SOUP_STATUS_CANT_RESOLVE:
193             case SOUP_STATUS_NOT_FOUND:
194                 type = wxWEBVIEW_NAV_ERR_NOT_FOUND;
195                 break;
196 
197             case SOUP_STATUS_CANT_RESOLVE_PROXY:
198             case SOUP_STATUS_CANT_CONNECT:
199             case SOUP_STATUS_CANT_CONNECT_PROXY:
200             case SOUP_STATUS_SSL_FAILED:
201             case SOUP_STATUS_IO_ERROR:
202                 type = wxWEBVIEW_NAV_ERR_CONNECTION;
203                 break;
204 
205             case SOUP_STATUS_MALFORMED:
206             //case SOUP_STATUS_TOO_MANY_REDIRECTS:
207                 type = wxWEBVIEW_NAV_ERR_REQUEST;
208                 break;
209 
210             //case SOUP_STATUS_NO_CONTENT:
211             //case SOUP_STATUS_RESET_CONTENT:
212 
213             case SOUP_STATUS_BAD_REQUEST:
214                 type = wxWEBVIEW_NAV_ERR_REQUEST;
215                 break;
216 
217             case SOUP_STATUS_UNAUTHORIZED:
218             case SOUP_STATUS_FORBIDDEN:
219                 type = wxWEBVIEW_NAV_ERR_AUTH;
220                 break;
221 
222             case SOUP_STATUS_METHOD_NOT_ALLOWED:
223             case SOUP_STATUS_NOT_ACCEPTABLE:
224                 type = wxWEBVIEW_NAV_ERR_SECURITY;
225                 break;
226 
227             case SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
228                 type = wxWEBVIEW_NAV_ERR_AUTH;
229                 break;
230 
231             case SOUP_STATUS_REQUEST_TIMEOUT:
232                 type = wxWEBVIEW_NAV_ERR_CONNECTION;
233                 break;
234 
235             //case SOUP_STATUS_PAYMENT_REQUIRED:
236             case SOUP_STATUS_REQUEST_ENTITY_TOO_LARGE:
237             case SOUP_STATUS_REQUEST_URI_TOO_LONG:
238             case SOUP_STATUS_UNSUPPORTED_MEDIA_TYPE:
239                 type = wxWEBVIEW_NAV_ERR_REQUEST;
240                 break;
241 
242             case SOUP_STATUS_BAD_GATEWAY:
243             case SOUP_STATUS_SERVICE_UNAVAILABLE:
244             case SOUP_STATUS_GATEWAY_TIMEOUT:
245                 type = wxWEBVIEW_NAV_ERR_CONNECTION;
246                 break;
247 
248             case SOUP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
249                 type = wxWEBVIEW_NAV_ERR_REQUEST;
250                 break;
251             //case SOUP_STATUS_INSUFFICIENT_STORAGE:
252             //case SOUP_STATUS_NOT_EXTENDED:
253         }
254     }
255     else if (strcmp(g_quark_to_string(error->domain),
256                     "webkit-network-error-quark") == 0)
257     {
258         switch (error->code)
259         {
260             //WEBKIT_NETWORK_ERROR_FAILED:
261             //WEBKIT_NETWORK_ERROR_TRANSPORT:
262 
263             case WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL:
264                 type = wxWEBVIEW_NAV_ERR_REQUEST;
265                 break;
266 
267             case WEBKIT_NETWORK_ERROR_CANCELLED:
268                 type = wxWEBVIEW_NAV_ERR_USER_CANCELLED;
269                 break;
270 
271             case WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST:
272                 type = wxWEBVIEW_NAV_ERR_NOT_FOUND;
273                 break;
274         }
275     }
276     else if (strcmp(g_quark_to_string(error->domain),
277                     "webkit-policy-error-quark") == 0)
278     {
279         switch (error->code)
280         {
281             //case WEBKIT_POLICY_ERROR_FAILED:
282             //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE:
283             //case WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL:
284             //case WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE:
285             case WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT:
286                 type = wxWEBVIEW_NAV_ERR_SECURITY;
287                 break;
288         }
289     }
290     /*
291     webkit_plugin_error_quark
292     else
293     {
294         printf("Error domain %s\n", g_quark_to_string(error->domain));
295     }
296     */
297 
298     wxWebViewEvent event(wxEVT_WEBVIEW_ERROR,
299                          webKitWindow->GetId(),
300                          uri, "");
301     event.SetString(description);
302     event.SetInt(type);
303 
304     webKitWindow->HandleWindowEvent(event);
305 
306     return FALSE;
307 }
308 
309 static gboolean
wxgtk_webview_webkit_new_window(WebKitWebView *,WebKitWebFrame * frame,WebKitNetworkRequest * request,WebKitWebNavigationAction * action,WebKitWebPolicyDecision * policy_decision,wxWebViewWebKit * webKitCtrl)310 wxgtk_webview_webkit_new_window(WebKitWebView*,
311                                 WebKitWebFrame *frame,
312                                 WebKitNetworkRequest *request,
313                                 WebKitWebNavigationAction* action,
314                                 WebKitWebPolicyDecision *policy_decision,
315                                 wxWebViewWebKit *webKitCtrl)
316 {
317     const gchar* uri = webkit_network_request_get_uri(request);
318     wxString target = webkit_web_frame_get_name (frame);
319 
320     WebKitWebNavigationReason reason = webkit_web_navigation_action_get_reason(action);
321 
322     wxWebViewNavigationActionFlags flags = wxWEBVIEW_NAV_ACTION_USER;
323 
324     if(reason == WEBKIT_WEB_NAVIGATION_REASON_OTHER)
325         flags = wxWEBVIEW_NAV_ACTION_OTHER;
326 
327     wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
328                                        webKitCtrl->GetId(),
329                                        wxString( uri, wxConvUTF8 ),
330                                        target, flags);
331 
332     webKitCtrl->HandleWindowEvent(event);
333 
334     //We always want the user to handle this themselves
335     webkit_web_policy_decision_ignore(policy_decision);
336     return TRUE;
337 }
338 
339 static void
wxgtk_webview_webkit_title_changed(WebKitWebView *,WebKitWebFrame *,gchar * title,wxWebViewWebKit * webKitCtrl)340 wxgtk_webview_webkit_title_changed(WebKitWebView*,
341                                    WebKitWebFrame*,
342                                    gchar *title,
343                                    wxWebViewWebKit *webKitCtrl)
344 {
345     wxWebViewEvent event(wxEVT_WEBVIEW_TITLE_CHANGED,
346                          webKitCtrl->GetId(),
347                          webKitCtrl->GetCurrentURL(),
348                          "");
349     event.SetString(wxString(title, wxConvUTF8));
350 
351     webKitCtrl->HandleWindowEvent(event);
352 }
353 
354 static void
wxgtk_webview_webkit_resource_req(WebKitWebView *,WebKitWebFrame *,WebKitWebResource *,WebKitNetworkRequest * request,WebKitNetworkResponse *,wxWebViewWebKit * webKitCtrl)355 wxgtk_webview_webkit_resource_req(WebKitWebView *,
356                                   WebKitWebFrame *,
357                                   WebKitWebResource *,
358                                   WebKitNetworkRequest *request,
359                                   WebKitNetworkResponse *,
360                                   wxWebViewWebKit *webKitCtrl)
361 {
362     wxString uri = webkit_network_request_get_uri(request);
363 
364     wxSharedPtr<wxWebViewHandler> handler;
365     wxVector<wxSharedPtr<wxWebViewHandler> > handlers = webKitCtrl->GetHandlers();
366 
367     //We are not vetoed so see if we match one of the additional handlers
368     for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = handlers.begin();
369         it != handlers.end(); ++it)
370     {
371         if(uri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
372         {
373             handler = (*it);
374         }
375     }
376     //If we found a handler we can then use it to load the file directly
377     //ourselves
378     if(handler)
379     {
380         //If it is requsting the page itself then return as we have already
381         //loaded it from the archive
382         if(webKitCtrl->m_vfsurl == uri)
383             return;
384 
385         wxFSFile* file = handler->GetFile(uri);
386         if(file)
387         {
388             //We load the data into a data url to save it being written out again
389             size_t size = file->GetStream()->GetLength();
390             char *buffer = new char[size];
391             file->GetStream()->Read(buffer, size);
392             wxString data = wxBase64Encode(buffer, size);
393             delete[] buffer;
394             wxString mime = file->GetMimeType();
395             wxString path = "data:" + mime + ";base64," + data;
396             //Then we can redirect the call
397             webkit_network_request_set_uri(request, path.utf8_str());
398         }
399 
400     }
401 }
402 
403 #if WEBKIT_CHECK_VERSION(1, 10, 0)
404 
405 static gboolean
wxgtk_webview_webkit_context_menu(WebKitWebView *,GtkWidget *,WebKitHitTestResult *,gboolean,wxWebViewWebKit * webKitCtrl)406 wxgtk_webview_webkit_context_menu(WebKitWebView *,
407                                   GtkWidget *,
408                                   WebKitHitTestResult *,
409                                   gboolean,
410                                   wxWebViewWebKit *webKitCtrl)
411 {
412     return !webKitCtrl->IsContextMenuEnabled();
413 }
414 
415 #endif
416 
417 static WebKitWebView*
wxgtk_webview_webkit_create_webview(WebKitWebView * web_view,WebKitWebFrame *,wxWebViewWebKit * webKitCtrl)418 wxgtk_webview_webkit_create_webview(WebKitWebView *web_view,
419                                     WebKitWebFrame*,
420                                     wxWebViewWebKit *webKitCtrl)
421 {
422     //As we do not know the uri being loaded at this point allow the load to
423     //continue and catch it in navigation-policy-decision-requested
424     webKitCtrl->m_creating = true;
425     return web_view;
426 }
427 
428 } // extern "C"
429 
430 //-----------------------------------------------------------------------------
431 // wxWebViewWebKit
432 //-----------------------------------------------------------------------------
433 
434 wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewWebKit, wxWebView);
435 
wxWebViewWebKit()436 wxWebViewWebKit::wxWebViewWebKit()
437 {
438     m_web_view = NULL;
439 }
440 
Create(wxWindow * parent,wxWindowID id,const wxString & url,const wxPoint & pos,const wxSize & size,long style,const wxString & name)441 bool wxWebViewWebKit::Create(wxWindow *parent,
442                       wxWindowID id,
443                       const wxString &url,
444                       const wxPoint& pos,
445                       const wxSize& size,
446                       long style,
447                       const wxString& name)
448 {
449     m_web_view = NULL;
450     m_busy = false;
451     m_guard = false;
452     m_creating = false;
453     FindClear();
454 
455     // We currently unconditionally impose scrolling in both directions as it's
456     // necessary to show arbitrary pages.
457     style |= wxHSCROLL | wxVSCROLL;
458 
459     if (!PreCreation( parent, pos, size ) ||
460         !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
461     {
462         wxFAIL_MSG( wxT("wxWebViewWebKit creation failed") );
463         return false;
464     }
465 
466     m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
467     GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
468     g_object_ref(m_widget);
469 
470     g_signal_connect_after(m_web_view, "navigation-policy-decision-requested",
471                            G_CALLBACK(wxgtk_webview_webkit_navigation),
472                            this);
473     g_signal_connect_after(m_web_view, "load-error",
474                            G_CALLBACK(wxgtk_webview_webkit_error),
475                            this);
476 
477     g_signal_connect_after(m_web_view, "new-window-policy-decision-requested",
478                            G_CALLBACK(wxgtk_webview_webkit_new_window), this);
479 
480     g_signal_connect_after(m_web_view, "title-changed",
481                            G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
482 
483     g_signal_connect_after(m_web_view, "resource-request-starting",
484                            G_CALLBACK(wxgtk_webview_webkit_resource_req), this);
485 
486 #if WEBKIT_CHECK_VERSION(1, 10, 0)
487      g_signal_connect_after(m_web_view, "context-menu",
488                            G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
489 #endif
490 
491      g_signal_connect_after(m_web_view, "create-web-view",
492                            G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
493 
494     m_parent->DoAddChild( this );
495 
496     PostCreation(size);
497 
498     /* Open a webpage */
499     webkit_web_view_load_uri(m_web_view, url.utf8_str());
500 
501     //Get the initial history limit so we can enable and disable it later
502     WebKitWebBackForwardList* history;
503     history = webkit_web_view_get_back_forward_list(m_web_view);
504     m_historyLimit = webkit_web_back_forward_list_get_limit(history);
505 
506     // last to avoid getting signal too early
507     g_signal_connect_after(m_web_view, "notify::load-status",
508                            G_CALLBACK(wxgtk_webview_webkit_load_status),
509                            this);
510 
511     return true;
512 }
513 
~wxWebViewWebKit()514 wxWebViewWebKit::~wxWebViewWebKit()
515 {
516     if (m_web_view)
517         GTKDisconnect(m_web_view);
518 }
519 
Enable(bool enable)520 bool wxWebViewWebKit::Enable( bool enable )
521 {
522     if (!wxControl::Enable(enable))
523         return false;
524 
525     gtk_widget_set_sensitive(gtk_bin_get_child(GTK_BIN(m_widget)), enable);
526 
527     //if (enable)
528     //    GTKFixSensitivity();
529 
530     return true;
531 }
532 
533 GdkWindow*
GTKGetWindow(wxArrayGdkWindows & WXUNUSED (windows)) const534 wxWebViewWebKit::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
535 {
536     GdkWindow* window = gtk_widget_get_parent_window(m_widget);
537     return window;
538 }
539 
ZoomIn()540 void wxWebViewWebKit::ZoomIn()
541 {
542     webkit_web_view_zoom_in(m_web_view);
543 }
544 
ZoomOut()545 void wxWebViewWebKit::ZoomOut()
546 {
547     webkit_web_view_zoom_out(m_web_view);
548 }
549 
SetWebkitZoom(float level)550 void wxWebViewWebKit::SetWebkitZoom(float level)
551 {
552     webkit_web_view_set_zoom_level(m_web_view, level);
553 }
554 
GetWebkitZoom() const555 float wxWebViewWebKit::GetWebkitZoom() const
556 {
557     return webkit_web_view_get_zoom_level(m_web_view);
558 }
559 
Stop()560 void wxWebViewWebKit::Stop()
561 {
562      webkit_web_view_stop_loading(m_web_view);
563 }
564 
Reload(wxWebViewReloadFlags flags)565 void wxWebViewWebKit::Reload(wxWebViewReloadFlags flags)
566 {
567     if (flags & wxWEBVIEW_RELOAD_NO_CACHE)
568     {
569         webkit_web_view_reload_bypass_cache(m_web_view);
570     }
571     else
572     {
573         webkit_web_view_reload(m_web_view);
574     }
575 }
576 
LoadURL(const wxString & url)577 void wxWebViewWebKit::LoadURL(const wxString& url)
578 {
579     webkit_web_view_load_uri(m_web_view, wxGTK_CONV(url));
580 }
581 
582 
GoBack()583 void wxWebViewWebKit::GoBack()
584 {
585     webkit_web_view_go_back(m_web_view);
586 }
587 
GoForward()588 void wxWebViewWebKit::GoForward()
589 {
590     webkit_web_view_go_forward(m_web_view);
591 }
592 
593 
CanGoBack() const594 bool wxWebViewWebKit::CanGoBack() const
595 {
596     return webkit_web_view_can_go_back(m_web_view) != 0;
597 }
598 
599 
CanGoForward() const600 bool wxWebViewWebKit::CanGoForward() const
601 {
602     return webkit_web_view_can_go_forward(m_web_view) != 0;
603 }
604 
ClearHistory()605 void wxWebViewWebKit::ClearHistory()
606 {
607     WebKitWebBackForwardList* history;
608     history = webkit_web_view_get_back_forward_list(m_web_view);
609     webkit_web_back_forward_list_clear(history);
610 }
611 
EnableHistory(bool enable)612 void wxWebViewWebKit::EnableHistory(bool enable)
613 {
614     WebKitWebBackForwardList* history;
615     history = webkit_web_view_get_back_forward_list(m_web_view);
616     if(enable)
617     {
618         webkit_web_back_forward_list_set_limit(history, m_historyLimit);
619     }
620     else
621     {
622         webkit_web_back_forward_list_set_limit(history, 0);
623     }
624 }
625 
GetBackwardHistory()626 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewWebKit::GetBackwardHistory()
627 {
628     wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
629     WebKitWebBackForwardList* history;
630     history = webkit_web_view_get_back_forward_list(m_web_view);
631     GList* list = webkit_web_back_forward_list_get_back_list_with_limit(history,
632                                                                         m_historyLimit);
633     //We need to iterate in reverse to get the order we desire
634     for(int i = g_list_length(list) - 1; i >= 0 ; i--)
635     {
636         WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)g_list_nth_data(list, i);
637         wxWebViewHistoryItem* wxitem = new wxWebViewHistoryItem(
638                                    webkit_web_history_item_get_uri(gtkitem),
639                                    webkit_web_history_item_get_title(gtkitem));
640         wxitem->m_histItem = gtkitem;
641         wxSharedPtr<wxWebViewHistoryItem> item(wxitem);
642         backhist.push_back(item);
643     }
644     return backhist;
645 }
646 
GetForwardHistory()647 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewWebKit::GetForwardHistory()
648 {
649     wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
650     WebKitWebBackForwardList* history;
651     history = webkit_web_view_get_back_forward_list(m_web_view);
652     GList* list = webkit_web_back_forward_list_get_forward_list_with_limit(history,
653                                                                            m_historyLimit);
654     for(guint i = 0; i < g_list_length(list); i++)
655     {
656         WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)g_list_nth_data(list, i);
657         wxWebViewHistoryItem* wxitem = new wxWebViewHistoryItem(
658                                    webkit_web_history_item_get_uri(gtkitem),
659                                    webkit_web_history_item_get_title(gtkitem));
660         wxitem->m_histItem = gtkitem;
661         wxSharedPtr<wxWebViewHistoryItem> item(wxitem);
662         forwardhist.push_back(item);
663     }
664     return forwardhist;
665 }
666 
LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)667 void wxWebViewWebKit::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
668 {
669     WebKitWebHistoryItem* gtkitem = (WebKitWebHistoryItem*)item->m_histItem;
670     if(gtkitem)
671     {
672         webkit_web_view_go_to_back_forward_item(m_web_view,
673                                                 WEBKIT_WEB_HISTORY_ITEM(gtkitem));
674     }
675 }
676 
CanCut() const677 bool wxWebViewWebKit::CanCut() const
678 {
679     return webkit_web_view_can_cut_clipboard(m_web_view) != 0;
680 }
681 
CanCopy() const682 bool wxWebViewWebKit::CanCopy() const
683 {
684     return webkit_web_view_can_copy_clipboard(m_web_view) != 0;
685 }
686 
CanPaste() const687 bool wxWebViewWebKit::CanPaste() const
688 {
689     return webkit_web_view_can_paste_clipboard(m_web_view) != 0;
690 }
691 
Cut()692 void wxWebViewWebKit::Cut()
693 {
694     webkit_web_view_cut_clipboard(m_web_view);
695 }
696 
Copy()697 void wxWebViewWebKit::Copy()
698 {
699     webkit_web_view_copy_clipboard(m_web_view);
700 }
701 
Paste()702 void wxWebViewWebKit::Paste()
703 {
704     webkit_web_view_paste_clipboard(m_web_view);
705 }
706 
CanUndo() const707 bool wxWebViewWebKit::CanUndo() const
708 {
709     return webkit_web_view_can_undo(m_web_view) != 0;
710 }
711 
CanRedo() const712 bool wxWebViewWebKit::CanRedo() const
713 {
714     return webkit_web_view_can_redo(m_web_view) != 0;
715 }
716 
Undo()717 void wxWebViewWebKit::Undo()
718 {
719     webkit_web_view_undo(m_web_view);
720 }
721 
Redo()722 void wxWebViewWebKit::Redo()
723 {
724     webkit_web_view_redo(m_web_view);
725 }
726 
GetCurrentURL() const727 wxString wxWebViewWebKit::GetCurrentURL() const
728 {
729     // FIXME: check which encoding the web kit control uses instead of
730     // assuming UTF8 (here and elsewhere too)
731     return wxString::FromUTF8(webkit_web_view_get_uri(m_web_view));
732 }
733 
734 
GetCurrentTitle() const735 wxString wxWebViewWebKit::GetCurrentTitle() const
736 {
737     return wxString::FromUTF8(webkit_web_view_get_title(m_web_view));
738 }
739 
740 
GetPageSource() const741 wxString wxWebViewWebKit::GetPageSource() const
742 {
743     WebKitWebFrame* frame = webkit_web_view_get_main_frame(m_web_view);
744     WebKitWebDataSource* src = webkit_web_frame_get_data_source (frame);
745 
746     // TODO: check encoding with
747     // const gchar*
748     // webkit_web_data_source_get_encoding(WebKitWebDataSource *data_source);
749     return wxString(webkit_web_data_source_get_data (src)->str, wxConvUTF8);
750 }
751 
752 
GetZoomFactor() const753 float wxWebViewWebKit::GetZoomFactor() const
754 {
755     return GetWebkitZoom();
756 }
757 
758 
SetZoomFactor(float zoom)759 void wxWebViewWebKit::SetZoomFactor(float zoom)
760 {
761     SetWebkitZoom(zoom);
762 }
763 
SetZoomType(wxWebViewZoomType type)764 void wxWebViewWebKit::SetZoomType(wxWebViewZoomType type)
765 {
766     webkit_web_view_set_full_content_zoom(m_web_view,
767                                           type == wxWEBVIEW_ZOOM_TYPE_LAYOUT);
768 }
769 
GetZoomType() const770 wxWebViewZoomType wxWebViewWebKit::GetZoomType() const
771 {
772     gboolean fczoom = webkit_web_view_get_full_content_zoom(m_web_view);
773 
774     if (fczoom) return wxWEBVIEW_ZOOM_TYPE_LAYOUT;
775     else        return wxWEBVIEW_ZOOM_TYPE_TEXT;
776 }
777 
CanSetZoomType(wxWebViewZoomType) const778 bool wxWebViewWebKit::CanSetZoomType(wxWebViewZoomType) const
779 {
780     // this port supports all zoom types
781     return true;
782 }
783 
DoSetPage(const wxString & html,const wxString & baseUri)784 void wxWebViewWebKit::DoSetPage(const wxString& html, const wxString& baseUri)
785 {
786     webkit_web_view_load_string (m_web_view,
787                                  html.mb_str(wxConvUTF8),
788                                  "text/html",
789                                  "UTF-8",
790                                  baseUri.mb_str(wxConvUTF8));
791 }
792 
Print()793 void wxWebViewWebKit::Print()
794 {
795     WebKitWebFrame* frame = webkit_web_view_get_main_frame(m_web_view);
796     webkit_web_frame_print (frame);
797 
798     // GtkPrintOperationResult  webkit_web_frame_print_full
799     //      (WebKitWebFrame *frame,
800     //       GtkPrintOperation *operation,
801     //       GtkPrintOperationAction action,
802     //       GError **error);
803 
804 }
805 
806 
IsBusy() const807 bool wxWebViewWebKit::IsBusy() const
808 {
809     return m_busy;
810 
811     // This code looks nice but returns true after a page was cancelled
812     /*
813     WebKitLoadStatus status = webkit_web_view_get_load_status
814             (WEBKIT_WEB_VIEW(web_view));
815 
816 
817 #if WEBKIT_CHECK_VERSION(1,1,16)
818     // WEBKIT_LOAD_FAILED is new in webkit 1.1.16
819     if (status == WEBKIT_LOAD_FAILED)
820     {
821         return false;
822     }
823 #endif
824     if (status == WEBKIT_LOAD_FINISHED)
825     {
826         return false;
827     }
828 
829     return true;
830      */
831 }
832 
SetEditable(bool enable)833 void wxWebViewWebKit::SetEditable(bool enable)
834 {
835     webkit_web_view_set_editable(m_web_view, enable);
836 }
837 
IsEditable() const838 bool wxWebViewWebKit::IsEditable() const
839 {
840     return webkit_web_view_get_editable(m_web_view) != 0;
841 }
842 
DeleteSelection()843 void wxWebViewWebKit::DeleteSelection()
844 {
845     webkit_web_view_delete_selection(m_web_view);
846 }
847 
HasSelection() const848 bool wxWebViewWebKit::HasSelection() const
849 {
850     return webkit_web_view_has_selection(m_web_view) != 0;
851 }
852 
SelectAll()853 void wxWebViewWebKit::SelectAll()
854 {
855     webkit_web_view_select_all(m_web_view);
856 }
857 
GetSelectedText() const858 wxString wxWebViewWebKit::GetSelectedText() const
859 {
860     WebKitDOMDocument* doc;
861     WebKitDOMDOMWindow* win;
862     WebKitDOMDOMSelection* sel;
863     WebKitDOMRange* range;
864 
865     doc = webkit_web_view_get_dom_document(m_web_view);
866     win = webkit_dom_document_get_default_view(WEBKIT_DOM_DOCUMENT(doc));
867     sel = webkit_dom_dom_window_get_selection(WEBKIT_DOM_DOM_WINDOW(win));
868     range = webkit_dom_dom_selection_get_range_at(WEBKIT_DOM_DOM_SELECTION(sel),
869                                                   0, NULL);
870     return wxString(webkit_dom_range_get_text(WEBKIT_DOM_RANGE(range)),
871                     wxConvUTF8);
872 }
873 
GetSelectedSource() const874 wxString wxWebViewWebKit::GetSelectedSource() const
875 {
876     WebKitDOMDocument* doc;
877     WebKitDOMDOMWindow* win;
878     WebKitDOMDOMSelection* sel;
879     WebKitDOMRange* range;
880     WebKitDOMElement* div;
881     WebKitDOMDocumentFragment* clone;
882     WebKitDOMHTMLElement* html;
883 
884     doc = webkit_web_view_get_dom_document(m_web_view);
885     win = webkit_dom_document_get_default_view(WEBKIT_DOM_DOCUMENT(doc));
886     sel = webkit_dom_dom_window_get_selection(WEBKIT_DOM_DOM_WINDOW(win));
887     range = webkit_dom_dom_selection_get_range_at(WEBKIT_DOM_DOM_SELECTION(sel),
888                                                   0, NULL);
889     div = webkit_dom_document_create_element(WEBKIT_DOM_DOCUMENT(doc), "div", NULL);
890 
891     clone = webkit_dom_range_clone_contents(WEBKIT_DOM_RANGE(range), NULL);
892     webkit_dom_node_append_child(&div->parent_instance, &clone->parent_instance, NULL);
893     html = (WebKitDOMHTMLElement*)div;
894 
895     return wxString(webkit_dom_html_element_get_inner_html(WEBKIT_DOM_HTML_ELEMENT(html)),
896                     wxConvUTF8);
897 }
898 
ClearSelection()899 void wxWebViewWebKit::ClearSelection()
900 {
901     WebKitDOMDocument* doc;
902     WebKitDOMDOMWindow* win;
903     WebKitDOMDOMSelection* sel;
904 
905     doc = webkit_web_view_get_dom_document(m_web_view);
906     win = webkit_dom_document_get_default_view(WEBKIT_DOM_DOCUMENT(doc));
907     sel = webkit_dom_dom_window_get_selection(WEBKIT_DOM_DOM_WINDOW(win));
908     webkit_dom_dom_selection_remove_all_ranges(WEBKIT_DOM_DOM_SELECTION(sel));
909 
910 }
911 
GetPageText() const912 wxString wxWebViewWebKit::GetPageText() const
913 {
914     WebKitDOMDocument* doc;
915     WebKitDOMHTMLElement* body;
916 
917     doc = webkit_web_view_get_dom_document(m_web_view);
918     body = webkit_dom_document_get_body(WEBKIT_DOM_DOCUMENT(doc));
919     return wxString(webkit_dom_html_element_get_inner_text(WEBKIT_DOM_HTML_ELEMENT(body)),
920                     wxConvUTF8);
921 }
922 
RunScript(const wxString & javascript,wxString * output) const923 bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output) const
924 {
925     wxCHECK_MSG( m_web_view, false,
926         wxS("wxWebView must be created before calling RunScript()") );
927 
928     if ( output != NULL )
929     {
930         wxLogWarning(_("Retrieving JavaScript script output is not supported with WebKit v1"));
931         return false;
932     }
933 
934     webkit_web_view_execute_script(m_web_view,
935                                    javascript.mb_str(wxConvUTF8));
936 
937     return true;
938 }
939 
RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)940 void wxWebViewWebKit::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
941 {
942     m_handlerList.push_back(handler);
943 }
944 
EnableContextMenu(bool enable)945 void wxWebViewWebKit::EnableContextMenu(bool enable)
946 {
947 #if !WEBKIT_CHECK_VERSION(1, 10, 0) //If we are using an older version
948     g_object_set(webkit_web_view_get_settings(m_web_view),
949                  "enable-default-context-menu", enable, NULL);
950 #endif
951     wxWebView::EnableContextMenu(enable);
952 }
953 
Find(const wxString & text,int flags)954 long wxWebViewWebKit::Find(const wxString& text, int flags)
955 {
956     bool newSearch = false;
957     if(text != m_findText ||
958        (flags & wxWEBVIEW_FIND_MATCH_CASE) != (m_findFlags & wxWEBVIEW_FIND_MATCH_CASE))
959     {
960         newSearch = true;
961         //If it is a new search we need to clear existing highlights
962         webkit_web_view_unmark_text_matches(m_web_view);
963         webkit_web_view_set_highlight_text_matches(m_web_view, false);
964     }
965 
966     m_findFlags = flags;
967     m_findText = text;
968 
969     //If the search string is empty then we clear any selection and highlight
970     if (text.empty())
971     {
972         webkit_web_view_unmark_text_matches(m_web_view);
973         webkit_web_view_set_highlight_text_matches(m_web_view, false);
974         ClearSelection();
975         return wxNOT_FOUND;
976     }
977 
978     bool wrap = false, matchCase = false, forward = true;
979     if(flags & wxWEBVIEW_FIND_WRAP)
980         wrap = true;
981     if(flags & wxWEBVIEW_FIND_MATCH_CASE)
982         matchCase = true;
983     if(flags & wxWEBVIEW_FIND_BACKWARDS)
984         forward = false;
985 
986     if(newSearch)
987     {
988         //Initially we mark the matches to know how many we have
989         m_findCount = webkit_web_view_mark_text_matches(m_web_view, wxGTK_CONV(text), matchCase, 0);
990         //In this case we return early to match IE behaviour
991         m_findPosition = -1;
992         return m_findCount;
993     }
994     else
995     {
996         if(forward)
997             m_findPosition++;
998         else
999             m_findPosition--;
1000         if(m_findPosition < 0)
1001             m_findPosition += m_findCount;
1002         if(m_findPosition > m_findCount)
1003             m_findPosition -= m_findCount;
1004     }
1005 
1006     //Highlight them if needed
1007     bool highlight = flags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT ? true : false;
1008     webkit_web_view_set_highlight_text_matches(m_web_view, highlight);
1009 
1010     if(!webkit_web_view_search_text(m_web_view, wxGTK_CONV(text), matchCase, forward, wrap))
1011     {
1012         m_findPosition = -1;
1013         ClearSelection();
1014         return wxNOT_FOUND;
1015     }
1016     return newSearch ? m_findCount : m_findPosition;
1017 }
1018 
FindClear()1019 void wxWebViewWebKit::FindClear()
1020 {
1021     m_findCount = 0;
1022     m_findFlags = 0;
1023     m_findText = "";
1024     m_findPosition = -1;
1025 }
1026 
1027 // static
1028 wxVisualAttributes
GetClassDefaultAttributes(wxWindowVariant WXUNUSED (variant))1029 wxWebViewWebKit::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
1030 {
1031      return GetDefaultAttributesFromGTKWidget(webkit_web_view_new());
1032 }
1033 
1034 
1035 #endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_WEBKIT
1036