XTech 2005: XML, the Web and beyond.
Today's Web browsers offer somewhat limited graphics capabilities to
Web developers. Advances in hardware, especially graphics processors,
offer the potential for far richer graphics in interactive
applications. To realize this potential in Web applications, browsers
must expose rich new graphics APIs to Web content. The Mozilla project
will meet this challenge with two major new features to be delivered
in Firefox 1.1: integrated SVG and a new canvas HTML
element. Work is also underway "under the hood" on a new unified
graphics architecture that uses 3D graphics processors to accelerate
all rendering. This work provides additional benefits to Web
developers such as the ability to apply SVG effects to HTML
content.
Today Web developers use a mix of three main approaches to display complex graphics on the screen:
Two initiatives are underway to remedy this situation. The best-known is the W3C's
Scalable Vector Graphics
activity. The SVG specifications define an XML vocabulary to express scriptable
rich graphics that can integrate with documents containing HTML and other XML
content. Until recently browserf have not offered native support for SVG, but Opera and Mozilla
have announced SVG support. Apple has taken another approach,
introducing a new canvas HTML element. This element is
essentially an image that exposes a rendering API that scripts can use to draw into it.
Apple and Mozilla are working together to
standardize canvas through the WHATWG group.
Apple shipped canvas support
as part of their latest release of Safari, and Mozilla will support it in Firefox 1.1.
In fact SVG and canvas
are complementary. SVG represents a powerful "retained mode" drawing API where the 2D scene is
a tree of DOM objects. SVG supports accessibility, declarative animation, and CSS styling,
and can contain "foreign objects" from other XML namespaces. On the contrary,
canvas is an "immediate mode" API; it is nothing more than
an abstract pixel buffer that script can draw into with explicit drawing commands. Thus
we expect developers to find that given a particular task, one or the other will be clearly
more suitable.
In the rest of this paper I give some examples of SVG
and canvas being used in Web pages.
Then I present our new graphics architecture that overcomes a few limitations of
the Firefox 1.1 implementation. I also discuss the issues of deploying
these technologies in Web content today.
shows how the canvas
element might be used in a Web page. Initially the canvas is merely a fully
transparent image. The Javascript in the example uses the the canvas' drawing
API to draw a translucent PNG into the canvas with a random size, angle and offset,
once every 200ms. This example illustrates how canvas
naturally integrates with regular Web scripting. It could not be produced in
today's browsers without the aid of plugins. With a plugin, code would have to be
distributed across multiple files, and communicating a click outside the plugin
to script running inside the plugin would be tricky.
<html>
<head>
<title>Canvas Test</title>
<script type="application/x-javascript">
var files = ["http://libpng.org/pub/png/img_png/stefan_pal_rgba.png",
"http://libpng.org/pub/png/img_png/RedbrushAlpha-0.25.png"];
var fileIndex = 0;
var img = new Image();
img.src = files[fileIndex];
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.save();
ctx.translate(Math.random()*400 + 100, Math.random()*400 + 100);
var scale = Math.random()*2;
ctx.scale(scale, scale);
ctx.rotate(Math.random()*360);
ctx.drawImage(img, 0, 0);
ctx.restore();
setTimeout(draw, 200);
}
function switchImage() {
fileIndex = (fileIndex+1)%files.length;
img.src = files[fileIndex];
}
</script>
</head>
<body onload="draw();" onclick="switchImage();">
<h1>Canvas</h1>
<canvas id="canvas" width="600" height="600"/>
</body>
</html>
A rendering of this example is shown in .
The example shows a situation where SVG would not be suitable. A very large number of objects must be composed together, and the objects are individually static; maintaining a DOM tree with all the elements would eventually consume far more resources than a simple pixel buffer. Canvas may be preferred in other situations where it is most convenient to generate an image algorithmically.
shows how SVG may be usefully
added to an existing HTML page. The page is XHTML and uses XML namespaces
to access both XHTML and SVG vocabularies in the same document.
We have a basic HTML form with a background provided by
an inline svg element. The
svg element, in the SVG
namespace, contains two DOM child elements representing shapes ---
a circle on top of a rectangle. The shapes are
both filled with a gradient, and the gradient colors are specified via CSS.
We signal a user error by updating the colors, using regular DOM and CSS
machinery. Adding such an effect to an existing HTML form would be
significantly more difficult with other technologies.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
stop.begin { stop-color:yellow; }
stop.end { stop-color:green; }
body.invalid stop.end { stop-color:red; }
#err { display:none; }
body.invalid #err { display:inline; }
</style>
<script>
function signalError() {
document.getElementById('body').setAttribute("class", "invalid");
}
</script>
</head>
<body id="body"
style="position:absolute; z-index:0; border:1px solid black; width:90%; height:90%;">
<form>
<fieldset>
<legend>HTML Form</legend>
<p><label>Enter something:</label> <input type="text"/>
<span id="err">Incorrect value!</span></p>
<p><button onclick="signalError();">Activate!</button></p>
</fieldset>
</form>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100"
preserveAspectRatio="xMidYMid slice"
style="width:100%; height:100%; position:absolute; top:0; left:0; z-index:-1;">
<linearGradient id="gradient">
<stop class="begin" offset="0%"/>
<stop class="end" offset="100%"/>
</linearGradient>
<rect x="0" y="0" width="100" height="100" style="fill:url(#gradient)" />
<circle cx="50" cy="50" r="30" style="fill:url(#gradient)" />
</svg>
</body>
</html>
A rendering of this example is shown in .
Note that this document degrades gracefully on browsers that do not support SVG. The SVG background is simply not rendered; everything else works.
SVG is more appropriate than canvas for this task. A canvas-based solution would be less declarative and would require extra logic to update the background in response to window size changes.
The World Wide Web Consortium has convened the
Compound Document
Formats Working Group to specify in detail how mixed-namespace documents
should be rendered. For relatively simply mixtures such as this one, there is
little ambiguity and the rendering should not be affected by the decisions of
the CDFWG. In more complicated scenarios, such as HTML containing SVG containing
HTML, some ambiguities or problems may need to be worked out. Currently we do not
support SVG containing non-SVG content (in particular the SVG
foreignobject element is not supported ---
see below), so any such issues do not arise.
Our current implementation of SVG and canvas
is functional but has some limitations that we will work to overcome in the next
release.
In Firefox 1.1 the canvas element is implemented using Cairo, a portable open source library for advanced 2D graphics. On Linux, SVG rendering is also implemented using Cairo, but on Windows SVG uses Microsoft's GDI+ library. On the other hand, on each platform the Gecko engine uses the native graphics API to draw normal HTML and CSS content.
This situation is unsatisfactory for a few reasons. Obviously there is some duplication of code. Most of the code already existed before we started using it, but we still have had to write a significant amount of glue code. On the other hand, if we had a single underlying graphics implementation, we would only have to deal with one set of bugs. It would also minimize build dependencies and download footprint.
From the Web developer's perspective a more significant problem in the current architecture is that SVG content can't contain non-SVG content. Generally non-SVG content will be rendered by native graphics APIs, and getting the results of drawing with those APIs into the SVG rendering process is problematic. Many platform graphics APIs can't express SVG transforms such as rotation, let alone SVG filters (e.g., drop shadows or Gaussian blur). We could render non-SVG content to an intermediate buffer and apply SVG transforms to the buffer, but in many situations we'll still need to know the alpha values of the pixels in the buffer (for example when drawing antialiased text using native APIs), and these are not generally available.
Thus we looked for a design satisfying the following requirements:
No framework exists today that fully satisfies these requirements, but the Cairo project
has closely aligned goals, so we are working on making Cairo the unified substrate for canvas,
SVG and HTML/CSS rendering. Cairo's "Glitz" backend utilizes 3D graphics hardware to
implement most operations and we are looking forward to deploying it to accelerate not
only SVG and canvas,
but also regular Web page rendering. For example, pages using many
heavy translucent images often hit performance bottlenecks in image rendering code today.
Hardware support should remove those bottlenecks and allow enhancements such as more
sophisticated image scaling algorithms.
With a unified rendering infrastructure, we will support
arbitrary nesting of SVG and HTML content (including canvases, although
canvas will always be effectively a leaf element).
In particular this will allow rotation, scaling, path-clipping and application of
filter effects to arbitrary HTML content.
This new graphics infrastructure is scheduled for release in the next major release of Firefox after 1.1.
In addition to infrastructure work, some major pieces of SVG 1.1 were not finished in time for Firefox 1.1. In particular, SVG fonts, SMIL animation, and filters are not implemented. These are obvious targets for ongoing work.
Some developers are fortunate enough to know for sure that their user audience will
have Firefox 1.1 ... for example, XUL application authors who package Gecko with their
application. Also, over time we expect support for these features to emerge in other browsers;
Safari 1.3 and 2.0 already support canvas,
and Opera 8 has some support for SVG. However, most Web developers will have to deal
with the likelihood that some of their users won't have SVG or canvas in the near future.
There are a variety of strategies available for dealing with these users.
One approach is write script to detect support for canvases and/or SVG and
dynamically emit canvas/SVG content if available. Canvas support can be detected by checking
whether a canvas element supports the
getContext() method. Browser SVG support can be detected by checking whether
svg elements implement the SVGElement
interface.
Script-free fallback mechanisms are also available. As mentioned earlier,
SVG content (apart from SVG text elements) will be ignored by most browsers
that do not support SVG. This makes it easy to add visual effects to Web pages that
will simply not appear where support is not available. A canvas
element behaves like the HTML object element;
when canvases are not supported, the children of the canvas
element are rendered instead.
Ultimately, the fastest way to get new features implemented by browsers and into the hands of users is to create demand for them. For that, we depend on the cooperation of Web developers.
The time is ripe for Web sites to start taking advantage of emerging standards
for Web graphics. SVG and the canvas element
offer complementary approaches to adding rich graphics to existing Web pages. Support
for these features is arriving in leading-edge Web browsers, and even more
powerful functionality is in the works. It's up to Web developers to take the initiative
to bring rich Web graphics to the masses.
I had little to do with most of the work described in this paper. Credit goes to SVG hackers Alex Fritze, Scooter Morris, Tim Rowley, Jonathan Watt and others, canvas hackers Vladimir Vukicevic, Stuart Parmenter, and Mike Shaver, the Cairo team led by Carl Worth, and many many other direct and indirect contributors to the Mozilla effort. Thanks also to my Novell Ximian management for giving me the opportunity to pursue these interests (although this paper represents my own opinions, not Novell's).
Robert O'Callahan
Software Engineer, Novell
Robert O'Callahan is a long-time Mozilla contributor and programming language/tools researcher currently employed by Novell's Ximian division. His blog is Well, I'm Back. This paper represents his personal opinions, not any official statement by Novell.