diff --git a/Lib/fontTools/varLib/merger.py b/Lib/fontTools/varLib/merger.py index 7e6392540..c3366cbcd 100644 --- a/Lib/fontTools/varLib/merger.py +++ b/Lib/fontTools/varLib/merger.py @@ -81,7 +81,6 @@ class Merger(object): typ = type(thing) for celf in celf.mro(): - mergers = getattr(celf, "mergers", None) if mergers is None: break @@ -318,7 +317,13 @@ def merge(merger, self, lst): ): self.Value = otBase.ValueRecord(valueFormat, self.Value) 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() return @@ -449,7 +454,6 @@ def _PairPosFormat1_merge(self, lst, merger): def _ClassDef_invert(self, allGlyphs=None): - if isinstance(self, dict): classDefs = self else: @@ -505,7 +509,6 @@ def _ClassDef_merge_classify(lst, allGlyphses=None): def _PairPosFormat2_align_matrices(self, lst, font, transparent=False): - matrices = [l.Class1Record for l in lst] # Align first classes @@ -1057,7 +1060,6 @@ def merge(merger, self, lst): ("XPlacement", "XPlaDevice"), ("YPlacement", "YPlaDevice"), ]: - assert not hasattr(self, tableName) if hasattr(self, name): @@ -1085,7 +1087,6 @@ class MutatorMerger(AligningMerger): @MutatorMerger.merger(ot.CaretValue) def merge(merger, self, lst): - # Hack till we become selfless. self.__dict__ = lst[0].__dict__.copy() @@ -1108,7 +1109,6 @@ def merge(merger, self, lst): @MutatorMerger.merger(ot.Anchor) def merge(merger, self, lst): - # Hack till we become selfless. self.__dict__ = lst[0].__dict__.copy() @@ -1139,7 +1139,6 @@ def merge(merger, self, lst): @MutatorMerger.merger(otBase.ValueRecord) def merge(merger, self, lst): - # Hack till we become selfless. self.__dict__ = lst[0].__dict__.copy() @@ -1150,7 +1149,6 @@ def merge(merger, self, lst): ("XPlacement", "XPlaDevice"), ("YPlacement", "YPlaDevice"), ]: - if not hasattr(self, tableName): continue dev = getattr(self, tableName) @@ -1266,7 +1264,6 @@ def merge(merger, self, lst): ("XPlacement", "XPlaDevice"), ("YPlacement", "YPlaDevice"), ]: - if hasattr(self, name): value, deviceTable = buildVarDevTable( merger.store_builder, [getattr(a, name, 0) for a in lst] diff --git a/Tests/varLib/merger_test.py b/Tests/varLib/merger_test.py index aa7a69984..c92921248 100644 --- a/Tests/varLib/merger_test.py +++ b/Tests/varLib/merger_test.py @@ -7,6 +7,7 @@ from fontTools.varLib.models import VariationModel from fontTools.ttLib import TTFont from fontTools.ttLib.tables import otTables as ot from fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter +from io import BytesIO import pytest @@ -1842,3 +1843,41 @@ class COLRVariationMergerTest: if colr.table.LayerList: 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] diff --git a/requirements.txt b/requirements.txt index d8c98876a..690837eb2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ fs==2.4.16 skia-pathops==0.7.3; platform_python_implementation != "PyPy" # this is only required to run Tests/cu2qu/{ufo,cli}_test.py ufoLib2==0.14.0 +ufo2ft==2.31.0 pyobjc==9.0; sys_platform == "darwin" freetype-py==2.3.0 uharfbuzz==0.32.0