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,110 @@
1
+ """
2
+ Various round-to-integer helpers.
3
+ """
4
+
5
+ import math
6
+ import functools
7
+ import logging
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+ __all__ = [
12
+ "noRound",
13
+ "otRound",
14
+ "maybeRound",
15
+ "roundFunc",
16
+ "nearestMultipleShortestRepr",
17
+ ]
18
+
19
+
20
+ def noRound(value):
21
+ return value
22
+
23
+
24
+ def otRound(value):
25
+ """Round float value to nearest integer towards ``+Infinity``.
26
+
27
+ The OpenType spec (in the section on `"normalization" of OpenType Font Variations <https://docs.microsoft.com/en-us/typography/opentype/spec/otvaroverview#coordinate-scales-and-normalization>`_)
28
+ defines the required method for converting floating point values to
29
+ fixed-point. In particular it specifies the following rounding strategy:
30
+
31
+ for fractional values of 0.5 and higher, take the next higher integer;
32
+ for other fractional values, truncate.
33
+
34
+ This function rounds the floating-point value according to this strategy
35
+ in preparation for conversion to fixed-point.
36
+
37
+ Args:
38
+ value (float): The input floating-point value.
39
+
40
+ Returns
41
+ float: The rounded value.
42
+ """
43
+ # See this thread for how we ended up with this implementation:
44
+ # https://github.com/fonttools/fonttools/issues/1248#issuecomment-383198166
45
+ return int(math.floor(value + 0.5))
46
+
47
+
48
+ def maybeRound(v, tolerance, round=otRound):
49
+ rounded = round(v)
50
+ return rounded if abs(rounded - v) <= tolerance else v
51
+
52
+
53
+ def roundFunc(tolerance, round=otRound):
54
+ if tolerance < 0:
55
+ raise ValueError("Rounding tolerance must be positive")
56
+
57
+ if tolerance == 0:
58
+ return noRound
59
+
60
+ if tolerance >= 0.5:
61
+ return round
62
+
63
+ return functools.partial(maybeRound, tolerance=tolerance, round=round)
64
+
65
+
66
+ def nearestMultipleShortestRepr(value: float, factor: float) -> str:
67
+ """Round to nearest multiple of factor and return shortest decimal representation.
68
+
69
+ This chooses the float that is closer to a multiple of the given factor while
70
+ having the shortest decimal representation (the least number of fractional decimal
71
+ digits).
72
+
73
+ For example, given the following:
74
+
75
+ >>> nearestMultipleShortestRepr(-0.61883544921875, 1.0/(1<<14))
76
+ '-0.61884'
77
+
78
+ Useful when you need to serialize or print a fixed-point number (or multiples
79
+ thereof, such as F2Dot14 fractions of 180 degrees in COLRv1 PaintRotate) in
80
+ a human-readable form.
81
+
82
+ Args:
83
+ value (value): The value to be rounded and serialized.
84
+ factor (float): The value which the result is a close multiple of.
85
+
86
+ Returns:
87
+ str: A compact string representation of the value.
88
+ """
89
+ if not value:
90
+ return "0.0"
91
+
92
+ value = otRound(value / factor) * factor
93
+ eps = 0.5 * factor
94
+ lo = value - eps
95
+ hi = value + eps
96
+ # If the range of valid choices spans an integer, return the integer.
97
+ if int(lo) != int(hi):
98
+ return str(float(round(value)))
99
+
100
+ fmt = "%.8f"
101
+ lo = fmt % lo
102
+ hi = fmt % hi
103
+ assert len(lo) == len(hi) and lo != hi
104
+ for i in range(len(lo)):
105
+ if lo[i] != hi[i]:
106
+ break
107
+ period = lo.find(".")
108
+ assert period < i
109
+ fmt = "%%.%df" % (i - period)
110
+ return fmt % value
@@ -0,0 +1,227 @@
1
+ """sstruct.py -- SuperStruct
2
+
3
+ Higher level layer on top of the struct module, enabling to
4
+ bind names to struct elements. The interface is similar to
5
+ struct, except the objects passed and returned are not tuples
6
+ (or argument lists), but dictionaries or instances.
7
+
8
+ Just like struct, we use fmt strings to describe a data
9
+ structure, except we use one line per element. Lines are
10
+ separated by newlines or semi-colons. Each line contains
11
+ either one of the special struct characters ('@', '=', '<',
12
+ '>' or '!') or a 'name:formatchar' combo (eg. 'myFloat:f').
13
+ Repetitions, like the struct module offers them are not useful
14
+ in this context, except for fixed length strings (eg. 'myInt:5h'
15
+ is not allowed but 'myString:5s' is). The 'x' fmt character
16
+ (pad byte) is treated as 'special', since it is by definition
17
+ anonymous. Extra whitespace is allowed everywhere.
18
+
19
+ The sstruct module offers one feature that the "normal" struct
20
+ module doesn't: support for fixed point numbers. These are spelled
21
+ as "n.mF", where n is the number of bits before the point, and m
22
+ the number of bits after the point. Fixed point numbers get
23
+ converted to floats.
24
+
25
+ pack(fmt, object):
26
+ 'object' is either a dictionary or an instance (or actually
27
+ anything that has a __dict__ attribute). If it is a dictionary,
28
+ its keys are used for names. If it is an instance, it's
29
+ attributes are used to grab struct elements from. Returns
30
+ a string containing the data.
31
+
32
+ unpack(fmt, data, object=None)
33
+ If 'object' is omitted (or None), a new dictionary will be
34
+ returned. If 'object' is a dictionary, it will be used to add
35
+ struct elements to. If it is an instance (or in fact anything
36
+ that has a __dict__ attribute), an attribute will be added for
37
+ each struct element. In the latter two cases, 'object' itself
38
+ is returned.
39
+
40
+ unpack2(fmt, data, object=None)
41
+ Convenience function. Same as unpack, except data may be longer
42
+ than needed. The returned value is a tuple: (object, leftoverdata).
43
+
44
+ calcsize(fmt)
45
+ like struct.calcsize(), but uses our own fmt strings:
46
+ it returns the size of the data in bytes.
47
+ """
48
+
49
+ from fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
50
+ from fontTools.misc.textTools import tobytes, tostr
51
+ import struct
52
+ import re
53
+
54
+ __version__ = "1.2"
55
+ __copyright__ = "Copyright 1998, Just van Rossum <just@letterror.com>"
56
+
57
+
58
+ class Error(Exception):
59
+ pass
60
+
61
+
62
+ def pack(fmt, obj):
63
+ formatstring, names, fixes = getformat(fmt, keep_pad_byte=True)
64
+ elements = []
65
+ if not isinstance(obj, dict):
66
+ obj = obj.__dict__
67
+ for name in names.keys():
68
+ value = obj[name]
69
+ if name in fixes:
70
+ # fixed point conversion
71
+ value = fl2fi(value, fixes[name])
72
+ elif isinstance(value, str):
73
+ value = tobytes(value)
74
+ elements.append(value)
75
+ # Check it fits
76
+ try:
77
+ struct.pack(names[name], value)
78
+ except Exception as e:
79
+ raise ValueError(
80
+ "Value %s does not fit in format %s for %s" % (value, names[name], name)
81
+ ) from e
82
+ data = struct.pack(*(formatstring,) + tuple(elements))
83
+ return data
84
+
85
+
86
+ def unpack(fmt, data, obj=None):
87
+ if obj is None:
88
+ obj = {}
89
+ data = tobytes(data)
90
+ formatstring, names, fixes = getformat(fmt)
91
+ if isinstance(obj, dict):
92
+ d = obj
93
+ else:
94
+ d = obj.__dict__
95
+ elements = struct.unpack(formatstring, data)
96
+ for i, name in enumerate(names.keys()):
97
+ value = elements[i]
98
+ if name in fixes:
99
+ # fixed point conversion
100
+ value = fi2fl(value, fixes[name])
101
+ elif isinstance(value, bytes):
102
+ try:
103
+ value = tostr(value)
104
+ except UnicodeDecodeError:
105
+ pass
106
+ d[name] = value
107
+ return obj
108
+
109
+
110
+ def unpack2(fmt, data, obj=None):
111
+ length = calcsize(fmt)
112
+ return unpack(fmt, data[:length], obj), data[length:]
113
+
114
+
115
+ def calcsize(fmt):
116
+ formatstring, names, fixes = getformat(fmt)
117
+ return struct.calcsize(formatstring)
118
+
119
+
120
+ # matches "name:formatchar" (whitespace is allowed)
121
+ _elementRE = re.compile(
122
+ r"\s*" # whitespace
123
+ r"([A-Za-z_][A-Za-z_0-9]*)" # name (python identifier)
124
+ r"\s*:\s*" # whitespace : whitespace
125
+ r"([xcbB?hHiIlLqQfd]|" # formatchar...
126
+ r"[0-9]+[ps]|" # ...formatchar...
127
+ r"([0-9]+)\.([0-9]+)(F))" # ...formatchar
128
+ r"\s*" # whitespace
129
+ r"(#.*)?$" # [comment] + end of string
130
+ )
131
+
132
+ # matches the special struct fmt chars and 'x' (pad byte)
133
+ _extraRE = re.compile(r"\s*([x@=<>!])\s*(#.*)?$")
134
+
135
+ # matches an "empty" string, possibly containing whitespace and/or a comment
136
+ _emptyRE = re.compile(r"\s*(#.*)?$")
137
+
138
+ _fixedpointmappings = {8: "b", 16: "h", 32: "l"}
139
+
140
+ _formatcache = {}
141
+
142
+
143
+ def getformat(fmt, keep_pad_byte=False):
144
+ fmt = tostr(fmt, encoding="ascii")
145
+ try:
146
+ formatstring, names, fixes = _formatcache[fmt]
147
+ except KeyError:
148
+ lines = re.split("[\n;]", fmt)
149
+ formatstring = ""
150
+ names = {}
151
+ fixes = {}
152
+ for line in lines:
153
+ if _emptyRE.match(line):
154
+ continue
155
+ m = _extraRE.match(line)
156
+ if m:
157
+ formatchar = m.group(1)
158
+ if formatchar != "x" and formatstring:
159
+ raise Error("a special fmt char must be first")
160
+ else:
161
+ m = _elementRE.match(line)
162
+ if not m:
163
+ raise Error("syntax error in fmt: '%s'" % line)
164
+ name = m.group(1)
165
+ formatchar = m.group(2)
166
+ if keep_pad_byte or formatchar != "x":
167
+ names[name] = formatchar
168
+ if m.group(3):
169
+ # fixed point
170
+ before = int(m.group(3))
171
+ after = int(m.group(4))
172
+ bits = before + after
173
+ if bits not in [8, 16, 32]:
174
+ raise Error("fixed point must be 8, 16 or 32 bits long")
175
+ formatchar = _fixedpointmappings[bits]
176
+ names[name] = formatchar
177
+ assert m.group(5) == "F"
178
+ fixes[name] = after
179
+ formatstring += formatchar
180
+ _formatcache[fmt] = formatstring, names, fixes
181
+ return formatstring, names, fixes
182
+
183
+
184
+ def _test():
185
+ fmt = """
186
+ # comments are allowed
187
+ > # big endian (see documentation for struct)
188
+ # empty lines are allowed:
189
+
190
+ ashort: h
191
+ along: l
192
+ abyte: b # a byte
193
+ achar: c
194
+ astr: 5s
195
+ afloat: f; adouble: d # multiple "statements" are allowed
196
+ afixed: 16.16F
197
+ abool: ?
198
+ apad: x
199
+ """
200
+
201
+ print("size:", calcsize(fmt))
202
+
203
+ class foo(object):
204
+ pass
205
+
206
+ i = foo()
207
+
208
+ i.ashort = 0x7FFF
209
+ i.along = 0x7FFFFFFF
210
+ i.abyte = 0x7F
211
+ i.achar = "a"
212
+ i.astr = "12345"
213
+ i.afloat = 0.5
214
+ i.adouble = 0.5
215
+ i.afixed = 1.5
216
+ i.abool = True
217
+
218
+ data = pack(fmt, i)
219
+ print("data:", repr(data))
220
+ print(unpack(fmt, data))
221
+ i2 = foo()
222
+ unpack(fmt, data, i2)
223
+ print(vars(i2))
224
+
225
+
226
+ if __name__ == "__main__":
227
+ _test()
@@ -0,0 +1,242 @@
1
+ from fontTools.pens.basePen import BasePen
2
+ from functools import partial
3
+ from itertools import count
4
+ import sympy as sp
5
+ import sys
6
+
7
+ n = 3 # Max Bezier degree; 3 for cubic, 2 for quadratic
8
+
9
+ t, x, y = sp.symbols("t x y", real=True)
10
+ c = sp.symbols("c", real=False) # Complex representation instead of x/y
11
+
12
+ X = tuple(sp.symbols("x:%d" % (n + 1), real=True))
13
+ Y = tuple(sp.symbols("y:%d" % (n + 1), real=True))
14
+ P = tuple(zip(*(sp.symbols("p:%d[%s]" % (n + 1, w), real=True) for w in "01")))
15
+ C = tuple(sp.symbols("c:%d" % (n + 1), real=False))
16
+
17
+ # Cubic Bernstein basis functions
18
+ BinomialCoefficient = [(1, 0)]
19
+ for i in range(1, n + 1):
20
+ last = BinomialCoefficient[-1]
21
+ this = tuple(last[j - 1] + last[j] for j in range(len(last))) + (0,)
22
+ BinomialCoefficient.append(this)
23
+ BinomialCoefficient = tuple(tuple(item[:-1]) for item in BinomialCoefficient)
24
+ del last, this
25
+
26
+ BernsteinPolynomial = tuple(
27
+ tuple(c * t**i * (1 - t) ** (n - i) for i, c in enumerate(coeffs))
28
+ for n, coeffs in enumerate(BinomialCoefficient)
29
+ )
30
+
31
+ BezierCurve = tuple(
32
+ tuple(
33
+ sum(P[i][j] * bernstein for i, bernstein in enumerate(bernsteins))
34
+ for j in range(2)
35
+ )
36
+ for n, bernsteins in enumerate(BernsteinPolynomial)
37
+ )
38
+ BezierCurveC = tuple(
39
+ sum(C[i] * bernstein for i, bernstein in enumerate(bernsteins))
40
+ for n, bernsteins in enumerate(BernsteinPolynomial)
41
+ )
42
+
43
+
44
+ def green(f, curveXY):
45
+ f = -sp.integrate(sp.sympify(f), y)
46
+ f = f.subs({x: curveXY[0], y: curveXY[1]})
47
+ f = sp.integrate(f * sp.diff(curveXY[0], t), (t, 0, 1))
48
+ return f
49
+
50
+
51
+ class _BezierFuncsLazy(dict):
52
+ def __init__(self, symfunc):
53
+ self._symfunc = symfunc
54
+ self._bezfuncs = {}
55
+
56
+ def __missing__(self, i):
57
+ args = ["p%d" % d for d in range(i + 1)]
58
+ f = green(self._symfunc, BezierCurve[i])
59
+ f = sp.gcd_terms(f.collect(sum(P, ()))) # Optimize
60
+ return sp.lambdify(args, f)
61
+
62
+
63
+ class GreenPen(BasePen):
64
+ _BezierFuncs = {}
65
+
66
+ @classmethod
67
+ def _getGreenBezierFuncs(celf, func):
68
+ funcstr = str(func)
69
+ if not funcstr in celf._BezierFuncs:
70
+ celf._BezierFuncs[funcstr] = _BezierFuncsLazy(func)
71
+ return celf._BezierFuncs[funcstr]
72
+
73
+ def __init__(self, func, glyphset=None):
74
+ BasePen.__init__(self, glyphset)
75
+ self._funcs = self._getGreenBezierFuncs(func)
76
+ self.value = 0
77
+
78
+ def _moveTo(self, p0):
79
+ self._startPoint = p0
80
+
81
+ def _closePath(self):
82
+ p0 = self._getCurrentPoint()
83
+ if p0 != self._startPoint:
84
+ self._lineTo(self._startPoint)
85
+
86
+ def _endPath(self):
87
+ p0 = self._getCurrentPoint()
88
+ if p0 != self._startPoint:
89
+ # Green theorem is not defined on open contours.
90
+ raise NotImplementedError
91
+
92
+ def _lineTo(self, p1):
93
+ p0 = self._getCurrentPoint()
94
+ self.value += self._funcs[1](p0, p1)
95
+
96
+ def _qCurveToOne(self, p1, p2):
97
+ p0 = self._getCurrentPoint()
98
+ self.value += self._funcs[2](p0, p1, p2)
99
+
100
+ def _curveToOne(self, p1, p2, p3):
101
+ p0 = self._getCurrentPoint()
102
+ self.value += self._funcs[3](p0, p1, p2, p3)
103
+
104
+
105
+ # Sample pens.
106
+ # Do not use this in real code.
107
+ # Use fontTools.pens.momentsPen.MomentsPen instead.
108
+ AreaPen = partial(GreenPen, func=1)
109
+ MomentXPen = partial(GreenPen, func=x)
110
+ MomentYPen = partial(GreenPen, func=y)
111
+ MomentXXPen = partial(GreenPen, func=x * x)
112
+ MomentYYPen = partial(GreenPen, func=y * y)
113
+ MomentXYPen = partial(GreenPen, func=x * y)
114
+
115
+
116
+ def printGreenPen(penName, funcs, file=sys.stdout, docstring=None):
117
+ if docstring is not None:
118
+ print('"""%s"""' % docstring)
119
+
120
+ print(
121
+ """from fontTools.pens.basePen import BasePen, OpenContourError
122
+ try:
123
+ import cython
124
+ except (AttributeError, ImportError):
125
+ # if cython not installed, use mock module with no-op decorators and types
126
+ from fontTools.misc import cython
127
+ COMPILED = cython.compiled
128
+
129
+
130
+ __all__ = ["%s"]
131
+
132
+ class %s(BasePen):
133
+
134
+ def __init__(self, glyphset=None):
135
+ BasePen.__init__(self, glyphset)
136
+ """
137
+ % (penName, penName),
138
+ file=file,
139
+ )
140
+ for name, f in funcs:
141
+ print(" self.%s = 0" % name, file=file)
142
+ print(
143
+ """
144
+ def _moveTo(self, p0):
145
+ self._startPoint = p0
146
+
147
+ def _closePath(self):
148
+ p0 = self._getCurrentPoint()
149
+ if p0 != self._startPoint:
150
+ self._lineTo(self._startPoint)
151
+
152
+ def _endPath(self):
153
+ p0 = self._getCurrentPoint()
154
+ if p0 != self._startPoint:
155
+ raise OpenContourError(
156
+ "Glyph statistics is not defined on open contours."
157
+ )
158
+ """,
159
+ end="",
160
+ file=file,
161
+ )
162
+
163
+ for n in (1, 2, 3):
164
+ subs = {P[i][j]: [X, Y][j][i] for i in range(n + 1) for j in range(2)}
165
+ greens = [green(f, BezierCurve[n]) for name, f in funcs]
166
+ greens = [sp.gcd_terms(f.collect(sum(P, ()))) for f in greens] # Optimize
167
+ greens = [f.subs(subs) for f in greens] # Convert to p to x/y
168
+ defs, exprs = sp.cse(
169
+ greens,
170
+ optimizations="basic",
171
+ symbols=(sp.Symbol("r%d" % i) for i in count()),
172
+ )
173
+
174
+ print()
175
+ for name, value in defs:
176
+ print(" @cython.locals(%s=cython.double)" % name, file=file)
177
+ if n == 1:
178
+ print(
179
+ """\
180
+ @cython.locals(x0=cython.double, y0=cython.double)
181
+ @cython.locals(x1=cython.double, y1=cython.double)
182
+ def _lineTo(self, p1):
183
+ x0,y0 = self._getCurrentPoint()
184
+ x1,y1 = p1
185
+ """,
186
+ file=file,
187
+ )
188
+ elif n == 2:
189
+ print(
190
+ """\
191
+ @cython.locals(x0=cython.double, y0=cython.double)
192
+ @cython.locals(x1=cython.double, y1=cython.double)
193
+ @cython.locals(x2=cython.double, y2=cython.double)
194
+ def _qCurveToOne(self, p1, p2):
195
+ x0,y0 = self._getCurrentPoint()
196
+ x1,y1 = p1
197
+ x2,y2 = p2
198
+ """,
199
+ file=file,
200
+ )
201
+ elif n == 3:
202
+ print(
203
+ """\
204
+ @cython.locals(x0=cython.double, y0=cython.double)
205
+ @cython.locals(x1=cython.double, y1=cython.double)
206
+ @cython.locals(x2=cython.double, y2=cython.double)
207
+ @cython.locals(x3=cython.double, y3=cython.double)
208
+ def _curveToOne(self, p1, p2, p3):
209
+ x0,y0 = self._getCurrentPoint()
210
+ x1,y1 = p1
211
+ x2,y2 = p2
212
+ x3,y3 = p3
213
+ """,
214
+ file=file,
215
+ )
216
+ for name, value in defs:
217
+ print(" %s = %s" % (name, value), file=file)
218
+
219
+ print(file=file)
220
+ for name, value in zip([f[0] for f in funcs], exprs):
221
+ print(" self.%s += %s" % (name, value), file=file)
222
+
223
+ print(
224
+ """
225
+ if __name__ == '__main__':
226
+ from fontTools.misc.symfont import x, y, printGreenPen
227
+ printGreenPen('%s', ["""
228
+ % penName,
229
+ file=file,
230
+ )
231
+ for name, f in funcs:
232
+ print(" ('%s', %s)," % (name, str(f)), file=file)
233
+ print(" ])", file=file)
234
+
235
+
236
+ if __name__ == "__main__":
237
+ import sys
238
+
239
+ if sys.argv[1:]:
240
+ penName = sys.argv[1]
241
+ funcs = [(name, eval(f)) for name, f in zip(sys.argv[2::2], sys.argv[3::2])]
242
+ printGreenPen(penName, funcs, file=sys.stdout)