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:
Scott Talbert
2018-02-04 16:32:03 -05:00
committed by Vadim Zeitlin
parent aaf58e2b49
commit 1f2173b9be
3 changed files with 60 additions and 84 deletions

View File

@@ -209,6 +209,7 @@ wxGTK:
- Implement ShowPosition() for single-line wxTextCtrl.
- Improve wx{Client,Paint,Screen,Window}DC::GetPPI() (GTK+ 3).
- Suppress focus loss events for wxChoice and wxComboBox on opening popup.
- Make custom URI schemes work WebKit2-based wxWebView (Scott Talbert).
wxMSW:

View File

@@ -21,6 +21,7 @@ class wxGtkError
{
public:
wxGtkError() { m_error = NULL; }
explicit wxGtkError(GError* error) { m_error = error; }
~wxGtkError() { if ( m_error ) g_error_free(m_error); }
GError** Out()
@@ -37,6 +38,11 @@ public:
return m_error != NULL;
}
operator GError*() const
{
return m_error;
}
wxString GetMessage() const
{
return wxString::FromUTF8(m_error->message);

View File

@@ -67,7 +67,7 @@ wxgtk_webview_webkit_load_changed(GtkWidget *,
}
static gboolean
wxgtk_webview_webkit_navigation(WebKitWebView *web_view,
wxgtk_webview_webkit_navigation(WebKitWebView *,
WebKitPolicyDecision *decision,
wxWebViewWebKit *webKitCtrl)
{
@@ -93,16 +93,6 @@ wxgtk_webview_webkit_navigation(WebKitWebView *web_view,
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;
wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
@@ -120,32 +110,6 @@ wxgtk_webview_webkit_navigation(WebKitWebView *web_view,
}
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;
}
}
@@ -325,49 +289,53 @@ wxgtk_webview_webkit_title_changed(GtkWidget* widget,
}
static void
wxgtk_webview_webkit_resource_req(WebKitWebView *,
WebKitWebResource *,
WebKitURIRequest *request,
wxWebViewWebKit *webKitCtrl)
wxgtk_webview_webkit_uri_scheme_request_cb(WebKitURISchemeRequest *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;
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(uri.substr(0, (*it)->GetName().length()) == (*it)->GetName())
if(scheme == (*it)->GetName())
{
handler = (*it);
}
}
//If we found a handler we can then use it to load the file directly
//ourselves
if(handler)
{
//If it is requsting the page itself then return as we have already
//loaded it from the archive
if(webKitCtrl->m_vfsurl == uri)
return;
const wxString uri = wxString::FromUTF8(webkit_uri_scheme_request_get_uri(request));
wxFSFile* file = handler->GetFile(uri);
if(file)
{
//We load the data into a data url to save it being written out again
size_t size = file->GetStream()->GetLength();
char *buffer = new char[size];
file->GetStream()->Read(buffer, size);
wxString data = wxBase64Encode(buffer, size);
delete[] buffer;
gint64 length = file->GetStream()->GetLength();
guint8 *data = g_new(guint8, length);
file->GetStream()->Read(data, length);
GInputStream *stream = g_memory_input_stream_new_from_data(data,
length,
g_free);
wxString mime = file->GetMimeType();
wxString path = "data:" + mime + ";base64," + data;
//Then we can redirect the call
webkit_uri_request_set_uri(request, path.utf8_str());
webkit_uri_scheme_request_finish(request, stream, length, mime.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();
g_signal_connect_after(webkit_web_context_get_default(),
"initialize-web-extensions",
G_CALLBACK(wxgtk_initialize_web_extensions),
m_dbusServer);
g_signal_connect(webkit_web_context_get_default(),
"initialize-web-extensions",
G_CALLBACK(wxgtk_initialize_web_extensions),
m_dbusServer);
m_web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
GTKCreateScrolledWindowWith(GTK_WIDGET(m_web_view));
g_object_ref(m_widget);
g_signal_connect_after(m_web_view, "decide-policy",
G_CALLBACK(wxgtk_webview_webkit_decide_policy),
this);
g_signal_connect(m_web_view, "decide-policy",
G_CALLBACK(wxgtk_webview_webkit_decide_policy),
this);
g_signal_connect_after(m_web_view, "load-failed",
G_CALLBACK(wxgtk_webview_webkit_load_failed), this);
g_signal_connect(m_web_view, "load-failed",
G_CALLBACK(wxgtk_webview_webkit_load_failed), this);
g_signal_connect_after(m_web_view, "notify::title",
G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
g_signal_connect(m_web_view, "notify::title",
G_CALLBACK(wxgtk_webview_webkit_title_changed), this);
g_signal_connect_after(m_web_view, "resource-load-started",
G_CALLBACK(wxgtk_webview_webkit_resource_req), this);
g_signal_connect(m_web_view, "context-menu",
G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
g_signal_connect_after(m_web_view, "context-menu",
G_CALLBACK(wxgtk_webview_webkit_context_menu), this);
g_signal_connect_after(m_web_view, "create",
G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
g_signal_connect(m_web_view, "create",
G_CALLBACK(wxgtk_webview_webkit_create_webview), this);
WebKitFindController* findctrl = webkit_web_view_get_find_controller(m_web_view);
g_signal_connect_after(findctrl, "counted-matches",
G_CALLBACK(wxgtk_webview_webkit_counted_matches),
&m_findCount);
g_signal_connect(findctrl, "counted-matches",
G_CALLBACK(wxgtk_webview_webkit_counted_matches),
&m_findCount);
m_parent->DoAddChild( this );
@@ -610,9 +575,9 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
webkit_web_view_load_uri(m_web_view, url.utf8_str());
// last to avoid getting signal too early
g_signal_connect_after(m_web_view, "load-changed",
G_CALLBACK(wxgtk_webview_webkit_load_changed),
this);
g_signal_connect(m_web_view, "load-changed",
G_CALLBACK(wxgtk_webview_webkit_load_changed),
this);
return true;
}
@@ -1279,6 +1244,10 @@ bool wxWebViewWebKit::RunScript(const wxString& javascript, wxString* output)
void wxWebViewWebKit::RegisterHandler(wxSharedPtr<wxWebViewHandler> 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)