Extending Gecko
with XBL and XTF
Brian Ryner
What is Gecko?
- HTML and XML rendering engine, including CSS, Javascript, DOM
- Goals include standards compliance and compatibility
- Common shared core of applications such as Firefox and Thunderbird
Adding to Gecko
- Constant pressure to add new functionality to Gecko
- New standards support (XForms, XHTML 2)
- Language extensions (WHATWG canvas, new XUL widgets)
- This conflicts with the desire to keep the layout engine small
- Where it makes sense, these new features can be implemented as optional extensions
- Features that build on existing features are the best extension candidates
Ways to extend Gecko
- XBL (XML Binding Language)
- Well-established (being standardized in SVG)
- Binding is expressed in declarative XML
- Bindings attach to elements through CSS
- XTF (Extensible Tag Framework)
- New/experimental API
- Bindings can be implemented as C++ or Javascript objects
- Bindings are attached via predetermined namespace+tag mapping
Anonymous Content
- Both mechanisms make use of anonymous content
- To provide an appearance for an element, you provide content that is
rendered as if it is inserted beneath the element
- Anonymous content would typically consist of more fundamental elements that have a predefined appearance
- The anonymous content is not visible to the DOM
Simple Anonymous Content Example: Scrollbar
- How could we represent a typical vertical scrollbar using anonymous content?
- Scrollbar consists of an arrow, a slider (track), a thumb, and another arrow
- Anonymous content tree:
<button class="arrow-up"/>
<slider>
<button class="scrollbar-thumb"/>
</slider>
<button class="arrow-down"/>
In turn, the buttons and slider could have bindings that determine how they draw and respond to events
XBL Terminology
- An XBL binding defines the behavior and appearance of an element.
- As previously mentioned, anonymous content defined by the binding is inserted into the rendering.
- The element that binding is attached to is called the bound element.
- When a binding has anonymous content, we use the term explicit children to mean the normal, non-anonymous children of the bound element.
Structure of a Binding
<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl"
xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="mybinding">
<implementation>
<constructor>...</constructor>
<destructor>...</destructor>
<method name="update">
<body> ... </body>
</method>
<property name="enabled">
<setter>...</setter>
<getter>...</getter>
</property>
</implementation>
(continued)
- The binding resides in a bindings file as shown
- The implementation section of a binding defines properties and methods using Javascript.
- Properties and methods are mapped onto Javascript object properties.
Structure of a Binding, continued
<content>
<html:button>
<html:img inherits="src=imagesrc"/>
<childen/>
</html:button>
</content>
<handlers>
<handler event="mouseover" action="showTooltip();"/>
</handlers>
</binding>
</bindings>
- The content section defines anonymous content
- The xbl:inherits attribute allows anonymous content to easily use the values of attributes on the bound element
- The xbl:children element indicates where explicit children should be inserted relative to the anonymous content.
- The handlers section defines event handlers using Javascript. Attributes such as modifiers and phase allow for built-in filtering.
Attaching a Binding
- Once a binding is created, it is attached to an element using CSS.
imagebutton {
-moz-binding: url("mybindings.xml#mybinding");
}
This mechanism is very flexible because any CSS selector can be used to select the binding.
Non-local bindings load asynchronously
The binding constructor is called when the binding is attached, and the destructor is called when it is detached.
Advanced XBL features
- Bindings can inherit from other bindings
<binding id="mybinding" extends="mybindings.xml#otherbinding">
- Bindings can implement Mozilla XPCOM interfaces
<binding id="mybinding" implements="nsISelectElement">
- xbl:children supports filtering to insert explicit children at more than one location
<content>
<children includes="xul:image"/>
<xul:separator>
<children/>
</content>
Advanced XBL features, continued
XTF Overview
- XTF was developed to address certain shortcomings of XBL
- Lack of easy API for native / non-Javascript implementation
- Difficult to add "built-in" XBL bindings
- Asynchronous attachment can cause problems
- Still in beta form
XTF Terminology
- The XTFElement implementation is analogous to an XBL binding.
- It talks to an element wrapper, which is analogous to the bound element in XBL.
- A Visual is a type of XTFElement that has anonymous content associated with it
- An element factory creates an appropriate XTFElement implementation for a given namespace+tag
Structure of an XTFElement
class MyElement : public XTFXMLVisual // : XTFVisual : XTFElement
{
// XTFElement
void onDestroyed();
unsigned long getElementType() { return ELEMENT_TYPE_XML_VISUAL; }
bool getIsAttributeHandler() { return false; }
void getScriptingInterfaces(....);
void willChangeDocument(DOMDocument *newDoc);
void documentChanged(DOMDocument *newDoc);
void willChangeParent(DOMElement *newParent);
void parentChanged(DOMElement *newParent);
...
bool handleDefault(DOMEvent *event);
(continued)
- The element receives notifications for modifications to the DOM
- getScriptingInterfaces() can return an array of DOM interfaces (IIDs) that are flattened and exposed to script.
- Elements can handle events via handleDefault()
Structure of an XTFElement, continued
// XTFVisual
DOMElement* getVisualContent();
DOMElement* getInsertionPoint();
bool getApplyDocumentStyleSheets() { return true; }
void didLayout();
const char* getClassAttributeName() { return "class"; }
// XTFXMLVisual
void onCreated(XTFXMLVisualWrapper *wrapper);
};
- getVisualContent() returns the root of the anonymous content tree. The anonymous content can be constructed via document.createElementNS() etc.
- getInsertionPoint() returns a node in the anonymous content tree which will have all explicit children appended as child nodes in the rendering.
- onCreated() is similar to the XBL constructor, and tells the element about its associated wrapper.
XTF Example: XForms
- XForms 1.0 is implemented using XTF
- XForms elements use the corresponding HTML elements as their anonymous content
XForms Example
What else could be implemented this way?
Future Direction
- XBL and XTF each have strengths and weaknesses
- XTF cannot be applied on a per-site basis, and cannot be hosted remotely
- XTF cannot extend an existing namespace, only implement a new one
- XBL forces a Javascript-based implementation
- XBL's asynchronous loading can make it non-intuitive
- Moving forward, we want to integrate XTF functionality into "XBL 2"
- Native-backed implementations for bindings
- Non-CSS binding attachment to facilitate global bindings
- Address the asychronous loading problem
- We also want to provide more flexibility
- Bindings now have full control of drawing via <canvas>
- Javascript 2 will provide new implementation alternatives