The Storage panel expects storesUpdate messages after watched storage
changes. Summarize committed IndexedDB mutation logs into DevTools paths
and forward them through WebContent so Firefox can refresh database,
object-store, and record rows without polling.
Firefox's behaviour is less than ideal here. A lot of things don't
update automatically even inspecting a page in Firefox. Some
things (like new databases) won't show up until you fully refresh the
page. So that makes it a bit hard to know that we're doing things
correctly. As far as I can tell, we are at least behaving as well as
Firefox requires.
We do have one workaround: Firefox doesn't display record updates
without a manual refresh, and in fact any change messages for them show
up as rows in the host's database table. So for now, we filter them out
to avoid visual weirdness in the inspector.
WebContent no longer chooses between CPU and GPU display list players,
and the remaining callers always use Skia raster playback. Remove the
PageClient virtual and now-single-value enum, then play SVG image and
cursor display lists directly.
Nested navigables were represented through compositor surface ids owned
by the parent context. That forced CompositorState and ContextState to
maintain bidirectional attach/detach bookkeeping, publish child
snapshots into a surface map, and keep presentation mode variants just
to distinguish UI presentation from parent composition.
Record the child compositor context id directly in the display list and
let the compositor resolve it against the painting parent at playback
time. Child contexts now keep their parent context id and latest
rendered surface, while parents no longer track child maps or compositor
surface ids. UI presentation is represented separately from parent
composition, so closing a page only stops client presentation and nested
contexts keep using set_parent_context.
Compositor-backed canvas contexts keep their transports tied to a single
Compositor connection. When that connection dies, the 2D backing
storage and WebGL GL objects disappear with it, but WebContent does not
surface the loss to canvas contexts or create fresh host contexts after
reconnect.
Track compositor loss through the WebContent connection, mark WebGL
contexts lost, dispatch the standard context events, and rebuild the
remote proxy when the page opts into restoration. For 2D canvas, queue
the canvas context loss steps, discard the dead backing storage, and
create new storage before firing contextrestored.
Canvas rendering is a major remaining path where WebContent directly
owns GPU-facing drawing state. Back 2D and WebGL canvas contexts with
remote Compositor transports, so WebContent talks to canvas surfaces
through IPC while the Compositor owns the rasterization resources.
This is a large step toward GPU sandboxing because canvas GPU work now
lives behind the Compositor boundary. It also gives OffscreenCanvas the
process-independent canvas plumbing that HTMLCanvasElement now uses,
making worker-owned canvases possible without another WebContent-local
rendering path.
Same-document navigations now commit synchronously in WebContent, while
the UI process mirror learns about them over asynchronous IPC. A stale
UI seed could be accepted back into a live non-initial document and
overwrite its latest entry, making queued traversals target unreachable
entries.
Share descriptor comparison helpers between LibWeb and LibWebView.
Reject stale top-level seeds against the active document latest entry,
and let the UI process adopt WebContent current snapshots when a seed is
rejected. Test-only session history dumps now first send WebContent
current state synchronously, so dumps observe the converged state.
Allow post-load UI seeds to carry UI-owned nested histories that the
freshly loaded top-level document has not reconstructed yet. Add unit
coverage for matching those seeds while still checking top-level state.
Use the LibWebView history mirror to preserve traversable session
history across WebContent process swaps. WebContent reports snapshots to
the UI process, and new renderers can be seeded from the mirror.
Browser back and forward now resolve through the UI-owned used history
steps. WebContent still runs the spec traversal path when the current
renderer has enough matching state to do so.
Handle canceled and no-op UI navigations without leaving speculative
history entries or pending WebDriver waits behind. Preserve traversal
precheck state across synchronous IPC shutdown, and avoid overwriting a
restored target entry's persisted scroll state before the document has
adopted that entry.
Add Internals.deleteAllCookies(), backed by an async WebContent to
browser request and ack pair. CookieJar can now clear transient and
persisted cookies. Note that we only delete all cookies associated
with the current URL so that tests are able to run in parallel with
one another without impacting shared cookie state.
Firefox keeps the Storage panel current by sending store update packets
when localStorage or sessionStorage changes. Forward successful Web
Storage mutations to the storage actors and emit the matching update or
clear packet.
Use listener IDs for storage updates so the local and session storage
actors can subscribe independently.
Remove internals.loadTestVariants and the IPC forwarding that reported
variant metadata back to WebView. test-web now identifies WPT variants
during collection, so no loaded document needs to expose this test-only
hook.
UA and user stylesheets do not have owner nodes or owner rules, so their
matched rules cannot be mapped through the generic stylesheet identifier
helper. Share the built-in UA stylesheet enumeration and map UA rules by
the matched CSSStyleSheet object, so that they stay in sync with any
future changes.
Include parser rule locations and stylesheet identities in the applied
style rule data sent to DevTools. This gives the protocol layer enough
information to map matched rules to existing stylesheet resources
without guessing from displayed rule text.
Use Core::Process::terminate_immediately() when the UI process goes
away or a sync IPC request fails because the client disconnected. This
avoids running exit-time destructors during WebContent shutdown.
Enable -Wexit-time-destructors for the WebContent executable and
service target, then convert the existing warning sites to permanent
process lifetime storage.
Make navigable focus depend on whether the page client currently has
system focus. WebContent already receives focus changes from the UI
process, but LibWeb did not consult that state when deciding whether the
top-level traversable was focused.
Repaint the text caret when WebContent focus changes so a focused text
control stops showing an active caret as soon as browser chrome takes
focus, and resets the blink cycle when page focus returns.
Grid and flex inspector payloads are only consumed by DevTools, but
layout currently builds them for every page. Gate that collection on an
active DevTools client so ordinary browsing avoids the extra CPU work
and retained memory.
DevTools may connect after the page has already completed layout, so
force one catch-up layout pass when the first DevTools client attaches.
After that, normal relayouts keep the data fresh until DevTools
disconnects. Inspection requests only flush dirty layout instead of
forcing repeated collection passes.
When DevTools detaches, clear the stored inspection data and overlays.
Page IDs were allocated independently by each WebContent PageHost,
starting at zero for every process. That made them unsuitable as a
global identity for page-presenting compositor contexts, because the
same numeric page ID could exist in multiple WebContent processes.
Move page ID allocation to WebView::Application and initialize each
WebContent process with its browser-assigned first page ID over IPC.
New view requests now get a browser-assigned page ID before
WebContent creates the PageClient, and PageHost no longer owns a
local page counter.
This gives page-presenting compositor contexts a stable global page
identity, which will allow their context IDs to be derived from page
IDs and simplify compositor context allocation in a follow-up.
When an HTTPS response carries a Strict-Transport-Security header, the
received policy is now respected. Subsequent HTTP requests to a known
HSTS host are upgraded to HTTPS before the fetch algorithm makes
further decisions such as CORS and mixed content.
Fixes tpexpress.co.uk, where an XHR redirects HTTPS -> HTTP -> HTTPS,
relying on a HSTS policy received on the document response to avoid the
CORS failure.
Commit 218d82cb65 added support for
pasting text with the middle mouse button. But primary pasting is
actually meant to interact with the "selection" clipboard, not the
text clipboard.
The WebContent compositor server exposed stop_presenting_to_client()
next to destroy_context(), even though only the latter controls context
lifetime. The former moved a live top-level context out of the client-
facing presentation path, making the IPC boundary look like it had two
ways to tear down a live compositor context.
Make client presentation an explicit PresentationMode alternative.
Top-level contexts start as PresentToClient. Tab close switches them to
Empty, while destroy_context() remains the only API that removes
compositor state. This keeps the existing lifetime behavior while
routing all presentation target changes through set_presentation_mode().
Snapshot DevTools DOM mutation payloads immediately, but defer subtree
serialization until the target document's layout is up to date.
This avoids re-entering layout-backed DOM serialization from style and
layout updates, which could crash WebContent while DevTools was
listening for mutations.
This lays the groundwork to allow shared workers, nested workers (i.e.
workers owned by workers) and service workers to function independently
of WebContent.
Track whether WebContent still needs a beforeunload check and let the
frontends immediately remove a tab or window when no prompt can be
shown. WebContent still receives the close request so pagehide, unload,
and cleanup steps can run.
When the visible view is removed immediately, keep detached ownership of
the WebContent page until it reports that the top-level traversable
closed. If no acknowledgement arrives, release detached ownership and
ask ProcessManager to shut down the unused WebContent process.
Refresh Qt chrome palettes from the current color scheme when the
application palette changes. Recompute autocomplete and location field
colors and repaint WebContent immediately so theme changes do not
require another interaction or restart.
Notify the UI process with the solid canvas background color recorded
for the top-level document. This is the Canvas system color with the
effective document background composited over it, matching the color
used before normal painting.
Store that color on the view and use it when AppKit, Qt, and Gtk need
to fill areas exposed while an older bitmap is still on screen during a
window resize.
The browser previously treated the out-of-process Compositor as fatal.
Restart the shared Compositor from the browser process, reconnect
process-backed WebContent clients, recreate compositor contexts, restore
viewport state, and ask WebContent to repaint and republish canvas and
media resources. WebContent now marks its compositor connection lost,
returns conservative values for synchronous compositor queries while
reconnecting, and drops outgoing updates until the replacement transport
arrives.
Synchronous input queries through the compositor control connection now
use fallible IPC. If the Compositor exits after the open check or before
the sync reply arrives, scroll and mouse handling report that the
Compositor did not handle the event and let the normal WebContent
fallback run.
Mouse events queued while the Compositor is unavailable now fall back to
direct WebContent dispatch. This keeps input completion in step with the
pending-event queue.
Recovery is capped at three automatic restarts. If the restart limit is
exceeded, if restart, reconnect, or context recreation fails, or if the
replacement Compositor exits during active recovery, the browser crashes
instead of switching process-backed views to a fallback path.
The helper process is a Browser-owned singleton, so Browser has to be
the source of truth for which contexts exist: it is the only party that
can register them with the helper, route backing-store and presentation
upcalls back to the right WebContent and page, and reap them when a
WebContent crashes. Move id allocation into Browser and have WebContent
ask for ids over IPC, so the runtime switch in the next commit only has
to select the backend. Behavior is preserved because Browser reproduces
the previous deterministic-vs-fresh allocation logic and the in-process
compositor still owns rendering.
LibWeb still exposed the concrete CompositorThread to Page,
Navigable, and EventHandler, so compositor IPC would have leaked the
thread implementation into callers. The old thread APIs also bundled
page presentation callbacks and main-thread wakeups into the same
object, which made it awkward for WebContent to put an actor boundary
in between.
Introduce CompositorHost and context handles as the caller-facing API,
and move shared compositor protocol values out of CompositorThread. Add
WebContentCompositor IPC endpoints and route PageHost through a paired
in-process transport. The actor owns CompositorThread with explicit
main-thread and UI presentation clients, while screenshot completion is
serialized on the WebContent event loop using request IDs.
The intention for introducing IPC here is to prepare for moving the
compositor thread into a separate process.
Move compositor-thread ownership to WebContent's PageHost so every Page
object in one WebContent process registers its navigables on the same
compositor thread. This covers auxiliary pages created by window.open(),
while worker and SVG helper pages continue to skip compositor thread
creation.
Keep page presentation keyed by page id. Each presenting context records
the page id it presents for, and static compositor entry points route
ready-to-paint, async scrolling, and viewport scrollbar events to that
page's presenting context on the shared thread.
Use the snapshot from the previous commit to let CompositorThread apply
experimental viewport wheel deltas when async scrolling is enabled. The
event handler first performs synchronous admission on the main thread,
then enqueues a compositor scroll command instead of mutating live
document scroll state directly.
Rasterize accepted scrolls through the same compositor presentation
path added earlier. The compositor stores the newest async viewport
offset so the next main-thread display-list recording can adopt it
before repainting, preventing older paints from snapping the visible
position backward.
Keep DOM wheel dispatch on the main thread. When the compositor already
performed the default action, dispatch the wheel as non-cancelable and
suppress a second default scroll. Non-viewport targets, nested
scrollers, and pages with blocking wheel listeners stay synchronous.
Introduce a dedicated Compositor IPC channel between the UI process and
WebContent. Use it for backing-store setup, presented bitmap delivery,
and bitmap-specific ready_to_paint acknowledgements.
This makes CompositorThread the single owner of frame presentation
bookkeeping before async scrolling starts producing frames without the
main thread.
Remove old paint and backing-store messages from WebContentClient and
PageClient so the UI process no longer observes two presentation
protocols.
Previously a fixed-rate paint refresh timer kept queueing rendering
update tasks at the maximum configured frame rate, regardless of whether
anything had actually changed. This wasted CPU on idle pages, which
spend most of their time in a steady state where no style, layout, or
paint work is needed.
Replace the repeating timer with a single-shot frame timer driven by
PageClient::request_frame(). A rendering update is now scheduled only
when something requires one. The configured maximum frame rate is
preserved as a ceiling on how closely consecutive frames can follow each
other.
Route BroadcastChannel messages over IPC so matching channels can
receive them across WebContent and WebWorker processes, rather than only
within a single process.
Each channel now serializes its payload, sends it upward over IPC, and
receiving processes deliver it locally after matching by storage key and
channel name.
Generalize the backing store sharing abstraction into SharedImage, which
represents shared GPU memory independently of Skia and can be used to
share memory between different processes or different GPU contexts.
Now that LibIPC uses Mach ports for transport on macOS, IOSurface port
rights can be sent as regular IPC message attachments instead of through
a separate ad-hoc Mach message side-channel. Introduce
Web::SharedBackingStore that wraps either a MachPort (macOS) or
ShareableBitmap (other platforms) with IPC encode/decode support,
unifying backing store allocation into the existing
did_allocate_backing_stores IPC message.
Registering multiple Mach port names with the bootstrap server at
runtime is not how macOS expects it to be used — the bootstrap server
is meant for static services, and the only reason we used it originally
was so child processes could reach back to the UI process.
Remove bootstrap_transport_over_socket(), which had both sides register
dynamic names with the bootstrap server and exchange them over a socket.
Instead, WebDriver and BrowserProcess connections now go through
MachPortServer instances directly. When a non-child process contacts a
MachPortServer, the server creates a port pair on demand (detected via
sysctl ppid check) and returns the local half immediately. This keeps
bootstrap server usage limited to the one original case: child processes
looking up their parent's MachPortServer.
WebDriver Session now runs its own MachPortServer per session.
--webdriver-content-path becomes --webdriver-mach-server-name on macOS.
Spare WebContent launches are skipped when a WebDriver session is active
to avoid bootstrap races.
Instead of passing RequestServer and ImageDecoder socket FDs as
command-line arguments to WebWorker, send them over the main IPC channel
after launch. The worker-agent handoff now carries all three transport
handles (worker, RequestServer, ImageDecoder) so the connection path
matches WebContent.
Add IPC::TransportHandle as an abstraction for passing IPC
transports through .ipc messages. This replaces IPC::File at
all sites where a transport (not a generic file) is being
transferred between processes.
TransportHandle provides from_transport(),
clone_from_transport(), and create_transport() methods that
encapsulate the fd-to-socket-to-transport conversion in one
place. This is preparatory work for Mach port support on
macOS -- when that lands, only TransportHandle's internals
need to change while all .ipc definitions and call sites
remain untouched.
Stop converting between CSS and device pixels as part of rendering - the
display list should be as simple as possible, so convert to DevicePixels
once when constructing the display list.
These IPC methods should be expanded in the future to allow WebContent
to specify what UI elements should be kept/removed, for example, the
navigation UI.
The set_viewport_size and set_device_pixel_ratio IPC messages were sent
separately, potentially causing a race condition when the DPR changes
(e.g. moving a window between screens): the DPR message would arrive
and use a stale viewport size, computing a temporarily wrong CSS
viewport. Combine both into a single set_viewport IPC that updates the
device viewport size and DPR together.
We were effectively copying the logic from .set_viewport_size() into
PageClient, but we forgot to actually update the viewport size on device
pixel ratio changes.
Remove 11 heavy includes from Document.h that were only needed for
pointer/reference types (already forward-declared in Forward.h), and
extract the nested ViewportClient interface to a standalone header.
This reduces Document.h's recompilation cascade from ~1228 files to
~717 files (42% reduction). Headers like BrowsingContext.h that were
previously transitively included see even larger improvements (from
~1228 down to ~73 dependents).
Move the inline dom_node() method to Viewport.cpp so the header no
longer needs the full Document definition. Add explicit includes to
files that relied on the transitive dependency.
If our UI informed the page of a DPI change, we would store the new
device pixel ratio and leave it at that. It would take a layout/style
update (e.g. by clicking the page) to actually render the page using the
new DPI. This is very visible on macOS when moving the Ladybird window
from a 1x resolution monitor to a HiDPI 2x monitor.
We now instantly update the backing stores and mark media queries for
reevaluation. Moving the Ladybird window on macOS now immediately
updates the page when dragging it to a HiDPI monitor.