fonttools 4.57.0__cp39-cp39-macosx_10_9_universal2.whl → 4.58.1__cp39-cp39-macosx_10_9_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.

Files changed (67) hide show
  1. fontTools/__init__.py +1 -1
  2. fontTools/cffLib/__init__.py +61 -26
  3. fontTools/cffLib/specializer.py +4 -1
  4. fontTools/cu2qu/cu2qu.c +4578 -4050
  5. fontTools/cu2qu/cu2qu.cpython-39-darwin.so +0 -0
  6. fontTools/designspaceLib/statNames.py +14 -7
  7. fontTools/feaLib/ast.py +12 -9
  8. fontTools/feaLib/builder.py +75 -49
  9. fontTools/feaLib/lexer.c +6290 -7116
  10. fontTools/feaLib/lexer.cpython-39-darwin.so +0 -0
  11. fontTools/feaLib/parser.py +1 -39
  12. fontTools/fontBuilder.py +6 -0
  13. fontTools/merge/cmap.py +33 -1
  14. fontTools/merge/tables.py +12 -1
  15. fontTools/misc/bezierTools.c +13668 -15551
  16. fontTools/misc/bezierTools.cpython-39-darwin.so +0 -0
  17. fontTools/misc/etree.py +4 -27
  18. fontTools/misc/loggingTools.py +1 -1
  19. fontTools/misc/symfont.py +6 -8
  20. fontTools/mtiLib/__init__.py +1 -3
  21. fontTools/otlLib/builder.py +359 -145
  22. fontTools/otlLib/optimize/gpos.py +42 -62
  23. fontTools/pens/momentsPen.c +4509 -4674
  24. fontTools/pens/momentsPen.cpython-39-darwin.so +0 -0
  25. fontTools/pens/pointPen.py +21 -12
  26. fontTools/pens/t2CharStringPen.py +31 -11
  27. fontTools/qu2cu/qu2cu.c +5746 -5465
  28. fontTools/qu2cu/qu2cu.cpython-39-darwin.so +0 -0
  29. fontTools/subset/__init__.py +12 -1
  30. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  31. fontTools/ttLib/tables/T_S_I__0.py +14 -3
  32. fontTools/ttLib/tables/T_S_I__5.py +16 -5
  33. fontTools/ttLib/tables/__init__.py +1 -0
  34. fontTools/ttLib/tables/_c_v_t.py +2 -0
  35. fontTools/ttLib/tables/_f_p_g_m.py +3 -1
  36. fontTools/ttLib/tables/_g_l_y_f.py +2 -6
  37. fontTools/ttLib/tables/_g_v_a_r.py +58 -15
  38. fontTools/ttLib/tables/_p_o_s_t.py +5 -2
  39. fontTools/ttLib/tables/otBase.py +1 -0
  40. fontTools/ufoLib/__init__.py +3 -3
  41. fontTools/ufoLib/converters.py +89 -25
  42. fontTools/ufoLib/errors.py +8 -0
  43. fontTools/ufoLib/etree.py +1 -1
  44. fontTools/ufoLib/filenames.py +155 -100
  45. fontTools/ufoLib/glifLib.py +9 -2
  46. fontTools/ufoLib/kerning.py +66 -36
  47. fontTools/ufoLib/utils.py +5 -2
  48. fontTools/unicodedata/Mirrored.py +446 -0
  49. fontTools/unicodedata/__init__.py +6 -2
  50. fontTools/varLib/__init__.py +20 -6
  51. fontTools/varLib/featureVars.py +13 -7
  52. fontTools/varLib/hvar.py +1 -1
  53. fontTools/varLib/instancer/__init__.py +14 -5
  54. fontTools/varLib/iup.c +6851 -6363
  55. fontTools/varLib/iup.cpython-39-darwin.so +0 -0
  56. fontTools/voltLib/__main__.py +206 -0
  57. fontTools/voltLib/ast.py +4 -0
  58. fontTools/voltLib/parser.py +16 -8
  59. fontTools/voltLib/voltToFea.py +347 -166
  60. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/METADATA +64 -11
  61. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/RECORD +67 -63
  62. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/WHEEL +1 -1
  63. fonttools-4.58.1.dist-info/licenses/LICENSE.external +359 -0
  64. {fonttools-4.57.0.data → fonttools-4.58.1.data}/data/share/man/man1/ttx.1 +0 -0
  65. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/entry_points.txt +0 -0
  66. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/licenses/LICENSE +0 -0
  67. {fonttools-4.57.0.dist-info → fonttools-4.58.1.dist-info}/top_level.txt +0 -0
