Over the last couple of years, I’ve worked extensively with Firefox, and while it still has its warts (and while I believe that its days of double digit rises in adoption are probably coming to a close) overall, I’ve found that it has become, for me anyway, my de facto browser into the web and the focus of most of the web applications (and extensions) that I’ve built in the last year. For that reason alone, if nothing else, I’ve been watching closely as Firefox 3.0 approaches its final release.

The second beta version of FF3 is now out, and I have to say that overall I’m feeling quite pleased with what I’m seeing, with a few caveats. Since I do generally dig into the application daily, my focus in trying it out (and in writing this review) is less on the immediate UI and functionality changes for the typical user and more on how its going to affect web software development. Thus, I ask that you forgive me for not talking about the new theme (okay, though not a radical departure from the old) or other user improvements or give you a lot of screenshots … I want to look a little more deeply under the hood.

DOM Changes

The changes coming to this version with JavaScript are likely to engender some headaches in the short-term, especially for big AJAX libraries, but longer term will prove fairly beneficial. One of the most important of these is a major change to the Document Object Model, specifically, the use of two new functions - importNode() and adoptNode(). The importNode() function represents a shift from the use of cloneNode() for adding a DOM node from an existing document into a new document. In earlier versions of JavaScript, you’d add that new node as follows:

// Assume dom1 and dom2 are predefined DOM documents

var sourceNode = dom1.getElementById('foo');
var targetParentNode = dom2.getElementById('bar');
var newNode = sourceNode.cloneNode(true);
targetParentNode.appendChild(newNode);

However, this will now generate an error, because you are attempting to add a node that is not a part of dom2 into the dom2 tree. In the FF3, this same action would be handled in a slightly different way:

// Assume dom1 and dom2 are predefined DOM documents

var sourceNode = dom1.getElementById('foo');
var targetParentNode = dom2.getElementById('bar');
var newNode = dom2.importNode(sourceNode,true);
targetParentNode.appendChild(newNode);

Here, the importNode() function creates an unaffiliated node that belongs to dom2, performing the cloneNode() implicitly then copying the clone into the new space. The appendChild() function then afiliates the node with the appropriate parent. Note that the second argument in importNode() is the same as the first argument for cloneNode() - if true, then the node and its descendents are all cloned, if false then only the node itself is cloned.

The adoptNode()works in a similar fashion, but with one major difference - it automatically removes the node in question from the source dom prior to affiliating it with the target dom. Thus while importNode() performs what amounts to a copy of the original node to the new DOM, adoptNode() performs a move instead:

// Assume dom1 and dom2 are predefined DOM documents

var sourceNode = dom1.getElementById('foo');
var targetParentNode = dom2.getElementById('bar');
var newNode = dom2.adoptNode(sourceNode);
// sourceNode has been removed from dom1
targetParentNode.appendChild(newNode);
// and added to dom2

This particular change is likely to cause all kinds of grief in the short term, as there are a fair number of scripts that add new content, likely from an AJAX XMLHttpRequest, to the existing DOM as part of the functionality of those scripts (this is particularly true of more complex RIA applications), so it should remain to be seen whether the pain point will be enough to cause a regression of this feature. I’m suspecting it likely won’t be - the performance improvements from this change are fairly significant, and a lot of RIA developers have been watching this particular delta for a while.

Beyond this, the other major change in the DOM is the support for a number of methods that are included with Internet Explorer, using a strategy called “Embrace and Extend” (oh, wait, that’s already been taken!). A number of these are genuinely useful, and have reflected holes in the Mozilla DOM model for some time, but with their adoption what you see is a version of Mozilla reality that seems to want to incorporate both the IE and W3C DOM models. We’ll see how successful they are.

Such changes include:

  • clientTop and clientLeft extensions added,
  • getClientRects() and getBoundingClientRect() makes it possible to determine the extent of a resource (such as a block of text),
  • elementFromPoint() (one of the cooler methods) added,
  • getElementsByClassName() method added (this is an extraordinarily useful command, as shown below)
  • The editing events oncut, oncopy, onpaste, onbeforecut, onbeforecopy and onbeforepaste are all now supported (whoot!!!)

One note on getElementsByClassName() - this function sits at the heart of just about every significant AJAX binding library on the planet, but because this isn’t native within earlier Firefox versions the code to retrieve this content executed at the speed of JavaScript (i.e., terribly slow, especially since its possible for elements to change classes). By moving this into C++, it is likely to give such AJAX libraries a significant performance boost once their project leads start adapting the libraries for Firefox 3.

