Building a browser using Servo as a web engine!

2024-09-11 Let's build another web browser based on Servo!

As a web engine, Servo primarily handles everything around scripting and layout. For embedding use cases, the Tauri community experimented with adding a new Servo backend, but Servo can also be used to build a browser.

We have a reference browser in the form of servoshell, which has historically been used as a minimal example and as a test harness for the Web Platform Tests. Nevertheless, the Servo community has steadily worked towards making it a browser in its own right, starting with our new browser UI based on egui last year.

This year, @wusyong, a member of Servo TSC, created the Verso project as a way to explore the features Servo needs to power a robust web browser. In this post, we’ll explain what we tried to achieve, what we found, and what’s next for building a browser using Servo as a web engine.

Multi-view

Of course, the first major feature we want to achieve is multiple webviews. A webview is a term abstracted from the top-level browsing context. This is what people refer to as a web page. With multi-view support, we can create multiple web pages as tabs in a single window. Most importantly, we can draw our UI with additional webviews. The main reason we want to write UI using Servo itself is that we can dogfood our own stack and verify that it can meet practical requirements, such as prompt windows, context menus, file selectors, and more.

Basic multi-view support was reviewed and merged into Servo earlier this year thanks to @delan (#30840, #30841, #30842). Verso refined that into a specific type called WebView. From there, any function that owns webviews can decide how to present them depending on their IDs. In a Verso window, two webviews are created at the moment—one for handling regular web pages and the other for handling the UI, which is currently called the Panel. The result of the showcase in Verso’s README.md looks like this:

Verso displaying ASCII text in a CRT style
Figure 1: Verso window displaying two different webviews. One for the UI, the other for the web page.

For now, the inter-process communication is done via Servo’s existing channel messages like EmbedderMsg and EmbedderEvent. We are looking to improve the IPC mechanism with more granular control over DOM elements. So, the panel UI can be updated based on the status of web pages. One example is when the page URL is changed and the navigation bar needs to be updated. There are some candidates for this, such as WebDriverCommandMsg. @webbeef also started a discussion about defining custom elements like <webview> for better ergonomics. Overall, improving IPC will be the next target to research after initial multi-view support. We will also define more specific webview types to satisfy different purposes in the future.

Multi-window

The other prominent feature after multi-view is the ability to support multiple windows. This one wasn’t planned at first, but because it affects too many components, we ended up resolving them together from the ground up.

Servo uses WebRender, based on OpenGL, to render its layout. To support multiple windows, we need to support multiple OpenGL surfaces. One approach would be to create separate OpenGL contexts for each window. But since our implementations of WebGL, WebGPU, and WebXR are all tied to a single WebRender instance, which in turn only supports a single OpenGL context for now, we chose to use a single context with multiple surfaces. This alternative approach could potentially use less memory and spawn fewer threads. For more details, see this series of blog posts by @wusyong.

Verso displaying two windows
Figure 2: Verso creates two separate windows with the same OpenGL context.

There is still room for improvement. For example, WebRender currently only supports rendering a single “document”. Unless we create multiple WebRender instances, like Firefox does, we have one WebRender document that has to constantly update all of its display lists to show on all of our windows. This could potentially lead to race conditions where a webview may draw to the wrong window for a split second.

There are also different OpenGL versions across multiple platforms, which can be challenging to configure and link. Verso is experimenting with using Glutin for better configuration and attempting to get closer to the general Rust ecosystem.

What’s next?

With multi-view and multi-window support as the fundamental building blocks, we could create more UI elements to keep pushing the envelope of our browser and embedding research. At the same time, Servo is a huge project, with many potential improvements still to come, so we want to reflect on our progress and decide on our priorities. Here are some directions that are worth pursuing.

Benchmarking and metrics

We want to gather the strength of the community to help us track the statistics of supported CSS properties and web APIs in Servo by popularity order and benchmark results such as jetstream2 and speedometer3. @sagudev already started a subset of speedometer3 to experiment. We hope this will eventually give newcomers a better overview of Servo.

Script triage

There’s a Servo triage meeting every two weeks to triage any issues around the script crate and more. Once we get the statistics of supported web APIs, we can find the most popular ones that haven’t been implemented or fixed yet. We are already fixing some issues around loading the order and re-implementing ReadableStream in Rust. If you are interested in implementing web APIs in Servo, feel free to join the next meeting.

Multi-process and sandboxing

Some features are crucial to the browser but not visible to users. Multi-process architecture and sandboxing belong to this category. Both of these are implemented in Servo to some extent, but only on Linux and macOS right now, and neither of the features are enabled by default.

We would like to improve these features and validate them in CI workflows. In the meantime, we are looking for people who can extend our sandbox to Windows via Named Pipes and AppContainer Isolation.

Acknowledgments

This work was sponsored by NLNet and the Next Generation Internet initiative. We are grateful the European Commission shares the same vision for a better and more open browser ecosystem.

NLNet Logo NGI Logo