The proposals in this unofficial draft have been incorporated into the OpenType specification. For more details, see the following sections of the OpenType specification:
This document defines a new OpenType table that allows multi-colored, animated glyphs to be specified using SVG.
This document is an Unofficial Editor’s Draft of the SVG Glyphs in OpenType specification, produced by the editors listed above. It is not yet a document that has been officially adopted by a W3C Working Group, although it is intended to be officially adopted by the W3C SVG Working Group or some other group at some point. Please send comments about this document to public-svgopentype@w3.org (archived).
This document proposes a way to define glyphs in OpenType fonts which can be colored or animated, or indeed support any existing feature of SVG’s secure animated mode. This is achieved by defining a new OpenType table containing SVG documents which include glyph definitions in SVG.
Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.
All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]
Two conformance classes are defined: conforming fonts and conforming implementations. Conformance requirements on fonts are authoring conformance requirements. Violating an authoring conformance requirement has no affect on how an implementation processes an OpenType font with SVG glyphs unless otherwise stated with requirements on conforming implementations.
An OpenType table with the tag “SVG
” – hereafter called the
SVG table – is used as an index to point to an embedded SVG document within
the table that defines SVG glyphs for glyph IDs within a specified range.
The table consists of a header, followed by an index, and then a number of
SVG documents. The table format uses the data types and contentions used
in the OpenType specification. [OPENTYPE]
The header has the following format:
Name | Type | Description |
---|---|---|
version |
USHORT |
The version of the SVG table. Currently set to 1. |
numIndices |
USHORT |
The number of index entries to follow. |
This header is then followed by numIndices
index entries.
Fonts conforming to this specification must use 1 as the version number. Conforming implementations must ignore SVG tables that have an unrecognized version number. If a font has more than one SVG table, all but the first with a recognized version number must be ignored.
Each index entry specifies a range [startGlyphId, endGlyphId]
of glyph
IDs and the location of the associated SVG document in the font relative to the start
of the SVG table. Each glyph ID in the range may, but need not, have a glyph
definition in the document.
Name | Type | Description |
---|---|---|
startGlyphId |
USHORT |
The first glyph ID in the range described by this index entry. |
endGlyphId |
USHORT |
The last glyph ID in the range described by this index entry. |
documentOffset |
ULONG |
The offset of the SVG document, in bytes, into the font relative to the beginning of the SVG table. |
documentLength |
ULONG |
The length of the SVG document, in bytes. |
Index entries may have equal (documentOffset, documentLength)
pairs, but the ranges must not otherwise intersect. The startGlyphId
in an index entry must be less than or equal to endGlyphId
, and the
[startGlyphId, endGlyphId]
ranges across all of the index entries
must not overlap.
Implementations must ignore the entire SVG table if it contains index entries with invalidly intersecting byte ranges, mis-ordered start and end glyph IDs or overlapping glyph ID ranges.
Following the header section is a series of UTF-8 encoded SVG documents.
The SVG documents are largely standard SVG with some extensions for SVG glyphs. Two new attributes are defined to map glyph IDs to elements, either of which can be used on graphics elements and container elements.
Each SVG document identified by a (documentOffset, documentLength)
pair must
be a well-formed XML 1.0 document that is a conforming SVG 2 stand-alone files.
It might be better to reference SVG 1.1, given that SVG 2 is still in development.
An SVG document must be parsed with a non-validating XML 1.0 parser. [XML10] If a document fails to parse, or if it successfully parses its document element is not the “svg” element in the SVG namespace “http://www.w3.org/2000/svg”, or if uses any encoding other than UTF-8, then the document is ignored and considered not to contain any SVG glyph definitions.
Each successfully loaded SVG document must be processed in secure animated mode. [SVGINTEGRATION] The SVG document therefore will not be able to resolve any external resources or run any script.
All animation timelines across all SVG documents in SVG tables must be synchronized with a timeline start appropriate for the kind of animation as if they ran directly in the document using the font. For example, the timeline for SVG animation elements would all begin with t = 0s at the time the referencing document’s load event is dispatched. When rendering glyphs to media that do not support animation, the SVG documents must be processed without applying any animations, not by rendering them with animations applied but at a particular snapshot time.
To associate elements in the document with glyph IDs, two new attributes are defined for use on graphics elements and container elements: glyphchar and glyphid.
Name | Value | Lacuna value | Animatable |
---|---|---|---|
glyphchar | see below | N/A | no |
The value of a glyphchar
attribute must be a single Unicode character followed by an optional
Unicode Variation Selector (UVS). [UNICODE6]
This value is mapped to a glyph ID via the CMAP
table of the typeface. By specifying this
attribute on a graphics element
or container element,
it indicates that the element is the definition of the SVG graphics
for the corresponding glyph ID. The attribute must not be specified on any other element.
Name | Value | Lacuna value | Animatable |
---|---|---|---|
glyphid | <integer> | N/A | no |
The value of a glyphid
attribute must be an integer in the range [0, 65535] and represents a
glyph ID. By specifying this attribute on a
graphics element
or container element,
it indicates that the element is the definition of the SVG graphics
for the corresponding glyph ID. The attribute must not be specified on any other element.
Specifying the glyph ID directly with glyphid,
and not with a glyphchar attribute,
can be useful for glyph substitutions via, for example, the GSUB
table.
If an element has both a glyphchar and a glyphid attribute, then glyphchar must be ignored. If these attributes have a specified value that does not match the required syntax, then the element is considered not to define a glyph, as if the attributes were not specified. A given SVG document embedded in the SVG table must not define more than one element for a given glyph ID; if it does, then the first in document order must be used. If the attributes are specified on an element other than a graphics element or container element, then the glyph will be considered to be defined but will not have any graphical content.
It is important to note that as the CMAP
table is used to resolve
glyph IDs, the font should contain “legacy” outlines to fall back on for user agents
which do not yet support this feature, and for rendering glyphs in contexts where
an outline glyph is required, for example in a
clipPath
element.
We should go into more detail about known situations where the plain glyphs will be used instead of the SVG glyphs.
SVG glyphs have a baseline of y = 0 and a height of 1000 user units. The coordinate system is “y-down”, in contrast to the “y-up” coordinate system used in SVG Fonts but not in the rest of SVG. (Note that the ascent will be negative in the element’s coordinate system.) Other coordinate spaces can be chosen by using an svg element with a viewBox attribute as the element defining the glyph. Note that transforms on ancestor elements of the element defining a glyph do not have an effect on the position of the graphics within the glyph’s em box.
All other metrics are defined in the usual OpenType manner.
Consider the following SVG glyph document used in a font where the glyphs for “A” and “B” both have an ascent of 800 and an advance of 100:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="400" height="400"> <g transform="rotate(45)"> <g glyphchar="A"> <path d="M 0,200 h 100 v -1000 h -100 z"/> </g> <svg glyphchar="B" viewBox="0 0 10 100" width="100" height="1000"> <path d="M 0,20 h 10 v -100 h -10 z"/> </svg> </g> </svg>
Despite the use of the viewBox, width and height attributes on the outermost svg element and the transform attribute on the outer g element, the path defining the shape of the “A” glyph exactly traces the outside of the glyph’s em box.
The “B” glyph is defined to look identical to the “A” glyph, but it uses an svg element with a viewBox attribute to change the coordinate system used by the path element.
This section extends some SVG styling properties with values that inherit from the context text object. In Web content, the context text object is the CSS box (for HTML or similar content) or SVG text content element that references the font and defines the text to render using the SVG glyphs. Note that a user agent style sheet is used to make glyphs default to inheriting fill and stroke context styles from context text object.
The ‘stroke-width
’,
‘stroke-dasharray
’
and ‘stroke-dashoffset
’
properties are extended to allow a new value context-value.
Name: |
stroke-width ,
stroke-dasharray ,
stroke-dashoffset
|
---|---|
New Value: | context-value |
The context-value value represents the value of the given property on the context text object scaled in such a way that it has the same size in the glyph’s coordinate system. Since the height of the em box of all SVG glyphs is 1000 user units, the scale factor is:
scale = 1000 ÷ font_size
where font_size is the value of the
‘font-size
’ property
on the context text object in px.
Consider the following SVG document:
<svg xmlns="http://www.w3.org/2000/svg"> <text x="100" y="100" font-family="Fancy Font" font-size="0.5in" stroke-width="2px">A</text> </svg>
Assume that “Fancy Font” refers to an OpenType font with the following SVG glyph:
<svg xmlns="http://www.w3.org/2000/svg"> <g glyphchar="A"> <g transform="scale(0.5)"> <path d="..." stroke-width="context-value"/> </g> </g> </svg>
0.5in is equal to 48px. Thus, the scale factor to use is 1000 ÷ 48, resulting in the effective value of the context-value value being 2px × 1000 ÷ 48 ≃ 41.667px. Note that the transform on the g element has no effect in determining the effective value of the context-value value.
The <paint> and <color> data types are extended to allow new values context-fill and context-stroke.
Name: | <paint>, <color> |
---|---|
New Value: | context-fill | context-stroke |
When the context-fill or context-stroke
values are used as the value of a property that takes a <paint>,
the effect is as if the value of the
‘fill
’ or
‘stroke
’
property (respectively) on the context text object were used,
except that any SVG paint server is painted in the coordinate system of the
context text object rather than the coordinate system of the
element on which context-fill or context-stroke
were specified. If the paint server uses any values relative to the bounding box of the element
it is applied to (for example by specifying ‘objectBoundingBox’
for the patternUnits
attribute on a pattern element),
then these are resolved against the bounding box of the context text object.
Should we allow a fallback color to be specified after context-fill or context-stroke?
When the context-fill or context-stroke
values are used as the value of a property that takes a <color>,
the visual effect is as if the solid color component of the
‘fill
’ or
‘stroke
’
property (respectively) on the context text object were used. Solid color
components include the basic and extended color keywords, RGB and RGBA color values, the transparent
color keyword, HSL and HSLA color values, the currentColor color keyword,
the CSS2 system colors from CSS Color Module Level 3
([CSS3COLOR], section 4) and ICC, LAB, ICC named colors and uncalibrated device colors
from SVG 2 ([SVG2], chapter 12).
If the context paint value is a paint server reference with no fallback solid color or a CSS gradient value,
then the visual effect is as if transparent were used.
Consider the following document:
<svg xmlns="http://www.w3.org/2000/svg"> <linearGradient id="g" x1="0" y1="0" x2="1" y2="0"> <stop offset="0" stop-color="red"/> <stop offset="1" stop-color="yellow"/> </linearGradient> <text x="100" y="150" font-family="Simple Font" font-size="100px" fill="url(#g) orange">AAA</text> </svg>
Assume that “Simple Font” refers to an OpenType font with the following SVG glyph that has both an ascent and an advance of 800:
<svg xmlns="http://www.w3.org/2000/svg"> <g glyphchar="A"> <circle cx="400" cy="-400" r="300" fill="none" stroke="context-fill" stroke-width="100px"/> </g> </svg>
The use of context-fill as the value of
‘stroke
’
on the glyph’s circle element
will result in the linear gradient being sized to the context text object.
The document would render approximately like the following:
The ‘fill-opacity
’,
‘stroke-opacity
’ and
‘opacity
’ are extended
to allow new values context-fill-opacity and context-stroke-opacity.
Name: |
fill-opacity ,
stroke-opacity ,
opacity
|
---|---|
New Value: | context-fill-opacity | context-stroke-opacity |
The effect of the context-fill-opacity and
context-stroke-opacity values is to take on the
value of the ‘fill-opacity
’
or ‘stroke-opacity
’
property (respectively) on the context text object, with the exception that if the
‘fill
’ or
‘stroke
’ property
(again, respectively) has the value none, then the effective opacity value will be
0.
Consider the following SVG document:
<svg xmlns="http://www.w3.org/2000/svg" width="350" height="200"> <text x="100" y="120" font-family="Accented I" font-size="100px"> i <tspan fill="none" stroke="olivedrab" stroke-width="2px">i</tspan> <tspan fill="indigo" fill-opacity="0.5">i</tspan> </text> </svg>
Assume that “Accented I” refers to an OpenType font with the following SVG glyph that has ascent of 800 and an advance of 500:
<svg xmlns="http://www.w3.org/2000/svg"> <g glyphchar="i"> <path d="M 100,-400 h 200 v 350 h 100 v 50 h -300 v -50 h 100 v -300 h -100 z"/> <circle cx="240" cy="-530" r="50" fill="none" stroke="red" stroke-width="30px" stroke-opacity="context-fill-opacity" stroke-dasharray="none"/> <circle cx="240" cy="-530" r="15" fill="none"/> <circle cx="240" cy="-530" r="75" fill="none"/> </g> </svg>
The glyph defines a lowercase “i” that has a red stroked circle forming the dot
above the base of the letter. Since we want to consider the stroke of the red circle
to effectively be part of the filled shape of the glyph, we use the
context-fill-opacity value for its
‘stroke-opacity
’
property. We also set its ‘stroke-dasharray
’
property to none so that dashed strokes do not affect it.
The two following circles are used to define the path to stroke
if the text using the glyph is stroked. Those circles have
‘fill
’
set to none so that any
fill paint on the text is not used.
The SVG document would be rendered as follows:
Notice that due to the special behavior of context-fill-opacity
being equivalent to 0 when the context text object’s
‘fill
’
is none, the red circle in the second “i” is not rendered.
Are all of these new values sufficiently motivated? For cases where we need to define a separate region in a glyph to be stroked, we might be able to use the regular OpenType outline. However, it could be that this outline, although suitable for fallback, is different enough from the SVG glyph that it makes sense to be able to define the stroking region in the SVG glyph itself.
The following user agent style sheet must be applied to SVG documents processed from the SVG table:
:root { fill: context-fill; fill-opacity: context-fill-opacity; stroke: context-stroke; stroke-opacity: context-stroke-opacity; stroke-width: context-value; stroke-dasharray: context-value; stroke-dashoffset: context-value; }
The editors wish to thank Robert O’Callahan and Sairus Patel for their input into this specification.