Beyond these ie-isms, certain efforts of the HTML 5/WhatWG efforts are also making their way into Firefox. Among them is the introduction of the activeElement and hasFocus properties. The activeElement property (on the document) gives a pointer to the element that currently has the focus, or the body element if nothing else has it within the document. Similarly, the hasFocus property on an element will retrieve whether that element currently has the property or not. Admittedly, more thorough implementation of onfocus and onblur would probably be more useful here, but it is unclear at this stage whether this particular change is likely to be made.

Also from the same efforts come a set of drag events - ondrag, ondragstart, ondragend and ondragleave. These again can be simulated with a lot of effort via AJAX libraries, but because drag and drop is such a common operation in contemporary applications, it makes a lot more sense to turn these into C++ based event handlers that can be caught and processed cleanly.

Cross Site XMLHttpRequest

One of the biggest headaches that Firefox developers (and AJAX developers) have had to face has been the issue of cross-site XMLHttpRequest, which for the sake of both legibility and typing I’ll refer to as the http component. Up until Firefox 3, developers were extraordinarily limited in where they could pull information from when making an http socket call - they could generally only pull content from the same domain that served the initial page.

Unfortunately, in the age of syndicated feeds and web services, this can be frustrating - the chances are good that if you are doing a mashup of some sort, you need to pull information from multiple sites - mapping information from Google or Yahoo, internal data from your own site, perhaps stock data from an equities board, and so forth - and in some cases you needed to upload content elsewhere beyond the immediate node.

This has had the effect of pushing AJAX developers to either set up their servers to load and pass through feed content from external resources (which added considerably to unnecessary content duplication and put more strain on your immediate server) or had to “cheat” by using hacks (such as script injection) which were not only potentially very insecure but which were also sensitive to changes that the browser vendors themselves might implement.

On the flipside, there’s a very real danger of opening up the http component to have access to any server; since it becomes possible to use this to load in rogue code without oversite.

