1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Common interface and events for web view component
4 // Author: Marianne Gagnon
6 // Copyright: (c) 2010 Marianne Gagnon, 2011 Steven Lamerton
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #if defined(__BORLANDC__)
19 #include "wx/webview.h"
21 #include "wx/osx/webview_webkit.h"
22 #include "wx/gtk/webview_webkit.h"
23 #include "wx/msw/webview_ie.h"
24 #include "wx/filesys.h"
25 #include "wx/tokenzr.h"
27 // DLL options compatibility check:
29 WX_CHECK_BUILD_OPTIONS("wxWEB")
31 extern WXDLLIMPEXP_DATA_WEB(const char) wxWebViewNameStr
[] = "wxWebView";
32 extern WXDLLIMPEXP_DATA_WEB(const char) wxWebViewDefaultURLStr
[] = "about:blank";
34 IMPLEMENT_DYNAMIC_CLASS(wxWebNavigationEvent
, wxCommandEvent
)
36 wxDEFINE_EVENT( wxEVT_COMMAND_WEB_VIEW_NAVIGATING
, wxWebNavigationEvent
);
37 wxDEFINE_EVENT( wxEVT_COMMAND_WEB_VIEW_NAVIGATED
, wxWebNavigationEvent
);
38 wxDEFINE_EVENT( wxEVT_COMMAND_WEB_VIEW_LOADED
, wxWebNavigationEvent
);
39 wxDEFINE_EVENT( wxEVT_COMMAND_WEB_VIEW_ERROR
, wxWebNavigationEvent
);
40 wxDEFINE_EVENT( wxEVT_COMMAND_WEB_VIEW_NEWWINDOW
, wxWebNavigationEvent
);
41 wxDEFINE_EVENT( wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED
, wxWebNavigationEvent
);
43 //Taken from wx/filesys.cpp
44 static wxString
EscapeFileNameCharsInURL(const char *in
)
48 for ( const unsigned char *p
= (const unsigned char*)in
; *p
; ++p
)
50 const unsigned char c
= *p
;
52 if ( c
== '/' || c
== '-' || c
== '.' || c
== '_' || c
== '~' ||
53 (c
>= '0' && c
<= '9') ||
54 (c
>= 'a' && c
<= 'z') ||
55 (c
>= 'A' && c
<= 'Z') )
61 s
<< wxString::Format("%%%02x", c
);
68 wxWebFileProtocolHandler::wxWebFileProtocolHandler()
71 m_fileSystem
= new wxFileSystem();
74 wxFSFile
* wxWebFileProtocolHandler::GetFile(const wxString
&uri
)
76 size_t pos
= uri
.find('?');
77 //There is no query string so we can load the file directly
78 if(pos
== wxString::npos
)
80 size_t doubleslash
= uri
.find("//");
81 //The path is incorrectly formed without // after the first protocol
82 if(doubleslash
== wxString::npos
)
85 wxString fspath
= "file:" +
86 EscapeFileNameCharsInURL(uri
.substr(doubleslash
+ 2));
87 return m_fileSystem
->OpenFile(fspath
);
89 //Otherwise we have a query string of some kind that we need to extract
91 //First we extract the query string, this should have two parameters,
92 //protocol=type and path=path
93 wxString query
= uri
.substr(pos
+ 1), protocol
, path
;
94 //We also trim the query off the end as we handle it alone
95 wxString lefturi
= uri
.substr(0, pos
);
96 wxStringTokenizer
tokenizer(query
, ";");
97 while(tokenizer
.HasMoreTokens() && (protocol
== "" || path
== ""))
99 wxString token
= tokenizer
.GetNextToken();
100 if(token
.substr(0, 9) == "protocol=")
102 protocol
= token
.substr(9);
104 else if(token
.substr(0, 5) == "path=")
106 path
= token
.substr(5);
109 if(protocol
== "" || path
== "")
112 //We now have the path and the protocol and so can format a correct uri
113 //to pass to wxFileSystem to get a wxFSFile
114 size_t doubleslash
= uri
.find("//");
115 //The path is incorrectly formed without // after the first protocol
116 if(doubleslash
== wxString::npos
)
119 wxString fspath
= "file:" +
120 EscapeFileNameCharsInURL(lefturi
.substr(doubleslash
+ 2))
121 + "#" + protocol
+":" + path
;
122 return m_fileSystem
->OpenFile(fspath
);
126 wxString
wxWebFileProtocolHandler::CombineURIs(const wxString
&baseuri
,
127 const wxString
&newuri
)
129 //If there is a colon in the path then we just return it
130 if(newuri
.find(':') != wxString::npos
)
134 //We have an absolute path and no query string
135 else if(newuri
.substr(0, 1) == "/" && baseuri
.find('?') == wxString::npos
)
137 //By finding the next / after file:// we get to the end of the
138 //(optional) hostname
139 size_t pos
= baseuri
.find('/', 7);
140 //So we return up to the end of the hostname, plus the newuri
141 return baseuri
.substr(0, pos
) + newuri
;
143 //We have an absolute path and a query string
144 else if(newuri
.substr(0, 1) == "/" && baseuri
.find('?') != wxString::npos
)
146 wxString query
= baseuri
.substr(baseuri
.find('?') + 1);
148 wxStringTokenizer
tokenizer(query
, ";");
149 while(tokenizer
.HasMoreTokens())
151 wxString token
= tokenizer
.GetNextToken();
152 if(token
.substr(0, 5) == "path=")
154 //As the path is absolue simply replace the old path with the
156 newquery
= newquery
+ "path=" + newuri
;
162 //We need to add the separators back
163 if(tokenizer
.HasMoreTokens())
166 return baseuri
.substr(0, baseuri
.find('?')) + "?" + newquery
;
168 //We have a relative path and no query string
169 else if(baseuri
.find('?') == wxString::npos
)
171 //By finding the next / after file:// we get to the end of the
172 //(optional) hostname
173 size_t pos
= baseuri
.find('/', 7);
174 wxString path
= baseuri
.substr(pos
);
175 //Then we remove the last filename
176 path
= path
.BeforeLast('/') + '/';
177 //Ensure that we have the leading / so we can normalise properly
178 if(path
.substr(0, 1) != "/")
181 //If we have a colon in the path (i.e. we are on windows) we need to
182 //handle it specially
183 if(path
.find(':') != wxString::npos
)
185 wxFileName
fn(path
.AfterFirst('/').AfterFirst('/') + newuri
);
186 fn
.Normalize(wxPATH_NORM_DOTS
, "", wxPATH_UNIX
);
187 return baseuri
.substr(0, pos
) + '/' +
188 path
.AfterFirst('/').BeforeFirst('/') + '/' +
189 fn
.GetFullPath(wxPATH_UNIX
);
193 //We can now use wxFileName to perform the normalisation
194 wxFileName
fn(path
+ newuri
);
195 fn
.Normalize(wxPATH_NORM_DOTS
, "", wxPATH_UNIX
);
196 return baseuri
.substr(0, pos
) + fn
.GetFullPath(wxPATH_UNIX
);
199 //We have a relative path and a query string
202 wxString query
= baseuri
.substr(baseuri
.find('?') + 1);
204 wxStringTokenizer
tokenizer(query
, ";");
205 while(tokenizer
.HasMoreTokens())
207 wxString token
= tokenizer
.GetNextToken();
208 if(token
.substr(0, 5) == "path=")
210 wxString path
= token
.substr(6);
211 //Then we remove the last filename
212 path
= path
.BeforeLast('/') + '/';
213 //Ensure that we have the leading / so we can normalise properly
214 //if(path.substr(0, 1) != "/")
215 // path = "/" + path;
217 //We can now use wxFileName to perform the normalisation
218 wxFileName
fn(path
+ newuri
);
219 fn
.Normalize(wxPATH_NORM_DOTS
, "", wxPATH_UNIX
);
220 newquery
= newquery
+ "path=" + fn
.GetFullPath(wxPATH_UNIX
);
226 //We need to add the separators back
227 if(tokenizer
.HasMoreTokens())
230 return baseuri
.substr(0, baseuri
.find('?')) + "?" + newquery
;
235 wxWebView
* wxWebView::New(wxWebViewBackend backend
)
239 #if defined(wxUSE_WEBVIEW_WEBKIT) && \
240 (defined(__WXGTK__) || defined(__WXOSX__))
241 case wxWEB_VIEW_BACKEND_WEBKIT
:
242 return new wxWebViewWebKit();
246 case wxWEB_VIEW_BACKEND_IE
:
247 return new wxWebViewIE();
250 case wxWEB_VIEW_BACKEND_DEFAULT
:
252 #if defined(wxUSE_WEBVIEW_WEBKIT) && \
253 (defined(__WXGTK__) || defined(__WXOSX__))
254 return new wxWebViewWebKit();
258 return new wxWebViewIE();
261 // fall-through intended
268 wxWebView
* wxWebView::New(wxWindow
* parent
,
273 wxWebViewBackend backend
,
275 const wxString
& name
)
279 #if defined(wxUSE_WEBVIEW_WEBKIT) && \
280 (defined(__WXGTK__) || defined(__WXOSX__))
281 case wxWEB_VIEW_BACKEND_WEBKIT
:
282 return new wxWebViewWebKit(parent
, id
, url
, pos
, size
, style
, name
);
286 case wxWEB_VIEW_BACKEND_IE
:
287 return new wxWebViewIE(parent
, id
, url
, pos
, size
, style
, name
);
290 case wxWEB_VIEW_BACKEND_DEFAULT
:
292 #if defined(wxUSE_WEBVIEW_WEBKIT) && \
293 (defined(__WXGTK__) || defined(__WXOSX__))
294 return new wxWebViewWebKit(parent
, id
, url
, pos
, size
, style
, name
);
298 return new wxWebViewIE(parent
, id
, url
, pos
, size
, style
, name
);
301 // fall-through intended