# libaura-webview: Web pages in AURA

`libs/aura-webview` provides the AURA element `WebView`: a full Chromium page in the scene graph, using the Chromium Embedded Framework (CEF). The page supports touch interaction and communicates with C++ code through a WebChannel. Custom JavaScript can be injected into any page.

```qml
WebView {
    id: page
    url: "https://example.org"
    script: "document.addEventListener('DOMContentLoaded', () => { ... })"
    size: parent.width - 48, parent.height - 104
}
```

Example and tests: `tests/ui-webview/webview.aura` and `tests/test_webview.cpp`.

## Building

| Option | Meaning |
|---|---|
| `-DAURA_WITH_WEBVIEW=ON` | Builds `libaura-webview` and links it into `aura-view` and `aura_webview_tests` (preset `webview`). Default: `OFF`. |
| `-DAURA_CEF_ROOT=<dir>` | Uses an unpacked CEF distribution instead of downloading it |
| `AURA_CEF_VERSION` | CEF version (default 156.0.14, Chromium 156.0.8078.48) |

- **Download:** Without `AURA_CEF_ROOT`, the build downloads the “minimal” distribution from Spotify's CDN (`cef-builds.spotifycdn.com`): approximately 330 MB (x86_64) or 430 MB (arm64). SHA1 checksums are in `cmake/Cef.cmake`.
- **Cache:** For development, download and unpack it once, for example under `~/.cache/aura/cef/`, then use `-DAURA_CEF_ROOT=~/.cache/aura/cef/cef_binary_<version>_<platform>_minimal`.
- **Wrapper:** The build compiles `libcef_dll_wrapper` (the C++ API over `libcef.so`'s C API) from the distribution's sources, using our compiler.
- **Runtime directory:** `build/<preset>/cef/` contains symlinks to `libcef.so` and the resources (`*.pak`, `icudtl.dat`, `v8_context_snapshot.bin`, `locales/`), plus the `aura-webview-helper` executable. Programs locate `libcef.so` through their rpath; the directory can be overridden at runtime with `AURA_WEBVIEW_DIR`.

## Architecture

| Part | Responsibility |
|---|---|
| `WebViewNode` (`aura/webview/webview.h`) | The node: renders the page, forwards touch input, WebChannel, scripts |
| `aura-webview-helper` | CEF subprocesses (renderer, GPU, network). In the renderer, it sets up `window.aura` and executes scripts. The application's `main()` remains free of CEF. |
| `aura::ui::registerElementType` (`aura/ui/elements.h`) | Element types from other libraries for the loader. This keeps `aura-ui` independent of CEF. |
| `aura::post()` (`aura/core/tasks.h`) | Transfers work to the UI thread safely. The loop processes it before each frame; the `aura-view` server does so on every request (`aura::runPosted()`). |

- **Rendering:** CEF renders off-screen in software (`ozone-platform=headless`, without GPU) into a BGRA buffer. The node draws it as a Skia image, with open dropdowns (`<select>`) above it. No X11 or Wayland server is required, which suits a kiosk using KMS/DRM.
- **Threads:** CEF runs its own message loop (`multi_threaded_message_loop`). A new image wakes the application (`Application::wakeUp`), and `aura-view` detects it through `frameCount()`.
- **Startup:** CEF starts with the first WebView; the browser starts on its first draw, when the node knows its size. A WebView that is never displayed costs nothing.
- **Input:** Press, drag, and release are forwarded to the page as touch events. Chromium turns them into taps and inertial scrolling. Links with `target=_blank` open in the same view.
- **Cache:** Each process has its own `/tmp/aura-webview-<pid>` directory (with `cef.log`), removed by `shutdown()`. Cookies and data do not survive a restart.

## WebChannel and scripts

Every page has `window.aura` before its own scripts run.

```js
const sum = await aura.call("add", 2, 3);   // JavaScript -> C++, Promise
aura.on("cart", (value) => render(value));  // C++ -> JavaScript
```

```cpp
#include "aura/webview/webview.h"

dialog->page->handle("add", [](const auto& args) {
	return AuraJson(args[0].toInt() + args[1].toInt());
});
dialog->page->emit("cart", {{"items", 3}});
dialog->page->runJavaScript("document.body.style.zoom = 1.2");
dialog->page->addUserScript("window.kiosk = true;");
```

- **Values:** JSON (`AuraJson`). Arguments to `aura.call` arrive as an array.
- **Handlers:** They run on the UI thread and may access the scene graph and application state. An exception rejects the Promise with its message; an unknown name does the same.
- **`emit`, `runJavaScript`:** Apply to the currently loaded page; otherwise they do nothing.
- **Scripts:** `addUserScript()` and AURA's `script:` run in every new document in the view, in the main frame, before the page's own scripts. Adding a script or changing `script` also executes it immediately in the current page. An error goes to the page's console and does not prevent the other scripts from running.
- **Transport:** CEF's message router (`auraQuery`) for calls, `ExecuteJavaScript` for events, and process messages for script lists.

## Application integration

```cpp
int main(int argc, char** argv)
{
	// Before building the first UI: register WebView for the loader;
	// locale: Chromium language (default en-US)
	aura::webview::setup(argc, argv, {.locale = "de"});
	...
	aura::webview::shutdown();  // closes all browsers and stops CEF
}
```

`aura-view` initializes CEF when built with WebView (`aura::webview` then defines the preprocessor symbol `AURA_WITH_WEBVIEW`). Without the library, the loader reports “element type 'WebView' is not part of this program” and uses the compiled version. A file containing `WebView` can only be compiled if the program links `aura::webview`.

## Preview (aura-view, VS Code)

- **Built with WebView:** `aura-view` displays WebViews in its window, with `--render`, and in the server.
- **`--render`:** Waits until the page has not repainted for 1.5 s (at most 20 s).
- **Server:** While a WebView is open, it reports `animating`, and the extension requests an image approximately every 33 ms. A response only contains a PNG if Chromium has repainted.
- **Interaction:** A click is a tap. Dragging with the mouse button pressed scrolls; the `move` command was added for this. Pausing playback in the preview also pauses the page.
- **Setting:** The preview's `aura-view` (`aura.preview.command`) must be built with WebView.

## Tests

`aura_webview_tests` (`tests/test_webview.cpp`, `tests/ui-webview/webview.aura`) builds a dialog containing a `WebView` once through compiled code and once through the loader. It loads a `data:` page without network access and checks:

- The result of `aura.call`,
- Errors and unknown handlers,
- The script defined in AURA,
- `emit` and `runJavaScript`,
- The page's pixels in the node.

## Runtime and integration

- The target system needs the system libraries required by the selected CEF distribution, along with its resources and locales.
- The integration currently starts CEF with `no_sandbox`. Account for that when selecting and embedding web content.
- Touch interaction is forwarded to Chromium; validate keyboard, IME and scaling requirements for the particular application.
- The CEF distribution contains Chromium and other third-party components. Their license notices belong with the distribution; see [Dependencies & licenses](dependencies.md).
