SVGOpenTypeFonts

From MozillaWiki
Jump to: navigation, search

Introduction

This is an old page. More up-to-date work-in-progress documentation on SVG-in-OpenType can be found at http://dev.w3.org/SVG/modules/fonts/SVG-OpenType.html or, even more recently, here http://lists.w3.org/Archives/Public/public-svgopentype/2013Jul/0003.html

Use Cases

SVG Fonts address some use-cases which cannot be addressed using current OpenType-based solutions. For example:

  • Editable text where the glyphs display a "shiver" effect
  • Draw freehand graphics with self-intersecting curves and use them as glyphs for a font
  • Japanese "emoji" with colored glyphs

Limitations Of SVG 1.1 Fonts

Internationalization

SVG Fonts have very weak shaping support, which makes them unusable with Indic and other languages. Therefore we need a solution to address the above use-cases that also handles complex shaping. OpenType already supports shaping for most of the world's languages and because of the large ongoing investment in OpenType fonts and processing engines, will broaden its support over time. So, can we leverage OpenType to handle the above use-cases?

Advanced Font Features

SVG Fonts lack support for features such as stylistic alternates.

Style Inheritance

The way SVG font glyphs inherit style from the text is both broken for authors and difficult to implement.

An example of how it's broken for authors: if the author specifies 'stroke-width:2' on a piece of text where some characters are rendered with system font F and other characters are rendered with SVG font S, and the glyphs of S contain simple path shapes, then the glyphs of F get a stroke width of 2 user-space units, but the glyphs of S get a stroke width of 2 glyph-space units, which will typically be invisible.

It's difficult to implement because Gecko (and Webkit, and probably other engines) keep persistent computed style data attached to DOM nodes, so having the style inherit differently depending on how the nodes are being used is inefficient and intrusive.

SVG OpenType Fonts

Robert O'Callahan's proposed alternative to SVG fonts is to embed SVG glyph data in OpenType fonts, and draw glyphs by rendering that SVG. Use the OpenType data for everything other than glyph drawing (metrics, shaping, etc).

The current status of this proposal is that it has worked its way through the W3C process and is now a proposal that has been put forward by the W3C for consideration by the MPEG group (which owns the Open Font Format (aka OpenType) spec within ISO).

Tools

The current tools for creating SVG-in-OT fonts are basic, and possibly out of date.

Prototype Implementation

This work is going on in bug 719286.

The SVG table

We define a new optional OpenType table 'SVG '. This table contains one or more UTF-8 encoded SVG documents defining SVG glyphs.

The table begins with a header:

Name Type Description
version USHORT The version of the SVG table—currently 1
numIndices USHORT The number of index entries (see below) in this table

This is followed by numIndices index entries: each entry specifies a range of glyph IDs and location of the SVG document in the table for those glyph IDs. The index must not contain any intersecting glyph ID ranges and entries must be sorted in ascending order by glyph IDs. Index entries may share (documentOffset, documentLength) pairs, but may not have intersecting non-equal document locations.

Name Type Description
startGlyphId USHORT The first glyph ID mapped by this entry
endGlyphId USHORT The last glyph ID mapped by this entry
documentOffset ULONG The offset from the beginning of the SVG table where the SVG document can be found containing glyphs for this range
documentLength ULONG The length of the SVG document for this glyph range

Finally, the SVG documents themselves which are to be UTF-8 encoded, and whose length and offset are described by the document list above.

With this design, authors can easily create small fonts by putting all glyphs in a single document. They can also create efficient large fonts by putting each glyph in its own document. A UA could avoid managing too many SVG documents when rendering many glyphs, by rendering glyphs to a cache of glyph bitmaps and discarding their SVG documents as needed.

Structure of the SVG Document

Two additional attributes are supported in this SVG document: glyphid and glyphchar, which may be used on any SVG graphic element or container element.

glyphid is a number specifying a glyph ID. That glyph ID is rendered using that element.

glyphchar is a string of one character optionally followed by a Unicode Variation Selector. The glyph ID to associate with the glyph is then resolved using the cmap table. That glyph ID is rendered using that element.

If a glyph ID could be rendered by more than one element, then the first element in the document for that glyph ID wins.

SVG Glyphs

The glyphs themselves have an em-height of 1000 units with the baseline at y=0. (Note that the SVG 'viewbox' attribute can be used to easily select a different coordinate system.) The ink bounding boxes specified in the OpenType metrics tables are ignored; the ink bounding-box of each SVG glyph DOM subtree is used instead.

Two new paint server values are defined for use in SVG glyphs: objectFill and objectStroke (currently prefixed as -moz-objectFill and -moz-objectStroke). These values specify the fill or stroke applied to the text in the document that uses this font. Unlike SVG 1.1's style inheritance approach, they automatically take account of the change in coordinate systems from the document containing the text to the glyph document.

Two new values for fill-opacity and stroke-opacity are defined: objectFillOpacity and objectStrokeOpacity, which evaluate to the fill and stroke opacity applied to the text in the document that uses this font. Either value can be used with either property. Also, if objectFill is a fully transparent color, objectFillOpacity evalutes to zero, and likewise for objectStroke and objectStrokeOpacity. (This allows authors to easily set the fill colors of glyph parts while still not rendering anything in those parts when the text is not being filled.)

A new value objectValue is defined for the stroke-width, stroke-dasharray, and stroke-dashoffset properties. This value evaluates to the value from the text in the document using this font, appropriately adjusted for the scale in the coordinate systems from the text document to the glyph document.

Question: is it worth supporting 'custom stroking' of SVG glyphs, or should we just make stroking stroke the path defined by OpenType, and remove all the special stroking-related properties above? It might be quite hard for authors to effectively use custom stroking.

Security

For security's sake the SVG document is not allowed to refer to external resources—it may, however, contain resources in the form of data URIs. Moreover, scripting is disabled in the glyphs document.

Animation is enabled. (But not yet supported in Gecko.)

Example

<svg xmlns="http://www.w3.org/2000/svg">
  <rect x="100" y="-900" width="800" height="800" fill="objectFill" stroke="objectStroke" glyphchar="M" />
  <circle cx="500" cy="-500" r="300" fill="red" stroke="objectStroke" glyphchar="M&#xfe01;" />
  <path class="SamplePath" d="M100,200 C100,100 250,100 250,200 S400,300 400,200 Z" fill="objectFill"
    stroke="black" glyphid="45" />
</svg>

In this example we have three glyphs defined: a rectangle-shaped glyph to render M as; a circle-shaped glyph for M with the Unicode Variation Selector &#xfe01;; and a path to replace some glyph ID, usually a glyph ID which would be the result of substitution—for example via the GSUB table.

Also worth noting are the negative y coordinates due to SVG's y-down coordinate system and our placing the baseline at y=0.

Adobe's Proposal

Adobe are keen on a similar idea, an early proposal of which can be found here.

The main differences I can see are that each glyph definition has a whole SVG document. Also, they have two glyph definitions per actual glyph -- one static, one animated. I don't think this is necessary, though; we can let static glyphs be the glyph without any animations applied. Note that it's easy to create a glyph DOM subtree containing separate "static" and "animated" glyphs such that if SMIL is enabled, the animated glyph is drawn, otherwise the static glyph is drawn.