[varLib.models] By default, assume OpenType-like normalized space

See:
https://github.com/fonttools/fonttools/pull/2846#issuecomment-2267750076

I *think* this is an improvement, and no one should have been relying
on the broken existing behavior.

Docs need updating.
This commit is contained in:
Behdad Esfahbod 2024-08-05 11:27:12 -06:00
parent ead2a18d4b
commit 0c2652011e
6 changed files with 33 additions and 28 deletions

View File

@ -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

View File

@ -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):

View File

@ -16,7 +16,7 @@
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.875"/>
<EndCoord value="0.875"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/>

View File

@ -12,7 +12,7 @@
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.875"/>
<EndCoord value="0.875"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/>
@ -24,12 +24,12 @@
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.875"/>
<EndCoord value="0.875"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/>
<PeakCoord value="0.5"/>
<EndCoord value="0.5"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
</Region>
</VarRegionList>

View File

@ -12,7 +12,7 @@
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.875"/>
<EndCoord value="0.875"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/>
@ -24,12 +24,12 @@
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.875"/>
<EndCoord value="0.875"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/>
<PeakCoord value="0.5"/>
<EndCoord value="0.5"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
</Region>
</VarRegionList>

View File

@ -23,7 +23,7 @@
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.38"/>
<EndCoord value="0.38"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
</Region>
</VarRegionList>