XUL/XBL Replacement Newsletter 15

This is the fifteenth edition of the XUL/XBL Replacement Newsletter. Since the last edition we’ve been working to incorporate more web standard code into the browser frontend, and converted some particularly complex XBL bindings to Custom Elements.

CSS Shadow Parts

With XBL, direct descendant CSS selectors are able to traverse the anonymous content boundary. For instance, if dropmarker has some anonymous content like: <content><image class="dropmarker-icon" /></content>, then the icon could be selected from a document stylesheet with: dropmarker > .dropmarker-icon. This is handy and we’ve relied on it all over the place, but can be confusing: it’s not always clear when reading the CSS if you are working with anonymous or explicit content. Also, it’s unsound in the presence of dynamic changes to the DOM, and fixing that in the style engine would be very complicated.

Previously, we didn’t have a way to do this with Shadow DOM. Because of that, we would often convert bindings to use explicit DOM children instead of Shadow DOM (using appendChild etc in the connectedCallback) so that we could continue to style contents from our stylesheets. The CSS Shadow Parts specification aims to close this gap. With Shadow Parts you can expose an element in the Shadow DOM like: <image part="icon"> and then target it from CSS with syntax like: host-element::part(icon).

Emilio Cobos Álvarez has added partial support for this feature in bug 1505489, and we recently started using it in our first chrome Custom Element. Here’s the changeset that shows what that consumer looks like. We are planning to keep working with it in order to provide usage feedback to the standards process, and also to convert XBL bindings that need to use Shadow DOM and are also extensively styled from document sheets (like arrow panels).

Box object removal

XUL box objects were helper objects used to implement some layout features that could be tailored to the specific layout used by an element. Replacements for box object properties are generally available as web standard properties like getBoundingClientRect, screenX, and screenY.

Neil Deakin has now completely removed this feature. Frontend code was migrated to use the standard properties when possible. For cases where there is no standard property, the functionality has been moved to specific XUL element subclasses.

Binding Removals

There are 25 bindings left, compared to 33 from the last update and 300 from the start of the project. We also have a bug on file for every remaining XBL binding and are looking forward to a big drop after the upcoming merge to 70, once the old about:addons and old awesomebar code gets removed.

Here’s a list of changes since the last update:

XUL/XBL Replacement Newsletter 14

This is the fourteenth edition of the XUL/XBL Replacement Newsletter. Since the last edition, we’ve shipped browser.xhtml, started the process of removing the rest of the XUL documents in the tree, and continued to remove more XBL bindings.

Shipping browser.xhtml

As of this week the main browser window is no longer a XUL document. Also, the hidden XUL window (which is used on mac to provide menus when no browser window is visible) has been converted to XHTML. You (hopefully) didn’t notice this change in the UI but it’s the culmination of a lot of work, most notably by Brendan Dahl.

After we got the tree pretty much green with browser.xhtml (~75 bugs tracked mostly on the top-level html metabug and also detailed in newsletter #7), we began a performance investigation. We would have liked to have been able to load the browser window through the regular web-exposed HTML loading path, but investigation showed that getting to first paint in XHTML was slower than in XUL. Specifically, Talos performance tests showed regressions in tests that timed opening new browser windows or restoring the browser on startup.

The main reasons were that in XUL (1) we skip the XML parser in the “warm” startup case which Talos covers, and (2) we begin layout later, after the DOM is ready. We tried a bunch of workarounds for these. For example: making the document nearly empty and importing a shared fragment from JS, preventing early layout by hiding elements or suppressing it from Gecko, changing when various events fire in the document lifecycle. We would see incremental improvements with each approach, but nothing that reached the goal of parity with current performance, which is sensitive to even minor changes in the window opening time.

At the end of the investigation, we had learned enough about the internals here that it seemed viable to expand prototype cache support to XHTML documents as well. So the implementation was moved out of XULDocument and into PrototypeDocumentParser and PrototypeDocumentContentSink. Thanks a lot to Smaug for the guidance and reviews in this process.

I still hold out hope that someday the normal loading path with a bit of tuning will be fast enough for our use-cases, but in the meantime this approach has a few nice benefits:

  • The faster path is now enabled automatically for any chrome:// XHTML document.
  • It nearly emptied out what was left of the XULDocument implementation, which sets the stage for the rest of the XUL document burndown project - more on that below.
  • We could expand support to other chrome document types if we’d like (for instance, SVG).

What’s next? We are planning to migrate the root <xul:window> element to <html>, which will make the Browser Toolbox highlighters work like they do for web content. We’ll also rename the file in tree from browser.xul to browser.xhtml: we were waiting to make sure it stuck before doing any file moves since that can break in-flight patches.

XUL document burndown

We are also starting on a plan to remove all XUL documents from mozilla-central. Based on feedback from a dev-platform post outlining the plan, we are going to adjust it to not focus as much on converting straight to .html and aim for .xhtml for most documents. See the post for more details but from a high level this looks like:

  1. Load all XUL documents as XHTML using the prototype cache. This doesn’t require any file renaming, we will just detect a .xul file and act like it’s .xhtml. This is tracked in Bug 1550801
  2. Delete the XULDocument implementation.
  3. For most files, rename .xul->.xhtml. In this case everything should work identically with the file name changed since it’s already being loaded as such with (1). The main extra task here is to update bug, code, and comments referencing the old file name
  4. For the now-xhtml documents apply cleanups when appropriate. For instance, migrate <xul:window>-><html>, convert ProcessingInstruction stylesheets to <link>, etc. We’d like to automate this as much as possible since there are over 1500 xul documents in the tree.

This work is being tracked in the following metabug.

Binding Removals

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

XUL/XBL Replacement Newsletter 13

This is the thirteenth edition of the XUL/XBL Replacement Newsletter. Since the last edition, we’ve gotten close to shipping the main browser window as an HTML document, made some platform improvements related to ongoing frontend work, and continued to remove XBL bindings.

Progress towards browser.xhtml

We’ve gotten close to shipping the main browser window as XHTML instead of XUL. In addition to the broader top-level HTML support which is now complete, we filed a new metabug specifically for shipping browser.xhtml.

The biggest piece of work here was Brendan Dahl adding prototype cache support to XHTML documents. With this change we are seeing equivalent performance between browser.xul and browser.xhtml.

As part of that project, he also added <html:template> support to documents loaded with the prototype cache. This is a nice change to bring our chrome UI more in line with the Web platform and gives us a more standard way to lazify DOM creation (there’s a metabug to do so).

The final steps before enabling browser.xhtml are fixing some assertions (1, 2) that surfaced due to nsHTMLDocument being a DOM proxy and XULDocument not being a proxy. Once those are resolved we plan to flip the switch to enable browser.xhtml by default.

Platform improvements

I wanted to mention some platform improvements and code removal related to these projects, and acknowledge the people who’ve worked on them. These are mostly changes that were unblocked by removing in-content XBL and XBL stylesheets, and fixes for bugs we’ve discovered from dogfooding Web Components in the browser chrome.

Binding Removals

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

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: