[varLib.avar] Test & fix _pruneLocations

This commit is contained in:
Behdad Esfahbod 2024-08-02 19:32:45 -06:00
parent 700b6a7b0e
commit 2742c6287c
2 changed files with 88 additions and 20 deletions

View File

@ -22,15 +22,16 @@ def _pruneLocations(locations, poles, axisTags):
model = VariationModel(locations, axisTags) model = VariationModel(locations, axisTags)
modelMapping = model.mapping modelMapping = model.mapping
modelSupports = model.supports modelSupports = model.supports
pins = poles.copy() pins = {tuple(k.items()): None for k in poles}
for pole in poles.keys(): for location in poles:
location = dict(pole)
i = locations.index(location) i = locations.index(location)
i = modelMapping[i] i = modelMapping[i]
support = modelSupports[i] support = modelSupports[i]
supportAxes = set(support.keys()) supportAxes = set(support.keys())
for supportIndex, (axisTag, (minV, _, maxV)) in enumerate(support.items()): for axisTag, (minV, _, maxV) in support.items():
for v in (minV, maxV): for v in (minV, maxV):
if v in (-1, 0, 1):
continue
for pin in pins.keys(): for pin in pins.keys():
pinLocation = dict(pin) pinLocation = dict(pin)
pinAxes = set(pinLocation.keys()) pinAxes = set(pinLocation.keys())
@ -40,21 +41,27 @@ def _pruneLocations(locations, poles, axisTags):
continue continue
if pinLocation[axisTag] == v: if pinLocation[axisTag] == v:
break break
else: else:
# No pin found. Go through the previous masters # No pin found. Go through the previous masters
# and find a suitable pin. Going backwards is # and find a suitable pin. Going backwards is
# better because it can find a pin that is close # better because it can find a pin that is close
# to the pole in more dimensions, and reducing # to the pole in more dimensions, and reducing
# the total number of pins needed. # the total number of pins needed.
for candidateIdx in range(supportIndex - 1, -1, -1): for candidateIdx in range(i - 1, -1, -1):
candidate = modelSupports[candidateIdx] candidate = modelSupports[candidateIdx]
candidateAxes = set(candidate.keys()) candidateAxes = set(candidate.keys())
if candidateAxes != supportAxes: if candidateAxes != supportAxes:
continue continue
if axisTag not in candidateAxes: if axisTag not in candidateAxes:
continue continue
if candidateLocation[axisTag] == v: candidate = {
pins[tuple(candidateLocation.items())] = None k: defaultV for k, (_, defaultV, _) in candidate.items()
}
if candidate[axisTag] == v:
pins[tuple(candidate.items())] = None
break
else:
assert False, "No pin found"
return [dict(t) for t in pins.keys()] return [dict(t) for t in pins.keys()]
@ -115,7 +122,8 @@ def mappings_from_avar(font, denormalize=True):
key=lambda t: (len(t), tuple(axisIndexes[tag] for tag, _ in t)), key=lambda t: (len(t), tuple(axisIndexes[tag] for tag, _ in t)),
) )
] ]
inputLocations = _pruneLocations(inputLocations, poles, axisTags) poles = [dict(t) for t in poles.keys()]
inputLocations = _pruneLocations(inputLocations, list(poles), axisTags)
# Find the output locations, at input locations # Find the output locations, at input locations
varIdxMap = avar.table.VarIdxMap varIdxMap = avar.table.VarIdxMap
@ -210,6 +218,7 @@ def main(args=None):
segments, mappings = mappings_from_avar(font) segments, mappings = mappings_from_avar(font)
pprint(segments) pprint(segments)
pprint(mappings) pprint(mappings)
print(len(mappings), "mappings")
return return
axisTags = [a.axisTag for a in font["fvar"].axes] axisTags = [a.axisTag for a in font["fvar"].axes]

59
Tests/varLib/avar_test.py Normal file
View File

@ -0,0 +1,59 @@
from fontTools.varLib.avar import _pruneLocations
import unittest
import pytest
@pytest.mark.parametrize(
"locations, poles, expected",
[
(
[
{"wght": 1},
{"wght": 0.5},
],
[
{"wght": 0.5},
],
[
{"wght": 0.5},
],
),
(
[
{"wght": 1, "wdth": 1},
{"wght": 0.5, "wdth": 1},
],
[
{"wght": 1, "wdth": 1},
],
[
{"wght": 1, "wdth": 1},
{"wght": 0.5, "wdth": 1},
],
),
(
[
{"wght": 1},
{"wdth": 1},
{"wght": 0.5, "wdth": 0.5},
],
[
{"wght": 0.5, "wdth": 0.5},
],
[
{"wght": 0.5, "wdth": 0.5},
],
),
],
)
def test_pruneLocations(locations, poles, expected):
axisTags = set()
for location in locations:
axisTags.update(location.keys())
axisTags = sorted(axisTags)
locations = [{}] + locations
output = _pruneLocations(locations, poles, axisTags)
assert output == expected, (output, expected)