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,335 @@
1
+ from array import array
2
+ from typing import Any, Callable, Dict, Optional, Tuple
3
+ from fontTools.misc.fixedTools import MAX_F2DOT14, floatToFixedToFloat
4
+ from fontTools.misc.loggingTools import LogMixin
5
+ from fontTools.pens.pointPen import AbstractPointPen
6
+ from fontTools.misc.roundTools import otRound
7
+ from fontTools.pens.basePen import LoggingPen, PenError
8
+ from fontTools.pens.transformPen import TransformPen, TransformPointPen
9
+ from fontTools.ttLib.tables import ttProgram
10
+ from fontTools.ttLib.tables._g_l_y_f import flagOnCurve, flagCubic
11
+ from fontTools.ttLib.tables._g_l_y_f import Glyph
12
+ from fontTools.ttLib.tables._g_l_y_f import GlyphComponent
13
+ from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
14
+ from fontTools.ttLib.tables._g_l_y_f import dropImpliedOnCurvePoints
15
+ import math
16
+
17
+
18
+ __all__ = ["TTGlyphPen", "TTGlyphPointPen"]
19
+
20
+
21
+ class _TTGlyphBasePen:
22
+ def __init__(
23
+ self,
24
+ glyphSet: Optional[Dict[str, Any]],
25
+ handleOverflowingTransforms: bool = True,
26
+ ) -> None:
27
+ """
28
+ Construct a new pen.
29
+
30
+ Args:
31
+ glyphSet (Dict[str, Any]): A glyphset object, used to resolve components.
32
+ handleOverflowingTransforms (bool): See below.
33
+
34
+ If ``handleOverflowingTransforms`` is True, the components' transform values
35
+ are checked that they don't overflow the limits of a F2Dot14 number:
36
+ -2.0 <= v < +2.0. If any transform value exceeds these, the composite
37
+ glyph is decomposed.
38
+
39
+ An exception to this rule is done for values that are very close to +2.0
40
+ (both for consistency with the -2.0 case, and for the relative frequency
41
+ these occur in real fonts). When almost +2.0 values occur (and all other
42
+ values are within the range -2.0 <= x <= +2.0), they are clamped to the
43
+ maximum positive value that can still be encoded as an F2Dot14: i.e.
44
+ 1.99993896484375.
45
+
46
+ If False, no check is done and all components are translated unmodified
47
+ into the glyf table, followed by an inevitable ``struct.error`` once an
48
+ attempt is made to compile them.
49
+
50
+ If both contours and components are present in a glyph, the components
51
+ are decomposed.
52
+ """
53
+ self.glyphSet = glyphSet
54
+ self.handleOverflowingTransforms = handleOverflowingTransforms
55
+ self.init()
56
+
57
+ def _decompose(
58
+ self,
59
+ glyphName: str,
60
+ transformation: Tuple[float, float, float, float, float, float],
61
+ ):
62
+ tpen = self.transformPen(self, transformation)
63
+ getattr(self.glyphSet[glyphName], self.drawMethod)(tpen)
64
+
65
+ def _isClosed(self):
66
+ """
67
+ Check if the current path is closed.
68
+ """
69
+ raise NotImplementedError
70
+
71
+ def init(self) -> None:
72
+ self.points = []
73
+ self.endPts = []
74
+ self.types = []
75
+ self.components = []
76
+
77
+ def addComponent(
78
+ self,
79
+ baseGlyphName: str,
80
+ transformation: Tuple[float, float, float, float, float, float],
81
+ identifier: Optional[str] = None,
82
+ **kwargs: Any,
83
+ ) -> None:
84
+ """
85
+ Add a sub glyph.
86
+ """
87
+ self.components.append((baseGlyphName, transformation))
88
+
89
+ def _buildComponents(self, componentFlags):
90
+ if self.handleOverflowingTransforms:
91
+ # we can't encode transform values > 2 or < -2 in F2Dot14,
92
+ # so we must decompose the glyph if any transform exceeds these
93
+ overflowing = any(
94
+ s > 2 or s < -2
95
+ for (glyphName, transformation) in self.components
96
+ for s in transformation[:4]
97
+ )
98
+ components = []
99
+ for glyphName, transformation in self.components:
100
+ if glyphName not in self.glyphSet:
101
+ self.log.warning(f"skipped non-existing component '{glyphName}'")
102
+ continue
103
+ if self.points or (self.handleOverflowingTransforms and overflowing):
104
+ # can't have both coordinates and components, so decompose
105
+ self._decompose(glyphName, transformation)
106
+ continue
107
+
108
+ component = GlyphComponent()
109
+ component.glyphName = glyphName
110
+ component.x, component.y = (otRound(v) for v in transformation[4:])
111
+ # quantize floats to F2Dot14 so we get same values as when decompiled
112
+ # from a binary glyf table
113
+ transformation = tuple(
114
+ floatToFixedToFloat(v, 14) for v in transformation[:4]
115
+ )
116
+ if transformation != (1, 0, 0, 1):
117
+ if self.handleOverflowingTransforms and any(
118
+ MAX_F2DOT14 < s <= 2 for s in transformation
119
+ ):
120
+ # clamp values ~= +2.0 so we can keep the component
121
+ transformation = tuple(
122
+ MAX_F2DOT14 if MAX_F2DOT14 < s <= 2 else s
123
+ for s in transformation
124
+ )
125
+ component.transform = (transformation[:2], transformation[2:])
126
+ component.flags = componentFlags
127
+ components.append(component)
128
+ return components
129
+
130
+ def glyph(
131
+ self,
132
+ componentFlags: int = 0x04,
133
+ dropImpliedOnCurves: bool = False,
134
+ *,
135
+ round: Callable[[float], int] = otRound,
136
+ ) -> Glyph:
137
+ """
138
+ Returns a :py:class:`~._g_l_y_f.Glyph` object representing the glyph.
139
+
140
+ Args:
141
+ componentFlags: Flags to use for component glyphs. (default: 0x04)
142
+
143
+ dropImpliedOnCurves: Whether to remove implied-oncurve points. (default: False)
144
+ """
145
+ if not self._isClosed():
146
+ raise PenError("Didn't close last contour.")
147
+ components = self._buildComponents(componentFlags)
148
+
149
+ glyph = Glyph()
150
+ glyph.coordinates = GlyphCoordinates(self.points)
151
+ glyph.endPtsOfContours = self.endPts
152
+ glyph.flags = array("B", self.types)
153
+ self.init()
154
+
155
+ if components:
156
+ # If both components and contours were present, they have by now
157
+ # been decomposed by _buildComponents.
158
+ glyph.components = components
159
+ glyph.numberOfContours = -1
160
+ else:
161
+ glyph.numberOfContours = len(glyph.endPtsOfContours)
162
+ glyph.program = ttProgram.Program()
163
+ glyph.program.fromBytecode(b"")
164
+ if dropImpliedOnCurves:
165
+ dropImpliedOnCurvePoints(glyph)
166
+ glyph.coordinates.toInt(round=round)
167
+
168
+ return glyph
169
+
170
+
171
+ class TTGlyphPen(_TTGlyphBasePen, LoggingPen):
172
+ """
173
+ Pen used for drawing to a TrueType glyph.
174
+
175
+ This pen can be used to construct or modify glyphs in a TrueType format
176
+ font. After using the pen to draw, use the ``.glyph()`` method to retrieve
177
+ a :py:class:`~._g_l_y_f.Glyph` object representing the glyph.
178
+ """
179
+
180
+ drawMethod = "draw"
181
+ transformPen = TransformPen
182
+
183
+ def __init__(
184
+ self,
185
+ glyphSet: Optional[Dict[str, Any]] = None,
186
+ handleOverflowingTransforms: bool = True,
187
+ outputImpliedClosingLine: bool = False,
188
+ ) -> None:
189
+ super().__init__(glyphSet, handleOverflowingTransforms)
190
+ self.outputImpliedClosingLine = outputImpliedClosingLine
191
+
192
+ def _addPoint(self, pt: Tuple[float, float], tp: int) -> None:
193
+ self.points.append(pt)
194
+ self.types.append(tp)
195
+
196
+ def _popPoint(self) -> None:
197
+ self.points.pop()
198
+ self.types.pop()
199
+
200
+ def _isClosed(self) -> bool:
201
+ return (not self.points) or (
202
+ self.endPts and self.endPts[-1] == len(self.points) - 1
203
+ )
204
+
205
+ def lineTo(self, pt: Tuple[float, float]) -> None:
206
+ self._addPoint(pt, flagOnCurve)
207
+
208
+ def moveTo(self, pt: Tuple[float, float]) -> None:
209
+ if not self._isClosed():
210
+ raise PenError('"move"-type point must begin a new contour.')
211
+ self._addPoint(pt, flagOnCurve)
212
+
213
+ def curveTo(self, *points) -> None:
214
+ assert len(points) % 2 == 1
215
+ for pt in points[:-1]:
216
+ self._addPoint(pt, flagCubic)
217
+
218
+ # last point is None if there are no on-curve points
219
+ if points[-1] is not None:
220
+ self._addPoint(points[-1], 1)
221
+
222
+ def qCurveTo(self, *points) -> None:
223
+ assert len(points) >= 1
224
+ for pt in points[:-1]:
225
+ self._addPoint(pt, 0)
226
+
227
+ # last point is None if there are no on-curve points
228
+ if points[-1] is not None:
229
+ self._addPoint(points[-1], 1)
230
+
231
+ def closePath(self) -> None:
232
+ endPt = len(self.points) - 1
233
+
234
+ # ignore anchors (one-point paths)
235
+ if endPt == 0 or (self.endPts and endPt == self.endPts[-1] + 1):
236
+ self._popPoint()
237
+ return
238
+
239
+ if not self.outputImpliedClosingLine:
240
+ # if first and last point on this path are the same, remove last
241
+ startPt = 0
242
+ if self.endPts:
243
+ startPt = self.endPts[-1] + 1
244
+ if self.points[startPt] == self.points[endPt]:
245
+ self._popPoint()
246
+ endPt -= 1
247
+
248
+ self.endPts.append(endPt)
249
+
250
+ def endPath(self) -> None:
251
+ # TrueType contours are always "closed"
252
+ self.closePath()
253
+
254
+
255
+ class TTGlyphPointPen(_TTGlyphBasePen, LogMixin, AbstractPointPen):
256
+ """
257
+ Point pen used for drawing to a TrueType glyph.
258
+
259
+ This pen can be used to construct or modify glyphs in a TrueType format
260
+ font. After using the pen to draw, use the ``.glyph()`` method to retrieve
261
+ a :py:class:`~._g_l_y_f.Glyph` object representing the glyph.
262
+ """
263
+
264
+ drawMethod = "drawPoints"
265
+ transformPen = TransformPointPen
266
+
267
+ def init(self) -> None:
268
+ super().init()
269
+ self._currentContourStartIndex = None
270
+
271
+ def _isClosed(self) -> bool:
272
+ return self._currentContourStartIndex is None
273
+
274
+ def beginPath(self, identifier: Optional[str] = None, **kwargs: Any) -> None:
275
+ """
276
+ Start a new sub path.
277
+ """
278
+ if not self._isClosed():
279
+ raise PenError("Didn't close previous contour.")
280
+ self._currentContourStartIndex = len(self.points)
281
+
282
+ def endPath(self) -> None:
283
+ """
284
+ End the current sub path.
285
+ """
286
+ # TrueType contours are always "closed"
287
+ if self._isClosed():
288
+ raise PenError("Contour is already closed.")
289
+ if self._currentContourStartIndex == len(self.points):
290
+ # ignore empty contours
291
+ self._currentContourStartIndex = None
292
+ return
293
+
294
+ contourStart = self.endPts[-1] + 1 if self.endPts else 0
295
+ self.endPts.append(len(self.points) - 1)
296
+ self._currentContourStartIndex = None
297
+
298
+ # Resolve types for any cubic segments
299
+ flags = self.types
300
+ for i in range(contourStart, len(flags)):
301
+ if flags[i] == "curve":
302
+ j = i - 1
303
+ if j < contourStart:
304
+ j = len(flags) - 1
305
+ while flags[j] == 0:
306
+ flags[j] = flagCubic
307
+ j -= 1
308
+ flags[i] = flagOnCurve
309
+
310
+ def addPoint(
311
+ self,
312
+ pt: Tuple[float, float],
313
+ segmentType: Optional[str] = None,
314
+ smooth: bool = False,
315
+ name: Optional[str] = None,
316
+ identifier: Optional[str] = None,
317
+ **kwargs: Any,
318
+ ) -> None:
319
+ """
320
+ Add a point to the current sub path.
321
+ """
322
+ if self._isClosed():
323
+ raise PenError("Can't add a point to a closed contour.")
324
+ if segmentType is None:
325
+ self.types.append(0)
326
+ elif segmentType in ("line", "move"):
327
+ self.types.append(flagOnCurve)
328
+ elif segmentType == "qcurve":
329
+ self.types.append(flagOnCurve)
330
+ elif segmentType == "curve":
331
+ self.types.append("curve")
332
+ else:
333
+ raise AssertionError(segmentType)
334
+
335
+ self.points.append(pt)
@@ -0,0 +1,29 @@
1
+ from fontTools.pens.basePen import BasePen
2
+
3
+
4
+ __all__ = ["WxPen"]
5
+
6
+
7
+ class WxPen(BasePen):
8
+ def __init__(self, glyphSet, path=None):
9
+ BasePen.__init__(self, glyphSet)
10
+ if path is None:
11
+ import wx
12
+
13
+ path = wx.GraphicsRenderer.GetDefaultRenderer().CreatePath()
14
+ self.path = path
15
+
16
+ def _moveTo(self, p):
17
+ self.path.MoveToPoint(*p)
18
+
19
+ def _lineTo(self, p):
20
+ self.path.AddLineToPoint(*p)
21
+
22
+ def _curveToOne(self, p1, p2, p3):
23
+ self.path.AddCurveToPoint(*p1 + p2 + p3)
24
+
25
+ def _qCurveToOne(self, p1, p2):
26
+ self.path.AddQuadCurveToPoint(*p1 + p2)
27
+
28
+ def _closePath(self):
29
+ self.path.CloseSubpath()
@@ -0,0 +1,15 @@
1
+ # Copyright 2016 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from .qu2cu import *
@@ -0,0 +1,7 @@
1
+ import sys
2
+
3
+ from .cli import _main as main
4
+
5
+
6
+ if __name__ == "__main__":
7
+ sys.exit(main())
@@ -0,0 +1,56 @@
1
+ """Benchmark the qu2cu algorithm performance."""
2
+
3
+ from .qu2cu import *
4
+ from fontTools.cu2qu import curve_to_quadratic
5
+ import random
6
+ import timeit
7
+
8
+ MAX_ERR = 0.5
9
+ NUM_CURVES = 5
10
+
11
+
12
+ def generate_curves(n):
13
+ points = [
14
+ tuple(float(random.randint(0, 2048)) for coord in range(2))
15
+ for point in range(1 + 3 * n)
16
+ ]
17
+ curves = []
18
+ for i in range(n):
19
+ curves.append(tuple(points[i * 3 : i * 3 + 4]))
20
+ return curves
21
+
22
+
23
+ def setup_quadratic_to_curves():
24
+ curves = generate_curves(NUM_CURVES)
25
+ quadratics = [curve_to_quadratic(curve, MAX_ERR) for curve in curves]
26
+ return quadratics, MAX_ERR
27
+
28
+
29
+ def run_benchmark(module, function, setup_suffix="", repeat=25, number=1):
30
+ setup_func = "setup_" + function
31
+ if setup_suffix:
32
+ print("%s with %s:" % (function, setup_suffix), end="")
33
+ setup_func += "_" + setup_suffix
34
+ else:
35
+ print("%s:" % function, end="")
36
+
37
+ def wrapper(function, setup_func):
38
+ function = globals()[function]
39
+ setup_func = globals()[setup_func]
40
+
41
+ def wrapped():
42
+ return function(*setup_func())
43
+
44
+ return wrapped
45
+
46
+ results = timeit.repeat(wrapper(function, setup_func), repeat=repeat, number=number)
47
+ print("\t%5.1fus" % (min(results) * 1000000.0 / number))
48
+
49
+
50
+ def main():
51
+ run_benchmark("qu2cu", "quadratic_to_curves")
52
+
53
+
54
+ if __name__ == "__main__":
55
+ random.seed(1)
56
+ main()
fontTools/qu2cu/cli.py ADDED
@@ -0,0 +1,125 @@
1
+ import os
2
+ import argparse
3
+ import logging
4
+ from fontTools.misc.cliTools import makeOutputFileName
5
+ from fontTools.ttLib import TTFont
6
+ from fontTools.pens.qu2cuPen import Qu2CuPen
7
+ from fontTools.pens.ttGlyphPen import TTGlyphPen
8
+ import fontTools
9
+
10
+
11
+ logger = logging.getLogger("fontTools.qu2cu")
12
+
13
+
14
+ def _font_to_cubic(input_path, output_path=None, **kwargs):
15
+ font = TTFont(input_path)
16
+ logger.info("Converting curves for %s", input_path)
17
+
18
+ stats = {} if kwargs["dump_stats"] else None
19
+ qu2cu_kwargs = {
20
+ "stats": stats,
21
+ "max_err": kwargs["max_err_em"] * font["head"].unitsPerEm,
22
+ "all_cubic": kwargs["all_cubic"],
23
+ }
24
+
25
+ assert "gvar" not in font, "Cannot convert variable font"
26
+ glyphSet = font.getGlyphSet()
27
+ glyphOrder = font.getGlyphOrder()
28
+ glyf = font["glyf"]
29
+ for glyphName in glyphOrder:
30
+ glyph = glyphSet[glyphName]
31
+ ttpen = TTGlyphPen(glyphSet)
32
+ pen = Qu2CuPen(ttpen, **qu2cu_kwargs)
33
+ glyph.draw(pen)
34
+ glyf[glyphName] = ttpen.glyph(dropImpliedOnCurves=True)
35
+
36
+ font["head"].glyphDataFormat = 1
37
+
38
+ if kwargs["dump_stats"]:
39
+ logger.info("Stats: %s", stats)
40
+
41
+ logger.info("Saving %s", output_path)
42
+ font.save(output_path)
43
+
44
+
45
+ def _main(args=None):
46
+ """Convert an OpenType font from quadratic to cubic curves"""
47
+ parser = argparse.ArgumentParser(prog="qu2cu")
48
+ parser.add_argument("--version", action="version", version=fontTools.__version__)
49
+ parser.add_argument(
50
+ "infiles",
51
+ nargs="+",
52
+ metavar="INPUT",
53
+ help="one or more input TTF source file(s).",
54
+ )
55
+ parser.add_argument("-v", "--verbose", action="count", default=0)
56
+ parser.add_argument(
57
+ "-e",
58
+ "--conversion-error",
59
+ type=float,
60
+ metavar="ERROR",
61
+ default=0.001,
62
+ help="maxiumum approximation error measured in EM (default: 0.001)",
63
+ )
64
+ parser.add_argument(
65
+ "-c",
66
+ "--all-cubic",
67
+ default=False,
68
+ action="store_true",
69
+ help="whether to only use cubic curves",
70
+ )
71
+
72
+ output_parser = parser.add_mutually_exclusive_group()
73
+ output_parser.add_argument(
74
+ "-o",
75
+ "--output-file",
76
+ default=None,
77
+ metavar="OUTPUT",
78
+ help=("output filename for the converted TTF."),
79
+ )
80
+ output_parser.add_argument(
81
+ "-d",
82
+ "--output-dir",
83
+ default=None,
84
+ metavar="DIRECTORY",
85
+ help="output directory where to save converted TTFs",
86
+ )
87
+
88
+ options = parser.parse_args(args)
89
+
90
+ if not options.verbose:
91
+ level = "WARNING"
92
+ elif options.verbose == 1:
93
+ level = "INFO"
94
+ else:
95
+ level = "DEBUG"
96
+ logging.basicConfig(level=level)
97
+
98
+ if len(options.infiles) > 1 and options.output_file:
99
+ parser.error("-o/--output-file can't be used with multile inputs")
100
+
101
+ if options.output_dir:
102
+ output_dir = options.output_dir
103
+ if not os.path.exists(output_dir):
104
+ os.mkdir(output_dir)
105
+ elif not os.path.isdir(output_dir):
106
+ parser.error("'%s' is not a directory" % output_dir)
107
+ output_paths = [
108
+ os.path.join(output_dir, os.path.basename(p)) for p in options.infiles
109
+ ]
110
+ elif options.output_file:
111
+ output_paths = [options.output_file]
112
+ else:
113
+ output_paths = [
114
+ makeOutputFileName(p, overWrite=True, suffix=".cubic")
115
+ for p in options.infiles
116
+ ]
117
+
118
+ kwargs = dict(
119
+ dump_stats=options.verbose > 0,
120
+ max_err_em=options.conversion_error,
121
+ all_cubic=options.all_cubic,
122
+ )
123
+
124
+ for input_path, output_path in zip(options.infiles, output_paths):
125
+ _font_to_cubic(input_path, output_path, **kwargs)