Fix custom scheme handling in wxWebView WebKit2 implementation
The custom scheme handling implementation had been inherited from the original WebKit1 implementation. It attempted to intercept navigation and resource load requests and then inject the resources. It seems that this method doesn't work in WebKit2, but fortunately, there is native support in WebKit2 for custom URI schemes through the webkit_web_context_register_uri_scheme() API. Also extend wxGtkError to allow creating it from an existing GError object as a side-effect of these changes. See https://github.com/wxWidgets/wxWidgets/pull/716
This commit is contained in:
committed by
Vadim Zeitlin
parent
aaf58e2b49
commit
1f2173b9be
@@ -209,6 +209,7 @@ wxGTK:
|
|||||||
- Implement ShowPosition() for single-line wxTextCtrl.
|
- Implement ShowPosition() for single-line wxTextCtrl.
|
||||||
- Improve wx{Client,Paint,Screen,Window}DC::GetPPI() (GTK+ 3).
|
- Improve wx{Client,Paint,Screen,Window}DC::GetPPI() (GTK+ 3).
|
||||||
- Suppress focus loss events for wxChoice and wxComboBox on opening popup.
|
- Suppress focus loss events for wxChoice and wxComboBox on opening popup.
|
||||||
|
- Make custom URI schemes work WebKit2-based wxWebView (Scott Talbert).
|
||||||
|
|
||||||
wxMSW:
|
wxMSW:
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ class wxGtkError
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxGtkError() { m_error = NULL; }
|
wxGtkError() { m_error = NULL; }
|
||||||
|
explicit wxGtkError(GError* error) { m_error = error; }
|
||||||
~wxGtkError() { if ( m_error ) g_error_free(m_error); }
|
~wxGtkError() { if ( m_error ) g_error_free(m_error); }
|
||||||
|
|
||||||
GError** Out()
|
GError** Out()
|
||||||
@@ -37,6 +38,11 @@ public:
|
|||||||
return m_error != NULL;
|
return m_error != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator GError*() const
|
||||||
|
{
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
|
||||||
wxString GetMessage() const
|
wxString GetMessage() const
|
||||||
{
|
{
|
||||||
return wxString::FromUTF8(m_error->message);
|
return wxString::FromUTF8(m_error->message);
|
||||||
|
@@ -67,7 +67,7 @@ wxgtk_webview_webkit_load_changed(GtkWidget *,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
wxgtk_webview_webkit_navigation(WebKitWebView *web_view,
|
wxgtk_webview_webkit_navigation(WebKitWebView *,
|
||||||
WebKitPolicyDecision *decision,
|
WebKitPolicyDecision *decision,
|
||||||
wxWebViewWebKit *webKitCtrl)
|
wxWebViewWebKit *webKitCtrl)
|
||||||
{
|
{
|
||||||
@@ -93,16 +93,6 @@ wxgtk_webview_webkit_navigation(WebKitWebView *web_view,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(webKitCtrl->m_guard)
|
|
||||||
{
|
|
||||||
webKitCtrl->m_guard = false;
|
|
||||||
//We set this to make sure that we don't try to load the page again from
|
|
||||||
//the resource request callback
|
|
||||||
webKitCtrl->m_vfsurl = webkit_web_view_get_uri(web_view);
|
|
||||||
webkit_policy_decision_use(decision);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
webKitCtrl->m_busy = true;
|
webKitCtrl->m_busy = true;
|
||||||
|
|
||||||
wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
|
wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
|
||||||
@@ -120,32 +110,6 @@ wxgtk_webview_webkit_navigation(WebKitWebView *web_view,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
wxString wxuri = uri;
|
|
||||||
wxSharedPtr<wxWebViewHandler> handler;
|
|
||||||
wxVector<wxSharedPtr<wxWebViewHandler> > handlers = webKitCtrl->GetHandlers();
|
|
||||||
//We are not vetoed so see if we match one of the additional handlers
|
|
||||||
for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = handlers.begin();
|
|
||||||
it != handlers.end(); ++it)
|
|
||||||
{
|
|
||||||
if(wxuri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
|
|
||||||
{
|
|
||||||
handler = (*it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//If we found a handler we can then use it to load the file directly
|
|
||||||
//ourselves
|
|
||||||
if(handler)
|
|
||||||
{
|
|
||||||
webKitCtrl->m_guard = true;
|
|
||||||
wxFSFile* file = handler->GetFile(wxuri);
|
|
||||||
if(file)
|
|
||||||
{
|
|
||||||
webKitCtrl->SetPage(*file->GetStream(), wxuri);
|
|
||||||
}
|
|
||||||
//We need to throw some sort of error here if file is NULL
|
|
||||||
webkit_policy_decision_ignore(decision);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,49 +289,53 @@ wxgtk_webview_webkit_title_changed(GtkWidget* widget,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wxgtk_webview_webkit_resource_req(WebKitWebView *,
|
wxgtk_webview_webkit_uri_scheme_request_cb(WebKitURISchemeRequest *request,
|
||||||
WebKitWebResource *,
|
wxWebViewWebKit *webKitCtrl)
|
||||||
WebKitURIRequest *request,
|
|
||||||
wxWebViewWebKit *webKitCtrl)
|
|
||||||
{
|
{
|
||||||
wxString uri = webkit_uri_request_get_uri(request);
|
const wxString scheme = wxString::FromUTF8(webkit_uri_scheme_request_get_scheme(request));
|
||||||
|
|
||||||
wxSharedPtr<wxWebViewHandler> handler;
|
wxSharedPtr<wxWebViewHandler> handler;
|
||||||
wxVector<wxSharedPtr<wxWebViewHandler> > handlers = webKitCtrl->GetHandlers();
|
wxVector<wxSharedPtr<wxWebViewHandler> > handlers = webKitCtrl->GetHandlers();
|
||||||
|
|
||||||
//We are not vetoed so see if we match one of the additional handlers
|
|
||||||
for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = handlers.begin();
|
for(wxVector<wxSharedPtr<wxWebViewHandler> >::iterator it = handlers.begin();
|
||||||
it != handlers.end(); ++it)
|
it != handlers.end(); ++it)
|
||||||
{
|
{
|
||||||
if(uri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
|
if(scheme == (*it)->GetName())
|
||||||
{
|
{
|
||||||
handler = (*it);
|
handler = (*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//If we found a handler we can then use it to load the file directly
|
|
||||||
//ourselves
|
|
||||||
if(handler)
|
if(handler)
|
||||||
{
|
{
|
||||||
//If it is requsting the page itself then return as we have already
|
const wxString uri = wxString::FromUTF8(webkit_uri_scheme_request_get_uri(request));
|
||||||
//loaded it from the archive
|
|
||||||
if(webKitCtrl->m_vfsurl == uri)
|
|
||||||
return;
|
|
||||||
|
|
||||||
wxFSFile* file = handler->GetFile(uri);
|
wxFSFile* file = handler->GetFile(uri);
|
||||||
if(file)
|
if(file)
|
||||||
{
|
{
|
||||||
//We load the data into a data url to save it being written out again
|
gint64 length = file->GetStream()->GetLength();
|
||||||
size_t size = file->GetStream()->GetLength();
|
guint8 *data = g_new(guint8, length);
|
||||||
char *buffer = new char[size];
|
file->GetStream()->Read(data, length);
|
||||||
file->GetStream()->Read(buffer, size);
|
GInputStream *stream = g_memory_input_stream_new_from_data(data,
|
||||||
wxString data = wxBase64Encode(buffer, size);
|
length,
|
||||||
delete[] buffer;
|
g_free);
|
||||||
wxString mime = file->GetMimeType();
|
wxString mime = file->GetMimeType();
|
||||||
wxString path = "data:" + mime + ";base64," + data;
|
webkit_uri_scheme_request_finish(request, stream, length, mime.utf8_str());
|
||||||
//Then we can redirect the call
|
|
||||||
webkit_uri_request_set_uri(request, path.utf8_str());
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxGtkError error(g_error_new(WEBKIT_NETWORK_ERROR,
|
||||||
|
WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST,
|
||||||
|
"File not found: %s", uri.utf8_str().data()));
|
||||||
|
webkit_uri_scheme_request_finish_error(request, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wxGtkError error(g_error_new(WEBKIT_NETWORK_ERROR,
|
||||||
|
WEBKIT_NETWORK_ERROR_UNKNOWN_PROTOCOL,
|
||||||
|
"Unknown scheme: %s", scheme.utf8_str().data()));
|
||||||
|
webkit_uri_scheme_request_finish_error(request, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,38 +537,35 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetupWebExtensionServer();
|
SetupWebExtensionServer();
|
||||||
g_signal_connect_after(webkit_web_context_get_default(),
|
g_signal_connect(webkit_web_context_get_default(),
|
||||||
"initialize-web-extensions",
|
"initialize-web-extensions",
|
||||||
G_CALLBACK(wxgtk_initialize_web_extensions),
|
G_CALLBACK(wxgtk_initialize_web_extensions),
|
||||||
m_dbusServer);
|
m_dbusServer);
|
||||||
|
|
||||||
m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
|
m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
|
||||||
GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
|
GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
|
||||||
g_object_ref(m_widget);
|
g_object_ref(m_widget);
|
||||||
|
|
||||||
g_signal_connect_after(m_web_view, "decide-policy",
|
g_signal_connect(m_web_view, "decide-policy",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_decide_policy),
|
G_CALLBACK(wxgtk_webview_webkit_decide_policy),
|
||||||
this);
|
this);
|
||||||
|
|
||||||
g_signal_connect_after(m_web_view, "load-failed",
|
g_signal_connect(m_web_view, "load-failed",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_load_failed), this);
|
G_CALLBACK(wxgtk_webview_webkit_load_failed), this);
|
||||||
|
|
||||||
g_signal_connect_after(m_web_view, "notify::title",
|
g_signal_connect(m_web_view, "notify::title",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
|
G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
|
||||||
|
|
||||||
g_signal_connect_after(m_web_view, "resource-load-started",
|
g_signal_connect(m_web_view, "context-menu",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_resource_req), this);
|
G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
|
||||||
|
|
||||||
g_signal_connect_after(m_web_view, "context-menu",
|
g_signal_connect(m_web_view, "create",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
|
G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
|
||||||
|
|
||||||
g_signal_connect_after(m_web_view, "create",
|
|
||||||
G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
|
|
||||||
|
|
||||||
WebKitFindController* findctrl = webkit_web_view_get_find_controller(m_web_view);
|
WebKitFindController* findctrl = webkit_web_view_get_find_controller(m_web_view);
|
||||||
g_signal_connect_after(findctrl, "counted-matches",
|
g_signal_connect(findctrl, "counted-matches",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_counted_matches),
|
G_CALLBACK(wxgtk_webview_webkit_counted_matches),
|
||||||
&m_findCount);
|
&m_findCount);
|
||||||
|
|
||||||
m_parent->DoAddChild( this );
|
m_parent->DoAddChild( this );
|
||||||
|
|
||||||
@@ -610,9 +575,9 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
|
|||||||
webkit_web_view_load_uri(m_web_view, url.utf8_str());
|
webkit_web_view_load_uri(m_web_view, url.utf8_str());
|
||||||
|
|
||||||
// last to avoid getting signal too early
|
// last to avoid getting signal too early
|
||||||
g_signal_connect_after(m_web_view, "load-changed",
|
g_signal_connect(m_web_view, "load-changed",
|
||||||
G_CALLBACK(wxgtk_webview_webkit_load_changed),
|
G_CALLBACK(wxgtk_webview_webkit_load_changed),
|
||||||
this);
|
this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1279,6 +1244,10 @@ bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output)
|
|||||||
void wxWebViewWebKit::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
|
void wxWebViewWebKit::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
|
||||||
{
|
{
|
||||||
m_handlerList.push_back(handler);
|
m_handlerList.push_back(handler);
|
||||||
|
WebKitWebContext* context = webkit_web_context_get_default();
|
||||||
|
webkit_web_context_register_uri_scheme(context, handler->GetName().utf8_str(),
|
||||||
|
(WebKitURISchemeRequestCallback)wxgtk_webview_webkit_uri_scheme_request_cb,
|
||||||
|
this, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxWebViewWebKit::EnableContextMenu(bool enable)
|
void wxWebViewWebKit::EnableContextMenu(bool enable)
|
||||||
|
Reference in New Issue
Block a user