fonttools 4.56.0__py3-none-any.whl → 4.57.0__py3-none-any.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 CHANGED
@@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger
3
3
 
4
4
  log = logging.getLogger(__name__)
5
5
 
6
- version = __version__ = "4.56.0"
6
+ version = __version__ = "4.57.0"
7
7
 
8
8
  __all__ = ["version", "log", "configLogger"]
@@ -73,3 +73,18 @@ Config.register_option(
73
73
  parse=Option.parse_optional_bool,
74
74
  validate=Option.validate_optional_bool,
75
75
  )
76
+
77
+ Config.register_option(
78
+ name="fontTools.ttLib:OPTIMIZE_FONT_SPEED",
79
+ help=dedent(
80
+ """\
81
+ Enable optimizations that prioritize speed over file size. This
82
+ mainly affects how glyf table and gvar / VARC tables are compiled.
83
+ The produced fonts will be larger, but rendering performance will
84
+ be improved with HarfBuzz and other text layout engines.
85
+ """
86
+ ),
87
+ default=False,
88
+ parse=Option.parse_optional_bool,
89
+ validate=Option.validate_optional_bool,
90
+ )
fontTools/feaLib/ast.py CHANGED
@@ -1828,15 +1828,16 @@ class BaseAxis(Statement):
1828
1828
  """An axis definition, being either a ``VertAxis.BaseTagList/BaseScriptList``
1829
1829
  pair or a ``HorizAxis.BaseTagList/BaseScriptList`` pair."""
1830
1830
 
1831
- def __init__(self, bases, scripts, vertical, location=None):
1831
+ def __init__(self, bases, scripts, vertical, minmax=None, location=None):
1832
1832
  Statement.__init__(self, location)
1833
1833
  self.bases = bases #: A list of baseline tag names as strings
1834
1834
  self.scripts = scripts #: A list of script record tuplets (script tag, default baseline tag, base coordinate)
1835
1835
  self.vertical = vertical #: Boolean; VertAxis if True, HorizAxis if False
1836
+ self.minmax = [] #: A set of minmax record
1836
1837
 
1837
1838
  def build(self, builder):
1838
1839
  """Calls the builder object's ``set_base_axis`` callback."""
1839
- builder.set_base_axis(self.bases, self.scripts, self.vertical)
1840
+ builder.set_base_axis(self.bases, self.scripts, self.vertical, self.minmax)
1840
1841
 
1841
1842
  def asFea(self, indent=""):
1842
1843
  direction = "Vert" if self.vertical else "Horiz"
@@ -1844,9 +1845,13 @@ class BaseAxis(Statement):
1844
1845
  "{} {} {}".format(a[0], a[1], " ".join(map(str, a[2])))
1845
1846
  for a in self.scripts
1846
1847
  ]
1848
+ minmaxes = [
1849
+ "\n{}Axis.MinMax {} {} {}, {};".format(direction, a[0], a[1], a[2], a[3])
1850
+ for a in self.minmax
1851
+ ]
1847
1852
  return "{}Axis.BaseTagList {};\n{}{}Axis.BaseScriptList {};".format(
1848
1853
  direction, " ".join(self.bases), indent, direction, ", ".join(scripts)
1849
- )
1854
+ ) + "\n".join(minmaxes)
1850
1855
 
1851
1856
 
1852
1857
  class OS2Field(Statement):
@@ -341,6 +341,7 @@ class Builder(object):
341
341
  table = self.font["head"] = newTable("head")
342
342
  table.decompile(b"\0" * 54, self.font)
343
343
  table.tableVersion = 1.0
344
+ table.magicNumber = 0x5F0F3CF5
344
345
  table.created = table.modified = 3406620153 # 2011-12-13 11:22:33
345
346
  table.fontRevision = self.fontRevision_
346
347
 
@@ -727,10 +728,16 @@ class Builder(object):
727
728
  result.table = base
728
729
  return result
729
730
 
731
+ def buildBASECoord(self, c):
732
+ coord = otTables.BaseCoord()
733
+ coord.Format = 1
734
+ coord.Coordinate = c
735
+ return coord
736
+
730
737
  def buildBASEAxis(self, axis):
731
738
  if not axis:
732
739
  return
733
- bases, scripts = axis
740
+ bases, scripts, minmax = axis
734
741
  axis = otTables.Axis()
735
742
  axis.BaseTagList = otTables.BaseTagList()
736
743
  axis.BaseTagList.BaselineTag = bases
@@ -739,19 +746,35 @@ class Builder(object):
739
746
  axis.BaseScriptList.BaseScriptRecord = []
740
747
  axis.BaseScriptList.BaseScriptCount = len(scripts)
741
748
  for script in sorted(scripts):
749
+ minmax_for_script = [
750
+ record[1:] for record in minmax if record[0] == script[0]
751
+ ]
742
752
  record = otTables.BaseScriptRecord()
743
753
  record.BaseScriptTag = script[0]
744
754
  record.BaseScript = otTables.BaseScript()
745
- record.BaseScript.BaseLangSysCount = 0
746
755
  record.BaseScript.BaseValues = otTables.BaseValues()
747
756
  record.BaseScript.BaseValues.DefaultIndex = bases.index(script[1])
748
757
  record.BaseScript.BaseValues.BaseCoord = []
749
758
  record.BaseScript.BaseValues.BaseCoordCount = len(script[2])
759
+ record.BaseScript.BaseLangSysRecord = []
760
+
750
761
  for c in script[2]:
751
- coord = otTables.BaseCoord()
752
- coord.Format = 1
753
- coord.Coordinate = c
754
- record.BaseScript.BaseValues.BaseCoord.append(coord)
762
+ record.BaseScript.BaseValues.BaseCoord.append(self.buildBASECoord(c))
763
+ for language, min_coord, max_coord in minmax_for_script:
764
+ minmax_record = otTables.MinMax()
765
+ minmax_record.MinCoord = self.buildBASECoord(min_coord)
766
+ minmax_record.MaxCoord = self.buildBASECoord(max_coord)
767
+ minmax_record.FeatMinMaxCount = 0
768
+ if language == "dflt":
769
+ record.BaseScript.DefaultMinMax = minmax_record
770
+ else:
771
+ lang_record = otTables.BaseLangSysRecord()
772
+ lang_record.BaseLangSysTag = language
773
+ lang_record.MinMax = minmax_record
774
+ record.BaseScript.BaseLangSysRecord.append(lang_record)
775
+ record.BaseScript.BaseLangSysCount = len(
776
+ record.BaseScript.BaseLangSysRecord
777
+ )
755
778
  axis.BaseScriptList.BaseScriptRecord.append(record)
756
779
  return axis
757
780
 
@@ -1235,11 +1258,11 @@ class Builder(object):
1235
1258
  def add_cv_character(self, character, tag):
1236
1259
  self.cv_characters_[tag].append(character)
1237
1260
 
1238
- def set_base_axis(self, bases, scripts, vertical):
1261
+ def set_base_axis(self, bases, scripts, vertical, minmax=[]):
1239
1262
  if vertical:
1240
- self.base_vert_axis_ = (bases, scripts)
1263
+ self.base_vert_axis_ = (bases, scripts, minmax)
1241
1264
  else:
1242
- self.base_horiz_axis_ = (bases, scripts)
1265
+ self.base_horiz_axis_ = (bases, scripts, minmax)
1243
1266
 
1244
1267
  def set_size_parameters(
1245
1268
  self, location, DesignSize, SubfamilyID, RangeStart, RangeEnd
@@ -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
 
@@ -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_("<")
@@ -46,7 +46,8 @@ def parseXmlInto(font, parseInto, xmlSnippet):
46
46
  parsed_xml = [e for e in parseXML(xmlSnippet.strip()) if not isinstance(e, str)]
47
47
  for name, attrs, content in parsed_xml:
48
48
  parseInto.fromXML(name, attrs, content, font)
49
- parseInto.populateDefaults()
49
+ if hasattr(parseInto, "populateDefaults"):
50
+ parseInto.populateDefaults()
50
51
  return parseInto
51
52
 
52
53
 
@@ -53,12 +53,18 @@ def compact(font: TTFont, level: int) -> TTFont:
53
53
  # are not grouped together first; instead each subtable is treated
54
54
  # independently, so currently this step is:
55
55
  # Split existing subtables into more smaller subtables
56
- gpos = font["GPOS"]
56
+ gpos = font.get("GPOS")
57
+
58
+ # If the font does not contain a GPOS table, there is nothing to do.
59
+ if gpos is None:
60
+ return font
61
+
57
62
  for lookup in gpos.table.LookupList.Lookup:
58
63
  if lookup.LookupType == 2:
59
64
  compact_lookup(font, level, lookup)
60
65
  elif lookup.LookupType == 9 and lookup.SubTable[0].ExtensionLookupType == 2:
61
66
  compact_ext_lookup(font, level, lookup)
67
+
62
68
  return font
63
69
 
64
70
 
@@ -1,5 +1,6 @@
1
1
  """fontTools.ttLib -- a package for dealing with TrueType fonts."""
2
2
 
3
+ from fontTools.config import OPTIONS
3
4
  from fontTools.misc.loggingTools import deprecateFunction
4
5
  import logging
5
6
 
@@ -7,6 +8,9 @@ import logging
7
8
  log = logging.getLogger(__name__)
8
9
 
9
10
 
11
+ OPTIMIZE_FONT_SPEED = OPTIONS["fontTools.ttLib:OPTIMIZE_FONT_SPEED"]
12
+
13
+
10
14
  class TTLibError(Exception):
11
15
  pass
12
16
 
@@ -1,5 +1,5 @@
1
1
  import sys
2
- from fontTools.ttLib import TTLibError, TTLibFileIsCollectionError
2
+ from fontTools.ttLib import OPTIMIZE_FONT_SPEED, TTLibError, TTLibFileIsCollectionError
3
3
  from fontTools.ttLib.ttFont import *
4
4
  from fontTools.ttLib.ttCollection import TTCollection
5
5
 
@@ -51,7 +51,7 @@ def main(args=None):
51
51
  )
