XUL/XBL Replacement Newsletter 12

This is the twelfth edition of the XUL/XBL Replacement Newsletter. Since the last edition, we’ve Custom-Element’ified XUL trees, removed a complex XBL platform feature, and removed a bunch of bindings.

XUL trees no longer use XBL

XUL <tree> elements are used for rendering important parts of Firefox, like the Places UI. They are implemented partly in C++ and partly in JS. Though similar functionality and performance can now be achieved in JS alone, the full migration away from this element is a big project that relies on a number of moving parts. Victor Porof has put together a more detailed document outlining the state of things here.

Because of this, we decided it would be helpful to migrate the JS portion of XUL trees out of XBL and into Custom Elements to unblock the XBL removal project. This was after already having removed bindings for child elements over the last few months (including tree-base, treecols, treecol-base, treecol, treecol-image, columnpicker, treerows, and treebody).

One challenge with this element was that it was using XBL <children /> slotting that was hard to work around with light DOM alone. We’d tried to use Shadow DOM on other XBL migrations in the past, but struggled to make it work because we can’t nest a XBL element with <children /> inside of a Shadow DOM <slot />. This means we can only use Shadow DOM if we know there’s never XBL slotted into the element, which is hard to guarantee in the general case. Luckily, <tree>has a templated structure, we’ve de-XBL’ed its children, and instrumented the code at runtime to ensure no unsupported elements are inserted. So this means that <tree> is the now first consumer of Shadow DOM in our chrome Custom Elements.

The migrated source can be seen in the MozTree class in tree.js and the MozPlacesTree class in places-tree.js.

Removing the ability to override the node name in XBL

XBL had a feature which allowed a binding to override the node name of an element. For example, if there was a <tab> element that had <binding display="xul:button"> attached to it, then the element would pretend to be a <button>.This was done by adding the [display="xul:element"] attribute, and also the [extends="xul:element"] syntax which (confusingly) did mostly the same thing.

This feature didn’t have an equivalent in the Web platform, was applied inconsistently inside Gecko, and wasn’t well understood. So Emilio Cobos Álvarez filed bug 1450652 to track the work required to remove it.

Over time, we’ve either removed the bindings using this feature or removed the need for it within the binding. Usually this meant wiring up the proper CSS frame based on the real node name rather than the one defined in XBL, but there were lots of small mysteries to figure out for individual bindings along the way. Last week, Emilio removed the final consumer and also removed the platform implementation.

Binding Removals

There are 55 bindings left, compared to 78 from the last update and 300 from the start of the project. Here’s a list of changes:

XUL/XBL Replacement Newsletter 11

This is the eleventh edition of the XUL/XBL Replacement Newsletter. We’ve continued to make consistent progress removing XBL bindings, and are aiming to get down to 62 bindings by the end of Q1. That will put us on track for the last bindings being removed around Q3.

In-content XBL is gone

As announced in newsletter #8, we created a system called UA Widgets to replace instances of running XBL in the content process. Then as announced in newsletter #10, the final in-content binding was removed and the feature was turned off by default. I’m happy to announce now that in-content XBL has been entirely removed from mozilla-central and the metabug has been closed.

This will allow us to improve the security and performance of content processes in Firefox. Here are some known areas to investigate:

  • Make element JS reflection simpler in the content process since we don’t need to check if they have XBL attached.
  • Rip out all the XBL scope, bindToUntrustedContent, and exposeToUntrustedContent machinery.
  • Disable XBL handling for Stylo in the content process.

If you know of other areas that can be simplified or want to take on some of this work, then please let me know or file a bug depending on the metabug so we can track it.

<browser> is now a Custom Element

The <browser> element is used for rendering the actual web content inside a tab, so it’s quite a complex and important element. After the tabbrowser and videoControls bindings were removed last year, this was the largest remaining binding at around 2000 LOC.

It took a lot of debugging, but after merging together the remote-browser and browser bindings, the converter tool gave a good starting point to get it done. Thanks to Mike Conley for having fun with the review and Neil Deakin for making QueryInterface work properly for this use case. More details can be seen in the bug and in the post to firefox-dev.

This opens up the ability to start looking into creating a build with XBL disabled, since this was the last element in Android using XBL.

Removing some uses of XUL grid layout

Tim Nguyen noticed that within the Firefox UI we have a relatively small number of consumers using XUL grid layout (most often seen as the <grid>, <columns>, <column>, <rows>, and <row> elements). He filed a metabug to track removing them. Long term, doing this will help us migrate our UI to web-exposed layout algorithms, and remove the XUL-specific grid implementation.

After converting a number of them that don’t actually need to be grids to flexbox, the next step was looking into our options for using either CSS grids or CSS table layout for the remainder. It appears that these will have to be put on hold until we ship the XUL flexbox -> CSS flexbox emulation feature, since XUL flexbox children don’t always play nicely inside of non-XUL layouts.

