UFO 3

Draft 1: February 3, 2010

The UFO 3 specification is currently in early development. The current version of the draft is documented here. This is in no way a final draft and everything is subject to change. Please contact the spec maintainers if you have any comments about this draft.

UFO 3 contains a number of major additions along with some enhancements to the pervious specification. In short, the UFO now supports layers, images, layer-level and glyph-level guidelines, GLIF has some changes, fontinfo.plist has some new properties, kerning.plist is slightly different, there is a new data directory for storing large amounts of arbitrary data and there may be some hinting data structures added to the specification.

The file structure in this draft looks like this:

Layers

The biggest change in UFO 3 is that the UFO now supports layers. These layers can be used for anything—the standard main+background+image drawing environment, multi-layered fonts, glyph revision history and so on. The UFO layering system is designed to be conceptually unrestricted. However, this does not mean that layers should be used to store an entire family of weights within a single UFO. The UFO is a single style file format, not a family format.

There are two types of layers—outline layers and image layers. The top level of the UFO gains one new file, layercontents.plist This file maps layer directory names to layer names. Each layer gets its a new layerinfo.plist file. Each layer may contain glyphs that are or are not part of other layers. The structure of the UFO, as it relates to layers, looks like this:

For example, this UFO contains three layers—the main layer, a layer named “Reference” and another named “Pencil Sketches”:

Outline Layers

Outline layers are implemented as a series of glyph sets within the UFO. There is one required layer—the glyphs directory. This directory is considered the primary outline source of the font. Additional layers are represented as additional directories that adhere to the naming convention of glyphs.* where * is a unique, case-insensitive, file-system legal string.

Image Layers

Image layers are implemented as a directory of image glyph files. One or more iglyphs.* directories that follow the same basic structure as the glyphs directories may exist within the UFO. An IGLIF file stores data about placement, Affine transformations and color in individual glyphs.

Image Glyph Interchange Format

The IGLIF format is still being sketched out. At the moment it has the following structure.

<image-glyph> The top level element.
Attributes
attribute name description
name The name of the glyph
format The format version. 1 for this version.
Child Elements
element name description
image Must occur at least once.
<image> An image reference.
Attributes
attribute name data type description default value
fileName string The image file name. None
directory string The directory the image is stored in. If this is not given, the image must be stored in the images directory within the UFO. None
xScale integer or float See below. 1
xyScale integer or float See below. 0
yxScale integer or float See below. 0
yScale integer or float See below. 1
xOffset integer or float See below. 0
yOffset integer or float See below. 0
color string The color that should be applied to the image. The format follows the color definition standard. This attribute is optional. If no color is provided, the image should be drawn using the colors stored in the image data. None

xScale, xyScale, yxScale, yScale, xOffset, yOffset taken together in that order form an Affine transformation matrix, to be used to transform the image. The default matrix is [1 0 0 1 0 0], the identity transformation.

This element has no child elements. However, a mask child element could be of use.

Example
<?xml version="1.0" encoding="UTF-8"?>
<image-glyph name="A" format="1">
  <image fileName="my-sketch.png"
    directory=""
    xScale="1" xyScale="0"
    yxScale="0" yScale="1"
    xOffset="100" yOffset="200"
    color="1,0,0,.25"/>
  <image fileName="my-other-sketch.png"
    directory="/Users/me/Documents/Glyph Images"
    xScale="1" xyScale="0"
    yxScale="0" yScale="1"
    xOffset="500" yOffset="-100"
    color="0,1,0,.25"/>
</image-glyph>
Coloring Images

If a color is to be applied to an image, as a result of a color attribute in an image element or a layer fill color attribute in layerinfo.plist, the application displaying the image should convert the image to grayscale and then apply the color.

Image Storage

Images files may be stored within the UFO or not. If they are stored within the UFO, they must be stored in an images directory at the top of the UFO. Obviously, each image must have a unique file name. However, beyond that there are no file name requirements. All images must be formatted as PNG files. Applications should try to prevent duplicate images, but this is not a requirement of the UFO format.

layercontents.plist

File Format Property List

Description

This file maps the layer names to the glyphs and iglyphs directory names. Those directory names must be plain directory names, not absolute or relative paths in the file system. Care must be taken when choosing directory names: many file systems have character, length and case sensitivity restrictions. There is no one standard layer name to directory name conversion. However, a sample one must be developed1. Additionally, all layers must have unique names within the UFO.

The mapping is stored as an array in the property list. This array also defines the order of the layers from top to bottom. The mapping is stored within the array as arrays containing the layer names first and the directory name second.

1 The glyph name to GLIF file name conversion should provide a good starting point for this. Perhaps that algorithm can be abstracted so that it is file name extension agnostic. It will also need to gain an additional step to handle characters that may not be suitable for use in a file system name.

Example
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
  <array>
    <string></string>
    <string>glyphs</string>
  </array>
  <array>
    <string>Sketches</string>
    <string>glyphs.S_ketches</string>
  </array>
  <array>
    <string>Reference</string>
    <string>glyphs.R_eference</string>
  </array>
