Testing fillText vs HTML rendering

letter-spacing seems to be different on Firefox 6. (Haven't tested on previous versions of Firefox). If you disable direct2d on Firefox (via about:config). The widths reported are same.

by davidhong

HTML

<div><p>Hello, World! Avalon is my hero</p></div>
<canvas id="c" width="300" height="25"></canvas>
<canvas id="d" width="300" height="25"></canvas>

CSS

div, canvas { margin: 0; padding: 0; width: 300px; height: 25px; border: 1px dotted #222; position: absolute; left: 0; }
div { top: 0; }
p { bottom: 0; left: 0; position: absolute; font: normal normal 400 12px/12px Monaco; margin: 0; padding: 0; }
#c { top: 30px; }
#d { top: 60px; }

JavaScript

var log = function() {
    if (typeof console !== 'undefined' && console.log) {
        console.log(Array.prototype.slice.call(arguments));
    }
};

/**
 * fillTextCharByChar
 *
 * uses measureText() to progress forward on x-axis; Uses fillText() on
 * each individual char instead of the whole string.
 *
 * @param context {CanvasRenderingContext2D}
 * @param text    {string}
 * @param x       {number}
 * @param y       {number}
 */
var fillTextCharByChar = function(context, text, x, y) {
    text = String(text);

    var charlist = String.prototype.split.call(text, ''),
        charlen = charlist.length,
        current = 0,
        position = x;

    for (; current < charlen; current += 1) {
        var char = charlist[current],
            charwidth = context.measureText(char).width;

        context.fillText(char, position, y);
        position += charwidth;
    }
    
    log('fillTextCharByChar', text, position);
};

(function(document) {
    var c = document.getElementById('c'),
        d = document.getElementById('d'),
        cctx = c.getContext('2d'),
        dctx = d.getContext('2d'),
        text = 'Hello, World! Avalon is my hero';

    // Set both canvas elements to have same font styling
    cctx.font = dctx.font = 'normal normal 400 12px/12px Monaco';

    // First method uses the built-in fillText method
    cctx.fillText(text, 0, 22);
    log('fillText', text, cctx.measureText(text).width);

    // Second method is to use individual character and their measureText().width to progress on x-coordinate vector
    fillTextCharByChar(dctx, text, 0, 22);
}(document));