Binding Removals

There are 78 bindings left, compared to 94 from the last update and 300 from the start of the project. Here’s a list of changes:

XUL/XBL Replacement Newsletter 10

This is the tenth edition of the XUL/XBL Replacement Newsletter. Since the last edition, we’ve stopped relying on two major components of the XBL implementation: “in-content” XBL and XBL stylesheets.

Final In-Content XBL Bindings Removed

After recently landing UA Widget alternatives for <marquee>, “plugin problem” UI, and the date / time picker, we don’t need to rely on XBL in the content process anymore. This will allow us to improve the security and performance of the content process in Firefox.

It also makes the widgets themselves simpler, since they’re implemented with more well-known technologies like frame scripts, JS classes, and Shadow DOM (see the in-tree UA Widget docs for more information). There’s DevTools support as well - if you run this command you can see the UA Shadow DOM and <slot> in the Inspector panel:

./mach run 'data:text/html,<marquee>slotted child</marquee>' --devtools --temp-profile --setpref devtools.inspector.showUserAgentShadowRoots=true

The next steps are to enable the UA widget pref by default in release, and then to remove the pref and start tearing out platform support. Barring any unforeseen issues, we expect to enable the pref by default in Firefox 65, and then start removing the feature in a subsequent release.

I’d like to again thank Tim Guan-tin Chien for leading this work, and to the many others who’ve been involved with planning, reviews, and patches. If you have a look at the metabug and graph tracking the number of bindings, you can see the amount of work involved. It took us on a tour of the DOM via scrollbars, video controls (on desktop and android), input fields (filepickers and datepickers), and even to unexpected places like the little resizer thing inside textareas, XML pretty printing and key handling inside input fields.

Final XBL Stylesheets Migrated to Document Sheets

Back in June, Paolo Amadini announced that we were starting the process of migrating our XBL scoped stylesheets to be standard document-level author sheets. This would allow us to remove an extra unspecified CSS cascade level in the style engine, and make it easier for frontend developers to figure out which rule takes precedence over others based only on the specificity.

This work was broken down into individual bugs per stylesheet to make it easier to track regressions. Paolo, Dão Gottwald, and Tim Nguyen have been pushing this forward over the months. Recently, Dão took this over the finish line by converting some of the more tricky sheets (textbox.css, button.css, and toolbarbutton.css). All of the XBL stylesheets in chrome have now either been removed or ported into widgets.css.

We still have some leftovers to take care of before platform support can be removed (including deleting the preffed off in-content bindings as discussed above), but when we remove support it’ll be a significant simplification.

Customizable UI Bindings Removed

It used to be the case that the “Customizable UI” feature, along with many of the toolbars used in the primary browser chrome, required XBL to implement their behavior. Gijs Kruitbosch did a detailed breakdown of the work required to remove this dependency. Most of the bindings were able to be converted into plain JS instead of being attached to DOM nodes. In addition to helping burn down the number of bindings in the browser/ directory, this will give us more control over when to initialize different components during browser startup.

Binding Removals

There are 94 bindings left, compared to 115 from the last update and 300 from the start of the project. Here’s a list of changes:

XUL/XBL Replacement Newsletter 9

This is the ninth edition of the XUL/XBL Replacement Newsletter. Since the last update we’ve continued to remove “in-content” bindings, started using native Custom Elements in more chrome UI, and shipped a new top-level HTML window.

Common Keybindings No Longer Use XBL

It used to be the case that we used XBL to handle certain keyboard shortcuts for elements like <input> and <textarea>, and for chrome-specific elements like <editor> and <browser>. For example, when you press ctrl+c in an input field an XBL handler would be triggered to copy selected text to the clipboard, or when you press down in a browser it would scroll the page down. Mossop and Masayuki Nakano took on the task of decoupling this key handling from XBL.

This led to a bunch of goodness. In the process of doing this, they:

  • Added missing test coverage for these features.
  • Simplified how the whole system works by moving the handlers for the keyboard shortcuts closer to the native keyboard shortcut handlers.
  • Saved 48K of memory overhead per content process.
  • Removed 20(!) XBL bindings, many of which were “in-content” - attached to elements and running scripts in the content process.

<input type=file> no longer uses XUL

Previously, we used a XUL label to render the filename inside of an HTML file input. This worked, but it meant that we were using XBL and XUL layout in the web page. We worked with UX to see if we could directly replace the XUL label with an HTML label, but ultimately decided that the “middle crop” feature provided by XUL labels was too important to lose when previewing file names. Thankfully, Mats Palmgren stepped in and implemented that feature using an HTML label in the file input, which also fixed some cropping bugs and improved support for mixed direction text in filenames.

Custom Elements in the Payment Request Dialog