52
52
  parser.add_argument("font", metavar="font", nargs="*", help="Font file.")
53
53
  parser.add_argument(
54
- "-t", "--table", metavar="table", nargs="*", help="Tables to decompile."
54
+ "-t", "--table", metavar="table", action="append", help="Tables to decompile."
55
55
  )
56
56
  parser.add_argument(
57
57
  "-o", "--output", metavar="FILE", default=None, help="Output file."
@@ -71,27 +71,66 @@ def main(args=None):
71
71
  default=None,
72
72
  help="Flavor of output font. 'woff' or 'woff2'.",
73
73
  )
74
+ parser.add_argument(
75
+ "--no-recalc-timestamp",
76
+ dest="recalcTimestamp",
77
+ action="store_false",
78
+ help="Keep the original font 'modified' timestamp.",
79
+ )
80
+ parser.add_argument(
81
+ "-b",
82
+ dest="recalcBBoxes",
83
+ action="store_false",
84
+ help="Don't recalc glyph bounding boxes: use the values in the original font.",
85
+ )
86
+ parser.add_argument(
87
+ "--optimize-font-speed",
88
+ action="store_true",
89
+ help=(
90
+ "Enable optimizations that prioritize speed over file size. This "
91
+ "mainly affects how glyf table and gvar / VARC tables are compiled."
92
+ ),
93
+ )
74
94
  options = parser.parse_args(args)
75
95
 
76
96
  fontNumber = int(options.y) if options.y is not None else None
77
97
  outFile = options.output
78
98
  lazy = options.lazy
79
99
  flavor = options.flavor
80
- tables = options.table if options.table is not None else ["*"]
100
+ tables = options.table
101
+ recalcBBoxes = options.recalcBBoxes
102
+ recalcTimestamp = options.recalcTimestamp
103
+ optimizeFontSpeed = options.optimize_font_speed
81
104
 
82
105
  fonts = []
83
106
  for f in options.font:
84
107
  try:
85
- font = TTFont(f, fontNumber=fontNumber, lazy=lazy)
108
+ font = TTFont(
109
+ f,
110
+ recalcBBoxes=recalcBBoxes,
111
+ recalcTimestamp=recalcTimestamp,
112
+ fontNumber=fontNumber,
113
+ lazy=lazy,
114
+ )
115
+ if optimizeFontSpeed:
116
+ font.cfg[OPTIMIZE_FONT_SPEED] = optimizeFontSpeed
86
117
  fonts.append(font)
87
118
  except TTLibFileIsCollectionError:
88
119
  collection = TTCollection(f, lazy=lazy)
89
120
  fonts.extend(collection.fonts)
90
121
 
91
- if lazy is False:
92
- for font in fonts:
93
- for table in tables if "*" not in tables else font.keys():
94
- font[table] # Decompiles
122
+ if tables is None:
123
+ if lazy is False:
124
+ tables = ["*"]
125
+ elif optimizeFontSpeed:
126
+ tables = {"glyf", "gvar", "VARC"}.intersection(font.keys())
127
+ else:
128
+ tables = []
129
+ for font in fonts:
130
+ if "GlyphOrder" in tables:
131
+ font.getGlyphOrder()
132
+ for table in tables if "*" not in tables else font.keys():
133
+ font[table] # Decompiles
95
134
 
96
135
  if outFile is not None:
97
136
  if len(fonts) == 1:
@@ -1,9 +1,15 @@
1
1
  import json
2
+ from textwrap import indent
2
3
 
3
4
  from . import DefaultTable
5
+ from fontTools.misc.textTools import tostr
4
6
 
5
7
 
6
8
  class table_D__e_b_g(DefaultTable.DefaultTable):
9
+ def __init__(self, tag=None):
10
+ DefaultTable.DefaultTable.__init__(self, tag)
11
+ self.data = {}
12
+
7
13
  def decompile(self, data, ttFont):
8
14
  self.data = json.loads(data)
9
15
 
@@ -11,7 +17,19 @@ class table_D__e_b_g(DefaultTable.DefaultTable):
11
17
  return json.dumps(self.data).encode("utf-8")
12
18
 
13
19
  def toXML(self, writer, ttFont):
14
- writer.writecdata(json.dumps(self.data, indent=2))
20
+ # make sure json indentation inside CDATA block matches XMLWriter's
21
+ data = json.dumps(self.data, indent=len(writer.indentwhite))
22
+ prefix = tostr(writer.indentwhite) * (writer.indentlevel + 1)
23
+ # but don't indent the first json line so it's adjacent to `<![CDATA[{`
24
+ cdata = indent(data, prefix, lambda ln: ln != "{\n")
25
+
26
+ writer.begintag("json")
27
+ writer.newline()
28
+ writer.writecdata(cdata)
29
+ writer.newline()
30
+ writer.endtag("json")
31
+ writer.newline()
15
32
 
16
33
  def fromXML(self, name, attrs, content, ttFont):
17
- self.data = json.loads(content)
34
+ if name == "json":
35
+ self.data = json.loads("".join(content))
@@ -141,6 +141,17 @@ class table__c_m_a_p(DefaultTable.DefaultTable):
141
141
  result.setdefault(name, set()).add(codepoint)
142
142
  return result
143
143
 
144
+ def buildReversedMin(self):
145
+ result = {}
146
+ for subtable in self.tables:
147
+ if subtable.isUnicode():
148
+ for codepoint, name in subtable.cmap.items():
149
+ if name in result:
150
+ result[name] = min(result[name], codepoint)
151
+ else:
152
+ result[name] = codepoint
153
+ return result
154
+
144
155
  def decompile(self, data, ttFont):
145
156
  tableVersion, numSubTables = struct.unpack(">HH", data[:4])
146
157
  self.tableVersion = int(tableVersion)
@@ -1162,13 +1173,15 @@ class cmap_format_12_or_13(CmapSubtable):
1162
1173
  charCodes = []
1163
1174
  gids = []
1164
1175
  pos = 0
1176
+ groups = array.array("I", data[: self.nGroups * 12])
1177
+ if sys.byteorder != "big":
1178
+ groups.byteswap()
1165
1179
  for i in range(self.nGroups):
1166
- startCharCode, endCharCode, glyphID = struct.unpack(
1167
- ">LLL", data[pos : pos + 12]
1168
- )
1169
- pos += 12
1180
+ startCharCode = groups[i * 3]
1181
+ endCharCode = groups[i * 3 + 1]
1182
+ glyphID = groups[i * 3 + 2]
1170
1183
  lenGroup = 1 + endCharCode - startCharCode
1171
- charCodes.extend(list(range(startCharCode, endCharCode + 1)))
1184
+ charCodes.extend(range(startCharCode, endCharCode + 1))
1172
1185
  gids.extend(self._computeGIDs(glyphID, lenGroup))
1173
1186
  self.data = data = None
1174
1187
  self.cmap = _make_map(self.ttFont, charCodes, gids)
@@ -1299,7 +1312,7 @@ class cmap_format_12(cmap_format_12_or_13):
1299
1312
  cmap_format_12_or_13.__init__(self, format)
1300
1313
 
1301
1314
  def _computeGIDs(self, startingGlyph, numberOfGlyphs):
1302
- return list(range(startingGlyph, startingGlyph + numberOfGlyphs))
1315
+ return range(startingGlyph, startingGlyph + numberOfGlyphs)
1303
1316
 
1304
1317
  def _IsInSameRun(self, glyphID, lastGlyphID, charCode, lastCharCode):
1305
1318
  return (glyphID == 1 + lastGlyphID) and (charCode == 1 + lastCharCode)
@@ -134,6 +134,8 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
134
134
  glyph.expand(self)
135
135
 
136
136
  def compile(self, ttFont):
137
+ optimizeSpeed = ttFont.cfg[ttLib.OPTIMIZE_FONT_SPEED]
138
+
137
139
  self.axisTags = (
138
140
  [axis.axisTag for axis in ttFont["fvar"].axes] if "fvar" in ttFont else []
139
141
  )
@@ -148,7 +150,12 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
148
150
  boundsDone = set()
149
151
  for glyphName in self.glyphOrder:
150
152
  glyph = self.glyphs[glyphName]
