1. beautiful fonts with @font-face

    While Firefox 3.0 improved typographic rendering by introducing support for kerning, ligatures, and multiple weights along with support for rendering complex scripts, authors are still limited to using commonly available fonts in their designs. Firefox 3.5 removes this restriction by introducing support for the CSS @font-face rule, a way of linking to TrueType and OpenType fonts just as code and images are linked to today. Safari has supported this type of font linking since version 3.1, and Opera has announced that they plan to support it in Opera 10.

    Using @font-face for font linking is relatively straightforward. Within a stylesheet, each @font-face rule defines a family name to be used, the font resource to be loaded, and the style characteristics of a given face such as whether it’s bold or italic. Firefox 3.5 only downloads the fonts as needed, so a stylesheet can list a whole set of fonts of which only a select few will actually be used.

    /* Graublau Sans Web (www.fonts.info) */
     
    @font-face {
      font-family: Graublau Sans Web;
      src: url(GraublauWeb.otf) format("opentype");
    }
     
    body {
      font-family: Graublau Sans Web, Lucida Grande, sans-serif; 
    }

    Browsers that support @font-face will render text using Graublau Sans Web while older browsers will render text using either Lucida Grande or the default sans-serif face. Example here:



    Digging A Little Deeper

    Most font families today consist of only four faces: regular, bold, italic and bold italic. To define each of these faces the font-weight and font-style descriptors are used. These define the style of the face; there’s no concept of a cascade or inheritance that applies here. Without an explicit definition each of these defaults to a value of ‘normal’:

    /* Gentium by SIL International   */
    /* http://scripts.sil.org/gentium */
     
    @font-face {
      font-family: Gentium;
      src: url(Gentium.ttf);
      /* font-weight, font-style ==> default to normal */
    }
     
    @font-face {
      font-family: Gentium;
      src: url(GentiumItalic.ttf);
      font-style: italic;
    }
     
    body { font-family: Gentium, Times New Roman, serif; }

    The sample text below when rendered with this font family:



    A feature that’s easy to overlook is that @font-face allows the creation of families with more than just regular and bold faces — up to nine weights can be defined for a single family. This is true even on Windows, where underlying platform limitations usually restrict font families to just regular and bold weights. Fonts such as those of the Japanese open source M+ Fonts project have as many as seven weights. A selection of these are used in the sample below:



    In some situations, authors may prefer to use fonts available locally and only download fonts when those faces aren’t available. This is possible with the use of local() in the definition of the src descriptor of an @font-face rule. The browser will iterate over the list of fonts in the src descriptor until it successfully loads one.

    /* MgOpen Moderna                      */
    /* http://www.zvr.gr/typo/mgopen/index */
     
    @font-face {
      font-family: MyHelvetica;
      src: local("Helvetica Neue"), 
           local("HelveticaNeue"), 
           url(MgOpenModernaRegular.ttf);
    }
     
    @font-face {
      font-family: MyHelvetica;
      src: local("Helvetica Neue Bold"), 
           local("HelveticaNeue-Bold"), 
           url(MgOpenModernaBold.ttf);
      font-weight: bold;
    }
     
    body { font-family: MyHelvetica, sans-serif; }

    The screenshot below shows from top to bottom the results on Mac OS X, Windows and Linux for a simple testcase that uses the font family defined above:



    The Helvetica Neue font family is available on most Mac OS X systems but generally on neither Windows nor Linux machines. When the example here is rendered on Mac OS X, the local Helvetica Neue faces are used and no font is downloaded. Under Windows and Linux the attempt to load a local font fails and a substitute font — MgOpen Moderna — is downloaded and used instead. MgOpen Moderna is designed to be a substitute for Helvetica, so it renders similarly to Helvetica Neue. This way, an author can guarantee text appearance but avoid a font download when it’s unnecessary.

    The name used to refer to a specific font face is the full name for an individual font. Generally it’s the family name plus the style name (e.g. “Helvetica Bold”). Under Mac OS X, the name is listed in the information panel for a given face. Select a single face and choose ‘Show Font Info’ from the Preview menu in FontBook:

    Similar tools exist under Linux. On Windows, use the font properties extension, a free download from Microsoft to view these names. With the extension installed, the properties panel shows information about an individual font. The full name is referred to as the “Font Name” on the Name tab:

    Safari only supports PostScript name lookup under Mac OS X, so under Mac OS X Postscript names are also supported. For OpenType PS fonts (often labeled with an .otf extension) the full name is the same as the PostScript name under Windows. So for these fonts, authors are advised to include both the full name and the PostScript name for cross-platform interoperability.

    Supporting Many Languages

    Many languages suffer from a lack of commonly available fonts. For minority languages and ancient scripts, the options often dwindle to just a handful. The use of @font-face allows authors using these languages to ameliorate this by including fonts with their pages.

    @font-face {
      font-family: Scheherazade;
      src: url(fonts/ScheherazadeRegAAT.ttf) format("truetype-aat"), 
           url(fonts/ScheherazadeRegOT.ttf) format("opentype");
    }
     
    body { font-family: Scheherazade, serif; }

    Languages such as Arabic require text shaping, where the display of a given character is affected by the characters surrounding it. Different platforms support different rendering technologies to enable text shaping; under Mac OS X, AAT fonts are required while under Windows and Linux OpenType fonts are required. Without a font in a format required for a given platform, text shaping will not be rendered correctly.



    Under Mac OS X, the AAT version of the font is downloaded. On Windows and Linux, where rendering with AAT fonts is not supported, the download of the AAT font is skipped and the OpenType font is used instead. Hence, the text is rendered correctly on all platforms.

    Cross-Site Font Usage

    By default, Firefox 3.5 only allows fonts to be loaded for pages served from the same site. This prevents sites from freely using fonts found on other sites. For sites that explicitly want to allow cross-site font sharing, an online font library for example, Firefox 3.5 supports the use of access control headers to control this behavior. By adding an additional header to the HTTP headers sent with font files, sites can enable cross-site usage.

    # example Apache .htaccess file to add access control header
     
    <FilesMatch "\.(ttf|otf)$">
    <IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
    </IfModule>
    </FilesMatch>

    With this HTTP header enabled, any page can access the fonts on this site, not just pages from the same site.

    Font Licensing Issues

    When using a font for a website, it’s important to always confirm that the font license permits use on a website. If the license agreement is filled with opaque legalese, err on the side of caution and check with the font vendor before using a font on a site. If the license permits its use, it’s a good idea to add a comment near the @font-face rules that points to the license, for future reference.

    “I found a free font, can I use it on my site?”

    Maybe, maybe not. Some free fonts are distributed as teaser products to encourage a purchase and don’t allow for redistribution or posting on a web server. Check the license, even for free fonts.

    “I just want to use [insert favorite font name here] on my site. Is that possible?”

    Right now, probably not. The use of font linking on the web is still in its infancy. Most fonts that ship with proprietary OS’s today have licenses that limit their use to standard desktop applications, so uploading these fonts to a web server is almost certainly not permitted. Piracy has plagued the font industry in the past, so most font vendors are wary of allowing their fonts to be used except in relatively limited contexts. Many font vendors are focused on the needs of publishing and printing industries, and the relative complexity of their license agreements often reflects this. In the future, some font designers may conclude that the sales of fonts as web fonts will outweigh any potential loss in sales due to piracy, others may not. Their license agreements will reflect this choice and should be respected.

    The stock photography market is often described as a $2 billion market but the web font market is still close to a $0 market, it can only go up!

    Font Linking In Internet Explorer

    Font linking has been possible with Internet Explorer but only for linking to fonts in the proprietary EOT font format. The only way to create EOT fonts is to use the Microsoft WEFT tool, available only on Windows. Only TrueType and OpenType TT fonts can be converted to EOT format, OpenType PS (.otf) fonts cannot be used.

    Internet Explorer only recognizes the font-family and src descriptors within @font-face rules, so each family can only contain a single face. It doesn’t understand format() hints and will ignore any @font-face rule containing these hints. This behavior can be used enable font linking cross platform:

    /* Font definition for Internet Explorer */
    /*         (*must* be first)             */
    @font-face {
      font-family: Gentium;
      src: url(Gentium.eot) /* can't use format() */;
    }
     
    /* Font definition for other browsers */
    @font-face {
      font-family: Gentium;
      src: url(Gentium.ttf) format("opentype");
    }

    Future Work

    For Firefox 3.5, the font-stretch and unicode-range descriptors are not supported. Fonts defined in SVG documents are also not supported yet. These are under consideration for inclusion in future releases. As always, patches are welcome!

    Further Resources

    Translations

    Documentation

    Examples

    Font Resources

    Font Politics

  2. an update on open video codecs and quality

    Two days ago we posted a comparison by Greg Maxwell of low and medium resolution YouTube videos vs. Theora counterparts at the same bit rates. The result in that test was that Theora did much better at the low bit rate and more or less the same at the slightly higher bit rate. The conclusion being that Theora is perfectly appropriate for a site like YouTube.

    Now Maik Merten has done the same with videos at HD resolution, comparing videos encoded by YouTube and a video encoded with the new Theora encoder at a managed bitrate. The results? Go have a look at the images in the post. Tell us if you can honestly see a major difference. We can’t.

    H.264
    Theora

  3. color correction for images in Firefox 3.5

    Back in Firefox 3, we introduced support for color profiles in tagged images, but it was disabled by default. In Firefox 3.5 we were able to make the color correction process about 5x faster than it was in Firefox 3 so we’ve enabled support for color correction for tagged images.

    Most images on the web are untagged. If you don’t know the difference between tagged images and untagged images the odds are good are you won’t notice this change. However, we suggest that you read on to learn about what it might mean for you if you want to include them and how future Firefox releases might change the interactions between CSS colors and images.

    What’s a color profile?

    People who spend a lot of time taking photographs or any kind of high-resolution color printing will understand that many output devices – LCDs, CRTs, paper etc – all have very different interpretations of what various colors mean. For example, uncorrected red will look very different on an LCD vs. a CRT. You can see this if you set up two very different monitors next to each other and the operating system doesn’t do color correction – colors will look more washed out in one of them vs. the other.

    JPG and PNG images both have support for color profiles. These color profiles allow Firefox to take colors in the image and translate them into colors that are independent of any particular device.

    While images contain color profiles it’s also important to note that output devices like monitors also have color profiles. As an example an output device may be better at displaying reds than blues. When you’re getting ready to show something that’s “red” on that device it might need to be converted from the neutral #ff0000 value to #f40301 in order to show up as red on the screen.

    What this means is that there are actually two conversions that take place with color profiles. The first is to take the original color information in the image and, using the color profile, convert it into a device-independent color space. Then once it’s in that independent space you convert it again using the output device’s color profile to get it ready to display on the output device.

    So what about CSS colors?

    It’s important to understand how color profiles work and how they are converted to properly understand how CSS interacts with these color spaces.

    In Firefox 3.5 we consider CSS colors to already be in the device output’s color space. Another way of saying this is that CSS colors are not in the neutral color space and are not converted into the output device like tagged images are.

    What this means is that if you have a tagged image where a color is expected to match the CSS that’s right next to it, it won’t. Or at least it’s likely that it won’t on some output device – maybe not the one that you happen to be using for development. Remember that different output devices have different color profiles. Here’s an example of what that looks like:

    In Firefox 3, this will look like one contiguous block of purple. In Firefox 3.5 and Safari you will notice that there’s a purple box within a purple box (unless your system profile is sRGB.) This is because the image is color corrected while the surrounding CSS is not.

    This is where the statement about the future comes in. In a future release of Firefox we are likely to make it possible for people to turn on color correction for tagged images and CSS. You can test this setting today by changing the pref listed on the page on color correction on the Mozilla Developer Center to “Full color management.” In that case untagged images should continue to work as we will be rendering both CSS and untagged images in the sRGB color space.

    Image support and tools

    PNG’s can be tagged in three different ways. First they can have an iCCP chunk that contains the associated ICC profile. Second they can be explicitly tagged as sRGB using a sRGB chunk. Finally, they can contain gAMA and cHRM chunks that describe the image’s gamma and chromaticies. Using any of thse methods will cause Firefox to color correct the image.

    You can remove all of the color correction chunks resulting in an untagged image using pngcrush:

    pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB infile.png outfile.png

    Alternatively, you can use TweakPNG and delete the gAMA, cHRM, iCCP and sRGB chunks by hand.

  4. Firefox 3.5 for 35 days – dreaming about the future of the web

    35 days logo

    Over the next 35 days we’ll be talking about all of the new developer features in Firefox 3.5.

    The upcoming release of Firefox 3.5 is a big upgrade for users.  It includes new privacy features, improvements in interactive performance and a new JavaScript engine that will improve the experience for users using script-heavy web sites.  These are all features that users will appreciate and talk about.

    But what Firefox 3.5 really represents is a huge upgrade to the web itself.  We’ve included support for audio, video, threads in JavaScript, new canvas features, tons of new CSS features, downloadable fonts and geolocation.  While Firefox 3 was a signifigant upgrade for the web’s users, Firefox 3.5 does the same for developers.

    Because of the sheer volume of new features for developers in Firefox 3.5 we’ll be spending the next 35 days featuring all of them, with two posts a day, every day.  Each day’s first post will describe one new feature in Firefox in depth – how to use it, why it’s there and some examples of what it can do for you.  The second post will be all fun – examples of demos that people have put together using all of the features that are in Firefox 3.5.

    Like much of what we do at Mozilla this is a community-led project. We’ve reached out to members of the Mozilla and web developer community for posts and demos.  Some posts will be written by core Mozilla hackers, but many of them will be written by people who are just excited about the chance to use this technology in the wild.

    My personal belief is that these posts represent Mozilla’s dreams for the future of the web.  We are not a company like every other browser vendor – our core mission is to improve and protect the web.  Firefox 3.5 represents what we think the next stage of the web will be – interactive applications, video, web sites collaborating and sharing information – all via the browser.  Our hope is that each of you will take what we post here, encourage other browser vendors to implement similar features where they haven’t already, and do your part to keep the web vibrant.

  5. what does tracemonkey feel like?

    One of our goals with Firefox 3.5 is to help upgrade the web. Over the lifecycle of this release we’ve invested heavily in developer features. One of the features that we’ve invested in is TraceMonkey – a tracing interpreter that turns commonly-run JavaScript code into machine code so that it can run at near-native speeds. We consider it to be both an end user feature because it makes existing web applications faster as well as a developer feature because of the new kinds of applications it enables.

    We’re always challenged to try and come up with ways to describe what that means in a way that’s not a dry benchmark. How can we explain what it feels like?

    We’ve made a video to help describe both what it means by the numbers, but also shows what it feels like. If you want to try the demo we suggest you try it in both Firefox 3 and Firefox 3.5. It’s something you can really feel.

    Sadfaces. Your browser doesn’t support native video. Maybe you can try the .ogv version or the .mp4 version and hope for the best?

  6. 3D transforms in Firefox 3.5 – the isocube

    This demo was created by Zachary Johnson, a Minneapolis, MN based web developer who has also authored a jQuery plugin for animated “3D” rotation.

    I’d like to show an example of a visual effect that can be accomplished using the new -moz-transform CSS transformation property that is available in the Firefox 3.5 browser. I was very excited to see this feature added to Firefox because I knew it would allow me to produce a faux-3D isometric effect, also sometimes called 2.5D. I created a demo where HTML content is mapped onto the faces of a “3D” isometric cube:

    The -moz-transform property can take a list of CSS transform functions including rotate, scale, skew, and translate. Or, multiple transformations can be done simultaneously using a single 2D affine transformation matrix. Because all of the CSS transformation functions work in two dimensions, true 3D transformations with perspective projection cannot yet be accomplished. In this demo, I use the rotate and skew transformation functions in order to create the isometric effect.

    First, I define a container div for the cube, and then a square div for the top, left, and right faces of the cube.

    <div class="cube">
        <div class="face top">
        </div>
        <div class="face left">
        </div>
        <div class="face right">
        </div>
    </div>
    .cube {
        position: absolute;
    }
     
    .face {
        position: absolute;
        width: 200px;
        height: 200px;
    }

    Without getting too wrapped up in isometric projection math, we have to rotate and skew the cube faces in order to turn each square div into a parallelogram where the angles of the vertices are 60° or 120°. Here are what those transformations look like using the new -moz-transform CSS property:

    .top {
        -moz-transform: rotate(-45deg) skew(15deg, 15deg);
    }
     
    .left {
        -moz-transform: rotate(15deg) skew(15deg, 15deg);
    }
     
    .right {
        -moz-transform: rotate(-15deg) skew(-15deg, -15deg);
    }

    Now all that is left to do is to use absolute positioning to connect each transformed div in order to form the faces of the isometric cube. You can use matrix math to do this, or you could just move the faces around until they line up and it looks right.

    To add to the 3D effect, I’ve shaded the isometric cube by assigning different colors to the faces. I also gave the cube a shadow. You can see that the shadow is basically just a copy of the top face of the cube moved down to the bottom left, and then I gave the shadow div a black background color and set opacity: 0.5; in the CSS to make it filter over the page background.

    Any HTML, such as the text and form buttons in this example, can be put inside the div for any face of the cube. It will be translated into the correct perspective. Christopher Blizzard gave me the idea to throw video onto one side of the cube using the new HTML5 video tag now supported in Firefox 3.5. As you can see, it works great.

    Finally, by making a copy of the cube markup and using two more of the CSS transformation functions, I was able to create a second cube. I made the cube 50% as big using a scale(0.5) transformation, and I moved it into place by using translate(600px, 400px).

    I hope you found this demo to be interesting and that it opened up your mind to some exciting possibilities that Firefox 3.5 CSS transformations bring to the web.

    CSS transformations are also supported by Safari 3.1+ and Chrome using the -webkit-transform CSS property.

  7. html5 video fallbacks with markup

    In a previous post on this blog we talked about using JavaScript to create video elements on the fly. While that was a good use case for the Mozilla’s support site in this post we offer another set of methods that will likely find more use on the web. In fact you can see it in use on Mozilla’s What’s New in Firefox 3.5 video, this blog and we’re starting to see pickup on the web as a whole.

    The examples here should work with Safari 4, Firefox 3.5 and IE using a flash fallback. If you’re looking for a complete example that includes support for the video element, quicktime, windows media, iPhone support, and finally flash support you might try checking out Video for Everybody. It’s been tested with a huge pile of browsers in different configurations and is a good start point if you’re looking for support for everything under the universe.

    You might also check out Michael Verdi’s video tags with fallbacks article where he uses a much simpler, but somewhat easier to understand method.

    A simple example

    The video tag looks something like this in a web page:

    <video src="zombie.ogg" controls></video>

    What this does is insert a video element into your page. Firefox 3.5 will load the video, determine its size and re-size the element to the natural size of the video.

    Firefox 3.5 supports the Ogg Theora video format, a free and open standard for video. Opera and Google Chrome will also include support for Theora in later versions. Safari 4 can also support the same format when using the Xiph Quicktime component but is not guaranteed to be present. Apple has licensed the mpeg4 format for use in Safari 4 and it is supported by default.

    If you want to support both formats you need to be able to provide more than one type of format. You also need to change the markup to tell the browser about the types of the files, which order they are preferred and then let the browser choose which one it should use to display the video element. For our example the code would look something like this:

    <video controls>
    <source src="zombie.ogg" type="video/ogg"/>
    <source src="zombie.mp4" type="video/mp4"/>
    </video>

    In this case the browser will first check to see if it supports the video/ogg video type. If it does, it will use that and load it. If it doesn’t it will move on to the next entry, the mp4 file and use it if it’s supported.

    While most modern browsers have specific plans to support the video element, Microsoft has not made their intentions clear. So in order to support IE users into the near future you should provide fallbacks until Microsoft adopts this part of the new HTML5 standard. For our example we’ll use a simple flash fallback.

    One nice thing about the video element is how easily it degrades to older browsers. If in the above example your browser doesn’t support the video tag and doesn’t support the source tag it will simple fall back to whatever happened to be included inside them. This makes it very easy to support fallbacks in a very easy way. Here’s what a flash fallback would look like that uses blip.tv:

    <video controls>
    <source src="zombie.ogg" type="video/ogg"/>
    <source src="zombie.mp4" type="video/mp4"/>
    <embed src="http://blip.tv/play/AYGLzBmU8hw"
      type="application/x-shockwave-flash"
      width="500" height="396"
      allowscriptaccess="always"
      allowfullscreen="true"/>
    </video>

    And that’s it. This example supports all browsers, degrades nicely and helps to move the web forward all in one blow. HTML5 isn’t finished, but web developers can certainly start taking advantage of the features that it provides in modern browsers today.

    The full example is embedded below.

  8. the potential of web typography

    This post counts as both a demo and commentary about the changing nature of typography on the web. Ian Lynam and Craig Mod have put together a page that is an excellent example of typography in action, but also offer some suggestions on what the next steps for typography on the web might look like. The page itself takes advantage of a number of typefaces that Craig and Ian got permission to use and uses a pleasing multi-column layout. Please click through to the complete article to get the full effect.

  9. using HTML5 video with fallbacks to other formats

    The Mozilla Support Project and support.mozilla.com (SUMO for short) is an open and volunteer powered community that helps over 3 million Firefox users a week get support and help with their favorite browser. The Firefox support community maintains a knowledge base with articles in over 30 languages and works directly with users through our support forums or live chat service. They’ve put together the following demonstration of how to use open video and Flash-based video at the same time to provide embedded videos to users regardless of their browser. This demo article was written by Laura Thomson, Cheng Wang and Eric Cooper

    Note: This article shows how to add video objects to a page using JavaScript. For most pages we suggest that you read the article that contains information on how to use the video tag to provide simple markup fallbacks. Markup-based fallbacks are much more elegant than JavaScript solutions and are generally recommended for use on the web.

    One of the challenges to open video adoption on the web is making sure that online video still performs well on browsers that don’t currently support open video.  Rather than asking users with these browsers to download the video file and use a separate viewer, the new <video> tag degrades gracefully to allow web developers to provide a good experience for everyone.  As Firefox 3.5 upgrades the web, users in this transitional period can be shown open video or video using an existing plugin in an entirely seamless way depending on what their browser supports.

    At SUMO, we use this system to provide screencasts of problem-solving steps such as in the article on how to make Firefox the default browser.

    If you visit the page using Firefox 3.5, or another browser with open video support, and click on the “Watch a video of these instructions” link, you get a screencast using an Ogg-formatted file.  If you visit with a browser that does not support <video> you get the exact same user experience using an open source .flv player and the same video encoded in the .flv format, or in some cases using the SWF Flash format.  These alternate viewing methods use the virtually ubiquitous Adobe Flash plugin which is one of the most common ways to show video on the web.

    The code works as follows.

    In the page which contains the screencasts, we include some JavaScript.   Excerpts from this code follow, but you can see or check out the complete listing from Mozilla SVN.

    The code begins by setting up an object to represent the player:

    Screencasts.Player = {
    width: 640,
    height: 480,
    thumbnails: [],
    priority: { 'ogg': 1, 'swf': 2, 'flv': 3 },
    handlers: { 'swf': 'Swf', 'flv': 'Flash', 'ogg': 'Ogg' },
    properNouns: { 'swf': 'Flash', 'flv': 'Flash', 'ogg': 'Ogg Theora' },
    canUseVideo: false,
    isThumb: false,
    thumbWidth: 160,
    thumbHeight: 120
    };

    We allocate a priority to each of the possible video formats.  You’ll notice we also have the 'canUseVideo' attribute, which defaults to false.

    Later on in the code, we test the user’s browser to see if it is video-capable:

    var detect = document.createElement('video');
    if (typeof detect.canPlayType === 'function' &&
        detect.canPlayType('video/ogg;codecs="theora,vorbis"') == 'probably' ) {
          Screencasts.Player.canUseVideo = true;
          Screencasts.Player.priority.ogg =
              Screencasts.Player.priority.flv + 2
    }

    If we can create a video element and it indicates that it can play the Ogg Theora format we set canUseVideo to true and increase the priority of the Ogg file to be greater than the priority of the .flv file. (Note that you could also detect if the browser could play .mp4 files to support Safari out of the box.)

    Finally, we use the priority to select which file is actually played, by iterating through the list of files to find the one that has the highest priority:

    for (var x=0; x < file.length; x++) {
      if (!best ) {
        best = file[x];
      } else {
        if (this.priority[best] < this.priority[file[x]])
          best = file[x];
      }
    }

    With these parts in place, the browser displays only the highest priority video and in a format that it can handle.

    If you want to learn more about the Mozilla Support Project or get involved in helping Firefox users, check out their guide to getting started.

    Resources

    * Note: To view this demo using Safari 4 on Mac OSX, you will need to add Ogg support to Quicktime using the Xiph Quicktime plugin available from http://www.xiph.org/quicktime/download.html

  10. XHR progress and rich file upload feedback

    This demo is by Olli Pettay (smaug) with help from Austin King.

    A common limitation on the web today has been a rich file upload widget for web applications. Many sites use Flash or a desktop helper applications to improve the experience of uploading files.

    Firefox 3.5 bridges one of these gaps allowing a better progress indicator to be built. Many developers don’t realize that they can use Firefox’s File object (nsIDOMFile) and XMLHttpRequest together to accomplish file uploads. This demo will feature an upload widget that gives the kind of rich progress feedback that users have come to expect, as well as fast and easy multiple simultaneous file uploads.

    Progress Indicators

    It’s always a good idea to expose feedback that your application is hard at work for them, and when the current action is expected to finish. The two main types of progress feedback are:

    • indeterminate progress – some activity just happened
    • deterministic progress I’m 40% done, I’m 42% done… etc

    Deterministicsaidwhat? The Demo

    We’ve created a simple file upload / download page that demonstrates the progress bar:

    The demo is host at mozilla.pettay.fi and requires Firefox 3.5 beta4 or later. It demonstrates how to do multiple simultaneous file uploads without posting a form or leaving the current page. For each file upload / download we display the current speed, % complete, and bytes transmitted. We’ll go over a few key snippets of the code which are used in the screenshot above. Please click through the the demo and view source for the full code example.

    The page contains two HTML inputs, one type="file" and one type="button". The form is never actually submitted, instead we add an onclick handler to the button:

    <input type="file" id="file">
    <input type="button"
              onclick="startXHR();"
              value="Upload file using XHR">

    In the startXHR function, we create an XMLHttpRequest and add an event handler to the XHR request to listen for the new ‘progress’ event. With this ProgressEvent’s lengthComputable property, we will know if we are dealing with an indeterminate or deterministic progress. The object also gives us loaded and total bytes.

    var xhr = new XMLHttpRequest();
     
    xhr.onprogress = function(evt) {        
    if (evt.lengthComputable) {
        evt.target.curLoad = evt.loaded;
        evt.target.log.parentNode.parentNode.previousSibling.textContent =
            Number(evt.loaded/k).toFixed() + "/"+ Number(evt.total/k).toFixed() + "kB";
    }
    if (evt.lengthComputable) {
        var loaded = (evt.loaded / evt.total);
        if (loaded < 1) {
            var newW = loaded * width;
            if (newW < 10) newW = 10;
                evt.target.log.style.width = newW + "px";
            }
        }
    };

    Now we need some data to send. We grab the contents of the file directly from the input by id:

    var files = document.getElementById("file").files;
    if (files) {
       var file = files.item(0);
       xhr.sendAsBinary(file.getAsBinary());

    And the last step is to start the request:

    xhr.open("POST", "cgi-bin/posthandler.pl");
    xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
    xhr.sendAsBinary(file.getAsBinary());

    These methods would also work with xhr.upload.onprogress.

    Notice the use of the sendAsBinary method on the XMLHttpRequest object and getAsBinary on the File object. Starting with Firefox 3 you’ve been able to get at the contents of a file on the client side without form submission. This is quite useful for moving beyond the limitation of tranditional file input and form submissions. It is also part of an up and coming W3C standard for FileUpload.

    A related method that the nsIDOMFile provides is the getAsText method which returns a DOMString suitable for slicing, dicing, and displaying.

    Here is an example usage, not used by the demo:

    file.getAsText("utf8");

    So that’s the gist of the code. Check out the demo and view it’s source.

    Feedback In User Interfaces

    Exposing system feedback to users improves perceived performance. We
    can’t always determine how long something will take, so at a minimum we
    can show indeterminate progress.

    During file uploads and file downloads (assuming the server gives us Content-Length) we do indeed know the total number of bytes. Firefox 3.5’s Progress Events support adds a progress event so that we can show actual upload/download progress.

    Traditionally XMLHttpRequests were difficult to get deterministic progress back from. In theory, you could give it callbacks and watch for status code updates and textual message updates, but in practice they turn out to be not very useful. In the past, if a deterministic progress meter was important, you’d have to make a second XHR request to poll for progress.

    Enter Progress Events

    The W3C has a working draft for Progress Events 1.0 which we include in Firefox 3.5. Firefox has added a key new DOM ProgressEvent progress event, as well as the loadstart event. The other existing events included: error, abort and load.

    These same events are also available for uploads and downloads. The progress event gives us the following properties:

    • lengthComputable – true or false, is the size of the request known?
    • loaded – number of bytes received so far
    • total – number of bytes expected for entire request

    The Contract

    When you’re looking at the properties of those progress events, certain rules apply that you can depend on. They are:

    • The total property will be 0 when lengthComputable is false.
    • The loadstart event is always signaled only once.
    • The progress event is fired off zero or more times after loadstart.

    And that’s it. Go forth and improve file uploads with Firefox 3.5 goodness.