fonttools 4.60.0__cp313-cp313-win_amd64.whl → 4.60.1__cp313-cp313-win_amd64.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.
Potentially problematic release.
This version of fonttools might be problematic. Click here for more details.
- fontTools/__init__.py +1 -1
- fontTools/cu2qu/cu2qu.cp313-win_amd64.pyd +0 -0
- fontTools/feaLib/lexer.cp313-win_amd64.pyd +0 -0
- fontTools/misc/bezierTools.cp313-win_amd64.pyd +0 -0
- fontTools/misc/visitor.py +24 -16
- fontTools/pens/momentsPen.cp313-win_amd64.pyd +0 -0
- fontTools/qu2cu/qu2cu.cp313-win_amd64.pyd +0 -0
- fontTools/subset/__init__.py +178 -12
- fontTools/ufoLib/__init__.py +2 -2
- fontTools/varLib/iup.cp313-win_amd64.pyd +0 -0
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/METADATA +13 -1
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/RECORD +18 -18
- {fonttools-4.60.0.data → fonttools-4.60.1.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/WHEEL +0 -0
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/entry_points.txt +0 -0
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/licenses/LICENSE +0 -0
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/licenses/LICENSE.external +0 -0
- {fonttools-4.60.0.dist-info → fonttools-4.60.1.dist-info}/top_level.txt +0 -0
fontTools/__init__.py
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
fontTools/misc/visitor.py
CHANGED
|
@@ -79,12 +79,15 @@ class Visitor(object):
|
|
|
79
79
|
def visitObject(self, obj, *args, **kwargs):
|
|
80
80
|
"""Called to visit an object. This function loops over all non-private
|
|
81
81
|
attributes of the objects and calls any user-registered (via
|
|
82
|
-
|
|
82
|
+
``@register_attr()`` or ``@register_attrs()``) ``visit()`` functions.
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
The visitor will proceed to call ``self.visitAttr()``, unless there is a
|
|
85
|
+
user-registered visit function and:
|
|
86
|
+
|
|
87
|
+
* It returns ``False``; or
|
|
88
|
+
* It returns ``None`` (or doesn't return anything) and
|
|
89
|
+
``visitor.defaultStop`` is ``True`` (non-default).
|
|
90
|
+
"""
|
|
88
91
|
|
|
89
92
|
keys = sorted(vars(obj).keys())
|
|
90
93
|
_visitors = self._visitorsFor(obj)
|
|
@@ -121,19 +124,24 @@ class Visitor(object):
|
|
|
121
124
|
|
|
122
125
|
def visit(self, obj, *args, **kwargs):
|
|
123
126
|
"""This is the main entry to the visitor. The visitor will visit object
|
|
124
|
-
obj
|
|
127
|
+
``obj``.
|
|
125
128
|
|
|
126
129
|
The visitor will first determine if there is a registered (via
|
|
127
|
-
|
|
128
|
-
will be called, and (visitor, obj, *args, **kwargs) will be passed
|
|
129
|
-
the user visit function.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
``@register()``) visit function for the type of object. If there is, it
|
|
131
|
+
will be called, and ``(visitor, obj, *args, **kwargs)`` will be passed
|
|
132
|
+
to the user visit function.
|
|
133
|
+
|
|
134
|
+
The visitor will not recurse if there is a user-registered visit
|
|
135
|
+
function and:
|
|
136
|
+
|
|
137
|
+
* It returns ``False``; or
|
|
138
|
+
* It returns ``None`` (or doesn't return anything) and
|
|
139
|
+
``visitor.defaultStop`` is ``True`` (non-default)
|
|
140
|
+
|
|
141
|
+
Otherwise, the visitor will proceed to dispatch to one of
|
|
142
|
+
``self.visitObject()``, ``self.visitList()``, ``self.visitDict()``, or
|
|
143
|
+
``self.visitLeaf()`` (any of which can be overriden in a subclass).
|
|
144
|
+
"""
|
|
137
145
|
|
|
138
146
|
visitorFunc = self._visitorsFor(obj).get(None, None)
|
|
139
147
|
if visitorFunc is not None:
|
|
Binary file
|
|
Binary file
|
fontTools/subset/__init__.py
CHANGED
|
@@ -272,7 +272,7 @@ Font table options
|
|
|
272
272
|
Specify (=), add to (+=) or exclude from (-=) the comma-separated
|
|
273
273
|
set of tables that will be be dropped.
|
|
274
274
|
By default, the following tables are dropped:
|
|
275
|
-
'
|
|
275
|
+
'JSTF', 'DSIG', 'EBDT', 'EBLC', 'EBSC', 'PCLT', 'LTSH'
|
|
276
276
|
and Graphite tables: 'Feat', 'Glat', 'Gloc', 'Silf', 'Sill'.
|
|
277
277
|
The tool will attempt to subset the remaining tables.
|
|
278
278
|
|
|
@@ -827,13 +827,26 @@ def subset_glyphs(self, s):
|
|
|
827
827
|
self.MarkArray.MarkRecord, mark_indices
|
|
828
828
|
)
|
|
829
829
|
self.MarkArray.MarkCount = len(self.MarkArray.MarkRecord)
|
|
830
|
-
|
|
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)
|
|
831
845
|
self.BaseArray.BaseRecord = _list_subset(
|
|
832
846
|
self.BaseArray.BaseRecord, base_indices
|
|
833
847
|
)
|
|
834
848
|
self.BaseArray.BaseCount = len(self.BaseArray.BaseRecord)
|
|
835
849
|
# Prune empty classes
|
|
836
|
-
class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord)
|
|
837
850
|
self.ClassCount = len(class_indices)
|
|
838
851
|
for m in self.MarkArray.MarkRecord:
|
|
839
852
|
m.Class = class_indices.index(m.Class)
|
|
@@ -867,13 +880,31 @@ def subset_glyphs(self, s):
|
|
|
867
880
|
self.MarkArray.MarkRecord, mark_indices
|
|
868
881
|
)
|
|
869
882
|
self.MarkArray.MarkCount = len(self.MarkArray.MarkRecord)
|
|
870
|
-
|
|
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)
|
|
871
903
|
self.LigatureArray.LigatureAttach = _list_subset(
|
|
872
904
|
self.LigatureArray.LigatureAttach, ligature_indices
|
|
873
905
|
)
|
|
874
906
|
self.LigatureArray.LigatureCount = len(self.LigatureArray.LigatureAttach)
|
|
875
907
|
# Prune empty classes
|
|
876
|
-
class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord)
|
|
877
908
|
self.ClassCount = len(class_indices)
|
|
878
909
|
for m in self.MarkArray.MarkRecord:
|
|
879
910
|
m.Class = class_indices.index(m.Class)
|
|
@@ -915,13 +946,26 @@ def subset_glyphs(self, s):
|
|
|
915
946
|
self.Mark1Array.MarkRecord, mark1_indices
|
|
916
947
|
)
|
|
917
948
|
self.Mark1Array.MarkCount = len(self.Mark1Array.MarkRecord)
|
|
918
|
-
|
|
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)
|
|
919
964
|
self.Mark2Array.Mark2Record = _list_subset(
|
|
920
965
|
self.Mark2Array.Mark2Record, mark2_indices
|
|
921
966
|
)
|
|
922
967
|
self.Mark2Array.MarkCount = len(self.Mark2Array.Mark2Record)
|
|
923
968
|
# Prune empty classes
|
|
924
|
-
class_indices = _uniq_sort(v.Class for v in self.Mark1Array.MarkRecord)
|
|
925
969
|
self.ClassCount = len(class_indices)
|
|
926
970
|
for m in self.Mark1Array.MarkRecord:
|
|
927
971
|
m.Class = class_indices.index(m.Class)
|
|
@@ -1717,6 +1761,19 @@ def subset_features(self, feature_indices):
|
|
|
1717
1761
|
return bool(self.SubstitutionCount)
|
|
1718
1762
|
|
|
1719
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
|
+
|
|
1720
1777
|
@_add_method(otTables.FeatureVariations)
|
|
1721
1778
|
def subset_features(self, feature_indices):
|
|
1722
1779
|
self.ensureDecompiled()
|
|
@@ -1735,6 +1792,24 @@ def subset_features(self, feature_indices):
|
|
|
1735
1792
|
return bool(self.FeatureVariationCount)
|
|
1736
1793
|
|
|
1737
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
|
+
|
|
1738
1813
|
@_add_method(otTables.DefaultLangSys, otTables.LangSys)
|
|
1739
1814
|
def subset_features(self, feature_indices):
|
|
1740
1815
|
if self.ReqFeatureIndex in feature_indices:
|
|
@@ -1750,6 +1825,16 @@ def subset_features(self, feature_indices):
|
|
|
1750
1825
|
return bool(self.FeatureCount or self.ReqFeatureIndex != 65535)
|
|
1751
1826
|
|
|
1752
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
|
+
|
|
1753
1838
|
@_add_method(otTables.DefaultLangSys, otTables.LangSys)
|
|
1754
1839
|
def collect_features(self):
|
|
1755
1840
|
feature_indices = self.FeatureIndex[:]
|
|
@@ -1773,6 +1858,21 @@ def subset_features(self, feature_indices, keepEmptyDefaultLangSys=False):
|
|
|
1773
1858
|
return bool(self.LangSysCount or self.DefaultLangSys)
|
|
1774
1859
|
|
|
1775
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
|
+
|
|
1776
1876
|
@_add_method(otTables.Script)
|
|
1777
1877
|
def collect_features(self):
|
|
1778
1878
|
feature_indices = [l.LangSys.collect_features() for l in self.LangSysRecord]
|
|
@@ -1794,6 +1894,19 @@ def subset_features(self, feature_indices, retain_empty):
|
|
|
1794
1894
|
return bool(self.ScriptCount)
|
|
1795
1895
|
|
|
1796
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
|
+
|
|
1797
1910
|
@_add_method(otTables.ScriptList)
|
|
1798
1911
|
def collect_features(self):
|
|
1799
1912
|
return _uniq_sort(sum((s.Script.collect_features() for s in self.ScriptRecord), []))
|
|
@@ -1981,21 +2094,74 @@ def subset_script_tags(self, tags):
|
|
|
1981
2094
|
|
|
1982
2095
|
@_add_method(ttLib.getTableClass("GSUB"), ttLib.getTableClass("GPOS"))
|
|
1983
2096
|
def prune_features(self):
|
|
1984
|
-
"""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
|
+
"""
|
|
1985
2100
|
if self.table.ScriptList:
|
|
1986
2101
|
feature_indices = self.table.ScriptList.collect_features()
|
|
1987
2102
|
else:
|
|
1988
2103
|
feature_indices = []
|
|
2104
|
+
(feature_indices, feature_index_map) = self.remap_duplicate_features(
|
|
2105
|
+
feature_indices
|
|
2106
|
+
)
|
|
2107
|
+
|
|
1989
2108
|
if self.table.FeatureList:
|
|
1990
2109
|
self.table.FeatureList.subset_features(feature_indices)
|
|
1991
2110
|
if getattr(self.table, "FeatureVariations", None):
|
|
1992
|
-
self.table.FeatureVariations.
|
|
2111
|
+
self.table.FeatureVariations.prune_features(feature_index_map)
|
|
1993
2112
|
if self.table.ScriptList:
|
|
1994
|
-
self.table.ScriptList.
|
|
1995
|
-
|
|
2113
|
+
self.table.ScriptList.prune_features(
|
|
2114
|
+
feature_index_map, self.retain_empty_scripts()
|
|
1996
2115
|
)
|
|
1997
2116
|
|
|
1998
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
|
+
|
|
1999
2165
|
@_add_method(ttLib.getTableClass("GSUB"), ttLib.getTableClass("GPOS"))
|
|
2000
2166
|
def prune_pre_subset(self, font, options):
|
|
2001
2167
|
# Drop undesired features
|
|
@@ -3145,7 +3311,6 @@ class Options(object):
|
|
|
3145
3311
|
|
|
3146
3312
|
# spaces in tag names (e.g. "SVG ", "cvt ") are stripped by the argument parser
|
|
3147
3313
|
_drop_tables_default = [
|
|
3148
|
-
"BASE",
|
|
3149
3314
|
"JSTF",
|
|
3150
3315
|
"DSIG",
|
|
3151
3316
|
"EBDT",
|
|
@@ -3157,6 +3322,7 @@ class Options(object):
|
|
|
3157
3322
|
_drop_tables_default += ["Feat", "Glat", "Gloc", "Silf", "Sill"] # Graphite
|
|
3158
3323
|
_no_subset_tables_default = [
|
|
3159
3324
|
"avar",
|
|
3325
|
+
"BASE",
|
|
3160
3326
|
"fvar",
|
|
3161
3327
|
"gasp",
|
|
3162
3328
|
"head",
|
fontTools/ufoLib/__init__.py
CHANGED
|
@@ -534,7 +534,7 @@ class UFOReader(_UFOBaseIO):
|
|
|
534
534
|
raise UFOLibError(message)
|
|
535
535
|
return groups
|
|
536
536
|
|
|
537
|
-
def
|
|
537
|
+
def getKerningGroupConversionRenameMaps(
|
|
538
538
|
self, validate: Optional[bool] = None
|
|
539
539
|
) -> KerningGroupRenameMaps:
|
|
540
540
|
"""
|
|
@@ -1263,7 +1263,7 @@ class UFOWriter(UFOReader):
|
|
|
1263
1263
|
}
|
|
1264
1264
|
|
|
1265
1265
|
This is the same form returned by UFOReader's
|
|
1266
|
-
|
|
1266
|
+
getKerningGroupConversionRenameMaps method.
|
|
1267
1267
|
"""
|
|
1268
1268
|
if self._formatVersion >= UFOFormatVersion.FORMAT_3_0:
|
|
1269
1269
|
return # XXX raise an error here
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fonttools
|
|
3
|
-
Version: 4.60.
|
|
3
|
+
Version: 4.60.1
|
|
4
4
|
Summary: Tools to manipulate font files
|
|
5
5
|
Home-page: http://github.com/fonttools/fonttools
|
|
6
6
|
Author: Just van Rossum
|
|
@@ -392,6 +392,18 @@ Have fun!
|
|
|
392
392
|
Changelog
|
|
393
393
|
~~~~~~~~~
|
|
394
394
|
|
|
395
|
+
4.60.1 (released 2025-09-29)
|
|
396
|
+
----------------------------
|
|
397
|
+
|
|
398
|
+
- [ufoLib] Reverted accidental method name change in ``UFOReader.getKerningGroupConversionRenameMaps``
|
|
399
|
+
that broke compatibility with downstream projects like defcon (#3948, #3947, robotools/defcon#478).
|
|
400
|
+
- [ufoLib] Added test coverage for ``getKerningGroupConversionRenameMaps`` method (#3950).
|
|
401
|
+
- [subset] Don't try to subset BASE table; pass it through by default instead (#3949).
|
|
402
|
+
- [subset] Remove empty BaseRecord entries in MarkBasePos lookups (#3897, #3892).
|
|
403
|
+
- [subset] Add pruning for MarkLigPos and MarkMarkPos lookups (#3946).
|
|
404
|
+
- [subset] Remove duplicate features when subsetting (#3945).
|
|
405
|
+
- [Docs] Added documentation for the visitor module (#3944).
|
|
406
|
+
|
|
395
407
|
4.60.0 (released 2025-09-17)
|
|
396
408
|
----------------------------
|
|
397
409
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
fontTools/__init__.py,sha256
|
|
1
|
+
fontTools/__init__.py,sha256=Kx6CqtCPpUeyrf7vwLVhBcoe7feUBG34YBh7HlfUk2Q,191
|
|
2
2
|
fontTools/__main__.py,sha256=T8Tg8xPKHOCVoYVG82p_zpQXfW7_ERRAphBkZVvhWN8,960
|
|
3
3
|
fontTools/afmLib.py,sha256=YbmmjT8Du6qFUhFHwnAhOdvsyfXszODVjSJtd18CCjY,13603
|
|
4
4
|
fontTools/agl.py,sha256=4aKwnbvSVUa39eV5Ka8e5ULwV-IEp4pcfwlMwEH_z3k,118208
|
|
@@ -26,7 +26,7 @@ fontTools/cu2qu/__main__.py,sha256=6Vb8Ler3yqJ5w84UwlMJV6cS01uhV4PN10OlXQ6jlqo,9
|
|
|
26
26
|
fontTools/cu2qu/benchmark.py,sha256=FwdvNjKfWHo18_CX0CO8AY5c68XSBE4M4TJo_EkB4q8,1350
|
|
27
27
|
fontTools/cu2qu/cli.py,sha256=CvWzC5a6XF_v5o0yrS4vGI1JXiVVLzSJahTIqpJmiPk,6274
|
|
28
28
|
fontTools/cu2qu/cu2qu.c,sha256=2FsHl-S3Z_szu4zNH2Hv9ouU4Kg7jlK_GFax_U57xeU,653740
|
|
29
|
-
fontTools/cu2qu/cu2qu.cp313-win_amd64.pyd,sha256=
|
|
29
|
+
fontTools/cu2qu/cu2qu.cp313-win_amd64.pyd,sha256=KY0o6KmWgK-TDMxKG2kI9aBS_UQyJJW0Wp-rZhJrpoQ,101888
|
|
30
30
|
fontTools/cu2qu/cu2qu.py,sha256=nyniLf18Y6D7CBjp6NXZj2XOpYdaiiZVFprZLiFTwtc,18549
|
|
31
31
|
fontTools/cu2qu/errors.py,sha256=uYyPSs_x-EMJKO2S3cLGWyk_KlHoOoh_XEtdB_oKBp0,2518
|
|
32
32
|
fontTools/cu2qu/ufo.py,sha256=Mpd_7Be9jxNcOKFqkyRp8Oem3CS3R-ZYMMSD03LJL6o,12143
|
|
@@ -45,7 +45,7 @@ fontTools/feaLib/ast.py,sha256=q-UvEPZ97AAHpggVOzVHdgfTcE072kuOK08rdAYpCXU,76301
|
|
|
45
45
|
fontTools/feaLib/builder.py,sha256=_ofuSJ9Jtz1Ybzk4ReCWSa431PXfIq-UcVkYZ2B0Ruo,75565
|
|
46
46
|
fontTools/feaLib/error.py,sha256=pqi8F2tnH2h7pXVffxwzuBuWaSHMzZsXs5VckdQKQAI,670
|
|
47
47
|
fontTools/feaLib/lexer.c,sha256=y9M2Lf0jZy0tYvxpZBWoPs5DZPOVIoZSzmD5Ab5jjRM,771641
|
|
48
|
-
fontTools/feaLib/lexer.cp313-win_amd64.pyd,sha256=
|
|
48
|
+
fontTools/feaLib/lexer.cp313-win_amd64.pyd,sha256=s577TMbQsiavKtqAgwia5sH63yNHeVmOBZ_0TWbPeMY,117760
|
|
49
49
|
fontTools/feaLib/lexer.py,sha256=7VZ3NPFH7V1mvRbym111BNKvbB4hLfGLTMS0VV_3Ipw,11408
|
|
50
50
|
fontTools/feaLib/location.py,sha256=teHrhjT8zzImcGBEJS1J43oaX9onCPu_pynxS8d-tUg,246
|
|
51
51
|
fontTools/feaLib/lookupDebugInfo.py,sha256=h4Ig8kmEk5WlGf1C9JJAbbOKQK5OwkFLdj8CT7fOkmU,316
|
|
@@ -63,7 +63,7 @@ fontTools/merge/util.py,sha256=3alo4b7mhFNC6h8PjeqNU99dS7EuO8sdZkZpvRsEE6E,3521
|
|
|
63
63
|
fontTools/misc/__init__.py,sha256=QoK6HlOoqtVqX5gOyv0bJiTXsVBbBRreUifdccWNp2k,76
|
|
64
64
|
fontTools/misc/arrayTools.py,sha256=baENNALPvYRUhS4rdx_F3ltOmVIf1PV9G2EaMt7gAHM,11907
|
|
65
65
|
fontTools/misc/bezierTools.c,sha256=wub0OhTy2OMmdZ6ppQxP1YTKNzEskK_i6lNfRiVNW9M,1861888
|
|
66
|
-
fontTools/misc/bezierTools.cp313-win_amd64.pyd,sha256=
|
|
66
|
+
fontTools/misc/bezierTools.cp313-win_amd64.pyd,sha256=XlSGbh-QnyfYV57a7-nTPTMVfpjYXX19DKBhZJbM0qc,338432
|
|
67
67
|
fontTools/misc/bezierTools.py,sha256=m4j14ckKYtrKy8NhFFFY_Uv3kuL8g-SWNdEKUzqGjRQ,46535
|
|
68
68
|
fontTools/misc/classifyTools.py,sha256=wLTjOhLiZaLiwwUTj2Ad5eZ5T_38W0Eo_uzRGWHWYvE,5783
|
|
69
69
|
fontTools/misc/cliTools.py,sha256=7zKOXczaCKRMW6Yv5jdCZYHco8y0-lfimhIWzQ2IL8A,1915
|
|
@@ -95,7 +95,7 @@ fontTools/misc/timeTools.py,sha256=lmncKUKvxQKO4Kqx2k7UNFkYYpj2n5CwR1lPiLZv3tA,2
|
|
|
95
95
|
fontTools/misc/transform.py,sha256=pCR0tbKzmhH6crB_rDT5hnAWySztW_XqL0efmKOVsCU,16314
|
|
96
96
|
fontTools/misc/treeTools.py,sha256=IMopMUcuhelvz8gNra50Zc1w8DSlWywnL6DFaz1ijQs,1314
|
|
97
97
|
fontTools/misc/vector.py,sha256=yaNixq5pXXpPCD_wRP-LsXYSLr4WPX_y92Po05FeLU0,4209
|
|
98
|
-
fontTools/misc/visitor.py,sha256=
|
|
98
|
+
fontTools/misc/visitor.py,sha256=jZ2I2yTiao67kUL2GPLx1Rpuw-X2gIx0ikqZOkcfYf8,5912
|
|
99
99
|
fontTools/misc/xmlReader.py,sha256=gqYg3qlDkrKsO55DPaJ-dU0i5rltqZgnKlrXmR2Z7dQ,6768
|
|
100
100
|
fontTools/misc/xmlWriter.py,sha256=rGn6BDiB2MPrhoNabDbY4vAHZC6-mEciwCJXtOL6hMA,7060
|
|
101
101
|
fontTools/misc/filesystem/__init__.py,sha256=wAfcTDA9TBfzZpEN-jnlhNgJ-7tsvsEpbEb3TP9B8Vs,2079
|
|
@@ -133,7 +133,7 @@ fontTools/pens/filterPen.py,sha256=wvNVXLGKmNxJcpAKAnmev2wy6Rshq6aXgRfxL0Iobdg,1
|
|
|
133
133
|
fontTools/pens/freetypePen.py,sha256=NqNzXrOTDckoH4N6WLnj-KuxGcg6z7DlqSCfmpq8qAE,20370
|
|
134
134
|
fontTools/pens/hashPointPen.py,sha256=ZAU87uw5ge3Kb4i9kRV28a5VFeZ_TWSsJabyAzwAHrU,3662
|
|
135
135
|
fontTools/pens/momentsPen.c,sha256=tccF2oegGdXqHhmkR_ReOr-SveDxltMm67E3XryuVbI,578781
|
|
136
|
-
fontTools/pens/momentsPen.cp313-win_amd64.pyd,sha256=
|
|
136
|
+
fontTools/pens/momentsPen.cp313-win_amd64.pyd,sha256=SBKbt9WYiXn8OM9OhrM6kpDdDxOjZpBHbGTz4ysVa2w,89088
|
|
137
137
|
fontTools/pens/momentsPen.py,sha256=Z-V5CjQBSj3qPxg3C_DBFKExqno89nOe3jWwHT9_xsM,26537
|
|
138
138
|
fontTools/pens/perimeterPen.py,sha256=Zy5F8QzaNJAkkQQSb2QJCp-wZTvDAjBn-B099t2ABds,2222
|
|
139
139
|
fontTools/pens/pointInsidePen.py,sha256=Hy48iR5NWV3x_wWoos-UC7GMtwvvUhd_q_ykiwaWdzQ,6547
|
|
@@ -157,9 +157,9 @@ fontTools/qu2cu/__main__.py,sha256=leKpToUNNyHf0nobr1I19vus2ziA1pO7rRKkreat-Xw,1
|
|
|
157
157
|
fontTools/qu2cu/benchmark.py,sha256=PFxx2Bfu7-KuNrzdOIBXHPZvyNphqqcTVy4CneaCo3M,1456
|
|
158
158
|
fontTools/qu2cu/cli.py,sha256=1QLBTSZW7e_VATJN9vjszRxIk_-Xjxu1KP53yX4T7q8,3839
|
|
159
159
|
fontTools/qu2cu/qu2cu.c,sha256=zpMJuiGamoWxvBEqP84gp1DPDsSlvbqMxf0gkxgA0u8,707187
|
|
160
|
-
fontTools/qu2cu/qu2cu.cp313-win_amd64.pyd,sha256=
|
|
160
|
+
fontTools/qu2cu/qu2cu.cp313-win_amd64.pyd,sha256=tHbW4pe6NKbxH4ep9X10bt12A_oWF15qzgS647Wd5DY,107008
|
|
161
161
|
fontTools/qu2cu/qu2cu.py,sha256=dtp5Zqhcs_NePwA2U5fgG2LtWleRwmBilTurau8sLL0,12693
|
|
162
|
-
fontTools/subset/__init__.py,sha256=
|
|
162
|
+
fontTools/subset/__init__.py,sha256=ALzTEOHbFPSwQB7T6ro7vopxv-rud6d3oo-9KqPe9z0,147359
|
|
163
163
|
fontTools/subset/__main__.py,sha256=cEIC52EtGOJvFDfHXzi0M2EAYmyHAcI-ZZ0lb2y4r7s,101
|
|
164
164
|
fontTools/subset/cff.py,sha256=GSmxdsokxuFKvJJQVcAIOhd5hYQq8KkzxnXE_dgm8yo,6329
|
|
165
165
|
fontTools/subset/svg.py,sha256=y_yTZuAm3bjcoEOFu5likXoHuG5u1oNiv0mOni2Z9fQ,9637
|
|
@@ -283,7 +283,7 @@ fontTools/ttLib/tables/sbixGlyph.py,sha256=a-mCmO5EibN_He7QQohG06Qg-fCOHWiNFMAbC
|
|
|
283
283
|
fontTools/ttLib/tables/sbixStrike.py,sha256=Q1F4rFlj-SwUKFDJkcta1oz_b393dt9VYFOyxaFSc_o,6828
|
|
284
284
|
fontTools/ttLib/tables/table_API_readme.txt,sha256=E9lwGW1P_dGqy1FYBcYLVEDDmikbsqW4pUtpv1RKCJU,2839
|
|
285
285
|
fontTools/ttLib/tables/ttProgram.py,sha256=vkRtptH7QXD0Ng8LNzh-A_Ln27VPCxSJOXgW8878nSo,36482
|
|
286
|
-
fontTools/ufoLib/__init__.py,sha256=
|
|
286
|
+
fontTools/ufoLib/__init__.py,sha256=SNoNeSIgQMccB0jZSnlCEPQ4nRF2aSVC8fSSlJZ0K4c,101556
|
|
287
287
|
fontTools/ufoLib/converters.py,sha256=7B5JwsY2GrtgEcPirkkYnsWGvQpbntQRaERFH1LiG7c,13851
|
|
288
288
|
fontTools/ufoLib/errors.py,sha256=pgJKS2A5RcsfQS2Z6Y_l3mIz62-VD_SrpIysKmywuYA,875
|
|
289
289
|
fontTools/ufoLib/etree.py,sha256=kTUP1EzN2wSXZ4jwAX8waNfKz52u7jc2qQ2LrqPYLBw,237
|
|
@@ -315,7 +315,7 @@ fontTools/varLib/interpolatableTestContourOrder.py,sha256=Pbt0jW0LoVggIwrtADZ7HW
|
|
|
315
315
|
fontTools/varLib/interpolatableTestStartingPoint.py,sha256=f5MJ3mj8MctJCvDJwqmW1fIVOgovUMYAOela9HweaRU,4403
|
|
316
316
|
fontTools/varLib/interpolate_layout.py,sha256=tTPUes_K7MwooUO_wac9AeFEVgL1uGSz4ITYiOizaME,3813
|
|
317
317
|
fontTools/varLib/iup.c,sha256=ah8enmoMLi_AO2jjHrcRou4Wip4X8Y-0ik8_N-KNGmw,847577
|
|
318
|
-
fontTools/varLib/iup.cp313-win_amd64.pyd,sha256=
|
|
318
|
+
fontTools/varLib/iup.cp313-win_amd64.pyd,sha256=eHi0To4eOOklHgYew47e3wpChVlveH01zWQ_FDeQ_TA,130048
|
|
319
319
|
fontTools/varLib/iup.py,sha256=O_xPJOBECrNDbQqCC3e5xf9KsWXUd1i3BAp9Fl6Hv2Y,15474
|
|
320
320
|
fontTools/varLib/merger.py,sha256=V-B17poOYbbrRsfUYJbdqt46GtRfG833MKwtv9NOB3Q,62519
|
|
321
321
|
fontTools/varLib/models.py,sha256=ZqQb1Lapj5dCO8dwa3UTx1LsIpF0-GiDte32t_TMJJQ,23040
|
|
@@ -343,11 +343,11 @@ fontTools/voltLib/error.py,sha256=3TsaZBA82acFd2j5Beq3WUQTURTKM0zxOnUFGZovSNA,40
|
|
|
343
343
|
fontTools/voltLib/lexer.py,sha256=v9V4zdBO2VqVJG__IWrL8fv_CRURmh2eD_1UpbIJn9g,3467
|
|
344
344
|
fontTools/voltLib/parser.py,sha256=HS72gxtFzvcPSwEbUYj3E41CPK7ZqK9mSe0nLRxn-IY,26060
|
|
345
345
|
fontTools/voltLib/voltToFea.py,sha256=nS-OSlx_a-TngGICFNKyFxMhjqkV3OQLcvyzw4sQFyk,37460
|
|
346
|
-
fonttools-4.60.
|
|
347
|
-
fonttools-4.60.
|
|
348
|
-
fonttools-4.60.
|
|
349
|
-
fonttools-4.60.
|
|
350
|
-
fonttools-4.60.
|
|
351
|
-
fonttools-4.60.
|
|
352
|
-
fonttools-4.60.
|
|
353
|
-
fonttools-4.60.
|
|
346
|
+
fonttools-4.60.1.data/data/share/man/man1/ttx.1,sha256=E71F9mRNWlttVpzlnP7w_fqkQygPkph5s-AtVa0Js50,5601
|
|
347
|
+
fonttools-4.60.1.dist-info/licenses/LICENSE,sha256=Ir74Bpfs-qF_l-YrmibfoSggvgVYPo3RKtFpskEnTJk,1093
|
|
348
|
+
fonttools-4.60.1.dist-info/licenses/LICENSE.external,sha256=sIKl-Gd1smQfAbzLi5yCkISB3l9QK7JUseE7_CqfMD0,20410
|
|
349
|
+
fonttools-4.60.1.dist-info/METADATA,sha256=jvqLM8U0BGUXOJ7jWp22ISqXYUaqovRTQppZhgkPJdE,114562
|
|
350
|
+
fonttools-4.60.1.dist-info/WHEEL,sha256=qV0EIPljj1XC_vuSatRWjn02nZIz3N1t8jsZz7HBr2U,101
|
|
351
|
+
fonttools-4.60.1.dist-info/entry_points.txt,sha256=8kVHddxfFWA44FSD4mBpmC-4uCynQnkoz_9aNJb227Y,147
|
|
352
|
+
fonttools-4.60.1.dist-info/top_level.txt,sha256=rRgRylrXzekqWOsrhygzib12pQ7WILf7UGjqEwkIFDM,10
|
|
353
|
+
fonttools-4.60.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|