Since the Payment Request dialog is fairly independent of the rest of the Firefox UI, it was developed from the beginning to not use XUL/XBL. Instead, it’s primarily written with unprivileged HTML using Custom Elements. The third-party polyfill that was initially used before Gecko’s Custom Element implementation was stable was removed two weeks ago, so the UI no longer has any external dependencies. It uses Custom Element mixins and an ES module to manage application state and allow for a reactive rendering model (source code). We’ll be looking out ways to share some of these patterns with other Custom Elements in chrome going forward.

Browser Toolbox Window As HTML

The Browser Toolbox is set up as a separate Firefox process that passes in the --chrome parameter to override the default window that opens when Firefox starts up. This used to be a XUL window, but Honza Odvarko recently updated it so that the chrome window is HTML (toolbox-process-window.html). This also gave us a chance to remove some unused code and simplify how we wire up commands in that window. Notably, it’s now the case that we don’t render any top-level XUL windows in the Browser Toolbox process.

After this, Jason Laster wrote a post explaining how to open the Browser Toolbox using a Nightly binary to debug broken DevTools in a local build, updated with the new URL.

Binding Removals

There are 115 bindings left, compared to 153 from the last update and 300 from the start of the project. Here’s a list of changes:

XUL/XBL Replacement Newsletter 8

This is the eighth edition of the XUL/XBL Replacement Newsletter. Since the last update there’ve been steps towards removing in-content XBL, flexbox performance improvements, and new chrome Custom Element capabilities.

In Content XBL → UA Widgets

We have been using XBL inside web content for a long time for rendering UI like scrollbars. But there are even more complex situations where we use XBL to insert DOM and run JS inside the content document. For example, with <video controls> or <input type="date">.

Tim Guan-tin Chien has been busy working on an alternative to this setup. Now that bug 1484048 has landed, the video controls are working entirely without XBL in nightly builds. Instead, we are using Shadow DOM and JS running inside of a sandbox. The setup is coined “UA Widgets” - you can read more about the design in bug 1431255.

This setup is pretty complex, mostly because of the level of encapsulation needed. The web content must not be able to probe into the DOM inserted, nor interact with the JS directly. The sandboxes are created per-origin as an extra layer of security to ensure isolation among different origins in the same content process.

Now that the first binding is done and the framework is in place, Tim is setting his sights on the rest. There aren’t too many in-content bindings left after this. The most complex ones are the date and time pickers, the marquee tag, and the “click to play” plugin UI. Once we remove the last one that’ll let us remove the in-content XBL implementation which we expect will provide performance, security, and code simplification benefits.

Flexbox performance improvements

One of the main aspects of the UI that we’d like to migrate away from XUL and towards web standards is flexbox. One reason this is important is that it’ll make it easier to use HTML elements in the browser chrome. But the main thing I wanted to talk about here is that it creates a need to greatly improve the performance of CSS flexbox.

Flexbox perf issues affect web content in Firefox - for example Twitter DMs, WhatsApp, and number of other sites. And as Neil noticed in 2015, switching the browser chrome to use CSS flexbox causes large perf regressions. To track this, we added a pref to enable CSS flexbox in the browser chrome which lets us measure the difference between XUL and CSS flexbox with Talos.

In order to improve performance in both these environments (web content, and chrome with CSS flex layout), the layout team has prioritized optimizing flexbox during the second half of this year. Daniel Holbert landed the first major piece of this effort recently in Bug 1490890. This had a massive impact on some DevTools panels that are already using CSS flex, especially the webconsole. As Nicolas Chevobbe noted, one console test case where characters get typed into the input field sped up from ~800ms to ~100ms.

It’s still TBD when it’ll get fast enough to lay out the browser chrome, but each step in that direction will make websites using flexbox faster in Firefox. Keep an eye on the main flexbox performance metabug if you want to follow along.

XPCOM support for (chrome) Custom Elements

XBL has a way to wire up XPCOM interfaces with DOM elements. You may have seen this before inside of XBL bindings - for example the browser binding uses implements="nsIObserver, nsIBrowser". This lets the XBL binding provide the implementation for functions on that interface, and lets other code QueryInterface to that interface using the element.

This feature is (obviously) not part of the specification for Custom Elements. But if you look closely at our tree of XBL bindings, you can see that a bunch of them inherit from basecontrol which relies on this feature. That means we’ve been blocked off from migrating most of those bindings to Custom Elements.

We are unblocking this on two fronts:

  1. Adding XPCOM support to chrome Custom Elements. This is done - Neil Deakin landed this feature in bugs 1461742 and 1478372.
  2. Remove individual interfaces when possible. Alex Surkov recently removed nsIDOMXULLabelElement, nsIDOMXULLabeledControlElement, and nsIDOMXULCheckboxElement, for example. This also has some overlap with the work bz did to remove nsIDOMElement and nsIDOMNode a few months back, and we’re hoping to do more of this when it makes sense.

Binding Removals

There are 153 bindings left, compared to 161 from the last update and 300 from the start of the project. Here’s a list of changes: