[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:
parent
ead2a18d4b
commit
0c2652011e
@ -209,10 +209,14 @@ def supportScalar(location, support, ot=True, extrapolate=False, axisRanges=None
|
|||||||
class VariationModel(object):
|
class VariationModel(object):
|
||||||
"""Locations must have the base master at the origin (ie. 0).
|
"""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
|
If the extrapolate argument is set to True, then values are extrapolated
|
||||||
outside the axis range.
|
outside the axis range.
|
||||||
|
|
||||||
>>> from pprint import pprint
|
>>> from pprint import pprint
|
||||||
|
>>> axisRanges = {'wght': (-180, +180), 'wdth': (-1, +1)}
|
||||||
>>> locations = [ \
|
>>> locations = [ \
|
||||||
{'wght':100}, \
|
{'wght':100}, \
|
||||||
{'wght':-100}, \
|
{'wght':-100}, \
|
||||||
@ -224,7 +228,7 @@ class VariationModel(object):
|
|||||||
{'wght':+180,'wdth':.3}, \
|
{'wght':+180,'wdth':.3}, \
|
||||||
{'wght':+180}, \
|
{'wght':+180}, \
|
||||||
]
|
]
|
||||||
>>> model = VariationModel(locations, axisOrder=['wght'])
|
>>> model = VariationModel(locations, axisOrder=['wght'], axisRanges=axisRanges)
|
||||||
>>> pprint(model.locations)
|
>>> pprint(model.locations)
|
||||||
[{},
|
[{},
|
||||||
{'wght': -100},
|
{'wght': -100},
|
||||||
@ -252,14 +256,22 @@ class VariationModel(object):
|
|||||||
7: 0.6666666666666667}]
|
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):
|
if len(set(tuple(sorted(l.items())) for l in locations)) != len(locations):
|
||||||
raise VariationModelError("Locations must be unique.")
|
raise VariationModelError("Locations must be unique.")
|
||||||
|
|
||||||
self.origLocations = locations
|
self.origLocations = locations
|
||||||
self.axisOrder = axisOrder if axisOrder is not None else []
|
self.axisOrder = axisOrder if axisOrder is not None else []
|
||||||
self.extrapolate = extrapolate
|
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]
|
locations = [{k: v for k, v in loc.items() if v != 0.0} for loc in locations]
|
||||||
keyFunc = self.getMasterLocationsSortKeyFunc(
|
keyFunc = self.getMasterLocationsSortKeyFunc(
|
||||||
@ -425,23 +437,16 @@ class VariationModel(object):
|
|||||||
|
|
||||||
def _locationsToRegions(self):
|
def _locationsToRegions(self):
|
||||||
locations = self.locations
|
locations = self.locations
|
||||||
# Compute min/max across each axis, use it as total range.
|
axisRanges = self.axisRanges
|
||||||
# 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))
|
|
||||||
|
|
||||||
regions = []
|
regions = []
|
||||||
for loc in locations:
|
for loc in locations:
|
||||||
region = {}
|
region = {}
|
||||||
for axis, locV in loc.items():
|
for axis, locV in loc.items():
|
||||||
if locV > 0:
|
if locV > 0:
|
||||||
region[axis] = (0, locV, maxV[axis])
|
region[axis] = (0, locV, axisRanges[axis][1])
|
||||||
else:
|
else:
|
||||||
region[axis] = (minV[axis], locV, 0)
|
region[axis] = (axisRanges[axis][0], locV, 0)
|
||||||
regions.append(region)
|
regions.append(region)
|
||||||
return regions
|
return regions
|
||||||
|
|
||||||
|
@ -1112,12 +1112,12 @@ class BuilderTest(unittest.TestCase):
|
|||||||
var_region_list = font.tables["GDEF"].table.VarStore.VarRegionList
|
var_region_list = font.tables["GDEF"].table.VarStore.VarRegionList
|
||||||
var_region_axis_wght = var_region_list.Region[0].VarRegionAxis[0]
|
var_region_axis_wght = var_region_list.Region[0].VarRegionAxis[0]
|
||||||
var_region_axis_wdth = var_region_list.Region[0].VarRegionAxis[1]
|
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)
|
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_wght = var_region_list.Region[1].VarRegionAxis[0]
|
||||||
var_region_axis_wdth = var_region_list.Region[1].VarRegionAxis[1]
|
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_wght) == (0.0, 0.875, 1.0)
|
||||||
assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 0.5)
|
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
|
# With `avar`, shifting the wght axis' positive midpoint 0.5 a bit to
|
||||||
# the right, but leaving the wdth axis alone:
|
# 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_list = font.tables["GDEF"].table.VarStore.VarRegionList
|
||||||
var_region_axis_wght = var_region_list.Region[0].VarRegionAxis[0]
|
var_region_axis_wght = var_region_list.Region[0].VarRegionAxis[0]
|
||||||
var_region_axis_wdth = var_region_list.Region[0].VarRegionAxis[1]
|
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)
|
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_wght = var_region_list.Region[1].VarRegionAxis[0]
|
||||||
var_region_axis_wdth = var_region_list.Region[1].VarRegionAxis[1]
|
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_wght) == (0.0, 0.90625, 1.0)
|
||||||
assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 0.5)
|
assert self.get_region(var_region_axis_wdth) == (0.0, 0.5, 1.0)
|
||||||
|
|
||||||
def test_ligatureCaretByPos_variable_scalar(self):
|
def test_ligatureCaretByPos_variable_scalar(self):
|
||||||
"""Test that the `avar` table is consulted when normalizing user-space
|
"""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_list = table.VarStore.VarRegionList
|
||||||
var_region_axis = var_region_list.Region[0].VarRegionAxis[0]
|
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):
|
def generate_feature_file_test(name):
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<VarRegionAxis index="0">
|
<VarRegionAxis index="0">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.875"/>
|
<PeakCoord value="0.875"/>
|
||||||
<EndCoord value="0.875"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
<VarRegionAxis index="1">
|
<VarRegionAxis index="1">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<VarRegionAxis index="0">
|
<VarRegionAxis index="0">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.875"/>
|
<PeakCoord value="0.875"/>
|
||||||
<EndCoord value="0.875"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
<VarRegionAxis index="1">
|
<VarRegionAxis index="1">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
@ -24,12 +24,12 @@
|
|||||||
<VarRegionAxis index="0">
|
<VarRegionAxis index="0">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.875"/>
|
<PeakCoord value="0.875"/>
|
||||||
<EndCoord value="0.875"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
<VarRegionAxis index="1">
|
<VarRegionAxis index="1">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.5"/>
|
<PeakCoord value="0.5"/>
|
||||||
<EndCoord value="0.5"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
</Region>
|
</Region>
|
||||||
</VarRegionList>
|
</VarRegionList>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<VarRegionAxis index="0">
|
<VarRegionAxis index="0">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.875"/>
|
<PeakCoord value="0.875"/>
|
||||||
<EndCoord value="0.875"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
<VarRegionAxis index="1">
|
<VarRegionAxis index="1">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
@ -24,12 +24,12 @@
|
|||||||
<VarRegionAxis index="0">
|
<VarRegionAxis index="0">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.875"/>
|
<PeakCoord value="0.875"/>
|
||||||
<EndCoord value="0.875"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
<VarRegionAxis index="1">
|
<VarRegionAxis index="1">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.5"/>
|
<PeakCoord value="0.5"/>
|
||||||
<EndCoord value="0.5"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
</Region>
|
</Region>
|
||||||
</VarRegionList>
|
</VarRegionList>
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<VarRegionAxis index="0">
|
<VarRegionAxis index="0">
|
||||||
<StartCoord value="0.0"/>
|
<StartCoord value="0.0"/>
|
||||||
<PeakCoord value="0.38"/>
|
<PeakCoord value="0.38"/>
|
||||||
<EndCoord value="0.38"/>
|
<EndCoord value="1.0"/>
|
||||||
</VarRegionAxis>
|
</VarRegionAxis>
|
||||||
</Region>
|
</Region>
|
||||||
</VarRegionList>
|
</VarRegionList>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user