fonttools 4.55.4__cp313-cp313-musllinux_1_2_aarch64.whl → 4.61.1__cp313-cp313-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fontTools/__init__.py +1 -1
- fontTools/annotations.py +30 -0
- fontTools/cffLib/CFF2ToCFF.py +65 -10
- fontTools/cffLib/__init__.py +61 -26
- fontTools/cffLib/specializer.py +4 -1
- fontTools/cffLib/transforms.py +11 -6
- fontTools/config/__init__.py +15 -0
- fontTools/cu2qu/cu2qu.c +6567 -5579
- fontTools/cu2qu/cu2qu.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/cu2qu/cu2qu.py +36 -4
- fontTools/cu2qu/ufo.py +14 -0
- fontTools/designspaceLib/__init__.py +8 -3
- fontTools/designspaceLib/statNames.py +14 -7
- fontTools/feaLib/ast.py +24 -15
- fontTools/feaLib/builder.py +139 -66
- fontTools/feaLib/error.py +1 -1
- fontTools/feaLib/lexer.c +7038 -7995
- fontTools/feaLib/lexer.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/feaLib/parser.py +75 -40
- fontTools/feaLib/variableScalar.py +6 -1
- fontTools/fontBuilder.py +50 -44
- fontTools/merge/__init__.py +1 -1
- fontTools/merge/cmap.py +33 -1
- fontTools/merge/tables.py +12 -1
- fontTools/misc/bezierTools.c +14913 -17013
- fontTools/misc/bezierTools.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/misc/bezierTools.py +4 -1
- fontTools/misc/configTools.py +3 -1
- fontTools/misc/enumTools.py +23 -0
- fontTools/misc/etree.py +4 -27
- fontTools/misc/filesystem/__init__.py +68 -0
- fontTools/misc/filesystem/_base.py +134 -0
- fontTools/misc/filesystem/_copy.py +45 -0
- fontTools/misc/filesystem/_errors.py +54 -0
- fontTools/misc/filesystem/_info.py +75 -0
- fontTools/misc/filesystem/_osfs.py +164 -0
- fontTools/misc/filesystem/_path.py +67 -0
- fontTools/misc/filesystem/_subfs.py +92 -0
- fontTools/misc/filesystem/_tempfs.py +34 -0
- fontTools/misc/filesystem/_tools.py +34 -0
- fontTools/misc/filesystem/_walk.py +55 -0
- fontTools/misc/filesystem/_zipfs.py +204 -0
- fontTools/misc/fixedTools.py +1 -1
- fontTools/misc/loggingTools.py +1 -1
- fontTools/misc/psCharStrings.py +17 -2
- fontTools/misc/sstruct.py +2 -6
- fontTools/misc/symfont.py +6 -8
- fontTools/misc/testTools.py +5 -1
- fontTools/misc/textTools.py +4 -2
- fontTools/misc/visitor.py +32 -16
- fontTools/misc/xmlWriter.py +44 -8
- fontTools/mtiLib/__init__.py +1 -3
- fontTools/otlLib/builder.py +402 -155
- fontTools/otlLib/optimize/gpos.py +49 -63
- fontTools/pens/filterPen.py +218 -26
- fontTools/pens/momentsPen.c +5514 -5584
- fontTools/pens/momentsPen.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/pens/pointPen.py +61 -18
- fontTools/pens/roundingPen.py +2 -2
- fontTools/pens/t2CharStringPen.py +31 -11
- fontTools/qu2cu/qu2cu.c +6581 -6168
- fontTools/qu2cu/qu2cu.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/subset/__init__.py +283 -25
- fontTools/subset/svg.py +2 -3
- fontTools/ttLib/__init__.py +4 -0
- fontTools/ttLib/__main__.py +47 -8
- fontTools/ttLib/removeOverlaps.py +7 -5
- fontTools/ttLib/reorderGlyphs.py +8 -7
- fontTools/ttLib/sfnt.py +11 -9
- fontTools/ttLib/tables/D__e_b_g.py +20 -2
- fontTools/ttLib/tables/G_V_A_R_.py +5 -0
- fontTools/ttLib/tables/S__i_l_f.py +2 -2
- fontTools/ttLib/tables/T_S_I__0.py +14 -3
- fontTools/ttLib/tables/T_S_I__1.py +2 -5
- fontTools/ttLib/tables/T_S_I__5.py +18 -7
- fontTools/ttLib/tables/__init__.py +1 -0
- fontTools/ttLib/tables/_a_v_a_r.py +12 -3
- fontTools/ttLib/tables/_c_m_a_p.py +20 -7
- fontTools/ttLib/tables/_c_v_t.py +3 -2
- fontTools/ttLib/tables/_f_p_g_m.py +3 -1
- fontTools/ttLib/tables/_g_l_y_f.py +45 -21
- fontTools/ttLib/tables/_g_v_a_r.py +67 -19
- fontTools/ttLib/tables/_h_d_m_x.py +4 -4
- fontTools/ttLib/tables/_h_m_t_x.py +7 -3
- fontTools/ttLib/tables/_l_o_c_a.py +2 -2
- fontTools/ttLib/tables/_n_a_m_e.py +11 -6
- fontTools/ttLib/tables/_p_o_s_t.py +9 -7
- fontTools/ttLib/tables/otBase.py +5 -12
- fontTools/ttLib/tables/otConverters.py +5 -2
- fontTools/ttLib/tables/otData.py +1 -1
- fontTools/ttLib/tables/otTables.py +33 -30
- fontTools/ttLib/tables/otTraverse.py +2 -1
- fontTools/ttLib/tables/sbixStrike.py +3 -3
- fontTools/ttLib/ttFont.py +666 -120
- fontTools/ttLib/ttGlyphSet.py +0 -10
- fontTools/ttLib/woff2.py +10 -13
- fontTools/ttx.py +13 -1
- fontTools/ufoLib/__init__.py +300 -202
- fontTools/ufoLib/converters.py +103 -30
- fontTools/ufoLib/errors.py +8 -0
- fontTools/ufoLib/etree.py +1 -1
- fontTools/ufoLib/filenames.py +171 -106
- fontTools/ufoLib/glifLib.py +303 -205
- fontTools/ufoLib/kerning.py +98 -48
- fontTools/ufoLib/utils.py +46 -15
- fontTools/ufoLib/validators.py +121 -99
- fontTools/unicodedata/Blocks.py +35 -20
- fontTools/unicodedata/Mirrored.py +446 -0
- fontTools/unicodedata/ScriptExtensions.py +63 -37
- fontTools/unicodedata/Scripts.py +173 -152
- fontTools/unicodedata/__init__.py +10 -2
- fontTools/varLib/__init__.py +198 -109
- fontTools/varLib/avar/__init__.py +0 -0
- fontTools/varLib/avar/__main__.py +72 -0
- fontTools/varLib/avar/build.py +79 -0
- fontTools/varLib/avar/map.py +108 -0
- fontTools/varLib/avar/plan.py +1004 -0
- fontTools/varLib/{avar.py → avar/unbuild.py} +70 -59
- fontTools/varLib/avarPlanner.py +3 -999
- fontTools/varLib/featureVars.py +21 -7
- fontTools/varLib/hvar.py +113 -0
- fontTools/varLib/instancer/__init__.py +180 -65
- fontTools/varLib/interpolatableHelpers.py +3 -0
- fontTools/varLib/iup.c +7564 -6903
- fontTools/varLib/iup.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/varLib/models.py +17 -2
- fontTools/varLib/mutator.py +11 -0
- fontTools/varLib/varStore.py +10 -38
- fontTools/voltLib/__main__.py +206 -0
- fontTools/voltLib/ast.py +4 -0
- fontTools/voltLib/parser.py +16 -8
- fontTools/voltLib/voltToFea.py +347 -166
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/METADATA +269 -1410
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/RECORD +318 -294
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/WHEEL +1 -1
- fonttools-4.61.1.dist-info/licenses/LICENSE.external +388 -0
- {fonttools-4.55.4.data → fonttools-4.61.1.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/entry_points.txt +0 -0
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info/licenses}/LICENSE +0 -0
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/top_level.txt +0 -0
|
Binary file
|
fontTools/subset/__init__.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Google Author(s): Behdad Esfahbod
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
from fontTools import config
|
|
6
8
|
from fontTools.misc.roundTools import otRound
|
|
7
9
|
from fontTools import ttLib
|
|
@@ -15,7 +17,8 @@ from fontTools.subset.util import _add_method, _uniq_sort
|
|
|
15
17
|
from fontTools.subset.cff import *
|
|
16
18
|
from fontTools.subset.svg import *
|
|
17
19
|
from fontTools.varLib import varStore, multiVarStore # For monkey-patching
|
|
18
|
-
from fontTools.ttLib.tables._n_a_m_e import NameRecordVisitor
|
|
20
|
+
from fontTools.ttLib.tables._n_a_m_e import NameRecordVisitor, makeName
|
|
21
|
+
from fontTools.unicodedata import mirrored
|
|
19
22
|
import sys
|
|
20
23
|
import struct
|
|
21
24
|
import array
|
|
@@ -24,16 +27,16 @@ from collections import Counter, defaultdict
|
|
|
24
27
|
from functools import reduce
|
|
25
28
|
from types import MethodType
|
|
26
29
|
|
|
27
|
-
__usage__ = "
|
|
30
|
+
__usage__ = "fonttools subset font-file [glyph...] [--option=value]..."
|
|
28
31
|
|
|
29
32
|
__doc__ = (
|
|
30
33
|
"""\
|
|
31
|
-
|
|
34
|
+
fonttools subset -- OpenType font subsetter and optimizer
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
It accepts any TT- or CFF-flavored OpenType (.otf or .ttf)
|
|
35
|
-
font file. The subsetted glyph set is based on the
|
|
36
|
-
or characters, and specified OpenType layout features.
|
|
36
|
+
fonttools subset is an OpenType font subsetter and optimizer, based on
|
|
37
|
+
fontTools. It accepts any TT- or CFF-flavored OpenType (.otf or .ttf)
|
|
38
|
+
or WOFF (.woff) font file. The subsetted glyph set is based on the
|
|
39
|
+
specified glyphs or characters, and specified OpenType layout features.
|
|
37
40
|
|
|
38
41
|
The tool also performs some size-reducing optimizations, aimed for using
|
|
39
42
|
subset fonts as webfonts. Individual optimizations can be enabled or
|
|
@@ -127,11 +130,11 @@ you might need to escape the question mark, like this: '--glyph-names\\?'.
|
|
|
127
130
|
|
|
128
131
|
Examples::
|
|
129
132
|
|
|
130
|
-
$
|
|
133
|
+
$ fonttools subset --glyph-names?
|
|
131
134
|
Current setting for 'glyph-names' is: False
|
|
132
|
-
$
|
|
135
|
+
$ fonttools subset --name-IDs=?
|
|
133
136
|
Current setting for 'name-IDs' is: [0, 1, 2, 3, 4, 5, 6]
|
|
134
|
-
$
|
|
137
|
+
$ fonttools subset --hinting? --no-hinting --hinting?
|
|
135
138
|
Current setting for 'hinting' is: True
|
|
136
139
|
Current setting for 'hinting' is: False
|
|
137
140
|
|
|
@@ -269,7 +272,7 @@ Font table options
|
|
|
269
272
|
Specify (=), add to (+=) or exclude from (-=) the comma-separated
|
|
270
273
|
set of tables that will be be dropped.
|
|
271
274
|
By default, the following tables are dropped:
|
|
272
|
-
'
|
|
275
|
+
'JSTF', 'DSIG', 'EBDT', 'EBLC', 'EBSC', 'PCLT', 'LTSH'
|
|
273
276
|
and Graphite tables: 'Feat', 'Glat', 'Gloc', 'Silf', 'Sill'.
|
|
274
277
|
The tool will attempt to subset the remaining tables.
|
|
275
278
|
|
|
@@ -442,7 +445,7 @@ Example
|
|
|
442
445
|
Produce a subset containing the characters ' !"#$%' without performing
|
|
443
446
|
size-reducing optimizations::
|
|
444
447
|
|
|
445
|
-
$
|
|
448
|
+
$ fonttools subset font.ttf --unicodes="U+0020-0025" \\
|
|
446
449
|
--layout-features=* --glyph-names --symbol-cmap --legacy-cmap \\
|
|
447
450
|
--notdef-glyph --notdef-outline --recommended-glyphs \\
|
|
448
451
|
--name-IDs=* --name-legacy --name-languages=*
|
|
@@ -824,13 +827,26 @@ def subset_glyphs(self, s):
|
|
|
824
827
|
self.MarkArray.MarkRecord, mark_indices
|
|
825
828
|
)
|
|
826
829
|
self.MarkArray.MarkCount = len(self.MarkArray.MarkRecord)
|
|
827
|
-
|
|
830
|
+
class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord)
|
|
831
|
+
|
|
832
|
+
intersect_base_indices = self.BaseCoverage.intersect(s.glyphs)
|
|
833
|
+
base_records = self.BaseArray.BaseRecord
|
|
834
|
+
num_base_records = len(base_records)
|
|
835
|
+
base_indices = [
|
|
836
|
+
i
|
|
837
|
+
for i in intersect_base_indices
|
|
838
|
+
if i < num_base_records
|
|
839
|
+
and any(base_records[i].BaseAnchor[j] is not None for j in class_indices)
|
|
840
|
+
]
|
|
841
|
+
if not base_indices:
|
|
842
|
+
return False
|
|
843
|
+
|
|
844
|
+
self.BaseCoverage.remap(base_indices)
|
|
828
845
|
self.BaseArray.BaseRecord = _list_subset(
|
|
829
846
|
self.BaseArray.BaseRecord, base_indices
|
|
830
847
|
)
|
|
831
848
|
self.BaseArray.BaseCount = len(self.BaseArray.BaseRecord)
|
|
832
849
|
# Prune empty classes
|
|
833
|
-
class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord)
|
|
834
850
|
self.ClassCount = len(class_indices)
|
|
835
851
|
for m in self.MarkArray.MarkRecord:
|
|
836
852
|
m.Class = class_indices.index(m.Class)
|
|
@@ -864,13 +880,31 @@ def subset_glyphs(self, s):
|
|
|
864
880
|
self.MarkArray.MarkRecord, mark_indices
|
|
865
881
|
)
|
|
866
882
|
self.MarkArray.MarkCount = len(self.MarkArray.MarkRecord)
|
|
867
|
-
|
|
883
|
+
class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord)
|
|
884
|
+
|
|
885
|
+
intersect_ligature_indices = self.LigatureCoverage.intersect(s.glyphs)
|
|
886
|
+
ligature_array = self.LigatureArray.LigatureAttach
|
|
887
|
+
num_ligatures = self.LigatureArray.LigatureCount
|
|
888
|
+
|
|
889
|
+
ligature_indices = [
|
|
890
|
+
i
|
|
891
|
+
for i in intersect_ligature_indices
|
|
892
|
+
if i < num_ligatures
|
|
893
|
+
and any(
|
|
894
|
+
any(component.LigatureAnchor[j] is not None for j in class_indices)
|
|
895
|
+
for component in ligature_array[i].ComponentRecord
|
|
896
|
+
)
|
|
897
|
+
]
|
|
898
|
+
|
|
899
|
+
if not ligature_indices:
|
|
900
|
+
return False
|
|
901
|
+
|
|
902
|
+
self.LigatureCoverage.remap(ligature_indices)
|
|
868
903
|
self.LigatureArray.LigatureAttach = _list_subset(
|
|
869
904
|
self.LigatureArray.LigatureAttach, ligature_indices
|
|
870
905
|
)
|
|
871
906
|
self.LigatureArray.LigatureCount = len(self.LigatureArray.LigatureAttach)
|
|
872
907
|
# Prune empty classes
|
|
873
|
-
class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord)
|
|
874
908
|
self.ClassCount = len(class_indices)
|
|
875
909
|
for m in self.MarkArray.MarkRecord:
|
|
876
910
|
m.Class = class_indices.index(m.Class)
|
|
@@ -912,13 +946,26 @@ def subset_glyphs(self, s):
|
|
|
912
946
|
self.Mark1Array.MarkRecord, mark1_indices
|
|
913
947
|
)
|
|
914
948
|
self.Mark1Array.MarkCount = len(self.Mark1Array.MarkRecord)
|
|
915
|
-
|
|
949
|
+
class_indices = _uniq_sort(v.Class for v in self.Mark1Array.MarkRecord)
|
|
950
|
+
|
|
951
|
+
intersect_mark2_indices = self.Mark2Coverage.intersect(s.glyphs)
|
|
952
|
+
mark2_records = self.Mark2Array.Mark2Record
|
|
953
|
+
num_mark2_records = len(mark2_records)
|
|
954
|
+
mark2_indices = [
|
|
955
|
+
i
|
|
956
|
+
for i in intersect_mark2_indices
|
|
957
|
+
if i < num_mark2_records
|
|
958
|
+
and any(mark2_records[i].Mark2Anchor[j] is not None for j in class_indices)
|
|
959
|
+
]
|
|
960
|
+
if not mark2_indices:
|
|
961
|
+
return False
|
|
962
|
+
|
|
963
|
+
self.Mark2Coverage.remap(mark2_indices)
|
|
916
964
|
self.Mark2Array.Mark2Record = _list_subset(
|
|
917
965
|
self.Mark2Array.Mark2Record, mark2_indices
|
|
918
966
|
)
|
|
919
967
|
self.Mark2Array.MarkCount = len(self.Mark2Array.Mark2Record)
|
|
920
968
|
# Prune empty classes
|
|
921
|
-
class_indices = _uniq_sort(v.Class for v in self.Mark1Array.MarkRecord)
|
|
922
969
|
self.ClassCount = len(class_indices)
|
|
923
970
|
for m in self.Mark1Array.MarkRecord:
|
|
924
971
|
m.Class = class_indices.index(m.Class)
|
|
@@ -1527,6 +1574,7 @@ def subset_glyphs(self, s):
|
|
|
1527
1574
|
if self.MarkFilteringSet not in s.used_mark_sets:
|
|
1528
1575
|
self.MarkFilteringSet = None
|
|
1529
1576
|
self.LookupFlag &= ~0x10
|
|
1577
|
+
self.LookupFlag |= 0x8
|
|
1530
1578
|
else:
|
|
1531
1579
|
self.MarkFilteringSet = s.used_mark_sets.index(self.MarkFilteringSet)
|
|
1532
1580
|
return bool(self.SubTableCount)
|
|
@@ -1713,6 +1761,19 @@ def subset_features(self, feature_indices):
|
|
|
1713
1761
|
return bool(self.SubstitutionCount)
|
|
1714
1762
|
|
|
1715
1763
|
|
|
1764
|
+
@_add_method(otTables.FeatureTableSubstitution)
|
|
1765
|
+
def prune_features(self, feature_index_map):
|
|
1766
|
+
self.ensureDecompiled()
|
|
1767
|
+
self.SubstitutionRecord = [
|
|
1768
|
+
r for r in self.SubstitutionRecord if r.FeatureIndex in feature_index_map.keys()
|
|
1769
|
+
]
|
|
1770
|
+
# remap feature indices
|
|
1771
|
+
for r in self.SubstitutionRecord:
|
|
1772
|
+
r.FeatureIndex = feature_index_map[r.FeatureIndex]
|
|
1773
|
+
self.SubstitutionCount = len(self.SubstitutionRecord)
|
|
1774
|
+
return bool(self.SubstitutionCount)
|
|
1775
|
+
|
|
1776
|
+
|
|
1716
1777
|
@_add_method(otTables.FeatureVariations)
|
|
1717
1778
|
def subset_features(self, feature_indices):
|
|
1718
1779
|
self.ensureDecompiled()
|
|
@@ -1731,6 +1792,24 @@ def subset_features(self, feature_indices):
|
|
|
1731
1792
|
return bool(self.FeatureVariationCount)
|
|
1732
1793
|
|
|
1733
1794
|
|
|
1795
|
+
@_add_method(otTables.FeatureVariations)
|
|
1796
|
+
def prune_features(self, feature_index_map):
|
|
1797
|
+
self.ensureDecompiled()
|
|
1798
|
+
for r in self.FeatureVariationRecord:
|
|
1799
|
+
r.FeatureTableSubstitution.prune_features(feature_index_map)
|
|
1800
|
+
# Prune empty records at the end only
|
|
1801
|
+
# https://github.com/fonttools/fonttools/issues/1881
|
|
1802
|
+
while (
|
|
1803
|
+
self.FeatureVariationRecord
|
|
1804
|
+
and not self.FeatureVariationRecord[
|
|
1805
|
+
-1
|
|
1806
|
+
].FeatureTableSubstitution.SubstitutionCount
|
|
1807
|
+
):
|
|
1808
|
+
self.FeatureVariationRecord.pop()
|
|
1809
|
+
self.FeatureVariationCount = len(self.FeatureVariationRecord)
|
|
1810
|
+
return bool(self.FeatureVariationCount)
|
|
1811
|
+
|
|
1812
|
+
|
|
1734
1813
|
@_add_method(otTables.DefaultLangSys, otTables.LangSys)
|
|
1735
1814
|
def subset_features(self, feature_indices):
|
|
1736
1815
|
if self.ReqFeatureIndex in feature_indices:
|
|
@@ -1746,6 +1825,16 @@ def subset_features(self, feature_indices):
|
|
|
1746
1825
|
return bool(self.FeatureCount or self.ReqFeatureIndex != 65535)
|
|
1747
1826
|
|
|
1748
1827
|
|
|
1828
|
+
@_add_method(otTables.DefaultLangSys, otTables.LangSys)
|
|
1829
|
+
def prune_features(self, feature_index_map):
|
|
1830
|
+
self.ReqFeatureIndex = feature_index_map.get(self.ReqFeatureIndex, 65535)
|
|
1831
|
+
self.FeatureIndex = [
|
|
1832
|
+
feature_index_map[f] for f in self.FeatureIndex if f in feature_index_map.keys()
|
|
1833
|
+
]
|
|
1834
|
+
self.FeatureCount = len(self.FeatureIndex)
|
|
1835
|
+
return bool(self.FeatureCount or self.ReqFeatureIndex != 65535)
|
|
1836
|
+
|
|
1837
|
+
|
|
1749
1838
|
@_add_method(otTables.DefaultLangSys, otTables.LangSys)
|
|
1750
1839
|
def collect_features(self):
|
|
1751
1840
|
feature_indices = self.FeatureIndex[:]
|
|
@@ -1769,6 +1858,21 @@ def subset_features(self, feature_indices, keepEmptyDefaultLangSys=False):
|
|
|
1769
1858
|
return bool(self.LangSysCount or self.DefaultLangSys)
|
|
1770
1859
|
|
|
1771
1860
|
|
|
1861
|
+
@_add_method(otTables.Script)
|
|
1862
|
+
def prune_features(self, feature_index_map, keepEmptyDefaultLangSys=False):
|
|
1863
|
+
if (
|
|
1864
|
+
self.DefaultLangSys
|
|
1865
|
+
and not self.DefaultLangSys.prune_features(feature_index_map)
|
|
1866
|
+
and not keepEmptyDefaultLangSys
|
|
1867
|
+
):
|
|
1868
|
+
self.DefaultLangSys = None
|
|
1869
|
+
self.LangSysRecord = [
|
|
1870
|
+
l for l in self.LangSysRecord if l.LangSys.prune_features(feature_index_map)
|
|
1871
|
+
]
|
|
1872
|
+
self.LangSysCount = len(self.LangSysRecord)
|
|
1873
|
+
return bool(self.LangSysCount or self.DefaultLangSys)
|
|
1874
|
+
|
|
1875
|
+
|
|
1772
1876
|
@_add_method(otTables.Script)
|
|
1773
1877
|
def collect_features(self):
|
|
1774
1878
|
feature_indices = [l.LangSys.collect_features() for l in self.LangSysRecord]
|
|
@@ -1790,6 +1894,19 @@ def subset_features(self, feature_indices, retain_empty):
|
|
|
1790
1894
|
return bool(self.ScriptCount)
|
|
1791
1895
|
|
|
1792
1896
|
|
|
1897
|
+
@_add_method(otTables.ScriptList)
|
|
1898
|
+
def prune_features(self, feature_index_map, retain_empty):
|
|
1899
|
+
# https://bugzilla.mozilla.org/show_bug.cgi?id=1331737#c32
|
|
1900
|
+
self.ScriptRecord = [
|
|
1901
|
+
s
|
|
1902
|
+
for s in self.ScriptRecord
|
|
1903
|
+
if s.Script.prune_features(feature_index_map, s.ScriptTag == "DFLT")
|
|
1904
|
+
or retain_empty
|
|
1905
|
+
]
|
|
1906
|
+
self.ScriptCount = len(self.ScriptRecord)
|
|
1907
|
+
return bool(self.ScriptCount)
|
|
1908
|
+
|
|
1909
|
+
|
|
1793
1910
|
@_add_method(otTables.ScriptList)
|
|
1794
1911
|
def collect_features(self):
|
|
1795
1912
|
return _uniq_sort(sum((s.Script.collect_features() for s in self.ScriptRecord), []))
|
|
@@ -1977,21 +2094,74 @@ def subset_script_tags(self, tags):
|
|
|
1977
2094
|
|
|
1978
2095
|
@_add_method(ttLib.getTableClass("GSUB"), ttLib.getTableClass("GPOS"))
|
|
1979
2096
|
def prune_features(self):
|
|
1980
|
-
"""Remove unreferenced features
|
|
2097
|
+
"""Remove unreferenced and duplicate features in FeatureList
|
|
2098
|
+
Remove unreferenced features and remap duplicate feature indices in ScriptList and FeatureVariations
|
|
2099
|
+
"""
|
|
1981
2100
|
if self.table.ScriptList:
|
|
1982
2101
|
feature_indices = self.table.ScriptList.collect_features()
|
|
1983
2102
|
else:
|
|
1984
2103
|
feature_indices = []
|
|
2104
|
+
(feature_indices, feature_index_map) = self.remap_duplicate_features(
|
|
2105
|
+
feature_indices
|
|
2106
|
+
)
|
|
2107
|
+
|
|
1985
2108
|
if self.table.FeatureList:
|
|
1986
2109
|
self.table.FeatureList.subset_features(feature_indices)
|
|
1987
2110
|
if getattr(self.table, "FeatureVariations", None):
|
|
1988
|
-
self.table.FeatureVariations.
|
|
2111
|
+
self.table.FeatureVariations.prune_features(feature_index_map)
|
|
1989
2112
|
if self.table.ScriptList:
|
|
1990
|
-
self.table.ScriptList.
|
|
1991
|
-
|
|
2113
|
+
self.table.ScriptList.prune_features(
|
|
2114
|
+
feature_index_map, self.retain_empty_scripts()
|
|
1992
2115
|
)
|
|
1993
2116
|
|
|
1994
2117
|
|
|
2118
|
+
@_add_method(ttLib.getTableClass("GSUB"), ttLib.getTableClass("GPOS"))
|
|
2119
|
+
def remap_duplicate_features(self, feature_indices):
|
|
2120
|
+
"""Return retained feature indices(without duplicates) and remapped feature indices"""
|
|
2121
|
+
features = self.table.FeatureList.FeatureRecord
|
|
2122
|
+
|
|
2123
|
+
unique_features = {}
|
|
2124
|
+
duplicate_features = {}
|
|
2125
|
+
for i in feature_indices:
|
|
2126
|
+
f = features[i]
|
|
2127
|
+
tag = f.FeatureTag
|
|
2128
|
+
|
|
2129
|
+
same_tag_features = unique_features.get(tag)
|
|
2130
|
+
if same_tag_features is None:
|
|
2131
|
+
unique_features[tag] = set([i])
|
|
2132
|
+
duplicate_features[i] = i
|
|
2133
|
+
continue
|
|
2134
|
+
|
|
2135
|
+
found = False
|
|
2136
|
+
for other_i in same_tag_features:
|
|
2137
|
+
if features[other_i] == f:
|
|
2138
|
+
found = True
|
|
2139
|
+
duplicate_features[i] = other_i
|
|
2140
|
+
break
|
|
2141
|
+
|
|
2142
|
+
if not found:
|
|
2143
|
+
same_tag_features.add(i)
|
|
2144
|
+
duplicate_features[i] = i
|
|
2145
|
+
|
|
2146
|
+
## remap retained feature indices
|
|
2147
|
+
feature_map = {}
|
|
2148
|
+
new_idx = 0
|
|
2149
|
+
|
|
2150
|
+
for i in feature_indices:
|
|
2151
|
+
unique_i = duplicate_features.get(i, i)
|
|
2152
|
+
v = feature_map.get(unique_i)
|
|
2153
|
+
if v is None:
|
|
2154
|
+
feature_map[i] = new_idx
|
|
2155
|
+
new_idx += 1
|
|
2156
|
+
else:
|
|
2157
|
+
feature_map[i] = v
|
|
2158
|
+
|
|
2159
|
+
retained_feature_indices = _uniq_sort(
|
|
2160
|
+
sum((list(s) for s in unique_features.values()), [])
|
|
2161
|
+
)
|
|
2162
|
+
return (retained_feature_indices, feature_map)
|
|
2163
|
+
|
|
2164
|
+
|
|
1995
2165
|
@_add_method(ttLib.getTableClass("GSUB"), ttLib.getTableClass("GPOS"))
|
|
1996
2166
|
def prune_pre_subset(self, font, options):
|
|
1997
2167
|
# Drop undesired features
|
|
@@ -2870,6 +3040,15 @@ def prune_post_subset(self, font, options):
|
|
|
2870
3040
|
def closure_glyphs(self, s):
|
|
2871
3041
|
tables = [t for t in self.tables if t.isUnicode()]
|
|
2872
3042
|
|
|
3043
|
+
# Closure unicodes, which for now is pulling in bidi mirrored variants
|
|
3044
|
+
if s.options.bidi_closure:
|
|
3045
|
+
additional_unicodes = set()
|
|
3046
|
+
for u in s.unicodes_requested:
|
|
3047
|
+
mirror_u = mirrored(u)
|
|
3048
|
+
if mirror_u is not None:
|
|
3049
|
+
additional_unicodes.add(mirror_u)
|
|
3050
|
+
s.unicodes_requested.update(additional_unicodes)
|
|
3051
|
+
|
|
2873
3052
|
# Close glyphs
|
|
2874
3053
|
for table in tables:
|
|
2875
3054
|
if table.format == 14:
|
|
@@ -2994,6 +3173,9 @@ def prune_pre_subset(self, font, options):
|
|
|
2994
3173
|
return True
|
|
2995
3174
|
|
|
2996
3175
|
|
|
3176
|
+
NAME_IDS_TO_OBFUSCATE = {1, 2, 3, 4, 6, 16, 17, 18}
|
|
3177
|
+
|
|
3178
|
+
|
|
2997
3179
|
@_add_method(ttLib.getTableClass("name"))
|
|
2998
3180
|
def prune_post_subset(self, font, options):
|
|
2999
3181
|
visitor = NameRecordVisitor()
|
|
@@ -3012,6 +3194,11 @@ def prune_post_subset(self, font, options):
|
|
|
3012
3194
|
self.names = [n for n in self.names if n.langID in options.name_languages]
|
|
3013
3195
|
if options.obfuscate_names:
|
|
3014
3196
|
namerecs = []
|
|
3197
|
+
# Preserve names to be scrambled or dropped elsewhere so that other
|
|
3198
|
+
# parts of the font don't break.
|
|
3199
|
+
needRemapping = visitor.seen.intersection(NAME_IDS_TO_OBFUSCATE)
|
|
3200
|
+
if needRemapping:
|
|
3201
|
+
_remap_select_name_ids(font, needRemapping)
|
|
3015
3202
|
for n in self.names:
|
|
3016
3203
|
if n.nameID in [1, 4]:
|
|
3017
3204
|
n.string = ".\x7f".encode("utf_16_be") if n.isUnicode() else ".\x7f"
|
|
@@ -3026,6 +3213,76 @@ def prune_post_subset(self, font, options):
|
|
|
3026
3213
|
return True # Required table
|
|
3027
3214
|
|
|
3028
3215
|
|
|
3216
|
+
def _remap_select_name_ids(font: ttLib.TTFont, needRemapping: set[int]) -> None:
|
|
3217
|
+
"""Remap a set of IDs so that the originals can be safely scrambled or
|
|
3218
|
+
dropped.
|
|
3219
|
+
|
|
3220
|
+
For each name record whose name id is in the `needRemapping` set, make a copy
|
|
3221
|
+
and allocate a new unused name id in the font-specific range (> 255).
|
|
3222
|
+
|
|
3223
|
+
Finally update references to these in the `fvar` and `STAT` tables.
|
|
3224
|
+
"""
|
|
3225
|
+
|
|
3226
|
+
if "fvar" not in font and "STAT" not in font:
|
|
3227
|
+
return
|
|
3228
|
+
|
|
3229
|
+
name = font["name"]
|
|
3230
|
+
|
|
3231
|
+
# 1. Assign new IDs for names to be preserved.
|
|
3232
|
+
existingIds = {record.nameID for record in name.names}
|
|
3233
|
+
remapping = {}
|
|
3234
|
+
nextId = name._findUnusedNameID() - 1 # Should skip gaps in name IDs.
|
|
3235
|
+
for nameId in needRemapping:
|
|
3236
|
+
nextId += 1 # We should have complete freedom until 32767.
|
|
3237
|
+
assert nextId not in existingIds, "_findUnusedNameID did not skip gaps"
|
|
3238
|
+
if nextId > 32767:
|
|
3239
|
+
raise ValueError("Ran out of name IDs while trying to remap existing ones.")
|
|
3240
|
+
remapping[nameId] = nextId
|
|
3241
|
+
|
|
3242
|
+
# 2. Copy records to use the new ID. We can't rewrite them in place, because
|
|
3243
|
+
# that could make IDs 1 to 6 "disappear" from code that follows. Some
|
|
3244
|
+
# tools that produce EOT fonts expect them to exist, even when they're
|
|
3245
|
+
# scrambled. See https://github.com/fonttools/fonttools/issues/165.
|
|
3246
|
+
copiedRecords = []
|
|
3247
|
+
for record in name.names:
|
|
3248
|
+
if record.nameID not in needRemapping:
|
|
3249
|
+
continue
|
|
3250
|
+
recordCopy = makeName(
|
|
3251
|
+
record.string,
|
|
3252
|
+
remapping[record.nameID],
|
|
3253
|
+
record.platformID,
|
|
3254
|
+
record.platEncID,
|
|
3255
|
+
record.langID,
|
|
3256
|
+
)
|
|
3257
|
+
copiedRecords.append(recordCopy)
|
|
3258
|
+
name.names.extend(copiedRecords)
|
|
3259
|
+
|
|
3260
|
+
# 3. Rewrite the corresponding IDs in other tables. For now, care only about
|
|
3261
|
+
# STAT and fvar. If more tables need to be changed, consider adapting
|
|
3262
|
+
# NameRecordVisitor to rewrite IDs wherever it finds them.
|
|
3263
|
+
fvar = font.get("fvar")
|
|
3264
|
+
if fvar is not None:
|
|
3265
|
+
for axis in fvar.axes:
|
|
3266
|
+
axis.axisNameID = remapping.get(axis.axisNameID, axis.axisNameID)
|
|
3267
|
+
for instance in fvar.instances:
|
|
3268
|
+
nameID = instance.subfamilyNameID
|
|
3269
|
+
instance.subfamilyNameID = remapping.get(nameID, nameID)
|
|
3270
|
+
nameID = instance.postscriptNameID
|
|
3271
|
+
instance.postscriptNameID = remapping.get(nameID, nameID)
|
|
3272
|
+
|
|
3273
|
+
stat = font.get("STAT")
|
|
3274
|
+
if stat is None:
|
|
3275
|
+
return
|
|
3276
|
+
elidedNameID = stat.table.ElidedFallbackNameID
|
|
3277
|
+
stat.table.ElidedFallbackNameID = remapping.get(elidedNameID, elidedNameID)
|
|
3278
|
+
if stat.table.DesignAxisRecord:
|
|
3279
|
+
for axis in stat.table.DesignAxisRecord.Axis:
|
|
3280
|
+
axis.AxisNameID = remapping.get(axis.AxisNameID, axis.AxisNameID)
|
|
3281
|
+
if stat.table.AxisValueArray:
|
|
3282
|
+
for value in stat.table.AxisValueArray.AxisValue:
|
|
3283
|
+
value.ValueNameID = remapping.get(value.ValueNameID, value.ValueNameID)
|
|
3284
|
+
|
|
3285
|
+
|
|
3029
3286
|
@_add_method(ttLib.getTableClass("head"))
|
|
3030
3287
|
def prune_post_subset(self, font, options):
|
|
3031
3288
|
# Force re-compiling head table, to update any recalculated values.
|
|
@@ -3054,7 +3311,6 @@ class Options(object):
|
|
|
3054
3311
|
|
|
3055
3312
|
# spaces in tag names (e.g. "SVG ", "cvt ") are stripped by the argument parser
|
|
3056
3313
|
_drop_tables_default = [
|
|
3057
|
-
"BASE",
|
|
3058
3314
|
"JSTF",
|
|
3059
3315
|
"DSIG",
|
|
3060
3316
|
"EBDT",
|
|
@@ -3066,6 +3322,7 @@ class Options(object):
|
|
|
3066
3322
|
_drop_tables_default += ["Feat", "Glat", "Gloc", "Silf", "Sill"] # Graphite
|
|
3067
3323
|
_no_subset_tables_default = [
|
|
3068
3324
|
"avar",
|
|
3325
|
+
"BASE",
|
|
3069
3326
|
"fvar",
|
|
3070
3327
|
"gasp",
|
|
3071
3328
|
"head",
|
|
@@ -3191,6 +3448,7 @@ class Options(object):
|
|
|
3191
3448
|
self.font_number = -1
|
|
3192
3449
|
self.pretty_svg = False
|
|
3193
3450
|
self.lazy = True
|
|
3451
|
+
self.bidi_closure = True
|
|
3194
3452
|
|
|
3195
3453
|
self.set(**kwargs)
|
|
3196
3454
|
|
|
@@ -3677,7 +3935,7 @@ def parse_glyphs(s):
|
|
|
3677
3935
|
|
|
3678
3936
|
def usage():
|
|
3679
3937
|
print("usage:", __usage__, file=sys.stderr)
|
|
3680
|
-
print("Try
|
|
3938
|
+
print("Try fonttools subset --help for more information.\n", file=sys.stderr)
|
|
3681
3939
|
|
|
3682
3940
|
|
|
3683
3941
|
@timer("make one with everything (TOTAL TIME)")
|
|
@@ -3746,7 +4004,7 @@ def main(args=None):
|
|
|
3746
4004
|
text += g[7:]
|
|
3747
4005
|
continue
|
|
3748
4006
|
if g.startswith("--text-file="):
|
|
3749
|
-
with open(g[12:], encoding="utf-8") as f:
|
|
4007
|
+
with open(g[12:], encoding="utf-8-sig") as f:
|
|
3750
4008
|
text += f.read().replace("\n", "")
|
|
3751
4009
|
continue
|
|
3752
4010
|
if g.startswith("--unicodes="):
|
fontTools/subset/svg.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from functools import
|
|
4
|
+
from functools import cache
|
|
5
5
|
from itertools import chain, count
|
|
6
6
|
from typing import Dict, Iterable, Iterator, List, Optional, Set, Tuple
|
|
7
7
|
|
|
@@ -29,8 +29,7 @@ NAMESPACES = {
|
|
|
29
29
|
XLINK_HREF = f'{{{NAMESPACES["xlink"]}}}href'
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
@lru_cache(maxsize=None)
|
|
32
|
+
@cache
|
|
34
33
|
def xpath(path):
|
|
35
34
|
# compile XPath upfront, caching result to reuse on multiple elements
|
|
36
35
|
return etree.XPath(path, namespaces=NAMESPACES)
|
fontTools/ttLib/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""fontTools.ttLib -- a package for dealing with TrueType fonts."""
|
|
2
2
|
|
|
3
|
+
from fontTools.config import OPTIONS
|
|
3
4
|
from fontTools.misc.loggingTools import deprecateFunction
|
|
4
5
|
import logging
|
|
5
6
|
|
|
@@ -7,6 +8,9 @@ import logging
|
|
|
7
8
|
log = logging.getLogger(__name__)
|
|
8
9
|
|
|
9
10
|
|
|
11
|
+
OPTIMIZE_FONT_SPEED = OPTIONS["fontTools.ttLib:OPTIMIZE_FONT_SPEED"]
|
|
12
|
+
|
|
13
|
+
|
|
10
14
|
class TTLibError(Exception):
|
|
11
15
|
pass
|
|
12
16
|
|
fontTools/ttLib/__main__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import sys
|
|
2
|
-
from fontTools.ttLib import TTLibError, TTLibFileIsCollectionError
|
|
2
|
+
from fontTools.ttLib import OPTIMIZE_FONT_SPEED, TTLibError, TTLibFileIsCollectionError
|
|
3
3
|
from fontTools.ttLib.ttFont import *
|
|
4
4
|
from fontTools.ttLib.ttCollection import TTCollection
|
|
5
5
|
|
|
@@ -51,7 +51,7 @@ def main(args=None):
|
|
|
51
51
|
)
|
|
52
52
|
parser.add_argument("font", metavar="font", nargs="*", help="Font file.")
|
|
53
53
|
parser.add_argument(
|
|
54
|
-
"-t", "--table", metavar="table",
|
|
54
|
+
"-t", "--table", metavar="table", action="append", help="Tables to decompile."
|
|
55
55
|
)
|
|
56
56
|
parser.add_argument(
|
|
57
57
|
"-o", "--output", metavar="FILE", default=None, help="Output file."
|
|
@@ -71,27 +71,66 @@ def main(args=None):
|
|
|
71
71
|
default=None,
|
|
72
72
|
help="Flavor of output font. 'woff' or 'woff2'.",
|
|
73
73
|
)
|
|
74
|
+
parser.add_argument(
|
|
75
|
+
"--no-recalc-timestamp",
|
|
76
|
+
dest="recalcTimestamp",
|
|
77
|
+
action="store_false",
|
|
78
|
+
help="Keep the original font 'modified' timestamp.",
|
|
79
|
+
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"-b",
|
|
82
|
+
dest="recalcBBoxes",
|
|
83
|
+
action="store_false",
|
|
84
|
+
help="Don't recalc glyph bounding boxes: use the values in the original font.",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"--optimize-font-speed",
|
|
88
|
+
action="store_true",
|
|
89
|
+
help=(
|
|
90
|
+
"Enable optimizations that prioritize speed over file size. This "
|
|
91
|
+
"mainly affects how glyf table and gvar / VARC tables are compiled."
|
|
92
|
+
),
|
|
93
|
+
)
|
|
74
94
|
options = parser.parse_args(args)
|
|
75
95
|
|
|
76
96
|
fontNumber = int(options.y) if options.y is not None else None
|
|
77
97
|
outFile = options.output
|
|
78
98
|
lazy = options.lazy
|
|
79
99
|
flavor = options.flavor
|
|
80
|
-
tables = options.table
|
|
100
|
+
tables = options.table
|
|
101
|
+
recalcBBoxes = options.recalcBBoxes
|
|
102
|
+
recalcTimestamp = options.recalcTimestamp
|
|
103
|
+
optimizeFontSpeed = options.optimize_font_speed
|
|
81
104
|
|
|
82
105
|
fonts = []
|
|
83
106
|
for f in options.font:
|
|
84
107
|
try:
|
|
85
|
-
font = TTFont(
|
|
108
|
+
font = TTFont(
|
|
109
|
+
f,
|
|
110
|
+
recalcBBoxes=recalcBBoxes,
|
|
111
|
+
recalcTimestamp=recalcTimestamp,
|
|
112
|
+
fontNumber=fontNumber,
|
|
113
|
+
lazy=lazy,
|
|
114
|
+
)
|
|
115
|
+
if optimizeFontSpeed:
|
|
116
|
+
font.cfg[OPTIMIZE_FONT_SPEED] = optimizeFontSpeed
|
|
86
117
|
fonts.append(font)
|
|
87
118
|
except TTLibFileIsCollectionError:
|
|
88
119
|
collection = TTCollection(f, lazy=lazy)
|
|
89
120
|
fonts.extend(collection.fonts)
|
|
90
121
|
|
|
91
|
-
if
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
122
|
+
if tables is None:
|
|
123
|
+
if lazy is False:
|
|
124
|
+
tables = ["*"]
|
|
125
|
+
elif optimizeFontSpeed:
|
|
126
|
+
tables = {"glyf", "gvar", "VARC"}.intersection(font.keys())
|
|
127
|
+
else:
|
|
128
|
+
tables = []
|
|
129
|
+
for font in fonts:
|
|
130
|
+
if "GlyphOrder" in tables:
|
|
131
|
+
font.getGlyphOrder()
|
|
132
|
+
for table in tables if "*" not in tables else font.keys():
|
|
133
|
+
font[table] # Decompiles
|
|
95
134
|
|
|
96
135
|
if outFile is not None:
|
|
97
136
|
if len(fonts) == 1:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Simplify TrueType glyphs by merging overlapping contours/components.
|
|
2
2
|
|
|
3
3
|
Requires https://github.com/fonttools/skia-pathops
|
|
4
4
|
"""
|
|
@@ -250,9 +250,10 @@ def _remove_cff_overlaps(
|
|
|
250
250
|
glyphSet: _TTGlyphMapping,
|
|
251
251
|
removeHinting: bool,
|
|
252
252
|
ignoreErrors: bool,
|
|
253
|
+
table_tag: str,
|
|
253
254
|
removeUnusedSubroutines: bool = True,
|
|
254
255
|
) -> None:
|
|
255
|
-
cffFontSet = font[
|
|
256
|
+
cffFontSet = font[table_tag].cff
|
|
256
257
|
modified = set()
|
|
257
258
|
for glyphName in glyphNames:
|
|
258
259
|
try:
|
|
@@ -311,9 +312,9 @@ def removeOverlaps(
|
|
|
311
312
|
any glyphs are modified.
|
|
312
313
|
"""
|
|
313
314
|
|
|
314
|
-
if "glyf" not in font and "CFF " not in font:
|
|
315
|
+
if "glyf" not in font and "CFF " not in font and "CFF2" not in font:
|
|
315
316
|
raise NotImplementedError(
|
|
316
|
-
"No outline data found in the font: missing 'glyf'
|
|
317
|
+
"No outline data found in the font: missing 'glyf', 'CFF ', or 'CFF2' table"
|
|
317
318
|
)
|
|
318
319
|
|
|
319
320
|
if glyphNames is None:
|
|
@@ -331,13 +332,14 @@ def removeOverlaps(
|
|
|
331
332
|
ignoreErrors=ignoreErrors,
|
|
332
333
|
)
|
|
333
334
|
|
|
334
|
-
if "CFF " in font:
|
|
335
|
+
if "CFF " in font or "CFF2" in font:
|
|
335
336
|
_remove_cff_overlaps(
|
|
336
337
|
font=font,
|
|
337
338
|
glyphNames=glyphNames,
|
|
338
339
|
glyphSet=glyphSet,
|
|
339
340
|
removeHinting=removeHinting,
|
|
340
341
|
ignoreErrors=ignoreErrors,
|
|
342
|
+
table_tag="CFF " if "CFF " in font else "CFF2",
|
|
341
343
|
removeUnusedSubroutines=removeUnusedSubroutines,
|
|
342
344
|
)
|
|
343
345
|
|