Mozilla

Feature Articles

Sort by:

View:

  1. beautiful fonts with @font-face

    This article is also available in Bulgarian.

    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
    
    
    
    Header set Access-Control-Allow-Origin "*"
    
    
    

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

  3. an overview of TraceMonkey

    This post was written by David Mandelin who works on Mozilla’s JavaScript team.

    Firefox 3.5 has a new JavaScript engine, TraceMonkey, that runs many JavaScript programs 3-4x faster than Firefox 3, speeding up existing web apps and enabling new ones. This article gives a peek under the hood at the major parts of TraceMonkey and how they speed up JS. This will also explain what kinds of programs get the best speedup from TraceMonkey and what kinds of things you can do to get your program to run faster.

    Why it’s hard to run JS fast: dynamic typing

    High-level dynamic languages such as JavaScript and Python make programming more productive, but they have always been slow compared to statically typed languages like Java or C. A typical rule of thumb was that a JS program might be 10x slower than an equivalent Java program.

    There are two main reasons JS and other dynamic scripting languages usually run slower than Java or C. The first reason is that in dynamic languages it is generally not possible to determine the types of values ahead of time. Because of this, the language must store all values in a generic format and process values using generic operations.

    In Java, by contrast, the programmer declares types for variables and methods, so the compiler can determine the types of values ahead of time. The compiler can then generate code that uses specialized formats and operations that run much faster than generic operations. I will call these type-specialized operations.

    The second main reason that dynamic languages run slower is that scripting languages are usually implemented with interpreters, while statically typed languages are compiled to native code. Interpreters are easier to create, but they incur extra runtime overhead for tracking their internal state. Languages like Java compile to machine language, which requires almost no state tracking overhead.

    Let’s make this concrete with a picture. Here are the slowdowns in picture form for a simple numeric add operation: a + b, where a and b are integers. For now, ignore the rightmost bar and focus on the comparison of the Firefox 3 JavaScript interpreter vs. a Java JIT. Each column shows the steps that have to be done to complete the add operation in each programming language. Time goes downward, and the height of each box is proportional to the time it takes to finish the steps in the box.

    time diagram of add operation

    In the middle, Java simply runs one machine language add instruction, which runs in time T (one processor cycle). Because the Java compiler knows that the operands are standard machine integers, it can use a standard integer add machine language instruction. That’s it.

    On the left, SpiderMonkey (the JS interpreter in FF3) takes about 40 times as long. The brown boxes are interpreter overhead: the interpreter must read the add operation and jump to the interpreter’s code for a generic add. The orange boxes represent extra work that has to be done because the interpreter doesn’t know the operand types. The interpreter has to unpack the generic representations of a and i, figure out their types, select the specific addition operation, convert the values to the right types, and at the end, convert the result back to a generic format.

    The diagram shows that using an interpreter instead of a compiler is slowing things down a little bit, but not having type information is slowing things down a lot. If we want JS to run more than a little faster than in FF3, by Amdahl’s law, we need to do something about types.

    Getting types by tracing

    Our goal in TraceMonkey is to compile type-specialized code. To do that, TraceMonkey needs to know the types of variables. But JavaScript doesn’t have type declarations, and we also said that it’s practically impossible for a JS engine to figure out the types ahead of time. So if we want to just compile everything ahead of time, we’re stuck.

    So let’s turn the problem around. If we let the program run for a bit in an interpreter, the engine can directly observe the types of values. Then, the engine can use those types to compile fast type-specialized code. Finally, the engine can start running the type-specialized code, and it will run much faster.

    There are a few key details about this idea. First, when the program runs, even if there are many if statements and other branches, the program always goes only one way. So the engine doesn’t get to observe types for a whole method — the engine observes types through the paths, which we call traces, that the program actually takes. Thus, while standard compilers compile methods, TraceMonkey compiles traces. One side benefit of trace-at-a-time compilation is that function calls that happen on a trace are inlined, making traced function calls very fast.

    Second, compiling type-specialized code takes time. If a piece of code is going to run only one or a few times, which is common with web code, it can easily take more time to compile and run the code than it would take to simply run the code in an interpreter. So it only pays to compile hot code (code that is executed many times). In TraceMonkey, we arrange this by tracing only loops. TraceMonkey initially runs everything in the interpreter, and starts recording traces through a loop once it gets hot (runs more than a few times).

    Tracing only hot loops has an important consequence: code that runs only a few times won’t speed up in TraceMonkey. Note that this usually doesn’t matter in practice, because code that runs only a few times usually runs too fast to be noticeable. Another consequence is that paths through a loop that are not taken at all never need to be compiled, saving compile time.

    Finally, above we said that TraceMonkey figures out the types of values by observing execution, but as we all know, past performance does not guarantee future results: the types might be different the next time the code is run, or the 500th next time. And if we try to run code that was compiled for numbers when the values are actually strings, very bad things will happen. So TraceMonkey must insert type checks into the compiled code. If a check doesn’t pass, TraceMonkey must leave the current trace and compile a new trace for the new types. This means that code with many branches or type changes tends to run a little slower in TraceMonkey, because it takes time to compile the extra traces and jump from one to another.

    TraceMonkey in action

    Now, we’ll show tracing in action by example on this sample program, which adds the first N whole numbers to a starting value:

     function addTo(a, n) {
       for (var i = 0; i < n; ++i)
         a = a + i;
       return a;
     }
    
     var t0 = new Date();
     var n = addTo(0, 10000000);
     print(n);
     print(new Date() - t0);
    

    TraceMonkey always starts running the program in the interpreter. Every time the program starts a loop iteration, TraceMonkey briefly enters monitoring mode to increment a counter for that loop. In FF3.5, when the counter reaches 2, the loop is considered hot and it's time to trace.

    Now TraceMonkey continues running in the interpreter but starts recording a trace as the code runs. The trace is simply the code that runs up to the end of the loop, along with the types used. The types are determined by looking at the actual values. In our example, the loop executes this sequence of JavaScript statements, which becomes our trace:

        a = a + i;    // a is an integer number (0 before, 1 after)
        ++i;          // i is an integer number (1 before, 2 after)
        if (!(i < n)) // n is an integer number (10000000)
          break;
    

    That's what the trace looks like in a JavaScript-like notation. But TraceMonkey needs more information in order to compile the trace. The real trace looks more like this:

      trace_1_start:
        ++i;            // i is an integer number (0 before, 1 after)
        temp = a + i;   // a is an integer number (1 before, 2 after)
        if (lastOperationOverflowed())
          exit_trace(OVERFLOWED);
        a = temp;
        if (!(i < n))   // n is an integer number (10000000)
          exit_trace(BRANCHED);
        goto trace_1_start;
    

    This trace represents a loop, and it should be compiled as a loop, so we express that directly using a goto. Also, integer addition can overflow, which requires special handling (for example, redoing with floating-point addition), which in turn requires exiting the trace. So the trace must include an overflow check. Finally, the trace exits in the same way if the loop condition is false. The exit codes tell TraceMonkey why the trace was exited, so that TraceMonkey can decide what to do next (such as whether to redo the add or exit the loop). Note that traces are recorded in a special internal format that is never exposed to the programmer — the notation used above is just for expository purposes.

    After recording, the trace is ready to be compiled to type-specialized machine code. This compilation is performed by a tiny JIT compiler (named, appropriately enough, nanojit) and the results are stored in memory, ready to be executed by the CPU.

    The next time the interpreter passes the loop header, TraceMonkey will start executing the compiled trace. The program now runs very fast.

    On iteration 65537, the integer addition will overflow. (2147450880 + 65537 = 2147516417, which is greater than 2^31-1 = 2147483647, the largest signed 32-bit integer.) At this point, the trace exits with an OVERFLOWED code. Seeing this, TraceMonkey will return to interpreter mode and redo the addition. Because the interpreter does everything generically, the addition overflow is handled and everything works as normal. TraceMonkey will also start monitoring this exit point, and if the overflow exit point ever becomes hot, a new trace will be started from that point.

    But in this particular program, what happens instead is that the program passes the loop header again. TraceMonkey knows it has a trace for this point, but TraceMonkey also knows it can't use that trace because that trace was for integer values, but a is now in a floating-point format. So TraceMonkey records a new trace:

      trace_2_start:
        ++i;            // i is an integer number
        a = a + i;      // a is a floating-point number
        if (!(i < n))   // n is an integer number (10000000)
          exit_trace(BRANCHED);
        goto trace_2_start;
    

    TraceMonkey then compiles the new trace, and on the next loop iteration, starts executing it. In this way, TraceMonkey keeps the JavaScript running as machine code, even when types change. Eventually the trace will exit with a BRANCHED code. At this point, TraceMonkey will return to the interpreter, which takes over and finishes running the program.

    Here are the run times for this program on my laptop (2.2GHz MacBook Pro):

    System Run Time (ms)
    SpiderMonkey (FF3) 990
    TraceMonkey (FF3.5) 45
    Java (using int) 25
    Java (using double) 74
    C (using int) 5
    C (using double) 15

    This program gets a huge 22x speedup from tracing and runs about as fast as Java! Functions that do simple arithmetic inside loops usually get big speedups from tracing. Many of the bit operation and math SunSpider benchmarks, such bitops-3bit-bits-in-byte, ctrypto-sha1, and math-spectral-norm get 6x-22x speedups.

    Functions that use more complex operations, such as object manipulation, get a smaller speedup, usually 2-5x. This follows mathematically from Amdahl's law and the fact that complex operations take longer. Looking back at the time diagram, consider a more complex operation that takes time 30T for the green part. The orange and brown parts will still be about 30T together, so eliminating them gives a 2x speedup. The SunSpider benchmark string-fasta is an example of this kind of program: most of the time is taken by string operations that have a relatively long time for the green box.

    Here is a version of our example program you can try in the browser:

    Numerical result:

    Run time:

    Average run time:

    Understanding and fixing performance problems

    Our goal is to make TraceMonkey reliably fast enough that you can write your code in the way that best expresses your ideas, without worrying about performance. If TraceMonkey isn't speeding up your program, we hope you'll report it as a bug so we can improve the engine. That said, of course, you may need your program to run faster in today's FF3.5. In this section, we'll explain some tools and techniques for fixing performance of a program that doesn't get a good (2x or more) speedup with the tracing JIT enabled. (You can disable the jit by going to about:config and setting the pref javascript.options.jit.content to false.)

    The first step is understanding the cause of the problem. The most common cause is a trace abort, which simply means that TraceMonkey was unable to finish recording a trace, and gave up. The usual result is that the loop containing the abort will run in the interpreter, so you won't get a speedup on that loop. Sometimes, one path through the loop is traced, but there is an abort on another path, which will cause TraceMonkey to switch back and forth between interpreting and running native code. This can leave you with a reduced speedup, no speedup, or even a slowdown: switching modes takes time, so rapid switching can lead to poor performance.

    With a debug build of the browser or a JS shell (which I build myself - we don't publish these builds) you can tell TraceMonkey to print information about aborts by setting the TMFLAGS environment variable. I usually do it like this:

    TMFLAGS=minimal,abort
    dist/MinefieldDebug.app/Contents/MacOS/firefox
    

    The minimal option prints out all the points where recording starts and where recording successfully finishes. This gives a basic idea of what the tracer is trying to do. The abort option prints out all the points where recording was aborted due to an unsupported construct. (Setting TMFLAGS=help will print the list of other TMFLAGS options and then exit.)

    (Note also that TMFLAGS is the new way to print the debug information. If you are using a debug build of the FF3.5 release, the environment variable setting is TRACEMONKEY=abort.)

    Here's an example program that doesn't get much of a speedup in TraceMonkey.

    function runExample2() {
      var t0 = new Date;
    
      var sum = 0;
      for (var i = 0; i < 100000; ++i) {
        sum += i;
      }
    
      var prod = 1;
      for (var i = 1; i < 100000; ++i) {
        eval("prod *= i");
      }
      var dt = new Date - t0;
      document.getElementById(example2_time').innerHTML = dt + ' ms';
    }
    

    Run time:

    If we set TMFLAGS=minimal,abort, we'll get this:

    Recording starting from ab.js:5@23
    recording completed at  ab.js:5@23 via closeLoop
    
    Recording starting from ab.js:5@23
    recording completed at  ab.js:5@23 via closeLoop
    
    Recording starting from ab.js:10@63
    Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.
    
    Recording starting from ab.js:10@63
    Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.
    
    Recording starting from ab.js:10@63
    Abort recording of tree ab.js:10@63 at ab.js:11@70: eval.
    

    The first two pairs of lines show that the first loop, starting at line 5, traced fine. The following lines showed that TraceMonkey started tracing the loop on line 10, but failed each time because of an eval.

    An important note about this debug output is that you will typically see some messages referring to inner trees growing, stabilizing, and so on. These really aren't problems: they usually just indicate a delay in finishing tracing a loop because of the way TraceMonkey links inner and outer loops. And in fact, if you look further down the output after such aborts, you will usually see that the loops eventually do trace.

    Otherwise, aborts are mainly caused by JavaScript constructs that are not yet supported by tracing. The trace recording process is easier to implement for a basic operation like + than it is for an advanced feature like arguments. We didn't have time to do robust, secure tracing of every last JavaScript feature in time for the FF3.5 release, so some of the more advanced ones, like arguments, aren't traced in FF3.5.0. Other advanced features that are not traced include getters and setters, with, and eval. There is partial support for closures, depending on exactly how they are used. Refactoring to avoid these constructs can help performance.

    Two particularly important JavaScript features that are not traced are:

    • Recursion. TraceMonkey doesn't see repetition that occurs through recursion as a loop, so it doesn't try to trace it. Refactoring to use explicit for or while loops will generally give better performance.
    • Getting or setting a DOM property. (DOM method calls are fine.) Avoiding these constructs is generally impossible, but refactoring the code to move DOM property access out of hot loops and performance-critical segments should help.

    We are actively working on tracing all the features named above. For example, support for tracing arguments is already available in nightly builds.

    Here is the slow example program refactored to avoid eval. Of course, I could have simply done the multiplication inline. Instead, I used a function created by eval because that's a more general way of refactoring an eval. Note that the eval still can't be traced, but it only runs once so it doesn't matter.

    function runExample3() {
      var t0 = new Date;
    
      var sum = 0;
      for (var i = 0; i < 100000; ++i) {
        sum += i;
      }
    
      var prod = 1;
      var mul = eval("(function(i) { return prod * i; })");
    
      for (var i = 1; i < 100000; ++i) {
        prod = mul(i);
      }
      var dt = new Date - t0;
      document.getElementById('example3_time').innerHTML = dt + ' ms';
    }
    

    Run time:

    There are a few more esoteric situations that can also hurt tracing performance. One of them is trace explosion, which happens when a loop has many paths through it. Consider a loop with 10 if statements in a row: the loop has 1024 paths, potentially causing 1024 traces to be recorded. That would use up too much memory, so TraceMonkey caps each loop at 32 traces. If the loop has fewer than 32 hot traces, it will perform well. But if each path occurs with equal frequency, then only 3% of the paths are traced, and performance will suffer.

    This kind of problem is best analyzed with TraceVis, which creates visualizations of TraceMonkey performance. Currently, the build system only supports enabling TraceVis for shell builds, but the basic system can also run in the browser, and there is ongoing work to enable TraceVis in a convenient form in the browser.

    The blog post on TraceVis is currently the most detailed explanation of what the diagrams mean and how to use them to diagnose performance problems. The post also contains a detailed analysis of a diagram that is helpful in understanding how TraceMonkey works in general.

    Comparative JITerature

    Here I will give a few comparisons to other JavaScript JIT designs. I'll focus more on hypothetical designs than competing engines, because I don't know details about them — I've read the release information and skimmed a few bits of code. Another big caveat is that real-world performance depends at least as much on engineering details as it does on engine architecture.

    One design option could be a called a per-method non-specializing JIT. By this, I mean a JIT compiler that compiles a method at a time and generates generic code, just like what the interpreter does. Thus, the brown boxes from our diagrams are cut out. This kind of JIT doesn't need to take time to record and compile traces, but it also does not type-specialize, so the orange boxes remain. Such an engine can still be made pretty fast by carefully designing and optimizing the orange box code. But the orange box can't be completely eliminated in this design, so the maximum performance on numeric programs won't be as good as a type-specializing engine.

    As far as I can tell, as of this writing Nitro and V8 are both lightweight non-specializing JITs. (I'm told that V8 does try to guess a few types by looking at the source code (such as guessing that a is an integer in a >> 2) in order to do a bit of type specialization.) It seem that TraceMonkey is generally faster on numeric benchmarks, as predicted above. But TraceMonkey suffers a bit on benchmarks that use more objects, because our object operations and memory management haven't been optimized as heavily.

    A further development of the basic JIT is the per-method type-specializing JIT. This kind of a JIT tries to type-specialize a method based on the argument types the method is called with. Like TraceMonkey, this requires some runtime observation: the basic design checks the argument types each time a method is called, and if those types have not been seen before, compiles a new version of the method. Also like TraceMonkey, this design can heavily specialize code and remove both the brown and orange boxes.

    I'm not aware that anyone has deployed a per-method type-specializing JIT for JavaScript, but I wouldn't be surprised if people are working on it.

    The main disadvantage of a per-method type-specializing JIT compared to a tracing JIT is that the basic per-method JIT only directly observes the input types to a method. It must try to infer types for variables inside the method algorithmically, which is difficult for JavaScript, especially if the method reads object properties. Thus, I would expect that a per-method type-specializing JIT would have to use generic operations for some parts of the method. The main advantage of the per-method design is that the method needs to be compiled exactly once per set of input types, so it's not vulnerable to trace explosion. In turn, I think a per-method JIT would tend to be faster on methods that have many paths, and a tracing JIT would tend to be faster on highly type-specializable methods, especially if the method also reads a lot of values from properties.

    Conclusion

    By now, hopefully you have a good idea of what makes JavaScript engines fast, how TraceMonkey works, and how to analyze and fix some performance issues that may occur running JavaScript under TraceMonkey. Please report bugs if you run into any significant performance problems. Bug reports are also a good place for us to give additional tuning advice. Finally, we're trying to improve constantly, so check out nightly TraceMonkey builds if you're into the bleeding edge.

  4. Firefox 4 Beta 2 is here – Welcome CSS3 transitions

    As we have explained before, Mozilla is now making more frequent updates to our beta program. So here it is, Firefox Beta 2 has just been released, 3 weeks after Beta 1.

    Firefox 4 Beta 1 already brought a large amount of new features (see the Beta 1 feature list). So what’s new for web developers in this beta?

    Performance & CSS3 Transitions

    The two major features for web developers with this release are Performance improvements and CSS3 Transitions on CSS3 Transforms.

    This video is hosted by Youtube and uses the HTML5 video tag if you have enabled it (see here). Youtube video here.

    Performance: In this new Beta, Firefox comes with a new page building mechanism: Retained Layers. This mechanism provides noticeable faster speed for web pages with dynamic content, and scrolling is much smoother. Also, we’re still experimenting with hardware acceleration: using the GPU to render and build some parts of the web page.

    CSS3 Transitions on transforms: The major change for web developers is probably CSS3 Transitions on CSS3 Transformations.

    CSS3 Transitions provide a way to animate changes to CSS properties, instead of having the changes take effect instantly. See the documentation for details.

    This feature was available in Firefox 4 Beta 1, but in this new Beta, you can use Transitions on Transformation.

    A CSS3 Transformation allows you to define a Transformation (scale, translate, skew) on any HTML element. And you can animate this transformation with the transitions.

    See this box? Move your mouse over it, and its position transform: rotate(5deg); will transform transform: rotate(350deg) scale(1.4) rotate(-30deg); through a smooth animation.
    #victim {
      background-color: yellow;
      color: black;
    
      transition-duration: 1s;
      transform: rotate(10deg);
    
      /* Prefixes */
    
      -moz-transition-duration: 1s;
      -moz-transform: rotate(5deg);
    
      -webkit-transition-duration: 1s;
      -webkit-transform: rotate(10deg);
    
      -o-transition-duration: 1s;
      -o-transform: rotate(10deg);
    }
    #victim:hover {
      background-color: red;
      color: white;
    
      transform:  rotate(350deg) scale(1.4) rotate(-30deg);
    
      /* Prefixes */
    
      -moz-transform:  rotate(350deg) scale(1.4) rotate(-30deg);
      -webkit-transform:  rotate(350deg) scale(1.4) rotate(-30deg);
      -o-transform:  rotate(350deg) scale(1.4) rotate(-30deg);
    }

    CSS 3 Transitions are supported by Webkit-based browsers (Safari and Chrome), Opera and now Firefox as well. Degradation (if not supported) is graceful (no animation, but the style is still applied). Therefore, you can start using it right away.

    Demos

    I’ve written a couple of demos to show both CSS3 Transitions on Transforms and hardware acceleration (See the video above for screencasts).

    This demo shows 5 videos. The videos are Black&White in the thumbnails (using a SVG Filter) and colorful when real size (click on them). The “whirly” effect is done with CSS Transitions. Move you mouse over the video, you’ll see a question mark (?) button. Click on it to have the details about the video and to see another SVG Filter applied (feGaussianBlur).
    This page shows 2 videos. The top left video is a round video (thanks to SVG clip-path) with SVG controls. The main video is clickable (magnifies the video). The text on top of the video is clickable as well, to send it to the background using CSS Transitions.
    This page is a simple list of images, video and canvas elements. Clicking on an element will apply a CSS Transform to the page itself with a transition. White elements are clickable (play video or bring a WebGL object). I encourage you to use a hardware accelerated and a WebGL capable browser. For Firefox on Windows, you should enable Direct2D.

    Credits

    Creative Commons videos:

    The multicolor cloud effect (MIT License)

  5. new device API for Firefox 3.6: orientation

    One new feature that we’re including as part of Firefox 3.6 is support for web pages to access machine orientation information if it’s available. As you can see from the demo above you can use it to figure out if the machine is moving and what direction it’s facing.

    Using the API is very simple. All you have to do is add a simple event listener:

    window.addEventListener("MozOrientation", function(e) {
                            /* 3 values: e.x, e.y, e.z */
                            }, true);
    
    

    Originally built as something that we would include for our upcoming mobile browser release, we’ve made it available on desktop systems as well. Many modern Macbooks and Thinkpads contain devices and drivers that expose this information. We’ve added support for Linux, Macs and some Thinkpads where drivers and devices are available. (Note, on some Macbooks detect the orientation information backwards – we’re working on that.)

    You can find more information on two posts by Doug Turner and an update on documentation for orientation from Eric Shepherd.

    Paul Rouget has this and some other demos up in one of his posts.

  6. css gradients in Firefox 3.6

    Firefox 3.6 includes many CSS improvements. In this post we’re going to show you how to use CSS gradients.

    If you are running the latest beta of Firefox 3.6, you should check out our interactive demo and take a look at the corresponding code. Use the radio buttons to switch different style options on or off.

    Backgrounds with CSS Gradients

    Using CSS gradients in a background allows you to display smooth transitions between two or more specified colors without having to use images. This in turn reduces download time and bandwidth use, looks better while zooming, and lets you create a more flexible layout.

    Firefox 3.6 supports two kinds of CSS gradients: linear (-moz-linear-gradient) and radial (-moz-radial-gradient).

    Linear Gradients

    To create a linear gradient, you’ll need to set a starting point and a direction (or angle) for the gradient and to define the color stops.

     -moz-linear-gradient( [ || ,]? ,  [, ]* )
    

    Starting Point. The starting point works just like background position. You can set the horizontal and the vertical positions as a percentage, in pixels, or using left/center/right for horizontal, and top/center/bottom for vertical. Positions start from the top left corner. If you don’t specify the horizontal or the vertical position, it will default to center.

    For example, here’s a linear gradient that starts at the center (horizontal) and top (vertical), and goes from blue to white:

    basic_linear_bluetop

      .linear_gradient_square {
        width: 100px;
        height: 100px;
        border: 1px solid #333;
        background: -moz-linear-gradient(top, blue, white);
      }

    One that starts left (horizontal) and center (vertical):

    basic_linear_blueleft

        background: -moz-linear-gradient(left, blue, white);

    And a gradient starting left (horizontal) and top (vertical):

    basic_linear_bluetopleft

        background: -moz-linear-gradient(left top, blue, white);

    Angle. As you can see above, if you don’t specify an angle, it is defined automatically based on the start position. If you would like more control over the direction of the gradient, you can set the angle as well.

    For example, the following gradients have the same starting point of left center, but the one on the right hand-side also has an angle of 20 degrees.

    linear_gradient_angle

        background: -moz-linear-gradient(left 20deg, black, white);

    When specifying the angle, remember that is it the angle between a horizontal line and the gradient line, going counter-clockwise. So using 0deg will generate a left to right horizontal gradient, while 90deg will create a vertical gradient from the bottom to the top.

    linear_redangles

        background: -moz-linear-gradient(, red, white);

    Color Stops. In addition to start position and angle, you should specify color stops. Color stops are points along the gradient line that will have the specified color at the specified location (set as a percentage or length). The number of color stops is unlimited. If you use a percentage for the location, 0% represents the starting point, and 100% is the ending point, but values above and below those can be used to achieve the desired effect.

    Here’s a simple example with three color stops. Because no point is specified for the first and last colors, they will default to 0% and 100%.

    linear_colorstops

        background: -moz-linear-gradient(top, blue, white 80%, orange);

    Colors will be evenly spaced if no position is specified.

    linear_rainbow

        background: -moz-linear-gradient(left, red, orange, yellow, green, blue);
    

    Transparency. Gradients also support transparency. This can be useful, for example, when stacking multiple backgrounds. Here’s a combination of two backgrounds: one image and one linear gradient from white to transparent white.

    linear_multibg_transparent

    .multibackground_transparent {
        background: -moz-linear-gradient(right, rgba(255,255,255,0), rgba(255,255,255,1)), url(http://demos.hacks.mozilla.org/openweb/resources/images/patterns/flowers-pattern.jpg);
    }

    Radial Gradients

    The syntax for radial gradients is very similar to that of linear gradients:

     -moz-radial-gradient([ || ,]? [ || ,]? , [, ]*);
    

    In addition to the start position, the direction, and the colors, which you have already seen in linear gradients, radial gradients allow you to specify the gradient’s shape (circle or ellipse) and size (closest-side, closest-corner, farthest-side, farthest-corner, contain or cover).

    Color stops. Just like with linear gradients, you should define color stops along the gradient line. The following circles have the same color stops, but the gradient on the left defaults to evenly spaced colors, while the one on the right has a specific position for each color.

    radial_gradient_stop

     background: -moz-radial-gradient(red, yellow, #1E90FF);
     background: -moz-radial-gradient(red 5%, yellow 25%, #1E90FF 50%);
    

    Shape. Here you can see the difference between the two possible shapes, a circle (on the left) and an ellipse (on the right), both with a bottom left starting point:

    radial_circle_ellipse

     .radial_gradient_circle {
        background: -moz-radial-gradient(bottom left, circle, red, yellow, #1E90FF);
    }
     .radial_gradient_ellipse {
        background: -moz-radial-gradient(bottom left, ellipse, red, yellow, #1E90FF);
    }

    Size. The different options for size (closest-side, closest-corner, farthest-side, farthest-corner, contain or cover) refer to the point used to define the size of the circle or ellipse.

    Example: closest-side vs. farthest corner for an ellipse.
    The following two ellipses have different sizes. The one on the left is set by the distance from the start point (center) to the closest-side, while the one on the right is determined by the distance from the start point to the farthest corner.

    radial_ellipse_size

      background: -moz-radial-gradient(ellipse closest-side, red, yellow 10%, #1E90FF 50%, white);
      background: -moz-radial-gradient(ellipse farthest-corner, red, yellow 10%, #1E90FF 50%, white);
    

    Example: closest-side vs. farthest-side for a circle.
    The size of the circle on the left is determined by the distance between the start point (the center) and the closest side, while the one on the right is the distance between the start point and the farthest side.

    radial_circle_size

     background: -moz-radial-gradient(circle closest-side, red, yellow 10%, #1E90FF 50%, white);
     background: -moz-radial-gradient(circle farthest-side, red, yellow 10%, #1E90FF 50%, white);
    

    Example: contained circle.
    Here you can see the default circle on the left, and the version of the same gradient but contained on the right.

    radial_contain

     background: -moz-radial-gradient(red, yellow, #1E90FF);
     background: -moz-radial-gradient(contain, red, yellow, #1E90FF);
    

    Repeating Gradients

    If you would like to repeat a gradient, you should use -moz-repeating-linear-gradient and -moz-repeating-radial-gradient.

    In the examples below, four color stops are specified in each case, and are repeated indefinitely.

    repeating_gradients

     .repeating_radial_gradient_example {
        background: -moz-repeating-radial-gradient(black, black 5px, white 5px, white 10px);
    }
     .repeating_linear_gradient_example {
         background: -moz-repeating-linear-gradient(top left -45deg, red, red 5px, white 5px, white 10px);
    }
    

    Demo

    Check out our interactive demo of linear and radial gradients for more examples.

    Note that the gradient syntax has changed between Firefox 3.6 beta 1 and beta 2, so if you used gradients with beta 1, you may need to update your code.

  7. Firefox 3.6 Alpha 1 – web developer changes

    As covered on the Mozilla Developer Center, Firefox 3.6 Alpha 1 is now available for download. And we’ve been busy since Firefox 3.5.

    Web developers will be interested in a number of features that are new in Firefox 3.6 Alpha 1:

    • The TraceMonkey JavaScript engine has continued to get faster.
    • We’ve made a huge number of improvements to overall DOM and element layout performance. In some cases we’re much, much faster. We’ll cover details on those in a later post.
    • The compositor landing has made it possible to fix a large number of interactions between web content, CSS and plugins. We’ll be talking about this in a later post as well.
    • We now support the -moz-background-size CSS property which lets you set the size of background images.
    • We now support CSS Gradients.
    • We now support multiple background images.
    • We now support the rem unit as a CSS unit.
    • image-rendering is supported for images, background images, videos and canvases.
    • We now send a reorder event to embedded frames and iframes when their document is loaded.
    • We’ve removed the getBoxObjectFor() method. It was non-standard and exposed all kinds of non-standard stuff to the web.
    • We now send a hashchange event to a page whenever the URI part after the # changes.
    • We now have Geolocation address support for user-readable position information.
    • We now support the complete attribute on document.readystate.

    You can keep track of this list and other features for XUL and add-ons developers on the Firefox 3.6 for developers page on developer.mozilla.org

    Unlike the year that passed between Firefox 3 and Firefox 3.5, we expect that this 3.6 release will be released in a small number of months. Our main focus for the 3.6 release will be end-user perceived performance, TraceMonkey and DOM performance and new web developer features.

    Enjoy and test away!

  8. WebSockets in Firefox

    Here’s the pitch for WebSockets: a low-complexity, low-latency, bi-directional communication system that has a pretty simple API for web developers. Let’s break that down, and then talk about if and when we’re going to include it in Firefox:

    Low-complexity

    The WebSocket protocol, which is started via an HTTP-like handshake, has a relatively simple model for sending text packets back and forth. The complexity of the protocol is quite low. There’s no multiplexing, no support for binary data, and once the data connection is set up, the actual transport is quite cheap.

    Note that there are people who feel – possibly correctly – that support for multiplexing and binary data should be added. That would obviously increase the complexity but in some cases might be worth the cost. But more on that later.

    Bi-directional Communication

    One of the key aspects of WebSocket is its support for simple bi-directional communication. Servers can easily send updates to clients and clients can send updates to servers. Many of the comet-style applications that people have built will be much simpler and faster with this model because the protocol and API support it directly.

    While allowing for bi-directional communication it also is bound by the HTTP same-origin model. That is, it’s doesn’t give the browser the ability to connect to any site on any port it wants to.

    So WebSocket is really TCP with the HTTP security model.

    Low-latency

    This is actually the primary value in WebSockets. The key thing is that the cost of sending a small amount of data is also very small. It’s possible to do bi-directional communication today with comet-style applications, but small amounts of data often require a huge amount of overhead to do so.

    A second-hand story to give you a sense of scale: Google Wave, which tries to do real-time communication with keystrokes has a several-kilobyte overhead for just about every keystroke because of the TCP startup, teardown and HTTP message headers involved with what should be only a few bytes sent over the wire.

    I haven’t tried, but I’m going to guess that if you built Quake on top of HTTP comet that the interactive experience would be poor. So this is where WebSockets really shine.

    Simple API

    The actual API that a developer sees for WebSocket is relatively simple. You can send messages, you can get messages, you get events when sockets open, close or there’s an error. Additional complexity, which I’m sure others will develop, will happen in JavaScript and backend libraries.

    (While this might seem like punting on the issue of complexity, this is actually the model for success we’ve seen for other browser standards: build something relatively simple that others can experiment with. When we understand what’s slow or what’s preventing progress, iterate and improve.)

    When will it be in Firefox?

    We really really want to support WebSockets in the next version of Firefox. And a lot of other people want us to include support too.

    The first set of test patches, written by the wonderful Wellington Fernando de Macedo (one of our most excellent contributors!) was first submitted in April of 2009. Since then we’ve been iterating both on the patches themselves and following the spec as it’s changed.

    Unfortunately, the spec itself is still under revision. WebSockets did ship in Chrome with version 4 and I’m told by Chrome developers that it’s going to be included in Chrome 5, without changes. Unfortunately, the version that Google included in Chrome doesn’t reflect the current draft. The handshake for how to start a WebSocket connection has changed, largely to improve security on servers. There’s also a lot of ongoing discussion on the role of integrated compression, direct support for binary data (instead of encoding binary data as strings), whether or not the protocol should support multiplexing and a number of other issues.

    Since WebSocket isn’t used widely yet, and that Chrome has an uptake rate that’s similar to Firefox, the hope is that once a more recent draft makes it through the process that both Chrome and Firefox can include a more recent version at around the same time.

    So in short: we want to ship it because the promise of WebSockets is great, but we’ll have to see if it’s stable and safe enough to do so. Code isn’t the issue – we’ve had that for a while. It’s whether or not there’s consensus on if the protocol is “done enough” to ship it to a few hundred million people.

  9. CSS 3D transformations in Firefox Nightly

    When the first 3D transformations in CSS got support on Webkit browsers people got incredibly excited about them. Now that they have matured we also support 3D CSS in Firefox. To see it for yourself, check out one of the latest nightly builds.

    You can see them in action in this demo of a rotating HTML5 logo and the screencast below:

    This means now that we need your support in trying out CSS 3D examples in Firefox and add other extensions than -webkit- to your CSS 3D products and demos. To show that this is possible, we took the well-known webkit-only “poster circle” demo and made it work with Firefox nightly by adding the -moz- (and of course the other prefixes and one set of instructions without browser prefixes). Here is a slight excerpt:

    -webkit-transform-style: preserve-3d;
    -moz-transform-style: preserve-3d;
    -o-transform-style: preserve-3d;
    -ms-transform-style: preserve-3d;
    transform-style: preserve-3d;
    

    You can see this in action in the screencast below alongside Chrome and you try the demo out yourself. The slight jerkiness is actually my MacBook Air impersonating a starting jet every time I use ScreenFlow and not the browser.

    To celebrate the release and to show how CSS 3D can be applied as subtle effect, have a game of pairs using your favourite browsers (and a cat) :

    browser pairs

    Oleg Romashin also spent some time to convert a few CSS 3D demos to work with Mozilla and you can check the 3D city for more “wow”.

    If you are new to CSS 3D transformations here’s a good beginner course and a tool to create them.

    The rotating HTML5 logo demo also shows how you can check if the currently used browser supports 3D transforms. Instead of repeating the animation frames for all the prefixes we test in JavaScript and create the CSS on the fly:

    function checksupport() {
      var props = ['perspectiveProperty', 'WebkitPerspective',
                   'MozPerspective', 'OPerspective', 'msPerspective'],
          i = 0,
          support = false;
      while (props[i]) {
        if (props[i] in form.style) {
          support = true;
          pfx = props[i].replace('Perspective','');
          pfx = pfx.toLowerCase();
          break;
        }
        i++;
      }
      return support;
    }
    if (checksupport()) {
      var s = '';
      styles = document.createElement('style');
      s += '#stage{-'+ pfx +'-perspective: 300px;}'+
           '#logo{-'+ pfx +'-transform-style: preserve-3d;position:relative;}'+
           '#logo.spin{-'+ pfx +'-animation: spin 3s infinite linear;}'+
           '@-'+ pfx +'-keyframes spin {'+
           '0% {'+
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);'+
           '}'+
           '100% {'+
           '-'+ pfx +'-transform: rotateX(0deg) rotateY(360deg)'+
           ' rotateZ(360deg);'+
           '}}';
      styles.innerHTML = s;
      document.querySelector('head').appendChild(styles);
    }
    

    For more information on creating your own pages that use 3D transformations, take a look at the draft specification

    As always, If you find any bugs, please report them at bugzilla.mozilla.org!

    So please reward our hard work bringing the third dimension to Firefox’s CSS engine by supporting and testing. Cheers!

  10. W3C FileAPI in Firefox 3.6

    Often, web applications will prompt the user to select a file, typically to upload to a server. Unless the web application makes use of a plugin, file selection occurs through an HTML input element, of the sort <input type="file"/>. Firefox 3.6 now supports much of the W3C File API, which specifies the ability to asynchronously read the selected file into memory, and perform operations on the file data within the web application (for example, to display a thumbnail preview of an image, before it is uploaded, or to look for ID3 tags within an MP3 file, or to look for EXIF data in JPEG files, all on the client side). This is a new API, and replaces the file API that was introduced in Firefox 3.

    It is important to note that even before the advent of the W3C File API draft (which only became a Working Draft in November 2009), Firefox 3 and later provide the ability to read files into memory synchronously but that capability should be considered deprecated in favor of the new implementation in Firefox 3.6 of the asynchronous File API. The deprecated API allowed you synchronously access a file:

    // After obtaining a handle to a file
    // access the file data
    var dataURL = file.getAsDataURL();
    img.src = dataURL;

    While Firefox 3.6 will continue to support code usage of the sort above, it should be considered deprecated since it reads files synchronously on the main thread. For large files, this could result in blocking on the result of the read, which isn’t desirable. Moreover, the file object itself provides a method to read from it, rather than having a separate reader object. These considerations informed the technical direction of the new File API in Firefox 3.6 (and the direction of the specification). The rest of this article is about the newly introduced File API.

    Accessing file selections

    Firefox 3.6 supports multiple file selections on an input element, and returns all the files selected using the FileList interface. Previous versions of Firefox only supported one selection of a file using the input element. Additionally, the FileList interface is also exposed to the HTML5 Drag and Drop API as a property of the DataTransfer interface. Users can drag and drop multiple files to a drop target within a web page as well.

    The following HTML spawns the standard file picker, with which you can select multiple files:

    Note that if you don’t use the multiple attribute, you only enable single file selection.

    You can work with all the selected files obtained either through the file picker (using the input element) or through the DataTransfer object by iterating through the FileList:

    var files = document.getElementById("inputFiles").files;
    
    // or, for a drag event e:
    // var dt = e.dataTransfer; var files = dt.files
    
    for (var i = 0; i < files.length; i++) {
      var file = files[i];
      handleFile(file);
    
    }

    Properties of files

    Once you obtain a reference to an individually selected file from a FileList, you get a File object, which has name, type, and size properties. Continuing with the code snippet above:

    function handleFile(file) {
        // RegExp for JPEG mime type
        var imageType = /image/jpeg/;
    
        // Check if match
        if (!file.type.match(imageType)) {
            return false;
        }
       // Check if the picture exceeds set limit
       if(file.size > maxSize) {
          alert("Choose a smaller photo!");
          return false;
       }
      // Add file name to page
      var picData = document.createTextNode(file.name);
      dataGrid.appendChild(picData);
      return true;
    }

    The size attribute is the file's size, in bytes. The name attribute is the file's name, without path information. The type attribute is an ASCII-encoded string in lower case representing the media type of the file, expressed as an RFC2046 MIME type. The type attribute in particular is useful in sniffing file type, as in the example above, where the script determines if the file in question is a JPEG file. If Firefox 3.6 cannot determine the file's type, it will return the empty string.

    Reading Files

    Firefox 3.6 and beyond support the FileReader object to read file data asynchronously into memory, using event callbacks to mark progress. The object is instantiated in the standard way:

    var binaryReader = new FileReader();

    Event handler attributes are used to work with the result of the file read operation. For very large files, it is possible to watch for progress events as the file is being read into memory (using the onprogress event handler attribute to set the event handler function). This is useful in scenarios where the drives in question may not be local to the hardware, or if the file in question is particularly big.

    The FileReader object supports three methods to read files into memory. Each allows programmatic access to the files data in a different format, though in practice only one read method should be called on a given FileReader object:

    • filereader.readAsBinaryString(file); will asynchronously return a binary string with each byte represented by an integer in the range [0..255]. This is useful for binary manipulations of a file's data, for example to look for ID3 tags in an MP3 file, or to look for EXIF data in a JPEG image.
    • filereader.readAsText(file, encoding); will asynchronously return a string in the format solicited by the encoding parameter (for example encoding = "UTF-8"). This is useful for working with a text file, for example to parse an XML file.
    • filereader.readAsDataURL(file); will asynchronously return a Data URL. Firefox 3.6 allows large URLs, and so this feature is particularly useful when a URL could help display media content in a web page, for example for image data, video data, or audio data.

    An example helps tie this all together:

    if (files.length > 0) {
        if (!handleFile(files[0])) {
            invalid.style.visibility="visible";
            invalid.msg = "Select a JPEG Image";
         }
    }
    
    var binaryReader = new FileReader();
    binaryReader.onload = function(){
       var exif = findEXIFInJPG(binaryReader.result);
       if (!exif) {
          // ...set up conditions for lack of data
       }
       else {
        // ...write out exif data
       }
    
    binaryReader.onprogress = updateProgress;
    binaryReader.onerror = errorHandler;
    
    binaryReader.readAsBinaryString(file);
    
    function updateProgress(evt){
       // use lengthComputable, loaded, and total on ProgressEvent
       if (evt.lengthComputable) {
              var loaded = (evt.loaded / evt.total);
              if (loaded < 1) {
                // update progress meter
                progMeter.style.width = (loaded * 200) + "px";
              }
       }
    }
    
    function errorHandler(evt) {
      if(evt.target.error.code == evt.target.error.NOT_FOUND_ERR) {
       alert("File Not Found!");
      }
    }

    In order to work with binary data, the use of the charCodeAt function exposed on strings will be particularly useful. For instance, an utility of the sort:

    function getByteAt(file, idx) {
        return file.charCodeAt(idx);
    }

    allows extraction of the Unicode value of the character at the given index.

    An example of similar code in action in Firefox 3.6, including use of the readAsDataURL method to render an image, as well as binary analysis of a JPEG for EXIF detection (using the readAsBinaryString method), can be found in Paul Rouget's great demo of the File API..

    A word on the specification

    The existence of a W3C public working draft of the File API holds the promise of other browsers implementing it shortly. Firefox 3.6's implementation is fairly complete, but is missing some of the technology mentioned in the specification. Notably, the urn feature on the File object isn't yet implemented, and neither is the ability to extract byte-ranges of files using the slice method. A synchronous way to read files isn't yet implemented as part of Worker Threads. These features will come in future versions of Firefox.

    References