From af22cf053273fd2122309fa121275859caafd8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=92=90?= Date: Thu, 23 May 2024 09:57:26 +0800 Subject: [PATCH] Fix merging of SinglePos with pos=0 --- ...-Fix-merging-of-SinglePos-with-pos-0.patch | 172 ++++++++++++++++++ python-fonttools.spec | 6 +- 2 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 backport-Fix-merging-of-SinglePos-with-pos-0.patch diff --git a/backport-Fix-merging-of-SinglePos-with-pos-0.patch b/backport-Fix-merging-of-SinglePos-with-pos-0.patch new file mode 100644 index 0000000..b2f2cc9 --- /dev/null +++ b/backport-Fix-merging-of-SinglePos-with-pos-0.patch @@ -0,0 +1,172 @@ +From 4c24a3e32823ad4fb5ee4e785451266271bb4df4 Mon Sep 17 00:00:00 2001 +From: Behdad Esfahbod +Date: Fri, 19 May 2023 10:03:50 -0600 +Subject: [PATCH] [varLib/merger] Fix merging of SinglePos with pos=0 + +Fixes https://github.com/fonttools/fonttools/issues/3111 +--- + Lib/fontTools/varLib/merger.py | 17 ++++++--------- + Tests/varLib/merger_test.py | 39 ++++++++++++++++++++++++++++++++++ + requirements.txt | 1 + + 3 files changed, 47 insertions(+), 10 deletions(-) + +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 +-- +2.27.0 + diff --git a/python-fonttools.spec b/python-fonttools.spec index f70188a..b1ffc61 100644 --- a/python-fonttools.spec +++ b/python-fonttools.spec @@ -1,11 +1,12 @@ Name: fonttools Version: 4.39.4 -Release: 2 +Release: 3 Summary: Tools to manipulate font files License: MIT URL: https://github.com/fonttools/fonttools/ Source0: %{url}/archive/refs/tags/%{version}.tar.gz Patch0: CVE-2023-45139.patch +Patch1: backport-Fix-merging-of-SinglePos-with-pos-0.patch Requires: python3-fonttools Requires: python3-setuptools BuildArch: noarch @@ -65,6 +66,9 @@ rm -rf *.egg-info %{python3_sitelib}/fonttools-%{version}-py3.*.egg-info %changelog +* Thu May 23 2024 lilu - 4.39.4-3 +- Fix merging of SinglePos with pos=0 + * Thu Jan 11 2024 wangkai <13474090681@163.com> - 4.39.4-2 - Fix CVE-2023-45139