aboutsummaryrefslogtreecommitdiff
path: root/Tests/varLib/instancer/instancer_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/varLib/instancer/instancer_test.py')
-rw-r--r--Tests/varLib/instancer/instancer_test.py364
1 files changed, 299 insertions, 65 deletions
diff --git a/Tests/varLib/instancer/instancer_test.py b/Tests/varLib/instancer/instancer_test.py
index db224cca..20d9194f 100644
--- a/Tests/varLib/instancer/instancer_test.py
+++ b/Tests/varLib/instancer/instancer_test.py
@@ -1,4 +1,5 @@
from fontTools.misc.fixedTools import floatToFixedToFloat
+from fontTools.misc.roundTools import noRound
from fontTools.misc.testTools import stripVariableItemsFromTTX
from fontTools.misc.textTools import Tag
from fontTools import ttLib
@@ -51,7 +52,15 @@ def fvarAxes():
def _get_coordinates(varfont, glyphname):
# converts GlyphCoordinates to a list of (x, y) tuples, so that pytest's
# assert will give us a nicer diff
- return list(varfont["glyf"].getCoordinatesAndControls(glyphname, varfont)[0])
+ return list(
+ varfont["glyf"]._getCoordinatesAndControls(
+ glyphname,
+ varfont["hmtx"].metrics,
+ varfont["vmtx"].metrics,
+ # the tests expect float coordinates
+ round=noRound,
+ )[0]
+ )
class InstantiateGvarTest(object):
@@ -112,6 +121,8 @@ class InstantiateGvarTest(object):
],
)
def test_pin_and_drop_axis(self, varfont, glyph_name, location, expected, optimize):
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateGvar(varfont, location, optimize=optimize)
assert _get_coordinates(varfont, glyph_name) == expected[glyph_name]
@@ -124,9 +135,9 @@ class InstantiateGvarTest(object):
)
def test_full_instance(self, varfont, optimize):
- instancer.instantiateGvar(
- varfont, {"wght": 0.0, "wdth": -0.5}, optimize=optimize
- )
+ location = instancer.NormalizedAxisLimits(wght=0.0, wdth=-0.5)
+
+ instancer.instantiateGvar(varfont, location, optimize=optimize)
assert _get_coordinates(varfont, "hyphen") == [
(33.5, 229),
@@ -169,7 +180,7 @@ class InstantiateGvarTest(object):
assert hmtx["minus"] == (422, 40)
assert vmtx["minus"] == (536, 229)
- location = {"wght": -1.0, "wdth": -1.0}
+ location = instancer.NormalizedAxisLimits(wght=-1.0, wdth=-1.0)
instancer.instantiateGvar(varfont, location)
@@ -206,6 +217,8 @@ class InstantiateCvarTest(object):
],
)
def test_pin_and_drop_axis(self, varfont, location, expected):
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateCvar(varfont, location)
assert list(varfont["cvt "].values) == expected
@@ -217,7 +230,9 @@ class InstantiateCvarTest(object):
)
def test_full_instance(self, varfont):
- instancer.instantiateCvar(varfont, {"wght": -0.5, "wdth": -0.5})
+ location = instancer.NormalizedAxisLimits(wght=-0.5, wdth=-0.5)
+
+ instancer.instantiateCvar(varfont, location)
assert list(varfont["cvt "].values) == [500, -400, 165, 225]
@@ -272,6 +287,8 @@ class InstantiateMVARTest(object):
assert mvar.VarStore.VarData[1].VarRegionCount == 1
assert all(len(item) == 1 for item in mvar.VarStore.VarData[1].Item)
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateMVAR(varfont, location)
for mvar_tag, expected_value in expected.items():
@@ -312,6 +329,8 @@ class InstantiateMVARTest(object):
],
)
def test_full_instance(self, varfont, location, expected):
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateMVAR(varfont, location)
for mvar_tag, expected_value in expected.items():
@@ -344,6 +363,8 @@ class InstantiateHVARTest(object):
],
)
def test_partial_instance(self, varfont, location, expectedRegions, expectedDeltas):
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateHVAR(varfont, location)
assert "HVAR" in varfont
@@ -376,7 +397,9 @@ class InstantiateHVARTest(object):
assert varStore.VarData[varIdx >> 16].Item[varIdx & 0xFFFF] == expectedDeltas
def test_full_instance(self, varfont):
- instancer.instantiateHVAR(varfont, {"wght": 0, "wdth": 0})
+ location = instancer.NormalizedAxisLimits(wght=0, wdth=0)
+
+ instancer.instantiateHVAR(varfont, location)
assert "HVAR" not in varfont
@@ -390,7 +413,9 @@ class InstantiateHVARTest(object):
axis.axisTag = "TEST"
fvar.axes.append(axis)
- instancer.instantiateHVAR(varfont, {"wght": 0, "wdth": 0})
+ location = instancer.NormalizedAxisLimits(wght=0, wdth=0)
+
+ instancer.instantiateHVAR(varfont, location)
assert "HVAR" in varfont
@@ -452,6 +477,8 @@ class InstantiateItemVariationStoreTest(object):
def test_instantiate_default_deltas(
self, varStore, fvarAxes, location, expected_deltas, num_regions
):
+ location = instancer.NormalizedAxisLimits(location)
+
defaultDeltas = instancer.instantiateItemVariationStore(
varStore, fvarAxes, location
)
@@ -504,8 +531,9 @@ class TupleVarStoreAdapterTest(object):
adapter = instancer._TupleVarStoreAdapter(
regions, axisOrder, tupleVarData, itemCounts=[2, 2]
)
+ location = instancer.NormalizedAxisLimits(wght=0.5)
- defaultDeltaArray = adapter.instantiate({"wght": 0.5})
+ defaultDeltaArray = adapter.instantiate(location)
assert defaultDeltaArray == [[15, 45], [0, 0]]
assert adapter.regions == [{"wdth": (-1.0, -1.0, 0)}]
@@ -747,6 +775,8 @@ class InstantiateOTLTest(object):
vf = varfontGDEF
assert "GDEF" in vf
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateOTL(vf, location)
assert "GDEF" in vf
@@ -778,6 +808,8 @@ class InstantiateOTLTest(object):
vf = varfontGDEF
assert "GDEF" in vf
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateOTL(vf, location)
assert "GDEF" in vf
@@ -806,6 +838,8 @@ class InstantiateOTLTest(object):
assert "GDEF" in vf
assert "GPOS" in vf
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateOTL(vf, location)
gdef = vf["GDEF"].table
@@ -839,6 +873,8 @@ class InstantiateOTLTest(object):
assert "GDEF" in vf
assert "GPOS" in vf
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateOTL(vf, location)
assert "GDEF" not in vf
@@ -870,6 +906,8 @@ class InstantiateOTLTest(object):
assert "GDEF" in vf
assert "GPOS" in vf
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateOTL(vf, location)
v1, v2 = expected
@@ -915,6 +953,8 @@ class InstantiateOTLTest(object):
assert "GDEF" in vf
assert "GPOS" in vf
+ location = instancer.NormalizedAxisLimits(location)
+
instancer.instantiateOTL(vf, location)
v1, v2 = expected
@@ -955,7 +995,7 @@ class InstantiateOTLTest(object):
# check that MutatorMerger for ValueRecord doesn't raise AttributeError
# when XAdvDevice is present but there's no corresponding XAdvance.
- instancer.instantiateOTL(vf, {"wght": 0.5})
+ instancer.instantiateOTL(vf, instancer.NormalizedAxisLimits(wght=0.5))
pairPos = vf["GPOS"].table.LookupList.Lookup[0].SubTable[0]
assert pairPos.ValueFormat1 == 0x4
@@ -967,12 +1007,16 @@ class InstantiateOTLTest(object):
class InstantiateAvarTest(object):
@pytest.mark.parametrize("location", [{"wght": 0.0}, {"wdth": 0.0}])
def test_pin_and_drop_axis(self, varfont, location):
+ location = instancer.AxisLimits(location)
+
instancer.instantiateAvar(varfont, location)
assert set(varfont["avar"].segments).isdisjoint(location)
def test_full_instance(self, varfont):
- instancer.instantiateAvar(varfont, {"wght": 0.0, "wdth": 0.0})
+ location = instancer.AxisLimits(wght=0.0, wdth=0.0)
+
+ instancer.instantiateAvar(varfont, location)
assert "avar" not in varfont
@@ -1139,6 +1183,8 @@ class InstantiateAvarTest(object):
],
)
def test_limit_axes(self, varfont, axisLimits, expectedSegments):
+ axisLimits = instancer.AxisLimits(axisLimits)
+
instancer.instantiateAvar(varfont, axisLimits)
newSegments = varfont["avar"].segments
@@ -1162,8 +1208,10 @@ class InstantiateAvarTest(object):
def test_drop_invalid_segment_map(self, varfont, invalidSegmentMap, caplog):
varfont["avar"].segments["wght"] = invalidSegmentMap
+ axisLimits = instancer.AxisLimits(wght=(100, 400))
+
with caplog.at_level(logging.WARNING, logger="fontTools.varLib.instancer"):
- instancer.instantiateAvar(varfont, {"wght": (100, 400)})
+ instancer.instantiateAvar(varfont, axisLimits)
assert "Invalid avar" in caplog.text
assert "wght" not in varfont["avar"].segments
@@ -1210,6 +1258,8 @@ class InstantiateFvarTest(object):
],
)
def test_pin_and_drop_axis(self, varfont, location, instancesLeft):
+ location = instancer.AxisLimits(location)
+
instancer.instantiateFvar(varfont, location)
fvar = varfont["fvar"]
@@ -1224,20 +1274,51 @@ class InstantiateFvarTest(object):
] == instancesLeft
def test_full_instance(self, varfont):
- instancer.instantiateFvar(varfont, {"wght": 0.0, "wdth": 0.0})
+ location = instancer.AxisLimits({"wght": 0.0, "wdth": 0.0})
+
+ instancer.instantiateFvar(varfont, location)
assert "fvar" not in varfont
+ @pytest.mark.parametrize(
+ "location, expected",
+ [
+ ({"wght": (30, 40, 700)}, (100, 100, 700)),
+ ({"wght": (30, 40, None)}, (100, 100, 900)),
+ ({"wght": (30, None, 700)}, (100, 400, 700)),
+ ({"wght": (None, 200, 700)}, (100, 200, 700)),
+ ({"wght": (40, None, None)}, (100, 400, 900)),
+ ({"wght": (None, 40, None)}, (100, 100, 900)),
+ ({"wght": (None, None, 700)}, (100, 400, 700)),
+ ({"wght": (None, None, None)}, (100, 400, 900)),
+ ],
+ )
+ def test_axis_limits(self, varfont, location, expected):
+ location = instancer.AxisLimits(location)
+
+ varfont = instancer.instantiateVariableFont(varfont, location)
+
+ fvar = varfont["fvar"]
+ axes = {a.axisTag: a for a in fvar.axes}
+ assert axes["wght"].minValue == expected[0]
+ assert axes["wght"].defaultValue == expected[1]
+ assert axes["wght"].maxValue == expected[2]
+
class InstantiateSTATTest(object):
@pytest.mark.parametrize(
"location, expected",
[
({"wght": 400}, ["Regular", "Condensed", "Upright", "Normal"]),
- ({"wdth": 100}, ["Thin", "Regular", "Black", "Upright", "Normal"]),
+ (
+ {"wdth": 100},
+ ["Thin", "Regular", "Medium", "Black", "Upright", "Normal"],
+ ),
],
)
def test_pin_and_drop_axis(self, varfont, location, expected):
+ location = instancer.AxisLimits(location)
+
instancer.instantiateSTAT(varfont, location)
stat = varfont["STAT"].table
@@ -1256,7 +1337,7 @@ class InstantiateSTATTest(object):
def test_skip_table_no_axis_value_array(self, varfont):
varfont["STAT"].table.AxisValueArray = None
- instancer.instantiateSTAT(varfont, {"wght": 100})
+ instancer.instantiateSTAT(varfont, instancer.AxisLimits(wght=100))
assert len(varfont["STAT"].table.DesignAxisRecord.Axis) == 3
assert varfont["STAT"].table.AxisValueArray is None
@@ -1318,7 +1399,9 @@ class InstantiateSTATTest(object):
return result
def test_limit_axes(self, varfont2):
- instancer.instantiateSTAT(varfont2, {"wght": (400, 500), "wdth": (75, 100)})
+ axisLimits = instancer.AxisLimits({"wght": (400, 500), "wdth": (75, 100)})
+
+ instancer.instantiateSTAT(varfont2, axisLimits)
assert len(varfont2["STAT"].table.AxisValueArray.AxisValue) == 5
assert self.get_STAT_axis_values(varfont2["STAT"].table) == [
@@ -1344,11 +1427,11 @@ class InstantiateSTATTest(object):
axisValue.AxisValueRecord.append(rec)
stat.AxisValueArray.AxisValue.append(axisValue)
- instancer.instantiateSTAT(varfont2, {"wght": (100, 600)})
+ instancer.instantiateSTAT(varfont2, instancer.AxisLimits(wght=(100, 600)))
assert axisValue in varfont2["STAT"].table.AxisValueArray.AxisValue
- instancer.instantiateSTAT(varfont2, {"wdth": (62.5, 87.5)})
+ instancer.instantiateSTAT(varfont2, instancer.AxisLimits(wdth=(62.5, 87.5)))
assert axisValue not in varfont2["STAT"].table.AxisValueArray.AxisValue
@@ -1359,7 +1442,7 @@ class InstantiateSTATTest(object):
stat.AxisValueArray.AxisValue.append(axisValue)
with caplog.at_level(logging.WARNING, logger="fontTools.varLib.instancer"):
- instancer.instantiateSTAT(varfont2, {"wght": 400})
+ instancer.instantiateSTAT(varfont2, instancer.AxisLimits(wght=400))
assert "Unknown AxisValue table format (5)" in caplog.text
assert axisValue in varfont2["STAT"].table.AxisValueArray.AxisValue
@@ -1452,6 +1535,18 @@ class InstantiateVariableFontTest(object):
assert _dump_ttx(instance) == expected
+ def test_move_weight_width_axis_default(self, varfont2):
+ # https://github.com/fonttools/fonttools/issues/2885
+ assert varfont2["OS/2"].usWeightClass == 400
+ assert varfont2["OS/2"].usWidthClass == 5
+
+ varfont = instancer.instantiateVariableFont(
+ varfont2, {"wght": (100, 500, 900), "wdth": 87.5}
+ )
+
+ assert varfont["OS/2"].usWeightClass == 500
+ assert varfont["OS/2"].usWidthClass == 4
+
@pytest.mark.parametrize(
"overlap, wght",
[
@@ -1482,20 +1577,39 @@ class InstantiateVariableFontTest(object):
location = {"wght": 280, "opsz": 18}
instance = instancer.instantiateVariableFont(
- varfont, location,
+ varfont,
+ location,
)
- expected = _get_expected_instance_ttx(
- "SinglePos", *location.values()
- )
+ expected = _get_expected_instance_ttx("SinglePos", *location.values())
assert _dump_ttx(instance) == expected
+ def test_varComposite(self):
+ input_path = os.path.join(
+ TESTDATA, "..", "..", "..", "ttLib", "data", "varc-ac00-ac01.ttf"
+ )
+ varfont = ttLib.TTFont(input_path)
+
+ location = {"wght": 600}
+
+ instance = instancer.instantiateVariableFont(
+ varfont,
+ location,
+ )
+
+ location = {"0000": 0.5}
+
+ instance = instancer.instantiateVariableFont(
+ varfont,
+ location,
+ )
def _conditionSetAsDict(conditionSet, axisOrder):
result = {}
- for cond in conditionSet.ConditionTable:
+ conditionSets = conditionSet.ConditionTable if conditionSet is not None else []
+ for cond in conditionSets:
assert cond.Format == 1
axisTag = axisOrder[cond.AxisIndex]
result[axisTag] = (cond.FilterRangeMinValue, cond.FilterRangeMaxValue)
@@ -1541,10 +1655,11 @@ class InstantiateFeatureVariationsTest(object):
({"wght": 0}, {}, [({"cntr": (0.75, 1.0)}, {"uni0041": "uni0061"})]),
(
{"wght": -1.0},
- {},
+ {"uni0061": "uni0041"},
[
({"cntr": (0, 0.25)}, {"uni0061": "uni0041"}),
({"cntr": (0.75, 1.0)}, {"uni0041": "uni0061"}),
+ ({}, {}),
],
),
(
@@ -1554,7 +1669,8 @@ class InstantiateFeatureVariationsTest(object):
(
{"cntr": (0.75, 1.0)},
{"uni0024": "uni0024.nostroke", "uni0041": "uni0061"},
- )
+ ),
+ ({}, {}),
],
),
(
@@ -1572,7 +1688,66 @@ class InstantiateFeatureVariationsTest(object):
(
{"wght": (0.20886, 1.0)},
{"uni0024": "uni0024.nostroke", "uni0041": "uni0061"},
- )
+ ),
+ ({}, {}),
+ ],
+ ),
+ (
+ {"cntr": (-0.5, 0, 1.0)},
+ {},
+ [
+ (
+ {"wght": (0.20886, 1.0), "cntr": (0.75, 1)},
+ {"uni0024": "uni0024.nostroke", "uni0041": "uni0061"},
+ ),
+ (
+ {"wght": (-1.0, -0.45654), "cntr": (0, 0.25)},
+ {"uni0061": "uni0041"},
+ ),
+ (
+ {"cntr": (0.75, 1.0)},
+ {"uni0041": "uni0061"},
+ ),
+ (
+ {"wght": (0.20886, 1.0)},
+ {"uni0024": "uni0024.nostroke"},
+ ),
+ ],
+ ),
+ (
+ {"cntr": (0.8, 0.9, 1.0)},
+ {"uni0041": "uni0061"},
+ [
+ (
+ {"wght": (0.20886, 1.0)},
+ {"uni0024": "uni0024.nostroke", "uni0041": "uni0061"},
+ ),
+ (
+ {},
+ {"uni0041": "uni0061"},
+ ),
+ ],
+ ),
+ (
+ {"cntr": (0.7, 0.9, 1.0)},
+ {"uni0041": "uni0061"},
+ [
+ (
+ {"cntr": (-0.7499999999999999, 1.0), "wght": (0.20886, 1.0)},
+ {"uni0024": "uni0024.nostroke", "uni0041": "uni0061"},
+ ),
+ (
+ {"cntr": (-0.7499999999999999, 1.0)},
+ {"uni0041": "uni0061"},
+ ),
+ (
+ {"wght": (0.20886, 1.0)},
+ {"uni0024": "uni0024.nostroke"},
+ ),
+ (
+ {},
+ {},
+ ),
],
),
],
@@ -1589,25 +1764,30 @@ class InstantiateFeatureVariationsTest(object):
]
)
- instancer.instantiateFeatureVariations(font, location)
+ limits = instancer.NormalizedAxisLimits(location)
+ instancer.instantiateFeatureVariations(font, limits)
gsub = font["GSUB"].table
featureVariations = gsub.FeatureVariations
assert featureVariations.FeatureVariationCount == len(expectedRecords)
- axisOrder = [a.axisTag for a in font["fvar"].axes if a.axisTag not in location]
+ axisOrder = [
+ a.axisTag
+ for a in font["fvar"].axes
+ if a.axisTag not in location or isinstance(location[a.axisTag], tuple)
+ ]
for i, (expectedConditionSet, expectedSubs) in enumerate(expectedRecords):
rec = featureVariations.FeatureVariationRecord[i]
conditionSet = _conditionSetAsDict(rec.ConditionSet, axisOrder)
- assert conditionSet == expectedConditionSet
+ assert conditionSet == expectedConditionSet, i
subsRecord = rec.FeatureTableSubstitution.SubstitutionRecord[0]
lookupIndices = subsRecord.Feature.LookupListIndex
substitutions = _getSubstitutions(gsub, lookupIndices)
- assert substitutions == expectedSubs
+ assert substitutions == expectedSubs, i
appliedLookupIndices = gsub.FeatureList.FeatureRecord[0].Feature.LookupListIndex
@@ -1638,11 +1818,16 @@ class InstantiateFeatureVariationsTest(object):
),
]
)
+ gsub = font["GSUB"].table
+ assert gsub.FeatureVariations
+ assert gsub.Version == 0x00010001
+
+ location = instancer.NormalizedAxisLimits(location)
instancer.instantiateFeatureVariations(font, location)
- gsub = font["GSUB"].table
assert not hasattr(gsub, "FeatureVariations")
+ assert gsub.Version == 0x00010000
if appliedSubs:
lookupIndices = gsub.FeatureList.FeatureRecord[0].Feature.LookupListIndex
@@ -1650,6 +1835,24 @@ class InstantiateFeatureVariationsTest(object):
else:
assert not gsub.FeatureList.FeatureRecord
+ def test_null_conditionset(self):
+ # A null ConditionSet offset should be treated like an empty ConditionTable, i.e.
+ # all contexts are matched; see https://github.com/fonttools/fonttools/issues/3211
+ font = makeFeatureVarsFont(
+ [([{"wght": (-1.0, 1.0)}], {"uni0024": "uni0024.nostroke"})]
+ )
+ gsub = font["GSUB"].table
+ gsub.FeatureVariations.FeatureVariationRecord[0].ConditionSet = None
+
+ location = instancer.NormalizedAxisLimits({"wght": 0.5})
+ instancer.instantiateFeatureVariations(font, location)
+
+ assert not hasattr(gsub, "FeatureVariations")
+ assert gsub.Version == 0x00010000
+
+ lookupIndices = gsub.FeatureList.FeatureRecord[0].Feature.LookupListIndex
+ assert _getSubstitutions(gsub, lookupIndices) == {"uni0024": "uni0024.nostroke"}
+
def test_unsupported_condition_format(self, caplog):
font = makeFeatureVarsFont(
[
@@ -1665,7 +1868,9 @@ class InstantiateFeatureVariationsTest(object):
rec1.ConditionSet.ConditionTable[0].Format = 2
with caplog.at_level(logging.WARNING, logger="fontTools.varLib.instancer"):
- instancer.instantiateFeatureVariations(font, {"wdth": 0})
+ instancer.instantiateFeatureVariations(
+ font, instancer.NormalizedAxisLimits(wdth=0)
+ )
assert (
"Condition table 0 of FeatureVariationRecord 0 "
@@ -1695,7 +1900,7 @@ class InstantiateFeatureVariationsTest(object):
class LimitTupleVariationAxisRangesTest:
def check_limit_single_var_axis_range(self, var, axisTag, axisRange, expected):
- result = instancer.limitTupleVariationAxisRange(var, axisTag, axisRange)
+ result = instancer.changeTupleVariationAxisLimit(var, axisTag, axisRange)
print(result)
assert len(result) == len(expected)
@@ -1758,8 +1963,8 @@ class LimitTupleVariationAxisRangesTest:
"wght",
0.4,
[
- TupleVariation({"wght": (0.0, 0.5, 1.99994)}, [100, 100]),
- TupleVariation({"wght": (0.5, 1.0, 1.0)}, [8.33333, 8.33333]),
+ TupleVariation({"wght": (0.0, 0.5, 1.0)}, [100, 100]),
+ TupleVariation({"wght": (0.5, 1.0, 1.0)}, [75, 75]),
],
),
(
@@ -1777,7 +1982,7 @@ class LimitTupleVariationAxisRangesTest:
],
)
def test_positive_var(self, var, axisTag, newMax, expected):
- axisRange = instancer.NormalizedAxisRange(0, newMax)
+ axisRange = instancer.NormalizedAxisTripleAndDistances(0, 0, newMax)
self.check_limit_single_var_axis_range(var, axisTag, axisRange, expected)
@pytest.mark.parametrize(
@@ -1837,8 +2042,8 @@ class LimitTupleVariationAxisRangesTest:
"wght",
-0.4,
[
- TupleVariation({"wght": (-2.0, -0.5, -0.0)}, [100, 100]),
- TupleVariation({"wght": (-1.0, -1.0, -0.5)}, [8.33333, 8.33333]),
+ TupleVariation({"wght": (-1.0, -0.5, -0.0)}, [100, 100]),
+ TupleVariation({"wght": (-1.0, -1.0, -0.5)}, [75, 75]),
],
),
(
@@ -1856,30 +2061,30 @@ class LimitTupleVariationAxisRangesTest:
],
)
def test_negative_var(self, var, axisTag, newMin, expected):
- axisRange = instancer.NormalizedAxisRange(newMin, 0)
+ axisRange = instancer.NormalizedAxisTripleAndDistances(newMin, 0, 0, 1, 1)
self.check_limit_single_var_axis_range(var, axisTag, axisRange, expected)
@pytest.mark.parametrize(
- "oldRange, newRange, expected",
+ "oldRange, newLimit, expected",
[
- ((1.0, -1.0), (-1.0, 1.0), None), # invalid oldRange min > max
- ((0.6, 1.0), (0, 0.5), None),
- ((-1.0, -0.6), (-0.5, 0), None),
- ((0.4, 1.0), (0, 0.5), (0.8, 1.0)),
- ((-1.0, -0.4), (-0.5, 0), (-1.0, -0.8)),
- ((0.4, 1.0), (0, 0.4), (1.0, 1.0)),
- ((-1.0, -0.4), (-0.4, 0), (-1.0, -1.0)),
- ((-0.5, 0.5), (-0.4, 0.4), (-1.0, 1.0)),
- ((0, 1.0), (-1.0, 0), (0, 0)), # or None?
- ((-1.0, 0), (0, 1.0), (0, 0)), # or None?
+ ((1.0, -1.0), (-1.0, 0, 1.0), None), # invalid oldRange min > max
+ ((0.6, 1.0), (0, 0, 0.5), None),
+ ((-1.0, -0.6), (-0.5, 0, 0), None),
+ ((0.4, 1.0), (0, 0, 0.5), (0.8, 1.0)),
+ ((-1.0, -0.4), (-0.5, 0, 0), (-1.0, -0.8)),
+ ((0.4, 1.0), (0, 0, 0.4), (1.0, 1.0)),
+ ((-1.0, -0.4), (-0.4, 0, 0), (-1.0, -1.0)),
+ ((-0.5, 0.5), (-0.4, 0, 0.4), (-1.0, 1.0)),
+ ((0, 1.0), (-1.0, 0, 0), (0, 0)), # or None?
+ ((-1.0, 0), (0, 0, 1.0), (0, 0)), # or None?
],
)
-def test_limitFeatureVariationConditionRange(oldRange, newRange, expected):
+def test_limitFeatureVariationConditionRange(oldRange, newLimit, expected):
condition = featureVars.buildConditionTable(0, *oldRange)
- result = instancer._limitFeatureVariationConditionRange(
- condition, instancer.NormalizedAxisRange(*newRange)
+ result = instancer.featureVars._limitFeatureVariationConditionRange(
+ condition, instancer.NormalizedAxisTripleAndDistances(*newLimit, 1, 1)
)
assert result == expected
@@ -1890,12 +2095,33 @@ def test_limitFeatureVariationConditionRange(oldRange, newRange, expected):
[
(["wght=400", "wdth=100"], {"wght": 400, "wdth": 100}),
(["wght=400:900"], {"wght": (400, 900)}),
- (["slnt=11.4"], {"slnt": pytest.approx(11.399994)}),
+ (["wght=400:700:900"], {"wght": (400, 700, 900)}),
+ (["slnt=11.4"], {"slnt": 11.399994}),
(["ABCD=drop"], {"ABCD": None}),
+ (["wght=:500:"], {"wght": (None, 500, None)}),
+ (["wght=::700"], {"wght": (None, None, 700)}),
+ (["wght=200::"], {"wght": (200, None, None)}),
+ (["wght=200:300:"], {"wght": (200, 300, None)}),
+ (["wght=:300:500"], {"wght": (None, 300, 500)}),
+ (["wght=300::700"], {"wght": (300, None, 700)}),
+ (["wght=300:700"], {"wght": (300, None, 700)}),
+ (["wght=:700"], {"wght": (None, None, 700)}),
+ (["wght=200:"], {"wght": (200, None, None)}),
],
)
def test_parseLimits(limits, expected):
- assert instancer.parseLimits(limits) == expected
+ limits = instancer.parseLimits(limits)
+ expected = instancer.AxisLimits(expected)
+
+ assert limits.keys() == expected.keys()
+ for axis, triple in limits.items():
+ expected_triple = expected[axis]
+ if expected_triple is None:
+ assert triple is None
+ else:
+ assert isinstance(triple, instancer.AxisTriple)
+ assert isinstance(expected_triple, instancer.AxisTriple)
+ assert triple == pytest.approx(expected_triple)
@pytest.mark.parametrize(
@@ -1906,27 +2132,35 @@ def test_parseLimits_invalid(limits):
instancer.parseLimits(limits)
-def test_normalizeAxisLimits_tuple(varfont):
- normalized = instancer.normalizeAxisLimits(varfont, {"wght": (100, 400)})
- assert normalized == {"wght": (-1.0, 0)}
+@pytest.mark.parametrize(
+ "limits, expected",
+ [
+ # 300, 500 come from the font having 100,400,900 fvar axis limits.
+ ({"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):
+ limits = instancer.AxisLimits(limits)
+ normalized = limits.normalize(varfont)
-def test_normalizeAxisLimits_unsupported_range(varfont):
- with pytest.raises(NotImplementedError, match="Unsupported range"):
- instancer.normalizeAxisLimits(varfont, {"wght": (401, 700)})
+ assert normalized == instancer.NormalizedAxisLimits(expected)
def test_normalizeAxisLimits_no_avar(varfont):
del varfont["avar"]
- normalized = instancer.normalizeAxisLimits(varfont, {"wght": (400, 500)})
+ limits = instancer.AxisLimits(wght=(400, 400, 500))
+ normalized = limits.normalize(varfont)
- assert normalized["wght"] == pytest.approx((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):
with pytest.raises(ValueError, match="not present in fvar"):
- instancer.normalizeAxisLimits(varfont, {"ZZZZ": 1000})
+ instancer.AxisLimits({"ZZZZ": 1000}).normalize(varfont)
def test_sanityCheckVariableTables(varfont):