Binary file
@@ -0,0 +1,206 @@
1
+ import argparse
2
+ import logging
3
+ import sys
4
+ from io import StringIO
5
+ from pathlib import Path
6
+
7
+ from fontTools import configLogger
8
+ from fontTools.feaLib.builder import addOpenTypeFeaturesFromString
9
+ from fontTools.feaLib.error import FeatureLibError
10
+ from fontTools.feaLib.lexer import Lexer
11
+ from fontTools.misc.cliTools import makeOutputFileName
12
+ from fontTools.ttLib import TTFont, TTLibError
13
+ from fontTools.voltLib.parser import Parser
14
+ from fontTools.voltLib.voltToFea import TABLES, VoltToFea
15
+
16
+ log = logging.getLogger("fontTools.feaLib")
17
+
18
+ SUPPORTED_TABLES = TABLES + ["cmap"]
19
+
20
+
21
+ def invalid_fea_glyph_name(name):
22
+ """Check if the glyph name is valid according to FEA syntax."""
23
+ if name[0] not in Lexer.CHAR_NAME_START_:
24
+ return True
25
+ if any(c not in Lexer.CHAR_NAME_CONTINUATION_ for c in name[1:]):
26
+ return True
27
+ return False
28
+
29
+
30
+ def sanitize_glyph_name(name):
31
+ """Sanitize the glyph name to ensure it is valid according to FEA syntax."""
32
+ sanitized = ""
33
+ for i, c in enumerate(name):
34
+ if i == 0 and c not in Lexer.CHAR_NAME_START_:
35
+ sanitized += "a" + c
36
+ elif c not in Lexer.CHAR_NAME_CONTINUATION_:
37
+ sanitized += "_"
38
+ else:
39
+ sanitized += c
40
+
41
+ return sanitized
42
+
43
+
44
+ def main(args=None):
45
+ """Build tables from a MS VOLT project into an OTF font"""
46
+ parser = argparse.ArgumentParser(
47
+ description="Use fontTools to compile MS VOLT projects."
48
+ )
49
+ parser.add_argument(
50
+ "input",
51
+ metavar="INPUT",
52
+ help="Path to the input font/VTP file to process",
53
+ type=Path,
54
+ )
55
+ parser.add_argument(
56
+ "-f",
57
+ "--font",
58
+ metavar="INPUT_FONT",
59
+ help="Path to the input font (if INPUT is a VTP file)",
60
+ type=Path,
61
+ )
62
+ parser.add_argument(
63
+ "-o",
64
+ "--output",
65
+ dest="output",
66
+ metavar="OUTPUT",
67
+ help="Path to the output font.",
68
+ type=Path,
69
+ )
70
+ parser.add_argument(
71
+ "-t",
72
+ "--tables",
73
+ metavar="TABLE_TAG",
74
+ choices=SUPPORTED_TABLES,
75
+ nargs="+",
76
+ help="Specify the table(s) to be built.",
77
+ )
78
+ parser.add_argument(
79
+ "-F",
80
+ "--debug-feature-file",
81
+ help="Write the generated feature file to disk.",
82
+ action="store_true",
83
+ )
84
+ parser.add_argument(
85
+ "--ship",
86
+ help="Remove source VOLT tables from output font.",
87
+ action="store_true",
88
+ )
89
+ parser.add_argument(
90
+ "-v",
91
+ "--verbose",
92
+ help="Increase the logger verbosity. Multiple -v options are allowed.",
93
+ action="count",
94
+ default=0,
95
+ )
96
+ parser.add_argument(
97
+ "-T",
98
+ "--traceback",
99
+ help="show traceback for exceptions.",
100
+ action="store_true",
101
+ )
102
+ options = parser.parse_args(args)
103
+
104
+ levels = ["WARNING", "INFO", "DEBUG"]
105
+ configLogger(level=levels[min(len(levels) - 1, options.verbose)])
106
+
107
+ output_font = options.output or Path(
108
+ makeOutputFileName(options.font or options.input)
109
+ )
110
+ log.info(f"Compiling MS VOLT to '{output_font}'")
111
+
112
+ file_or_path = options.input
113
+ font = None
114
+
115
+ # If the input is a font file, extract the VOLT data from the "TSIV" table
116
+ try:
117
+ font = TTFont(file_or_path)
118
+ if "TSIV" in font:
119
+ file_or_path = StringIO(font["TSIV"].data.decode("utf-8"))
120
+ else:
121
+ log.error('"TSIV" table is missing')
122
+ return 1
123
+ except TTLibError:
124
+ pass
125
+
126
+ # If input is not a font file, the font must be provided
127
+ if font is None:
128
+ if not options.font:
129
+ log.error("Please provide an input font")
130
+ return 1
131
+ font = TTFont(options.font)
132
+
133
+ # FEA syntax does not allow some glyph names that VOLT accepts, so if we
134
+ # found such glyph name we will temporarily rename such glyphs.
135
+ glyphOrder = font.getGlyphOrder()
136
+ tempGlyphOrder = None
137
+ if any(invalid_fea_glyph_name(n) for n in glyphOrder):
138
+ tempGlyphOrder = []
139
+ for n in glyphOrder:
140
+ if invalid_fea_glyph_name(n):
141
+ n = sanitize_glyph_name(n)
142
+ existing = set(tempGlyphOrder) | set(glyphOrder)
143
+ while n in existing:
144
+ n = "a" + n
145
+ tempGlyphOrder.append(n)
146
+ font.setGlyphOrder(tempGlyphOrder)
147
+
148
+ doc = Parser(file_or_path).parse()
149
+
150
+ log.info("Converting VTP data to FEA")
151
+ converter = VoltToFea(doc, font)
152
+ try:
153
+ fea = converter.convert(options.tables, ignore_unsupported_settings=True)
154
+ except NotImplementedError as e:
155
+ if options.traceback:
156
+ raise
157
+ location = getattr(e.args[0], "location", None)
158
+ message = f'"{e}" is not supported'
159
+ if location:
160
+ path, line, column = location
161
+ log.error(f"{path}:{line}:{column}: {message}")
162
+ else:
163
+ log.error(message)
164
+ return 1
165
+
166
+ fea_filename = options.input
167
+ if options.debug_feature_file:
168
+ fea_filename = output_font.with_suffix(".fea")
169
+ log.info(f"Writing FEA to '{fea_filename}'")
170
+ with open(fea_filename, "w") as fp:
171
+ fp.write(fea)
172
+
173
+ log.info("Compiling FEA to OpenType tables")
174
+ try:
175
+ addOpenTypeFeaturesFromString(
176
+ font,
177
+ fea,
178
+ filename=fea_filename,
179
+ tables=options.tables,
180
+ )
181
+ except FeatureLibError as e:
182
+ if options.traceback:
183
+ raise
184
+ log.error(e)
185
+ return 1
186
+
187
+ if options.ship:
188
+ for tag in ["TSIV", "TSIS", "TSIP", "TSID"]:
189
+ if tag in font:
190
+ del font[tag]
191
+
192
+ # Restore original glyph names.
193
+ if tempGlyphOrder:
194
+ import io
195
+
196
+ f = io.BytesIO()
197
+ font.save(f)
198
+ font = TTFont(f)
199
+ font.setGlyphOrder(glyphOrder)
200
+ font["post"].extraNames = []
201
+
202
+ font.save(output_font)
203
+
204
+
205
+ if __name__ == "__main__":
206
+ sys.exit(main())
fontTools/voltLib/ast.py CHANGED
@@ -317,6 +317,10 @@ class SubstitutionLigatureDefinition(SubstitutionDefinition):
317
317
  pass
