From 1f2173b9be49016f023a6de982c08542b10db7f3 Mon Sep 17 00:00:00 2001 From: Scott Talbert Date: Sun, 4 Feb 2018 16:32:03 -0500 Subject: [PATCH] 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 --- docs/changes.txt | 1 + include/wx/gtk/private/error.h | 6 ++ src/gtk/webview_webkit2.cpp | 137 +++++++++++++-------------------- 3 files changed, 60 insertions(+), 84 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 6ad30469d8..9eb241556d 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -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: diff --git a/include/wx/gtk/private/error.h b/include/wx/gtk/private/error.h index e3b49475b7..25802dd6f3 100644 --- a/include/wx/gtk/private/error.h +++ b/include/wx/gtk/private/error.h @@ -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); diff --git a/src/gtk/webview_webkit2.cpp b/src/gtk/webview_webkit2.cpp index c65c41c3ad..cc495dea75 100644 --- a/src/gtk/webview_webkit2.cpp +++ b/src/gtk/webview_webkit2.cpp @@ -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 handler; - wxVector > handlers = webKitCtrl->GetHandlers(); - //We are not vetoed so see if we match one of the additional handlers - for(wxVector >::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 handler; wxVector > handlers = webKitCtrl->GetHandlers(); - //We are not vetoed so see if we match one of the additional handlers for(wxVector >::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 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)