[varLib/merger] Fix merging of SinglePos with pos=0

Fixes https://github.com/fonttools/fonttools/issues/3111
This commit is contained in:
Behdad Esfahbod 2023-05-19 10:03:50 -06:00
parent 65bc6105f7
commit 4c24a3e328
3 changed files with 47 additions and 10 deletions

View File

@ -81,7 +81,6 @@ class Merger(object):
typ = type(thing) typ = type(thing)
for celf in celf.mro(): for celf in celf.mro():
mergers = getattr(celf, "mergers", None) mergers = getattr(celf, "mergers", None)
if mergers is None: if mergers is None:
break break
@ -318,7 +317,13 @@ def merge(merger, self, lst):
): ):
self.Value = otBase.ValueRecord(valueFormat, self.Value) self.Value = otBase.ValueRecord(valueFormat, self.Value)
if valueFormat != 0: if valueFormat != 0:
merger.mergeThings(self.Value, [v.Value for v in lst]) # If v.Value is None, it means a kerning of 0; we want
# it to participate in the model still.
# https://github.com/fonttools/fonttools/issues/3111
merger.mergeThings(
self.Value,
[v.Value if v.Value is not None else otBase.ValueRecord() for v in lst],
)
self.ValueFormat = self.Value.getFormat() self.ValueFormat = self.Value.getFormat()
return return
@ -449,7 +454,6 @@ def _PairPosFormat1_merge(self, lst, merger):
def _ClassDef_invert(self, allGlyphs=None): def _ClassDef_invert(self, allGlyphs=None):
if isinstance(self, dict): if isinstance(self, dict):
classDefs = self classDefs = self
else: else:
@ -505,7 +509,6 @@ def _ClassDef_merge_classify(lst, allGlyphses=None):
def _PairPosFormat2_align_matrices(self, lst, font, transparent=False): def _PairPosFormat2_align_matrices(self, lst, font, transparent=False):
matrices = [l.Class1Record for l in lst] matrices = [l.Class1Record for l in lst]
# Align first classes # Align first classes
@ -1057,7 +1060,6 @@ def merge(merger, self, lst):
("XPlacement", "XPlaDevice"), ("XPlacement", "XPlaDevice"),
("YPlacement", "YPlaDevice"), ("YPlacement", "YPlaDevice"),
]: ]:
assert not hasattr(self, tableName) assert not hasattr(self, tableName)
if hasattr(self, name): if hasattr(self, name):
@ -1085,7 +1087,6 @@ class MutatorMerger(AligningMerger):
@MutatorMerger.merger(ot.CaretValue) @MutatorMerger.merger(ot.CaretValue)
def merge(merger, self, lst): def merge(merger, self, lst):
# Hack till we become selfless. # Hack till we become selfless.
self.__dict__ = lst[0].__dict__.copy() self.__dict__ = lst[0].__dict__.copy()
@ -1108,7 +1109,6 @@ def merge(merger, self, lst):
@MutatorMerger.merger(ot.Anchor) @MutatorMerger.merger(ot.Anchor)
def merge(merger, self, lst): def merge(merger, self, lst):
# Hack till we become selfless. # Hack till we become selfless.
self.__dict__ = lst[0].__dict__.copy() self.__dict__ = lst[0].__dict__.copy()
@ -1139,7 +1139,6 @@ def merge(merger, self, lst):
@MutatorMerger.merger(otBase.ValueRecord) @MutatorMerger.merger(otBase.ValueRecord)
def merge(merger, self, lst): def merge(merger, self, lst):
# Hack till we become selfless. # Hack till we become selfless.
self.__dict__ = lst[0].__dict__.copy() self.__dict__ = lst[0].__dict__.copy()
@ -1150,7 +1149,6 @@ def merge(merger, self, lst):
("XPlacement", "XPlaDevice"), ("XPlacement", "XPlaDevice"),
("YPlacement", "YPlaDevice"), ("YPlacement", "YPlaDevice"),
]: ]:
if not hasattr(self, tableName): if not hasattr(self, tableName):
continue continue
dev = getattr(self, tableName) dev = getattr(self, tableName)
@ -1266,7 +1264,6 @@ def merge(merger, self, lst):
("XPlacement", "XPlaDevice"), ("XPlacement", "XPlaDevice"),
("YPlacement", "YPlaDevice"), ("YPlacement", "YPlaDevice"),
]: ]:
if hasattr(self, name): if hasattr(self, name):
value, deviceTable = buildVarDevTable( value, deviceTable = buildVarDevTable(
merger.store_builder, [getattr(a, name, 0) for a in lst] merger.store_builder, [getattr(a, name, 0) for a in lst]

View File

@ -7,6 +7,7 @@ from fontTools.varLib.models import VariationModel
from fontTools.ttLib import TTFont from fontTools.ttLib import TTFont
from fontTools.ttLib.tables import otTables as ot from fontTools.ttLib.tables import otTables as ot
from fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter from fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter
from io import BytesIO
import pytest import pytest
@ -1842,3 +1843,41 @@ class COLRVariationMergerTest:
if colr.table.LayerList: if colr.table.LayerList:
assert len({id(p) for p in colr.table.LayerList.Paint}) == after_layer_count assert len({id(p) for p in colr.table.LayerList.Paint}) == after_layer_count
class SparsePositioningMergerTest:
def test_sparse_positioning_at_default(self):
# https://github.com/fonttools/fonttools/issues/3111
pytest.importorskip("ufo2ft")
pytest.importorskip("ufoLib2")
from fontTools.designspaceLib import DesignSpaceDocument
from ufo2ft import compileVariableTTF
from ufoLib2 import Font
ds = DesignSpaceDocument()
ds.addAxisDescriptor(
name="wght", tag="wght", minimum=100, maximum=900, default=400
)
ds.addSourceDescriptor(font=Font(), location=dict(wght=100))
ds.addSourceDescriptor(font=Font(), location=dict(wght=400))
ds.addSourceDescriptor(font=Font(), location=dict(wght=900))
ds.sources[0].font.newGlyph("a").unicode = ord("a")
ds.sources[0].font.newGlyph("b").unicode = ord("b")
ds.sources[0].font.features.text = "feature kern { pos a b b' 100; } kern;"
ds.sources[1].font.newGlyph("a").unicode = ord("a")
ds.sources[1].font.newGlyph("b").unicode = ord("b")
ds.sources[1].font.features.text = "feature kern { pos a b b' 0; } kern;"
ds.sources[2].font.newGlyph("a").unicode = ord("a")
ds.sources[2].font.newGlyph("b").unicode = ord("b")
ds.sources[2].font.features.text = "feature kern { pos a b b' -100; } kern;"
font = compileVariableTTF(ds, inplace=True)
b = BytesIO()
font.save(b)
assert font["GDEF"].table.VarStore.VarData[0].Item[0] == [100, -100]

View File

@ -10,6 +10,7 @@ fs==2.4.16
skia-pathops==0.7.3; platform_python_implementation != "PyPy" skia-pathops==0.7.3; platform_python_implementation != "PyPy"
# this is only required to run Tests/cu2qu/{ufo,cli}_test.py # this is only required to run Tests/cu2qu/{ufo,cli}_test.py
ufoLib2==0.14.0 ufoLib2==0.14.0
ufo2ft==2.31.0
pyobjc==9.0; sys_platform == "darwin" pyobjc==9.0; sys_platform == "darwin"
freetype-py==2.3.0 freetype-py==2.3.0
uharfbuzz==0.32.0 uharfbuzz==0.32.0