2022-04-14 15:05:20 +01:00
|
|
|
#######################################################
|
|
|
|
designspaceLib: Read, write, and edit designspace files
|
|
|
|
#######################################################
|
2017-11-29 12:03:34 +00:00
|
|
|
|
2022-04-14 15:05:20 +01:00
|
|
|
Implements support for reading and manipulating ``designspace`` files.
|
|
|
|
Allows the users to define axes, rules, sources, variable fonts and instances,
|
2024-09-16 12:48:15 +01:00
|
|
|
and their ``STAT`` information.
|
2017-11-29 12:03:34 +00:00
|
|
|
|
|
|
|
.. toctree::
|
|
|
|
:maxdepth: 1
|
|
|
|
|
2022-04-14 15:05:20 +01:00
|
|
|
python
|
|
|
|
xml
|
2017-11-29 12:03:34 +00:00
|
|
|
scripting
|
|
|
|
|
2022-04-14 15:05:20 +01:00
|
|
|
|
|
|
|
Notes
|
|
|
|
=====
|
|
|
|
|
|
|
|
Paths and filenames
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
A designspace file needs to store many references to UFO files.
|
|
|
|
|
|
|
|
- designspace files can be part of versioning systems and appear on
|
|
|
|
different computers. This means it is not possible to store absolute
|
|
|
|
paths.
|
|
|
|
- So, all paths are relative to the designspace document path.
|
|
|
|
- Using relative paths allows designspace files and UFO files to be
|
|
|
|
**near** each other, and that they can be **found** without enforcing
|
|
|
|
one particular structure.
|
|
|
|
- The **filename** attribute in the ``SourceDescriptor`` and
|
|
|
|
``InstanceDescriptor`` classes stores the preferred relative path.
|
|
|
|
- The **path** attribute in these objects stores the absolute path. It
|
|
|
|
is calculated from the document path and the relative path in the
|
|
|
|
filename attribute when the object is created.
|
|
|
|
- Only the **filename** attribute is written to file.
|
|
|
|
- Both **filename** and **path** must use forward slashes (``/``) as
|
|
|
|
path separators, even on Windows.
|
|
|
|
|
|
|
|
Right before we save we need to identify and respond to the following
|
|
|
|
situations:
|
|
|
|
|
|
|
|
In each descriptor, we have to do the right thing for the filename
|
|
|
|
attribute. Before writing to file, the ``documentObject.updatePaths()``
|
|
|
|
method prepares the paths as follows:
|
|
|
|
|
|
|
|
**Case 1**
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
descriptor.filename == None
|
|
|
|
descriptor.path == None
|
|
|
|
|
|
|
|
**Action**
|
|
|
|
|
|
|
|
- write as is, descriptors will not have a filename attr. Useless, but
|
|
|
|
no reason to interfere.
|
|
|
|
|
|
|
|
**Case 2**
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
descriptor.filename == "../something"
|
|
|
|
descriptor.path == None
|
|
|
|
|
|
|
|
**Action**
|
|
|
|
|
|
|
|
- write as is. The filename attr should not be touched.
|
|
|
|
|
|
|
|
**Case 3**
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
descriptor.filename == None
|
|
|
|
descriptor.path == "~/absolute/path/there"
|
|
|
|
|
|
|
|
**Action**
|
|
|
|
|
|
|
|
- calculate the relative path for filename. We're not overwriting some
|
|
|
|
other value for filename, it should be fine.
|
|
|
|
|
|
|
|
**Case 4**
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
descriptor.filename == '../somewhere'
|
|
|
|
descriptor.path == "~/absolute/path/there"
|
|
|
|
|
|
|
|
**Action**
|
|
|
|
|
|
|
|
- There is a conflict between the given filename, and the path. The
|
|
|
|
difference could have happened for any number of reasons. Assuming
|
|
|
|
the values were not in conflict when the object was created, either
|
|
|
|
could have changed. We can't guess.
|
|
|
|
- Assume the path attribute is more up to date. Calculate a new value
|
|
|
|
for filename based on the path and the document path.
|
|
|
|
|
|
|
|
Recommendation for editors
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
- If you want to explicitly set the **filename** attribute, leave the
|
|
|
|
path attribute empty.
|
|
|
|
- If you want to explicitly set the **path** attribute, leave the
|
|
|
|
filename attribute empty. It will be recalculated.
|
|
|
|
- Use ``documentObject.updateFilenameFromPath()`` to explicitly set the
|
|
|
|
**filename** attributes for all instance and source descriptors.
|
|
|
|
|
|
|
|
|
|
|
|
Common Lib Key Registry
|
|
|
|
=======================
|
|
|
|
|
|
|
|
public.skipExportGlyphs
|
|
|
|
-----------------------
|
|
|
|
|
|
|
|
This lib key works the same as the UFO lib key with the same name. The
|
|
|
|
difference is that applications using a Designspace as the corner stone of the
|
|
|
|
font compilation process should use the lib key in that Designspace instead of
|
|
|
|
any of the UFOs. If the lib key is empty or not present in the Designspace, all
|
|
|
|
glyphs should be exported, regardless of what the same lib key in any of the
|
|
|
|
UFOs says.
|
|
|
|
|
2023-11-28 11:31:19 -05:00
|
|
|
public.fontInfo
|
|
|
|
-----------------------
|
|
|
|
|
2023-12-05 15:52:42 -05:00
|
|
|
This lib key, when included in the ``<lib>`` element inside an ``<instance>``
|
|
|
|
or ``<variable-font>`` tag, or the ``<lib>`` element at the root of a
|
|
|
|
designspace document, allows for direct manipulation of font info data in
|
2023-11-28 18:08:17 -05:00
|
|
|
instances and variable fonts. The lib value must follow the
|
2023-11-28 11:31:19 -05:00
|
|
|
`UFO3 fontinfo.plist specification <https://unifiedfontobject.org/versions/ufo3/fontinfo.plist/>`_,
|
|
|
|
and should functionally appear to be a property list dictionary with the same
|
|
|
|
structure as the ``fontinfo.plist`` file in a UFO.
|
|
|
|
|
|
|
|
All font info items in the UFO fontinfo.plist specification should be able to
|
|
|
|
be defined in the ``public.fontInfo`` lib. Checking validity of the data using
|
|
|
|
``fontTools.ufoLib.validators`` is recommended but not required.
|
|
|
|
|
2023-12-05 15:52:42 -05:00
|
|
|
All font info items for a variable font or an instance must be inherited using
|
|
|
|
the following order, in order of descending priority:
|
|
|
|
|
|
|
|
#. The ``public.fontInfo`` key in the ``<lib>`` element of the ``<variable-font>``
|
|
|
|
or ``<instance>`` elements.
|
2023-12-07 15:41:30 -05:00
|
|
|
#. XML attributes for names (i.e. ``familyname``, ``stylename``, etc.), if the
|
|
|
|
target is an ``<instance>`` element.
|
2023-12-05 15:52:42 -05:00
|
|
|
#. The ``public.fontInfo`` key found in the ``<lib>`` element of the designspace
|
|
|
|
document's root.
|
|
|
|
#. The ``fontinfo.plist`` in the UFO source at the origin of the interpolation
|
|
|
|
space.
|
|
|
|
|
|
|
|
Absence of a font info key from the value of a ``public.fontInfo`` lib does
|
|
|
|
**not** mean a that piece of font info should be interpreted as being undefined.
|
2023-12-07 15:41:30 -05:00
|
|
|
A tool generating the variable font or instance should recursively continue on
|
|
|
|
to the next level of the inheritence order and apply the value found there, if
|
|
|
|
any. If the tool makes it to the end of the inheritence order without finding a
|
|
|
|
valid value for a given font info key, it should then be considered undefined.
|
|
|
|
In the case of any conflicting values for a font info key, the value highest in
|
|
|
|
the inheritance order must be chosen over the others.
|
2022-04-14 15:05:20 +01:00
|
|
|
|
|
|
|
Implementation and differences
|
|
|
|
==============================
|
|
|
|
|
|
|
|
The designspace format has gone through considerable development.
|
|
|
|
|
|
|
|
- the format was originally written for MutatorMath.
|
2023-05-30 22:33:38 -06:00
|
|
|
- the format is now also used in fontTools.varLib.
|
2022-04-14 15:05:20 +01:00
|
|
|
- not all values are be required by all implementations.
|
|
|
|
|
2023-05-30 22:33:38 -06:00
|
|
|
varLib vs. MutatorMath
|
2022-04-14 15:05:20 +01:00
|
|
|
----------------------
|
|
|
|
|
2023-05-30 22:33:38 -06:00
|
|
|
There are some differences between the way MutatorMath and fontTools.varLib handle designspaces.
|
2022-04-14 15:05:20 +01:00
|
|
|
|
2023-05-30 22:33:38 -06:00
|
|
|
- varLib does not support anisotropic interpolations.
|
2022-04-14 15:05:20 +01:00
|
|
|
- MutatorMath will extrapolate over the boundaries of
|
2023-05-30 22:33:38 -06:00
|
|
|
the axes. varLib can not (at the moment).
|
|
|
|
- varLib requires much less data to define an instance than
|
2022-04-14 15:05:20 +01:00
|
|
|
MutatorMath.
|
2023-05-30 22:33:38 -06:00
|
|
|
- The goals of varLib and MutatorMath are different, so not all
|
2022-04-14 15:05:20 +01:00
|
|
|
attributes are always needed.
|
|
|
|
|
|
|
|
|
|
|
|
Rules and generating static UFO instances
|
|
|
|
-----------------------------------------
|
|
|
|
|
|
|
|
When making instances as UFOs from a designspace with rules, it can
|
|
|
|
be useful to evaluate the rules so that the characterset of the UFO
|
|
|
|
reflects, as much as possible, the state of a variable font when seen
|
|
|
|
at the same location. This can be done by some swapping and renaming of
|
|
|
|
glyphs.
|
|
|
|
|
|
|
|
While useful for proofing or development work, it should be noted that
|
|
|
|
swapping and renaming leaves the UFOs with glyphnames that are no longer
|
|
|
|
descriptive. For instance, after a swap ``dollar.bar`` could contain a shape
|
|
|
|
without a bar. Also, when the swapped glyphs are part of other GSUB variations
|
|
|
|
it can become complex very quickly. So proceed with caution.
|
|
|
|
|
|
|
|
- Assuming ``rulesProcessingLast = True``:
|
|
|
|
- We need to swap the glyphs so that the original shape is still available.
|
|
|
|
For instance, if a rule swaps ``a`` for ``a.alt``, a glyph
|
|
|
|
that references ``a`` in a component would then show the new ``a.alt``.
|
|
|
|
- But that can lead to unexpected results, the two glyphs may have different
|
|
|
|
widths or height. So, glyphs that are not specifically referenced in a rule
|
|
|
|
**should not change appearance**. That means that the implementation that swaps
|
|
|
|
``a`` and ``a.alt`` also swap all components that reference these
|
|
|
|
glyphs in order to preserve their appearance.
|
|
|
|
- The swap function also needs to take care of swapping the names in
|
|
|
|
kerning data and any GPOS code.
|
|
|
|
|
|
|
|
Version history
|
|
|
|
===============
|
|
|
|
|
2023-05-30 22:32:18 -06:00
|
|
|
Version 5.1
|
|
|
|
-----------
|
|
|
|
|
|
|
|
The format was extended to support arbitrary mapping between input and output
|
2023-06-01 11:02:28 -06:00
|
|
|
designspace locations. The ``<axes>`` elements now can have a ``<mappings>``
|
|
|
|
element that specifies such mappings, which when present carries data that is
|
|
|
|
used to compile to an ``avar`` version 2 table.
|
2023-05-30 22:32:18 -06:00
|
|
|
|
2022-04-14 15:05:20 +01:00
|
|
|
Version 5.0
|
|
|
|
-----------
|
|
|
|
|
|
|
|
The format was extended to describe the entire design space of a reasonably
|
|
|
|
regular font family in one file, with global data about the family to reduce
|
|
|
|
repetition in sub-sections. "Reasonably regular" means that the sources and
|
|
|
|
instances across the previously multiple Designspace files are positioned on a
|
|
|
|
grid and derive their metadata (like style name) in a way that's compatible with
|
|
|
|
the STAT model, based on their axis positions. Axis mappings must be the same
|
|
|
|
across the entire space.
|
|
|
|
|
|
|
|
1. Each axis can have labels attached to stops within the axis range, analogous to the
|
|
|
|
`OpenType STAT <https://docs.microsoft.com/en-us/typography/opentype/spec/stat>`_
|
|
|
|
table. Free-standing labels for locations are also allowed. The data is intended
|
|
|
|
to be compiled into a ``STAT`` table.
|
|
|
|
2. The axes can be discrete, to say that they do not interpolate, like a distinctly
|
|
|
|
constructed upright and italic variant of a family.
|
|
|
|
3. The data can be used to derive style and PostScript names for instances.
|
|
|
|
4. A new ``variable-fonts`` element can subdivide the Designspace into multiple subsets that
|
|
|
|
mix and match the globally available axes. It is possible for these sub-spaces to have
|
|
|
|
a different default location from the global default location. It is required if the
|
|
|
|
Designspace contains a discrete axis and you want to produce a variable font.
|
|
|
|
|
|
|
|
What is currently not supported is e.g.
|
|
|
|
|
|
|
|
1. A setup where different sources sit at the same logical location in the design space,
|
|
|
|
think "MyFont Regular" and "MyFont SmallCaps Regular". (this situation could be
|
|
|
|
encoded by adding a "SmallCaps" discrete axis, if that makes sense).
|
|
|
|
2. Anisotropic locations for axis labels.
|
|
|
|
|
|
|
|
Older versions
|
|
|
|
--------------
|
|
|
|
|
|
|
|
- In some implementations that preceed Variable Fonts, the `copyInfo`
|
|
|
|
flag in a source indicated the source was to be treated as the default.
|
|
|
|
This is no longer compatible with the assumption that the default font
|
|
|
|
is located on the default value of each axis.
|
|
|
|
- Older implementations did not require axis records to be present in
|
|
|
|
the designspace file. The axis extremes for instance were generated
|
|
|
|
from the locations used in the sources. This is no longer possible.
|
|
|
|
|