</array>
</plist>

layerinfo.plist

File Format Property List

Description

This file contains information about the layer. This file is optional. Not all values are required for a proper file.

Version 1

The property list data consists of a dictionary at the top level. The keys and values are as follows.

key value type description default value
guidelines array An array of guideline definitions that apply to all glyphs in the layer. None
fillColor string The color that should be used to fill all glyphs in the layer. The format follows the color definition standard. This attribute is optional. None
strokeColor string The color that should be used to stroke all glyphs in the layer. The format follows the color definition standard. This attribute is optional. None
strokeWeight positive integer or float The weight of the stroke to be applied to all glyphs in the layer. This attribute is optional. None
lib dictionary A lib specific to the layer. To avoid naming conflicts, keys should use the Reverse Domain Naming Convention defined for lib.plist. None

In an image glyph layer, strokeColor and strokeWeight should be ignored.

Guideline Format

The guidelines are stored as dictionaries of the following format.

key value type description default value
x integer or float The ‘x’ coordinate. None
y integer or float The ‘y’ coordinate. None
angle integer or float The angle of the guideline. This must be a value between 0 and 360. None
name string An arbitrary name for the guideline. This attribute is optional. None
color string The color that should be applied to the guideline. The format follows the color definition standard. This attribute is optional. None

The guideline extends along angle to infinity in both directions out of the point defined by x and y.

GLIF

<guideline> A reference guideline.

This element may occur any number of times.

Attributes

attribute name data type description default value
x integer or float The ‘x’ coordinate. None
y integer or float The ‘y’ coordinate. None
angle integer or float The angle of the guideline. This must be a value between 0 and 360. None
name string An arbitrary name for the guideline. This attribute is optional. None
color string The color that should be applied to the guideline. The format follows the color definition standard. This attribute is optional. None

The guideline extends along angle to infinity in both directions out of the point defined by x and y.

Child Elements

This element has no child elements.

<contour> Contour description.

The contour element gains a new name attribute.

attribute name data type description default value
name string Arbitrary name or label for this contour. The name does not have to be unique within an outline. None

<component> Insert another glyph as part of the outline.

The component element gains a new name attribute.

attribute name data type description default value
name string Arbitrary name or label for this compopnent. The name does not have to be unique within an outline. None

This element has a new rule that governs component behavior as it relates to layers: When multiple glyphs directories are in the font, a component may only reference a glyph within the same glyphs directory that contains the glyph that contains the component.

fontinfo.plist

There are several additions to the font info file.

OpenType Name Table Records

A list of specific OpenType name table records. This is an addition to the top level of the font info dictionary. The name table fields are covered by the top level info fields. This name record storage area is intended for records that require platform, encoding and or language localization.

key value type description
openTypeNameRecords list A list of name records.

Name Table Record Format

The records are stored as dictionaries of the following format.

key value type description
nameID integer The name ID.
platformID integer The platform ID.
encodingID integer The encoding ID.
languageID integer The language ID.
string string The string value for the record.

Records must have a unique nameID, platformID, encodingID and languageID combination.

WOFF Fields

Many of these fields can be populated from generic fontinfo.plist elements, but since WOFF is a wrapper format they may not always be duplicated. As such, all of the WOFF fields are unique key/value pairs.

key value type description
woffMajorVersion integer Major version of the font.
woffMinorVersion integer Minor version of the font.
woffMetadataUniqueID string Identification string. Corresponds to the uniqueid element id attribute.
woffMetadataVendor string Font vendor. Corresponds to the vendor element name attribute.
woffMetadataVendorURL string Font vendor URL. Corresponds to the vendor element url attribute.
woffMetadataCredits list List of credit records. Corresponds to the credits element.
woffMetadataDescription string Description string. Corresponds to the description element.
woffMetadataLicense string License string. Corresponds to the license element.
woffMetadataLicenseID string License ID string. Corresponds to the license element id attribute.
woffMetadataLicenseURL string License URL string. Corresponds to the license element url attribute.
woffMetadataCopyright string Copyright string. Corresponds to the copyright element.
woffMetadataTrademark string Trademark string. Corresponds to the trademark element.
woffMetadataLicenseeName string Licensee name string. Corresponds to the licensee element name attribute.
woffMetadataRecords list List of metadata records. This record storage area is intended for records that require language localization.

Credit Record

The records are stored as dictionaries of the following format.

key value type description
name string The name for the credit.
url string The url for the credit.
role string The role for the credit.

Metadata Records

The records are stored as dictionaries of the following format.

key value type description
tag string The element tag of the record.
language string The language tag of the record.
text string The text for of record.
Localization Notes

The metadata attributes at the top of this file correspond to the default, unlocalized elements in the WOFF metadata. If an element needs to be localized, the localized element is stored as a Metadata Record in the woffMetadataRecords array. For example, this shows how the WOFF section of fontinfo.plist would look if it contained a localized license.

