fonttools 4.56.0__cp312-cp312-win32.whl → 4.58.0__cp312-cp312-win32.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 (71) hide show
  1. fontTools/__init__.py +1 -1
  2. fontTools/cffLib/__init__.py +61 -26
  3. fontTools/config/__init__.py +15 -0
  4. fontTools/cu2qu/cu2qu.c +15345 -14829
  5. fontTools/cu2qu/cu2qu.cp312-win32.pyd +0 -0
  6. fontTools/designspaceLib/statNames.py +14 -7
  7. fontTools/feaLib/ast.py +92 -13
  8. fontTools/feaLib/builder.py +52 -13
  9. fontTools/feaLib/lexer.c +17143 -17986
  10. fontTools/feaLib/lexer.cp312-win32.pyd +0 -0
  11. fontTools/feaLib/parser.py +59 -39
  12. fontTools/fontBuilder.py +6 -0
  13. fontTools/misc/bezierTools.c +39936 -41831
  14. fontTools/misc/bezierTools.cp312-win32.pyd +0 -0
  15. fontTools/misc/etree.py +4 -27
  16. fontTools/misc/testTools.py +2 -1
  17. fontTools/mtiLib/__init__.py +0 -2
  18. fontTools/otlLib/builder.py +195 -145
  19. fontTools/otlLib/optimize/gpos.py +49 -63
  20. fontTools/pens/momentsPen.c +13266 -13448
  21. fontTools/pens/momentsPen.cp312-win32.pyd +0 -0
  22. fontTools/pens/pointPen.py +21 -12
  23. fontTools/qu2cu/qu2cu.c +16538 -16269
  24. fontTools/qu2cu/qu2cu.cp312-win32.pyd +0 -0
  25. fontTools/subset/__init__.py +11 -0
  26. fontTools/ttLib/__init__.py +4 -0
  27. fontTools/ttLib/__main__.py +47 -8
  28. fontTools/ttLib/tables/D__e_b_g.py +20 -2
  29. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  30. fontTools/ttLib/tables/T_S_I__0.py +14 -3
  31. fontTools/ttLib/tables/T_S_I__5.py +16 -5
  32. fontTools/ttLib/tables/__init__.py +1 -0
  33. fontTools/ttLib/tables/_c_m_a_p.py +19 -6
  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 +11 -10
  37. fontTools/ttLib/tables/_g_v_a_r.py +62 -17
  38. fontTools/ttLib/tables/_p_o_s_t.py +5 -2
  39. fontTools/ttLib/tables/otBase.py +1 -0
  40. fontTools/ttLib/tables/otConverters.py +5 -2
  41. fontTools/ttLib/tables/otTables.py +5 -1
  42. fontTools/ttLib/ttFont.py +3 -5
  43. fontTools/ttLib/ttGlyphSet.py +0 -10
  44. fontTools/ttx.py +13 -1
  45. fontTools/ufoLib/__init__.py +2 -2
  46. fontTools/ufoLib/converters.py +89 -25
  47. fontTools/ufoLib/errors.py +8 -0
  48. fontTools/ufoLib/etree.py +1 -1
  49. fontTools/ufoLib/filenames.py +155 -100
  50. fontTools/ufoLib/glifLib.py +9 -2
  51. fontTools/ufoLib/kerning.py +66 -36
  52. fontTools/ufoLib/utils.py +5 -2
  53. fontTools/unicodedata/Mirrored.py +446 -0
  54. fontTools/unicodedata/__init__.py +6 -2
  55. fontTools/varLib/__init__.py +94 -89
  56. fontTools/varLib/hvar.py +113 -0
  57. fontTools/varLib/iup.c +19630 -19154
  58. fontTools/varLib/iup.cp312-win32.pyd +0 -0
  59. fontTools/varLib/varStore.py +1 -1
  60. fontTools/voltLib/__main__.py +206 -0
  61. fontTools/voltLib/ast.py +4 -0
  62. fontTools/voltLib/parser.py +16 -8
  63. fontTools/voltLib/voltToFea.py +347 -166
  64. {fonttools-4.56.0.dist-info → fonttools-4.58.0.dist-info}/METADATA +60 -12
  65. {fonttools-4.56.0.dist-info → fonttools-4.58.0.dist-info}/RECORD +71 -66
  66. {fonttools-4.56.0.dist-info → fonttools-4.58.0.dist-info}/WHEEL +1 -1
  67. fonttools-4.58.0.dist-info/licenses/LICENSE.external +359 -0
  68. {fonttools-4.56.0.data → fonttools-4.58.0.data}/data/share/man/man1/ttx.1 +0 -0
  69. {fonttools-4.56.0.dist-info → fonttools-4.58.0.dist-info}/entry_points.txt +0 -0
  70. {fonttools-4.56.0.dist-info → fonttools-4.58.0.dist-info/licenses}/LICENSE +0 -0
  71. {fonttools-4.56.0.dist-info → fonttools-4.58.0.dist-info}/top_level.txt +0 -0
