featureVars: modify normalization using avar maps

This commit is contained in:
Cosimo Lupo 2018-04-16 18:38:58 +02:00
parent 4256e6c6bf
commit 081ca1327c
No known key found for this signature in database
GPG Key ID: 59D54DB0C9976482

View File

@ -4,6 +4,7 @@ from fontTools.ttLib import newTable
from fontTools.ttLib.tables import otTables as ot from fontTools.ttLib.tables import otTables as ot
from fontTools.otlLib.builder import buildLookup, buildSingleSubstSubtable from fontTools.otlLib.builder import buildLookup, buildSingleSubstSubtable
from fontTools.varLib.models import normalizeValue from fontTools.varLib.models import normalizeValue
from fontTools.varLib import _DesignspaceAxis
def addFeatureVariations(font, conditionalSubstitutions): def addFeatureVariations(font, conditionalSubstitutions):
@ -21,7 +22,8 @@ def addFeatureVariations(font, conditionalSubstitutions):
functionality is not compromised if they do. functionality is not compromised if they do.
The minimum and maximum values are expressed in raw user coordinates, and The minimum and maximum values are expressed in raw user coordinates, and
are internally normalized without going through the `avar` mapping. are internally normalized using the `avar` mapping, if present, else using
the default mapping.
A Substitution is a dict mapping source glyph names to substitute glyph names. A Substitution is a dict mapping source glyph names to substitute glyph names.
""" """
@ -38,10 +40,12 @@ def addFeatureVariations(font, conditionalSubstitutions):
# >>> f.save(dstPath) # >>> f.save(dstPath)
defaultSpace = {} defaultSpace = {}
axisMap = {} axes = {}
for axis in font["fvar"].axes: for axis in font["fvar"].axes:
defaultSpace[axis.axisTag] = (axis.minValue, axis.maxValue) defaultSpace[axis.axisTag] = (axis.minValue, axis.maxValue)
axisMap[axis.axisTag] = (axis.minValue, axis.defaultValue, axis.maxValue) axes[axis.axisTag] = (axis.minValue, axis.defaultValue, axis.maxValue)
maps = font['avar'].segments if 'avar' in font else None
# Since the FeatureVariations table will only ever match one rule at a time, # Since the FeatureVariations table will only ever match one rule at a time,
# we will make new rules for all possible combinations of our input, so we # we will make new rules for all possible combinations of our input, so we
@ -62,7 +66,9 @@ def addFeatureVariations(font, conditionalSubstitutions):
# Remove default values, so we don't generate redundant ConditionSets # Remove default values, so we don't generate redundant ConditionSets
space = cleanupSpace(space, defaultSpace) space = cleanupSpace(space, defaultSpace)
if space: if space:
space = normalizeSpace(space, axisMap) space = normalizeSpace(space, axes)
if maps is not None:
space = mapSpace(space, maps)
explodedConditionalSubstitutions.append((space, lookups)) explodedConditionalSubstitutions.append((space, lookups))
addFeatureVariationsRaw(font, explodedConditionalSubstitutions) addFeatureVariationsRaw(font, explodedConditionalSubstitutions)
@ -180,14 +186,30 @@ def cleanupSpace(space, defaultSpace):
return {tag: limit for tag, limit in space.items() if limit != defaultSpace[tag]} return {tag: limit for tag, limit in space.items() if limit != defaultSpace[tag]}
def normalizeSpace(space, axisMap): def normalizeSpace(space, axes):
"""Convert the min/max values in the `space` dict to normalized """Convert the min/max values in the `space` dict to normalized
design space values.""" design space values.
space = {tag: (normalizeValue(minValue, axisMap[tag]), normalizeValue(maxValue, axisMap[tag])) The `axes` argument is a dictionary keyed by axis tags, containing
for tag, (minValue, maxValue) in space.items()} (minimum, default, maximum) tuples from the fvar table.
"""
space = {tag: (normalizeValue(minValue, axes[tag]),
normalizeValue(maxValue, axes[tag]))
for tag, (minValue, maxValue) in space.items()}
return space return space
def mapSpace(space, maps):
"""Modify normalized min/max values in the `space` dict using axis maps
from avar table.
"""
return {
tag: (
_DesignspaceAxis._map(minValue, maps[tag]),
_DesignspaceAxis._map(maxValue, maps[tag])
) for tag, (minValue, maxValue) in space.items()
}
# #
# Low level implementation # Low level implementation
# #