<key>woffMetadataLicense</key>
<string>A license goes here.</string>
<key>woffMetadataLicenseID</key>
<string>fontvendor-web-corporate-v2</string>
<key>woffMetadataRecords</key>
<array>
  <dict>
    <key>tag</key>
    <string>license</string>
    <key>language</key>
    <string>en</string>
    <key>text</key>
    <string>A license goes here.</string>
  </dict>
  <dict>
    <key>tag</key>
    <string>license</string>
    <key>language</key>
    <string>fr</string>
    <key>text</key>
    <string>Un permis va ici.</string>
  </dict>
</array>

kerning.plist

The structure of the file is now a dictionary of key value pairs. These key value pairs do not represent the kerning pairs as in UFO 1 and UFO 2. The structure is as follows.

key value type description default value
leftGroupPrefix string An arbitrary string that defines the group name prefix for left kerning groups used in the pairs dictionary. This string should not be the same as the string in rightGroupPrefix. None
rightGroupPrefix string An arbitrary string that defines the group name prefix for right kerning groups used in the pairs dictionary. This string should not be the same as the string in leftGroupPrefix. None
pairs dictionary Keys are left glyph or group names and values are dictionaries. These dictionaries contain right glyph or group names as keys and kerning values as the values. Glyphs or groups in the pairs are not required to be in the font. None

Notes

If an application allows the user to edit group kerning (aka class kerning), the group prefixes must be registered. All members of the pairs defined in the pairs dictionary should be assumed to be glyphs if the appropriate members do not start with the leftGroupPrefix or the rightGroupPrefix. This represents a conceptual change from UFO 1 and UFO 2. The change is necessary to eliminate ambiguities that could arise in the interpretation of group based kerning.

Converting to UFO 3 formatted kerning

A conversion algorithm needs to be developed.

Example

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>leftGroupPrefix</key>
  <string>@left_</string>
  <key>rightGroupPrefix</key>
  <string>@right_</string>
  <key>pairs</key>
  <dict>
    <key>@left_A</key>
    <dict>
      <key>@right_B</key>
      <integer>-10</integer>
      <key>X</key>
      <integer>-10</integer>
      <key>Z</key>
      <integer>-15</integer>
    </dict>
    <key>X</key>
    <dict>
      <key>Q</key>
      <integer>-10</integer>
    </dict>
  </dict>
</dict>
</plist>

data directory

This directory allows applications to store application specific data that is too complex or too large for lib.plist. The items within the directory may be either files or directories. The only requirement is that the top level files and directories follow the same reverse domain naming convention used in lib.plist. Applications are required to copy the entire data directory tree.

If an application uses the data directory to store its own outline data or data that is dependent on the outline data stored elsewhere in the UFO, it is the responsibility of that application to ensure that the data in glyphs and glyphs.* is up to date. The outline data in glyphs and glyphs.* is always considered current.

Color Definitions

Several elements have a color attribute that defines a color value to be applied to the element. A color definition is defined as a string containing a comma-separated sequence of four integers or floats between 0 and 1. White space characters are allowed around the numerical values. The values in the string define the red, green, blue and alpha components of the color. The color is always specified in the sRGB color space.

Hinting Data

One thing that is up for consideration in UFO 3 is the inclusion of Postscript and TrueType hinting data or an abstraction of hinting data. There are several issues that complicate this. One is that no member of the UFO specification maintenance team is an expert in hinting. We are looking into the specification, but it is a very deep subject. We must find an application independent format for storing this data.

If you are an expert in Postscript or TrueType hinting data structures and would like to help, please contact us.

Compact UFO

A couple of people have asked about creating a compacted version of the UFO. The easiest way to do this would be to put the contents of the UFO into a zip archive. On a general level, this seems easy enough to do in the specification, there are precedents for compacting packages this way and there would be some benefits for the user. However, the implementation of this will be complicated for applications.

By design the UFO doesn’t place a limit on how many glyphs can be in a font, so there could be lots and lots of GLIF files within a UFO. (Modern file systems would allow for up to 4,294,967,295 GLIF files.) The nice thing about the existing UFO structure is that it allows for very efficient management of the GLIF files. Not all glyphs must be loaded all of the time and saving procedures are very simple—if a glyph is to be removed, it is removed with an operating system call; if a glyph is unchanged since loading, the existing GLIF doesn’t need to be resaved; a “save as” operation can be initiated with a directory tree copy. Our experiments with creating a compact version of the UFO, for example inside of a zip archive, have indicated that the aforementioned simplicity is no longer available. In the case of zip archives, files cannot be programmatically removed from or replaced in an existing zip. (At least they can’t with the Python API.) This means that the entire contents of the UFO must be rewritten with each save. If there are a large number of glyphs, this could introduce serious memory issues. One way around this may be to do a directory tree copy to a temporary location, make the UFO changes, recompress and replace the existing file. This could lead to serious performance issues, so it needs to be studied before moving forward with this addition to the specification.

While this is under consideration, it is unlikely to make it into the UFO 3 specification.