SVGFontKit (under development)
The Problem
Firefox doesn't yet handle embeded SVG fonts. Despite the fact that it handles text, it does so in a way that sucks. I'm sure they have their reasons like "integration with the rest of the text on the page" but it sucks -- increasing or decreasing the size of text on the page changes the text in the SVG, which makes it look stupid since SVG text is absolutely positioned. This is, hopefully, a temporary hack to solve the problems I'm having. Unlike the other parts of SVGKit, it will only be made as general as I (or user requests) need it to be.
Introduction
This is a hack to replace all SVG <text> and <tspan> elements that reference an embeded SVG font with references to the font's glyphs properly positioned and spaced. This hack is necesary because Firefox lacks support for SVG Fonts, and currently <text> elements are rendered and sized according to the rest of the web pages's fonts rather than pixel-perfectly anti-aliased as demanded the SVG spec seems to require.
The major motivation for this is to render TeX equations for SVGPlot. TeX's fonts are natively specified using METAFONT, which uses a different way of describing fonts compared to PostScript (and SVG). Rather than giving a mathematical description for the outline, which get filled, METAFONT fonts are actually the stroke of a variable-width pen. Also, different sizes aren't just exact scalings of each other -- a whole program gets run with new parameters to generate new strokes. Computer Modern 5 is smaller then 10, but has more relative spacing between the letters and the same stroke thickness for greater readability.
Browse Code in SVN Repository
What it does
It's a stand-alone JavaScript that doesn't require SVGKit or MochiKit that:
- Takes an SVG font and creates a list of
<path>
elements in the<defs>
section which can be referenced in the next step. - Each path is assigned a unique id that includes the font name and the unicode field of the origional glyph. This is becayse the glyph-name field doesn't have to be present or unique. Unfortunately there can be more than one glyph for a given unicode, which means the glyph-name is used, but I won't worry about this here. For example, if the font is "Bitstream Vera Sans" and the unicode is "A" the reference becomes "Bitstream Vera Sans _ A" Maybe this can be shortened to save space.
- Goes through and replaces the SVG
<text>
and<tspan>
elements that reference an embeded font with a series of properly spaced <use> elements that reference<paths>
corresponding to the glyphs. - Calculates bounding boxes
- Is able to do the inverse (switch back to
<text>
elements) making it a one-to-one lossless mapping. This is so the SVG can be exported with<text>
elements. It achieves this by tagging the<text>
elements with "display=none" and everything it touched by class=SVGFontKit". What about if the text started out display:none? It wouldn't be modified on the forward or inverse pass. - Useful Bit: Integrate another SVG image's fonts, perhaps even going so far as to add only new glyphs. This would be useful for TeX equations.
Things that make this a horrible hack
- Text is no longer searchable or copyable to the system clipboard
- The DOM tree will be altered to a bunch of
<use>
elements rather than the<text>
element - Text elements are no longer editable -- at the end of the day you'll want to restore your
<text>
elements and will lose style and transform information. (Maybe there can be an outter group which starts off with no stye.) - It may not handle CSS applied to the
<font>
and<glyph>
elements properly.
To steal from the spec:
<?xml version="1.0" standalone="yes"?> <svg width="400px" height="300px" version="1.1" xmlns = 'http://www.w3.org/2000/svg'> <defs> <font id="Font1" horiz-adv-x="1000"> <font-face font-family="Super Sans" font-weight="bold" font-style="normal" units-per-em="1000" cap-height="600" x-height="400" ascent="700" descent="300" alphabetic="0" mathematical="350" ideographic="400" hanging="500"> <font-face-src> <font-face-name name="Super Sans Bold"/> </font-face-src> </font-face> <missing-glyph><path d="M0,0h200v200h-200z"/></missing-glyph> <glyph unicode="!" horiz-adv-x="300"><!-- Outline of exclam. pt. glyph --></glyph> <glyph unicode="@"><!-- Outline of @ glyph --></glyph> <!-- more glyphs --> </font> </defs> <text x="100" y="100" style="font-family: 'Super Sans', Helvetica, sans-serif; font-weight: bold; font-style: normal">Text using embedded font</text> </svg>
Tests
- Font cards created by Batik
- Batik examples
- TeX Output
References
What Makes Fonts Hard
- Unicode - huge number of glyphs to embed in every file
- Character substitution for things like ligatures: 'fi'
- Kerning - Like moving the 'A' back a little in the pair 'WA'.
- Hinting - to align each character to a pixel and space the next one appropriately makes the bounding box not scale with the font size even though the vector paths themselves do.
- Licences on the fonts, Trademarks on the names, and Patents on the technology (like TrueType's hinting engine.)
SVG Font Issues
No hinting (grid-fitting) -- Hinting has to do with aligning a vector outline to a screen or printer's pixels. This can be good or bad, depending on the application. PDF and SVG are supposed to be device-independent, so hinting should't affect the placement of characters. Unfortunately this means that at low resolution, the text might not look as good as it would with hinting.
Font Recomendations
- For the web, use Bitstream Vera or the DejaVu unicode extension of it (which include more unicode characters). They are TrueType fonts with full hinting instructions, designed to render on low-resolution devices such as computer monitors. They are free and open, unlike Microsoft's excellent Verdana which is free-as-in-beer, but restrictively distributed.
- For printing, use Computer Modern, TeX's defult font, especially for complex equations.