XBL Replacement Newsletter 3

This is the third edition of the XBL Replacement Newsletter. Since the last update, we’ve removed 27 bindings and have been preparing to migrate bindings to Custom Elements.

Just a reminder that easiest way to follow along with the work is to follow the main meta bug. If you’d like to help, we are tagging bugs that are unblocked and ready to be worked on with xbl-available.

Custom Elements

Custom Elements have been enabled in Nightly by default, which is a big step towards being able to use them in the browser chrome. Mossop has landed initial Custom Element support for XUL elements, and we have a couple of follow-ups on file before we can start using them. We are also working to find the best way to include Custom Element scripts (bug 1411707) and styles (bug 1420229) in XUL documents.

Accessibility Roles

One of the features that XBL provides is a way to assign a ‘role’ to elements that have a particular binding attached. For example: <binding id="toolbar" role="xul:toolbar"> will attach the XULToolbarAccessible class to all toolbar elements with that binding attached.

We needed to come up with a new solution to continue supporting the accessibility roles, and initial work for that landed in bug 1403231 when we removed the image binding. This created a new XULMap.h file in which tag names get mapped to roles. The current implementation won’t handle every case, like when bindings are attached using more complex CSS selectors, but Paolo has done a thorough analysis of which bindings we can migrate right away.

Binding Removals

There are 240 more bindings left, down from 300 at the start of the project. We’ve also started to put a dent in the number of lines of code, passing below 90%. Here’s a list of the changes:

XBL Replacement Newsletter 2

This is the second edition of the XBL Replacement Newsletter. Since the last update, we’ve continued to remove unused or unnecessary bindings and improved tooling to make it easier to keep track of the work and to help find candidates for removal.

Just a reminder that easiest way to follow along with the work is to follow the main meta bug. If you’d like to help by removing a binding, I’ve added a whiteboard tag [xbl-available] to mark bugs that are unblocked and have instructions in them. The list is a bit short for now but I expect that more bindings will fit that description over time, especially once Custom Element support is ready.

Binding Removals

There are 267 more bindings left, compared to 289 from the last update and 300 from the start of the project.

  • Mossop removed the inline options feature that was only used by legacy add-ons, and as a result the mobile/ directory is the first top level directory to go down to zero bindings! Here’s the list of bindings removed by this change: setting-base, setting-bool, setting-boolint, setting-localized-bool, setting-integer, setting-control, setting-string, setting-color, setting-path, setting-multi, setting-fulltoggle-bool, setting-fulltoggle-boolint, setting-fulltoggle-localized-bool, android-checkbox-with-spacing.
  • New contributor 86ecce74 removed the searchbar-treebody binding by migrating the behavior into an attribute on the autocomplete-treebody binding.
  • 86ecce74 also removed the control-item binding by moving the one property it defined onto its three child bindings.
  • Paolo has merged together the panelmultiview and photonpanelmultiview bindings. This required doing some post-photon cleanup first, like updating the site identity panel to use the new photon style.
  • Paolo also removed the download-toolbarbutton binding by allowing child content inside the toolbarbutton-badged binding that it was extending.
  • I removed the menucaption-inmenulist binding by moving its implementation into the menucaption binding. It turns out that the only place we use menucaptions are for <optgroup>s, and they always were being bound to the inmenulist variation of the binding.
  • I also removed three unused statusbarpanel related bindings. Some followup work to that is going to be removing the statusbar and statusbarpanel bindings.
  • I also removed the menuseparator binding by moving the accessibility role detection into C++ and loading the CSS via global.css instead of through <resources>. This surfaced an issue in which we are relying on what appears to be non-standard behavior of stylesheets loaded by XBL, in which the application order of selectors is different. There’s still some discussion to be had about how to handle this situation, but moving to the standard behavior and improving tooling to detect potential issues before landing seems pretty reasonable.

Improved Tooling

Here are some noteworthy improvements to the tools and website since the last update:

  • The bug number and the “type” of each removal get printed on the timeline. To make that easier, I’ve started a spreadsheet to track which bindings are being removed in which bugs, and which type of removal they are.
  • There are new graphs looking at the # of bindings per directory and LOC per directory
  • The tree includes links to search m-c for each binding which makes it easier to find out where a binding is used
  • Binding usage data is now being gathered in Nightly builds in taskcluster as the “browser-instrumentation” job. Thanks to Joel Maher and his team for making it easy to gather this data with activedata and taskcluster artifacts.

XBL Replacement Newsletter 1

This is the first edition of the XBL Replacement Newsletter. First, as a reminder about the project: we are planning to replace XBL in Firefox (see this blog post for more details). There are 4 main focus areas for the project this quarter, so I’ll have a quick update on each:

1. Migrate a few bindings and update the plan based on what we learn