318
318
 
319
319
 
320
+ class SubstitutionAlternateDefinition(SubstitutionDefinition):
321
+ pass
322
+
323
+
320
324
  class SubstitutionReverseChainingSingleDefinition(SubstitutionDefinition):
321
325
  pass
322
326
 
@@ -313,19 +313,27 @@ class Parser(object):
313
313
  self.expect_keyword_("END_SUBSTITUTION")
314
314
  max_src = max([len(cov) for cov in src])
315
315
  max_dest = max([len(cov) for cov in dest])
316
+
316
317
  # many to many or mixed is invalid
317
- if (max_src > 1 and max_dest > 1) or (
318
- reversal and (max_src > 1 or max_dest > 1)
319
- ):
318
+ if max_src > 1 and max_dest > 1:
320
319
  raise VoltLibError("Invalid substitution type", location)
320
+
321
321
  mapping = dict(zip(tuple(src), tuple(dest)))
322
322
  if max_src == 1 and max_dest == 1:
323
- if reversal:
324
- sub = ast.SubstitutionReverseChainingSingleDefinition(
325
- mapping, location=location
326
- )
323
+ # Alternate substitutions are represented by adding multiple
324
+ # substitutions for the same glyph, so we detect that here
325
+ glyphs = [x.glyphSet() for cov in src for x in cov] # flatten src
326
+ if len(set(glyphs)) != len(glyphs): # src has duplicates
327
+ sub = ast.SubstitutionAlternateDefinition(mapping, location=location)
327
328
  else:
328
- sub = ast.SubstitutionSingleDefinition(mapping, location=location)
329
+ if reversal:
330
+ # Reversal is valid only for single glyph substitutions
331
+ # and VOLT ignores it otherwise.
332
+ sub = ast.SubstitutionReverseChainingSingleDefinition(
333
+ mapping, location=location
334
+ )
335
+ else:
336
+ sub = ast.SubstitutionSingleDefinition(mapping, location=location)
329
337
  elif max_src == 1 and max_dest > 1:
330
338
  sub = ast.SubstitutionMultipleDefinition(mapping, location=location)
331
339
  elif max_src > 1 and max_dest == 1: