[designspaceLib] Update documentation and add version 5
This commit is contained in:
parent
a7974986c3
commit
5a842cc249
@ -1,18 +1,217 @@
|
|||||||
##############
|
#######################################################
|
||||||
designspaceLib
|
designspaceLib: Read, write, and edit designspace files
|
||||||
##############
|
#######################################################
|
||||||
|
|
||||||
MutatorMath started out with its own reader and writer for designspaces.
|
Implements support for reading and manipulating ``designspace`` files.
|
||||||
Since then the use of designspace has broadened and it would be useful
|
Allows the users to define axes, rules, sources, variable fonts and instances,
|
||||||
to have a reader and writer that are independent of a specific system.
|
and their STAT information.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
readme
|
python
|
||||||
|
xml
|
||||||
scripting
|
scripting
|
||||||
|
|
||||||
.. automodule:: fontTools.designspaceLib
|
|
||||||
:inherited-members:
|
Notes
|
||||||
:members:
|
=====
|
||||||
:undoc-members:
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation and differences
|
||||||
|
==============================
|
||||||
|
|
||||||
|
The designspace format has gone through considerable development.
|
||||||
|
|
||||||
|
- the format was originally written for MutatorMath.
|
||||||
|
- the format is now also used in fontTools.varlib.
|
||||||
|
- not all values are be required by all implementations.
|
||||||
|
|
||||||
|
Varlib vs. MutatorMath
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
There are some differences between the way MutatorMath and fontTools.varlib handle designspaces.
|
||||||
|
|
||||||
|
- Varlib does not support anisotropic interpolations.
|
||||||
|
- MutatorMath will extrapolate over the boundaries of
|
||||||
|
the axes. Varlib can not (at the moment).
|
||||||
|
- Varlib requires much less data to define an instance than
|
||||||
|
MutatorMath.
|
||||||
|
- The goals of Varlib and MutatorMath are different, so not all
|
||||||
|
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
|
||||||
|
===============
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
199
Doc/source/designspaceLib/python.rst
Normal file
199
Doc/source/designspaceLib/python.rst
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
################################
|
||||||
|
1 DesignSpaceDocument Python API
|
||||||
|
################################
|
||||||
|
|
||||||
|
An object to read, write and edit interpolation systems for typefaces.
|
||||||
|
Define sources, axes, rules, variable fonts and instances.
|
||||||
|
|
||||||
|
Get an overview of the available classes in the Class Diagram below:
|
||||||
|
|
||||||
|
.. figure:: v5_class_diagram.png
|
||||||
|
:width: 650px
|
||||||
|
:alt: UML class diagram of designspaceLib
|
||||||
|
|
||||||
|
UML class diagram of designspaceLib. Click to enlarge.
|
||||||
|
|
||||||
|
.. contents:: Table of contents
|
||||||
|
:local:
|
||||||
|
|
||||||
|
.. _designspacedocument-object:
|
||||||
|
|
||||||
|
===================
|
||||||
|
DesignSpaceDocument
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::DesignSpaceDocument
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
.. _axis-descriptor-object:
|
||||||
|
|
||||||
|
AxisDescriptor
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::AxisDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:inherited-members: SimpleDescriptor
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
DiscreteAxisDescriptor
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::DiscreteAxisDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:inherited-members: SimpleDescriptor
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
AxisLabelDescriptor
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::AxisLabelDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
LocationLabelDescriptor
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::LocationLabelDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
RuleDescriptor
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::RuleDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
Evaluating rules
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. autofunction:: fontTools.designspaceLib::evaluateRule
|
||||||
|
.. autofunction:: fontTools.designspaceLib::evaluateConditions
|
||||||
|
.. autofunction:: fontTools.designspaceLib::processRules
|
||||||
|
|
||||||
|
|
||||||
|
.. _source-descriptor-object:
|
||||||
|
|
||||||
|
SourceDescriptor
|
||||||
|
================
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::SourceDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
VariableFontDescriptor
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::VariableFontDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
RangeAxisSubsetDescriptor
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::RangeAxisSubsetDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
ValueAxisSubsetDescriptor
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::ValueAxisSubsetDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
.. _instance-descriptor-object:
|
||||||
|
|
||||||
|
InstanceDescriptor
|
||||||
|
==================
|
||||||
|
|
||||||
|
.. autoclass:: fontTools.designspaceLib::InstanceDescriptor
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
||||||
|
|
||||||
|
.. _subclassing-descriptors:
|
||||||
|
|
||||||
|
=======================
|
||||||
|
Subclassing descriptors
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The DesignSpaceDocument can take subclassed Reader and Writer objects.
|
||||||
|
This allows you to work with your own descriptors. You could subclass
|
||||||
|
the descriptors. But as long as they have the basic attributes the
|
||||||
|
descriptor does not need to be a subclass.
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
class MyDocReader(BaseDocReader):
|
||||||
|
axisDescriptorClass = MyAxisDescriptor
|
||||||
|
discreteAxisDescriptorClass = MyDiscreteAxisDescriptor
|
||||||
|
axisLabelDescriptorClass = MyAxisLabelDescriptor
|
||||||
|
locationLabelDescriptorClass = MyLocationLabelDescriptor
|
||||||
|
ruleDescriptorClass = MyRuleDescriptor
|
||||||
|
sourceDescriptorClass = MySourceDescriptor
|
||||||
|
variableFontsDescriptorClass = MyVariableFontDescriptor
|
||||||
|
valueAxisSubsetDescriptorClass = MyValueAxisSubsetDescriptor
|
||||||
|
rangeAxisSubsetDescriptorClass = MyRangeAxisSubsetDescriptor
|
||||||
|
instanceDescriptorClass = MyInstanceDescriptor
|
||||||
|
|
||||||
|
class MyDocWriter(BaseDocWriter):
|
||||||
|
axisDescriptorClass = MyAxisDescriptor
|
||||||
|
discreteAxisDescriptorClass = MyDiscreteAxisDescriptor
|
||||||
|
axisLabelDescriptorClass = MyAxisLabelDescriptor
|
||||||
|
locationLabelDescriptorClass = MyLocationLabelDescriptor
|
||||||
|
ruleDescriptorClass = MyRuleDescriptor
|
||||||
|
sourceDescriptorClass = MySourceDescriptor
|
||||||
|
variableFontsDescriptorClass = MyVariableFontDescriptor
|
||||||
|
valueAxisSubsetDescriptorClass = MyValueAxisSubsetDescriptor
|
||||||
|
rangeAxisSubsetDescriptorClass = MyRangeAxisSubsetDescriptor
|
||||||
|
instanceDescriptorClass = MyInstanceDescriptor
|
||||||
|
|
||||||
|
myDoc = DesignSpaceDocument(MyDocReader, MyDocWriter)
|
||||||
|
|
||||||
|
|
||||||
|
==============
|
||||||
|
Helper modules
|
||||||
|
==============
|
||||||
|
|
||||||
|
fontTools.designspaceLib.split
|
||||||
|
==============================
|
||||||
|
|
||||||
|
See :ref:`Scripting > Working with DesignSpace version 5 <working_with_v5>`
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
.. automodule:: fontTools.designspaceLib.split
|
||||||
|
|
||||||
|
|
||||||
|
fontTools.designspaceLib.stat
|
||||||
|
=============================
|
||||||
|
|
||||||
|
.. automodule:: fontTools.designspaceLib.stat
|
||||||
|
|
||||||
|
|
||||||
|
fontTools.designspaceLib.statNames
|
||||||
|
==================================
|
||||||
|
|
||||||
|
.. automodule:: fontTools.designspaceLib.statNames
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
#######################
|
#########################
|
||||||
Scripting a designspace
|
3 Scripting a designspace
|
||||||
#######################
|
#########################
|
||||||
|
|
||||||
It can be useful to build a designspace with a script rather than
|
It can be useful to build a designspace with a script rather than
|
||||||
construct one with an interface like
|
construct one with an interface like
|
||||||
@ -88,6 +88,7 @@ OpenType <https://www.microsoft.com/typography/otspec/avar.htm>`__.
|
|||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
|
# (user space, design space), (user space, design space)...
|
||||||
a1.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)]
|
a1.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)]
|
||||||
|
|
||||||
Make a source object
|
Make a source object
|
||||||
@ -241,7 +242,7 @@ This is how you check the default font.
|
|||||||
Generating?
|
Generating?
|
||||||
***********
|
***********
|
||||||
|
|
||||||
You can generate the UFO's with MutatorMath:
|
You can generate the UFOs with MutatorMath:
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
@ -251,3 +252,39 @@ You can generate the UFO's with MutatorMath:
|
|||||||
- Assuming the outline data in the masters is compatible.
|
- Assuming the outline data in the masters is compatible.
|
||||||
|
|
||||||
Or you can use the file in making a **variable font** with varlib.
|
Or you can use the file in making a **variable font** with varlib.
|
||||||
|
|
||||||
|
|
||||||
|
.. _working_with_v5:
|
||||||
|
|
||||||
|
**********************************
|
||||||
|
Working with DesignSpace version 5
|
||||||
|
**********************************
|
||||||
|
|
||||||
|
The new version 5 allows "discrete" axes, which do not interpolate across their
|
||||||
|
values. This is useful to store in one place family-wide data such as the STAT
|
||||||
|
information, however it prevents the usual things done on designspaces that
|
||||||
|
interpolate everywhere:
|
||||||
|
|
||||||
|
- checking that all sources are compatible for interpolation
|
||||||
|
- building variable fonts
|
||||||
|
|
||||||
|
In order to allow the above in tools that want to handle designspace v5,
|
||||||
|
the :mod:`fontTools.designspaceLib.split` module provides two methods to
|
||||||
|
split a designspace into interpolable sub-spaces,
|
||||||
|
:func:`splitInterpolable() <fontTools.designspaceLib.split.splitInterpolable>`
|
||||||
|
and then
|
||||||
|
:func:`splitVariableFonts() <fontTools.designspaceLib.split.splitVariableFonts>`.
|
||||||
|
|
||||||
|
|
||||||
|
.. figure:: v5_split_downconvert.png
|
||||||
|
:width: 680px
|
||||||
|
:alt: Example process diagram to check and build DesignSpace 5
|
||||||
|
|
||||||
|
Example process process to check and build Designspace 5.
|
||||||
|
|
||||||
|
|
||||||
|
Also, for older tools that don't know about the other version 5 additions such
|
||||||
|
as the STAT data fields, the function
|
||||||
|
:func:`convert5to4() <fontTools.designspaceLib.split.convert5to4>` allows to
|
||||||
|
strip new information from a designspace version 5 to downgrade it to a
|
||||||
|
collection of version 4 documents, one per variable font.
|
||||||
|
BIN
Doc/source/designspaceLib/v5_class_diagram.png
Normal file
BIN
Doc/source/designspaceLib/v5_class_diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 267 KiB |
292
Doc/source/designspaceLib/v5_class_diagram.puml
Normal file
292
Doc/source/designspaceLib/v5_class_diagram.puml
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
@startuml v5_class_diagram
|
||||||
|
|
||||||
|
title
|
||||||
|
Designspace v5 Class Diagram
|
||||||
|
|
||||||
|
<size:12>Note: the ""Descriptor"" suffix is omitted from most classes
|
||||||
|
end title
|
||||||
|
|
||||||
|
' left to right direction
|
||||||
|
|
||||||
|
skinparam class {
|
||||||
|
BackgroundColor<<New>> PaleGreen
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesignSpaceDocument {
|
||||||
|
+ formatVersion: str = None
|
||||||
|
+ <color:green><b><<New>> elidedFallbackName: str = None
|
||||||
|
+ rulesProcessingLast: bool = False
|
||||||
|
+ lib: Dict = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
note left of DesignSpaceDocument::elidedFallbackName
|
||||||
|
STAT Style Attributes Header field ""elidedFallbackNameID""
|
||||||
|
end note
|
||||||
|
|
||||||
|
abstract class AbstractAxis {
|
||||||
|
+ tag: str
|
||||||
|
+ name: str
|
||||||
|
+ labelNames: Dict[str, str]
|
||||||
|
+ hidden: bool
|
||||||
|
+ map: List[Tuple[float, float]]
|
||||||
|
+ <color:green><b><<New>> axisOrdering: int
|
||||||
|
}
|
||||||
|
DesignSpaceDocument *-- "*" AbstractAxis: axes >
|
||||||
|
note right of AbstractAxis::axisOrdering
|
||||||
|
STAT Axis Record field
|
||||||
|
end note
|
||||||
|
|
||||||
|
class Axis {
|
||||||
|
+ minimum: float
|
||||||
|
+ maximum: float
|
||||||
|
+ default: float
|
||||||
|
}
|
||||||
|
AbstractAxis <|--- Axis
|
||||||
|
note bottom of Axis
|
||||||
|
This is the usual
|
||||||
|
Axis, with a range
|
||||||
|
of values.
|
||||||
|
end note
|
||||||
|
|
||||||
|
class DiscreteAxis <<New>> {
|
||||||
|
+ values: List[float]
|
||||||
|
+ default: float
|
||||||
|
}
|
||||||
|
AbstractAxis <|--- DiscreteAxis
|
||||||
|
note bottom of DiscreteAxis
|
||||||
|
A discrete axis is not
|
||||||
|
interpolable, e.g.
|
||||||
|
Uprights vs Italics, and
|
||||||
|
so has "discrete" stops
|
||||||
|
instead of a continuous
|
||||||
|
range of values.
|
||||||
|
end note
|
||||||
|
|
||||||
|
Axis .[hidden] DiscreteAxis
|
||||||
|
|
||||||
|
class AxisLabel <<New>> {
|
||||||
|
+ userMinimum: Optional[float]
|
||||||
|
+ userValue: float
|
||||||
|
+ userMaximum: Optional[float]
|
||||||
|
+ name: str
|
||||||
|
+ elidable: bool
|
||||||
|
+ olderSibling: bool
|
||||||
|
+ linkedUserValue: Optional[float]
|
||||||
|
+ labelNames: Dict[str, str]
|
||||||
|
|
||||||
|
+ getFormat(): 1 | 2 | 3
|
||||||
|
}
|
||||||
|
note right of AxisLabel
|
||||||
|
Label for a
|
||||||
|
stop on an Axis
|
||||||
|
(STAT format
|
||||||
|
1,2,3)
|
||||||
|
end note
|
||||||
|
AbstractAxis *-- "*" AxisLabel: <<New>> \n axisLabels >
|
||||||
|
|
||||||
|
class LocationLabel <<New>> {
|
||||||
|
+ name: str
|
||||||
|
+ location: Dict[str, float]
|
||||||
|
+ elidable: bool
|
||||||
|
+ olderSibling: bool
|
||||||
|
+ labelNames: Dict[str, str]
|
||||||
|
}
|
||||||
|
note right of LocationLabel
|
||||||
|
Label for a
|
||||||
|
freestanding
|
||||||
|
location
|
||||||
|
(STAT format 4)
|
||||||
|
end note
|
||||||
|
DesignSpaceDocument *--- "*" LocationLabel: <<New>> \n locationLabels >
|
||||||
|
|
||||||
|
class Rule {
|
||||||
|
+ name: str
|
||||||
|
+ conditionSets: List[ConditionSet]
|
||||||
|
+ subs: Dict[str, str]
|
||||||
|
}
|
||||||
|
DesignSpaceDocument *- "*" Rule: rules >
|
||||||
|
|
||||||
|
class Source {
|
||||||
|
+ name: Optional[str]
|
||||||
|
+ filename: str
|
||||||
|
+ path: str
|
||||||
|
+ layerName: Optional[str]
|
||||||
|
+ <color:brown><s><<Deprecated>> location: Location
|
||||||
|
+ <color:green><b><<New>> designLocation: AnisotropicLocation
|
||||||
|
....
|
||||||
|
+ font: Optional[Font]
|
||||||
|
....
|
||||||
|
+ familyName: Optional[str]
|
||||||
|
+ styleName: Optional[str]
|
||||||
|
+ <color:green><b><<New>> localisedFamilyName: Dict
|
||||||
|
....
|
||||||
|
+ <color:brown><s><<Deprecated>> copyLib: bool
|
||||||
|
+ <color:brown><s><<Deprecated>> copyInfo: bool
|
||||||
|
+ <color:brown><s><<Deprecated>> copyGroups: bool
|
||||||
|
+ <color:brown><s><<Deprecated>> copyFeatures: bool
|
||||||
|
....
|
||||||
|
+ muteKerning: bool
|
||||||
|
+ muteInfo: bool
|
||||||
|
+ mutedGlyphNames: List[str]
|
||||||
|
----
|
||||||
|
+ <color:green><b><<New>> getFullDesignLocation(doc)
|
||||||
|
}
|
||||||
|
DesignSpaceDocument *-- "*" Source: sources >
|
||||||
|
note right of Source::localisedFamilyName
|
||||||
|
New field to allow generation
|
||||||
|
of localised instance names using
|
||||||
|
STAT information.
|
||||||
|
end note
|
||||||
|
note right of Source::copyGroups
|
||||||
|
These fields are already not meaningful
|
||||||
|
anymore in version 4 (the default source
|
||||||
|
will be used as "neutral" for groups, info
|
||||||
|
and features. ''copyLib'' can be emulated
|
||||||
|
by putting content in the designspace's lib.
|
||||||
|
end note
|
||||||
|
|
||||||
|
note as NLocSource
|
||||||
|
The location of
|
||||||
|
sources can still only
|
||||||
|
be defined in design
|
||||||
|
coordinates, and now
|
||||||
|
also by relying on
|
||||||
|
axis defaults.
|
||||||
|
|
||||||
|
To build the final,
|
||||||
|
"full" location, a
|
||||||
|
helper method is
|
||||||
|
provided, that uses
|
||||||
|
axis defaults and
|
||||||
|
axis mappings to
|
||||||
|
fill in the blanks.
|
||||||
|
end note
|
||||||
|
NLocSource . Source::designLocation
|
||||||
|
NLocSource . Source::getFullDesignLocation
|
||||||
|
|
||||||
|
class VariableFont <<New>> {
|
||||||
|
+ filename: str
|
||||||
|
+ lib: Dict
|
||||||
|
}
|
||||||
|
DesignSpaceDocument *--- "*" VariableFont: <<New>> \n variableFonts >
|
||||||
|
note right of VariableFont
|
||||||
|
A variable font is a
|
||||||
|
subset of the designspace
|
||||||
|
where everything interpolates
|
||||||
|
(and so can be compiled into
|
||||||
|
an OpenType variable font).
|
||||||
|
end note
|
||||||
|
|
||||||
|
abstract class AbstractAxisSubset <<New>> {
|
||||||
|
+ name: str
|
||||||
|
}
|
||||||
|
VariableFont *-- "*" AbstractAxisSubset: <<New>> \n axisSubsets >
|
||||||
|
|
||||||
|
note right of AbstractAxisSubset
|
||||||
|
An axis subset selects a range
|
||||||
|
or a spot on each the available
|
||||||
|
axes from the whole designspace.
|
||||||
|
|
||||||
|
By default, only the default value
|
||||||
|
of each axis is used to define the
|
||||||
|
variable font.
|
||||||
|
|
||||||
|
Continuous axes can be specified
|
||||||
|
to include their full range instead;
|
||||||
|
or a subset of the range.
|
||||||
|
|
||||||
|
Discrete axes can be specified
|
||||||
|
to include a different spot than the
|
||||||
|
default.
|
||||||
|
end note
|
||||||
|
|
||||||
|
class RangeAxisSubset <<New>> {
|
||||||
|
+ userMinimum: float
|
||||||
|
+ userDefault: float
|
||||||
|
+ userMaximum: float
|
||||||
|
}
|
||||||
|
AbstractAxisSubset <|-- RangeAxisSubset
|
||||||
|
|
||||||
|
class ValueAxisSubset <<New>> {
|
||||||
|
+ userValue: float
|
||||||
|
}
|
||||||
|
AbstractAxisSubset <|-- ValueAxisSubset
|
||||||
|
|
||||||
|
class Instance {
|
||||||
|
+ filename: str
|
||||||
|
+ path: str
|
||||||
|
+ <color:brown><s><<Deprecated>> location: Location
|
||||||
|
+ <color:green><b><<New>> locationLabel: str
|
||||||
|
+ <color:green><b><<New>> designLocation: AnisotropicLocation
|
||||||
|
+ <color:green><b><<New>> userLocation: SimpleLocation
|
||||||
|
....
|
||||||
|
+ font: Optional[Font]
|
||||||
|
....
|
||||||
|
+ <color:orange><b><<Changed>> name: Optional[str]
|
||||||
|
+ <color:orange><b><<Changed>> familyName: Optional[str]
|
||||||
|
+ <color:orange><b><<Changed>> styleName: Optional[str]
|
||||||
|
+ <color:orange><b><<Changed>> postScriptFontName: Optional[str]
|
||||||
|
+ <color:orange><b><<Changed>> styleMapFamilyName: Optional[str]
|
||||||
|
+ <color:orange><b><<Changed>> styleMapStyleName: Optional[str]
|
||||||
|
+ localisedFamilyName: Dict
|
||||||
|
+ localisedStyleName: Dict
|
||||||
|
+ localisedStyleMapFamilyName: Dict
|
||||||
|
+ localisedStyleMapStyleName: Dict
|
||||||
|
....
|
||||||
|
+ <color:brown><s><<Deprecated>> glyphs: Dict
|
||||||
|
+ <color:brown><s><<Deprecated>> kerning: bool
|
||||||
|
+ <color:brown><s><<Deprecated>> info: bool
|
||||||
|
....
|
||||||
|
+ lib: Dict
|
||||||
|
----
|
||||||
|
+ <color:green><b><<New>> clearLocation()
|
||||||
|
+ <color:green><b><<New>> getLocationLabelDescriptor(doc)
|
||||||
|
+ <color:green><b><<New>> getFullDesignLocation(doc)
|
||||||
|
+ <color:green><b><<New>> getFullUserLocation(doc)
|
||||||
|
}
|
||||||
|
DesignSpaceDocument *-- "*" Instance: instances >
|
||||||
|
note right of Instance::locationLabel
|
||||||
|
The location can now alternatively
|
||||||
|
be a string = name of a LocationLabel
|
||||||
|
(STAT format 4). The instance then
|
||||||
|
adopts the location of that label.
|
||||||
|
See the Decovar example file.
|
||||||
|
end note
|
||||||
|
note right of Instance::styleMapStyleName
|
||||||
|
All the name field are now optional.
|
||||||
|
Their default values will be computed
|
||||||
|
using the provided STAT table data
|
||||||
|
and the STAT rules from the spec.
|
||||||
|
For styleMap{Family,Style}Name, they
|
||||||
|
would be computed using the STAT
|
||||||
|
""linkedUserValue"" fields.
|
||||||
|
end note
|
||||||
|
note right of Instance::glyphs
|
||||||
|
This attribute has been replaced by rules
|
||||||
|
end note
|
||||||
|
note right of Instance::kerning
|
||||||
|
All instances get kerning and info
|
||||||
|
nowadays.
|
||||||
|
end note
|
||||||
|
|
||||||
|
note as NLocInstance
|
||||||
|
The location of instances
|
||||||
|
can now be defined using
|
||||||
|
either:
|
||||||
|
- a STAT LocationLabel
|
||||||
|
- design coordinates
|
||||||
|
- user coordinates.
|
||||||
|
- relying on axis defaults
|
||||||
|
|
||||||
|
To build the final, "full"
|
||||||
|
location, a few helper
|
||||||
|
methods are provided,
|
||||||
|
that aggregate data from
|
||||||
|
these sources and apply
|
||||||
|
the axis mappings.
|
||||||
|
end note
|
||||||
|
NLocInstance . Instance::designLocation
|
||||||
|
NLocInstance . Instance::getFullDesignLocation
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
|
BIN
Doc/source/designspaceLib/v5_split_downconvert.png
Normal file
BIN
Doc/source/designspaceLib/v5_split_downconvert.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
147
Doc/source/designspaceLib/v5_split_downconvert.puml
Normal file
147
Doc/source/designspaceLib/v5_split_downconvert.puml
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
@startuml v5_split_downconvert
|
||||||
|
|
||||||
|
title
|
||||||
|
How to split and down-convert a DesignSpace version 5
|
||||||
|
<size:14>so that existing tools can work with it
|
||||||
|
end title
|
||||||
|
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
#lightgrey:DesignSpace 5.0
|
||||||
|
- with STAT data
|
||||||
|
- optional instance names
|
||||||
|
- with discrete axes
|
||||||
|
- with multiple VFs]
|
||||||
|
|
||||||
|
note left
|
||||||
|
- STAT data means that compilers will need
|
||||||
|
to write that data to the ouput TTFs
|
||||||
|
- optional instance names means that
|
||||||
|
compilers will need to generate any missing
|
||||||
|
names using the STAT data
|
||||||
|
- discrete axes mean that not all sources
|
||||||
|
are compatible for interpolation
|
||||||
|
- multiple VFs means that compilers will
|
||||||
|
need to output several TTFs for one DS
|
||||||
|
end note
|
||||||
|
|
||||||
|
split
|
||||||
|
split again
|
||||||
|
|
||||||
|
:""splitInterpolating()"";
|
||||||
|
|
||||||
|
note left
|
||||||
|
- Create one DS document per interpolating
|
||||||
|
sub-space, for example: with a discrete
|
||||||
|
axis for Upright vs Italics, create 2
|
||||||
|
DesignSpaces, one for the Uprights, and
|
||||||
|
one for the Italics.
|
||||||
|
- Expand all missing instance names using
|
||||||
|
the STAT data.
|
||||||
|
- Drop all the STAT data because as we start
|
||||||
|
taking out discrete axes, the sub-documents
|
||||||
|
lose STAT data anyway (only the full
|
||||||
|
document at the start of the process should
|
||||||
|
be used to generate the STAT table)
|
||||||
|
end note
|
||||||
|
|
||||||
|
split
|
||||||
|
|
||||||
|
#lightgrey:DesignSpace 5.0
|
||||||
|
- (no STAT data)
|
||||||
|
- (explicit instance names)
|
||||||
|
- (at discrete location #1)
|
||||||
|
- with multiple VFs]
|
||||||
|
|
||||||
|
note left
|
||||||
|
All sources in this sub-space are
|
||||||
|
(supposed to be) compatible for
|
||||||
|
interpolation
|
||||||
|
end note
|
||||||
|
|
||||||
|
split again
|
||||||
|
|
||||||
|
#lightgrey:DesignSpace 5.0
|
||||||
|
- (no STAT data)
|
||||||
|
- (explicit instance names)
|
||||||
|
- (at discrete location #2)
|
||||||
|
- with multiple VFs]
|
||||||
|
detach
|
||||||
|
|
||||||
|
split again
|
||||||
|
|
||||||
|
#lightgrey:etc
|
||||||
|
...]
|
||||||
|
detach
|
||||||
|
|
||||||
|
end split
|
||||||
|
|
||||||
|
:check compatibility;
|
||||||
|
:build compatible master TTFs with cu2qu;
|
||||||
|
|
||||||
|
:""splitVariableFonts()"";
|
||||||
|
|
||||||
|
note left
|
||||||
|
Create one DS document per variable font,
|
||||||
|
for example: the above document may
|
||||||
|
describe a weight and width space, out of
|
||||||
|
which we'll build 3 variable fonts:
|
||||||
|
full weight + width, weight only, width only.
|
||||||
|
end note
|
||||||
|
|
||||||
|
split
|
||||||
|
|
||||||
|
#lightgrey:DesignSpace 5.0
|
||||||
|
- (no STAT data)
|
||||||
|
- (explicit instance names)
|
||||||
|
- (at discrete location #1)
|
||||||
|
- (describing just VF #1)]
|
||||||
|
|
||||||
|
note left
|
||||||
|
This document looks very much
|
||||||
|
like version 4.1, you can just
|
||||||
|
change the version number at
|
||||||
|
the top and feed it to a tool
|
||||||
|
that doesn't know about v5;
|
||||||
|
see ""convert5to4()"".
|
||||||
|
end note
|
||||||
|
|
||||||
|
split again
|
||||||
|
|
||||||
|
#lightgrey:DesignSpace 5.0
|
||||||
|
- (no STAT data)
|
||||||
|
- (explicit instance names)
|
||||||
|
- (at discrete location #1)
|
||||||
|
- (describing just VF #2)]
|
||||||
|
detach
|
||||||
|
|
||||||
|
split again
|
||||||
|
|
||||||
|
#lightgrey:etc
|
||||||
|
...]
|
||||||
|
detach
|
||||||
|
|
||||||
|
end split
|
||||||
|
|
||||||
|
:""varLib.build()"";
|
||||||
|
|
||||||
|
#lightgrey:Variable font TTF
|
||||||
|
No STAT data]
|
||||||
|
|
||||||
|
end split
|
||||||
|
|
||||||
|
:""buildVFStatTable()"";
|
||||||
|
|
||||||
|
note left
|
||||||
|
Apply STAT data using the full document
|
||||||
|
from the start of the process + filtering
|
||||||
|
entries based on this VF's location
|
||||||
|
end note
|
||||||
|
|
||||||
|
#lightgrey:Variable font TTF
|
||||||
|
With STAT data]
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
@enduml
|
BIN
Doc/source/designspaceLib/v5_variable_fonts_vs_instances.png
Normal file
BIN
Doc/source/designspaceLib/v5_variable_fonts_vs_instances.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 141 KiB |
1014
Doc/source/designspaceLib/xml.rst
Normal file
1014
Doc/source/designspaceLib/xml.rst
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user