fonttools 4.57.0__cp313-cp313-macosx_10_13_universal2.whl → 4.58.1__cp313-cp313-macosx_10_13_universal2.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/cffLib/__init__.py +61 -26
- fontTools/cffLib/specializer.py +4 -1
- fontTools/cu2qu/cu2qu.c +4578 -4050
- fontTools/cu2qu/cu2qu.cpython-313-darwin.so +0 -0
- fontTools/designspaceLib/statNames.py +14 -7
- fontTools/feaLib/ast.py +12 -9
- fontTools/feaLib/builder.py +75 -49
- fontTools/feaLib/lexer.c +6290 -7116
- fontTools/feaLib/lexer.cpython-313-darwin.so +0 -0
- fontTools/feaLib/parser.py +1 -39
- fontTools/fontBuilder.py +6 -0
- fontTools/merge/cmap.py +33 -1
- fontTools/merge/tables.py +12 -1
- fontTools/misc/bezierTools.c +13668 -15551
- fontTools/misc/bezierTools.cpython-313-darwin.so +0 -0
- fontTools/misc/etree.py +4 -27
- fontTools/misc/loggingTools.py +1 -1
- fontTools/misc/symfont.py +6 -8
- fontTools/mtiLib/__init__.py +1 -3
- fontTools/otlLib/builder.py +359 -145
- fontTools/otlLib/optimize/gpos.py +42 -62
- fontTools/pens/momentsPen.c +4509 -4674
- fontTools/pens/momentsPen.cpython-313-darwin.so +0 -0
- fontTools/pens/pointPen.py +21 -12
- fontTools/pens/t2CharStringPen.py +31 -11
- fontTools/qu2cu/qu2cu.c +5746 -5465
- fontTools/qu2cu/qu2cu.cpython-313-darwin.so +0 -0
- fontTools/subset/__init__.py +12 -1
- fontTools/ttLib/tables/G_V_A_R_.py +5 -0
- fontTools/ttLib/tables/T_S_I__0.py +14 -3
- fontTools/ttLib/tables/T_S_I__5.py +16 -5
- fontTools/ttLib/tables/__init__.py +1 -0
- fontTools/ttLib/tables/_c_v_t.py +2 -0
- fontTools/ttLib/tables/_f_p_g_m.py +3 -1
- fontTools/ttLib/tables/_g_l_y_f.py +2 -6
- fontTools/ttLib/tables/_g_v_a_r.py +58 -15
- fontTools/ttLib/tables/_p_o_s_t.py +5 -2
- fontTools/ttLib/tables/otBase.py +1 -0
- fontTools/ufoLib/__init__.py +3 -3
- fontTools/ufoLib/converters.py +89 -25
- fontTools/ufoLib/errors.py +8 -0
- fontTools/ufoLib/etree.py +1 -1
- fontTools/ufoLib/filenames.py +155 -100
- fontTools/ufoLib/glifLib.py +9 -2
- fontTools/ufoLib/kerning.py +66 -36
- fontTools/ufoLib/utils.py +5 -2
- fontTools/unicodedata/Mirrored.py +446 -0
- fontTools/unicodedata/__init__.py +6 -2
- fontTools/varLib/__init__.py +20 -6
- fontTools/varLib/featureVars.py +13 -7
- fontTools/varLib/hvar.py +1 -1
- fontTools/varLib/instancer/__init__.py +14 -5
- fontTools/varLib/iup.c +6851 -6363
- fontTools/varLib/iup.cpython-313-darwin.so +0 -0
- 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.57.0.dist-info → fonttools-4.58.1.dist-info}/METADATA +64 -11
- {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/RECORD +67 -63
- {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/WHEEL +1 -1
- fonttools-4.58.1.dist-info/licenses/LICENSE.external +359 -0
- {fonttools-4.57.0.data → fonttools-4.58.1.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/entry_points.txt +0 -0
- {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/licenses/LICENSE +0 -0
- {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/top_level.txt +0 -0
fontTools/ufoLib/filenames.py
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
Convert user-provided internal UFO names to spec-compliant filenames.
|
|
3
|
+
|
|
4
|
+
This module implements the algorithm for converting between a "user name" -
|
|
5
|
+
something that a user can choose arbitrarily inside a font editor - and a file
|
|
6
|
+
name suitable for use in a wide range of operating systems and filesystems.
|
|
7
|
+
|
|
8
|
+
The `UFO 3 specification <http://unifiedfontobject.org/versions/ufo3/conventions/>`_
|
|
9
|
+
provides an example of an algorithm for such conversion, which avoids illegal
|
|
10
|
+
characters, reserved file names, ambiguity between upper- and lower-case
|
|
11
|
+
characters, and clashes with existing files.
|
|
12
|
+
|
|
13
|
+
This code was originally copied from
|
|
14
|
+
`ufoLib <https://github.com/unified-font-object/ufoLib/blob/8747da7/Lib/ufoLib/filenames.py>`_
|
|
15
|
+
by Tal Leming and is copyright (c) 2005-2016, The RoboFab Developers:
|
|
16
|
+
|
|
17
|
+
- Erik van Blokland
|
|
18
|
+
- Tal Leming
|
|
19
|
+
- Just van Rossum
|
|
4
20
|
"""
|
|
5
21
|
|
|
6
22
|
# Restrictions are taken mostly from
|
|
@@ -93,53 +109,69 @@ class NameTranslationError(Exception):
|
|
|
93
109
|
|
|
94
110
|
|
|
95
111
|
def userNameToFileName(userName: str, existing=(), prefix="", suffix=""):
|
|
96
|
-
"""
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
112
|
+
"""Converts from a user name to a file name.
|
|
113
|
+
|
|
114
|
+
Takes care to avoid illegal characters, reserved file names, ambiguity between
|
|
115
|
+
upper- and lower-case characters, and clashes with existing files.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
userName (str): The input file name.
|
|
119
|
+
existing: A case-insensitive list of all existing file names.
|
|
120
|
+
prefix: Prefix to be prepended to the file name.
|
|
121
|
+
suffix: Suffix to be appended to the file name.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
A suitable filename.
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
NameTranslationError: If no suitable name could be generated.
|
|
128
|
+
|
|
129
|
+
Examples::
|
|
130
|
+
|
|
131
|
+
>>> userNameToFileName("a") == "a"
|
|
132
|
+
True
|
|
133
|
+
>>> userNameToFileName("A") == "A_"
|
|
134
|
+
True
|
|
135
|
+
>>> userNameToFileName("AE") == "A_E_"
|
|
136
|
+
True
|
|
137
|
+
>>> userNameToFileName("Ae") == "A_e"
|
|
138
|
+
True
|
|
139
|
+
>>> userNameToFileName("ae") == "ae"
|
|
140
|
+
True
|
|
141
|
+
>>> userNameToFileName("aE") == "aE_"
|
|
142
|
+
True
|
|
143
|
+
>>> userNameToFileName("a.alt") == "a.alt"
|
|
144
|
+
True
|
|
145
|
+
>>> userNameToFileName("A.alt") == "A_.alt"
|
|
146
|
+
True
|
|
147
|
+
>>> userNameToFileName("A.Alt") == "A_.A_lt"
|
|
148
|
+
True
|
|
149
|
+
>>> userNameToFileName("A.aLt") == "A_.aL_t"
|
|
150
|
+
True
|
|
151
|
+
>>> userNameToFileName(u"A.alT") == "A_.alT_"
|
|
152
|
+
True
|
|
153
|
+
>>> userNameToFileName("T_H") == "T__H_"
|
|
154
|
+
True
|
|
155
|
+
>>> userNameToFileName("T_h") == "T__h"
|
|
156
|
+
True
|
|
157
|
+
>>> userNameToFileName("t_h") == "t_h"
|
|
158
|
+
True
|
|
159
|
+
>>> userNameToFileName("F_F_I") == "F__F__I_"
|
|
160
|
+
True
|
|
161
|
+
>>> userNameToFileName("f_f_i") == "f_f_i"
|
|
162
|
+
True
|
|
163
|
+
>>> userNameToFileName("Aacute_V.swash") == "A_acute_V_.swash"
|
|
164
|
+
True
|
|
165
|
+
>>> userNameToFileName(".notdef") == "_notdef"
|
|
166
|
+
True
|
|
167
|
+
>>> userNameToFileName("con") == "_con"
|
|
168
|
+
True
|
|
169
|
+
>>> userNameToFileName("CON") == "C_O_N_"
|
|
170
|
+
True
|
|
171
|
+
>>> userNameToFileName("con.alt") == "_con.alt"
|
|
172
|
+
True
|
|
173
|
+
>>> userNameToFileName("alt.con") == "alt._con"
|
|
174
|
+
True
|
|
143
175
|
"""
|
|
144
176
|
# the incoming name must be a string
|
|
145
177
|
if not isinstance(userName, str):
|
|
@@ -181,33 +213,42 @@ def userNameToFileName(userName: str, existing=(), prefix="", suffix=""):
|
|
|
181
213
|
|
|
182
214
|
|
|
183
215
|
def handleClash1(userName, existing=[], prefix="", suffix=""):
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
216
|
+
"""A helper function that resolves collisions with existing names when choosing a filename.
|
|
217
|
+
|
|
218
|
+
This function attempts to append an unused integer counter to the filename.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
userName (str): The input file name.
|
|
222
|
+
existing: A case-insensitive list of all existing file names.
|
|
223
|
+
prefix: Prefix to be prepended to the file name.
|
|
224
|
+
suffix: Suffix to be appended to the file name.
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
A suitable filename.
|
|
228
|
+
|
|
229
|
+
>>> prefix = ("0" * 5) + "."
|
|
230
|
+
>>> suffix = "." + ("0" * 10)
|
|
231
|
+
>>> existing = ["a" * 5]
|
|
232
|
+
|
|
233
|
+
>>> e = list(existing)
|
|
234
|
+
>>> handleClash1(userName="A" * 5, existing=e,
|
|
235
|
+
... prefix=prefix, suffix=suffix) == (
|
|
236
|
+
... '00000.AAAAA000000000000001.0000000000')
|
|
237
|
+
True
|
|
238
|
+
|
|
239
|
+
>>> e = list(existing)
|
|
240
|
+
>>> e.append(prefix + "aaaaa" + "1".zfill(15) + suffix)
|
|
241
|
+
>>> handleClash1(userName="A" * 5, existing=e,
|
|
242
|
+
... prefix=prefix, suffix=suffix) == (
|
|
243
|
+
... '00000.AAAAA000000000000002.0000000000')
|
|
244
|
+
True
|
|
245
|
+
|
|
246
|
+
>>> e = list(existing)
|
|
247
|
+
>>> e.append(prefix + "AAAAA" + "2".zfill(15) + suffix)
|
|
248
|
+
>>> handleClash1(userName="A" * 5, existing=e,
|
|
249
|
+
... prefix=prefix, suffix=suffix) == (
|
|
250
|
+
... '00000.AAAAA000000000000001.0000000000')
|
|
251
|
+
True
|
|
211
252
|
"""
|
|
212
253
|
# if the prefix length + user name length + suffix length + 15 is at
|
|
213
254
|
# or past the maximum length, silce 15 characters off of the user name
|
|
@@ -238,30 +279,44 @@ def handleClash1(userName, existing=[], prefix="", suffix=""):
|
|
|
238
279
|
|
|
239
280
|
|
|
240
281
|
def handleClash2(existing=[], prefix="", suffix=""):
|
|
241
|
-
"""
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
282
|
+
"""A helper function that resolves collisions with existing names when choosing a filename.
|
|
283
|
+
|
|
284
|
+
This function is a fallback to :func:`handleClash1`. It attempts to append an unused integer counter to the filename.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
userName (str): The input file name.
|
|
288
|
+
existing: A case-insensitive list of all existing file names.
|
|
289
|
+
prefix: Prefix to be prepended to the file name.
|
|
290
|
+
suffix: Suffix to be appended to the file name.
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
A suitable filename.
|
|
294
|
+
|
|
295
|
+
Raises:
|
|
296
|
+
NameTranslationError: If no suitable name could be generated.
|
|
297
|
+
|
|
298
|
+
Examples::
|
|
299
|
+
|
|
300
|
+
>>> prefix = ("0" * 5) + "."
|
|
301
|
+
>>> suffix = "." + ("0" * 10)
|
|
302
|
+
>>> existing = [prefix + str(i) + suffix for i in range(100)]
|
|
303
|
+
|
|
304
|
+
>>> e = list(existing)
|
|
305
|
+
>>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
|
|
306
|
+
... '00000.100.0000000000')
|
|
307
|
+
True
|
|
308
|
+
|
|
309
|
+
>>> e = list(existing)
|
|
310
|
+
>>> e.remove(prefix + "1" + suffix)
|
|
311
|
+
>>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
|
|
312
|
+
... '00000.1.0000000000')
|
|
313
|
+
True
|
|
314
|
+
|
|
315
|
+
>>> e = list(existing)
|
|
316
|
+
>>> e.remove(prefix + "2" + suffix)
|
|
317
|
+
>>> handleClash2(existing=e, prefix=prefix, suffix=suffix) == (
|
|
318
|
+
... '00000.2.0000000000')
|
|
319
|
+
True
|
|
265
320
|
"""
|
|
266
321
|
# calculate the longest possible string
|
|
267
322
|
maxLength = maxFileNameLength - len(prefix) - len(suffix)
|
fontTools/ufoLib/glifLib.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Generic module for reading and writing the .glif format.
|
|
3
3
|
|
|
4
4
|
More info about the .glif format (GLyphInterchangeFormat) can be found here:
|
|
5
5
|
|
|
6
6
|
http://unifiedfontobject.org
|
|
7
7
|
|
|
8
|
-
The main class in this module is GlyphSet
|
|
8
|
+
The main class in this module is :class:`GlyphSet`. It manages a set of .glif files
|
|
9
9
|
in a folder. It offers two ways to read glyph data, and one way to write
|
|
10
10
|
glyph data. See the class doc string for details.
|
|
11
11
|
"""
|
|
@@ -60,6 +60,13 @@ LAYERINFO_FILENAME = "layerinfo.plist"
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
class GLIFFormatVersion(tuple, _VersionTupleEnumMixin, enum.Enum):
|
|
63
|
+
"""Class representing the versions of the .glif format supported by the UFO version in use.
|
|
64
|
+
|
|
65
|
+
For a given :mod:`fontTools.ufoLib.UFOFormatVersion`, the :func:`supported_versions` method will
|
|
66
|
+
return the supported versions of the GLIF file format. If the UFO version is unspecified, the
|
|
67
|
+
:func:`supported_versions` method will return all available GLIF format versions.
|
|
68
|
+
"""
|
|
69
|
+
|
|
63
70
|
FORMAT_1_0 = (1, 0)
|
|
64
71
|
FORMAT_2_0 = (2, 0)
|
|
65
72
|
|
fontTools/ufoLib/kerning.py
CHANGED
|
@@ -1,43 +1,73 @@
|
|
|
1
1
|
def lookupKerningValue(
|
|
2
2
|
pair, kerning, groups, fallback=0, glyphToFirstGroup=None, glyphToSecondGroup=None
|
|
3
3
|
):
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
"""Retrieve the kerning value (if any) between a pair of elements.
|
|
5
|
+
|
|
6
|
+
The elments can be either individual glyphs (by name) or kerning
|
|
7
|
+
groups (by name), or any combination of the two.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
pair:
|
|
11
|
+
A tuple, in logical order (first, second) with respect
|
|
12
|
+
to the reading direction, to query the font for kerning
|
|
13
|
+
information on. Each element in the tuple can be either
|
|
14
|
+
a glyph name or a kerning group name.
|
|
15
|
+
kerning:
|
|
16
|
+
A dictionary of kerning pairs.
|
|
17
|
+
groups:
|
|
18
|
+
A set of kerning groups.
|
|
19
|
+
fallback:
|
|
20
|
+
The fallback value to return if no kern is found between
|
|
21
|
+
the elements in ``pair``. Defaults to 0.
|
|
22
|
+
glyphToFirstGroup:
|
|
23
|
+
A dictionary mapping glyph names to the first-glyph kerning
|
|
24
|
+
groups to which they belong. Defaults to ``None``.
|
|
25
|
+
glyphToSecondGroup:
|
|
26
|
+
A dictionary mapping glyph names to the second-glyph kerning
|
|
27
|
+
groups to which they belong. Defaults to ``None``.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
The kerning value between the element pair. If no kerning for
|
|
31
|
+
the pair is found, the fallback value is returned.
|
|
32
|
+
|
|
33
|
+
Note: This function expects the ``kerning`` argument to be a flat
|
|
34
|
+
dictionary of kerning pairs, not the nested structure used in a
|
|
35
|
+
kerning.plist file.
|
|
36
|
+
|
|
37
|
+
Examples::
|
|
8
38
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
>>> groups = {
|
|
40
|
+
... "public.kern1.O" : ["O", "D", "Q"],
|
|
41
|
+
... "public.kern2.E" : ["E", "F"]
|
|
42
|
+
... }
|
|
43
|
+
>>> kerning = {
|
|
44
|
+
... ("public.kern1.O", "public.kern2.E") : -100,
|
|
45
|
+
... ("public.kern1.O", "F") : -200,
|
|
46
|
+
... ("D", "F") : -300
|
|
47
|
+
... }
|
|
48
|
+
>>> lookupKerningValue(("D", "F"), kerning, groups)
|
|
49
|
+
-300
|
|
50
|
+
>>> lookupKerningValue(("O", "F"), kerning, groups)
|
|
51
|
+
-200
|
|
52
|
+
>>> lookupKerningValue(("O", "E"), kerning, groups)
|
|
53
|
+
-100
|
|
54
|
+
>>> lookupKerningValue(("O", "O"), kerning, groups)
|
|
55
|
+
0
|
|
56
|
+
>>> lookupKerningValue(("E", "E"), kerning, groups)
|
|
57
|
+
0
|
|
58
|
+
>>> lookupKerningValue(("E", "O"), kerning, groups)
|
|
59
|
+
0
|
|
60
|
+
>>> lookupKerningValue(("X", "X"), kerning, groups)
|
|
61
|
+
0
|
|
62
|
+
>>> lookupKerningValue(("public.kern1.O", "public.kern2.E"),
|
|
63
|
+
... kerning, groups)
|
|
64
|
+
-100
|
|
65
|
+
>>> lookupKerningValue(("public.kern1.O", "F"), kerning, groups)
|
|
66
|
+
-200
|
|
67
|
+
>>> lookupKerningValue(("O", "public.kern2.E"), kerning, groups)
|
|
68
|
+
-100
|
|
69
|
+
>>> lookupKerningValue(("public.kern1.X", "public.kern2.X"), kerning, groups)
|
|
70
|
+
0
|
|
41
71
|
"""
|
|
42
72
|
# quickly check to see if the pair is in the kerning dictionary
|
|
43
73
|
if pair in kerning:
|
fontTools/ufoLib/utils.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
"""
|
|
2
|
-
|
|
1
|
+
"""This module contains miscellaneous helpers.
|
|
2
|
+
|
|
3
|
+
It is not considered part of the public ufoLib API. It does, however,
|
|
4
|
+
define the :py:obj:`.deprecated` decorator that is used elsewhere in
|
|
5
|
+
the module.
|
|
3
6
|
"""
|
|
4
7
|
|
|
5
8
|
import warnings
|