Firefox nicely provides a middle-ground solution that both works nicely and can tie into other security features, the first by implementing the W3C Access Control Response Header and then by implementing the prolog for XML specific content. In essence, the idea is that a given external resource (http://www.myresources.com/myResource.xml) can be loaded in via the http component in a page on another server (http://www.myexample.com/hostpage.html) if that resource includes the Access Control header listing the calling server:

Access-Control: allow <myexample.com>

In this case then, when the http component gets any data from myexample.com, it will automatically pass through, but if this isn’t given, then the hosting domain rule applies (i.e., if myOtherExample.com) makes the call and there’s no such Access Control header, then the http component will generate an error.

This can be extended to allow general access using wildcard characters (useful for a news feed):

Access-Control: allow <*>

For XML content (which doesn’t have any danger of being “injectable code”) you can also include a <?access-control ?> processing instruction in the header of the document. This particular PI also uses the allow, deny, and method attributes, though you can’t have allow and deny in the same access-control PI. For instance, the following would let you allow myexample.com to access this particular resource, but only for the HTTP get or post methods:

<?access-control allow="myexample.com" method="get post"?>
<root> .... </root>

More information about the access-control mechanisms is available at http://www.w3.org/TR/access-control.

Detecting and Working with Offline Applications

As web applications have become more complex and robust, they have also become far more sensitive to needing to know when they are in fact online or offline. This is especially true of AJAX applications that often “die” at the worst possible time because you’ve lost a wireless signal to the Internet. Firefox 3 implements a new read-only property - navigator.onLine - and two new events (ononline and onoffline) which makes it possible to detect which such events occur.

The following illustrates a very basic usage of the these capabilities:

<html xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.w3.org/1999/xhtml http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd"
      xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Test</title>
        <script type="text/javascript"><![CDATA[
function updateStatus(){
    try {
    var statusNode = document.getElementById("status");
    if (navigator.onLine){
        statusNode.textContent="This document is online.";
        }
    else {
         statusNode.textContent="This document is offline.";
        }
      }
    catch(e){alert(e);}
    }
            ]]></script>
    </head>
    <body ononline="updateStatus()" onoffline="updateStatus()" onload="updateStatus()">
        <div id="status"></div>
    </body>
</html>

In my initial testing of the routine, it was quite capable of detecting whether the File -> Work Offline menu toggle had been set or not, but was less capable of determining when the Linux system I was using went on or offline - however, this may have been due to the way I set up the tests as well. Nonetheless, even being able to work with the toggled state has some significant advantages.

There is an additional API for caching offline resources, although this has not been fully documented yet, so likely will be exposed with the next beta. GIven the addition with Firefox 2 of the SQLLite database, it is likely that the full extent of this API will be to provide at least some level of access to the database for script developers.

CSS Changes

One of the central changes for CSS in Firefox is the adoption of the W3C Cascading StyleSheet Object Model (CSSOM) working draft (http://dev.w3.org/csswg/cssom/), which provides a comprehensive mechanism for enabling or disabling individual stylesheets, and for manipulating stylesheets from DOM. This spec is intended to both simplify the fairly arcane implementation for handling stylesheets from DOM that was originally designed in 2000, and to add support for alternative stylesheets that provide support for alternative media.

This functionality is actually pretty critical as people begin working with HTML increasingly for use in media beyond the traditional desktop web browser metaphor. Print, especially, is becoming a core requirement for organizations with a growing portion of their online business intelligence essentially encoded in HTML meant for the web.

At a more granular level, the CSS changes at the individual rule and property level are pretty impressive as well:

  • Support for inline-block and inline-table. This is an extraordinarily welcome addition (especially for XForms developers), because it makes it possible to take a span within a div element and set the height, width, text-alignment and so forth. Up until this stage, the only way that you could accomplish this was through the use of tables, which added their own functional problems to the mix. Inline-tables, on the other hand, make other effects possible, and can be especially handy with imported HTML content.
  • The :default selector. This new selector styles the particular button in a collection of buttons that have been designated as the default.
  • rgba() and hsla(). These CSS “functions” let you specify either red/green/blue/alpha byte values or hue/saturation/luminosity/alpha values for the CSS color property. This can give you very fine-grain control, both in CSS and via JavaScript for a wide number of effects.
  • text-rendering(). This property is actually from the SVG side of the camp, but has applicability in HTML as well. In essence, text-rendering determines the quality of the text output compared to the speed of rendering. Setting text-rendering to “optimizeLegibility” or “geometricPrecision” will in both cases enable kerning and ligature support, and will usually provide a higher quality (but generally slower) anti-aliasing algorithm. On the other hand, “optimizeSpeed” will disable kerning and ligatures, and will disable font hints designed for legibility. Setting this on the body element of an HTML document can set the whole page in this manner, which can be useful when you have a large volume of content that you want rendered in the fastest period of time
  • Soft hypens and tabs. Soft hyphens (indicated by the &shy; entity) will force a word to break at the hypen if its at the edge of a block of text, while hard (default) hyphens generally force the word onto the next line. Tabs in monospaced fonts are also now rendered more accurately, rather than just being treated as generic white space.
  • Soft hypens and tabs. Soft hyphens (indicated by the &shy; entity) will force a word to break at the hypen if its at the edge of a block of text, while hard (default) hyphens generally force the word onto the next line. Tabs in monospaced fonts are also now rendered more accurately, rather than just being treated as generic white space.

This list isn’t quite exhaustive. For more information, check out CSS Improvements in Firefox 3.

Graphics

The switch over to the Cairo rendering engine has definitely paid off in terms of both the quality and speed of rendering - I’ve noticed that the time to actually render, once the resources come online, is considerably shorter, and the controls that are exposed contain a number of very subtle shading and rendering differences that showcase a much more sophisticated engine than what was in Firefox 2. This has, however, likely slowed the development of both SVG and Canvas support as they needed to be rewritten essentially from the ground up for Cairo.

One simple, but useful, effect of this comes with rounded borders. Not to put too much of a spin on it, but rounded borders in FF2 were frankly, well, ugly. They had not anti-aliasing to speak of, and so either had a tendency to break up or to pixelate badly, to the extent that most people still tended to utilize PNGs or GIFs in order to support rounded borders. In FF3, rounded borders are smooth and well anti-aliased, (and most controls even support slight shadowing effects along the edges that are far more subtle than the equivalent FF2 output).

Mozilla SVG still does not (as of FF3b2) support the animation elements or glyphs, but other than that, the implementation is getting to be pretty impressive. At this stage, SVG fully supports the <foreignObject> element, meaning that you can render HTML content within SVG content (this comes in handy when doing things like bindings), pattern and mask (these are very useful, and tend to cut down on memory requirements significantly), nearly all of the filters, including the critical feComposite and the glow and drop-shadow producing feGaussianBlur filters, and supports the text dimension functions getNumberOfChars(), getComputedTextLength(), getSubStringLength(), getStartPositionOfChar(), getEndPositionOfChar(), getRotationOfChar(), and getCharNumAtPosition().

While I’d be very excited to see support for animations, some benchmark animation tests I’ve run in JavaScript shows that even there the rendering is quite fast, though buffering pauses due to memory reallocation can occasionally cause stuttering. As a second benchmark I loaded in a number of high resolution SVG images from Openclipart.org and compared them to both the equivalent PNG file renderings and the Opera 9.5 SVG rendered images, and there was a remarkably high similarity between the three. Firefox 2 generally could properly render about one image in three. In general, Opera rendered in the background and displayed the content while Firefox rendered the image progressively, but my not terribly rigorous benchmarks seemed to show that the total render time was about the save either way.

The additional work in handling the text dimensions also paid off for Canvas developers with the introduction of a number of non-WHATWG text functions - mozTextStyle, mozDrawText(), mozMeasureText(),mozPathText(), and mozTextAlongPath(), all of which are documented (somewhat) here. I see this having greatest applicability in the creation of customized widgets where the cost and complexity of building an SVG document is probably not worth the effort. One thing I do note is that the Canvas calls and SVG calls seem to take about the same amount of rendering or processing time, so which approach you choose to take falls mainly upon whether you prefer working in an imperative or declarative style.

On the topic of canvas, the Canvas object also now supports the use of transforms (likely due to work done from SVG). Both transform() and setTransform() work by passing the six items of a simplified linear transformation to the active transformation context - with transform() multiplying against the current transformation matrix (CTM) to create a new transformation matrix, and setTransform() resetting the CTM to the identity matrix before applying the transformation.

More

The changes within JavaScript 1.8 likely will not make sense unless you understand the changes in JavaScript 1.7 as well. As such, I’m going to hold off discussing the core language features until a subsequent article in order to do it justice.

There are a few other additions within the second beta that are quite exciting (and perhaps dangerous), and likely to spur some interesting page wars in the SAAS space. The first is the introduction of a new method on the navigator object called registerProtocolHandler(). This function lets you establish for a given internet protocol the web page that will process URIs that contain that protocol. The most obvious use for this is to set the default mailto: handler for web-based mail applications:

navigator.registerProtocolHandler("mailto",
                                 "https://mail.google.com/mail?view=cm&tf=0&to=%s",
                                 "Google Mail");

For instance, suppose that you had a link of the form:

<a href="mailto:kurt.cagle@gmail.com">Kurt Cagle</a>

The protocol in this case would be “mailto”, while the second line contains the URL of the web page to process this request. Note the %s expression - this function takes the content of everything after the protocol and the following colon (:) and then replaces the “%s” text with that content (making the above expression) “https://mail.google.com/mail?view=cm&tf=0&to=kurt.cagle@gmail.com”. The final parameter is a “friendly name” that identifies the specific protocol within the browser.

When a user clicks on the link, this will open up a dialog that lets you select whether you wish to add this particular web page as a processor or not. If you do, then it becomes the default protocol handler for that particular protocol, until such time as the user explicitly changes it.

Is this a good thing? I’m not sure. What you are doing here is establishing a link to an address in a URI space, so this works as a potentially useful shortcut for specifying the address. For instance, consider a location protocol that uses GML coordinates. The URI location:latitude=48.25;longitude=-123.21 or evenlocation:Victoria,BC,CA could be automatically tied into retrieving a map from mapquest, googleMaps, YahooMaps, etc. However, this also raises questions about whether it would be to the advantage or disadvantage of different vendors to standardize on a given protocol (not just the protocol name but the protocol variables). It should be interesting to see where this one goes.

In a similar category is the <a ping>. The idea behind this one is simple (and is again a part of the WHATWG proposal) - any time a user clicks on a link, the URLs listed in the ping attribute also get a notification that the link was made. The argument for instituting this was that a number of tracking agencies (marketing primarily) already use link redirects to do this same thing. By making this an asynchronous action, this action does not affect the download time to the next link.

It’s a valid argument, but there’s a growing amount of opposition to the use of <a ping> by the development community partially on the grounds of penetration (the protocol issue faces the same issue) and the potential for misuse on the part of marketing vultures.

As previously reported in this column, the EXSLT support for the XSLT engine has now been implemented. It’s not completely conformant - I was hoping to see more of the function set especially, but with support for node-set(), one of the key problems of working with XSLT … building intermediate XML content within a transformation … go away. Again, I hope to devote some time to XSLT + EXSLT in a subsequent column.

The final change in beta 2 is the introduction of the microformats API. This would essentially make it possible to access microformat content within a web page through a specialized programmatic interface, rather than having to try to retrieve it through DOM or similar means. While I think this is a very welcome addition (though I still have my doubts about some of the downsides of microformats), this is similarly a topic that needs a whole article to do it justice.

Wrap-Up

OVerall, Firefox 3 is shaping up to be a credible upgrade to the Firefox line. With recent announcements that certain projects (most notably Thunderbird) are being spun off into their own separate organizations, the net message coming from Mozilla.com and Mozilla.org is that they’re pulling their internal resources closer to their core projects; if Firefox 3 is any indication, this strategy should work.

Firefox 3 seems to be more stable, considerably faster to render, more functional and visually much more appealing than Firefox 2. I’d still like to see declarative animation in SVG, the upgrade of the XML API and a few other features, but overall, Firefox 3.0 is looking pretty good indeed..

Kurt Cagle is an author, software developer and system analyst living in Victoria, British Columbia