From 40ff38b63b594e6a82bf6f7845e0ac2cb8ae2449 Mon Sep 17 00:00:00 2001 From: Tobias Taschner Date: Thu, 8 Sep 2022 13:07:29 +0200 Subject: [PATCH 1/3] Add wxWebView::GetNativeConfiguration() New method to return the pointer to the native configuration used during the creation of the web view This allows for customization that would not be available to the application otherwise. --- include/wx/msw/private/webview_edge.h | 1 + include/wx/msw/webview_edge.h | 1 + include/wx/osx/webview_webkit.h | 7 ++++- include/wx/webview.h | 1 + interface/wx/webview.h | 42 +++++++++++++++++++++++++++ src/msw/webview_edge.cpp | 23 +++++++-------- src/osx/webview_webkit.mm | 11 ++++++- 7 files changed, 72 insertions(+), 14 deletions(-) diff --git a/include/wx/msw/private/webview_edge.h b/include/wx/msw/private/webview_edge.h index ec497f0e77..49b91f7c44 100644 --- a/include/wx/msw/private/webview_edge.h +++ b/include/wx/msw/private/webview_edge.h @@ -53,6 +53,7 @@ public: wxCOMPtr m_webViewEnvironment; wxCOMPtr m_webView; wxCOMPtr m_webViewController; + wxCOMPtr m_webViewEnvironmentOptions; bool m_initialized; bool m_isBusy; diff --git a/include/wx/msw/webview_edge.h b/include/wx/msw/webview_edge.h index d84b74d927..a52f0a989e 100644 --- a/include/wx/msw/webview_edge.h +++ b/include/wx/msw/webview_edge.h @@ -98,6 +98,7 @@ public: virtual void RegisterHandler(wxSharedPtr handler) wxOVERRIDE; virtual void* GetNativeBackend() const wxOVERRIDE; + virtual void* GetNativeConfiguration() const wxOVERRIDE; static void MSWSetBrowserExecutableDir(const wxString& path); diff --git a/include/wx/osx/webview_webkit.h b/include/wx/osx/webview_webkit.h index 420b8f6452..7ea1f0d688 100644 --- a/include/wx/osx/webview_webkit.h +++ b/include/wx/osx/webview_webkit.h @@ -32,7 +32,7 @@ class WXDLLIMPEXP_WEBVIEW wxWebViewWebKit : public wxWebView public: wxDECLARE_DYNAMIC_CLASS(wxWebViewWebKit); - wxWebViewWebKit() {} + wxWebViewWebKit() { Init(); } wxWebViewWebKit(wxWindow *parent, wxWindowID winID = wxID_ANY, const wxString& strURL = wxASCII_STR(wxWebViewDefaultURLStr), @@ -40,6 +40,7 @@ public: const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxASCII_STR(wxWebViewNameStr)) { + Init(); Create(parent, winID, strURL, pos, size, style, name); } bool Create(wxWindow *parent, @@ -105,6 +106,7 @@ public: virtual void RegisterHandler(wxSharedPtr handler) wxOVERRIDE; virtual void* GetNativeBackend() const wxOVERRIDE { return m_webView; } + virtual void* GetNativeConfiguration() const wxOVERRIDE { return m_webViewConfiguration; } protected: virtual void DoSetPage(const wxString& html, const wxString& baseUrl) wxOVERRIDE; @@ -112,12 +114,15 @@ protected: wxDECLARE_EVENT_TABLE(); private: + WX_NSObject m_webViewConfiguration; OSXWebViewPtr m_webView; wxStringToWebHandlerMap m_handlers; wxString m_customUserAgent; WX_NSObject m_navigationDelegate; WX_NSObject m_UIDelegate; + + void Init(); }; class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryWebKit : public wxWebViewFactory diff --git a/include/wx/webview.h b/include/wx/webview.h index e1af2b67ac..5ea5f03f74 100644 --- a/include/wx/webview.h +++ b/include/wx/webview.h @@ -259,6 +259,7 @@ public: //Get the pointer to the underlying native engine. virtual void* GetNativeBackend() const = 0; + virtual void* GetNativeConfiguration() const { return NULL; } //Find function virtual long Find(const wxString& text, int flags = wxWEBVIEW_FIND_DEFAULT); diff --git a/interface/wx/webview.h b/interface/wx/webview.h index e9f58cf055..209ffc4b34 100644 --- a/interface/wx/webview.h +++ b/interface/wx/webview.h @@ -623,6 +623,48 @@ public: */ virtual void* GetNativeBackend() const = 0; + /** + Return the pointer to the native configuration used during creation of + this control. + + When using two-step creation this method can be used to customize + configuration options not available via GetNativeBackend() + after using Create(). + + The return value needs to be down-casted to the appropriate type + depending on the platform: under macOS, it's a + WKWebViewConfiguration + pointer, under Windows with Edge it's a pointer to + ICoreWebView2EnvironmentOptions. + With other backends/platforms it's not implemented. + + The following pseudo code shows how to use this method with two-step + creation to set no user action requirement to play video in a + web view: + @code + #if defined(__WXMSW__) + #include "webview2.h" + #elif defined(__WXOSX__) + #import "WebKit/WebKit.h" + #endif + + wxWebView* webView = wxWebView::New(); + #if defined(__WXMSW__) + ICoreWebView2EnvironmentOptions* webViewOptions = + (ICoreWebView2EnvironmentOptions*) webView->GetNativeConfiguration(); + webViewOptions->put_AdditionalBrowserArguments("--autoplay-policy=no-user-gesture-required"); + #elif defined(__WXOSX__) + WKWebViewConfiguration* webViewConfiguration = + (WKWebViewConfiguration*) webView->GetNativeConfiguration(); + webViewConfiguration.mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone; + #endif + webView->Create(this, wxID_ANY, "https://www.wxwidgets.org"); + @endcode + + @since 3.3.0 + */ + virtual void* GetNativeConfiguration() const; + /** Get the HTML source code of the currently displayed document. @return The HTML source code, or an empty string if no page is currently diff --git a/src/msw/webview_edge.cpp b/src/msw/webview_edge.cpp index 5302691d2c..0ed09366e8 100644 --- a/src/msw/webview_edge.cpp +++ b/src/msw/webview_edge.cpp @@ -69,7 +69,9 @@ wxString wxWebViewEdgeImpl::ms_browserExecutableDir; wxWebViewEdgeImpl::wxWebViewEdgeImpl(wxWebViewEdge* webview): m_ctrl(webview) { - +#ifdef __VISUALC__ + m_webViewEnvironmentOptions = Make().Get(); +#endif } wxWebViewEdgeImpl::~wxWebViewEdgeImpl() @@ -99,23 +101,15 @@ bool wxWebViewEdgeImpl::Create() m_historyPosition = -1; wxString userDataPath = wxStandardPaths::Get().GetUserLocalDataDir(); -#ifdef __VISUALC__ - auto options = - Make(); - if (!m_customUserAgent.empty()) - options->put_AdditionalBrowserArguments( + if (m_webViewEnvironmentOptions && !m_customUserAgent.empty()) + m_webViewEnvironmentOptions->put_AdditionalBrowserArguments( wxString::Format("--user-agent=\"%s\"", m_customUserAgent).wc_str()); -#endif HRESULT hr = wxCreateCoreWebView2EnvironmentWithOptions( ms_browserExecutableDir.wc_str(), userDataPath.wc_str(), -#ifdef __VISUALC__ - options.Get(), -#else - nullptr, -#endif + m_webViewEnvironmentOptions, Callback(this, &wxWebViewEdgeImpl::OnEnvironmentCreated).Get()); if (FAILED(hr)) @@ -844,6 +838,11 @@ void* wxWebViewEdge::GetNativeBackend() const return m_impl->m_webView; } +void* wxWebViewEdge::GetNativeConfiguration() const +{ + return m_impl->m_webViewEnvironmentOptions; +} + void wxWebViewEdge::MSWSetBrowserExecutableDir(const wxString & path) { wxWebViewEdgeImpl::ms_browserExecutableDir = path; diff --git a/src/osx/webview_webkit.mm b/src/osx/webview_webkit.mm index 64b67381ab..d5f78341c7 100644 --- a/src/osx/webview_webkit.mm +++ b/src/osx/webview_webkit.mm @@ -111,6 +111,11 @@ wxVersionInfo wxWebViewFactoryWebKit::GetVersionInfo() // creation/destruction // ---------------------------------------------------------------------------- +void wxWebViewWebKit::Init() +{ + m_webViewConfiguration = [[WKWebViewConfiguration alloc] init]; +} + bool wxWebViewWebKit::Create(wxWindow *parent, wxWindowID winID, const wxString& strURL, @@ -122,7 +127,7 @@ bool wxWebViewWebKit::Create(wxWindow *parent, wxControl::Create(parent, winID, pos, size, style, wxDefaultValidator, name); NSRect r = wxOSXGetFrameForControl( this, pos , size ) ; - WKWebViewConfiguration* webViewConfig = [[WKWebViewConfiguration alloc] init]; + WKWebViewConfiguration* webViewConfig = (WKWebViewConfiguration*) m_webViewConfiguration; if (!m_handlers.empty()) { @@ -146,6 +151,10 @@ bool wxWebViewWebKit::Create(wxWindow *parent, MacPostControlCreate(pos, size); + // WKWebView configuration is only used during creation + [m_webViewConfiguration release]; + m_webViewConfiguration = nil; + if (!m_customUserAgent.empty()) SetUserAgent(m_customUserAgent); From 4953cf65b4b3cdfd747890c54bb1da11d621db81 Mon Sep 17 00:00:00 2001 From: Tobias Taschner Date: Fri, 9 Sep 2022 10:39:30 +0200 Subject: [PATCH 2/3] Improve wxJSScriptWrapper performance The previous implementation was very inefficent on larger scripts --- include/wx/private/jsscriptwrapper.h | 58 +++++++++++++++------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/include/wx/private/jsscriptwrapper.h b/include/wx/private/jsscriptwrapper.h index a69b286b48..6e9bb1844b 100644 --- a/include/wx/private/jsscriptwrapper.h +++ b/include/wx/private/jsscriptwrapper.h @@ -33,38 +33,42 @@ public: }; wxJSScriptWrapper(const wxString& js, OutputType outputType) - : m_escapedCode(js), m_outputType(outputType) + : m_outputType(outputType) { // Adds one escape level. const char *charsNeededToBeEscaped = "\\\"\n\r\v\t\b\f"; - for ( - size_t pos = m_escapedCode.find_first_of(charsNeededToBeEscaped, 0); - pos != wxString::npos; - pos = m_escapedCode.find_first_of(charsNeededToBeEscaped, pos) - ) { - switch (m_escapedCode[pos].GetValue()) + m_escapedCode.reserve(js.size()); + for (wxString::const_iterator it = js.begin(); it != js.end(); ++it) + { + if (wxStrchr(charsNeededToBeEscaped, *it)) { - case 0x0A: // '\n' - m_escapedCode[pos] = 'n'; - break; - case 0x0D: // '\r' - m_escapedCode[pos] = 'r'; - break; - case 0x0B: // '\v' - m_escapedCode[pos] = 'v'; - break; - case 0x09: // '\t' - m_escapedCode[pos] = 't'; - break; - case 0x08: // '\b' - m_escapedCode[pos] = 'b'; - break; - case 0x0C: // '\f' - m_escapedCode[pos] = 'f'; - break; + m_escapedCode += '\\'; + switch ((wxChar) *it) + { + case 0x0A: // '\n' + m_escapedCode += 'n'; + break; + case 0x0D: // '\r' + m_escapedCode += 'r'; + break; + case 0x0B: // '\v' + m_escapedCode += 'v'; + break; + case 0x09: // '\t' + m_escapedCode += 't'; + break; + case 0x08: // '\b' + m_escapedCode += 'b'; + break; + case 0x0C: // '\f' + m_escapedCode += 'f'; + break; + default: + m_escapedCode += *it; + } } - m_escapedCode.insert(pos, '\\'); - pos += 2; + else + m_escapedCode += *it; } } From 678038316333d1bd50b8a610fe85ae666474c0f2 Mon Sep 17 00:00:00 2001 From: Tobias Taschner Date: Fri, 9 Sep 2022 18:07:00 +0200 Subject: [PATCH 3/3] Fix wxWebView documentation grouping Set/GetUserAgent() where grouped under "Dev Tools" --- interface/wx/webview.h | 43 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/interface/wx/webview.h b/interface/wx/webview.h index 209ffc4b34..7b2fb837bc 100644 --- a/interface/wx/webview.h +++ b/interface/wx/webview.h @@ -753,6 +753,27 @@ public: */ virtual void Stop() = 0; + /** + Specify a custom user agent string for the web view. + Returns @true the user agent could be set. + + If your first request should already use the custom user agent + please use two step creation and call SetUserAgent() before Create(). + + @note This is not implemented for IE. For Edge SetUserAgent() + MUST be called before Create(). + + @since 3.1.5 + */ + virtual bool SetUserAgent(const wxString& userAgent); + + /** + Returns the current user agent string for the web view. + + @since 3.1.5 + */ + virtual wxString GetUserAgent() const; + /** @name Scripting */ @@ -995,28 +1016,6 @@ public: */ virtual bool IsAccessToDevToolsEnabled() const; - /** - Specify a custom user agent string for the web view. - Returns @true the user agent could be set. - - If your first request should already use the custom user agent - please use two step creation and call SetUserAgent() before Create(). - - @note This is not implemented for IE. For Edge SetUserAgent() - MUST be called before Create(). - - @since 3.1.5 - */ - virtual bool SetUserAgent(const wxString& userAgent); - - /** - Returns the current user agent string for the web view. - - @since 3.1.5 - */ - virtual wxString GetUserAgent() const; - - /** @name History */