Binary file
@@ -1286,6 +1286,19 @@ class Parser(object):
1286
1286
  n = match.group(0)[1:]
1287
1287
  return bytechr(int(n, 16)).decode(encoding)
1288
1288
 
1289
+ def find_previous(self, statements, class_):
1290
+ for previous in reversed(statements):
1291
+ if isinstance(previous, self.ast.Comment):
1292
+ continue
1293
+ elif isinstance(previous, class_):
1294
+ return previous
1295
+ else:
1296
+ # If we find something that doesn't match what we're looking
1297
+ # for, and isn't a comment, fail
1298
+ return None
1299
+ # Out of statements to look at
1300
+ return None
1301
+
1289
1302
  def parse_table_BASE_(self, table):
1290
1303
  statements = table.statements
1291
1304
  while self.next_token_ != "}" or self.cur_comments_:
@@ -1306,6 +1319,19 @@ class Parser(object):
1306
1319
  location=self.cur_token_location_,
1307
1320
  )
1308
1321
  )
1322
+ elif self.is_cur_keyword_("HorizAxis.MinMax"):
1323
+ base_script_list = self.find_previous(statements, ast.BaseAxis)
1324
+ if base_script_list is None:
1325
+ raise FeatureLibError(
1326
+ "MinMax must be preceded by BaseScriptList",
1327
+ self.cur_token_location_,
1328
+ )
1329
+ if base_script_list.vertical:
1330
+ raise FeatureLibError(
1331
+ "HorizAxis.MinMax must be preceded by HorizAxis statements",
1332
+ self.cur_token_location_,
1333
+ )
1334
+ base_script_list.minmax.append(self.parse_base_minmax_())
1309
1335
  elif self.is_cur_keyword_("VertAxis.BaseTagList"):
1310
1336
  vert_bases = self.parse_base_tag_list_()
1311
1337
  elif self.is_cur_keyword_("VertAxis.BaseScriptList"):
@@ -1318,6 +1344,19 @@ class Parser(object):
1318
1344
  location=self.cur_token_location_,
1319
1345
  )
1320
1346
  )
1347
+ elif self.is_cur_keyword_("VertAxis.MinMax"):
1348
+ base_script_list = self.find_previous(statements, ast.BaseAxis)
1349
+ if base_script_list is None:
1350
+ raise FeatureLibError(
1351
+ "MinMax must be preceded by BaseScriptList",
1352
+ self.cur_token_location_,
1353
+ )
1354
+ if not base_script_list.vertical:
1355
+ raise FeatureLibError(
1356
+ "VertAxis.MinMax must be preceded by VertAxis statements",
1357
+ self.cur_token_location_,
1358
+ )
1359
+ base_script_list.minmax.append(self.parse_base_minmax_())
1321
1360
  elif self.cur_token_ == ";":
1322
1361
  continue
1323
1362
 
@@ -1574,7 +1613,7 @@ class Parser(object):
1574
1613
  "HorizAxis.BaseScriptList",
1575
1614
  "VertAxis.BaseScriptList",
1576
1615
  ), self.cur_token_
