fonttools 4.60.2__cp311-cp311-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.
Files changed (353) hide show
  1. fontTools/__init__.py +8 -0
  2. fontTools/__main__.py +35 -0
  3. fontTools/afmLib.py +439 -0
  4. fontTools/agl.py +5233 -0
  5. fontTools/annotations.py +30 -0
  6. fontTools/cffLib/CFF2ToCFF.py +258 -0
  7. fontTools/cffLib/CFFToCFF2.py +305 -0
  8. fontTools/cffLib/__init__.py +3694 -0
  9. fontTools/cffLib/specializer.py +927 -0
  10. fontTools/cffLib/transforms.py +495 -0
  11. fontTools/cffLib/width.py +210 -0
  12. fontTools/colorLib/__init__.py +0 -0
  13. fontTools/colorLib/builder.py +664 -0
  14. fontTools/colorLib/errors.py +2 -0
  15. fontTools/colorLib/geometry.py +143 -0
  16. fontTools/colorLib/table_builder.py +223 -0
  17. fontTools/colorLib/unbuilder.py +81 -0
  18. fontTools/config/__init__.py +90 -0
  19. fontTools/cu2qu/__init__.py +15 -0
  20. fontTools/cu2qu/__main__.py +6 -0
  21. fontTools/cu2qu/benchmark.py +54 -0
  22. fontTools/cu2qu/cli.py +198 -0
  23. fontTools/cu2qu/cu2qu.c +15817 -0
  24. fontTools/cu2qu/cu2qu.cp311-win32.pyd +0 -0
  25. fontTools/cu2qu/cu2qu.py +563 -0
  26. fontTools/cu2qu/errors.py +77 -0
  27. fontTools/cu2qu/ufo.py +363 -0
  28. fontTools/designspaceLib/__init__.py +3343 -0
  29. fontTools/designspaceLib/__main__.py +6 -0
  30. fontTools/designspaceLib/split.py +475 -0
  31. fontTools/designspaceLib/statNames.py +260 -0
  32. fontTools/designspaceLib/types.py +147 -0
  33. fontTools/encodings/MacRoman.py +258 -0
  34. fontTools/encodings/StandardEncoding.py +258 -0
  35. fontTools/encodings/__init__.py +1 -0
  36. fontTools/encodings/codecs.py +135 -0
  37. fontTools/feaLib/__init__.py +4 -0
  38. fontTools/feaLib/__main__.py +78 -0
  39. fontTools/feaLib/ast.py +2143 -0
  40. fontTools/feaLib/builder.py +1814 -0
  41. fontTools/feaLib/error.py +22 -0
  42. fontTools/feaLib/lexer.c +17029 -0
  43. fontTools/feaLib/lexer.cp311-win32.pyd +0 -0
  44. fontTools/feaLib/lexer.py +287 -0
  45. fontTools/feaLib/location.py +12 -0
  46. fontTools/feaLib/lookupDebugInfo.py +12 -0
  47. fontTools/feaLib/parser.py +2394 -0
  48. fontTools/feaLib/variableScalar.py +118 -0
  49. fontTools/fontBuilder.py +1014 -0
  50. fontTools/help.py +36 -0
  51. fontTools/merge/__init__.py +248 -0
  52. fontTools/merge/__main__.py +6 -0
  53. fontTools/merge/base.py +81 -0
  54. fontTools/merge/cmap.py +173 -0
  55. fontTools/merge/layout.py +526 -0
  56. fontTools/merge/options.py +85 -0
  57. fontTools/merge/tables.py +352 -0
  58. fontTools/merge/unicode.py +78 -0
  59. fontTools/merge/util.py +143 -0
  60. fontTools/misc/__init__.py +1 -0
  61. fontTools/misc/arrayTools.py +424 -0
  62. fontTools/misc/bezierTools.c +39731 -0
  63. fontTools/misc/bezierTools.cp311-win32.pyd +0 -0
  64. fontTools/misc/bezierTools.py +1500 -0
  65. fontTools/misc/classifyTools.py +170 -0
  66. fontTools/misc/cliTools.py +53 -0
  67. fontTools/misc/configTools.py +349 -0
  68. fontTools/misc/cython.py +27 -0
  69. fontTools/misc/dictTools.py +83 -0
  70. fontTools/misc/eexec.py +119 -0
  71. fontTools/misc/encodingTools.py +72 -0
  72. fontTools/misc/enumTools.py +23 -0
  73. fontTools/misc/etree.py +456 -0
  74. fontTools/misc/filenames.py +245 -0
  75. fontTools/misc/filesystem/__init__.py +68 -0
  76. fontTools/misc/filesystem/_base.py +134 -0
  77. fontTools/misc/filesystem/_copy.py +45 -0
  78. fontTools/misc/filesystem/_errors.py +54 -0
  79. fontTools/misc/filesystem/_info.py +75 -0
  80. fontTools/misc/filesystem/_osfs.py +164 -0
  81. fontTools/misc/filesystem/_path.py +67 -0
  82. fontTools/misc/filesystem/_subfs.py +92 -0
  83. fontTools/misc/filesystem/_tempfs.py +34 -0
  84. fontTools/misc/filesystem/_tools.py +34 -0
  85. fontTools/misc/filesystem/_walk.py +55 -0
  86. fontTools/misc/filesystem/_zipfs.py +204 -0
  87. fontTools/misc/fixedTools.py +253 -0
  88. fontTools/misc/intTools.py +25 -0
  89. fontTools/misc/iterTools.py +12 -0
  90. fontTools/misc/lazyTools.py +42 -0
  91. fontTools/misc/loggingTools.py +543 -0
  92. fontTools/misc/macCreatorType.py +56 -0
  93. fontTools/misc/macRes.py +261 -0
  94. fontTools/misc/plistlib/__init__.py +681 -0
  95. fontTools/misc/plistlib/py.typed +0 -0
  96. fontTools/misc/psCharStrings.py +1511 -0
  97. fontTools/misc/psLib.py +398 -0
  98. fontTools/misc/psOperators.py +572 -0
  99. fontTools/misc/py23.py +96 -0
  100. fontTools/misc/roundTools.py +110 -0
  101. fontTools/misc/sstruct.py +227 -0
  102. fontTools/misc/symfont.py +242 -0
  103. fontTools/misc/testTools.py +233 -0
  104. fontTools/misc/textTools.py +156 -0
  105. fontTools/misc/timeTools.py +88 -0
  106. fontTools/misc/transform.py +516 -0
  107. fontTools/misc/treeTools.py +45 -0
  108. fontTools/misc/vector.py +147 -0
  109. fontTools/misc/visitor.py +158 -0
  110. fontTools/misc/xmlReader.py +188 -0
  111. fontTools/misc/xmlWriter.py +231 -0
  112. fontTools/mtiLib/__init__.py +1400 -0
  113. fontTools/mtiLib/__main__.py +5 -0
  114. fontTools/otlLib/__init__.py +1 -0
  115. fontTools/otlLib/builder.py +3465 -0
  116. fontTools/otlLib/error.py +11 -0
  117. fontTools/otlLib/maxContextCalc.py +96 -0
  118. fontTools/otlLib/optimize/__init__.py +53 -0
  119. fontTools/otlLib/optimize/__main__.py +6 -0
  120. fontTools/otlLib/optimize/gpos.py +439 -0
  121. fontTools/pens/__init__.py +1 -0
  122. fontTools/pens/areaPen.py +52 -0
  123. fontTools/pens/basePen.py +475 -0
  124. fontTools/pens/boundsPen.py +98 -0
  125. fontTools/pens/cairoPen.py +26 -0
  126. fontTools/pens/cocoaPen.py +26 -0
  127. fontTools/pens/cu2quPen.py +325 -0
  128. fontTools/pens/explicitClosingLinePen.py +101 -0
  129. fontTools/pens/filterPen.py +433 -0
  130. fontTools/pens/freetypePen.py +462 -0
  131. fontTools/pens/hashPointPen.py +89 -0
  132. fontTools/pens/momentsPen.c +13378 -0
  133. fontTools/pens/momentsPen.cp311-win32.pyd +0 -0
  134. fontTools/pens/momentsPen.py +879 -0
  135. fontTools/pens/perimeterPen.py +69 -0
  136. fontTools/pens/pointInsidePen.py +192 -0
  137. fontTools/pens/pointPen.py +643 -0
  138. fontTools/pens/qtPen.py +29 -0
  139. fontTools/pens/qu2cuPen.py +105 -0
  140. fontTools/pens/quartzPen.py +43 -0
  141. fontTools/pens/recordingPen.py +335 -0
  142. fontTools/pens/reportLabPen.py +79 -0
  143. fontTools/pens/reverseContourPen.py +96 -0
  144. fontTools/pens/roundingPen.py +130 -0
  145. fontTools/pens/statisticsPen.py +312 -0
  146. fontTools/pens/svgPathPen.py +310 -0
  147. fontTools/pens/t2CharStringPen.py +88 -0
  148. fontTools/pens/teePen.py +55 -0
  149. fontTools/pens/transformPen.py +115 -0
  150. fontTools/pens/ttGlyphPen.py +335 -0
  151. fontTools/pens/wxPen.py +29 -0
  152. fontTools/qu2cu/__init__.py +15 -0
  153. fontTools/qu2cu/__main__.py +7 -0
  154. fontTools/qu2cu/benchmark.py +56 -0
  155. fontTools/qu2cu/cli.py +125 -0
  156. fontTools/qu2cu/qu2cu.c +16682 -0
  157. fontTools/qu2cu/qu2cu.cp311-win32.pyd +0 -0
  158. fontTools/qu2cu/qu2cu.py +405 -0
  159. fontTools/subset/__init__.py +4096 -0
  160. fontTools/subset/__main__.py +6 -0
  161. fontTools/subset/cff.py +184 -0
  162. fontTools/subset/svg.py +253 -0
  163. fontTools/subset/util.py +25 -0
  164. fontTools/svgLib/__init__.py +3 -0
  165. fontTools/svgLib/path/__init__.py +65 -0
  166. fontTools/svgLib/path/arc.py +154 -0
  167. fontTools/svgLib/path/parser.py +322 -0
  168. fontTools/svgLib/path/shapes.py +183 -0
  169. fontTools/t1Lib/__init__.py +648 -0
  170. fontTools/tfmLib.py +460 -0
  171. fontTools/ttLib/__init__.py +30 -0
  172. fontTools/ttLib/__main__.py +148 -0
  173. fontTools/ttLib/macUtils.py +54 -0
  174. fontTools/ttLib/removeOverlaps.py +395 -0
  175. fontTools/ttLib/reorderGlyphs.py +285 -0
  176. fontTools/ttLib/scaleUpem.py +436 -0
  177. fontTools/ttLib/sfnt.py +661 -0
  178. fontTools/ttLib/standardGlyphOrder.py +271 -0
  179. fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  180. fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  181. fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  182. fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  183. fontTools/ttLib/tables/C_F_F_.py +61 -0
  184. fontTools/ttLib/tables/C_F_F__2.py +26 -0
  185. fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  186. fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  187. fontTools/ttLib/tables/D_S_I_G_.py +158 -0
  188. fontTools/ttLib/tables/D__e_b_g.py +35 -0
  189. fontTools/ttLib/tables/DefaultTable.py +49 -0
  190. fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  191. fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  192. fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  193. fontTools/ttLib/tables/F__e_a_t.py +149 -0
  194. fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  195. fontTools/ttLib/tables/G_M_A_P_.py +148 -0
  196. fontTools/ttLib/tables/G_P_K_G_.py +133 -0
  197. fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  198. fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  199. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  200. fontTools/ttLib/tables/G__l_a_t.py +235 -0
  201. fontTools/ttLib/tables/G__l_o_c.py +85 -0
  202. fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  203. fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  204. fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  205. fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  206. fontTools/ttLib/tables/M_E_T_A_.py +352 -0
  207. fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  208. fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  209. fontTools/ttLib/tables/S_I_N_G_.py +99 -0
  210. fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  211. fontTools/ttLib/tables/S_V_G_.py +223 -0
  212. fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  213. fontTools/ttLib/tables/S__i_l_l.py +92 -0
  214. fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  215. fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  216. fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  217. fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  218. fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  219. fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  220. fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  221. fontTools/ttLib/tables/T_S_I__0.py +70 -0
  222. fontTools/ttLib/tables/T_S_I__1.py +163 -0
  223. fontTools/ttLib/tables/T_S_I__2.py +17 -0
  224. fontTools/ttLib/tables/T_S_I__3.py +22 -0
  225. fontTools/ttLib/tables/T_S_I__5.py +60 -0
  226. fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  227. fontTools/ttLib/tables/TupleVariation.py +884 -0
  228. fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  229. fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  230. fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  231. fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  232. fontTools/ttLib/tables/__init__.py +98 -0
  233. fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  234. fontTools/ttLib/tables/_a_v_a_r.py +193 -0
  235. fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  236. fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  237. fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
  238. fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  239. fontTools/ttLib/tables/_c_v_t.py +56 -0
  240. fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  241. fontTools/ttLib/tables/_f_p_g_m.py +62 -0
  242. fontTools/ttLib/tables/_f_v_a_r.py +261 -0
  243. fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  244. fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  245. fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
  246. fontTools/ttLib/tables/_g_v_a_r.py +340 -0
  247. fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  248. fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  249. fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  250. fontTools/ttLib/tables/_h_m_t_x.py +164 -0
  251. fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  252. fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  253. fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  254. fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  255. fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  256. fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  257. fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  258. fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  259. fontTools/ttLib/tables/_n_a_m_e.py +1242 -0
  260. fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  261. fontTools/ttLib/tables/_p_o_s_t.py +319 -0
  262. fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  263. fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  264. fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  265. fontTools/ttLib/tables/_t_r_a_k.py +332 -0
  266. fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  267. fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  268. fontTools/ttLib/tables/asciiTable.py +20 -0
  269. fontTools/ttLib/tables/grUtils.py +92 -0
  270. fontTools/ttLib/tables/otBase.py +1458 -0
  271. fontTools/ttLib/tables/otConverters.py +2068 -0
  272. fontTools/ttLib/tables/otData.py +6400 -0
  273. fontTools/ttLib/tables/otTables.py +2703 -0
  274. fontTools/ttLib/tables/otTraverse.py +163 -0
  275. fontTools/ttLib/tables/sbixGlyph.py +149 -0
  276. fontTools/ttLib/tables/sbixStrike.py +177 -0
  277. fontTools/ttLib/tables/table_API_readme.txt +91 -0
  278. fontTools/ttLib/tables/ttProgram.py +594 -0
  279. fontTools/ttLib/ttCollection.py +125 -0
  280. fontTools/ttLib/ttFont.py +1148 -0
  281. fontTools/ttLib/ttGlyphSet.py +490 -0
  282. fontTools/ttLib/ttVisitor.py +32 -0
  283. fontTools/ttLib/woff2.py +1680 -0
  284. fontTools/ttx.py +479 -0
  285. fontTools/ufoLib/__init__.py +2575 -0
  286. fontTools/ufoLib/converters.py +407 -0
  287. fontTools/ufoLib/errors.py +30 -0
  288. fontTools/ufoLib/etree.py +6 -0
  289. fontTools/ufoLib/filenames.py +356 -0
  290. fontTools/ufoLib/glifLib.py +2120 -0
  291. fontTools/ufoLib/kerning.py +141 -0
  292. fontTools/ufoLib/plistlib.py +47 -0
  293. fontTools/ufoLib/pointPen.py +6 -0
  294. fontTools/ufoLib/utils.py +107 -0
  295. fontTools/ufoLib/validators.py +1208 -0
  296. fontTools/unicode.py +50 -0
  297. fontTools/unicodedata/Blocks.py +817 -0
  298. fontTools/unicodedata/Mirrored.py +446 -0
  299. fontTools/unicodedata/OTTags.py +50 -0
  300. fontTools/unicodedata/ScriptExtensions.py +832 -0
  301. fontTools/unicodedata/Scripts.py +3639 -0
  302. fontTools/unicodedata/__init__.py +306 -0
  303. fontTools/varLib/__init__.py +1600 -0
  304. fontTools/varLib/__main__.py +6 -0
  305. fontTools/varLib/avar/__init__.py +0 -0
  306. fontTools/varLib/avar/__main__.py +72 -0
  307. fontTools/varLib/avar/build.py +79 -0
  308. fontTools/varLib/avar/map.py +108 -0
  309. fontTools/varLib/avar/plan.py +1004 -0
  310. fontTools/varLib/avar/unbuild.py +271 -0
  311. fontTools/varLib/avarPlanner.py +8 -0
  312. fontTools/varLib/builder.py +215 -0
  313. fontTools/varLib/cff.py +631 -0
  314. fontTools/varLib/errors.py +219 -0
  315. fontTools/varLib/featureVars.py +703 -0
  316. fontTools/varLib/hvar.py +113 -0
  317. fontTools/varLib/instancer/__init__.py +2052 -0
  318. fontTools/varLib/instancer/__main__.py +5 -0
  319. fontTools/varLib/instancer/featureVars.py +190 -0
  320. fontTools/varLib/instancer/names.py +388 -0
  321. fontTools/varLib/instancer/solver.py +309 -0
  322. fontTools/varLib/interpolatable.py +1209 -0
  323. fontTools/varLib/interpolatableHelpers.py +399 -0
  324. fontTools/varLib/interpolatablePlot.py +1269 -0
  325. fontTools/varLib/interpolatableTestContourOrder.py +82 -0
  326. fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
  327. fontTools/varLib/interpolate_layout.py +124 -0
  328. fontTools/varLib/iup.c +19815 -0
  329. fontTools/varLib/iup.cp311-win32.pyd +0 -0
  330. fontTools/varLib/iup.py +490 -0
  331. fontTools/varLib/merger.py +1717 -0
  332. fontTools/varLib/models.py +642 -0
  333. fontTools/varLib/multiVarStore.py +253 -0
  334. fontTools/varLib/mutator.py +529 -0
  335. fontTools/varLib/mvar.py +40 -0
  336. fontTools/varLib/plot.py +238 -0
  337. fontTools/varLib/stat.py +149 -0
  338. fontTools/varLib/varStore.py +739 -0
  339. fontTools/voltLib/__init__.py +5 -0
  340. fontTools/voltLib/__main__.py +206 -0
  341. fontTools/voltLib/ast.py +452 -0
  342. fontTools/voltLib/error.py +12 -0
  343. fontTools/voltLib/lexer.py +99 -0
  344. fontTools/voltLib/parser.py +664 -0
  345. fontTools/voltLib/voltToFea.py +911 -0
  346. fonttools-4.60.2.data/data/share/man/man1/ttx.1 +225 -0
  347. fonttools-4.60.2.dist-info/METADATA +2250 -0
  348. fonttools-4.60.2.dist-info/RECORD +353 -0
  349. fonttools-4.60.2.dist-info/WHEEL +5 -0
  350. fonttools-4.60.2.dist-info/entry_points.txt +5 -0
  351. fonttools-4.60.2.dist-info/licenses/LICENSE +21 -0
  352. fonttools-4.60.2.dist-info/licenses/LICENSE.external +388 -0
  353. fonttools-4.60.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,340 @@
