[instancer/L4] Misc fixes and fix tests
This commit is contained in:
parent
43e5aae018
commit
204532aee3
@ -204,8 +204,8 @@ class AxisTriple(Sequence):
|
||||
default = None
|
||||
if n == 2:
|
||||
minimum, maximum = v
|
||||
elif n == 3:
|
||||
minimum, default, maximum = v
|
||||
elif n >= 3:
|
||||
return cls(*v)
|
||||
else:
|
||||
raise ValueError(f"expected sequence of 2 or 3; got {n}: {v!r}")
|
||||
return cls(minimum, default, maximum)
|
||||
@ -234,14 +234,14 @@ class AxisTriple(Sequence):
|
||||
|
||||
|
||||
@dataclasses.dataclass(frozen=True, order=True, repr=False)
|
||||
class NormalizedAxisTriple(AxisTriple):
|
||||
class NormalizedAxisTripleAndDistances(AxisTriple):
|
||||
"""A triple of (min, default, max) normalized axis values."""
|
||||
|
||||
minimum: float
|
||||
default: float
|
||||
maximum: float
|
||||
distanceNegative: float
|
||||
distancePositive: float
|
||||
distanceNegative: Optional[float] = 1
|
||||
distancePositive: Optional[float] = 1
|
||||
|
||||
def __post_init__(self):
|
||||
if self.default is None:
|
||||
@ -256,15 +256,18 @@ class NormalizedAxisTriple(AxisTriple):
|
||||
v = self
|
||||
return self.__class__(-v[2], -v[1], -v[0], v[4], v[3])
|
||||
|
||||
def normalizeValue(self, v):
|
||||
def normalizeValue(self, v, extrapolate=True):
|
||||
lower, default, upper, distanceNegative, distancePositive = self
|
||||
assert lower <= default <= upper
|
||||
|
||||
if not extrapolate:
|
||||
v = max(lower, min(upper, v))
|
||||
|
||||
if v == default:
|
||||
return 0
|
||||
|
||||
if default < 0:
|
||||
return -self.reverse_negate().normalizeValue(-v)
|
||||
return -self.reverse_negate().normalizeValue(-v, extrapolate=extrapolate)
|
||||
|
||||
# default >= 0 and v != default
|
||||
|
||||
@ -285,6 +288,12 @@ class NormalizedAxisTriple(AxisTriple):
|
||||
else:
|
||||
vDistance = -v * distanceNegative + distancePositive * default
|
||||
|
||||
if totalDistance == 0:
|
||||
# This happens
|
||||
if default == 0:
|
||||
return -v / lower
|
||||
return 0 # Shouldn't happen
|
||||
|
||||
return -vDistance / totalDistance
|
||||
|
||||
|
||||
@ -375,7 +384,7 @@ class AxisLimits(_BaseAxisLimits):
|
||||
distancePositive = triple[2] - triple[1]
|
||||
|
||||
if self[axis_tag] is None:
|
||||
normalizedLimits[axis_tag] = NormalizedAxisTriple(
|
||||
normalizedLimits[axis_tag] = NormalizedAxisTripleAndDistances(
|
||||
0, 0, 0, distanceNegative, distancePositive
|
||||
)
|
||||
continue
|
||||
@ -386,7 +395,7 @@ class AxisLimits(_BaseAxisLimits):
|
||||
defaultV = triple[1]
|
||||
|
||||
avarMapping = avarSegments.get(axis_tag, None)
|
||||
normalizedLimits[axis_tag] = NormalizedAxisTriple(
|
||||
normalizedLimits[axis_tag] = NormalizedAxisTripleAndDistances(
|
||||
*(normalize(v, triple, avarMapping) for v in (minV, defaultV, maxV)),
|
||||
distanceNegative,
|
||||
distancePositive,
|
||||
@ -402,7 +411,7 @@ class NormalizedAxisLimits(_BaseAxisLimits):
|
||||
self._data = data = {}
|
||||
for k, v in dict(*args, **kwargs).items():
|
||||
try:
|
||||
triple = NormalizedAxisTriple.expand(v)
|
||||
triple = NormalizedAxisTripleAndDistances.expand(v)
|
||||
except ValueError as e:
|
||||
raise ValueError(f"Invalid axis limits for {k!r}: {v!r}") from e
|
||||
data[k] = triple
|
||||
@ -486,7 +495,7 @@ def changeTupleVariationsAxisLimits(variations, axisLimits):
|
||||
|
||||
|
||||
def changeTupleVariationAxisLimit(var, axisTag, axisLimit):
|
||||
assert isinstance(axisLimit, NormalizedAxisTriple)
|
||||
assert isinstance(axisLimit, NormalizedAxisTripleAndDistances)
|
||||
|
||||
# Skip when current axis is missing (i.e. doesn't participate),
|
||||
lower, peak, upper = var.axes.get(axisTag, (-1, 0, 1))
|
||||
@ -549,7 +558,7 @@ def _instantiateGvarGlyph(
|
||||
"Instancing accross VarComposite axes with variation is not supported."
|
||||
)
|
||||
limits = axisLimits[tag]
|
||||
loc = limits.normalizeValue(loc)
|
||||
loc = limits.normalizeValue(loc, extrapolate=False)
|
||||
newLocation[tag] = loc
|
||||
component.location = newLocation
|
||||
|
||||
@ -969,7 +978,7 @@ def instantiateAvar(varfont, axisLimits):
|
||||
mappedMax = floatToFixedToFloat(
|
||||
piecewiseLinearMap(axisRange.maximum, mapping), 14
|
||||
)
|
||||
mappedAxisLimit = NormalizedAxisTriple(
|
||||
mappedAxisLimit = NormalizedAxisTripleAndDistances(
|
||||
mappedMin,
|
||||
mappedDef,
|
||||
mappedMax,
|
||||
|
@ -1,5 +1,4 @@
|
||||
from fontTools.ttLib.tables import otTables as ot
|
||||
from fontTools.varLib.models import normalizeValue
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
|
||||
@ -41,7 +40,9 @@ def _limitFeatureVariationConditionRange(condition, axisLimit):
|
||||
# condition invalid or out of range
|
||||
return
|
||||
|
||||
return tuple(axisLimit.normalizeValue(v) for v in (minValue, maxValue))
|
||||
return tuple(
|
||||
axisLimit.normalizeValue(v, extrapolate=False) for v in (minValue, maxValue)
|
||||
)
|
||||
|
||||
|
||||
def _instantiateFeatureVariationRecord(
|
||||
@ -50,9 +51,9 @@ def _instantiateFeatureVariationRecord(
|
||||
applies = True
|
||||
shouldKeep = False
|
||||
newConditions = []
|
||||
from fontTools.varLib.instancer import NormalizedAxisTriple
|
||||
from fontTools.varLib.instancer import NormalizedAxisTripleAndDistances
|
||||
|
||||
default_triple = NormalizedAxisTriple(-1, 0, +1, 0, 0)
|
||||
default_triple = NormalizedAxisTripleAndDistances(-1, 0, +1, 0, 0)
|
||||
for i, condition in enumerate(record.ConditionSet.ConditionTable):
|
||||
if condition.Format == 1:
|
||||
axisIdx = condition.AxisIndex
|
||||
|
@ -1950,7 +1950,7 @@ class LimitTupleVariationAxisRangesTest:
|
||||
],
|
||||
)
|
||||
def test_positive_var(self, var, axisTag, newMax, expected):
|
||||
axisRange = instancer.NormalizedAxisTriple(0, 0, newMax)
|
||||
axisRange = instancer.NormalizedAxisTripleAndDistances(0, 0, newMax, 1, 1)
|
||||
self.check_limit_single_var_axis_range(var, axisTag, axisRange, expected)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -2029,7 +2029,7 @@ class LimitTupleVariationAxisRangesTest:
|
||||
],
|
||||
)
|
||||
def test_negative_var(self, var, axisTag, newMin, expected):
|
||||
axisRange = instancer.NormalizedAxisTriple(newMin, 0, 0)
|
||||
axisRange = instancer.NormalizedAxisTripleAndDistances(newMin, 0, 0, 1, 1)
|
||||
self.check_limit_single_var_axis_range(var, axisTag, axisRange, expected)
|
||||
|
||||
|
||||
@ -2052,7 +2052,7 @@ def test_limitFeatureVariationConditionRange(oldRange, newLimit, expected):
|
||||
condition = featureVars.buildConditionTable(0, *oldRange)
|
||||
|
||||
result = instancer.featureVars._limitFeatureVariationConditionRange(
|
||||
condition, instancer.NormalizedAxisTriple(*newLimit)
|
||||
condition, instancer.NormalizedAxisTripleAndDistances(*newLimit, 1, 1)
|
||||
)
|
||||
|
||||
assert result == expected
|
||||
@ -2094,9 +2094,9 @@ def test_parseLimits_invalid(limits):
|
||||
@pytest.mark.parametrize(
|
||||
"limits, expected",
|
||||
[
|
||||
({"wght": (100, 400)}, {"wght": (-1.0, 0, 0)}),
|
||||
({"wght": (100, 400, 400)}, {"wght": (-1.0, 0, 0)}),
|
||||
({"wght": (100, 300, 400)}, {"wght": (-1.0, -0.5, 0)}),
|
||||
({"wght": (100, 400)}, {"wght": (-1.0, 0, 0, 300, 500)}),
|
||||
({"wght": (100, 400, 400)}, {"wght": (-1.0, 0, 0, 300, 500)}),
|
||||
({"wght": (100, 300, 400)}, {"wght": (-1.0, -0.5, 0, 300, 500)}),
|
||||
],
|
||||
)
|
||||
def test_normalizeAxisLimits(varfont, limits, expected):
|
||||
@ -2113,7 +2113,7 @@ def test_normalizeAxisLimits_no_avar(varfont):
|
||||
limits = instancer.AxisLimits(wght=(400, 400, 500))
|
||||
normalized = limits.normalize(varfont)
|
||||
|
||||
assert normalized["wght"] == pytest.approx((0, 0, 0.2), 1e-4)
|
||||
assert normalized["wght"] == pytest.approx((0, 0, 0.2, 300, 500), 1e-4)
|
||||
|
||||
|
||||
def test_normalizeAxisLimits_missing_from_fvar(varfont):
|
||||
|
@ -1,4 +1,5 @@
|
||||
from fontTools.varLib.instancer import solver
|
||||
from fontTools.varLib.instancer import NormalizedAxisTripleAndDistances
|
||||
import pytest
|
||||
|
||||
|
||||
@ -264,6 +265,8 @@ class RebaseTentTest(object):
|
||||
],
|
||||
)
|
||||
def test_rebaseTent(self, tent, axisRange, expected):
|
||||
axisRange = NormalizedAxisTripleAndDistances(*axisRange)
|
||||
|
||||
sol = solver.rebaseTent(tent, axisRange)
|
||||
|
||||
a = pytest.approx
|
||||
|
Loading…
x
Reference in New Issue
Block a user