XTech 2005: XML, the Web and beyond.

Rich Web: SVG And Canvas In Mozilla

Discuss this paper on the XTech wiki
View XML source for this paper

Keywords

Abstract

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.

Introduction

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.

Canvas

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.

Canvas Example
<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 .

Rendering of

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.

SVG

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.

SVG Example
<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 .

Rendering of

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.

Implementation

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.

Deployment Issues

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.

Conclusion

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.

Acknowledgements

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).

Biography

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.