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
|
@@ -3,6 +3,7 @@ from functools import partial
|
|
|
3
3
|
from fontTools.misc import sstruct
|
|
4
4
|
from fontTools.misc.textTools import safeEval
|
|
5
5
|
from fontTools.misc.lazyTools import LazyDict
|
|
6
|
+
from fontTools.ttLib import OPTIMIZE_FONT_SPEED
|
|
6
7
|
from fontTools.ttLib.tables.TupleVariation import TupleVariation
|
|
7
8
|
from . import DefaultTable
|
|
8
9
|
import array
|
|
@@ -23,19 +24,24 @@ log = logging.getLogger(__name__)
|
|
|
23
24
|
# FreeType2 source code for parsing 'gvar':
|
|
24
25
|
# http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/truetype/ttgxvar.c
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
GVAR_HEADER_FORMAT_HEAD = """
|
|
27
28
|
> # big endian
|
|
28
29
|
version: H
|
|
29
30
|
reserved: H
|
|
30
31
|
axisCount: H
|
|
31
32
|
sharedTupleCount: H
|
|
32
33
|
offsetToSharedTuples: I
|
|
33
|
-
|
|
34
|
+
"""
|
|
35
|
+
# In between the HEAD and TAIL lies the glyphCount, which is
|
|
36
|
+
# of different size: 2 bytes for gvar, and 3 bytes for GVAR.
|
|
37
|
+
GVAR_HEADER_FORMAT_TAIL = """
|
|
38
|
+
> # big endian
|
|
34
39
|
flags: H
|
|
35
40
|
offsetToGlyphVariationData: I
|
|
36
41
|
"""
|
|
37
42
|
|
|
38
|
-
|
|
43
|
+
GVAR_HEADER_SIZE_HEAD = sstruct.calcsize(GVAR_HEADER_FORMAT_HEAD)
|
|
44
|
+
GVAR_HEADER_SIZE_TAIL = sstruct.calcsize(GVAR_HEADER_FORMAT_TAIL)
|
|
39
45
|
|
|
40
46
|
|
|
41
47
|
class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
@@ -50,6 +56,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
|
50
56
|
"""
|
|
51
57
|
|
|
52
58
|
dependencies = ["fvar", "glyf"]
|
|
59
|
+
gid_size = 2
|
|
53
60
|
|
|
54
61
|
def __init__(self, tag=None):
|
|
55
62
|
DefaultTable.DefaultTable.__init__(self, tag)
|
|
@@ -72,28 +79,33 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
|
72
79
|
offsets.append(offset)
|
|
73
80
|
compiledOffsets, tableFormat = self.compileOffsets_(offsets)
|
|
74
81
|
|
|
82
|
+
GVAR_HEADER_SIZE = GVAR_HEADER_SIZE_HEAD + self.gid_size + GVAR_HEADER_SIZE_TAIL
|
|
75
83
|
header = {}
|
|
76
84
|
header["version"] = self.version
|
|
77
85
|
header["reserved"] = self.reserved
|
|
78
86
|
header["axisCount"] = len(axisTags)
|
|
79
87
|
header["sharedTupleCount"] = len(sharedTuples)
|
|
80
88
|
header["offsetToSharedTuples"] = GVAR_HEADER_SIZE + len(compiledOffsets)
|
|
81
|
-
header["glyphCount"] = len(compiledGlyphs)
|
|
82
89
|
header["flags"] = tableFormat
|
|
83
90
|
header["offsetToGlyphVariationData"] = (
|
|
84
91
|
header["offsetToSharedTuples"] + sharedTupleSize
|
|
85
92
|
)
|
|
86
|
-
compiledHeader = sstruct.pack(GVAR_HEADER_FORMAT, header)
|
|
87
93
|
|
|
88
|
-
result = [
|
|
94
|
+
result = [
|
|
95
|
+
sstruct.pack(GVAR_HEADER_FORMAT_HEAD, header),
|
|
96
|
+
len(compiledGlyphs).to_bytes(self.gid_size, "big"),
|
|
97
|
+
sstruct.pack(GVAR_HEADER_FORMAT_TAIL, header),
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
result.append(compiledOffsets)
|
|
89
101
|
result.extend(sharedTuples)
|
|
90
102
|
result.extend(compiledGlyphs)
|
|
91
103
|
return b"".join(result)
|
|
92
104
|
|
|
93
105
|
def compileGlyphs_(self, ttFont, axisTags, sharedCoordIndices):
|
|
106
|
+
optimizeSpeed = ttFont.cfg[OPTIMIZE_FONT_SPEED]
|
|
94
107
|
result = []
|
|
95
108
|
glyf = ttFont["glyf"]
|
|
96
|
-
optimizeSize = getattr(self, "optimizeSize", True)
|
|
97
109
|
for glyphName in ttFont.getGlyphOrder():
|
|
98
110
|
variations = self.variations.get(glyphName, [])
|
|
99
111
|
if not variations:
|
|
@@ -102,11 +114,12 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
|
102
114
|
pointCountUnused = 0 # pointCount is actually unused by compileGlyph
|
|
103
115
|
result.append(
|
|
104
116
|
compileGlyph_(
|
|
117
|
+
self.gid_size,
|
|
105
118
|
variations,
|
|
106
119
|
pointCountUnused,
|
|
107
120
|
axisTags,
|
|
108
121
|
sharedCoordIndices,
|
|
109
|
-
optimizeSize=
|
|
122
|
+
optimizeSize=not optimizeSpeed,
|
|
110
123
|
)
|
|
111
124
|
)
|
|
112
125
|
return result
|
|
@@ -114,9 +127,25 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
|
114
127
|
def decompile(self, data, ttFont):
|
|
115
128
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
|
116
129
|
glyphs = ttFont.getGlyphOrder()
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
|
|
131
|
+
# Parse the header
|
|
132
|
+
GVAR_HEADER_SIZE = GVAR_HEADER_SIZE_HEAD + self.gid_size + GVAR_HEADER_SIZE_TAIL
|
|
133
|
+
sstruct.unpack(GVAR_HEADER_FORMAT_HEAD, data[:GVAR_HEADER_SIZE_HEAD], self)
|
|
134
|
+
self.glyphCount = int.from_bytes(
|
|
135
|
+
data[GVAR_HEADER_SIZE_HEAD : GVAR_HEADER_SIZE_HEAD + self.gid_size], "big"
|
|
136
|
+
)
|
|
137
|
+
sstruct.unpack(
|
|
138
|
+
GVAR_HEADER_FORMAT_TAIL,
|
|
139
|
+
data[GVAR_HEADER_SIZE_HEAD + self.gid_size : GVAR_HEADER_SIZE],
|
|
140
|
+
self,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
assert len(glyphs) == self.glyphCount, (len(glyphs), self.glyphCount)
|
|
144
|
+
assert len(axisTags) == self.axisCount, (
|
|
145
|
+
len(axisTags),
|
|
146
|
+
self.axisCount,
|
|
147
|
+
axisTags,
|
|
148
|
+
)
|
|
120
149
|
sharedCoords = tv.decompileSharedTuples(
|
|
121
150
|
axisTags, self.sharedTupleCount, data, self.offsetToSharedTuples
|
|
122
151
|
)
|
|
@@ -144,7 +173,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
|
144
173
|
glyph = glyf[glyphName]
|
|
145
174
|
numPointsInGlyph = self.getNumPoints_(glyph)
|
|
146
175
|
return decompileGlyph_(
|
|
147
|
-
numPointsInGlyph, sharedCoords, axisTags, gvarData
|
|
176
|
+
self.gid_size, numPointsInGlyph, sharedCoords, axisTags, gvarData
|
|
148
177
|
)
|
|
149
178
|
|
|
150
179
|
return read_item
|
|
@@ -262,23 +291,42 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|
|
262
291
|
|
|
263
292
|
|
|
264
293
|
def compileGlyph_(
|
|
265
|
-
|
|
294
|
+
dataOffsetSize,
|
|
295
|
+
variations,
|
|
296
|
+
pointCount,
|
|
297
|
+
axisTags,
|
|
298
|
+
sharedCoordIndices,
|
|
299
|
+
*,
|
|
300
|
+
optimizeSize=True,
|
|
266
301
|
):
|
|
302
|
+
assert dataOffsetSize in (2, 3)
|
|
267
303
|
tupleVariationCount, tuples, data = tv.compileTupleVariationStore(
|
|
268
304
|
variations, pointCount, axisTags, sharedCoordIndices, optimizeSize=optimizeSize
|
|
269
305
|
)
|
|
270
306
|
if tupleVariationCount == 0:
|
|
271
307
|
return b""
|
|
272
|
-
|
|
273
|
-
|
|
308
|
+
|
|
309
|
+
offsetToData = 2 + dataOffsetSize + len(tuples)
|
|
310
|
+
|
|
311
|
+
result = [
|
|
312
|
+
tupleVariationCount.to_bytes(2, "big"),
|
|
313
|
+
offsetToData.to_bytes(dataOffsetSize, "big"),
|
|
314
|
+
tuples,
|
|
315
|
+
data,
|
|
316
|
+
]
|
|
317
|
+
if (offsetToData + len(data)) % 2 != 0:
|
|
274
318
|
result.append(b"\0") # padding
|
|
275
319
|
return b"".join(result)
|
|
276
320
|
|
|
277
321
|
|
|
278
|
-
def decompileGlyph_(pointCount, sharedTuples, axisTags, data):
|
|
279
|
-
|
|
322
|
+
def decompileGlyph_(dataOffsetSize, pointCount, sharedTuples, axisTags, data):
|
|
323
|
+
assert dataOffsetSize in (2, 3)
|
|
324
|
+
if len(data) < 2 + dataOffsetSize:
|
|
280
325
|
return []
|
|
281
|
-
|
|
326
|
+
|
|
327
|
+
tupleVariationCount = int.from_bytes(data[:2], "big")
|
|
328
|
+
offsetToData = int.from_bytes(data[2 : 2 + dataOffsetSize], "big")
|
|
329
|
+
|
|
282
330
|
dataPos = offsetToData
|
|
283
331
|
return tv.decompileTupleVariationStore(
|
|
284
332
|
"gvar",
|
|
@@ -287,6 +335,6 @@ def decompileGlyph_(pointCount, sharedTuples, axisTags, data):
|
|
|
287
335
|
pointCount,
|
|
288
336
|
sharedTuples,
|
|
289
337
|
data,
|
|
290
|
-
|
|
338
|
+
2 + dataOffsetSize,
|
|
291
339
|
offsetToData,
|
|
292
340
|
)
|
|
@@ -65,8 +65,8 @@ class table__h_d_m_x(DefaultTable.DefaultTable):
|
|
|
65
65
|
items = sorted(self.hdmx.items())
|
|
66
66
|
for ppem, widths in items:
|
|
67
67
|
data = data + bytechr(ppem) + bytechr(max(widths.values()))
|
|
68
|
-
for
|
|
69
|
-
width = widths[
|
|
68
|
+
for glyphName in glyphOrder:
|
|
69
|
+
width = widths[glyphName]
|
|
70
70
|
data = data + bytechr(width)
|
|
71
71
|
data = data + pad
|
|
72
72
|
return data
|
|
@@ -123,5 +123,5 @@ class table__h_d_m_x(DefaultTable.DefaultTable):
|
|
|
123
123
|
glyphName = safeEval('"""' + glyphName + '"""')
|
|
124
124
|
line = list(map(int, line[1:]))
|
|
125
125
|
assert len(line) == len(ppems), "illegal hdmx format"
|
|
126
|
-
for i in
|
|
127
|
-
hdmx[
|
|
126
|
+
for i, ppem in enumerate(ppems):
|
|
127
|
+
hdmx[ppem][glyphName] = line[i]
|
|
@@ -40,15 +40,19 @@ class table__h_m_t_x(DefaultTable.DefaultTable):
|
|
|
40
40
|
% (self.headerTag, self.numberOfMetricsName)
|
|
41
41
|
)
|
|
42
42
|
numberOfMetrics = numGlyphs
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
numberOfSideBearings = numGlyphs - numberOfMetrics
|
|
44
|
+
tableSize = 4 * numberOfMetrics + 2 * numberOfSideBearings
|
|
45
|
+
if len(data) < tableSize:
|
|
46
|
+
raise ttLib.TTLibError(
|
|
47
|
+
f"not enough '{self.tableTag}' table data: "
|
|
48
|
+
f"expected {tableSize} bytes, got {len(data)}"
|
|
49
|
+
)
|
|
45
50
|
# Note: advanceWidth is unsigned, but some font editors might
|
|
46
51
|
# read/write as signed. We can't be sure whether it was a mistake
|
|
47
52
|
# or not, so we read as unsigned but also issue a warning...
|
|
48
53
|
metricsFmt = ">" + self.longMetricFormat * numberOfMetrics
|
|
49
54
|
metrics = struct.unpack(metricsFmt, data[: 4 * numberOfMetrics])
|
|
50
55
|
data = data[4 * numberOfMetrics :]
|
|
51
|
-
numberOfSideBearings = numGlyphs - numberOfMetrics
|
|
52
56
|
sideBearings = array.array("h", data[: 2 * numberOfSideBearings])
|
|
53
57
|
data = data[2 * numberOfSideBearings :]
|
|
54
58
|
|
|
@@ -46,8 +46,8 @@ class table__l_o_c_a(DefaultTable.DefaultTable):
|
|
|
46
46
|
max_location = 0
|
|
47
47
|
if max_location < 0x20000 and all(l % 2 == 0 for l in self.locations):
|
|
48
48
|
locations = array.array("H")
|
|
49
|
-
for
|
|
50
|
-
locations.append(
|
|
49
|
+
for location in self.locations:
|
|
50
|
+
locations.append(location // 2)
|
|
51
51
|
ttFont["head"].indexToLocFormat = 0
|
|
52
52
|
else:
|
|
53
53
|
locations = array.array("I", self.locations)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
2
4
|
from fontTools.misc import sstruct
|
|
3
5
|
from fontTools.misc.textTools import (
|
|
4
6
|
bytechr,
|
|
@@ -63,7 +65,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|
|
63
65
|
)
|
|
64
66
|
stringData = data[stringOffset:]
|
|
65
67
|
data = data[6:]
|
|
66
|
-
self.names = []
|
|
68
|
+
self.names: list[NameRecord] = []
|
|
67
69
|
for i in range(n):
|
|
68
70
|
if len(data) < 12:
|
|
69
71
|
log.error("skipping malformed name record #%d", i)
|
|
@@ -112,7 +114,9 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|
|
112
114
|
self.names.append(name)
|
|
113
115
|
name.fromXML(name, attrs, content, ttFont)
|
|
114
116
|
|
|
115
|
-
def getName(
|
|
117
|
+
def getName(
|
|
118
|
+
self, nameID: int, platformID: int, platEncID: int, langID: int | None = None
|
|
119
|
+
) -> "NameRecord | None":
|
|
116
120
|
for namerecord in self.names:
|
|
117
121
|
if (
|
|
118
122
|
namerecord.nameID == nameID
|
|
@@ -123,8 +127,9 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|
|
123
127
|
return namerecord
|
|
124
128
|
return None # not found
|
|
125
129
|
|
|
126
|
-
def getDebugName(self, nameID):
|
|
127
|
-
englishName
|
|
130
|
+
def getDebugName(self, nameID: int) -> str | None:
|
|
131
|
+
englishName: str | None = None
|
|
132
|
+
someName: str | None = None
|
|
128
133
|
for name in self.names:
|
|
129
134
|
if name.nameID != nameID:
|
|
130
135
|
continue
|
|
@@ -513,7 +518,7 @@ class NameRecord(object):
|
|
|
513
518
|
self.platformID == 3 and self.platEncID in [0, 1, 10]
|
|
514
519
|
)
|
|
515
520
|
|
|
516
|
-
def toUnicode(self, errors="strict"):
|
|
521
|
+
def toUnicode(self, errors: str = "strict") -> str:
|
|
517
522
|
"""
|
|
518
523
|
If self.string is a Unicode string, return it; otherwise try decoding the
|
|
519
524
|
bytes in self.string to a Unicode string using the encoding of this
|
|
@@ -533,7 +538,7 @@ class NameRecord(object):
|
|
|
533
538
|
and saving it back will not change them.
|
|
534
539
|
"""
|
|
535
540
|
|
|
536
|
-
def isascii(b):
|
|
541
|
+
def isascii(b: int) -> bool:
|
|
537
542
|
return (b >= 0x20 and b <= 0x7E) or b in [0x09, 0x0A, 0x0D]
|
|
538
543
|
|
|
539
544
|
encoding = self.getEncoding()
|
|
@@ -118,21 +118,24 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|
|
118
118
|
def build_psNameMapping(self, ttFont):
|
|
119
119
|
mapping = {}
|
|
120
120
|
allNames = {}
|
|
121
|
+
glyphOrderNames = set(self.glyphOrder)
|
|
121
122
|
for i in range(ttFont["maxp"].numGlyphs):
|
|
122
123
|
glyphName = psName = self.glyphOrder[i]
|
|
123
124
|
if glyphName == "":
|
|
124
125
|
glyphName = "glyph%.5d" % i
|
|
126
|
+
|
|
125
127
|
if glyphName in allNames:
|
|
126
128
|
# make up a new glyphName that's unique
|
|
127
129
|
n = allNames[glyphName]
|
|
128
|
-
|
|
130
|
+
# check if the glyph name exists in the glyph order
|
|
131
|
+
while f"{glyphName}.{n}" in glyphOrderNames:
|
|
129
132
|
n += 1
|
|
130
133
|
allNames[glyphName] = n + 1
|
|
131
|
-
glyphName = glyphName
|
|
134
|
+
glyphName = f"{glyphName}.{n}"
|
|
132
135
|
|
|
133
|
-
self.glyphOrder[i] = glyphName
|
|
134
136
|
allNames[glyphName] = 1
|
|
135
137
|
if glyphName != psName:
|
|
138
|
+
self.glyphOrder[i] = glyphName
|
|
136
139
|
mapping[glyphName] = psName
|
|
137
140
|
|
|
138
141
|
self.mapping = mapping
|
|
@@ -171,10 +174,9 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|
|
171
174
|
extraNames = self.extraNames = [
|
|
172
175
|
n for n in self.extraNames if n not in standardGlyphOrder
|
|
173
176
|
]
|
|
174
|
-
for i in
|
|
175
|
-
extraDict[
|
|
176
|
-
for
|
|
177
|
-
glyphName = glyphOrder[glyphID]
|
|
177
|
+
for i, name in enumerate(extraNames):
|
|
178
|
+
extraDict[name] = i
|
|
179
|
+
for glyphName in glyphOrder:
|
|
178
180
|
if glyphName in self.mapping:
|
|
179
181
|
psName = self.mapping[glyphName]
|
|
180
182
|
else:
|
fontTools/ttLib/tables/otBase.py
CHANGED
|
@@ -15,10 +15,7 @@ have_uharfbuzz = False
|
|
|
15
15
|
try:
|
|
16
16
|
import uharfbuzz as hb
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
# imported but repack method is missing, behave as if uharfbuzz
|
|
20
|
-
# is not available (fallback to the slower Python implementation)
|
|
21
|
-
have_uharfbuzz = callable(getattr(hb, "repack", None))
|
|
18
|
+
have_uharfbuzz = True
|
|
22
19
|
except ImportError:
|
|
23
20
|
pass
|
|
24
21
|
|
|
@@ -398,6 +395,7 @@ class OTTableWriter(object):
|
|
|
398
395
|
self.localState = localState
|
|
399
396
|
self.tableTag = tableTag
|
|
400
397
|
self.parent = None
|
|
398
|
+
self.name = "<none>"
|
|
401
399
|
|
|
402
400
|
def __setitem__(self, name, value):
|
|
403
401
|
state = self.localState.copy() if self.localState else dict()
|
|
@@ -499,8 +497,7 @@ class OTTableWriter(object):
|
|
|
499
497
|
internedTables = {}
|
|
500
498
|
|
|
501
499
|
items = self.items
|
|
502
|
-
for i in
|
|
503
|
-
item = items[i]
|
|
500
|
+
for i, item in enumerate(items):
|
|
504
501
|
if hasattr(item, "getCountData"):
|
|
505
502
|
items[i] = item.getCountData()
|
|
506
503
|
elif hasattr(item, "subWriter"):
|
|
@@ -668,10 +665,7 @@ class OTTableWriter(object):
|
|
|
668
665
|
tableData = table.getDataForHarfbuzz()
|
|
669
666
|
data.append(tableData)
|
|
670
667
|
|
|
671
|
-
|
|
672
|
-
return hb.repack_with_tag(str(tableTag), data, obj_list)
|
|
673
|
-
else:
|
|
674
|
-
return hb.repack(data, obj_list)
|
|
668
|
+
return hb.serialize_with_tag(str(tableTag), data, obj_list)
|
|
675
669
|
|
|
676
670
|
def getAllData(self, remove_duplicate=True):
|
|
677
671
|
"""Assemble all data, including all subtables."""
|
|
@@ -1129,8 +1123,7 @@ class BaseTable(object):
|
|
|
1129
1123
|
for conv in self.getConverters():
|
|
1130
1124
|
if conv.repeat:
|
|
1131
1125
|
value = getattr(self, conv.name, [])
|
|
1132
|
-
for i in
|
|
1133
|
-
item = value[i]
|
|
1126
|
+
for i, item in enumerate(value):
|
|
1134
1127
|
conv.xmlWrite(xmlWriter, font, item, conv.name, [("index", i)])
|
|
1135
1128
|
else:
|
|
1136
1129
|
if conv.aux and not eval(conv.aux, None, vars(self)):
|
|
@@ -10,7 +10,7 @@ from fontTools.ttLib.tables.TupleVariation import TupleVariation
|
|
|
10
10
|
from fontTools.misc.roundTools import nearestMultipleShortestRepr, otRound
|
|
11
11
|
from fontTools.misc.textTools import bytesjoin, tobytes, tostr, pad, safeEval
|
|
12
12
|
from fontTools.misc.lazyTools import LazyList
|
|
13
|
-
from fontTools.ttLib import getSearchRange
|
|
13
|
+
from fontTools.ttLib import OPTIMIZE_FONT_SPEED, getSearchRange
|
|
14
14
|
from .otBase import (
|
|
15
15
|
CountReference,
|
|
16
16
|
FormatSwitchingBaseTable,
|
|
@@ -1810,7 +1810,10 @@ class TupleValues:
|
|
|
1810
1810
|
return TupleVariation.decompileDeltas_(None, data)[0]
|
|
1811
1811
|
|
|
1812
1812
|
def write(self, writer, font, tableDict, values, repeatIndex=None):
|
|
1813
|
-
|
|
1813
|
+
optimizeSpeed = font.cfg[OPTIMIZE_FONT_SPEED]
|
|
1814
|
+
return bytes(
|
|
1815
|
+
TupleVariation.compileDeltaValues_(values, optimizeSize=not optimizeSpeed)
|
|
1816
|
+
)
|
|
1814
1817
|
|
|
1815
1818
|
def xmlRead(self, attrs, content, font):
|
|
1816
1819
|
return safeEval(attrs["value"])
|
fontTools/ttLib/tables/otData.py
CHANGED
|
@@ -11,6 +11,7 @@ from functools import reduce
|
|
|
11
11
|
from math import radians
|
|
12
12
|
import itertools
|
|
13
13
|
from collections import defaultdict, namedtuple
|
|
14
|
+
from fontTools.ttLib import OPTIMIZE_FONT_SPEED
|
|
14
15
|
from fontTools.ttLib.tables.TupleVariation import TupleVariation
|
|
15
16
|
from fontTools.ttLib.tables.otTraverse import dfs_base_table
|
|
16
17
|
from fontTools.misc.arrayTools import quantizeRect
|
|
@@ -236,6 +237,8 @@ class VarComponent:
|
|
|
236
237
|
return data[i:]
|
|
237
238
|
|
|
238
239
|
def compile(self, font):
|
|
240
|
+
optimizeSpeed = font.cfg[OPTIMIZE_FONT_SPEED]
|
|
241
|
+
|
|
239
242
|
data = []
|
|
240
243
|
|
|
241
244
|
flags = self.flags
|
|
@@ -259,7 +262,8 @@ class VarComponent:
|
|
|
259
262
|
data.append(_write_uint32var(self.axisIndicesIndex))
|
|
260
263
|
data.append(
|
|
261
264
|
TupleVariation.compileDeltaValues_(
|
|
262
|
-
[fl2fi(v, 14) for v in self.axisValues]
|
|
265
|
+
[fl2fi(v, 14) for v in self.axisValues],
|
|
266
|
+
optimizeSize=not optimizeSpeed,
|
|
263
267
|
)
|
|
264
268
|
)
|
|
265
269
|
else:
|
|
@@ -986,8 +990,7 @@ class Coverage(FormatSwitchingBaseTable):
|
|
|
986
990
|
if brokenOrder or len(ranges) * 3 < len(glyphs): # 3 words vs. 1 word
|
|
987
991
|
# Format 2 is more compact
|
|
988
992
|
index = 0
|
|
989
|
-
for i in
|
|
990
|
-
start, end = ranges[i]
|
|
993
|
+
for i, (start, end) in enumerate(ranges):
|
|
991
994
|
r = RangeRecord()
|
|
992
995
|
r.StartID = start
|
|
993
996
|
r.Start = font.getGlyphName(start)
|
|
@@ -1400,8 +1403,7 @@ class ClassDef(FormatSwitchingBaseTable):
|
|
|
1400
1403
|
glyphCount = endGlyph - startGlyph + 1
|
|
1401
1404
|
if len(ranges) * 3 < glyphCount + 1:
|
|
1402
1405
|
# Format 2 is more compact
|
|
1403
|
-
for i in
|
|
1404
|
-
cls, start, startName, end, endName = ranges[i]
|
|
1406
|
+
for i, (cls, start, startName, end, endName) in enumerate(ranges):
|
|
1405
1407
|
rec = ClassRangeRecord()
|
|
1406
1408
|
rec.Start = startName
|
|
1407
1409
|
rec.End = endName
|
|
@@ -1459,8 +1461,7 @@ class AlternateSubst(FormatSwitchingBaseTable):
|
|
|
1459
1461
|
if alternates is None:
|
|
1460
1462
|
alternates = self.alternates = {}
|
|
1461
1463
|
items = list(alternates.items())
|
|
1462
|
-
for i in
|
|
1463
|
-
glyphName, set = items[i]
|
|
1464
|
+
for i, (glyphName, set) in enumerate(items):
|
|
1464
1465
|
items[i] = font.getGlyphID(glyphName), glyphName, set
|
|
1465
1466
|
items.sort()
|
|
1466
1467
|
cov = Coverage()
|
|
@@ -1516,8 +1517,8 @@ class LigatureSubst(FormatSwitchingBaseTable):
|
|
|
1516
1517
|
input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
|
|
1517
1518
|
ligSets = rawTable["LigatureSet"]
|
|
1518
1519
|
assert len(input) == len(ligSets)
|
|
1519
|
-
for i in
|
|
1520
|
-
ligatures[
|
|
1520
|
+
for i, inp in enumerate(input):
|
|
1521
|
+
ligatures[inp] = ligSets[i].Ligature
|
|
1521
1522
|
else:
|
|
1522
1523
|
assert 0, "unknown format: %s" % self.Format
|
|
1523
1524
|
self.ligatures = ligatures
|
|
@@ -1573,8 +1574,7 @@ class LigatureSubst(FormatSwitchingBaseTable):
|
|
|
1573
1574
|
ligatures = newLigatures
|
|
1574
1575
|
|
|
1575
1576
|
items = list(ligatures.items())
|
|
1576
|
-
for i in
|
|
1577
|
-
glyphName, set = items[i]
|
|
1577
|
+
for i, (glyphName, set) in enumerate(items):
|
|
1578
1578
|
items[i] = font.getGlyphID(glyphName), glyphName, set
|
|
1579
1579
|
items.sort()
|
|
1580
1580
|
cov = Coverage()
|
|
@@ -2226,24 +2226,28 @@ _equivalents = {
|
|
|
2226
2226
|
def fixLookupOverFlows(ttf, overflowRecord):
|
|
2227
2227
|
"""Either the offset from the LookupList to a lookup overflowed, or
|
|
2228
2228
|
an offset from a lookup to a subtable overflowed.
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2229
|
+
|
|
2230
|
+
The table layout is::
|
|
2231
|
+
|
|
2232
|
+
GPSO/GUSB
|
|
2233
|
+
Script List
|
|
2234
|
+
Feature List
|
|
2235
|
+
LookUpList
|
|
2236
|
+
Lookup[0] and contents
|
|
2237
|
+
SubTable offset list
|
|
2238
|
+
SubTable[0] and contents
|
|
2239
|
+
...
|
|
2240
|
+
SubTable[n] and contents
|
|
2241
|
+
...
|
|
2242
|
+
Lookup[n] and contents
|
|
2243
|
+
SubTable offset list
|
|
2244
|
+
SubTable[0] and contents
|
|
2245
|
+
...
|
|
2246
|
+
SubTable[n] and contents
|
|
2247
|
+
|
|
2245
2248
|
If the offset to a lookup overflowed (SubTableIndex is None)
|
|
2246
|
-
we must promote the *previous*
|
|
2249
|
+
we must promote the *previous* lookup to an Extension type.
|
|
2250
|
+
|
|
2247
2251
|
If the offset from a lookup to subtable overflowed, then we must promote it
|
|
2248
2252
|
to an Extension Lookup type.
|
|
2249
2253
|
"""
|
|
@@ -2271,8 +2275,7 @@ def fixLookupOverFlows(ttf, overflowRecord):
|
|
|
2271
2275
|
lookup = lookups[lookupIndex]
|
|
2272
2276
|
if lookup.LookupType != extType:
|
|
2273
2277
|
lookup.LookupType = extType
|
|
2274
|
-
for si in
|
|
2275
|
-
subTable = lookup.SubTable[si]
|
|
2278
|
+
for si, subTable in enumerate(lookup.SubTable):
|
|
2276
2279
|
extSubTableClass = lookupTypes[overflowRecord.tableType][extType]
|
|
2277
2280
|
extSubTable = extSubTableClass()
|
|
2278
2281
|
extSubTable.Format = 1
|
|
@@ -79,7 +79,8 @@ def bfs_base_table(
|
|
|
79
79
|
"""Breadth-first search tree of BaseTables.
|
|
80
80
|
|
|
81
81
|
Args:
|
|
82
|
-
|
|
82
|
+
root
|
|
83
|
+
the root of the tree.
|
|
83
84
|
root_accessor (Optional[str]): attribute name for the root table, if any (mostly
|
|
84
85
|
useful for debugging).
|
|
85
86
|
skip_root (Optional[bool]): if True, the root itself is not visited, only its
|
|
@@ -128,9 +128,9 @@ class Strike(object):
|
|
|
128
128
|
xmlWriter.simpletag("resolution", value=self.resolution)
|
|
129
129
|
xmlWriter.newline()
|
|
130
130
|
glyphOrder = ttFont.getGlyphOrder()
|
|
131
|
-
for
|
|
132
|
-
if
|
|
133
|
-
self.glyphs[
|
|
131
|
+
for glyphName in glyphOrder:
|
|
132
|
+
if glyphName in self.glyphs:
|
|
133
|
+
self.glyphs[glyphName].toXML(xmlWriter, ttFont)
|
|
134
134
|
# TODO: what if there are more glyph data records than (glyf table) glyphs?
|
|
135
135
|
xmlWriter.endtag("strike")
|
|
136
136
|
xmlWriter.newline()
|