diff --git a/Lib/fontTools/varLib/models.py b/Lib/fontTools/varLib/models.py index 819596991..fadfa242c 100644 --- a/Lib/fontTools/varLib/models.py +++ b/Lib/fontTools/varLib/models.py @@ -209,10 +209,14 @@ def supportScalar(location, support, ot=True, extrapolate=False, axisRanges=None class VariationModel(object): """Locations must have the base master at the origin (ie. 0). + If axis-ranges are not provided, values are assumed to be normalized to + the range [-1, 1]. + If the extrapolate argument is set to True, then values are extrapolated outside the axis range. >>> from pprint import pprint + >>> axisRanges = {'wght': (-180, +180), 'wdth': (-1, +1)} >>> locations = [ \ {'wght':100}, \ {'wght':-100}, \ @@ -224,7 +228,7 @@ class VariationModel(object): {'wght':+180,'wdth':.3}, \ {'wght':+180}, \ ] - >>> model = VariationModel(locations, axisOrder=['wght']) + >>> model = VariationModel(locations, axisOrder=['wght'], axisRanges=axisRanges) >>> pprint(model.locations) [{}, {'wght': -100}, @@ -252,14 +256,22 @@ class VariationModel(object): 7: 0.6666666666666667}] """ - def __init__(self, locations, axisOrder=None, extrapolate=False): + def __init__( + self, locations, axisOrder=None, extrapolate=False, *, axisRanges=None + ): if len(set(tuple(sorted(l.items())) for l in locations)) != len(locations): raise VariationModelError("Locations must be unique.") self.origLocations = locations self.axisOrder = axisOrder if axisOrder is not None else [] self.extrapolate = extrapolate - self.axisRanges = self.computeAxisRanges(locations) if extrapolate else None + if axisRanges is None: + if extrapolate: + axisRanges = self.computeAxisRanges(locations) + else: + allAxes = {axis for loc in locations for axis in loc.keys()} + axisRanges = {axis: (-1, 1) for axis in allAxes} + self.axisRanges = axisRanges locations = [{k: v for k, v in loc.items() if v != 0.0} for loc in locations] keyFunc = self.getMasterLocationsSortKeyFunc( @@ -425,23 +437,16 @@ class VariationModel(object): def _locationsToRegions(self): locations = self.locations - # Compute min/max across each axis, use it as total range. - # TODO Take this as input from outside? - minV = {} - maxV = {} - for l in locations: - for k, v in l.items(): - minV[k] = min(v, minV.get(k, v)) - maxV[k] = max(v, maxV.get(k, v)) + axisRanges = self.axisRanges regions = [] for loc in locations: region = {} for axis, locV in loc.items(): if locV > 0: - region[axis] = (0, locV, maxV[axis]) + region[axis] = (0, locV, axisRanges[axis][1]) else: - region[axis] = (minV[axis], locV, 0) + region[axis] = (axisRanges[axis][0], locV, 0) regions.append(region) return regions diff --git a/Tests/feaLib/builder_test.py b/Tests/feaLib/builder_test.py index e2f6a1d4d..6c1fdab24 100644 --- a/Tests/feaLib/builder_test.py +++ b/Tests/feaLib/builder_test.py @@ -1112,12 +1112,12 @@ class BuilderTest(unittest.TestCase): var_region_list = font.tables["GDEF"].table.VarStore.VarRegionList var_region_axis_wght = var_region_list.Region[0].VarRegionAxis[0] var_region_axis_wdth = var_region_list.Region[0].VarRegionAxis[1] - assert self.get_region(var_region_axis_wght) == (0.0, 0.875, 0.875) + assert self.get_region(var_region_axis_wght) == (0.0, 0.875, 1.0) assert self.get_region(var_region_axis_wdth) == (0.0, 0.0, 0.0) var_region_axis_wght = var_region_list.Region[1].VarRegionAxis[0] var_region_axis_wdth = var_region_list.Region[1].VarRegionAxis[1] - assert self.get_region(var_region_axis_wght) == (0.0, 0.875, 0.875) - assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 0.5) + assert self.get_region(var_region_axis_wght) == (0.0, 0.875, 1.0) + assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 1.0) # With `avar`, shifting the wght axis' positive midpoint 0.5 a bit to # the right, but leaving the wdth axis alone: @@ -1129,12 +1129,12 @@ class BuilderTest(unittest.TestCase): var_region_list = font.tables["GDEF"].table.VarStore.VarRegionList var_region_axis_wght = var_region_list.Region[0].VarRegionAxis[0] var_region_axis_wdth = var_region_list.Region[0].VarRegionAxis[1] - assert self.get_region(var_region_axis_wght) == (0.0, 0.90625, 0.90625) + assert self.get_region(var_region_axis_wght) == (0.0, 0.90625, 1.0) assert self.get_region(var_region_axis_wdth) == (0.0, 0.0, 0.0) var_region_axis_wght = var_region_list.Region[1].VarRegionAxis[0] var_region_axis_wdth = var_region_list.Region[1].VarRegionAxis[1] - assert self.get_region(var_region_axis_wght) == (0.0, 0.90625, 0.90625) - assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 0.5) + assert self.get_region(var_region_axis_wght) == (0.0, 0.90625, 1.0) + assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 1.0) def test_ligatureCaretByPos_variable_scalar(self): """Test that the `avar` table is consulted when normalizing user-space @@ -1158,7 +1158,7 @@ class BuilderTest(unittest.TestCase): var_region_list = table.VarStore.VarRegionList var_region_axis = var_region_list.Region[0].VarRegionAxis[0] - assert self.get_region(var_region_axis) == (0.0, 0.875, 0.875) + assert self.get_region(var_region_axis) == (0.0, 0.875, 1.0) def generate_feature_file_test(name): diff --git a/Tests/feaLib/data/variable_mark_anchor.ttx b/Tests/feaLib/data/variable_mark_anchor.ttx index 962cff741..d29fc43a1 100644 --- a/Tests/feaLib/data/variable_mark_anchor.ttx +++ b/Tests/feaLib/data/variable_mark_anchor.ttx @@ -16,7 +16,7 @@ - + diff --git a/Tests/feaLib/data/variable_scalar_anchor.ttx b/Tests/feaLib/data/variable_scalar_anchor.ttx index 6bb55691f..92a456d3b 100644 --- a/Tests/feaLib/data/variable_scalar_anchor.ttx +++ b/Tests/feaLib/data/variable_scalar_anchor.ttx @@ -12,7 +12,7 @@ - + @@ -24,12 +24,12 @@ - + - + diff --git a/Tests/feaLib/data/variable_scalar_valuerecord.ttx b/Tests/feaLib/data/variable_scalar_valuerecord.ttx index e3251f691..94bd3867d 100644 --- a/Tests/feaLib/data/variable_scalar_valuerecord.ttx +++ b/Tests/feaLib/data/variable_scalar_valuerecord.ttx @@ -12,7 +12,7 @@ - + @@ -24,12 +24,12 @@ - + - + diff --git a/Tests/varLib/data/test_results/BuildAvar2.ttx b/Tests/varLib/data/test_results/BuildAvar2.ttx index 27a41bfbb..493d9bdbb 100644 --- a/Tests/varLib/data/test_results/BuildAvar2.ttx +++ b/Tests/varLib/data/test_results/BuildAvar2.ttx @@ -23,7 +23,7 @@ - +