We’ve already been able to remove some bindings, I’ll highlight each of them at the end of the post. As for updating the plan - we’ve started to look at some of our our options for accessibility when moving away from XBL. At least for <image>, we decided to move the role assignment into C++ based on the tag name, but if we could find a way to expose the role from a Custom Element definition that would allow us to keep the role in the frontend. That part is a bit TBD for now while we are still working on XUL support in Custom Elements.

2. Land XUL support for Custom Elements

There has been some progress on the platform side here, mostly happening in Bug 1404420 and blockers.

Once we have platform support we’ll still need to figure some things out for the frontend, like how to load the scripts and stylesheets needed for the Custom Elements. Since XBL scripts are loaded via CSS and styles are specified via <resources>, we don’t have an exact analog. I’ve been taking a preliminary look into our options in Bug 1411707. We’ll ultimately have to do some performance testing to see what works best.

3. Improve tooling to make converting bindings easier

There’s a new website https://arewexblstill.com that contains tooling and dashboards. I’d like to thank Potch for helping with the site - he helped with the scripts that process XBL and also maintains a node XML parsing library that makes it easy.

This site has a timeline of binding removals and additions, a set of graphs showing various metrics (# of bindings, LOC, LOC per binding, and most used bindings), and a component tree showing inheritance hierarchy of bindings. There’s also an online XBL to Custom Element converter which is useful for prototyping.

4. Begin a bug breakdown for individual bindings

While we are working on Custom Element support, there’s still plenty of work that can be done. Sometimes when looking at a binding we realize that it’s never used or that it’s trivially extending another binding and can be folded into the parent. It’s not an exact science, but I’ve been looking for such bindings in the component tree and filing bugs. If you know of any bindings that can be removed, please file a bug blocking the De-XBL meta.

Bindings that have been removed so far

We have “only” 289 more bindings to go. That’s a lot, but we started with around 300.

We’ve removed 7 bindings so far: “tabbrowser-tabbox”, “image”, “radio” (windows-specific), “radio-with-spacing” (linux-specific), “checkbox-baseline”, and “checkbox-radio”, “panebutton”. There are 4 other bindings that’ve been removed but not specifically as part of the project: “plugin-popupnotification-center-item”, “click-to-play-plugins-notification”, “history-dropmarker”, “menuitem-iconic-tooltip”

OK, now for some of the changes:

  • Paolo removed the image binding by moving the small amount of XBL code it had into XUL. This is an important one because although it had very little code, it accounts for around 25% of XBL instances created during a mochitest-browser run:
    xbl instances with and without image
  • Dão removed the Windows and Linux radio overrides (“radio”, “radio-with-spacing”). In the process we found that the only other binding (“toolbarpaletteitem-spacer”) in toolkit/themes/windows/global/globalBindings.xml was unused and we could delete the entire file
  • Mossop removed the unused checkbox-baseline and checkbox-radio bindings
  • I removed tabbrowser-tabbox in favor of a new attribute on tabbox instead, and also removed the viewbutton binding and the pageInfo.xml file that it was in.

XBL In Firefox

XBL (XML Binding Language) is a markup language used to define appearance and behavior for UI components in Firefox. The implementation of XBL and the set of implemented bindings are deeply ingrained into Firefox, and it’s been an influence for Web Components specs like Shadow DOM.

But there are a number of problems with it. And since we’re no longer bound to support XUL extensions and the Web Components implementations are progressing, it’s a good time to think about what a migration away from XBL would look like.

We’ve proposed a plan do to just this, so I’ll give an overview of the plan and share some of the tools I created to help come up with it. Note that much of this is covered in more detail in this design review document.

Firefox has a lot UI written in XBL - around 300 individual bindings and over 40K LOC with a pretty wide distribution of complexity, so we’ll need to take different approaches depending on the binding. Here are some of the approaches we identified:

1. Convert many bindings to Web Components

For a simple case where the binding is only specifying some JS and anonymous content that gets attached to a node, it can be relatively straightforward to transform XBL into a JS class. I’ve built an online XBL to Custom Element converter that demonstrates this.

Note: there are XBL features like implements that use XPCOM and can make things things significantly more complicated (see “Special Cases” below). But to get a feel for the syntax, here’s a simple example:

<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl"
          xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <binding id="okcancel">
    <content>
      <xul:button label="OK"/>
      <xul:button label="Cancel"/>
    </content>
    <handlers>
      <handler event="input"><![CDATA[
        this.onClick(event);
      ]]></handler>
    </handlers>
    <method name="onClick">
      <parameter name="aEvent"/>
      <body><![CDATA[
      console.log("Clicked", aEvent.target);
      ]]></body>
    </method>
  </binding>
</bindings>

Becomes:

class FirefoxOkcancel extends XULElement {
  connectedCallback() {
    this.innerHTML = `
      <xul:button label="OK"></xul:button>
      <xul:button label="Cancel"></xul:button>
    `;

    this.addEventListener("input", event => {
      this.onClick(event);
    });
  }

  onClick(aEvent) {
    console.log("Clicked", aEvent.target);
  }
}
customElements.define("firefox-okcancel", FirefoxOkcancel);

And the markup would change from:

<style type="text/css">
  okcancel { -moz-binding: url(okcancel.xml#okcancel); }
</style>
<okcancel />

to:

<script src="okcancel.js"></script>
<firefox-okcancel />

Notice that we are extending XULElement instead of HTMLElement. We made an intentional decision not to couple replacing XBL with replacing XUL. This is to limit the scope and risk of the project, since XUL provides a lot of features that HTML doesn’t. Also, replacing XBL doesn’t prevent or add a lot of extra cost to replacing XUL, if we decided to do so in the future.

A few notes about the differences:

  • With XBL the binding is attached via CSS (see for example xul.css). A Custom Element is attached via tag name, and is registered in a normal script via customElements.define.
  • Because bindings are attached via CSS, it makes migrating to Custom Elements tricky if more than one binding is attached to the same tag based on a CSS selector (i.e. button vs button[type="repeat"]). We’ll need to either have two different elements (firefox-button and firefox-repeatbutton), or fold the logic into a single Custom Element definition and branch on the attribute.
  • XBL provides a <resources> element which allows you to specify stylesheets that will be scoped to the <content> within the binding. This is useful both as a way to only load styles when a binding is used in a document, and as a way to scope styles. Shadow DOM provides similar a capability, but with just Custom Elements we’ll need to work around this.
  • Custom Element tag names require a dash by spec, however we could bypass that for chrome documents if we want to avoid a mass find-replace.

2. Convert some bindings to JS modules

There are some bindings that aren’t actually widgets - bindings that are only used once, or don’t render any DOM. These can generally be converted to plain JS objects - either inside of a JSM file which is loaded only once per session, or in a script loaded inside of each browser window.

3. Unrefactored XUL/JS/CSS

Bindings that are rarely used and insert relatively little content can be unrefactored into their constituent parts (XUL, JS, CSS) and inserted into each bound element. It would be up to whoever was working on an individual binding to decide if this approach makes sense - we identified some candidates in the review.

4. Flatten the inheritance hierarchy

We use inheritance pretty widely in our bindings. There are likely cases where we don’t need to - the extra inheritance may have been required for XUL extensions, or may have had a purpose at one point but doesn’t any longer.

I’ve created a page to help visualize the inheritance tree. Some potential candidates for this approach can be found in this tree where a binding is the only child of its parent, and the parent is never directly used.

5. Handle special cases

There are plenty of bindings in Firefox that don’t fit into any of the approaches above. Generally, bindings that use the [implements] attribute but don’t map pretty closely back to an HTML tag may fall into this category.

Here are a few examples:

  • In-content XBL may provide special challenges due to security considerations (Scrollbars, Marquee, Video controls, Click-to-play plugin UI)
  • <tree>, which implements nsIDOMXULTreeElement and has a pretty complicated API
  • Bindings which take advantage of CSS selector matching to switch between bindings at runtime

What’s next?

The next steps are mostly being tracked in this meta bug:

  • Migrate a few bindings and update the plan based on what we learn
  • Land XUL support for Custom Elements
  • Improve tooling to make converting bindings easier
  • Begin a bug breakdown for individual bindings

Inspect User Agent Styles in Firefox DevTools

User agent styles refer to the styles loaded by the default stylesheets within a browser. Firefox has some basic style rules that get applied to every page - for instance, links are blue and <h1> tags are big and bold with margins.

Sometimes these styles can interact with the styles you add to a page, which is why it is important that you can see them in devtools. I recently added a feature in Firefox 32 (currently Nightly) that lets you inspect these rules. See Bug 935803 for the implementation details.

Within the inspector, these styles behave pretty much like any other style on the page. It lists rules in the order of application, and you can see which rules have been overridden. There are a few ways that devtools distinguishes between the UA styles and normal styles:

  1. They are not editable. Since you can’t change these files, you are not able to edit/disable them within the tools.
  2. They are shown with a slightly different background color.
  3. The links to the stylesheet open a popup window to view the source of a sheet instead of loading the sheet in the Style Editor. There isn’t much purpose for loading these in the style editor (see 1), but seeing the source of the sheet can still be nice for the curious.

user-agent-styles-usage

user-agent-styles-usage

Enabling User Agent Styles

This is turned off by default. To enable user agent styles, select the “Show Browser Styles” checkbox from the options panel:

user-agent-styles-option

user-agent-styles-option

You can open any page and toggle this feature on to see it. But here’s a quick page to try it with:

data:text/html,<blockquote style='color:red;' type=cite><pre _moz_quote=true>fun <a href='foo' style='color:orange'>to</a> inspect</pre></blockquote>