Merge branch 'webview-chromium'

Add Chromium-based wxWebView backend.

See #706.
This commit is contained in:
Vadim Zeitlin 2024-01-19 03:07:44 +01:00
commit f37401dde3
75 changed files with 5034 additions and 309 deletions

View file

@ -339,7 +339,8 @@ public:
local storage, etc.
@param path The path to the data directory.
@note This is only used by the Edge and WebKit2GTK+ backend.
@note This is used by Edge, WebKit2GTK+ and Chromium backends (the
latter creates "UserData" subdirectory under the given path).
*/
void SetDataPath(const wxString& path);
@ -350,7 +351,8 @@ public:
local storage, etc.
@return The path to the data directory.
@note This is only used by the Edge and WebKit2GTK+ backend.
@note This is used by Edge, WebKit2GTK+ and Chromium backends and
always returns empty string for the other ones.
*/
wxString GetDataPath() const;
};
@ -871,6 +873,11 @@ public:
The predefined @c wxWebViewBackendWebKit constant contains the name of this
backend.
@par wxWEBVIEW_CHROMIUM (MSW, OSX, GTK)
The Chromium Embedded Framework backend has to be enabled when building wxWidgets,
see wxWebViewChromium for additional usage and build instructions.
@section async Asynchronous Notifications
Many of the methods in wxWebView are asynchronous, i.e. they return
@ -899,6 +906,11 @@ public:
@c scheme:///C:/example/docs.zip;protocol=zip/main.htm
@beginEventEmissionTable{wxWebViewEvent}
@event{EVT_WEBVIEW_CREATED(id, func)}
Process a @c wxEVT_WEBVIEW_CREATED event, generated when the object is
fully initialized. For the backends using asynchronous initialization,
such as wxWebViewChromium, most of this class member functions can be
only used once this event is received.
@event{EVT_WEBVIEW_NAVIGATING(id, func)}
Process a @c wxEVT_WEBVIEW_NAVIGATING event, generated before trying
to get a resource. This event may be vetoed to prevent navigating to this
@ -962,6 +974,12 @@ public:
/**
Creation function for two-step creation.
Please note that the object creation may be asynchronous when using
some backends (currently this is the case only for wxWebViewChromium)
and the object is not really created until wxEVT_WEBVIEW_CREATED event
is received, so any non-trivial calls to its member functions should be
delayed until then.
*/
virtual bool Create(wxWindow* parent,
wxWindowID id,
@ -994,6 +1012,10 @@ public:
/**
Factory function to create a new wxWebView using a wxWebViewFactory.
Note that the returned object may not be immediately usable yet, see
Create() and wxEVT_WEBVIEW_CREATED.
@param parent Parent window for the control
@param id ID of this control
@param url Initial URL to load
@ -1217,8 +1239,17 @@ public:
The @a proxy string must be a valid proxy specification, e.g. @c
http://my.local.proxy.corp:8080
@note Currently this function is only implemented in WebKit2 and Edge
backends and must be called before Create() for the latter one.
Currently this function is only implemented in WebKit2, Edge and
Chromium backends and only WebKit2 backend allows to set the proxy
after creating the webview, so it is recommended to call it before
Create():
@code
auto webview = wxWebView::New();
if ( !webview->SetProxy("http://127.0.0.1:8080") ) {
wxLogWarning("Setting proxy failed!");
}
webview->Create(parent, wxID_ANY);
@endcode
@return @true if proxy was set successfully or @false if it failed,
e.g. because this is not supported by the currently used backend.
@ -1271,6 +1302,10 @@ public:
- When using WebKit under macOS, code execution is limited to at most
10MiB of memory and 10 seconds of execution time.
- When using Chromium backend, retrieving the result of JavaScript
execution is unsupported and this function will always return false
if @a output is non-null to indicate this.
- When using IE backend under MSW, scripts can only be executed when
the current page is fully loaded (i.e. @c wxEVT_WEBVIEW_LOADED event
was received). A script tag inside the page HTML is required in order
@ -1790,6 +1825,11 @@ public:
wxWebView objects.
@beginEventEmissionTable{wxWebViewEvent}
@event{EVT_WEBVIEW_CREATED(id, func)}
Process a @c wxEVT_WEBVIEW_CREATED event, generated when the object is
fully initialized. For the backends using asynchronous initialization,
such as wxWebViewChromium, most of this class member functions can be
only used once this event is received.
@event{EVT_WEBVIEW_NAVIGATING(id, func)}
Process a @c wxEVT_WEBVIEW_NAVIGATING event, generated before trying
to get a resource. This event may be vetoed to prevent navigating to this
@ -1916,6 +1956,7 @@ public:
};
wxEventType wxEVT_WEBVIEW_CREATED;
wxEventType wxEVT_WEBVIEW_NAVIGATING;
wxEventType wxEVT_WEBVIEW_NAVIGATED;
wxEventType wxEVT_WEBVIEW_LOADED;

View file

@ -0,0 +1,443 @@
/////////////////////////////////////////////////////////////////////////////
// Name: webview_chromium.h
// Purpose: interface of wxWebViewChromium
// Author: wxWidgets team
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
/**
@class wxWebViewChromium
wxWebViewChromium is a Chromium-based backend for wxWebView using the
Chromium Embedded Framework (CEF).
This backend is only available for Windows, Linux and macOS and currently
requires CEF version 116.
Using CEF also requires a compiler with C++14 support.
@section requirements Building CEF
If you are compiling your own copy of CEF then your compile flags must
match those you are using to compile wxWidgets. Specifically on Windows
it is likely you will need to adjust the following properties in the CEF
provided build files:
- C/C++ - Code Generation - Runtime Library - Multithreaded [Debug] DLL
- C/C++ - Code Generation - Enable C++ Exceptions - Yes
- C/C++ - Language - Enable Run-Time Type Information - Yes
@section instructions Build Instructions
__General__
When wxWebViewChromium backend is enabled, it is compiled as part of the
webview library which means that this library depends on CEF and all
applications using it must be linked with it.
Currently building wxWebViewChromium is possible only with configure-based
build system under Unix (including macOS) and using the provided MSVS
project files under MSW. Notably building it using CMake does not work.
Before enabling wxWebViewChromium you need to ensure that CEF is available:
1. Download the binaries for your platform from the CEF official site at
https://cef-builds.spotifycdn.com/index.html ("Minimal Distribution" is
sufficient)
2. Unpack the archive into `3rdparty/cef` directory under wxWidgets source
directory.
3. Build `libcef_dll_wrapper` using the instructions provided in the CEF
distribution, but, in short, just by using `cmake` to do it. Please note
that if you use `-DCMAKE_BUILD_TYPE=Debug` under Unix when building it, you
need to pass `--enable-cef_debug` option to wxWidgets configure to avoid
mismatches between various definitions in the wrapper itself and in
wxWidgets.
4. Copy the static library binary in the platform-dependent location:
- Under MSW, copy `libcefl_dll_wrapper.lib` file to either
`3rdparty/cef/Release` or `3rdparty/cef/Debug` depending on the build
configuration (it's recommended to build CEF wrapper in both
configurations and so copy the two files to both locations).
- Under Unix (including macOS), copy `libcef_dll_wrapper.a` file to
`3rdparty/cef/libcef_dll_wrapper` directory.
Then enable wxWebViewChromium support:
- Under MSW, set `wxUSE_WEBVIEW_CHROMIUM` to 1 in `wx/msw/setup.h`.
- Under Unix, add `--enable-webviewchromium` option to configure command
line.
Finally, build wxWidgets as usual: the resulting webview library will
include wxWebViewChromium.
It is recommended to build webview sample to check that everything is
working as expected. Under Unix, the required CEF files will be copied to
the sample directory as part of the build process, but under MSW you need
to copy them manually before running the sample: please copy
- All files from either `3rdparty/cef/Debug` or
`3rdparty/cef/Release` folder, depending on your build type
- The contents of the wx_root/3rdparty/cef/Resources folder.
to the directory containing `webview` executable.
Please see CEF `README.txt` for more details and also note that when
redistributing CEF you must abide by the terms of its `LICENSE.txt`.
Note that by default the webview sample uses the default platform-dependent
wxWebView backend and to use Chromium backend in it you need to set
`WX_WEBVIEW_BACKEND` environment variable to the value `wxWebViewChromium`.
__CEF Helper Process__
CEF uses multiple processes. The main process, using wxWidgets and creating
wxWebViewChromium, is known as the "browser process" but CEF also creates
additional helper processes for other tasks it needs to perform. Under
non-Mac platforms by default the main process itself is also used as the
helper process: if the main process detects the presence of the special
`--type=` command line option, it considers that it is executed as "CEF
helper" and just passes the command line to CEF instead of executing as
usual. This happens before executing any application-specific code and so
makes it impossible to use `--type` option for the application itself.
Under macOS main process cannot be used as the helper process and a
separate executable with the fixed name must be built to be used instead.
wxWidgets provides a trivial source of such helper process in
`samples/webview/cef_process_helper.cpp` file, which has to be compiled and
linked with CEF at least under macOS.
It may also be desirable to use a separate helper process under the other
platforms too and if an executable called `yourapp_cef_helper` (Unix) or
`yourapp_cef_helper.exe` (MSW), where `yourapp` is the name of the
application such as returned by wxApp::GetAppName(), is found in the same
directory as the main application executable itself, it will be used as the
CEF helper process.
__Microsoft Windows Platform__
Windows 10 or newer is required to run applications using wxWebViewChromium.
Such applications should also have an application manifest declaring compatibility
with supported Windows versions.
Microsoft Visual C++ 2022 must be used to build wxWebViewChromium.
When linking an application using it, both `libcef.lib` and
`libcef_dll_wrapper.lib` should be included in the libraries list.
__Linux with GTK__
wxWebviewChromium currently only supports X11 and not Wayland, i.e. you
need to either ensure that `GDK_BACKEND` environment variable is set to
"x11" before running your program using it or call
@code
gdk_set_allowed_backends("x11")
@endcode
in your application code, otherwise wxWebView::IsBackendAvailable() will
return @false when the application is running under Wayland and creating
wxWebviewChromium will fail in this case.
Moreover, the actual browser is only created once the window is shown, and
can't be used until then. You can bind an event handler for wxEVT_CREATE to
know when it is usable.
__Mac OS X Platform__
OS X 10.13 or above is required.
Due to the application bundle structure on OS X, wxWebviewChromium is a
little more complicated than on Windows/Linux platforms as extra helper
applications for executing separate Chromium processes(renderer, plugin,
etc) are required.
For applications using wxWebviewChromium, below are the steps to make
it work, based off the webview sample bakefile.
1. Build the webview library with CEF support.
2. Compile/link/package the `YourApp helper` app:
- Require `cef_process_helper.cpp`
- Require link frameworks: Chromium Embedded Framework.framework,
AppKit.frameworks.
- Require app bundle configuration: Info.plist
- Use system tool `install_name_tool -change` to correct `Chromium
Embedded Framework.framework/Chromium Embedded Framework` location.
3. Compile/link/package `YourApp` itself as usual under macOS.
4. Create a `Contents/Frameworks` directory in `YourApp.app` bundle
and copy `Chromium Embedded Framework` and `YourApp helper.app` into it.
5. Create clones of `YourApp helper.app`, in the same directory, with the
names `YourApp helper (Alerts).app`, `YourApp helper (GUI).app` etc. It
is possible to use symbolic links to `YourApp helper` binary for the
executable files of these extra helpers.
Below is the wxWebviewChromium sample app bundle directory structure,
omitting some resource files
webview.app
|____Contents
|____MacOS
| |____webview
|____Resources
| |____wxmac.icns
|____Frameworks
| |____webview Helper.app
| | |____Contents
| | |____MacOS
| | | |____webview Helper
| | |____Resources
| | | |____wxmac.icns
| | |____Info.plist
| |____webview Helper (GPU).app
| | |____Contents
| | |____MacOS
| | | |____webview Helper (GPU)
| | |____Resources
| | | |____wxmac.icns
| | |____Info.plist
| |____webview Helper (Plugin).app
| | |____Contents
| | |____MacOS
| | | |____webview Helper (Plugin)
| | |____Resources
| | | |____wxmac.icns
| | |____Info.plist
| |____Chromium Embedded Framework.framework
| | |____Resources
| | | |____chrome_200_percent.pak
| | | |____chrome_100_percent.pak
| | | |____icudtl.dat
| | | |____snapshot_blob.bin
| | | |____v8_context_snapshot.arm64.bin
| | | |____resources.pak
| | | |____gpu_shader_cache.bin
| | | |____Info.plist
| | |____Libraries
| | | |____libEGL.dylib
| | | |____vk_swiftshader_icd.json
| | | |____libvk_swiftshader.dylib
| | | |____libGLESv2.dylib
| | |____Chromium Embedded Framework
| |____webview Helper (Renderer).app
| | |____Contents
| | |____MacOS
| | | |____webview Helper (Renderer)
| | |____Resources
| | | |____wxmac.icns
| | |____Info.plist
| |____webview Helper (Alerts).app
| |____Contents
| |____MacOS
| | |____webview Helper (Alerts)
| |____Resources
| | |____wxmac.icns
| |____Info.plist
|____Info.plist
@section differences API Differences
wxWebViewChromium aims to support the full wxWebView API, but there are
some features which are currently unsupported:
- GetSelectedSource/GetSelectedText: Always returns "".
- HasSelection: Always returns false.
- IsEditable: Always returns false.
- CanUndo/CanRedo/CanCut/CanCopy/CanPaste: Always returns true.
- Find: Always returns -1.
- RunScript: Retrieving the result of JavaScript execution is not supported and
if the @a output parameter is non-null, the function will always return false.
wxWebView also provides some functions not available in the base class:
- SetRoot() allows to use the given directory for all application files.
@section events Events
wxWebViewChromiumEvent is a specific event generated when a message from
the renderer process (in which any user-defined JavaScript functions are
executing) is received in the browser process (containing UI). Such
messages are sent using `CefFrame::SendProcessMessage(PID_BROWSER)` from
the renderer process, but describing Chromium IPC in details is out of
scope of this document, please see Chromium documentation for more
information.
@since 3.3.0
@library{wxwebview}
@category{webview}
**/
class wxWebViewChromium : public wxWebView
{
public:
/**
Default constructor.
Use Create() to actually create the web view object later.
*/
wxWebViewChromium();
/**
Constructor allowing to specify extra configuration parameters.
You must use Create() to really initialize the object created with this
constructor.
Chromium-specific configuration parameters can be specified by setting
wxWebViewConfigurationChromium fields before passing @a config to this
function, e.g.
@code
wxWebViewConfiguration config =
wxWebView::NewConfiguration(wxWebViewBackendChromium);
auto configChrome =
static_cast<wxWebViewConfigurationChromium*>(config.GetNativeConfiguration());
configChrome->m_logFile = "/my/custom/CEF/log/file/path.txt";
auto webview = new wxWebViewChromium(config);
webview->Create(this, wxID_ANY, url);
@endcode
*/
explicit wxWebViewChromium(const wxWebViewConfiguration& config);
/**
wxWebViewChromium constructor, arguments as per wxWebView::New.
*/
wxWebViewChromium(wxWindow* parent,
wxWindowID id,
const wxString& url = wxWebViewDefaultURLStr,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxWebViewNameStr);
/**
Creation function for two-step creation.
*/
virtual bool Create(wxWindow* parent,
wxWindowID id,
const wxString& url = wxWebViewDefaultURLStr,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0,
const wxString& name = wxWebViewNameStr);
/**
Use the specified directory as root for the file:// URLs.
After calling this function, all file paths will be resolved relatively
to the given @a rootDir rather than to the actual file system root.
*/
void SetRoot(const wxFileName& rootDir);
};
/**
Chromium-specific configuration parameters.
This simple class contains parameters that can be passed to the function
initializing CEF when wxWebView is used for the first time.
To use this struct you need to cast the value returned from
wxWebViewConfiguration::GetNativeConfiguration() to this type:
@code
wxWebViewConfiguration config =
wxWebView::NewConfiguration(wxWebViewBackendChromium);
auto configChrome =
static_cast<wxWebViewConfigurationChromium*>(config.GetNativeConfiguration());
configChrome->m_logLevel = 99; // Disable all logging.
@endcode
@since 3.3.0
*/
class wxWebViewConfigurationChromium
{
public:
/**
Default constructor initializes the object to default parameters.
*/
wxWebViewConfigurationChromium();
/**
CEF log file location.
Should be an absolute path if specified.
If this variable is empty, `debug.log` under the data directory is
used.
*/
wxString m_logFile;
/**
Logging level to use for CEF.
This must be one of `cef_log_severity_t` values.
Default value 0 means to use default "INFO" log level.
*/
int m_logLevel = 0;
};
/**
Event class for events generated exclusively by wxWebViewChromium.
See wxWebViewEvent for other events also generated by wxWebViewEvent.
Currently there is a single event type corresponding to this event:
`wxEVT_WEBVIEW_CHROMIUM_MESSAGE_RECEIVED`. To use it (this example assumes
that the required CEF headers are included):
@code
webview->Bind(
wxEVT_WEBVIEW_CHROMIUM_MESSAGE_RECEIVED,
[this](wxWebViewChromiumEvent& event) {
if ( event.GetMessageName() == "MyCustomRequest" ) {
CefRefPtr<CefListValue> arguments = event.GetMessage().GetArgumentList();
CefRefPtr<CefProcessMessage> response = CefProcessMessage::Create("MyCustomResponse");
// ... do whatever is needed to construct the response ...
event.GetFrame().SendProcessMessage(PID_RENDERER, response);
} else {
// Not our message.
event.Skip();
}
}
);
@endcode
@since 3.3.0
@library{wxwebview}
@category{webview}
**/
class wxWebViewChromiumEvent : public wxCommandEvent
{
public:
/**
Get the associated browser frame.
This object can be used to call `SendProcessMessage(PID_RENDERER)` on
it to send the reply back to the renderer process.
*/
CefFrame& GetFrame() const;
/**
Get the actual message.
Message arguments can be used in the event handler to get information
associated with this message.
*/
CefProcessMessage& GetMessage() const;
/**
Get the message name.
This is just a convenient wrapper for `GetMessage().GetName()`.
*/
wxString GetMessageName() const;
};