151
- glyphData = glyph.compile(self, recalcBBoxes, boundsDone=boundsDone)
153
+ glyphData = glyph.compile(
154
+ self,
155
+ recalcBBoxes,
156
+ boundsDone=boundsDone,
157
+ optimizeSize=not optimizeSpeed,
158
+ )
152
159
  if padding > 1:
153
160
  glyphData = pad(glyphData, size=padding)
154
161
  locations.append(currentLocation)
@@ -714,7 +721,7 @@ class Glyph(object):
714
721
  self.decompileCoordinates(data)
715
722
 
716
723
  def compile(
717
- self, glyfTable, recalcBBoxes=True, *, boundsDone=None, optimizeSize=None
724
+ self, glyfTable, recalcBBoxes=True, *, boundsDone=None, optimizeSize=True
718
725
  ):
719
726
  if hasattr(self, "data"):
720
727
  if recalcBBoxes:
@@ -732,8 +739,6 @@ class Glyph(object):
732
739
  if self.isComposite():
733
740
  data = data + self.compileComponents(glyfTable)
734
741
  else:
735
- if optimizeSize is None:
736
- optimizeSize = getattr(glyfTable, "optimizeSize", True)
737
742
  data = data + self.compileCoordinates(optimizeSize=optimizeSize)
738
743
  return data
739
744
 
@@ -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
@@ -57,6 +58,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
57
58
  self.variations = {}
58
59
 
59
60
  def compile(self, ttFont):
61
+
60
62
  axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
61
63
  sharedTuples = tv.compileSharedTuples(
62
64
  axisTags, itertools.chain(*self.variations.values())
@@ -91,9 +93,9 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
91
93
  return b"".join(result)
92
94
 
93
95
  def compileGlyphs_(self, ttFont, axisTags, sharedCoordIndices):
96
+ optimizeSpeed = ttFont.cfg[OPTIMIZE_FONT_SPEED]
94
97
  result = []
95
98
  glyf = ttFont["glyf"]
96
- optimizeSize = getattr(self, "optimizeSize", True)
97
99
  for glyphName in ttFont.getGlyphOrder():
98
100
  variations = self.variations.get(glyphName, [])
99
101
  if not variations:
@@ -106,7 +108,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
106
108
  pointCountUnused,
107
109
  axisTags,
108
110
  sharedCoordIndices,
109
- optimizeSize=optimizeSize,
111
+ optimizeSize=not optimizeSpeed,
110
112
  )
111
113
  )
112
114
  return result
@@ -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
- return bytes(TupleVariation.compileDeltaValues_(values))
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"])
@@ -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:
fontTools/ttLib/ttFont.py CHANGED
@@ -593,10 +593,8 @@ class TTFont(object):
593
593
  # temporary cmap and by the real cmap in case we don't find a unicode
594
594
  # cmap.
595
595
  numGlyphs = int(self["maxp"].numGlyphs)
596
- glyphOrder = [None] * numGlyphs
596
+ glyphOrder = ["glyph%.5d" % i for i in range(numGlyphs)]
597
597
  glyphOrder[0] = ".notdef"
598
- for i in range(1, numGlyphs):
599
- glyphOrder[i] = "glyph%.5d" % i
600
598
  # Set the glyph order, so the cmap parser has something
601
599
  # to work with (so we don't get called recursively).
602
600
  self.glyphOrder = glyphOrder
@@ -606,7 +604,7 @@ class TTFont(object):
606
604
  # this naming table will usually not cover all glyphs in the font.
607
605
  # If the font has no Unicode cmap table, reversecmap will be empty.
608
606
  if "cmap" in self:
609
- reversecmap = self["cmap"].buildReversed()
607
+ reversecmap = self["cmap"].buildReversedMin()
610
608
  else:
611
609
  reversecmap = {}
612
610
  useCount = {}
@@ -616,7 +614,7 @@ class TTFont(object):
616
614
  # If a font maps both U+0041 LATIN CAPITAL LETTER A and
617
615
  # U+0391 GREEK CAPITAL LETTER ALPHA to the same glyph,
618
616
  # we prefer naming the glyph as "A".
619
- glyphName = self._makeGlyphName(min(reversecmap[tempName]))
617
+ glyphName = self._makeGlyphName(reversecmap[tempName])
620
618
  numUses = useCount[glyphName] = useCount.get(glyphName, 0) + 1
621
619
  if numUses > 1:
622
620
  glyphName = "%s.alt%d" % (glyphName, numUses - 1)
@@ -104,16 +104,6 @@ class _TTGlyphSetGlyf(_TTGlyphSet):
104
104
  return _TTGlyphGlyf(self, glyphName, recalcBounds=self.recalcBounds)
105
105
 
106
106
 
107
- class _TTGlyphSetGlyf(_TTGlyphSet):
108
- def __init__(self, font, location, recalcBounds=True):
109
- self.glyfTable = font["glyf"]
110
- super().__init__(font, location, self.glyfTable, recalcBounds=recalcBounds)
111
- self.gvarTable = font.get("gvar")
112
-
113
- def __getitem__(self, glyphName):
114
- return _TTGlyphGlyf(self, glyphName, recalcBounds=self.recalcBounds)
115
-
116
-
117
107
  class _TTGlyphSetCFF(_TTGlyphSet):
118
108
  def __init__(self, font, location):
119
109
  tableTag = "CFF2" if "CFF2" in font else "CFF "
fontTools/ttx.py CHANGED
@@ -101,9 +101,15 @@ Compile options
101
101
  --with-zopfli
102
102
  Use Zopfli instead of Zlib to compress WOFF. The Python
103
103
  extension is available at https://pypi.python.org/pypi/zopfli
104
+ --optimize-font-speed
105
+ Enable optimizations that prioritize speed over file size.
106
+ This mainly affects how glyf t able and gvar / VARC tables are
107
+ compiled. The produced fonts will be larger, but rendering
108
+ performance will be improved with HarfBuzz and other text
109
+ layout engines.
104
110
  """
105
111
 
106
- from fontTools.ttLib import TTFont, TTLibError
112
+ from fontTools.ttLib import OPTIMIZE_FONT_SPEED, TTFont, TTLibError
107
113
  from fontTools.misc.macCreatorType import getMacCreatorAndType
108
114
  from fontTools.unicode import setUnicodeData
109
115
  from fontTools.misc.textTools import Tag, tostr
@@ -141,6 +147,7 @@ class Options(object):
141
147
  recalcTimestamp = None
142
148
  flavor = None
143
149
  useZopfli = False
150
+ optimizeFontSpeed = False
144
151
 
145
152
  def __init__(self, rawOptions, numFiles):
146
153
  self.onlyTables = []
@@ -229,6 +236,8 @@ class Options(object):
229
236
  self.flavor = value
230
237
  elif option == "--with-zopfli":
231
238
  self.useZopfli = True
239
+ elif option == "--optimize-font-speed":
240
+ self.optimizeFontSpeed = True
232
241
  if self.verbose and self.quiet:
233
242
  raise getopt.GetoptError("-q and -v options are mutually exclusive")
234
243
  if self.verbose:
@@ -324,6 +333,8 @@ def ttCompile(input, output, options):
324
333
  recalcBBoxes=options.recalcBBoxes,
325
334
  recalcTimestamp=options.recalcTimestamp,
326
335
  )
336
+ if options.optimizeFontSpeed:
337
+ ttf.cfg[OPTIMIZE_FONT_SPEED] = options.optimizeFontSpeed
327
338
  ttf.importXML(input)
328
339
 
329
340
  if options.recalcTimestamp is None and "head" in ttf and input is not sys.stdin:
@@ -386,6 +397,7 @@ def parseOptions(args):
386
397
  "version",
387
398
  "with-zopfli",
388
399
  "newline=",
400
+ "optimize-font-speed",
389
401
  ],
390
402
  )
391
403
 
@@ -12,13 +12,13 @@ a Glyphs source, eg., using noto-source as an example:
12
12
 
13
13
  .. code-block:: sh
14
14
 
15
- $ fontmake -o ttf-interpolatable -g NotoSansArabic-MM.glyphs
15
+ $ fontmake -o ttf-interpolatable -g NotoSansArabic-MM.glyphs
16
16
 
17
17
  Then you can make a variable-font this way:
18
18
 
19
19
  .. code-block:: sh
20
20
 
21
- $ fonttools varLib master_ufo/NotoSansArabic.designspace
21
+ $ fonttools varLib master_ufo/NotoSansArabic.designspace
22
22
 
23
23
  API *will* change in near future.
24
24
  """
@@ -479,7 +479,15 @@ def _merge_TTHinting(font, masterModel, master_ttfs):
479
479
 
480
480
  _MetricsFields = namedtuple(
481
481
  "_MetricsFields",
482
- ["tableTag", "metricsTag", "sb1", "sb2", "advMapping", "vOrigMapping"],
482
+ [
483
+ "tableTag",
484
+ "metricsTag",
485
+ "sb1",
486
+ "sb2",
487
+ "advMapping",
488
+ "vOrigMapping",
489
+ "phantomIndex",
490
+ ],
483
491
  )
484
492
 