1
+ from collections import deque
2
+ from functools import partial
3
+ from fontTools.misc import sstruct
4
+ from fontTools.misc.textTools import safeEval
5
+ from fontTools.misc.lazyTools import LazyDict
6
+ from fontTools.ttLib import OPTIMIZE_FONT_SPEED
7
+ from fontTools.ttLib.tables.TupleVariation import TupleVariation
8
+ from . import DefaultTable
9
+ import array
10
+ import itertools
11
+ import logging
12
+ import struct
13
+ import sys
14
+ import fontTools.ttLib.tables.TupleVariation as tv
15
+
16
+ log = logging.getLogger(__name__)
17
+
18
+ # https://www.microsoft.com/typography/otspec/gvar.htm
19
+ # https://www.microsoft.com/typography/otspec/otvarcommonformats.htm
20
+ #
21
+ # Apple's documentation of 'gvar':
22
+ # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gvar.html
23
+ #
24
+ # FreeType2 source code for parsing 'gvar':
25
+ # http://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/src/truetype/ttgxvar.c
26
+
27
+ GVAR_HEADER_FORMAT_HEAD = """
28
+ > # big endian
29
+ version: H
30
+ reserved: H
31
+ axisCount: H
32
+ sharedTupleCount: H
33
+ offsetToSharedTuples: I
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
39
+ flags: H
40
+ offsetToGlyphVariationData: I
41
+ """
42
+
43
+ GVAR_HEADER_SIZE_HEAD = sstruct.calcsize(GVAR_HEADER_FORMAT_HEAD)
44
+ GVAR_HEADER_SIZE_TAIL = sstruct.calcsize(GVAR_HEADER_FORMAT_TAIL)
45
+
46
+
47
+ class table__g_v_a_r(DefaultTable.DefaultTable):
48
+ """Glyph Variations table
49
+
50
+ The ``gvar`` table provides the per-glyph variation data that
51
+ describe how glyph outlines in the ``glyf`` table change across
52
+ the variation space that is defined for the font in the ``fvar``
53
+ table.
54
+
55
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/gvar
56
+ """
57
+
58
+ dependencies = ["fvar", "glyf"]
59
+ gid_size = 2
60
+
61
+ def __init__(self, tag=None):
62
+ DefaultTable.DefaultTable.__init__(self, tag)
63
+ self.version, self.reserved = 1, 0
64
+ self.variations = {}
65
+
66
+ def compile(self, ttFont):
67
+ axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
68
+ sharedTuples = tv.compileSharedTuples(
69
+ axisTags, itertools.chain(*self.variations.values())
70
+ )
71
+ sharedTupleIndices = {coord: i for i, coord in enumerate(sharedTuples)}
72
+ sharedTupleSize = sum([len(c) for c in sharedTuples])
73
+ compiledGlyphs = self.compileGlyphs_(ttFont, axisTags, sharedTupleIndices)
74
+ offset = 0
75
+ offsets = []
76
+ for glyph in compiledGlyphs:
77
+ offsets.append(offset)
78
+ offset += len(glyph)
79
+ offsets.append(offset)
80
+ compiledOffsets, tableFormat = self.compileOffsets_(offsets)
81
+
82
+ GVAR_HEADER_SIZE = GVAR_HEADER_SIZE_HEAD + self.gid_size + GVAR_HEADER_SIZE_TAIL
83
+ header = {}
84
+ header["version"] = self.version
85
+ header["reserved"] = self.reserved
86
+ header["axisCount"] = len(axisTags)
87
+ header["sharedTupleCount"] = len(sharedTuples)
88
+ header["offsetToSharedTuples"] = GVAR_HEADER_SIZE + len(compiledOffsets)
89
+ header["flags"] = tableFormat
90
+ header["offsetToGlyphVariationData"] = (
91
+ header["offsetToSharedTuples"] + sharedTupleSize
92
+ )
93
+
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)
101
+ result.extend(sharedTuples)
102
+ result.extend(compiledGlyphs)
103
+ return b"".join(result)
104
+
105
+ def compileGlyphs_(self, ttFont, axisTags, sharedCoordIndices):
106
+ optimizeSpeed = ttFont.cfg[OPTIMIZE_FONT_SPEED]
107
+ result = []
108
+ glyf = ttFont["glyf"]
109
+ for glyphName in ttFont.getGlyphOrder():
110
+ variations = self.variations.get(glyphName, [])
111
+ if not variations:
112
+ result.append(b"")
113
+ continue
114
+ pointCountUnused = 0 # pointCount is actually unused by compileGlyph
115
+ result.append(
116
+ compileGlyph_(
117
+ self.gid_size,
118
+ variations,
119
+ pointCountUnused,
120
+ axisTags,
121
+ sharedCoordIndices,
122
+ optimizeSize=not optimizeSpeed,
123
+ )
124
+ )
125
+ return result
126
+
127
+ def decompile(self, data, ttFont):
128
+ axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
129
+ glyphs = ttFont.getGlyphOrder()
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
+ )
149
+ sharedCoords = tv.decompileSharedTuples(
150
+ axisTags, self.sharedTupleCount, data, self.offsetToSharedTuples
151
+ )
152
+ variations = {}
153
+ offsetToData = self.offsetToGlyphVariationData
154
+ glyf = ttFont["glyf"]
155
+
156
+ def get_read_item():
157
+ reverseGlyphMap = ttFont.getReverseGlyphMap()
158
+ tableFormat = self.flags & 1
159
+
160
+ def read_item(glyphName):
161
+ gid = reverseGlyphMap[glyphName]
162
+ offsetSize = 2 if tableFormat == 0 else 4
163
+ startOffset = GVAR_HEADER_SIZE + offsetSize * gid
164
+ endOffset = startOffset + offsetSize * 2
165
+ offsets = table__g_v_a_r.decompileOffsets_(
166
+ data[startOffset:endOffset],
167
+ tableFormat=tableFormat,
168
+ glyphCount=1,
169
+ )
170
+ gvarData = data[offsetToData + offsets[0] : offsetToData + offsets[1]]
171
+ if not gvarData:
172
+ return []
173
+ glyph = glyf[glyphName]
174
+ numPointsInGlyph = self.getNumPoints_(glyph)
175
+ return decompileGlyph_(
176
+ self.gid_size, numPointsInGlyph, sharedCoords, axisTags, gvarData
177
+ )
178
+
179
+ return read_item
180
+
181
+ read_item = get_read_item()
182
+ l = LazyDict({glyphs[gid]: read_item for gid in range(self.glyphCount)})
183
+
184
+ self.variations = l
185
+
186
+ if ttFont.lazy is False: # Be lazy for None and True
187
+ self.ensureDecompiled()
188
+
189
+ def ensureDecompiled(self, recurse=False):
190
+ # The recurse argument is unused, but part of the signature of
191
+ # ensureDecompiled across the library.
192
+ # Use a zero-length deque to consume the lazy dict
193
+ deque(self.variations.values(), maxlen=0)
194
+
195
+ @staticmethod
196
+ def decompileOffsets_(data, tableFormat, glyphCount):
197
+ if tableFormat == 0:
198
+ # Short format: array of UInt16
199
+ offsets = array.array("H")
200
+ offsetsSize = (glyphCount + 1) * 2
201
+ else:
202
+ # Long format: array of UInt32
203
+ offsets = array.array("I")
204
+ offsetsSize = (glyphCount + 1) * 4
205
+ offsets.frombytes(data[0:offsetsSize])
206
+ if sys.byteorder != "big":
207
+ offsets.byteswap()
208
+
209
+ # In the short format, offsets need to be multiplied by 2.
210
+ # This is not documented in Apple's TrueType specification,
211
+ # but can be inferred from the FreeType implementation, and
212
+ # we could verify it with two sample GX fonts.
213
+ if tableFormat == 0:
214
+ offsets = [off * 2 for off in offsets]
215
+
216
+ return offsets
217
+
218
+ @staticmethod
219
+ def compileOffsets_(offsets):
220
+ """Packs a list of offsets into a 'gvar' offset table.
221
+
222
+ Returns a pair (bytestring, tableFormat). Bytestring is the
223
+ packed offset table. Format indicates whether the table
224
+ uses short (tableFormat=0) or long (tableFormat=1) integers.
225
+ The returned tableFormat should get packed into the flags field
226
+ of the 'gvar' header.
227
+ """
228
+ assert len(offsets) >= 2
229
+ for i in range(1, len(offsets)):
230
+ assert offsets[i - 1] <= offsets[i]
231
+ if max(offsets) <= 0xFFFF * 2:
232
+ packed = array.array("H", [n >> 1 for n in offsets])
233
+ tableFormat = 0
234
+ else:
235
+ packed = array.array("I", offsets)
236
+ tableFormat = 1
237
+ if sys.byteorder != "big":
238
+ packed.byteswap()
239
+ return (packed.tobytes(), tableFormat)
240
+
241
+ def toXML(self, writer, ttFont):
242
+ writer.simpletag("version", value=self.version)
243
+ writer.newline()
244
+ writer.simpletag("reserved", value=self.reserved)
245
+ writer.newline()
246
+ axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
247
+ for glyphName in ttFont.getGlyphNames():
248
+ variations = self.variations.get(glyphName)
249
+ if not variations:
250
+ continue
251
+ writer.begintag("glyphVariations", glyph=glyphName)
252
+ writer.newline()
253
+ for gvar in variations:
254
+ gvar.toXML(writer, axisTags)
255
+ writer.endtag("glyphVariations")
256
+ writer.newline()
257
+
258
+ def fromXML(self, name, attrs, content, ttFont):
259
+ if name == "version":
260
+ self.version = safeEval(attrs["value"])
261
+ elif name == "reserved":
262
+ self.reserved = safeEval(attrs["value"])
263
+ elif name == "glyphVariations":
264
+ if not hasattr(self, "variations"):
265
+ self.variations = {}
266
+ glyphName = attrs["glyph"]
267
+ glyph = ttFont["glyf"][glyphName]
268
+ numPointsInGlyph = self.getNumPoints_(glyph)
269
+ glyphVariations = []
270
+ for element in content:
271
+ if isinstance(element, tuple):
272
+ name, attrs, content = element
273
+ if name == "tuple":
274
+ gvar = TupleVariation({}, [None] * numPointsInGlyph)
275
+ glyphVariations.append(gvar)
276
+ for tupleElement in content:
277
+ if isinstance(tupleElement, tuple):
278
+ tupleName, tupleAttrs, tupleContent = tupleElement
279
+ gvar.fromXML(tupleName, tupleAttrs, tupleContent)
280
+ self.variations[glyphName] = glyphVariations
281
+
282
+ @staticmethod
283
+ def getNumPoints_(glyph):
284
+ NUM_PHANTOM_POINTS = 4
285
+
286
+ if glyph.isComposite():
287
+ return len(glyph.components) + NUM_PHANTOM_POINTS
288
+ else:
289
+ # Empty glyphs (eg. space, nonmarkingreturn) have no "coordinates" attribute.
290
+ return len(getattr(glyph, "coordinates", [])) + NUM_PHANTOM_POINTS
291
+
292
+
293
+ def compileGlyph_(
294
+ dataOffsetSize,
295
+ variations,
296
+ pointCount,
297
+ axisTags,
298
+ sharedCoordIndices,
299
+ *,
300
+ optimizeSize=True,
301
+ ):
302
+ assert dataOffsetSize in (2, 3)
303
+ tupleVariationCount, tuples, data = tv.compileTupleVariationStore(
304
+ variations, pointCount, axisTags, sharedCoordIndices, optimizeSize=optimizeSize
305
+ )
306
+ if tupleVariationCount == 0:
307
+ return b""
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:
318
+ result.append(b"\0") # padding
319
+ return b"".join(result)
320
+
321
+
322
+ def decompileGlyph_(dataOffsetSize, pointCount, sharedTuples, axisTags, data):
323
+ assert dataOffsetSize in (2, 3)
324
+ if len(data) < 2 + dataOffsetSize:
325
+ return []
326
+
327
+ tupleVariationCount = int.from_bytes(data[:2], "big")
328
+ offsetToData = int.from_bytes(data[2 : 2 + dataOffsetSize], "big")
329
+
330
+ dataPos = offsetToData
331
+ return tv.decompileTupleVariationStore(
332
+ "gvar",
333
+ axisTags,
334
+ tupleVariationCount,
335
+ pointCount,
336
+ sharedTuples,
337
+ data,
338
+ 2 + dataOffsetSize,
339
+ offsetToData,
340
+ )
@@ -0,0 +1,127 @@
1
+ from fontTools.misc import sstruct
2
+ from fontTools.misc.textTools import bytechr, byteord, strjoin
3
+ from . import DefaultTable
4
+ import array
5
+ from collections.abc import Mapping
6
+
7
+ hdmxHeaderFormat = """
8
+ > # big endian!
9
+ version: H
10
+ numRecords: H
11
+ recordSize: l
12
+ """
13
+
14
+
15
+ class _GlyphnamedList(Mapping):
16
+ def __init__(self, reverseGlyphOrder, data):
17
+ self._array = data
18
+ self._map = dict(reverseGlyphOrder)
19
+
20
+ def __getitem__(self, k):
21
+ return self._array[self._map[k]]
22
+
23
+ def __len__(self):
24
+ return len(self._map)
25
+
26
+ def __iter__(self):
27
+ return iter(self._map)
28
+
29
+ def keys(self):
30
+ return self._map.keys()
31
+
32
+
33
+ class table__h_d_m_x(DefaultTable.DefaultTable):
34
+ """Horizontal Device Metrics table
35
+
36
+ The ``hdmx`` table is an optional table that stores advance widths for
37
+ glyph outlines at specified pixel sizes.
38
+
39
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/hdmx
40
+ """
41
+
42
+ def decompile(self, data, ttFont):
43
+ numGlyphs = ttFont["maxp"].numGlyphs
44
+ glyphOrder = ttFont.getGlyphOrder()
45
+ dummy, data = sstruct.unpack2(hdmxHeaderFormat, data, self)
46
+ self.hdmx = {}
47
+ for i in range(self.numRecords):
48
+ ppem = byteord(data[0])
49
+ maxSize = byteord(data[1])
50
+ widths = _GlyphnamedList(
51
+ ttFont.getReverseGlyphMap(), array.array("B", data[2 : 2 + numGlyphs])
52
+ )
53
+ self.hdmx[ppem] = widths
54
+ data = data[self.recordSize :]
55
+ assert len(data) == 0, "too much hdmx data"
56
+
57
+ def compile(self, ttFont):
58
+ self.version = 0
59
+ numGlyphs = ttFont["maxp"].numGlyphs
60
+ glyphOrder = ttFont.getGlyphOrder()
61
+ self.recordSize = 4 * ((2 + numGlyphs + 3) // 4)
62
+ pad = (self.recordSize - 2 - numGlyphs) * b"\0"
63
+ self.numRecords = len(self.hdmx)
64
+ data = sstruct.pack(hdmxHeaderFormat, self)
65
+ items = sorted(self.hdmx.items())
66
+ for ppem, widths in items:
67
+ data = data + bytechr(ppem) + bytechr(max(widths.values()))
68
+ for glyphName in glyphOrder:
69
+ width = widths[glyphName]
70
+ data = data + bytechr(width)
71
+ data = data + pad
72
+ return data
73
+
74
+ def toXML(self, writer, ttFont):
75
+ writer.begintag("hdmxData")
76
+ writer.newline()
77
+ ppems = sorted(self.hdmx.keys())
78
+ records = []
79
+ format = ""
80
+ for ppem in ppems:
81
+ widths = self.hdmx[ppem]
82
+ records.append(widths)
83
+ format = format + "%4d"
84
+ glyphNames = ttFont.getGlyphOrder()[:]
85
+ glyphNames.sort()
86
+ maxNameLen = max(map(len, glyphNames))
87
+ format = "%" + repr(maxNameLen) + "s:" + format + " ;"
88
+ writer.write(format % (("ppem",) + tuple(ppems)))
89
+ writer.newline()
90
+ writer.newline()
91
+ for glyphName in glyphNames:
92
+ row = []
93
+ for ppem in ppems:
94
+ widths = self.hdmx[ppem]
95
+ row.append(widths[glyphName])
96
+ if ";" in glyphName:
97
+ glyphName = "\\x3b".join(glyphName.split(";"))
98
+ writer.write(format % ((glyphName,) + tuple(row)))
99
+ writer.newline()
100
+ writer.endtag("hdmxData")
101
+ writer.newline()
102
+
103
+ def fromXML(self, name, attrs, content, ttFont):
104
+ if name != "hdmxData":
105
+ return
106
+ content = strjoin(content)
107
+ lines = content.split(";")
108
+ topRow = lines[0].split()
109
+ assert topRow[0] == "ppem:", "illegal hdmx format"
110
+ ppems = list(map(int, topRow[1:]))
111
+ self.hdmx = hdmx = {}
112
+ for ppem in ppems:
113
+ hdmx[ppem] = {}
114
+ lines = (line.split() for line in lines[1:])
115
+ for line in lines:
116
+ if not line:
117
+ continue
118
+ assert line[0][-1] == ":", "illegal hdmx format"
119
+ glyphName = line[0][:-1]
120
+ if "\\" in glyphName:
121
+ from fontTools.misc.textTools import safeEval
122
+
123
+ glyphName = safeEval('"""' + glyphName + '"""')
124
+ line = list(map(int, line[1:]))
125
+ assert len(line) == len(ppems), "illegal hdmx format"
126
+ for i, ppem in enumerate(ppems):
127
+ hdmx[ppem][glyphName] = line[i]
@@ -0,0 +1,130 @@
1
+ from fontTools.misc import sstruct
2
+ from fontTools.misc.fixedTools import floatToFixedToStr, strToFixedToFloat
3
+ from fontTools.misc.textTools import safeEval, num2binary, binary2num
4
+ from fontTools.misc.timeTools import (
5
+ timestampFromString,
6
+ timestampToString,
7
+ timestampNow,
8
+ )
9
+ from fontTools.misc.timeTools import epoch_diff as mac_epoch_diff # For backward compat
10
+ from fontTools.misc.arrayTools import intRect, unionRect
11
+ from . import DefaultTable
12
+ import logging
13
+
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+ headFormat = """
18
+ > # big endian
19
+ tableVersion: 16.16F
20
+ fontRevision: 16.16F
21
+ checkSumAdjustment: I
22
+ magicNumber: I
23
+ flags: H
24
+ unitsPerEm: H
25
+ created: Q
26
+ modified: Q
27
+ xMin: h
28
+ yMin: h
29
+ xMax: h
30
+ yMax: h
31
+ macStyle: H
32
+ lowestRecPPEM: H
33
+ fontDirectionHint: h
34
+ indexToLocFormat: h
35
+ glyphDataFormat: h
36
+ """
37
+
38
+
39
+ class table__h_e_a_d(DefaultTable.DefaultTable):
40
+ """Font Header table
41
+
42
+ The ``head`` table contains a variety of font-wide information.
43
+
44
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/head
45
+ """
46
+
47
+ dependencies = ["maxp", "loca", "CFF ", "CFF2"]
48
+
49
+ def decompile(self, data, ttFont):
50
+ dummy, rest = sstruct.unpack2(headFormat, data, self)
51
+ if rest:
52
+ # this is quite illegal, but there seem to be fonts out there that do this
53
+ log.warning("extra bytes at the end of 'head' table")
54
+ assert rest == b"\0\0"
55
+
56
+ # For timestamp fields, ignore the top four bytes. Some fonts have
57
+ # bogus values there. Since till 2038 those bytes only can be zero,
58
+ # ignore them.
59
+ #
60
+ # https://github.com/fonttools/fonttools/issues/99#issuecomment-66776810
61
+ for stamp in "created", "modified":
62
+ value = getattr(self, stamp)
63
+ if value > 0xFFFFFFFF:
64
+ log.warning("'%s' timestamp out of range; ignoring top bytes", stamp)
65
+ value &= 0xFFFFFFFF
66
+ setattr(self, stamp, value)
67
+ if value < 0x7C259DC0: # January 1, 1970 00:00:00
68
+ log.warning(
69
+ "'%s' timestamp seems very low; regarding as unix timestamp", stamp
70
+ )
71
+ value += 0x7C259DC0
72
+ setattr(self, stamp, value)
73
+
74
+ def compile(self, ttFont):
75
+ if ttFont.recalcBBoxes:
76
+ # For TT-flavored fonts, xMin, yMin, xMax and yMax are set in table__m_a_x_p.recalc().
77
+ if "CFF " in ttFont:
78
+ topDict = ttFont["CFF "].cff.topDictIndex[0]
79
+ self.xMin, self.yMin, self.xMax, self.yMax = intRect(topDict.FontBBox)
80
+ elif "CFF2" in ttFont:
81
+ topDict = ttFont["CFF2"].cff.topDictIndex[0]
82
+ charStrings = topDict.CharStrings
83
+ fontBBox = None
84
+ for charString in charStrings.values():
85
+ bounds = charString.calcBounds(charStrings)
86
+ if bounds is not None:
87
+ if fontBBox is not None:
88
+ fontBBox = unionRect(fontBBox, bounds)
89
+ else:
90
+ fontBBox = bounds
91
+ if fontBBox is not None:
92
+ self.xMin, self.yMin, self.xMax, self.yMax = intRect(fontBBox)
93
+ if ttFont.recalcTimestamp:
94
+ self.modified = timestampNow()
95
+ data = sstruct.pack(headFormat, self)
96
+ return data
97
+
98
+ def toXML(self, writer, ttFont):
99
+ writer.comment("Most of this table will be recalculated by the compiler")
100
+ writer.newline()
101
+ _, names, fixes = sstruct.getformat(headFormat)
102
+ for name in names:
103
+ value = getattr(self, name)
104
+ if name in fixes:
105
+ value = floatToFixedToStr(value, precisionBits=fixes[name])
106
+ elif name in ("created", "modified"):
107
+ value = timestampToString(value)
108
+ elif name in ("magicNumber", "checkSumAdjustment"):
109
+ if value < 0:
110
+ value = value + 0x100000000
111
+ value = hex(value)
112
+ if value[-1:] == "L":
113
+ value = value[:-1]
114
+ elif name in ("macStyle", "flags"):
115
+ value = num2binary(value, 16)
116
+ writer.simpletag(name, value=value)
117
+ writer.newline()
118
+
119
+ def fromXML(self, name, attrs, content, ttFont):
120
+ value = attrs["value"]
121
+ fixes = sstruct.getformat(headFormat)[2]
122
+ if name in fixes:
123
+ value = strToFixedToFloat(value, precisionBits=fixes[name])
124
+ elif name in ("created", "modified"):
125
+ value = timestampFromString(value)
126
+ elif name in ("macStyle", "flags"):
127
+ value = binary2num(value)
128
+ else:
129
+ value = safeEval(value)
130
+ setattr(self, name, value)