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,30 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Iterable, Optional, TypeVar, Union
3
+ from collections.abc import Callable, Sequence
4
+ from fontTools.misc.filesystem._base import FS
5
+ from os import PathLike
6
+ from xml.etree.ElementTree import Element as ElementTreeElement
7
+
8
+ if TYPE_CHECKING:
9
+ from fontTools.ufoLib import UFOFormatVersion
10
+ from fontTools.ufoLib.glifLib import GLIFFormatVersion
11
+ from lxml.etree import _Element as LxmlElement
12
+
13
+
14
+ T = TypeVar("T") # Generic type
15
+ K = TypeVar("K") # Generic dict key type
16
+ V = TypeVar("V") # Generic dict value type
17
+
18
+ GlyphNameToFileNameFunc = Optional[Callable[[str, set[str]], str]]
19
+ ElementType = Union[ElementTreeElement, "LxmlElement"]
20
+ FormatVersion = Union[int, tuple[int, int]]
21
+ FormatVersions = Optional[Iterable[FormatVersion]]
22
+ GLIFFormatVersionInput = Optional[Union[int, tuple[int, int], "GLIFFormatVersion"]]
23
+ UFOFormatVersionInput = Optional[Union[int, tuple[int, int], "UFOFormatVersion"]]
24
+ IntFloat = Union[int, float]
25
+ KerningPair = tuple[str, str]
26
+ KerningDict = dict[KerningPair, IntFloat]
27
+ KerningGroups = dict[str, Sequence[str]]
28
+ KerningNested = dict[str, dict[str, IntFloat]]
29
+ PathStr = Union[str, PathLike[str]]
30
+ PathOrFS = Union[PathStr, FS]
@@ -0,0 +1,258 @@
1
+ """CFF2 to CFF converter."""
2
+
3
+ from fontTools.ttLib import TTFont, newTable
4
+ from fontTools.misc.cliTools import makeOutputFileName
5
+ from fontTools.misc.psCharStrings import T2StackUseExtractor
6
+ from fontTools.cffLib import (
7
+ TopDictIndex,
8
+ buildOrder,
9
+ buildDefaults,
10
+ topDictOperators,
11
+ privateDictOperators,
12
+ FDSelect,
13
+ )
14
+ from .transforms import desubroutinizeCharString
15
+ from .specializer import specializeProgram
16
+ from .width import optimizeWidths
17
+ from collections import defaultdict
18
+ import logging
19
+
20
+
21
+ __all__ = ["convertCFF2ToCFF", "main"]
22
+
23
+
24
+ log = logging.getLogger("fontTools.cffLib")
25
+
26
+
27
+ def _convertCFF2ToCFF(cff, otFont):
28
+ """Converts this object from CFF2 format to CFF format. This conversion
29
+ is done 'in-place'. The conversion cannot be reversed.
30
+
31
+ The CFF2 font cannot be variable. (TODO Accept those and convert to the
32
+ default instance?)
33
+
34
+ This assumes a decompiled CFF2 table. (i.e. that the object has been
35
+ filled via :meth:`decompile` and e.g. not loaded from XML.)"""
36
+
37
+ cff.major = 1
38
+
39
+ topDictData = TopDictIndex(None)
40
+ for item in cff.topDictIndex:
41
+ # Iterate over, such that all are decompiled
42
+ item.cff2GetGlyphOrder = None
43
+ topDictData.append(item)
44
+ cff.topDictIndex = topDictData
45
+ topDict = topDictData[0]
46
+
47
+ if hasattr(topDict, "VarStore"):
48
+ raise ValueError("Variable CFF2 font cannot be converted to CFF format.")
49
+
50
+ opOrder = buildOrder(topDictOperators)
51
+ topDict.order = opOrder
52
+ for key in topDict.rawDict.keys():
53
+ if key not in opOrder:
54
+ del topDict.rawDict[key]
55
+ if hasattr(topDict, key):
56
+ delattr(topDict, key)
57
+
58
+ charStrings = topDict.CharStrings
59
+
60
+ fdArray = topDict.FDArray
61
+ if not hasattr(topDict, "FDSelect"):
62
+ # FDSelect is optional in CFF2, but required in CFF.
63
+ fdSelect = topDict.FDSelect = FDSelect()
64
+ fdSelect.gidArray = [0] * len(charStrings.charStrings)
65
+
66
+ defaults = buildDefaults(privateDictOperators)
67
+ order = buildOrder(privateDictOperators)
68
+ for fd in fdArray:
69
+ fd.setCFF2(False)
70
+ privateDict = fd.Private
71
+ privateDict.order = order
72
+ for key in order:
73
+ if key not in privateDict.rawDict and key in defaults:
74
+ privateDict.rawDict[key] = defaults[key]
75
+ for key in privateDict.rawDict.keys():
76
+ if key not in order:
77
+ del privateDict.rawDict[key]
78
+ if hasattr(privateDict, key):
79
+ delattr(privateDict, key)
80
+
81
+ # Add ending operators
82
+ for cs in charStrings.values():
83
+ cs.decompile()
84
+ cs.program.append("endchar")
85
+ for subrSets in [cff.GlobalSubrs] + [
86
+ getattr(fd.Private, "Subrs", []) for fd in fdArray
87
+ ]:
88
+ for cs in subrSets:
89
+ cs.program.append("return")
90
+
91
+ # Add (optimal) width to CharStrings that need it.
92
+ widths = defaultdict(list)
93
+ metrics = otFont["hmtx"].metrics
94
+ for glyphName in charStrings.keys():
95
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
96
+ if fdIndex == None:
97
+ fdIndex = 0
98
+ widths[fdIndex].append(metrics[glyphName][0])
99
+ for fdIndex, widthList in widths.items():
100
+ bestDefault, bestNominal = optimizeWidths(widthList)
101
+ private = fdArray[fdIndex].Private
102
+ private.defaultWidthX = bestDefault
103
+ private.nominalWidthX = bestNominal
104
+ for glyphName in charStrings.keys():
105
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
106
+ if fdIndex == None:
107
+ fdIndex = 0
108
+ private = fdArray[fdIndex].Private
109
+ width = metrics[glyphName][0]
110
+ if width != private.defaultWidthX:
111
+ cs.program.insert(0, width - private.nominalWidthX)
112
+
113
+ # Handle stack use since stack-depth is lower in CFF than in CFF2.
114
+ for glyphName in charStrings.keys():
115
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
116
+ if fdIndex is None:
117
+ fdIndex = 0
118
+ private = fdArray[fdIndex].Private
119
+ extractor = T2StackUseExtractor(
120
+ getattr(private, "Subrs", []), cff.GlobalSubrs, private=private
121
+ )
122
+ stackUse = extractor.execute(cs)
123
+ if stackUse > 48: # CFF stack depth is 48
124
+ desubroutinizeCharString(cs)
125
+ cs.program = specializeProgram(cs.program)
126
+
127
+ # Unused subroutines are still in CFF2 (ie. lacking 'return' operator)
128
+ # because they were not decompiled when we added the 'return'.
129
+ # Moreover, some used subroutines may have become unused after the
130
+ # stack-use fixup. So we remove all unused subroutines now.
131
+ cff.remove_unused_subroutines()
132
+
133
+ mapping = {
134
+ name: ("cid" + str(n).zfill(5) if n else ".notdef")
135
+ for n, name in enumerate(topDict.charset)
136
+ }
137
+ topDict.charset = [
138
+ "cid" + str(n).zfill(5) if n else ".notdef" for n in range(len(topDict.charset))
139
+ ]
140
+ charStrings.charStrings = {
141
+ mapping[name]: v for name, v in charStrings.charStrings.items()
142
+ }
143
+
144
+ topDict.ROS = ("Adobe", "Identity", 0)
145
+
146
+
147
+ def convertCFF2ToCFF(font, *, updatePostTable=True):
148
+ if "CFF2" not in font:
149
+ raise ValueError("Input font does not contain a CFF2 table.")
150
+ cff = font["CFF2"].cff
151
+ _convertCFF2ToCFF(cff, font)
152
+ del font["CFF2"]
153
+ table = font["CFF "] = newTable("CFF ")
154
+ table.cff = cff
155
+
156
+ if updatePostTable and "post" in font:
157
+ # Only version supported for fonts with CFF table is 0x00030000 not 0x20000
158
+ post = font["post"]
159
+ if post.formatType == 2.0:
160
+ post.formatType = 3.0
161
+
162
+
163
+ def main(args=None):
164
+ """Convert CFF2 OTF font to CFF OTF font"""
165
+ if args is None:
166
+ import sys
167
+
168
+ args = sys.argv[1:]
169
+
170
+ import argparse
171
+
172
+ parser = argparse.ArgumentParser(
173
+ "fonttools cffLib.CFF2ToCFF",
174
+ description="Convert a non-variable CFF2 font to CFF.",
175
+ )
176
+ parser.add_argument(
177
+ "input", metavar="INPUT.ttf", help="Input OTF file with CFF table."
178
+ )
179
+ parser.add_argument(
180
+ "-o",
181
+ "--output",
182
+ metavar="OUTPUT.ttf",
183
+ default=None,
184
+ help="Output instance OTF file (default: INPUT-CFF2.ttf).",
185
+ )
186
+ parser.add_argument(
187
+ "--no-recalc-timestamp",
188
+ dest="recalc_timestamp",
189
+ action="store_false",
190
+ help="Don't set the output font's timestamp to the current time.",
191
+ )
192
+ parser.add_argument(
193
+ "--remove-overlaps",
194
+ action="store_true",
195
+ help="Merge overlapping contours and components. Requires skia-pathops",
196
+ )
197
+ parser.add_argument(
198
+ "--ignore-overlap-errors",
199
+ action="store_true",
200
+ help="Don't crash if the remove-overlaps operation fails for some glyphs.",
201
+ )
202
+ loggingGroup = parser.add_mutually_exclusive_group(required=False)
203
+ loggingGroup.add_argument(
204
+ "-v", "--verbose", action="store_true", help="Run more verbosely."
205
+ )
206
+ loggingGroup.add_argument(
207
+ "-q", "--quiet", action="store_true", help="Turn verbosity off."
208
+ )
209
+ options = parser.parse_args(args)
210
+
211
+ from fontTools import configLogger
212
+
213
+ configLogger(
214
+ level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
215
+ )
216
+
217
+ import os
218
+
219
+ infile = options.input
220
+ if not os.path.isfile(infile):
221
+ parser.error("No such file '{}'".format(infile))
222
+
223
+ outfile = (
224
+ makeOutputFileName(infile, overWrite=True, suffix="-CFF")
225
+ if not options.output
226
+ else options.output
227
+ )
228
+
229
+ font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False)
230
+
231
+ convertCFF2ToCFF(font)
232
+
233
+ if options.remove_overlaps:
234
+ from fontTools.ttLib.removeOverlaps import removeOverlaps
235
+ from io import BytesIO
236
+
237
+ log.debug("Removing overlaps")
238
+
239
+ stream = BytesIO()
240
+ font.save(stream)
241
+ stream.seek(0)
242
+ font = TTFont(stream, recalcTimestamp=False, recalcBBoxes=False)
243
+ removeOverlaps(
244
+ font,
245
+ ignoreErrors=options.ignore_overlap_errors,
246
+ )
247
+
248
+ log.info(
249
+ "Saving %s",
250
+ outfile,
251
+ )
252
+ font.save(outfile)
253
+
254
+
255
+ if __name__ == "__main__":
256
+ import sys
257
+
258
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,305 @@
1
+ """CFF to CFF2 converter."""
2
+
3
+ from fontTools.ttLib import TTFont, newTable
4
+ from fontTools.misc.cliTools import makeOutputFileName
5
+ from fontTools.misc.psCharStrings import T2WidthExtractor
6
+ from fontTools.cffLib import (
7
+ TopDictIndex,
8
+ FDArrayIndex,
9
+ FontDict,
10
+ buildOrder,
11
+ topDictOperators,
12
+ privateDictOperators,
13
+ topDictOperators2,
14
+ privateDictOperators2,
15
+ )
16
+ from io import BytesIO
17
+ import logging
18
+
19
+ __all__ = ["convertCFFToCFF2", "main"]
20
+
21
+
22
+ log = logging.getLogger("fontTools.cffLib")
23
+
24
+
25
+ class _NominalWidthUsedError(Exception):
26
+ def __add__(self, other):
27
+ raise self
28
+
29
+ def __radd__(self, other):
30
+ raise self
31
+
32
+
33
+ def _convertCFFToCFF2(cff, otFont):
34
+ """Converts this object from CFF format to CFF2 format. This conversion
35
+ is done 'in-place'. The conversion cannot be reversed.
36
+
37
+ This assumes a decompiled CFF table. (i.e. that the object has been
38
+ filled via :meth:`decompile` and e.g. not loaded from XML.)"""
39
+
40
+ # Clean up T2CharStrings
41
+
42
+ topDict = cff.topDictIndex[0]
43
+ fdArray = topDict.FDArray if hasattr(topDict, "FDArray") else None
44
+ charStrings = topDict.CharStrings
45
+ globalSubrs = cff.GlobalSubrs
46
+ localSubrs = (
47
+ [getattr(fd.Private, "Subrs", []) for fd in fdArray]
48
+ if fdArray
49
+ else (
50
+ [topDict.Private.Subrs]
51
+ if hasattr(topDict, "Private") and hasattr(topDict.Private, "Subrs")
52
+ else []
53
+ )
54
+ )
55
+
56
+ for glyphName in charStrings.keys():
57
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
58
+ cs.decompile()
59
+
60
+ # Clean up subroutines first
61
+ for subrs in [globalSubrs] + localSubrs:
62
+ for subr in subrs:
63
+ program = subr.program
64
+ i = j = len(program)
65
+ try:
66
+ i = program.index("return")
67
+ except ValueError:
68
+ pass
69
+ try:
70
+ j = program.index("endchar")
71
+ except ValueError:
72
+ pass
73
+ program[min(i, j) :] = []
74
+
75
+ # Clean up glyph charstrings
76
+ removeUnusedSubrs = False
77
+ nominalWidthXError = _NominalWidthUsedError()
78
+ for glyphName in charStrings.keys():
79
+ cs, fdIndex = charStrings.getItemAndSelector(glyphName)
80
+ program = cs.program
81
+
82
+ thisLocalSubrs = (
83
+ localSubrs[fdIndex]
84
+ if fdIndex is not None
85
+ else (
86
+ getattr(topDict.Private, "Subrs", [])
87
+ if hasattr(topDict, "Private")
88
+ else []
89
+ )
90
+ )
91
+
92
+ # Intentionally use custom type for nominalWidthX, such that any
93
+ # CharString that has an explicit width encoded will throw back to us.
94
+ extractor = T2WidthExtractor(
95
+ thisLocalSubrs,
96
+ globalSubrs,
97
+ nominalWidthXError,
98
+ 0,
99
+ )
100
+ try:
101
+ extractor.execute(cs)
102
+ except _NominalWidthUsedError:
103
+ # Program has explicit width. We want to drop it, but can't
104
+ # just pop the first number since it may be a subroutine call.
105
+ # Instead, when seeing that, we embed the subroutine and recurse.
106
+ # If this ever happened, we later prune unused subroutines.
107
+ while len(program) >= 2 and program[1] in ["callsubr", "callgsubr"]:
108
+ removeUnusedSubrs = True
109
+ subrNumber = program.pop(0)
110
+ assert isinstance(subrNumber, int), subrNumber
111
+ op = program.pop(0)
112
+ bias = extractor.localBias if op == "callsubr" else extractor.globalBias
113
+ subrNumber += bias
114
+ subrSet = thisLocalSubrs if op == "callsubr" else globalSubrs
115
+ subrProgram = subrSet[subrNumber].program
116
+ program[:0] = subrProgram
117
+ # Now pop the actual width
118
+ assert len(program) >= 1, program
119
+ program.pop(0)
120
+
121
+ if program and program[-1] == "endchar":
122
+ program.pop()
123
+
124
+ if removeUnusedSubrs:
125
+ cff.remove_unused_subroutines()
126
+
127
+ # Upconvert TopDict
128
+
129
+ cff.major = 2
130
+ cff2GetGlyphOrder = cff.otFont.getGlyphOrder
131
+ topDictData = TopDictIndex(None, cff2GetGlyphOrder)
132
+ for item in cff.topDictIndex:
133
+ # Iterate over, such that all are decompiled
134
+ topDictData.append(item)
135
+ cff.topDictIndex = topDictData
136
+ topDict = topDictData[0]
137
+ if hasattr(topDict, "Private"):
138
+ privateDict = topDict.Private
139
+ else:
140
+ privateDict = None
141
+ opOrder = buildOrder(topDictOperators2)
142
+ topDict.order = opOrder
143
+ topDict.cff2GetGlyphOrder = cff2GetGlyphOrder
144
+
145
+ if not hasattr(topDict, "FDArray"):
146
+ fdArray = topDict.FDArray = FDArrayIndex()
147
+ fdArray.strings = None
148
+ fdArray.GlobalSubrs = topDict.GlobalSubrs
149
+ topDict.GlobalSubrs.fdArray = fdArray
150
+ charStrings = topDict.CharStrings
151
+ if charStrings.charStringsAreIndexed:
152
+ charStrings.charStringsIndex.fdArray = fdArray
153
+ else:
154
+ charStrings.fdArray = fdArray
155
+ fontDict = FontDict()
156
+ fontDict.setCFF2(True)
157
+ fdArray.append(fontDict)
158
+ fontDict.Private = privateDict
159
+ privateOpOrder = buildOrder(privateDictOperators2)
160
+ if privateDict is not None:
161
+ for entry in privateDictOperators:
162
+ key = entry[1]
163
+ if key not in privateOpOrder:
164
+ if key in privateDict.rawDict:
165
+ # print "Removing private dict", key
166
+ del privateDict.rawDict[key]
167
+ if hasattr(privateDict, key):
168
+ delattr(privateDict, key)
169
+ # print "Removing privateDict attr", key
170
+ else:
171
+ # clean up the PrivateDicts in the fdArray
172
+ fdArray = topDict.FDArray
173
+ privateOpOrder = buildOrder(privateDictOperators2)
174
+ for fontDict in fdArray:
175
+ fontDict.setCFF2(True)
176
+ for key in list(fontDict.rawDict.keys()):
177
+ if key not in fontDict.order:
178
+ del fontDict.rawDict[key]
179
+ if hasattr(fontDict, key):
180
+ delattr(fontDict, key)
181
+
182
+ privateDict = fontDict.Private
183
+ for entry in privateDictOperators:
184
+ key = entry[1]
185
+ if key not in privateOpOrder:
186
+ if key in list(privateDict.rawDict.keys()):
187
+ # print "Removing private dict", key
188
+ del privateDict.rawDict[key]
189
+ if hasattr(privateDict, key):
190
+ delattr(privateDict, key)
191
+ # print "Removing privateDict attr", key
192
+
193
+ # Now delete up the deprecated topDict operators from CFF 1.0
194
+ for entry in topDictOperators:
195
+ key = entry[1]
196
+ # We seem to need to keep the charset operator for now,
197
+ # or we fail to compile with some fonts, like AdditionFont.otf.
198
+ # I don't know which kind of CFF font those are. But keeping
199
+ # charset seems to work. It will be removed when we save and
200
+ # read the font again.
201
+ #
202
+ # AdditionFont.otf has <Encoding name="StandardEncoding"/>.
203
+ if key == "charset":
204
+ continue
205
+ if key not in opOrder:
206
+ if key in topDict.rawDict:
207
+ del topDict.rawDict[key]
208
+ if hasattr(topDict, key):
209
+ delattr(topDict, key)
210
+
211
+ # TODO(behdad): What does the following comment even mean? Both CFF and CFF2
212
+ # use the same T2Charstring class. I *think* what it means is that the CharStrings
213
+ # were loaded for CFF1, and we need to reload them for CFF2 to set varstore, etc
214
+ # on them. At least that's what I understand. It's probably safe to remove this
215
+ # and just set vstore where needed.
216
+ #
217
+ # See comment above about charset as well.
218
+
219
+ # At this point, the Subrs and Charstrings are all still T2Charstring class
220
+ # easiest to fix this by compiling, then decompiling again
221
+ file = BytesIO()
222
+ cff.compile(file, otFont, isCFF2=True)
223
+ file.seek(0)
224
+ cff.decompile(file, otFont, isCFF2=True)
225
+
226
+
227
+ def convertCFFToCFF2(font):
228
+ cff = font["CFF "].cff
229
+ del font["CFF "]
230
+ _convertCFFToCFF2(cff, font)
231
+ table = font["CFF2"] = newTable("CFF2")
232
+ table.cff = cff
233
+
234
+
235
+ def main(args=None):
236
+ """Convert CFF OTF font to CFF2 OTF font"""
237
+ if args is None:
238
+ import sys
239
+
240
+ args = sys.argv[1:]
241
+
242
+ import argparse
243
+
244
+ parser = argparse.ArgumentParser(
245
+ "fonttools cffLib.CFFToCFF2",
246
+ description="Upgrade a CFF font to CFF2.",
247
+ )
248
+ parser.add_argument(
249
+ "input", metavar="INPUT.ttf", help="Input OTF file with CFF table."
250
+ )
251
+ parser.add_argument(
252
+ "-o",
253
+ "--output",
254
+ metavar="OUTPUT.ttf",
255
+ default=None,
256
+ help="Output instance OTF file (default: INPUT-CFF2.ttf).",
257
+ )
258
+ parser.add_argument(
259
+ "--no-recalc-timestamp",
260
+ dest="recalc_timestamp",
261
+ action="store_false",
262
+ help="Don't set the output font's timestamp to the current time.",
263
+ )
264
+ loggingGroup = parser.add_mutually_exclusive_group(required=False)
265
+ loggingGroup.add_argument(
266
+ "-v", "--verbose", action="store_true", help="Run more verbosely."
267
+ )
268
+ loggingGroup.add_argument(
269
+ "-q", "--quiet", action="store_true", help="Turn verbosity off."
270
+ )
271
+ options = parser.parse_args(args)
272
+
273
+ from fontTools import configLogger
274
+
275
+ configLogger(
276
+ level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
277
+ )
278
+
279
+ import os
280
+
281
+ infile = options.input
282
+ if not os.path.isfile(infile):
283
+ parser.error("No such file '{}'".format(infile))
284
+
285
+ outfile = (
286
+ makeOutputFileName(infile, overWrite=True, suffix="-CFF2")
287
+ if not options.output
288
+ else options.output
289
+ )
290
+
291
+ font = TTFont(infile, recalcTimestamp=options.recalc_timestamp, recalcBBoxes=False)
292
+
293
+ convertCFFToCFF2(font)
294
+
295
+ log.info(
296
+ "Saving %s",
297
+ outfile,
298
+ )
299
+ font.save(outfile)
300
+
301
+
302
+ if __name__ == "__main__":
303
+ import sys
304
+
305
+ sys.exit(main(sys.argv[1:]))