This month in Servo: variable fonts, network tools, SVG, and more!

Servo’s biggest month by far, with everything from IndexedDB improvements to favicons in servoshell.

Posted 2025-09-25

Another month, another record number of pull requests merged! August flew by, and with it came 447 pull requests from Servo contributors. It was also the final month of our Outreachy cohort; you can read Jerens’ and Uthman’s blogs to learn about how it went!

Highlights

Our big new feature this month is rendering inline SVG elements (@mukilan, @Loirooriol, #38188, #38603). This improves the appearance of many popular websites.

Screenshot of servoshell with the Google homepage loaded
Did you know that the Google logo is an SVG element?

We have implemented named grid line lines and areas (@nicoburns, @loirooriol, #38306, #38574, #38493), still gated behind the layout_grid_enabled preference (#38306, #38574).

Screenshot of servoshell loading a page demoing a complex grid layout
CSS grids are all around us.

Servo now supports CSS ‘font-variation-settings’ on all main desktop platforms (@simonwuelker, @mrobinson, #38642, #38760, #38831). This feature is currently gated behind the layout_variable_fonts_enabled preference. We also respect format(*-variations) inside @font-face rules (@mrobinson, #38832). Additionally, Servo now reads data from OpenType Collection (.ttc) system font files on macOS (@nicoburns, #38753), and uses Helvetica for the ‘system-ui’ font (@dpogue, #39001).

servoshell nightly showcasing variable fonts, with variable weight (`wght`) values smoothly increasing and decreasing (click to pause)
This font can be customized!

Our developer tools continue to make progress! We now have a functional network monitor panel (@uthmaniv, @jdm, #38216, #38601, #38625), and our JS debugger can show potential breakpoints (@delan, @atbrakhi, #38331, #38363, #38333, #38551, #38550, #38334, #38624, #38826, #38797). Additionally, the layout inspector now dims nodes that are not displayed (@simonwuelker, #38575).

servoshell showing the Servo Mastodon account homepage The Firefox network monitor, showing a list of network connections for the Servo Mastodon account homepage
That's a lot of network requests.

We’ve fixed a significant source of crashes in the engine: hit testing using outdated display lists (issue #37932). Hit testing in a web rendering engine is the process that determines which element(s) the user’s mouse is hovering over.

Previously, this process ran inside of WebRender, which receives a display list representing what should be rendered for a particular page. WebRender runs on a separate thread or process from the actual page content, so display lists are updated asynchronously. By the time we do a hit test, the elements reported may not exist anymore, so we could trigger crashes by (for example) moving the mouse quickly over parts of the page that were rapidly changing.

This was fixed by making the hit test operation synchronous and moving it into the same thread as the actual content being tested against, eliminating the possibility of outdated results (@mrobinson, @Loirooriol, @kongbai1996, @yezhizhen, #38480, #38464, #38463, #38884, #38518).

Web platform support

DOM & JS

We’ve upgraded to SpiderMonkey v140 (changelog) (@jdm, #37077, #38563).

Numerous pieces of the Trusted Types API are now present in Servo (@TimvdLippe, @jdm, #38595, #37834, #38700, #38736, #38718, #38784, #38871, #8623, #38874, #38872, #38886), all gated behind the dom_trusted_types_enabled preference.

The IndexedDB implementation (gated behind dom_indexeddb_enabled) is progressing quickly (@arihant2math, @jdm, @rodion, @kkoyung, #28744, #38737, #38836, #38813, #38819, #38115, #38944, #38740, #38891, #38723, #38850, #38735), now reporting errors via IDBRequest interface and supporting autoincrement keys.

A prototype implementation of the CookieStore API is now implemented and gated by the dom_cookiestore_enabled preference (@sebsebmc, #37968, #38876).

Servo now passes over 99.6% of the CSS geometry test suite, thanks to an implementation of matrixTransform() on DOMPointReadOnly, making all geometry interfaces serializable, and adding the SVGMatrix and SVGPoint aliases (@lumiscosity, #38801, #38828, #38810).

You can now use the TextEncoderStream API (@minghuaw, #38466). Streams that are piped now correctly pass through undefined values, too (@gterzian, #38470). We also fixed a crash in the result of pipeTo() on ReadableStream (@gterzian, #38385).

We’ve implemented getModifierState() on MouseEvent (@PotatoCP, #38535), and made a number of changes involving DOM events: ‘mouseleave’ events are fired when the pointer leaves an <iframe> (@mrobinson, @Loirooriol, #38539), pasting from the clipboard into a text input triggers an ‘input’ event (@mrobinson, #37100), focus now occurs after ‘mousedown’ instead of ‘click’ (@yezhizhen, #38589), we ignore ‘mousedown’ and ‘mouseup’ events for elements that are disabled (@yezhizhen, #38671), and removing an event handler attribute like ‘onclick’ clears all relevant event listeners (@TimvdLippe, @kotx, #38734, #39011).

Servo now supports scrollIntoView() (@abdelrahman1234567, #38230), and fires a ‘scroll’ event whenever a page is scrolled (@stevennovaryo, #38321). You can now focus an element without scrolling, by passing the {preventScroll: true} option to focus() (@abdelrahman1234567, #38495).

navigator.sendBeacon() is now implemented, gated behind the dom_navigator_sendbeacon_enabled preference (@TimvdLippe, #38301). Similarly, the AbortSignal.abort() static method is hidden behind dom_abort_controller_enabled (@Taym95, #38746).

The HTMLDocument interface now exists as a property on the Window object (@leo030303, #38433). Meanwhile, the CSS window property is now a WebIDL namespace (@simonwuelker, #38579). We also implemented the new QuotaExceededError interface (@rmeno12, #38507, #38720), which replaces previous usages of DOMException with the QUOTA_EXCEEDED_ERR name.

Our 2D canvas implementation now supports addPath() on Path2D (@arthmis, #37838) and the restore() methods on CanvasRenderingContext2D and OffscreenCanvas now pop all applied clipping paths (@sagudev, #38496). Additionally, we now support using web fonts in the 2D canvas (@mrobinson, #38979). Meanwhile, the performance continues to improve in the new Vello-based backends (@sagudev, #38406, #38356, #38440, #38437), with asynchronous uploading also showing improvements (@sagudev, @mrobinson, #37776).

Muting media elements with the ‘mute’ HTML attribute now works during the initial resource load (@rayguo17, @jschwe, #38462).

Modifying stylesheets now integrates better with incremental layout, in both light trees and shadow trees (@coding-joedow, #38530, #38529). Note that calling setProperty() on a readonly CSSStyleDeclaration correctly throws an exception (@simonwuelker, #38677).

CSS

We’ve upgraded to the upstream Stylo revision as of August 1, 2025.

We now support custom CSS properties with the CSS.registerProperty() method (@simonwuelker, #38682), as well as custom element states with the ‘states’ property on ElementInternals (@simonwuelker, #38564).

Flexbox cross sizes can no longer end up negative through stretching (@Loirooriol, #38521), while ‘stretch’ on flex items now stretches to the line if possible (@Loirooriol, #38526).

Overflow calculations are more accurate, now that we ignore ‘position: fixed’ children of the root element (@stevennovaryo, #38618), compute overflow for <body> separate from the viewport (@shubhamg13, #38825), check for ‘overflow: visible’ in parents and children (@shubhamg13, #38443), and propagate ‘overflow’ to the viewport correctly (@shubhamg13, @Loirooriol, #38598).

‘color’ and ‘text-decoration’ properties no longer inherit into the contents of <select> elements (@simonwuelker, #38570).

Negative outline offsets work correctly (@lumiscosity, @mrobinson, #38418).

Video elements no longer fall back to a preferred aspect ratio of 2 (@Loirooriol, #38705).

‘position: sticky’ elements are handled correctly inside CSS transforms (@mrobinson, @Loirooriol, #38391).

Performance & Stability

We fixed several panics this month, involving IntersectionObserver and missing stacking contexts (@mrobinson, #38473), unpaintable canvases and text (@gterzian, #38664), serializing ‘location’ properties on Window objects (@jdm, #38709), and navigations canceled before HTTP headers are received (@gterzian, #38739).

We also fixed a number of performance pitfalls. The document rendering loop is now throttled to 60 FPS (@mrobinson, @Loirooriol, #38431), while animated images do less work when advancing the current frame (@mrobinson, #38857). In addition, elements with CSS images will not trigger page reflow until their image data is fully available (@coding-joedow, #38916).

Finally, we made improvements to memory usage and binary size. Inline stylesheets are now deduplicated, which can have a significant impact on pages with lots of form inputs or custom elements with common styles (@coding-joedow, #38540). We also removed many unused pieces of the ICU library, saving 16MB from the final binary.

Embedding

Servo has declared a Minimum Supported Rust Version (1.85.0), and this is verified with every new pull request (@jschwe, #37152).

Evaluating JS from the embedding layer now reports an error if the evaluation failed for any reason (@rodio, #38602).

Our WebDriver implementation now passes 80% of the implementation conformance tests. This is the result of lots of work on handling user prompts (@PotatoCP, #38591), computing obscured/disabled elements while clicking (@yezhizhen, #38497, #38841, #38436, #38490, #38383), and improving window focus behaviours (@yezhizhen, #38889, #38909). We also implemented the Get Window Handles command (@longvatrong111, @yezhizhen, #38622, #38745), added support for getting element boolean attributes (@kkoyung, #38401), and added more accurate errors for a number of commands (@yezhizhen, @longvatrong111, #38620, #38357). The Element Clear command now clears <input type="file"> elements correctly (@PotatoCP, #38536), and Element Send Keys now appends to file inputs with the ‘multiple’ attribute.

servoshell

We now display favicons of each top-level page in the tab bar (@simonwuelker, #36680).

servoshell showing a diffie favicon in the tab bar

Resizing the browser window to a very small dimension no longer crashes the browser (@leo030303, #38461). Element hit testing in full screen mode now works as expected (@yezhizhen, #38328).

Various popup dialogs, such as the <select> option chooser dialog, can now be closed without choosing a value (@TimvdLippe, #38373, #38949). Additionally, the browser now responds to a popup closing without any other inputs (@lumiscosity, #39038).

Donations

Thanks again for your generous support! We are now receiving 5552 USD/month (+18.3% over July) in recurring donations.

Historically this has helped cover the cost of our speedy CI servers and Outreachy interns. Thanks to your support, we’re now setting up two new CI servers for benchmarking, and funding the work of our long-time maintainer Josh Matthews (@jdm), with a particular focus on helping more people contribute to Servo.

Keep an eye out for further CI improvements in the coming months, including ten-minute WPT builds, macOS arm64 builds, and faster pull request checks.

Servo is also on thanks.dev, and already 15 GitHub users (−7 from July) that depend on Servo are sponsoring us there. If you use Servo libraries like url, html5ever, selectors, or cssparser, signing up for thanks.dev could be a good way for you (or your employer) to give back to the community.

5552 USD/month
10000

As always, use of these funds will be decided transparently in the Technical Steering Committee. For more details, head to our Sponsorship page.

Back