Skip to content

Commit

Permalink
Merge pull request #555 from googlefonts/new-instantiator
Browse files Browse the repository at this point in the history
New instantiator
  • Loading branch information
madig authored Aug 6, 2019
2 parents 6061608 + 2bba785 commit 5b8e0b7
Show file tree
Hide file tree
Showing 378 changed files with 14,845 additions and 12 deletions.
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ repos:
rev: 3.7.7
hooks:
- id: flake8
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.701
hooks:
- id: mypy
16 changes: 15 additions & 1 deletion Lib/fontmake/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ def main(args=None):
'E.g.: -i "Noto Sans Bold"; or -i ".* UI Condensed". '
"(for Glyphs or MutatorMath sources only). ",
)
outputGroup.add_argument(
"--use-mutatormath",
action="store_true",
help=(
"Use MutatorMath to generate instances (supports extrapolation and "
"anisotropic locations)."
),
)
outputGroup.add_argument(
"-M",
"--masters-as-instances",
Expand Down Expand Up @@ -366,7 +374,12 @@ def main(args=None):
exclude_args(
parser,
args,
["interpolate", "masters_as_instances", "interpolate_binary_layout"],
[
"interpolate",
"masters_as_instances",
"interpolate_binary_layout",
"use_mutatormath",
],
"variable output",
)
else:
Expand Down Expand Up @@ -405,6 +418,7 @@ def main(args=None):
args,
[
"interpolate",
"use_mutatormath",
"interpolate_binary_layout",
"round_instances",
"expand_features_to_instances",
Expand Down
101 changes: 94 additions & 7 deletions Lib/fontmake/font_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from functools import partial
from re import fullmatch

import attr
import ufo2ft
from defcon import Font
from defcon.objects.base import setUfoLibReadValidate, setUfoLibWriteValidate
Expand All @@ -36,6 +37,7 @@
from ufo2ft.featureWriters import FEATURE_WRITERS_KEY, loadFeatureWriters
from ufo2ft.util import makeOfficialGlyphOrder

from fontmake import instantiator
from fontmake.errors import FontmakeError, TTFAError
from fontmake.ttfautohint import ttfautohint

Expand Down Expand Up @@ -646,6 +648,78 @@ def interpolate_instance_ufos(
include=None,
round_instances=False,
expand_features_to_instances=False,
):
"""Interpolate master UFOs with Instantiator and return instance UFOs.
Args:
designspace: a DesignSpaceDocument object containing sources and
instances.
include (str): optional regular expression pattern to match the
DS instance 'name' attribute and only interpolate the matching
instances.
round_instances (bool): round instances' coordinates to integer.
expand_features_to_instances: parses the master feature file, expands all
include()s and writes the resulting full feature file to all instance
UFOs. Use this if you share feature files among masters in external
files. Otherwise, the relative include paths can break as instances
may end up elsewhere. Only done on interpolation.
Returns:
generator of ufoLib2.Font objects corresponding to the UFO instances.
Raises:
ValueError: The Designspace has no default source or contains incompatible
glyphs or contains anisotropic (MutatorMath) locations or contains a
<rules> substitution for a non-existant glyph.
"""
from glyphsLib.interpolation import apply_instance_data_to_ufo

logger.info(
"Interpolating master UFOs from designspace and applying instance data"
)
designspace = designspaceLib.DesignSpaceDocument.fromfile(designspace.path)
generator = instantiator.Instantiator.from_designspace(
designspace, round_geometry=round_instances
)

if expand_features_to_instances:
logger.debug("Expanding features to instance UFOs")
fea_txt = parseLayoutFeatures(designspace.default.font).asFea()
generator = attr.evolve(generator, copy_feature_text=fea_txt)

for instance in designspace.instances:
# Skip instances that have been set to non-export in Glyphs, stored as the
# instance's `com.schriftgestaltung.export` lib key.
if not instance.lib.get("com.schriftgestaltung.export", True):
continue

# Skip instances that do not match the user's inclusion regex if given.
if include is not None and not fullmatch(include, instance.name):
continue

instance.font = generator.generate_instance(instance)

apply_instance_data_to_ufo(instance.font, instance, designspace)

# TODO: Making filenames up on the spot is complicated, ideally don't save
# anything if filename is not set, but make something up when "ufo" is in
# output formats, but also consider output_path.
if instance.filename is None:
raise ValueError(
"It is currently required that instances have filenames set."
)
ufo_path = os.path.join(
os.path.dirname(designspace.path), instance.filename
)
os.makedirs(os.path.dirname(ufo_path), exist_ok=True)
instance.font.save(ufo_path, overwrite=True)

yield instance.font

def interpolate_instance_ufos_mutatormath(
self,
designspace,
include=None,
round_instances=False,
expand_features_to_instances=False,
):
"""Interpolate master UFOs with MutatorMath and return instance UFOs.
Expand Down Expand Up @@ -724,6 +798,7 @@ def run_from_designspace(
round_instances=False,
feature_writers=None,
expand_features_to_instances=False,
use_mutatormath=False,
**kwargs,
):
"""Run toolchain from a DesignSpace document to produce either static
Expand Down Expand Up @@ -781,6 +856,7 @@ def run_from_designspace(
round_instances=round_instances,
feature_writers=feature_writers,
expand_features_to_instances=expand_features_to_instances,
use_mutatormath=use_mutatormath,
**kwargs,
)
if interp_outputs:
Expand All @@ -801,21 +877,32 @@ def _run_from_designspace_static(
round_instances=False,
feature_writers=None,
expand_features_to_instances=False,
use_mutatormath=False,
**kwargs,
):
ufos = []
if not interpolate or masters_as_instances:
ufos.extend(s.path for s in designspace.sources if s.path)
if interpolate:
pattern = interpolate if isinstance(interpolate, str) else None
ufos.extend(
self.interpolate_instance_ufos(
designspace,
include=pattern,
round_instances=round_instances,
expand_features_to_instances=expand_features_to_instances,
if use_mutatormath:
ufos.extend(
self.interpolate_instance_ufos_mutatormath(
designspace,
include=pattern,
round_instances=round_instances,
expand_features_to_instances=expand_features_to_instances,
)
)
else:
ufos.extend(
self.interpolate_instance_ufos(
designspace,
include=pattern,
round_instances=round_instances,
expand_features_to_instances=expand_features_to_instances,
)
)
)

if interpolate_binary_layout is False:
interpolate_layout_from = interpolate_layout_dir = None
Expand Down
Loading

0 comments on commit 5b8e0b7

Please sign in to comment.