6.6 KiB
Servo Embedding Architecture
Decision
ELY is a Servo-based browser. The page renderer lives in the application process and follows Servo's embedder model:
┌──────────────────────────── ELY App Process ────────────────────────────┐
│ │
│ GPUI chrome │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Sidebar Toolbar Tabs Settings │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ Servo content host │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Servo + WebView + RenderingContext │ │
│ │ notify_new_frame_ready -> repaint -> paint -> present │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────┘
The app process owns WebView lifecycle, navigation, input, permissions, frame readiness, and rendering context presentation.
Current Code Boundary
WebSurfaceStore
-> GPUI NativeSurface
-> LiveRuntimeWorker
-> ServoLiveClient
-> SoftwareServoHost
-> servo::Servo + servo::WebView + servo::WindowRenderingContext
ServoLiveClient is now an in-process adapter over ely_servo_host::SoftwareServoHost. It shares one Servo runtime across profile scopes, creates multiple WebViews inside that runtime, and routes scroll, hover, click, keyboard, resize, zoom, navigation, and permissions through the ServoHost API.
Normal page display now enters GPUI through native_surface(...). GPUI creates a platform child surface for the content bounds, passes that raw handle into Servo's WindowRenderingContext, and presents with paint_without_readback_with_completion. The RGBA readback path remains inside ely_servo_host for low-level tests.
Current platform child surfaces:
- macOS: child
NSViewwith an AppKit raw window handle. - Windows: child
HWNDwith a Win32 raw window handle. - Linux/X11: child XCB window with XCB display/window handles.
- Linux/Wayland: child
wl_surfaceattached as awl_subsurfacewith Wayland display/surface handles.
Upstream Servo Route
Servo's own shell route is the model for the final ELY rendering path:
Window event
-> Servo spin_event_loop
-> WebViewDelegate::notify_new_frame_ready
-> window request_redraw
-> WebView::paint
-> RenderingContext::present
Relevant upstream evidence from Servo 7c48af7:
ports/servoshell/window.rscreatesWebViewBuilder::new(state.servo(), platform_window.rendering_context()).ports/servoshell/window.rsrepaints withwebview.paint()andrendering_context().present().ports/servoshell/running_app_state.rshandlesnotify_new_frame_readyby marking the owning window for repaint.components/paint/paint.rsowns one WebRender painter perRenderingContextand keeps paint coordination inside Servo's rendering pipeline.
Target Boundaries
crates/ely_browser_core
Owns browser domain state: tabs, spaces, profiles, search, settings.
crates/ely_app/src/shell
Owns GPUI chrome and command surfaces.
crates/ely_app/src/servo_embed
Owns in-process Servo runtime, platform content view attachment,
WebView lifecycle, repaint dispatch, and web input routing.
crates/ely_servo_host
Owns the current in-process compatibility adapter while the native
platform rendering surface lands.
Each production source file in the final embedding path stays below 500 lines. Large responsibilities split by ownership:
runtime.rs:Servo, wake handling, webview registry.platform_view.rs: platform content surface attachment.delegate.rs: ServoWebViewDelegateimplementation.input.rs: GPUI event to Servo input conversion.paint.rs: repaint and present coordination.metadata.rs: title, URL, favicon, load-state propagation.
Migration Slices
- App process owns the Servo runtime and WebView registry.
- App process routes web input and navigation directly into Servo.
- GPUI exposes one
NativeSurfaceHandleelement contract for platform child surfaces. - macOS creates a child
NSViewand hands the AppKit raw handle to Servo. - Windows creates a child
HWNDand hands the Win32 raw handle to Servo. - Linux/X11 creates a child XCB window and hands the XCB raw handle to Servo.
- Linux/Wayland creates a child
wl_surface/subsurface and hands the Wayland raw handle to Servo. - GPUI web page display uses native content surface presentation for every platform target.
Acceptance Gates
cargo runopens a normal web page with Servo inside the ELY app process.- Scrolling a live web page uses Servo input events and Servo repaint callbacks.
- Page display presents through a Servo rendering context.
- macOS, Windows, Linux/X11, and Linux/Wayland each have a platform child surface implementation under the same
NativeSurfaceHandlecontract. - Address/search, tabs, spaces, profiles, settings, permissions, and sync compile through existing domain APIs.
- Every new source file stays below 500 lines.
- User-facing chrome stays clean.
First Platform Surface Target
GPUI Window
-> GPUI NativeSurface element
-> platform child surface for web content bounds
-> Servo WindowRenderingContext
-> Servo WebView
This slice gives Servo a native surface in the ELY app process. The compatibility adapter remains a narrow bridge for tests and non-normal display probes.