Firefox rendering of OpenType font does not match the font specification

715 views Asked by At

I am loading the OpenType webfont Open Sans via the Google Fonts API / CSS.

In both Chrome 43 (Linux+Windows) and Internet Explorer 11 (Windows) the browser renders the text exactly as specified in the font. However, in Firefox 38.0.5, the text width and/or spacing is rendered differently for some characters. All font variants are at the default value ("normal").

As an example, we can use the characters 1, a, b, and i. Open Sans "unitsPerEm" is 2048. Therefore, at a font size of 18.0px, the width of 30 characters of each of the above characters should be as follows based on 1/u * p * c * w where u = 2048, p = 18.0, c = 30, and w is the advance width of each char (Wolfram Alpha equation).

+----------------------------------------+-----------+
| char | font(px) | numChars |  advance  | width(px) |
+------+----------+----------+-----------+-----------+
|  1   |   18.0   |    30    |   1171    |  308.76   |   
|  a   |   18.0   |    30    |   1139    |  300.322  |
|  b   |   18.0   |    30    |   1255    |  330.908  |
|  i   |   18.0   |    30    |   518     |  136.582  |
+----------------------------------------+-----------+

This (JSFiddle) uses the canvas method measureText to output the width in pixels of 30 characters of each of 1, a, b, and i.

Chrome text lengths match the expected values exactly:

Chrome widths

Firefox Linux text lengths do not match for any of the characters except a, even after accounting for the fact that Firefox does not provide subpixel accuracy:

Firefox Linux widths

I have confirmed that the width reported by canvas is indeed what is output by both Chrome and Firefox -- the following image shows a red background, with Chrome's text in black, and Firefox's text in white -- the widths match the outputs above according to the Gimp "Measure" tool. Firefox's b and i is too wide, and 1 is too narrow:

Chrome/Firefox Comparison

And as a side note, Firefox Windows text lengths are not even consistent with Firefox Linux -- the a and b widths are now as expected, but 1 and i are still incorrect:

Firefox Windows widths

This is a clean Firefox profile with default settings and no extensions installed.

Can someone explain what is going on, and how to force Firefox to render the font according to the font specification?

UPDATE: On Windows, setting the preference gfx.font_rendering.directwrite.enabled to true fixes the problem (which I believe is the Firefox default when hardware acceleration is available, this setting just forces it on even if hardware acceleration is unavailable, such as on my test VMWare system). DirectWrite has been the default in Chrome on Windows since version 37. The Linux behavior is still unexplained. This blog post explains more about DirectWrite rendering in Firefox on Windows.

1

There are 1 answers

0
Raman On BEST ANSWER

(This answer summarizes the main points raised in the question comments, as well as a bunch of additional research done after the question was posted.)

For various and complex reasons, not all browser/OS/font size combinations render to screen in the same way, nor do they always follow the specifications of the font. Therefore, in general, applications should be created in a way that avoids needing to do pixel-perfect positioning of text.

Subpixel Text Rendering Configuration

Some comments on configuring specific browser/OS combinations to support subpixel text rendering:

Windows

  • Browsers that support and enable DirectWrite (as opposed to the older GDI method) do tend to support linear, non-hinted, subpixel text positioning, and therefore are able to (and usually do) follow the font advance width specifications. This includes Chrome 37+ and Firefox 4+.
    • Firefox disables DirectWrite by default when hardware acceleration is not available, but it can be enabled via setting the config property gfx.font_rendering.directwrite.enabled to true.
    • Chrome 37+ DirectWrite is on by default, but can be disabled by setting the flag Disable DirectWrite.
    • Internet Explorer (9+?) DirectWrite is on by default, but can be disabled by setting compatibility mode.

Linux

Configure your display for anti-aliasing and sub-pixel text rendering by setting up fontconfig for subpixel rendering (usually via Gnome or KDE display manager settings, but can be done manually via fontconfig config files), installing freetype-freeworld (freetype with non-free subpixel rendering support), and adding Xft.lcdfilter: lcddefault into ~/.Xresources for applications without fontconfig support. Set the correct type of subpixel rendering based on your LCD display type.

  • Browser behavior seems inconsistent even when the underlying display supports and is configured for subpixel rendering.
    • Recent versions of Chrome (44 tested) appear to support linear, non-hinted, subpixel text positioning, and therefore generally follow the font specifications. Tested on KDE 4.14 with RGB subpixel text rendering enabled.
    • Firefox (38.0.5 tested) appears to do non-linear hinted positioning, therefore does not follow the font specifications, even if the display is configured for subpixel rendering. I have not identified a way to force Firefox to use subpixel text rendering.

Mac OS/X

No information for this platform yet.

Pixel-perfect Positioning

If, despite the difficulty, one is building an application that requires pixel-perfect text positioning and inspection, then there are generally two ways to go about it:

1) Canvas or DOM-based text width/height measurement: See Calculate text width with JavaScript. See also Font.js by Mike Kamermans (Pomax).

2) Use of OpenType.js to determine text dimensions from the source font, which is faster than the method above when it works, but does not work in all cases.