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:

XUL/XBL Replacement Newsletter 7

This is the seventh edition of the XUL/XBL Replacement Newsletter. Since the last edition, we've gotten some tooling improvements, landed an experimental HTML browser window and removed a bunch of listbox code.

Web Components Support in DevTools

As you may have heard, Custom Elements and Shadow DOM are riding the train for 63. The DevTools team has also done a lot of work to make sure we have good tooling for these features.

One of these features that I'd like to mention is called "Show Custom Element definition". A badge appears next to a Custom Element in the Inspector, and when you click on that it takes you directly to your Custom Element class in the Debugger. This also works in the Browser Toolbox and can be seen on any of the Custom Elements we currently ship in the browser window. For example: search for "moz-input-box" nodes in the Inspector to try it.

This highlights some benefits to using web standard tech within the Firefox frontend. We get to use the same DevTools features that we're shipping to web devs. And (at least in my experience) Firefox devs are quite likely to give feedback and file bugs on tools, which ends up improving those same features.

Finally, I'd like to point out that coordinating the release of a complex platform feature and tooling to go with it is hard to do. It takes a lot of planning and cooperation between the the DOM and DevTools teams. Thanks to Julian Descottes, Belén Albeza, Emilio Cobos Álvarez, Jim Blandy, and many others for making this happen.

browser.xhtml

The main browser window is currently a XUL document with (mostly) XUL elements in the DOM. We'd ultimately like to support an HTML document with (mostly) HTML elements in the DOM. That's a long road, though. One milestone we hope to hit along the way is loading an HTML document with (mostly) XUL elements in the DOM.

Practically, this can be done by loading a browser.xhtml file with the same markup as browser.xul. This will allow us to audit and fix issues affecting top-level HTML windows without rewriting the browser window from scratch. And since we have a large suite of browser tests to track progress against, we can be pretty confident about what's working and what's still broken. We'll be tracking that in the top-level HTML metabug

An experimental version of this has now landed. you can try it out by adding this to your .mozconfig file: mk_add_options 'export MOZ_BROWSER_XHTML=1'. It's worth calling out some of the changes we made to set thi up, so I've split them into two groups below.

First group: burning down XULDocument.webidl so that the browser JS doesn't rely on XUL-specific APIs. This is now finished - see the webidl file when we started vs now. Here are some notable changes:

  • Migrated all calls of document.persist to Services.xulStore.persist (bug 1476030, firefox-dev post).
  • Removed document.width and document.height from XULDocument (bug 1475305).
  • Moved document.getElementsByAttribute[NS] from XULDocument to ParentNode, so it supports all chrome documents and elements (bug 1475342).
  • Moved popupNode, popupRangeParent, popupRangeOffset, and tooltipNode from XULDocument to Document (bug 1480206).
  • Removed addBroadcastListenerFor and removeBroadcastListenerFor (bug 1482170).

Second group: adapting the frontend to work while running inside of an HTML document. This is ongoing, here are some of the changes so far:

  • Added support for XUL Custom Elements inside of chrome HTML documents (bug 1480465).
  • Rewrote callers of document.createElement in browser JS to document.createXULElement to explicitly construct XUL elements even when the document namespace is HTML (bug 1479050).
  • Updated all references to "browser.xul" to `AppConstants.BROWSER_CHROME_URL, which lets us change the URL in one place (bug 1476333, firefox-dev post).
  • XUL documents drop whitespace when parsing, so we frequently refer to APIs like node.firstChild and assume it's an element. For that to work in HTML documents callers were rewritten as node.firstElementChild (bug 1479125, firefox-dev post).
  • Stopped using <broadcaster> and <observer> (which only work in XUL documents) in browser.xul (bug 1479908).

Thanks to everyone who's helped with planning, patches, and reviews so far. In particular I'd like to acknowledge Brendan Dahl and Mossop for pushing this forward.

Listbox Removal

We don't have any <listbox> elements in Firefox anymore. If that sounds surprising, like saying "we don't have any buttons in Firefox anymore", there's a distinction to be made as we still use a lot of lists in the UI.

Previously, there were two main widgets to choose from when rendering a list in chrome: <listbox> and <richlistbox>. Richlistbox is more powerful and more "webby", and over the course of time most of the UI was updated to use it. Listbox relied on custom layout code to guarantee that the height of a list was a multiple of the height of a row, and handle scrolling differently. This can be useful, but it just wasn't required for the remaining consumers.

Since only a few <listbox> elements were left, it was a pretty easy decision to remove it and unify on a single list widget. Being able to support just richlistbox lets us focus effort on it and makes it easier to decide what to use when adding new UI. It also allowed us to delete around 3K lines of platform code and 2K lines of frontend code.

Finally, it's worth mentioning that the <tree> element is implemented similarly to <listbox>, but with more features. This element is on our radar for replacement in the coming year, but it will be more work because we have many instances of trees in Firefox and those UIs are more complex and performance sensitive than listboxes.

Binding Removals

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