Mozilla

SVG Articles

Sort by:

View:

  1. SVG & colors in OpenType fonts

    Sample of a colorfont

    Prolog

    Until recently having more than one color in a glyph of a vector font was technically not possible. Getting a polychrome letter required multiplying the content for every color. Like it happened with many other techniques before, it took some time for digital type to overcome the constraints of the old technique. When printing with wood or lead type the limitation to one color per glyph is inherent (if you don’t count random gradients). More than one color per letter required separate fonts for the differently colored parts and a new print run for every color. This has been done beautifully and pictures of some magnificent examples are available online. Using overprinting the impression of three colors can be achieved with just two colors.

    Overprinting colors
    Simulation of two overprinting colors resulting in a third.

    Digital font formats kept the limitation to one ‘surface’ per glyph. There can be several outlines in a glyph but when the font is used to set type the assigned color applies to all outlines. Analog to letterpress the content needs to be doubled and superimposed to have more than one color per glyph. Multiplying does not sound like an elegant solution and it is a constant source of errors.

    It took some emojis until the demand for multi-colored fonts was big enough to develop additional tables to store this information within OpenType fonts. As of this writing there are several different ways to implement this. Adam Twardoch compares all proposed solutions in great detail on the FontLab blog.

    To me the Adobe/Mozilla way looks the most intriguing.

    Upon its proposal it was discussed by a W3C community group and published as a stable document. The basic idea is to store the colored glyphs as svgs in the OpenType font. Of course this depends on the complexity of your typeface but svgs should usually result in a smaller file size than pngs. With the development of high resolution screens vectors also seem to be a better solution than pixels. The possibility to animate the svgs is an interesting addition and will surely be used in interesting (and very annoying) ways. BLING BLING.

    Technique

    I am not a font technician or a web developer just very curious about this new developments. There might be other ways but this is how I managed to build colorful OpenType fonts.

    In order to make your own you will need a font editor. There are several options like RoboFont and Glyphs (both Mac only), FontLab and the free FontForge. RoboFont is the editor of my choice, since it is highly customizable and you can build your own extensions with python. In a new font I added as many new layers as the amount of colors I wanted to have in the final font. Either draw in the separate layers right away or just copy the outlines into the respective layer after you’ve drawn them in the foreground layer. With the very handy Layer Preview extension you can preview all Layers overlapping. You can also just increase the size of the thumbnails in the font window. At some point they will show all layers. Adjust the colors to your liking in the Inspector since they are used for the preview.

    RoboFont Inspector
    Define the colors you want to see in the Layer Preview

    A separated letter
    Layer preview
    The outlines of the separate layers and their combination

    When you are done drawing your outlines you will need to safe a ufo for every layer / color. I used a little python script to safe them in the same place as the main file:

    f = CurrentFont()
    path = f.path
     
    for layer in f.layerOrder:
    newFont = RFont()
     
    for g in f:
        orig = g.getLayer(layer)
        newFont.newGlyph(g.name)
        newFont[g.name].appendGlyph(orig)
        newFont[g.name].width = orig.width
        newFont[g.name].update()
     
    newFont.info.familyName = f.info.familyName
    newFont.info.styleName = layer
    newFont.save(destDir = path[:-4] +"_%s" % layer +".ufo")
    newFont.close()
     
    print "Done Splitting"

    Once I had all my separate ufos I loaded them into TransType from FontLab. Just drop your ufos in the main window and select the ones you want to combine. In the Effect menu click ‘Overlay Fonts …’. You get a preview window where you can assign a rgba value for each ufo and then hit OK. Select the newly added font in the collection and export it as OpenType (ttf). You will get a folder with all colorfont versions.

    TransType
    The preview of your colorfont in TransType.

    RoboChrome

    In case you don’t want to use TransType you might have a look at the very powerful RoboFont extension by Jens Kutílek called RoboChrome. You will need a separate version of your base-glyph for every color, which can also be done with a scipt if you have all of your outlines in layers.

    f = CurrentFont()
    selection = f.selection
     
    for l, layer in enumerate(f.layerOrder):
    for g in selection:
        char = f[g]
        name = g + ".layer%d" % l
        f.newGlyph(name)
        f[name].width = f[g].width
        l_glyph = f[g].getLayer(layer)
        f[name].appendGlyph(l_glyph)
        f[name].mark = (.2, .2, .2, .2)
     
    print "Done with the Devision"

    For RoboChrome you will need to split your glyph into several.

    Fonttools

    You can also modify the svg table of a compiled font or insert your own if it does not have any yet. To do so I used the very helpful fonttools by Just van Rossum. Just generate a otf or ttf with the font editor of your choice. Open the Terminal and type ttx if you are on Mac OS and have fonttools installed. Drop the font file in the Terminal window and hit return. Fonttools will convert your font into an xml (YourFontName.ttx) in the same folder. This file can then be opened, modified and recompiled into a otf or ttf.

    This can be quite helpful to streamline the svg compiled by a program and therefore reduce the file size. I rewrote the svg of a 1.6mb font to get it down to 980kb. Using it as a webfont that makes quite a difference. If you want to add your own svg table and font that does not have any yet you might read a bit about the required header information. The endGlyphID and startGlyphID for the glyph you want to supply with svg data can be found in the <GlyphOrder> Table.

    <svg>
    <svgDoc endGlyphID="18" startGlyphID="18">
        <![CDATA[
        <!-- here goes your svg -->
        ]]>
    </svgDoc>
    <svgDoc endGlyphID="19" startGlyphID="19">...</svgDoc>
    <svgDoc endGlyphID="20" startGlyphID="20">...</svgDoc>
    ...
    <colorPalettes></colorPalettes>
    </svg>

    One thing to keep in mind is the two different coordinate systems. Contrary to a digital font svg has a y-down axis. So you either have to draw in the negative space or you draw reversed and then mirror everything with:

    transform="scale(1,-1)"
    Y-axis comparison
    While typefaces usually have a y-up axis SVG uses y-down.

    Animation

    Now if you really want to pimp your fonts you should add some unnecessary animation to annoy everybody. Just insert it between the opening and closing tags of whatever you want to modify. Here is an example of a circle changing its fill-opacity from zero to 100% over a duration of 500ms in a loop.

    <circle>
    <animate    attributeName="fill-opacity"
                begin="0"
                dur="500ms"
                from="0"
                to="1"
                repeatCount="indefinite"/>
    </circle>

    Implementation

    Technically these fonts should work in any application that works with otfs or ttfs. But as of this writing only Firefox shows the svg. If the rendering is not supported the application will just use the regular glyph outlines as a fallback. So if you have your font(s) ready it’s time to write some css and html to test and display them on a website.

    The @font-face

    @font-face {
    font-family: "Colors-Yes"; /* reference name */
    src: url('./fonts/Name_of_your_font.ttf');
    font-weight: 400; /* or whatever applies */
    font-style: normal; /* or whatever applies */
    text-rendering: optimizeLegibility; /* maybe */
    }

    The basic css

    .color_font { font-family: "Colors-Yes"; }

    The HTML

    <p class="color_font">Shiny polychromatic text</p>

    Restrictions

    As of this writing (October 2014) the format is supported by Firefox (26+) only. Since this was initiated by Adobe and Mozilla there might be a broader support in the future.

    While using svg has the advantage of reasonably small files and the content does not have to be multiplied it brings one major drawback. Since the colors are ‘hard-coded’ into the font there is no possibility to access them with css. Hopefully this might change with the implementation of a <COLR/CPAL> table.

    There is a bug that keeps animations from being played in Firefox 32. While animations are rendered in the current version (33) this might change for obvious reasons.

    Depending how you establish your svg table it might blow up and result in fairly big files. Be aware of that in case you use them to render the most crucial content of your websites.

    Examples

    Links, Credits & Thanks

    Thanks Erik, Frederik, Just and Tal for making great tools!

  2. Koalas to the Max – a case study

    One day I was browsing reddit when I came across this peculiar link posted on it: http://www.cesmes.fi/pallo.swf

    The game was addictive and I loved it but I found several design elements flawed. Why did it start with four circles and not one? Why was the color split so jarring? Why was it written in flash? (What is this, 2010?) Most importantly, it was missing a golden opportunity to split into dots that form an image instead of just doing random colors.

    Creating the project

    This seemed like a fun project, and I reimplemented it (with my design tweaks) using D3 to render with SVG.

    The main idea was to have the dots split into the pixels of an image, with each bigger dot having the average color of the four dots contained inside of it recursively, and allow the code to work on any web-based image.
    The code sat in my ‘Projects’ folder for some time; Valentines day was around the corner and I thought it could be a cute gift. I bought the domain name, found a cute picture, and thus “koalastothemax.com (KttM)” was born.

    Implementation

    While the user-facing part of KttM has changed little since its inception, the implementation has been revisited several times to incorporate bug fixes, improve performance, and bring support to a wider range of devices.

    Notable excerpts are presented below and the full code can be found on GitHub.

    Load the image

    If the image is hosted on koalastothemax.com (same) domain then loading it is as simple as calling new Image()

    var img = new Image();
    img.onload = function() {
     // Awesome rendering code omitted
    };
    img.src = the_image_source;

    One of the core design goals for KttM was to let people use their own images as the revealed image. Thus, when the image is on an arbitrary domain, it needs to be given special consideration. Given the same origin restrictions, there needs to be a image proxy that could channel the image from the arbitrary domain or send the image data as a JSONP call.

    Originally I used a library called $.getImageData but I had to switch to a self hosted solution after KttM went viral and brought the $.getImageData App Engine account to its limits.

    Extract the pixel data

    Once the image loads, it needs to be resized to the dimensions of the finest layer of circles (128 x 128) and its pixel data can be extracted with the help of an offscreen HTML5 canvas element.

    koala.loadImage = function(imageData) {
     // Create a canvas for image data resizing and extraction
     var canvas = document.createElement('canvas').getContext('2d');
     // Draw the image into the corner, resizing it to dim x dim
     canvas.drawImage(imageData, 0, 0, dim, dim);
     // Extract the pixel data from the same area of canvas
     // Note: This call will throw a security exception if imageData
     // was loaded from a different domain than the script.
     return canvas.getImageData(0, 0, dim, dim).data;
    };

    dim is the number of smallest circles that will appear on a side. 128 seemed to produce nice results but really any power of 2 could be used. Each circle on the finest level corresponds to one pixel of the resized image.

    Build the split tree

    Resizing the image returns the data needed to render the finest layer of the pixelization. Every successive layer is formed by grouping neighboring clusters of four dots together and averaging their color. The entire structure is stored as a (quaternary) tree so that when a circle splits it has easy access to the dots from which it was formed. During construction each subsequent layer of the tree is stored in an efficient 2D array.

    // Got the data now build the tree
    var finestLayer = array2d(dim, dim);
    var size = minSize;
     
    // Start off by populating the base (leaf) layer
    var xi, yi, t = 0, color;
    for (yi = 0; yi < dim; yi++) {
     for (xi = 0; xi < dim; xi++) {
       color = [colorData[t], colorData[t+1], colorData[t+2]];
       finestLayer(xi, yi, new Circle(vis, xi, yi, size, color));
       t += 4;
     }
    }

    Start by going through the color data extracted in from the image and creating the finest circles.

    // Build up successive nodes by grouping
    var layer, prevLayer = finestLayer;
    var c1, c2, c3, c4, currentLayer = 0;
    while (size < maxSize) {
     dim /= 2;
     size = size * 2;
     layer = array2d(dim, dim);
     for (yi = 0; yi < dim; yi++) {
       for (xi = 0; xi < dim; xi++) {
         c1 = prevLayer(2 * xi    , 2 * yi    );
         c2 = prevLayer(2 * xi + 1, 2 * yi    );
         c3 = prevLayer(2 * xi    , 2 * yi + 1);
         c4 = prevLayer(2 * xi + 1, 2 * yi + 1);
         color = avgColor(c1.color, c2.color, c3.color, c4.color);
         c1.parent = c2.parent = c3.parent = c4.parent = layer(xi, yi,
           new Circle(vis, xi, yi, size, color, [c1, c2, c3, c4], currentLayer, onSplit)
         );
       }
     }
     splitableByLayer.push(dim * dim);
     splitableTotal += dim * dim;
     currentLayer++;
     prevLayer = layer;
    }

    After the finest circles have been created, the subsequent circles are each built by merging four dots and doubling the radius of the resulting dot.

    Render the circles

    Once the split tree is built, the initial circle is added to the page.

    // Create the initial circle
    Circle.addToVis(vis, [layer(0, 0)], true);

    This employs the Circle.addToVis function that is used whenever the circle is split. The second argument is the array of circles to be added to the page.

    Circle.addToVis = function(vis, circles, init) {
     var circle = vis.selectAll('.nope').data(circles)
       .enter().append('circle');
     
     if (init) {
       // Setup the initial state of the initial circle
       circle = circle
         .attr('cx',   function(d) { return d.x; })
         .attr('cy',   function(d) { return d.y; })
         .attr('r', 4)
         .attr('fill', '#ffffff')
           .transition()
           .duration(1000);
     } else {
       // Setup the initial state of the opened circles
       circle = circle
         .attr('cx',   function(d) { return d.parent.x; })
         .attr('cy',   function(d) { return d.parent.y; })
         .attr('r',    function(d) { return d.parent.size / 2; })
         .attr('fill', function(d) { return String(d.parent.rgb); })
         .attr('fill-opacity', 0.68)
           .transition()
           .duration(300);
     }
     
     // Transition the to the respective final state
     circle
       .attr('cx',   function(d) { return d.x; })
       .attr('cy',   function(d) { return d.y; })
       .attr('r',    function(d) { return d.size / 2; })
       .attr('fill', function(d) { return String(d.rgb); })
       .attr('fill-opacity', 1)
       .each('end',  function(d) { d.node = this; });
    }

    Here the D3 magic happens. The circles in circles are added (.append('circle')) to the SVG container and animated to their position. The initial circle is given special treatment as it fades in from the center of the page while the others slide over from the position of their “parent” circle.

    In typical D3 fashion circle ends up being a selection of all the circles that were added. The .attr calls are applied to all of the elements in the selection. When a function is passed in it shows how to map the split tree node onto an SVG element.

    .attr('cx', function(d) { return d.parent.x; }) would set the X coordinate of the center of the circle to the X position of the parent.

    The attributes are set to their initial state then a transition is started with .transition() and then the attributes are set to their final state; D3 takes care of the animation.

    Detect mouse (and touch) over

    The circles need to split when the user moves the mouse (or finger) over them; to be done efficiently the regular structure of the layout can be taken advantage of.

    The described algorithm vastly outperforms native “onmouseover” event handlers.

    // Handle mouse events
    var prevMousePosition = null;
    function onMouseMove() {
     var mousePosition = d3.mouse(vis.node());
     
     // Do nothing if the mouse point is not valid
     if (isNaN(mousePosition[0])) {
       prevMousePosition = null;
       return;
     }
     
     if (prevMousePosition) {
       findAndSplit(prevMousePosition, mousePosition);
     }
     prevMousePosition = mousePosition;
     d3.event.preventDefault();
    }
     
    // Initialize interaction
    d3.select(document.body)
     .on('mousemove.koala', onMouseMove)

    Firstly a body wide mousemove event handler is registered. The event handler keeps track of the previous mouse position and calls on the findAndSplit function passing it the line segments traveled by the user’s mouse.

    function findAndSplit(startPoint, endPoint) {
     var breaks = breakInterval(startPoint, endPoint, 4);
     var circleToSplit = []
     
     for (var i = 0; i < breaks.length - 1; i++) {
       var sp = breaks[i],
           ep = breaks[i+1];
     
       var circle = splitableCircleAt(ep);
       if (circle && circle.isSplitable() && circle.checkIntersection(sp, ep)) {
         circle.split();
       }
     }
    }

    The findAndSplit function splits a potentially large segment traveled by the mouse into a series of small segments (not bigger than 4px long). It then checks each small segment for a potential circle intersection.

    function splitableCircleAt(pos) {
     var xi = Math.floor(pos[0] / minSize),
         yi = Math.floor(pos[1] / minSize),
         circle = finestLayer(xi, yi);
     if (!circle) return null;
     while (circle && !circle.isSplitable()) circle = circle.parent;
     return circle || null;
    }

    The splitableCircleAt function takes advantage of the regular structure of the layout to find the one circle that the segment ending in the given point might be intersecting. This is done by finding the leaf node of the closest fine circle and traversing up the split tree to find its visible parent.

    Finally the intersected circle is split (circle.split()).

    Circle.prototype.split = function() {
     if (!this.isSplitable()) return;
     d3.select(this.node).remove();
     delete this.node;
     Circle.addToVis(this.vis, this.children);
     this.onSplit(this);
    }

    Going viral

    Sometime after Valentines day I meet with Mike Bostock (the creator of D3) regarding D3 syntax and I showed him KttM, which he thought was tweet-worthy – it was, after all, an early example of a pointless artsy visualization done with D3.

    Mike has a twitter following and his tweet, which was retweeted by some members of the Google Chrome development team, started getting some momentum.

    Since the koala was out of the bag, I decided that it might as well be posted on reddit. I posted it on the programing subreddit with the tile “A cute D3 / SVG powered image puzzle. [No IE]” and it got a respectable 23 points which made me happy. Later that day it was reposted to the funny subreddit with the title “Press all the dots :D” and was upvoted to the front page.

    The traffic went exponential. Reddit was a spike that quickly dropped off, but people have picked up on it and spread it to Facebook, StumbleUpon, and other social media outlets.

    The traffic from these sources decays over time but every several months KttM gets rediscovered and traffic spikes.

    Such irregular traffic patterns underscore the need to write scalable code. Conveniently KttM does most of the work within the user’s browser; the server needs only to serve the page assets and one (small) image per page load allowing KttM to be hosted on a dirt-cheap shared hosting service.

    Measuring engagement

    After KttM became popular I was interested in exploring how people actually interacted with the application. Did they even realize that the initial single circle can split? Does anyone actually finish the whole image? Do people uncover the circles uniformly?

    At first the only tracking on KttM was the vanilla GA code that tracks pageviews. This quickly became underwhelming. I decided to add custom event tracking for when an entire layer was cleared and when a percentage of circles were split (in increments of 5%). The event value is set to the time in seconds since page load.

    As you can see such event tracking offers both insights and room for improvement. The 0% clear event is fired when the first circle is split and the average time for that event to fire seems to be 308 seconds (5 minutes) which does not sound reasonable. In reality this happens when someone opens KttM and leaves it open for days then, if a circle is split, the event value would be huge and it would skew the average. I wish GA had a histogram view.

    Even basic engagement tracking sheds vast amounts of light into how far people get through the game. These metrics proved very useful when the the mouse-over algorithm was upgraded. I could, after several days of running the new algorithm, see that people were finishing more of the puzzle before giving up.

    Lessons learned

    While making, maintaining, and running KttM I learned several lessons about using modern web standards to build web applications that run on a wide range of devices.

    Some native browser utilities give you 90% of what you need, but to get your app behaving exactly as you want, you need to reimplement them in JavaScript. For example, the SVG mouseover events could not cope well with the number of circles and it was much more efficient to implement them in JavaScript by taking advantage of the regular circle layout. Similarly, the native base64 functions (atob, btoa) are not universally supported and do not work with unicode. It is surprisingly easy to support the modern Internet Explorers (9 and 10) and for the older IEs Google Chrome Frame provides a great fallback.

    Despite the huge improvements in standard compliance it is still necessary to test the code on a wide variety of browsers and devices, as there are still differences in how certain features are implemented. For example, in IE10 running on the Microsoft Surface html {-ms-touch-action: none; } needed to be added to allow KttM to function correctly.

    Adding tracking and taking time to define and collect the key engagement metrics allows you to evaluate the impact of changes that get deployed to users in a quantitative manner. Having well defined metrics allows you to run controlled tests to figure out how to streamline your application.

    Finally, listen to your users! They pick up on things that you miss – even if they don’t know it. The congratulations message that appears on completion was added after I received complaints that is was not clear when a picture was fully uncovered.

    All projects are forever evolving and if you listen to your users and run controlled experiments then there is no limit to how much you can improve.

  3. The Web Developer Toolbox: Raphaël

    This is the first of a series of articles dedicated to the useful libraries that all web developers should have in their toolbox. My intent is to show you what those libraries can do and help you to use them at their best. This first article is dedicated to the Raphaël library.

    Introduction

    Raphaël is a library originally written by Dmitry Baranovskiy and is now part of Sencha Labs.

    The goal of this library is to simplify work with vector graphics on the Web. Raphaël relies on the SVG W3C Recommendation (which is well supported in all modern browsers) and falls back to the Micrsoft VML language in order to address legacy versions of Internet Explorer. It also tries to harmonize some working issues across SVG implementations such as the SVG Animations. As a consequence, Raphaël is a very nice wrapper to produce consistent kick-ass graphics all over the Web.

    Basic usage

    The library has very good documentation with many examples. Do not hesitate to use it extensively.

    The following example will draw a simple red circle inside an HTML element with the id “myPaper”.

    // the following example creates a drawing zone
    // that is 100px wide by 100px high.
    // This drawing zone is created at the top left corner
    // of the #myPaper element (or its top right corner in
    // dir="rtl" elements)
    var paper = Raphael("myPaper", 100, 100);
     
    // The circle will have a radius of 40
    // and its center will be at coordinate 50,50
    var c = paper.circle(50, 50, 40);
     
    // The circle will be filled with red
    // Note that the name of each element property
    // follow the SVG recommendation
    c.attr({
        fill: "#900"
    });

    Advanced usage

    Despite the fact that Raphaël reduces the possibilities offered by SVG (mainly because of the VML fallback) it allows one to perform very advanced stuff:

    • Advance Matrix transformation
    • Advance event handler
    • Cross browser animations
    • Easy drag system
    • Path intersection detection

    Raphaël is also extensible through an extension system that allows you to build custom functions.

    For example, here’s an extension to draw pie charts:

    /**
     * Pie method
     *
     * cx: x position of the rotating center of the pie
     * cy: y position of the rotating center of the pie
     * r : radius of the pie
     * a1: angle expressed in degrees where the pie start
     * a2: angle expressed in degrees where the pie end
     */
    Raphael.fn.pie = function (cx, cy, r, a1, a2) {
        var d,
            flag = (a2 - a1) &gt; 180;
     
        a1 = (a1 % 360) * Math.PI / 180;
        a2 = (a2 % 360) * Math.PI / 180;
     
        d = [
            // Setting the rotating axe of the pie
            "M", cx, cy,
     
            // Go to the start of the curve
            "l", r * Math.cos(a1), r * Math.sin(a1),
     
            // Drawing the curve to its end
            "A", r, r, "0", +flag, "1",
            cx + r * Math.cos(a2), cy + r * Math.sin(a2),
     
            // Closing the path
            "z"
        ];
     
        return this.path(d.join(' '));
    };

    Note: In the example above, you have to be familiar with the SVG path syntax (Raphaël will convert it to the VML syntax under the hood), but once it’s done you can reuse it as any other Raphaël primitive. Look at this extension working to draw a color wheel on jsFiddle.

    JSFiddle demo.

    Limits and precaution

    If you are not familiar with SVG and/or want to support legacy MS Internet Explorer browsers, this tool is made for you. However, it’s a JavaScript library, which means that you have to know JavaScript to use it. You cannot use SVG and ask Raphaël to parse it and interpret it (to do that, it exists other libraries).

    In terms of browser support, Raphaël gives you a large base. Raphaël currently supports Firefox 3.0+, Safari 3.0+, Chrome 5.0+, Opera 9.5+ and Internet Explorer 6.0+.

    In fact, the only browser that can not take advantage of Raphaël is the native browser for Android 1.x and 2.x (and obviously many feature phone browsers). This is due to the fact that those browsers do not support any vector language. Android starts (partially) supporting SVG with Android 3.0 so take care if you want to work with all mobile devices.

    Conclusion

    Raphaël was the first library to allow web designers and web developers to use SVG in the wild. If you want to write some nice applications without the need of the full SVG DOM API or if you have to support legacy browsers, this library will give you some power.

    In conclusion, here are some cool usages of Raphaël:

  4. Foxkeh's Wallpaper Creator: practical SVG application

    When we make graphical web applications, we may use Canvas and SVG. Comparing SVG with Canvas, SVG is suitable to make applications with these features:

    • use large images with smooth lines (SVG is vector graphics)
    • edit size, position, shape or colors of images (easy to change)
    • clip, mask or filter images (SVG supports these features)
    • user interactive objects (DOM events can be added to SVG elements)

    To demonstrate these advantages of SVG, Mozilla Japan has made a practical web application with SVG. “Foxkeh’s Wallpaper Creator” is a tool that allows you to easily create your own wallpaper in your browser. Not only can you choose Foxkeh and background image, you can easily change the size, position and transparency of Foxkeh and calender image.

    I believe this application is enough easy to use and no more explanation is needed.

    Just try creating wallpaper and realize how SVG is useful for web applications!

    http://wallpapers.foxkeh.com/en/

    Screenshot of Foxkeh's Wallpaper Creator

  5. Firefox 4: the HTML5 parser – inline SVG, speed and more

    This is a guest post from Henri Sivonen, who has been working on Firefox’s new HTML5 parser. The HTML parser is one of the most complicated and sensitive pieces of a browser. It controls how your HTML source is turned into web pages and as such changes to it are rare and need to be well-tested. While most of Gecko has been rebuilt since its initial inception in the late 90s, the parser was one of the stand-outs as being “original.” This replaces that code with a new parser that’s faster, compliant with the new HTML5 standard and enables a lot of new functionality as well.

    A project to replace Gecko’s old HTML parser, dating from 1998, has been ongoing for some time now. The parser was just turned on by default on the trunk, so you can now try it out by simply downloading a nightly build without having to flip any configuration switch.

    There are four main things that improve with the new HTML5 parser:

    • You can now use SVG and MathML inline in HTML5 pages, without XML namespaces.
    • Parsing is now done off Firefox’s main UI thread, improving overall browser responsiveness.
    • It’s improved the speed of innerHTML calls by about 20%.
    • With the landing of the new parser we’ve fixed dozens of long-standing parser related bugs.

    Try the demo with a Firefox Nightly or another HTML5-ready browser. It should look like this:

    What Is It?

    The HTML5 parser in Gecko turns a stream of bytes into a DOM tree according to the HTML5 parsing algorithm.

    HTML5 is the first specification that tells implementors, in detail, how parse HTML. Before HTML5, HTML specifications didn’t say how to turn a stream of bytes into a DOM tree. In theory, HTML before HTML5 was supposed to be defined in terms of SGML. This implied a certain relationship between the source of valid HTML documents and the DOM. However, parsing wasn’t well-defined for invalid documents (and Web content most often isn’t valid HTML4) and there are SGML constructs that were in theory part of HTML but that in reality popular browsers didn’t implement.

    The lack of a proper specification led to browser developers filling in the blanks on their own and reverse engineering the browser with the largest market share (first Mosaic, then Netscape, then IE) when in doubt about how to get compatible behavior. This led to a lot of unwritten common rules but also to different behavior across browsers.

    The HTML5 parsing algorithm standardizes well-defined behavior that browsers and other applications that consume HTML can converge on. By design, the HTML5 parsing algorithm is suitable for processing existing HTML content, so applications don’t need to continue maintaining their legacy parsers for legacy content. Concretely, in the trunk nightlies, the HTML5 parser is used for all text/html content.

    How Is It Different?

    The HTML5 parsing algorithm has two major parts: tokenization and tree building. Tokenization is the process of splitting the source stream into tags, text, comments and attributes inside tags. The tree building phase takes the tags and the interleaving text and comments and builds the DOM tree. The tokenization part of the HTML5 parsing algorithm is closer to what Internet Explorer does than what Gecko used to do. Internet Explorer has had the majority market share for a while, so sites have generally been tested not to break when subjected to IE’s tokenizer. The tree building part is close to what WebKit does already. Of the major browser engines WebKit had the most reasonable tree building solution prior to HTML5.

    Furthermore, the new HTML5 parser parses network streams off the main thread. Traditionally, browsers have performed most tasks on the main thread. Radical changes like off-the-main-thread parsing are made possible by the more maintainable code base of the HTML5 parser compared to Gecko’s old HTML parser.

    What’s In It for Web Developers?

    The changes mentioned above are mainly of interest to browser developers. A key feature of the HTML5 parser is that you don’t notice that anything has changed.

    However, there is one big new Web developer-facing feature, too: inline MathML and SVG. HTML5 parsing liberates MathML and SVG from XML and makes them available in the main file format of the Web.

    This means that you can include typographically sophisticated math in your HTML document without having to recast the entire document as XHTML or, more importantly, without having to retrofit the software that powers your site to output well-formed XHTML. For example, you can now include the solution for quadratic equations inline in HTML:

    <math>
      <mi>x</mi>
     
      <mo>=</mo>
      <mfrac>
        <mrow>
          <mo>&minus;</mo>
          <mi>b</mi>
          <mo>&PlusMinus;</mo>
          <msqrt>
            <msup>
     
              <mi>b</mi>
              <mn>2</mn>
            </msup>
            <mo>&minus;</mo>
            <mn>4</mn>
            <mo>&InvisibleTimes;</mo>
            <mi>a</mi>
     
            <mo>&InvisibleTimes;</mo>
            <mi>c</mi>
          </msqrt>
        </mrow>
        <mrow>
          <mn>2</mn>
          <mo>&InvisibleTimes;</mo>
          <mi>a</mi>
     
        </mrow>
      </mfrac>
    </math>

    Likewise, you can include scalable inline art as SVG without having to recast your HTML as XHTML. As screen sized and pixel densities become more varied, making graphics look crisp at all zoom levels becomes more important. Although it has previously been possible to use SVG graphics in HTML documents by reference (using the object element), putting SVG inline is more convenient in some cases. For example, an icon such as a warning sign can now be included inline instead of including it from an external file.

    <svg height=86 width=90 viewBox='5 9 90 86' style='float: right;'>
      <path stroke=#F53F0C stroke-width=10 fill=#F5C60C stroke-linejoin=round d='M 10,90 L 90,90 L 50,14 Z'/>
      <line stroke=black stroke-width=10 stroke-linecap=round x1=50 x2=50 y1=45 y2=75 />
    </svg>

    Make yourself a page that starts with <!DOCTYPE html> and put these two pieces of code in it and it should work with a new nightly.

    In general, if you have a piece of MathML or SVG as XML, you can just copy and paste the XML markup inline into HTML (omitting the XML declaration and the doctype if any). There are two caveats: The markup must not use namespace prefixes for elements (i.e. no svg:svg or math:math) and the namespace prefix for the XLink namespace has to be xlink.

    In the MathML and SVG snippits above you’ll see that the inline MathML and SVG pieces above are more HTML-like and less crufty than merely XML pasted inline. There are no namespace declarations and unnecessary quotes around attribute values have been omitted. The quote omission works, because the tags are tokenized by the HTML5 tokenizer—not by an XML tokenizer. The namespace declaration omission works, because the HTML5 tree builder doesn’t use attributes looking like namespace declarations to assign MathMLness or SVGness to elements. Instead, <svg> establishes a scope of elements that get assigned to the SVG namespace in the DOM and <math> establishes a scope of elements that get assigned to the MathML namespace in the DOM. You’ll also notice that the MathML example uses named character references that previously haven’t been supported in HTML.

    Here’s a quick summary of inline MathML and SVG parsing for Web authors:

    • <svg></svg> is assigned to the SVG namespace in the DOM.
    • <math></math> is assigned to the MathML namespace in the DOM.
    • foreignObject and annotation-xml (an various less important elements) establish a nested HTML scope, so you can nest SVG, MathML and HTML as you’d expect to be able to nest them.
    • The parser case-corrects markup so <SVG VIEWBOX='0 0 10 10'> works in HTML source.
    • The DOM methods and CSS selectors behave case-sensitively, so you need to write your DOM calls and CSS selectors using the canonical case, which is camelCase for various parts of SVG such as viewBox.
    • The syntax <foo/> opens and immediately closes the foo element if it is a MathML or SVG element (i.e. not an HTML element).
    • Attributes are tokenized the same way they are tokenized in HTML, so you can omit quotes in the same situations where you can omit quotes in HTML (i.e. when the attribute value is not the empty string and does not contain whitespace, ", ', `, <, =, or >).
    • Warning: the two above features do not combine well due to the reuse of legacy-compatible HTML tokenization. If you omit quotes on the last attribute value, you must have a space before the closing slash. <circle fill=green /> is OK but <circle fill=red/> is not.
    • Attributes starting with xmlns have absolutely no effect on what namespace elements or attributes end up in, so you don’t need to use attributes starting with xmlns.
    • Attributes in the XLink namespace must use the prefix xlink (e.g. xlink:href).
    • Element names must not have prefixes or colons in them.
    • The content of SVG script elements is tokenized like they are tokenized in XML—not like the content of HTML script elements is tokenized.
    • When an SVG or MathML element is open <![CDATA[]]> sections work the way they do in XML. You can use this to hide text content from older browsers that don’t support SVG or MathML in text/html.
    • The MathML named characters are available for use in named character references everywhere in the document (also in HTML content).
    • To deal with legacy pages where authors have pasted partial SVG fragments into HTML (who knows why) or used a <math> tag for non-MathML purposes, attempts to nest various common HTML elements as children of SVG elements (without foreignObject) will immediately break out of SVG or MathML context. This may make some typos have surprising effects.
  6. Mozilla developer preview (Gecko 1.9.3a1) available for download

    Editor’s note: Today, Mozilla released a preview of the Gecko 1.9.3 platform for developers and testers. Check out the Mozilla Developer News announcement reposted below.

    A Mozilla Developer Preview of improvements in the Gecko layout engine is now available for download. This is a pre-release version of the Gecko 1.9.3 platform, which forms the core of rich Internet applications such as Firefox. Please note that this release is intended for developers and testers only. As always, we appreciate any feedback you may have and encourage users to help us by filing bugs.

    This developer preview introduces several new features, including:

    and several other significant changes, including:

    • On Mac OS X, we render text using Core Text rather than ATSUI.
    • We rewrote major parts of the code for handling scrolling. See bug 526394 for details.
    • We rewrote the way a snapshot of a document is taken in order to print or print preview. See bug 487667 for details.
    • We made significant changes to table border handling. See bug 452319 and bug 43178 for details.
    • We made various architectural changes to improve Web page performance.

    More information on these changes is in the release notes, as well as the Upcoming Firefox features for developers article on the Mozilla Developer Center.

    Please use the following links when downloading this Mozilla Developer Preview:

  7. pointer-events for HTML in Firefox 3.6

    The pointer-events CSS property has long been available as part of SVG as a way to control if a mouse event should be sent to the element directly underneath the mouse or passed through to an element underneath it. In Firefox 3.6 we’ve extended the property to allow it to apply to normal HTML content as well.

    For SVG you can set the pointer-events property to one of several values, but for HTML you can only set it to one of two values: auto or none.

    .foo {
      pointer-events: none;
    }

    When pointer-events is set to none, pointer events are passed through the target element and are instead sent to the element that is underneath it.

    .foo {
      pointer-events: auto;
    }

    When pointer-events is set to auto, pointer events are handled normally. That is, the element blocks the events from being passed down to a lower element.

    Here’s a real world example from Paul Rouget. You will need a Firefox 3.6 beta to see it in action.

    Click the pointer-events: none checkbox under the image to see it change.

    He’s replicated the tag list that’s on the front page of twitter.com. (Note: you have to not be logged in to see the tag list.) If you go and look at it on twitter you’ll notice that it fades off on the right hand side. This is done with a transparent, faded image that sits on top of the underlying box. The tags underneath are clickable links but the image blocks events from being sent to the ones underneath the fade.

    What Paul has done is show how you can use the pointer-events property to allow you to click on the underlying links even with a fade on top of it.

  8. exploring music with the audio tag

    Today’s demo comes to us from Samuel Goldszmidt. He’s a web developer specializing in audio applications at Institut de Recherche et Coordination Acoustique/Musique (IRCAM). IRCAM is a European institute covering science, sound and avant garde electro-acoustical art music.

    The demo uses XML to describe the various segments of a piece of music – Florence Baschet’s StreicherKreis (Circle of Strings). The music itself is a combination of stringed instruments and electronic effects. From the XML, SVG is generated for each section of the music. You can click on each section to listen to that part of the piece and a description is shown on how that particular section was created.

    As far as demos go, this is relatively simple. But it’s worth highlighting because it shows how easy it is to build a timeline around a piece of music and add descriptive information. In this case, it’s information meant to teach people how a particular effect was created. But it could be anything, from showing different camera angles of people playing the music to links about different covers of a popular piece. Opening up media to the web means that we can combine it with text, images and other media. This is just a small example.

  9. using SVG and APNG to create an animated texture map

    Yesterday we featured a demo that used SVG to map 3D data. Today we link to Hans’ next demo: dynamically textured animations in the browser.

    He uses the same techniques that he used in the previous post, but this time he’s taking an Animated PNG image and mapping a random image texture on top of it using his SVG projection technique. The result is pretty neat. Have a look at the demo: