Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

work around MutatorMath "warping" sources/instances locations #552

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 56 additions & 13 deletions Lib/fontmake/font_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import shutil
import tempfile
from collections import OrderedDict
from contextlib import contextmanager
from functools import partial, wraps

import ufo2ft
Expand Down Expand Up @@ -90,6 +91,44 @@ def wrapper(*args, **kwargs):
return wrapper


@contextmanager
def temporarily_disabling_axis_maps(designspace_path):
"""Context manager to prevent MutatorMath from warping designspace locations.

MutatorMath assumes that the masters and instances' locations are in
user-space coordinates -- whereas they actually are in internal design-space
coordinates, and thus they do not need any 'bending'. To work around this we
we create a temporary designspace document without the axis maps, and with the
min/default/max triplet mapped "forward" from user-space coordinates (input)
to internal designspace coordinates (output).

Args:
designspace_path: A path to a designspace document.

Yields:
A temporary path string to the thus modified designspace document.
After the context is exited, it removes the temporary file.

Related issues:
https://github.com/LettError/designSpaceDocument/issues/16
https://github.com/fonttools/fonttools/pull/1395
"""
designspace = designspaceLib.DesignSpaceDocument.fromfile(designspace_path)
for axis in designspace.axes:
axis.minimum = axis.map_forward(axis.minimum)
axis.default = axis.map_forward(axis.default)
axis.maximum = axis.map_forward(axis.maximum)
del axis.map[:]

fd, temp_designspace_path = tempfile.mkstemp()
os.close(fd)
try:
designspace.write(temp_designspace_path)
yield temp_designspace_path
finally:
os.remove(temp_designspace_path)


class FontProject(object):
"""Provides methods for building fonts."""

Expand Down Expand Up @@ -762,19 +801,23 @@ def interpolate_instance_ufos(
"attribute"
)

# TODO: replace mutatorMath with ufoProcessor?
builder = DesignSpaceDocumentReader(
designspace.path, ufoVersion=3, roundGeometry=round_instances, verbose=True
)
logger.info("Interpolating master UFOs from designspace")
if include is not None:
instances = self._search_instances(designspace, pattern=include)
for instance_name in instances:
builder.readInstance(("name", instance_name))
filenames = set(instances.values())
else:
builder.readInstances()
filenames = None # will include all instances
with temporarily_disabling_axis_maps(designspace.path) as temp_designspace_path:
builder = DesignSpaceDocumentReader(
temp_designspace_path,
ufoVersion=3,
roundGeometry=round_instances,
verbose=True,
)
logger.info("Interpolating master UFOs from designspace")
if include is not None:
instances = self._search_instances(designspace, pattern=include)
for instance_name in instances:
builder.readInstance(("name", instance_name))
filenames = set(instances.values())
else:
builder.readInstances()
filenames = None # will include all instances

logger.info("Applying instance data from designspace")
instance_ufos = apply_instance_data(designspace, include_filenames=filenames)

Expand Down