485
493
  HVAR_FIELDS = _MetricsFields(
@@ -489,6 +497,7 @@ HVAR_FIELDS = _MetricsFields(
489
497
  sb2="RsbMap",
490
498
  advMapping="AdvWidthMap",
491
499
  vOrigMapping=None,
500
+ phantomIndex=0,
492
501
  )
493
502
 
494
503
  VVAR_FIELDS = _MetricsFields(
@@ -498,109 +507,43 @@ VVAR_FIELDS = _MetricsFields(
498
507
  sb2="BsbMap",
499
508
  advMapping="AdvHeightMap",
500
509
  vOrigMapping="VOrgMap",
510
+ phantomIndex=1,
501
511
  )
502
512
 
503
513
 
504
514
  def _add_HVAR(font, masterModel, master_ttfs, axisTags):
505
- _add_VHVAR(font, masterModel, master_ttfs, axisTags, HVAR_FIELDS)
515
+ getAdvanceMetrics = partial(
516
+ _get_advance_metrics, font, masterModel, master_ttfs, axisTags, HVAR_FIELDS
517
+ )
518
+ _add_VHVAR(font, axisTags, HVAR_FIELDS, getAdvanceMetrics)
506
519
 
507
520
 
508
521
  def _add_VVAR(font, masterModel, master_ttfs, axisTags):
509
- _add_VHVAR(font, masterModel, master_ttfs, axisTags, VVAR_FIELDS)
522
+ getAdvanceMetrics = partial(
523
+ _get_advance_metrics, font, masterModel, master_ttfs, axisTags, VVAR_FIELDS
524
+ )
525
+ _add_VHVAR(font, axisTags, VVAR_FIELDS, getAdvanceMetrics)
510
526
 
511
527
 
512
- def _add_VHVAR(font, masterModel, master_ttfs, axisTags, tableFields):
528
+ def _add_VHVAR(font, axisTags, tableFields, getAdvanceMetrics):
513
529
  tableTag = tableFields.tableTag
514
530
  assert tableTag not in font
531
+ glyphOrder = font.getGlyphOrder()
515
532
  log.info("Generating " + tableTag)
516
533
  VHVAR = newTable(tableTag)
517
534
  tableClass = getattr(ot, tableTag)
518
535
  vhvar = VHVAR.table = tableClass()
519
536
  vhvar.Version = 0x00010000
520
537
 
521
- glyphOrder = font.getGlyphOrder()
522
-
523
- # Build list of source font advance widths for each glyph
524
- metricsTag = tableFields.metricsTag
525
- advMetricses = [m[metricsTag].metrics for m in master_ttfs]
526
-
527
- # Build list of source font vertical origin coords for each glyph
528
- if tableTag == "VVAR" and "VORG" in master_ttfs[0]:
529
- vOrigMetricses = [m["VORG"].VOriginRecords for m in master_ttfs]
530
- defaultYOrigs = [m["VORG"].defaultVertOriginY for m in master_ttfs]
531
- vOrigMetricses = list(zip(vOrigMetricses, defaultYOrigs))
532
- else:
533
- vOrigMetricses = None
534
-
535
- metricsStore, advanceMapping, vOrigMapping = _get_advance_metrics(
536
- font,
537
- masterModel,
538
- master_ttfs,
539
- axisTags,
540
- glyphOrder,
541
- advMetricses,
542
- vOrigMetricses,
543
- )
538
+ vhAdvanceDeltasAndSupports, vOrigDeltasAndSupports = getAdvanceMetrics()
544
539
 
545
- vhvar.VarStore = metricsStore
546
- if advanceMapping is None:
547
- setattr(vhvar, tableFields.advMapping, None)
540
+ if vOrigDeltasAndSupports:
541
+ singleModel = False
548
542
  else:
549
- setattr(vhvar, tableFields.advMapping, advanceMapping)
550
- if vOrigMapping is not None:
551
- setattr(vhvar, tableFields.vOrigMapping, vOrigMapping)
552
- setattr(vhvar, tableFields.sb1, None)
553
- setattr(vhvar, tableFields.sb2, None)
554
-
555
- font[tableTag] = VHVAR
556
- return
557
-
558
-
559
- def _get_advance_metrics(
560
- font,
561
- masterModel,
562
- master_ttfs,
563
- axisTags,
564
- glyphOrder,
565
- advMetricses,
566
- vOrigMetricses=None,
567
- ):
568
- vhAdvanceDeltasAndSupports = {}
569
- vOrigDeltasAndSupports = {}
570
- # HACK: we treat width 65535 as a sentinel value to signal that a glyph
571
- # from a non-default master should not participate in computing {H,V}VAR,
572
- # as if it were missing. Allows to variate other glyph-related data independently
573
- # from glyph metrics
574
- sparse_advance = 0xFFFF
575
- for glyph in glyphOrder:
576
- vhAdvances = [
577
- (
578
- metrics[glyph][0]
579
- if glyph in metrics and metrics[glyph][0] != sparse_advance
580
- else None
581
- )
582
- for metrics in advMetricses
583
- ]
584
- vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
585
- vhAdvances, round=round
543
+ singleModel = models.allEqual(
544
+ id(v[1]) for v in vhAdvanceDeltasAndSupports.values()
586
545
  )
587
546
 
588
- singleModel = models.allEqual(id(v[1]) for v in vhAdvanceDeltasAndSupports.values())
589
-
590
- if vOrigMetricses:
591
- singleModel = False
592
- for glyph in glyphOrder:
593
- # We need to supply a vOrigs tuple with non-None default values
594
- # for each glyph. vOrigMetricses contains values only for those
595
- # glyphs which have a non-default vOrig.
596
- vOrigs = [
597
- metrics[glyph] if glyph in metrics else defaultVOrig
598
- for metrics, defaultVOrig in vOrigMetricses
599
- ]
600
- vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
601
- vOrigs, round=round
602
- )
603
-
604
547
  directStore = None
605
548
  if singleModel:
606
549
  # Build direct mapping
@@ -621,7 +564,7 @@ def _get_advance_metrics(
621
564
  storeBuilder.setSupports(supports)
622
565
  advMapping[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound)
623
566
 
624
- if vOrigMetricses:
567
+ if vOrigDeltasAndSupports:
625
568
  vOrigMap = {}
626
569
  for glyphName in glyphOrder:
627
570
  deltas, supports = vOrigDeltasAndSupports[glyphName]
@@ -633,7 +576,7 @@ def _get_advance_metrics(
633
576
  advMapping = [mapping2[advMapping[g]] for g in glyphOrder]
634
577
  advanceMapping = builder.buildVarIdxMap(advMapping, glyphOrder)
635
578
 
636
- if vOrigMetricses:
579
+ if vOrigDeltasAndSupports:
637
580
  vOrigMap = [mapping2[vOrigMap[g]] for g in glyphOrder]
638
581
 
639
582
  useDirect = False
@@ -657,10 +600,70 @@ def _get_advance_metrics(
657
600
  advanceMapping = None
658
601
  else:
659
602
  metricsStore = indirectStore
660
- if vOrigMetricses:
603
+ if vOrigDeltasAndSupports:
661
604
  vOrigMapping = builder.buildVarIdxMap(vOrigMap, glyphOrder)
662
605
 
663
- return metricsStore, advanceMapping, vOrigMapping
606
+ vhvar.VarStore = metricsStore
607
+ setattr(vhvar, tableFields.advMapping, advanceMapping)
608
+ if vOrigMapping is not None:
609
+ setattr(vhvar, tableFields.vOrigMapping, vOrigMapping)
610
+ setattr(vhvar, tableFields.sb1, None)
611
+ setattr(vhvar, tableFields.sb2, None)
612
+
613
+ font[tableTag] = VHVAR
614
+ return
615
+
616
+
617
+ def _get_advance_metrics(font, masterModel, master_ttfs, axisTags, tableFields):
618
+ tableTag = tableFields.tableTag
619
+ glyphOrder = font.getGlyphOrder()
620
+
621
+ # Build list of source font advance widths for each glyph
622
+ metricsTag = tableFields.metricsTag
623
+ advMetricses = [m[metricsTag].metrics for m in master_ttfs]
624
+
625
+ # Build list of source font vertical origin coords for each glyph
626
+ if tableTag == "VVAR" and "VORG" in master_ttfs[0]:
627
+ vOrigMetricses = [m["VORG"].VOriginRecords for m in master_ttfs]
628
+ defaultYOrigs = [m["VORG"].defaultVertOriginY for m in master_ttfs]
629
+ vOrigMetricses = list(zip(vOrigMetricses, defaultYOrigs))
630
+ else:
631
+ vOrigMetricses = None
632
+
633
+ vhAdvanceDeltasAndSupports = {}
634
+ vOrigDeltasAndSupports = {}
635
+ # HACK: we treat width 65535 as a sentinel value to signal that a glyph
636
+ # from a non-default master should not participate in computing {H,V}VAR,
637
+ # as if it were missing. Allows to variate other glyph-related data independently
638
+ # from glyph metrics
639
+ sparse_advance = 0xFFFF
640
+ for glyph in glyphOrder:
641
+ vhAdvances = [
642
+ (
643
+ metrics[glyph][0]
644
+ if glyph in metrics and metrics[glyph][0] != sparse_advance
645
+ else None
646
+ )
647
+ for metrics in advMetricses
648
+ ]
649
+ vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
650
+ vhAdvances, round=round
651
+ )
652
+
653
+ if vOrigMetricses:
654
+ for glyph in glyphOrder:
655
+ # We need to supply a vOrigs tuple with non-None default values
656
+ # for each glyph. vOrigMetricses contains values only for those
657
+ # glyphs which have a non-default vOrig.
658
+ vOrigs = [
659
+ metrics[glyph] if glyph in metrics else defaultVOrig
660
+ for metrics, defaultVOrig in vOrigMetricses
661
+ ]
662
+ vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(
663
+ vOrigs, round=round
664
+ )
665
+
666
+ return vhAdvanceDeltasAndSupports, vOrigDeltasAndSupports
664
667
 
665
668
 
666
669
  def _add_MVAR(font, masterModel, master_ttfs, axisTags):
@@ -0,0 +1,113 @@
1
+ from fontTools.misc.roundTools import noRound
2
+ from fontTools.ttLib import TTFont, newTable
3
+ from fontTools.ttLib.tables import otTables as ot
4
+ from fontTools.ttLib.tables.otBase import OTTableWriter
5
+ from fontTools.varLib import HVAR_FIELDS, VVAR_FIELDS, _add_VHVAR
6
+ from fontTools.varLib import builder, models, varStore
7
+ from fontTools.misc.fixedTools import fixedToFloat as fi2fl
8
+ from fontTools.misc.cliTools import makeOutputFileName
9
+ from functools import partial
10
+ import logging
11
+
12
+ log = logging.getLogger("fontTools.varLib.avar")
13
+
14
+
15
+ def _get_advance_metrics(font, axisTags, tableFields):
16
+ # There's two ways we can go from here:
17
+ # 1. For each glyph, at each master peak, compute the value of the
18
+ # advance width at that peak. Then pass these all to a VariationModel
19
+ # builder to compute back the deltas.
20
+ # 2. For each master peak, pull out the deltas of the advance width directly,
21
+ # and feed these to the VarStoreBuilder, forgoing the remoding step.
22
+ # We'll go with the second option, as it's simpler, faster, and more direct.
23
+ gvar = font["gvar"]
24
+ vhAdvanceDeltasAndSupports = {}
25
+ glyphOrder = font.getGlyphOrder()
26
+ phantomIndex = tableFields.phantomIndex
27
+ for glyphName in glyphOrder:
28
+ supports = []
29
+ deltas = []
30
+ variations = gvar.variations.get(glyphName, [])
31
+
32
+ for tv in variations:
33
+ supports.append(tv.axes)
34
+ phantoms = tv.coordinates[-4:]
35
+ phantoms = phantoms[phantomIndex * 2 : phantomIndex * 2 + 2]
36
+ assert len(phantoms) == 2
37
+ phantoms[0] = phantoms[0][phantomIndex] if phantoms[0] is not None else 0
38
+ phantoms[1] = phantoms[1][phantomIndex] if phantoms[1] is not None else 0
39
+ deltas.append(phantoms[1] - phantoms[0])
40
+
41
+ vhAdvanceDeltasAndSupports[glyphName] = (deltas, supports)
42
+
43
+ vOrigDeltasAndSupports = None # TODO
44
+
45
+ return vhAdvanceDeltasAndSupports, vOrigDeltasAndSupports
46
+
47
+
48
+ def add_HVAR(font):
49
+ if "HVAR" in font:
50
+ del font["HVAR"]
51
+ axisTags = [axis.axisTag for axis in font["fvar"].axes]
52
+ getAdvanceMetrics = partial(_get_advance_metrics, font, axisTags, HVAR_FIELDS)
53
+ _add_VHVAR(font, axisTags, HVAR_FIELDS, getAdvanceMetrics)
54
+
55
+
56
+ def add_VVAR(font):
57
+ if "VVAR" in font:
58
+ del font["VVAR"]
59
+ getAdvanceMetrics = partial(_get_advance_metrics, font, axisTags, HVAR_FIELDS)
60
+ axisTags = [axis.axisTag for axis in font["fvar"].axes]
61
+ _add_VHVAR(font, axisTags, VVAR_FIELDS, getAdvanceMetrics)
62
+
63
+
64
+ def main(args=None):
65
+ """Add `HVAR` table to variable font."""
66
+
67
+ if args is None:
68
+ import sys
69
+
70
+ args = sys.argv[1:]
71
+
72
+ from fontTools import configLogger
73
+ from fontTools.designspaceLib import DesignSpaceDocument
74
+ import argparse
75
+
76
+ parser = argparse.ArgumentParser(
77
+ "fonttools varLib.hvar",
78
+ description="Add `HVAR` table from to variable font.",
79
+ )
80
+ parser.add_argument("font", metavar="varfont.ttf", help="Variable-font file.")
81
+ parser.add_argument(
82
+ "-o",
83
+ "--output-file",
84
+ type=str,
85
+ help="Output font file name.",
86
+ )
87
+
88
+ options = parser.parse_args(args)
89
+
90
+ configLogger(level="WARNING")
91
+
92
+ font = TTFont(options.font)
93
+ if not "fvar" in font:
94
+ log.error("Not a variable font.")
95
+ return 1
96
+
97
+ add_HVAR(font)
98
+ if "vmtx" in font:
99
+ add_VVAR(font)
100
+
101
+ if options.output_file is None:
102
+ outfile = makeOutputFileName(options.font, overWrite=True, suffix=".hvar")
103
+ else:
104
+ outfile = options.output_file
105
+ if outfile:
106
+ log.info("Saving %s", outfile)
107
+ font.save(outfile)
108
+
109
+
110
+ if __name__ == "__main__":
111
+ import sys
112
+
113
+ sys.exit(main())
@@ -41,7 +41,7 @@ class OnlineVarStoreBuilder(object):
41
41
  def setSupports(self, supports):
42
42
  self._model = None
43
43
  self._supports = list(supports)
44
- if not self._supports[0]:
44
+ if self._supports and not self._supports[0]:
45
45
  del self._supports[0] # Drop base master support
46
46
  self._cache = None
47
47
  self._data = None
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: fonttools
3
- Version: 4.56.0
3
+ Version: 4.57.0
4
4
  Summary: Tools to manipulate font files
5
5
  Home-page: http://github.com/fonttools/fonttools
6
6
  Author: Just van Rossum
@@ -80,6 +80,7 @@ Dynamic: description
80
80
  Dynamic: description-content-type
81
81
  Dynamic: home-page
82
82
  Dynamic: license
83
+ Dynamic: license-file
83
84
  Dynamic: maintainer
84
85
  Dynamic: maintainer-email
85
86
  Dynamic: platform
@@ -391,6 +392,19 @@ Have fun!
391
392
  Changelog
392
393
  ~~~~~~~~~
393
394
 
395
+ 4.57.0 (released 2025-04-03)
396
+ ----------------------------
397
+
398
+ - [ttLib.__main__] Add `--no-recalc-timestamp` flag (#3771)
399
+ - [ttLib.__main__] Add `-b` (recalcBBoxes=False) flag (#3772)
400
+ - [cmap] Speed up glyphOrder loading from cmap (#3774)
401
+ - [ttLib.__main__] Improvements around the `-t` flag (#3776)
402
+ - [Debg] Fix parsing from XML; add roundtrip tests (#3781)
403
+ - [fealib] Support \*Base.MinMax tables (#3783, #3786)
404
+ - [config] Add OPTIMIZE_FONT_SPEED (#3784)
405
+ - [varLib.hvar] New module to add HVAR table to the font (#3780)
406
+ - [otlLib.optimize] Fix crash when the provided TTF does not contain a `GPOS` (#3794)
407
+
394
408
  4.56.0 (released 2025-02-07)
395
409
  ----------------------------
396
410
 
@@ -1,11 +1,11 @@
1
- fontTools/__init__.py,sha256=_orqitJ6zKfuWG-XX0I6vuq1MhBXcEAA8-wdaVMksIo,183
1
+ fontTools/__init__.py,sha256=T6Ml6H9-1VxuIVSMFDaDfwROmdl2-KslvDAmyvrgNEU,183
2
2
  fontTools/__main__.py,sha256=VjkGh1UD-i1zTDA1dXo1uecSs6PxHdGQ5vlCk_mCCYs,925
3
3
  fontTools/afmLib.py,sha256=1MagIItOzRV4vV5kKPxeDZbPJsfxLB3wdHLFkQvl0uk,13164
4
4
  fontTools/agl.py,sha256=05bm8Uq45uVWW8nPbP6xbNgmFyxQr8sWhYAiP0VSjnI,112975
5
5
  fontTools/fontBuilder.py,sha256=ntG0lXnhXNcHK-C7bp0nGNQ68OutFA-84TNNpzntTcE,33952
6
6
  fontTools/help.py,sha256=bAjatvIhV7TJyXI7WhsxdYO4YVlhScZXu_kRtHANEPo,1125
7
7
  fontTools/tfmLib.py,sha256=UMbkM73JXRJVS9t2B-BJc13rSjImaWBuzCoehLwHFhs,14270
8
- fontTools/ttx.py,sha256=XCerBn2ySMc5Bn54io4j5U5cW228GFREYvEeuvp0ZfM,16652
8
+ fontTools/ttx.py,sha256=FxuGubujWCGJWSTrJEjoNH--25fVIPy-ZRtYy9H6iTk,17277
9
9
  fontTools/unicode.py,sha256=ZZ7OMmWvIyV1IL1k6ioTzaRAh3tUvm6gvK7QgFbOIHY,1237
10
10
  fontTools/cffLib/CFF2ToCFF.py,sha256=pvwh6qxJ0D7c4xgXBcyAdmZGzpTiywMy45-jjp7dKck,6088
11
11
  fontTools/cffLib/CFFToCFF2.py,sha256=Qnk7lYlsTRHnlZQ6NXNdr_f4MJwZQ21kcS08KFbsyY8,10119
@@ -19,7 +19,7 @@ fontTools/colorLib/errors.py,sha256=CsaviiRxxrpgVX4blm7KCyK8553ljwL44xkJOeC5U7U,
19
19
  fontTools/colorLib/geometry.py,sha256=3ScySrR2YDJa7d5K5_xM5Yt1-3NCV-ry8ikYA5VwVbI,5518
20
20
  fontTools/colorLib/table_builder.py,sha256=ZeltWY6n-YPiJv_hQ1iBXoEFAG70EKxZyScgsMKUFGU,7469
21
21
  fontTools/colorLib/unbuilder.py,sha256=iW-E5I39WsV82K3NgCO4Cjzwm1WqzGrtypHt8epwbHM,2142
22
- fontTools/config/__init__.py,sha256=Ti5jpozjMqp5qhnrmwNcWI6b9uvHzhZlbWXHTqVZlGI,2643
22
+ fontTools/config/__init__.py,sha256=JICOHIz06KuHCiBmrxj-ga19P6ZTuLXh0lHmPh-Ra1w,3154
23
23
  fontTools/cu2qu/__init__.py,sha256=Cuc7Uglb0nSgaraTxXY5J8bReznH5wApW0uakN7MycY,618
24
24
  fontTools/cu2qu/__main__.py,sha256=kTUI-jczsHeelULLlory74QEeFjZWp9zigCc7PrdVQY,92
25
25
  fontTools/cu2qu/benchmark.py,sha256=wasPJmf8q9k9UHjpHChC3WQAGbBAyHN9PvJzXvWC0Fw,1296
@@ -38,13 +38,13 @@ fontTools/encodings/__init__.py,sha256=DJBWmoX_Haau7qlgmvWyfbhSzrX2qL636Rns7CG01
38
38
  fontTools/encodings/codecs.py,sha256=u50ruwz9fcRsrUrRGpR17Cr55Ovn1fvCHCKrElVumDE,4721
39
39
  fontTools/feaLib/__init__.py,sha256=jlIru2ghxvb1HhC5Je2BCXjFJmFQlYKpruorPoz3BvQ,213
40
40
  fontTools/feaLib/__main__.py,sha256=Df2PA6LXwna98lSXiL7R4as_ZEdWCIk3egSM5w7GpvM,2240
41
- fontTools/feaLib/ast.py,sha256=3DU5NKXesyNCVu5wcebGlnvwdMf0_NKrPgOvS0FrWSg,73800
42
- fontTools/feaLib/builder.py,sha256=y7t8_q0-PiPoLpXZCfThx1SmvF-ZpDDyVe8605FzaL4,71036
41
+ fontTools/feaLib/ast.py,sha256=koL7JLGrNWbABNLq4QrkKBFETKNEjSSC7dirZTFemqU,74050
42
+ fontTools/feaLib/builder.py,sha256=1rLV3zwA3JFXpZ452DXM8Y8E6NxAvcszzmOwFNvomqA,72101
43
43
  fontTools/feaLib/error.py,sha256=Bz_5tNcNVcY7_nrAmFlQNhQldtqZWd8WUGQ2E3PWhZo,648
44
44
  fontTools/feaLib/lexer.py,sha256=emyMPmRoqNZkzxnJyI6JRCCtXrbCOFofwa9O6ABGLiw,11121
45
45
  fontTools/feaLib/location.py,sha256=JXzHqGV56EHdcq823AwA5oaK05hf_1ySWpScbo3zGC0,234
46
46
  fontTools/feaLib/lookupDebugInfo.py,sha256=gVRr5-APWfT_a5-25hRuawSVX8fEvXVsOSLWkH91T2w,304
47
- fontTools/feaLib/parser.py,sha256=wbfG_-rqrn2RWMRQMlR3-uaiM9k4_mzCVF-wPLr00rQ,98466
47
+ fontTools/feaLib/parser.py,sha256=GRbPbMP2z9zOkScN-Zw7TCuPQ7UXT9UhZYENp4eaX1c,101085
48
48
  fontTools/feaLib/variableScalar.py,sha256=Xu8tpDlQbfIfjnKnYDEf43EqVdyIJUy8_1ROVPg9_mg,4069
49
49
  fontTools/merge/__init__.py,sha256=-l65-mbTwSh0gjarnojIfsAX-ZkMtdz3vGTjtYHQ2ws,8250
50
50
  fontTools/merge/__main__.py,sha256=hDx3gfbUBO83AJKumSEhiV-xqNTJNNgK2uFjazOGTmw,94
@@ -81,7 +81,7 @@ fontTools/misc/py23.py,sha256=aPVCEUz_deggwLBCeTSsccX6QgJavZqvdVtuhpzrPvA,2238
81
81
  fontTools/misc/roundTools.py,sha256=1RSXZ0gyi1qW42tz6WSBMJD1FlPdtgqKfWixVN9bd78,3173
82
82
  fontTools/misc/sstruct.py,sha256=HuXwoRr9-mAbBxI3gJ3n34ML7NAGSHsAAazaaloWQB4,7158
83
83
  fontTools/misc/symfont.py,sha256=SJtc3-9VdhT6fokx5Vvzs7YErqRib1u-rItNqXI0rTM,6991
84
- fontTools/misc/testTools.py,sha256=_JdQXAtThRxXKv8hHT2Arh6ezADIZyRJ8nO909A1bYE,7001
84
+ fontTools/misc/testTools.py,sha256=3vj_KllUQVEiVFbS0SzTmeuKv44-L-disI1dZ4XhOfw,7052
85
85
  fontTools/misc/textTools.py,sha256=pbhr6LVhm3J-0Z4saYnJfxBDzyoiw4BR9pAgwypiOw8,3377
86
86
  fontTools/misc/timeTools.py,sha256=e9h5pgzL04tBDXmCv_8eRGB4boFV8GKXlS6dq3ggEpw,2234
87
87
  fontTools/misc/transform.py,sha256=OR8dPsAw87z77gkZQMq00iUkDWLIxYv-12XiKH1-erk,15798
@@ -100,7 +100,7 @@ fontTools/otlLib/error.py,sha256=cthuhBuOwZYpkTLi5gFPupUxkXkCHe-L_YgkE7N1wCI,335
100
100
  fontTools/otlLib/maxContextCalc.py,sha256=3es4Kt84TaZ49sA2ev1zrlwPJikJCAECx5KavwhyB-I,3175
101
101
  fontTools/otlLib/optimize/__init__.py,sha256=UUQRpNkHU2RczCRt-Gz7sEiYE9AQq9BHLXZEOyvsnX4,1530
102
102
  fontTools/otlLib/optimize/__main__.py,sha256=BvP472kA9KxBb9RMyyehPNevAfpmgW9MfdazkUiAO3M,104
103
- fontTools/otlLib/optimize/gpos.py,sha256=NTDLwjo90L4GiqdIdWkBEycQ7VcT7cOxxype73mFz8c,18474
103
+ fontTools/otlLib/optimize/gpos.py,sha256=tbIfKaPalP3FwNBxOBcNvSRUXLbysMmPAUvbeqofhXs,18595
104
104
  fontTools/pens/__init__.py,sha256=DJBWmoX_Haau7qlgmvWyfbhSzrX2qL636Rns7CG01pk,75
105
105
  fontTools/pens/areaPen.py,sha256=Y1WkmqzcC4z_bpGAR0IZUKrtHFtxKUQBmr5-64_zCOk,1472
106
106
  fontTools/pens/basePen.py,sha256=eIGSKrKm6w4LLHuG6XJoQZ3eObtoKV5P6aF4gT4sk7U,17073
@@ -146,8 +146,8 @@ fontTools/svgLib/path/arc.py,sha256=-f5Ym6q4tDWQ76sMNSTUTWgL_7AfgXojvBhtBS7bWwQ,
146
146
  fontTools/svgLib/path/parser.py,sha256=8T6okMstvgM9ufb2zBcwSzsuuoYbqfnUjNYgb6kjznU,10788
147
147
  fontTools/svgLib/path/shapes.py,sha256=xvBUIckKyT9JLy7q_ZP50r6TjvZANyHdZP7wFDzErcI,5322
148
148
  fontTools/t1Lib/__init__.py,sha256=p42y70wEIbuX0IIxZG7-b_I-gHto1VLy0gLsDvxCfkw,20865
149
- fontTools/ttLib/__init__.py,sha256=fjOFcwbRed9b_giTgJ7FLsqeJC8ndnx327WfJztW-Tc,553
150
- fontTools/ttLib/__main__.py,sha256=3yxwadpQ5YTM27RXqG3sFE3EaOSFLQVHaUUH9P0qrSw,3443
149
+ fontTools/ttLib/__init__.py,sha256=1k7qp9z04gA3m6GvxDaINjqrKbzOkdTA_4RnqW_-LrA,661
150
+ fontTools/ttLib/__main__.py,sha256=lHMPWsnzjKPuMFavf6i1gpk9KexiAk4qzgDd50Mbby0,4733
151
151
  fontTools/ttLib/macUtils.py,sha256=lj3oeFpyjV7ko_JqnluneITmAtlc119J-vwTTg2s73A,1737
152
152
  fontTools/ttLib/removeOverlaps.py,sha256=YBtj1PX-d2jMgCiWGuI6ibghWApUWqH2trJGXNxrbjQ,12612
153
153
  fontTools/ttLib/reorderGlyphs.py,sha256=8ClsX9-tnPfuiD8kHY4jPliGJ-31-JdybA4s1UNWx4w,10316
@@ -155,8 +155,8 @@ fontTools/ttLib/scaleUpem.py,sha256=U_-NGkwfS9GRIackdEXjGYZ-wSomcUPXQahDneLeArI,
155
155
  fontTools/ttLib/sfnt.py,sha256=rkznKfteU_Rn9P65WSjFaiwQgpEAoh-TrQpvkQhdIlo,22832
156
156
  fontTools/ttLib/standardGlyphOrder.py,sha256=7AY_fVWdtwZ4iv5uWdyKAUcbEQiSDt1lN4sqx9xXwE0,5785
157
157
  fontTools/ttLib/ttCollection.py,sha256=aRph2MkBK3kd9-JCLqhJ1EN9pffN_lVX6WWmOTTewc8,3963
158
- fontTools/ttLib/ttFont.py,sha256=llMtJ3VnzRUEyHk606_ElVty3J80E9BHbJnWamB_lO0,41024
159
- fontTools/ttLib/ttGlyphSet.py,sha256=oq4u8OpTsKxR9ThOomNBJhOA1B9NxYK__Shkx6NIkHo,17853
158
+ fontTools/ttLib/ttFont.py,sha256=rTGWNOiTW5mnFFN1HrYIi1HzihBXyJOvhhpsxhYwKnA,40965
159
+ fontTools/ttLib/ttGlyphSet.py,sha256=cUBhMGa5hszeVqOm2KpOdeJh-LsiqE7RNdyIUPZ2vO8,17476
160
160
  fontTools/ttLib/ttVisitor.py,sha256=_tah4C42Tv6Pm9QeLNQwwVCxqI4VNEAqYCbmThp6cvY,1025
161
161
  fontTools/ttLib/woff2.py,sha256=Ryw4WVwUFMtdEo9FcIejP1OTV92Z4B9y5Wq7nWDW3lE,61058
162
162
  fontTools/ttLib/tables/B_A_S_E_.py,sha256=H71A9pJ850mvjbrWHqy8iFI2Dxg7102YRtAkfdCooig,369
@@ -168,7 +168,7 @@ fontTools/ttLib/tables/C_F_F__2.py,sha256=YoHfJQdF-ezx4OwRQ2Y2O7rRJEPjOkf3Hx5Y11
168
168
  fontTools/ttLib/tables/C_O_L_R_.py,sha256=SHwFVNVmoUQR2e87KuTSe-J9LfeegS4f2hEpee29_2o,5993
169
169
  fontTools/ttLib/tables/C_P_A_L_.py,sha256=odFjqM4GnjXyQYGEC-e0Gvqms1jQ5zHHG3SDg7y-BI0,11942
170
170
  fontTools/ttLib/tables/D_S_I_G_.py,sha256=AgQPM9Cdro1P-ehJjTfsC9mRTTtSc16At0nnpb1XOGI,5517
171
- fontTools/ttLib/tables/D__e_b_g.py,sha256=vROIV3UTxbK9eN3rmHOu1ARwBiOXL6K5ihmq0QMToJQ,443
171
+ fontTools/ttLib/tables/D__e_b_g.py,sha256=KDnfkNOUnm3F13wD_j3YNBOvYadZ40Gf_0170hFkJp0,1134
172
172
  fontTools/ttLib/tables/DefaultTable.py,sha256=cOtgkLWPY9qmOH2BSPt4c4IUSdANWTKx2rK1CTxQ4h0,1487
173
173
  fontTools/ttLib/tables/E_B_D_T_.py,sha256=uOpmt25gOJQeO1u1IGAyPWgVmh-4vSZqrQEHvOYwbwg,32534
174
174
  fontTools/ttLib/tables/E_B_L_C_.py,sha256=LfEVzBg_yWr9dhChzS0U2G-7wNOwzwB0LWoXIUYNKKM,30054
@@ -216,7 +216,7 @@ fontTools/ttLib/tables/_a_n_k_r.py,sha256=MpAzIifmIi_3gx2oP6PC3R2lu36Ewsr2-W1rXj
216
216
  fontTools/ttLib/tables/_a_v_a_r.py,sha256=QnjP8oO-hozKcI21_bRC-_SzZxVqcHC2VLDyNs4aH9U,7116
217
217
  fontTools/ttLib/tables/_b_s_l_n.py,sha256=_848o7SQqztzBDfHYei-80u9ltxIHVBzXu1dYHLV57M,465
218
218
  fontTools/ttLib/tables/_c_i_d_g.py,sha256=yt8rVIadpJSDUCoVH4dZetNiy0Azm5ESAxHjB2BX_eA,913
219
- fontTools/ttLib/tables/_c_m_a_p.py,sha256=ksU1GjkGBcmasD1_CxM2WVZ0V4wNjoHoA0p_n7QCN20,61721
219
+ fontTools/ttLib/tables/_c_m_a_p.py,sha256=0P0z1lYtQG4OgV_Bo3n1ciq1XKD2ANdfoOV5cSzN4Ig,62208
220
220
  fontTools/ttLib/tables/_c_v_a_r.py,sha256=35ayk2kX1pcLGwyx0y4I1l-r7LHgdKv0ulVx8oBPteI,3527
221
221
  fontTools/ttLib/tables/_c_v_t.py,sha256=mB7xAG_q-F4z_Gdwj0XLvfybTJ1bwsZkb2QDnhc0zjQ,1584
222
222
  fontTools/ttLib/tables/_f_e_a_t.py,sha256=Fi1XnjhkCG0tp43AcvpIaivD-YRFpufo6feGIrenQDo,469
@@ -224,8 +224,8 @@ fontTools/ttLib/tables/_f_p_g_m.py,sha256=t1T6lfuoJv1ImKu7X4h6jg2S6B4rxQZSlDrnZ5
224
224
  fontTools/ttLib/tables/_f_v_a_r.py,sha256=rV33H2BgHUl3Wuydsou1G-Hi4uASBppWaLj3FMmiLjs,8837
225
225
  fontTools/ttLib/tables/_g_a_s_p.py,sha256=YvhAVDvdssN2fjPMTfSrO4WBCfTuh9T2cU5zquDVnSw,2203
226
226
  fontTools/ttLib/tables/_g_c_i_d.py,sha256=AJ4uV7PTHbnsw4Tfw8c2Ezh0VMox3oAH0qhhq7y8hdM,362
227
- fontTools/ttLib/tables/_g_l_y_f.py,sha256=R0WuModxptcPfoBTZxvs5xDTnA9olAVf67blh-k-tmM,85631
228
- fontTools/ttLib/tables/_g_v_a_r.py,sha256=9T8XwBWaWyJINSeDhLR-g9oPiKLXJvlhThpXL0YuSs0,10773
227
+ fontTools/ttLib/tables/_g_l_y_f.py,sha256=37o4JyVctndRK0n_q4NwyDs4idlH1766a6QuEQs02Pc,85696
228
+ fontTools/ttLib/tables/_g_v_a_r.py,sha256=Fbm6ECXix65MGJvwIdKdgEJlaLhq_yEgkePdDGdYlQk,10824
229
229
  fontTools/ttLib/tables/_h_d_m_x.py,sha256=kgydwtD1ibF3T0Vbohq-aM_QD8PY-vp4oUuWQWJJMNA,4271
230
230
  fontTools/ttLib/tables/_h_e_a_d.py,sha256=yY2GTFq6Mn6nN8EegbMVJRMUWIqDYFln3FhTk3ziw6s,4926
231
231
  fontTools/ttLib/tables/_h_h_e_a.py,sha256=X4t1aF1MZMuz3phCVSFwKcNTeoZdx-042wFtHc-nK9w,4767
@@ -250,9 +250,9 @@ fontTools/ttLib/tables/_v_m_t_x.py,sha256=AUuxtyQvMWrTBNbOIaL6uKcB_DNpNb0YX28JIu
250
250
  fontTools/ttLib/tables/asciiTable.py,sha256=4c69jsAirUnDEpylf9CYBoCKTzwbmfbtUAOrtPnpHjY,637
251
251
  fontTools/ttLib/tables/grUtils.py,sha256=hcOJ5oJPOd2uJWnWA7qwR7AfL37YZ5zUT7g8o5BBV80,2270
252
252
  fontTools/ttLib/tables/otBase.py,sha256=Vq8fv4lm-e3oPCuSPcWTNMQI2KmX0iOIz_lO9kE1mKE,53355
253
- fontTools/ttLib/tables/otConverters.py,sha256=JI9b387HZwbPgf_0J2AO-nJA_wr6VHPJE1lC-H_An8E,74073
253
+ fontTools/ttLib/tables/otConverters.py,sha256=ihE_WMSKAKSaBbMvnFYDj2eMxf7PvRMMa8zGwfoYuYc,74202
254
254
  fontTools/ttLib/tables/otData.py,sha256=-XXRwdVfP-Wz7oBjMPpku0A0QH9lw_fFGNzZlt9N0mo,197262
255
- fontTools/ttLib/tables/otTables.py,sha256=wgmNkSSLbZOkT_DrF7Y-ki8OGW7SC0A7Ue6OHUJQC4E,96972
255
+ fontTools/ttLib/tables/otTables.py,sha256=IZQY8Scf8JFsUD28LY1csC8bvFbfY-aURH6YaQ3Ao24,97128
256
256
  fontTools/ttLib/tables/otTraverse.py,sha256=HznEVAlVf_8eyqjsO2edgELtMlXnjnUqccK3PytvVUE,5518
257
257
  fontTools/ttLib/tables/sbixGlyph.py,sha256=tjEUPVRfx6gr5yme8UytGTtVrimKN5qmbzT1GZPjXiM,5796
258
258
  fontTools/ttLib/tables/sbixStrike.py,sha256=gFyOlhRIGnd59y0SrhtsT2Ce4L3yaBrLoFJ_dK9u9mQ,6663
@@ -274,7 +274,7 @@ fontTools/unicodedata/OTTags.py,sha256=wOPpbMsNcp_gdvPFeITtgVMnTN8TJSNAsVEdu_nuP
274
274
  fontTools/unicodedata/ScriptExtensions.py,sha256=YTZr2bOteHiz_7I4108PRy0Is4kFof-32yFuoKjFHjc,28207
275
275
  fontTools/unicodedata/Scripts.py,sha256=I0nY08ovsZ4pHU5wYchjat9DjnxcpoTzaXAn5oFaKNI,130271
276
276
  fontTools/unicodedata/__init__.py,sha256=DOCX0X9-Eo3mEju7Zjgcod7d8aswTo3vjDRzV7-8Z4g,8824
277
- fontTools/varLib/__init__.py,sha256=Y3Yx5TlD6wN6GImZfrHsetdZJD4mH6p5VC8VU12ucMg,53391
277
+ fontTools/varLib/__init__.py,sha256=EOA9Tl3qOd72YtvmYBhE7H0MdcA2Oaxg7ZpPDeDnbmc,53619
278
278
  fontTools/varLib/__main__.py,sha256=wbdYC5bPjWCxA0I4SKcLO88gl-UMtsYS8MxdW9ySTkY,95
279
279
  fontTools/varLib/avar.py,sha256=Ye_u0HHznaPQaTzufNFKDj_v9o_LxOKJoa_eTK1D1F0,9647
280
280
  fontTools/varLib/avarPlanner.py,sha256=uLMGsL6cBbEMq5YItwABG_vXlXV3bxquM93WGDJ1brA,27358
@@ -282,6 +282,7 @@ fontTools/varLib/builder.py,sha256=mSKOCcnnw-WzmZs15FayoqCDh77Ts7o9Tre9psh8CUc,6
282
282
  fontTools/varLib/cff.py,sha256=EVgaQcoROIrYQsRuftnxFuGGldEPYbrIh5yBckylJC4,22901
283
283
  fontTools/varLib/errors.py,sha256=dMo8eGj76I7H4hrBEiNbYrGs2J1K1SwdsUyTHpkVOrQ,6934
284
284
  fontTools/varLib/featureVars.py,sha256=BCOBGjGUv2Rw_z0rlVi1ZYkTDcCMh0LyAUzDVJ2PYm4,25448
285
+ fontTools/varLib/hvar.py,sha256=4W5t3s7GOBN07x9KNDmA_4NGXxVEEahzkn3cWJZ4oGw,3693
285
286
  fontTools/varLib/interpolatable.py,sha256=Bhlq_LhEZ-sXfLNY8aFEChFrsKuT2kzmnuMfG5qi0v4,45221
286
287
  fontTools/varLib/interpolatableHelpers.py,sha256=lXd7kwfIVl-4opd-vxCDhf48RnJ7IQKv_uuFQM_6vaU,11496
287
288
  fontTools/varLib/interpolatablePlot.py,sha256=w393P6mGLRhYkIjSxMww3qyoYxAUZzCXlmPBbI_84C0,44375
@@ -296,7 +297,7 @@ fontTools/varLib/mutator.py,sha256=YJkKFFWjwpYZ1MrC7UZYJ1BuYTGiwgi7jHnpqNpKfKg,1
296
297
  fontTools/varLib/mvar.py,sha256=LTV77vH_3Ecg_qKBO5xQzjLOlJir_ppEr7mPVZRgad8,2449
297
298
  fontTools/varLib/plot.py,sha256=NoSZkJ5ndxNcDvJIvd5pQ9_jX6X1oM1K2G_tR4sdPVs,7494
298
299
  fontTools/varLib/stat.py,sha256=XuNKKZxGlBrl4OGFDAwVXhpBwJi23U3BdHmNTKoJnvE,4811
299
- fontTools/varLib/varStore.py,sha256=gE3mrrL5aEIdMkIbOLI5NcElnP2IThC6NzQCjR0fhxU,24050
300
+ fontTools/varLib/varStore.py,sha256=2QA9SDI6jQyQ_zq82OOwa3FBkfl-ksaSo1KGmVFpa9Q,24069
300
301
  fontTools/varLib/instancer/__init__.py,sha256=wFqRVbww2CjuJk3MPDQ2HGmpNBGNQd9JF58KQoBl8_c,71346
301
302
  fontTools/varLib/instancer/__main__.py,sha256=zfULwcP01FhplS1IlcMgNQnLxk5RVfmOuinWjqeid-g,104
302
303
  fontTools/varLib/instancer/featureVars.py,sha256=oPqSlnHLMDTtOsmQMi6gkzLox7ymCrqlRAkvC_EJ4bc,7110
@@ -308,10 +309,10 @@ fontTools/voltLib/error.py,sha256=phcQOQj-xOspCXu9hBJQRhSOBDzxHRgZd3fWQOFNJzw,39
308
309
  fontTools/voltLib/lexer.py,sha256=OvuETOSvlS6v7iCVeJ3IdH2Cg71n3OJoEyiB3-h6vhE,3368
309
310
  fontTools/voltLib/parser.py,sha256=wBSUrjLT3fSPv9Mjx6_ULIf8IcGlwjtb4Auxjh5wqnc,24916
310
311
  fontTools/voltLib/voltToFea.py,sha256=igP7_E-7AzSl8f_LiN_GHMoNmFiXPBaXp_zZLndjU4c,28505
311
- fonttools-4.56.0.data/data/share/man/man1/ttx.1,sha256=cLbm_pOOj1C76T2QXvDxzwDj9gk-GTd5RztvTMsouFw,5377
312
- fonttools-4.56.0.dist-info/LICENSE,sha256=Z4cgj4P2Wcy8IiOy_elS_6b36KymLxqKK_W8UbsbI4M,1072
313
- fonttools-4.56.0.dist-info/METADATA,sha256=mHbq7JOdQyQ3-vtlnRALzKhNmCpZgtAPIWzHOxG2txQ,101907
314
- fonttools-4.56.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
315
- fonttools-4.56.0.dist-info/entry_points.txt,sha256=8kVHddxfFWA44FSD4mBpmC-4uCynQnkoz_9aNJb227Y,147
316
- fonttools-4.56.0.dist-info/top_level.txt,sha256=rRgRylrXzekqWOsrhygzib12pQ7WILf7UGjqEwkIFDM,10
317
- fonttools-4.56.0.dist-info/RECORD,,
312
+ fonttools-4.57.0.data/data/share/man/man1/ttx.1,sha256=cLbm_pOOj1C76T2QXvDxzwDj9gk-GTd5RztvTMsouFw,5377
313
+ fonttools-4.57.0.dist-info/licenses/LICENSE,sha256=Z4cgj4P2Wcy8IiOy_elS_6b36KymLxqKK_W8UbsbI4M,1072
314
+ fonttools-4.57.0.dist-info/METADATA,sha256=lqvLLeINsYTJX7jelqex2SkxGaBysfnX87V4AT-_p9k,102535
315
+ fonttools-4.57.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
316
+ fonttools-4.57.0.dist-info/entry_points.txt,sha256=8kVHddxfFWA44FSD4mBpmC-4uCynQnkoz_9aNJb227Y,147
317
+ fonttools-4.57.0.dist-info/top_level.txt,sha256=rRgRylrXzekqWOsrhygzib12pQ7WILf7UGjqEwkIFDM,10
318
+ fonttools-4.57.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5