1577
- scripts = [(self.parse_base_script_record_(count))]
1616
+ scripts = [self.parse_base_script_record_(count)]
1578
1617
  while self.next_token_ == ",":
1579
1618
  self.expect_symbol_(",")
1580
1619
  scripts.append(self.parse_base_script_record_(count))
@@ -1587,6 +1626,25 @@ class Parser(object):
1587
1626
  coords = [self.expect_number_() for i in range(count)]
1588
1627
  return script_tag, base_tag, coords
1589
1628
 
1629
+ def parse_base_minmax_(self):
1630
+ script_tag = self.expect_script_tag_()
1631
+ language = self.expect_language_tag_()
1632
+ min_coord = self.expect_number_()
1633
+ self.advance_lexer_()
1634
+ if not (self.cur_token_type_ is Lexer.SYMBOL and self.cur_token_ == ","):
1635
+ raise FeatureLibError(
1636
+ "Expected a comma between min and max coordinates",
1637
+ self.cur_token_location_,
1638
+ )
1639
+ max_coord = self.expect_number_()
1640
+ if self.next_token_ == ",": # feature tag...
1641
+ raise FeatureLibError(
1642
+ "Feature tags are not yet supported in BASE table",
1643
+ self.cur_token_location_,
1644
+ )
1645
+
1646
+ return script_tag, language, min_coord, max_coord
1647
+
1590
1648
  def parse_device_(self):
1591
1649
  result = None
1592
1650
  self.expect_symbol_("<")
@@ -2004,44 +2062,6 @@ class Parser(object):
2004
2062
  )
2005
2063
  self.expect_symbol_(";")
2006
2064
 
2007
- # A multiple substitution may have a single destination, in which case
2008
- # it will look just like a single substitution. So if there are both
2009
- # multiple and single substitutions, upgrade all the single ones to
2010
- # multiple substitutions.
2011
-
2012
- # Check if we have a mix of non-contextual singles and multiples.
2013
- has_single = False
2014
- has_multiple = False
2015
- for s in statements:
2016
- if isinstance(s, self.ast.SingleSubstStatement):
2017
- has_single = not any([s.prefix, s.suffix, s.forceChain])
2018
- elif isinstance(s, self.ast.MultipleSubstStatement):
2019
- has_multiple = not any([s.prefix, s.suffix, s.forceChain])
2020
-
2021
- # Upgrade all single substitutions to multiple substitutions.
2022
- if has_single and has_multiple:
2023
- statements = []
2024
- for s in block.statements:
2025
- if isinstance(s, self.ast.SingleSubstStatement):
2026
- glyphs = s.glyphs[0].glyphSet()
2027
- replacements = s.replacements[0].glyphSet()
2028
- if len(replacements) == 1:
2029
- replacements *= len(glyphs)
2030
- for i, glyph in enumerate(glyphs):
2031
- statements.append(
2032
- self.ast.MultipleSubstStatement(
2033
- s.prefix,
2034
- glyph,
2035
- s.suffix,
2036
- [replacements[i]],
2037
- s.forceChain,
2038
- location=s.location,
2039
- )
2040
- )
2041
- else:
2042
- statements.append(s)
2043
- block.statements = statements
2044
-
2045
2065
  def is_cur_keyword_(self, k):
2046
2066
  if self.cur_token_type_ is Lexer.NAME:
2047
2067
  if isinstance(k, type("")): # basestring is gone in Python3
fontTools/fontBuilder.py CHANGED
@@ -714,6 +714,12 @@ class FontBuilder(object):
714
714
  gvar.reserved = 0
715
715
  gvar.variations = variations
716
716
 
717
+ def setupGVAR(self, variations):
718
+ gvar = self.font["GVAR"] = newTable("GVAR")
719
+ gvar.version = 1
720
+ gvar.reserved = 0
721
+ gvar.variations = variations
722
+
717
723
  def calcGlyphBounds(self):
718
724
  """Calculate the bounding boxes of all glyphs in the `glyf` table.
719
725
  This is usually not called explicitly by client code.