Technical Bulletin: UFO 3 Export

Applicability

As of 2018.12.28, the changes described are in the master branch. Current plans call for a release by the end of January 2019.

Overview

Until recently, FontForge had one import/export format for Unified Font Object (UFO) files, entirely compliant with neither the UFO 2 nor UFO 3 specification. Recent changes differentiate the two formats and may require minor workflow changes by users. There are no issues that make upgrading FontForge impractical.

Background

Historically, developers of typefaces and typeface software worked around limitations in UFO 2 by adding undocumented features to files marked as conforming to the UFO 2 specification. FontForge supported many of these extra features, and many of them became part of the UFO 3 specification, some mostly as used (layercontents.plist, for example) and others with changes (metrics groups). In order to maximize support for hybrid files, FontForge did not distinguish between UFO 2 and UFO 3 files. It would read layercontents.plist if present, for example, and emit it in all cases (with the expectation that UFO 2 software would ignore it). It would also choose the metrics group naming scheme based on the names used in the input file. FontForge flagged all UFO directories as having version 2 and glif files as having version 1.

With wider adoption of UFO 3, compliance with the specification has become more important and less problematic.

Changes

FontForge now formally distinguishes between UFO 2 and UFO 3 on import and export, with most non-compliant features removed from UFO 2 export. It also adds support for new UFO 3 features like guidelines and anchor tags (rather than named single points as were common in UFO 2).

Expected Impact

UFO 2 files with extra information may not export with all information after an import/export cycle through FontForge. Workflows that pass compliant UFO 3 files through FontForge may need to change scripts and file extensions.

Technical Details

UFO Version Selection

FontForge uses file extensions to refer to file formats. UFO 2 is “ufo2” to FontForge, and UFO 3 is “ufo3”. For convenience, the “ufo” extension now refers to UFO 3 rather than UFO 2 but is subject to change in the future. On import, FontForge will infer version from the imported file and parse entities permissively. On export, though, it will select the UFO version according to the format selected in the “Generate Fonts…” dialog or, in scripting mode, the extension of the file to be exported. If you have a script that you want to emit a version 3 UFO directory, please use the extension “ufo3”, and if you have a script that you want to emit a version 2 UFO direcotry, please use the extension “ufo2”. This is an unfortunate limitation of the current scripting conventions.

Guidelines

FontForge implements a single font-wide “grid” layer to be used for guides. It can have any type of supported spline. UFO 3 instead implements guidelines, each of which has just a base point and an angle but also a name, an identifier, and a color. There are global guidelines, and there are per glyph-layer guidelines. Mapping between the two systems required some sacrifice in exposure of UFO features in order to maintain usability.

FontForge will convert the UFO global guidelines to paths in the grid layer and back on import and export, with the guideline name in the UFO attached to the first point in the FontForge grid path and the identifier in the UFO dropped. The guideline exported to UFO uses the first and last points on the path in FontForge, with additional detail dropped.

FontForge will store glyph-layer-specific guidelines from UFO out of sight but will round-trip them correctly with names, identifiers, and colors. SFD stores them with the Guideline tag. The “Clear Special Data” menu item and the “clearSpecialData” Python function clear them and all other non-accessible UFO data.

Upgrade Preparation

  • If the output version is not important, and you are ready to start using UFO 3, no changes are necessary. Exporting to UFO via the graphical interface and via the scripting interface will now generate UFO 3. Remember that the version is subject to change in the future.
  • If you have a manual workflow that requires UFO 3 output, be sure to specify Unified Font Object 3 (“ufo3”) format on output.
  • If you have a scripted workflow that requires UFO 3 output, be sure to use a directory name that ends in “.ufo3”. If you want the name to end in “.ufo”, generate first and then move the resulting directory.
  • If you have a compliant UFO 2 file, and you want to keep output in UFO 2 format, be sure to specify Unified Font Object 2 (“ufo2”) format on output.
  • If you have a workflow that requires UFO 2 output and deals only with compliant UFO 2 input files, and you want to keep output in UFO 2 format, be sure to use a directory name that ends in “.ufo2”. If you want the name to end in “.ufo”, generate first and then move the resulting directory.
  • If you have a file that purports to follow UFO 2 (“formatVersion” set to “2” in metainfo.plist) but has a layercontents.plist file, consider importing it as-is and exporting to UFO 3 in order to preserve the data.
  • If you have a workflow that requires UFO 2 output with UFO 3 extensions, either stay on the 2017 version of FontForge or try exporting to UFO 3 (as previously described) and then changing the UFO version (as previously described).

Additional Details

See also pull request 3388.