fonttools 4.59.1__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fonttools might be problematic. Click here for more details.

Files changed (346) 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/cffLib/CFF2ToCFF.py +233 -0
  6. fontTools/cffLib/CFFToCFF2.py +305 -0
  7. fontTools/cffLib/__init__.py +3694 -0
  8. fontTools/cffLib/specializer.py +927 -0
  9. fontTools/cffLib/transforms.py +495 -0
  10. fontTools/cffLib/width.py +210 -0
  11. fontTools/colorLib/__init__.py +0 -0
  12. fontTools/colorLib/builder.py +664 -0
  13. fontTools/colorLib/errors.py +2 -0
  14. fontTools/colorLib/geometry.py +143 -0
  15. fontTools/colorLib/table_builder.py +223 -0
  16. fontTools/colorLib/unbuilder.py +81 -0
  17. fontTools/config/__init__.py +90 -0
  18. fontTools/cu2qu/__init__.py +15 -0
  19. fontTools/cu2qu/__main__.py +6 -0
  20. fontTools/cu2qu/benchmark.py +54 -0
  21. fontTools/cu2qu/cli.py +198 -0
  22. fontTools/cu2qu/cu2qu.c +15559 -0
  23. fontTools/cu2qu/cu2qu.cp314-win_amd64.pyd +0 -0
  24. fontTools/cu2qu/cu2qu.py +531 -0
  25. fontTools/cu2qu/errors.py +77 -0
  26. fontTools/cu2qu/ufo.py +349 -0
  27. fontTools/designspaceLib/__init__.py +3338 -0
  28. fontTools/designspaceLib/__main__.py +6 -0
  29. fontTools/designspaceLib/split.py +475 -0
  30. fontTools/designspaceLib/statNames.py +260 -0
  31. fontTools/designspaceLib/types.py +147 -0
  32. fontTools/encodings/MacRoman.py +258 -0
  33. fontTools/encodings/StandardEncoding.py +258 -0
  34. fontTools/encodings/__init__.py +1 -0
  35. fontTools/encodings/codecs.py +135 -0
  36. fontTools/feaLib/__init__.py +4 -0
  37. fontTools/feaLib/__main__.py +78 -0
  38. fontTools/feaLib/ast.py +2143 -0
  39. fontTools/feaLib/builder.py +1802 -0
  40. fontTools/feaLib/error.py +22 -0
  41. fontTools/feaLib/lexer.c +17350 -0
  42. fontTools/feaLib/lexer.cp314-win_amd64.pyd +0 -0
  43. fontTools/feaLib/lexer.py +287 -0
  44. fontTools/feaLib/location.py +12 -0
  45. fontTools/feaLib/lookupDebugInfo.py +12 -0
  46. fontTools/feaLib/parser.py +2379 -0
  47. fontTools/feaLib/variableScalar.py +113 -0
  48. fontTools/fontBuilder.py +1014 -0
  49. fontTools/help.py +36 -0
  50. fontTools/merge/__init__.py +248 -0
  51. fontTools/merge/__main__.py +6 -0
  52. fontTools/merge/base.py +81 -0
  53. fontTools/merge/cmap.py +173 -0
  54. fontTools/merge/layout.py +526 -0
  55. fontTools/merge/options.py +85 -0
  56. fontTools/merge/tables.py +352 -0
  57. fontTools/merge/unicode.py +78 -0
  58. fontTools/merge/util.py +143 -0
  59. fontTools/misc/__init__.py +1 -0
  60. fontTools/misc/arrayTools.py +424 -0
  61. fontTools/misc/bezierTools.c +40150 -0
  62. fontTools/misc/bezierTools.cp314-win_amd64.pyd +0 -0
  63. fontTools/misc/bezierTools.py +1497 -0
  64. fontTools/misc/classifyTools.py +170 -0
  65. fontTools/misc/cliTools.py +53 -0
  66. fontTools/misc/configTools.py +349 -0
  67. fontTools/misc/cython.py +27 -0
  68. fontTools/misc/dictTools.py +83 -0
  69. fontTools/misc/eexec.py +119 -0
  70. fontTools/misc/encodingTools.py +72 -0
  71. fontTools/misc/etree.py +456 -0
  72. fontTools/misc/filenames.py +245 -0
  73. fontTools/misc/filesystem/__init__.py +68 -0
  74. fontTools/misc/filesystem/_base.py +134 -0
  75. fontTools/misc/filesystem/_copy.py +45 -0
  76. fontTools/misc/filesystem/_errors.py +54 -0
  77. fontTools/misc/filesystem/_info.py +75 -0
  78. fontTools/misc/filesystem/_osfs.py +164 -0
  79. fontTools/misc/filesystem/_path.py +67 -0
  80. fontTools/misc/filesystem/_subfs.py +92 -0
  81. fontTools/misc/filesystem/_tempfs.py +34 -0
  82. fontTools/misc/filesystem/_tools.py +34 -0
  83. fontTools/misc/filesystem/_walk.py +55 -0
  84. fontTools/misc/filesystem/_zipfs.py +204 -0
  85. fontTools/misc/fixedTools.py +253 -0
  86. fontTools/misc/intTools.py +25 -0
  87. fontTools/misc/iterTools.py +12 -0
  88. fontTools/misc/lazyTools.py +42 -0
  89. fontTools/misc/loggingTools.py +543 -0
  90. fontTools/misc/macCreatorType.py +56 -0
  91. fontTools/misc/macRes.py +261 -0
  92. fontTools/misc/plistlib/__init__.py +681 -0
  93. fontTools/misc/plistlib/py.typed +0 -0
  94. fontTools/misc/psCharStrings.py +1511 -0
  95. fontTools/misc/psLib.py +398 -0
  96. fontTools/misc/psOperators.py +572 -0
  97. fontTools/misc/py23.py +96 -0
  98. fontTools/misc/roundTools.py +110 -0
  99. fontTools/misc/sstruct.py +227 -0
  100. fontTools/misc/symfont.py +242 -0
  101. fontTools/misc/testTools.py +233 -0
  102. fontTools/misc/textTools.py +154 -0
  103. fontTools/misc/timeTools.py +88 -0
  104. fontTools/misc/transform.py +516 -0
  105. fontTools/misc/treeTools.py +45 -0
  106. fontTools/misc/vector.py +147 -0
  107. fontTools/misc/visitor.py +150 -0
  108. fontTools/misc/xmlReader.py +188 -0
  109. fontTools/misc/xmlWriter.py +231 -0
  110. fontTools/mtiLib/__init__.py +1400 -0
  111. fontTools/mtiLib/__main__.py +5 -0
  112. fontTools/otlLib/__init__.py +1 -0
  113. fontTools/otlLib/builder.py +3465 -0
  114. fontTools/otlLib/error.py +11 -0
  115. fontTools/otlLib/maxContextCalc.py +96 -0
  116. fontTools/otlLib/optimize/__init__.py +53 -0
  117. fontTools/otlLib/optimize/__main__.py +6 -0
  118. fontTools/otlLib/optimize/gpos.py +439 -0
  119. fontTools/pens/__init__.py +1 -0
  120. fontTools/pens/areaPen.py +52 -0
  121. fontTools/pens/basePen.py +475 -0
  122. fontTools/pens/boundsPen.py +98 -0
  123. fontTools/pens/cairoPen.py +26 -0
  124. fontTools/pens/cocoaPen.py +26 -0
  125. fontTools/pens/cu2quPen.py +325 -0
  126. fontTools/pens/explicitClosingLinePen.py +101 -0
  127. fontTools/pens/filterPen.py +241 -0
  128. fontTools/pens/freetypePen.py +462 -0
  129. fontTools/pens/hashPointPen.py +89 -0
  130. fontTools/pens/momentsPen.c +13465 -0
  131. fontTools/pens/momentsPen.cp314-win_amd64.pyd +0 -0
  132. fontTools/pens/momentsPen.py +879 -0
  133. fontTools/pens/perimeterPen.py +69 -0
  134. fontTools/pens/pointInsidePen.py +192 -0
  135. fontTools/pens/pointPen.py +609 -0
  136. fontTools/pens/qtPen.py +29 -0
  137. fontTools/pens/qu2cuPen.py +105 -0
  138. fontTools/pens/quartzPen.py +43 -0
  139. fontTools/pens/recordingPen.py +335 -0
  140. fontTools/pens/reportLabPen.py +79 -0
  141. fontTools/pens/reverseContourPen.py +96 -0
  142. fontTools/pens/roundingPen.py +130 -0
  143. fontTools/pens/statisticsPen.py +312 -0
  144. fontTools/pens/svgPathPen.py +310 -0
  145. fontTools/pens/t2CharStringPen.py +88 -0
  146. fontTools/pens/teePen.py +55 -0
  147. fontTools/pens/transformPen.py +115 -0
  148. fontTools/pens/ttGlyphPen.py +335 -0
  149. fontTools/pens/wxPen.py +29 -0
  150. fontTools/qu2cu/__init__.py +15 -0
  151. fontTools/qu2cu/__main__.py +7 -0
  152. fontTools/qu2cu/benchmark.py +56 -0
  153. fontTools/qu2cu/cli.py +125 -0
  154. fontTools/qu2cu/qu2cu.c +16752 -0
  155. fontTools/qu2cu/qu2cu.cp314-win_amd64.pyd +0 -0
  156. fontTools/qu2cu/qu2cu.py +405 -0
  157. fontTools/subset/__init__.py +3929 -0
  158. fontTools/subset/__main__.py +6 -0
  159. fontTools/subset/cff.py +184 -0
  160. fontTools/subset/svg.py +253 -0
  161. fontTools/subset/util.py +25 -0
  162. fontTools/svgLib/__init__.py +3 -0
  163. fontTools/svgLib/path/__init__.py +65 -0
  164. fontTools/svgLib/path/arc.py +154 -0
  165. fontTools/svgLib/path/parser.py +322 -0
  166. fontTools/svgLib/path/shapes.py +183 -0
  167. fontTools/t1Lib/__init__.py +648 -0
  168. fontTools/tfmLib.py +460 -0
  169. fontTools/ttLib/__init__.py +30 -0
  170. fontTools/ttLib/__main__.py +148 -0
  171. fontTools/ttLib/macUtils.py +54 -0
  172. fontTools/ttLib/removeOverlaps.py +393 -0
  173. fontTools/ttLib/reorderGlyphs.py +285 -0
  174. fontTools/ttLib/scaleUpem.py +436 -0
  175. fontTools/ttLib/sfnt.py +661 -0
  176. fontTools/ttLib/standardGlyphOrder.py +271 -0
  177. fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  178. fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  179. fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  180. fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  181. fontTools/ttLib/tables/C_F_F_.py +61 -0
  182. fontTools/ttLib/tables/C_F_F__2.py +26 -0
  183. fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  184. fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  185. fontTools/ttLib/tables/D_S_I_G_.py +158 -0
  186. fontTools/ttLib/tables/D__e_b_g.py +35 -0
  187. fontTools/ttLib/tables/DefaultTable.py +49 -0
  188. fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  189. fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  190. fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  191. fontTools/ttLib/tables/F__e_a_t.py +149 -0
  192. fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  193. fontTools/ttLib/tables/G_M_A_P_.py +148 -0
  194. fontTools/ttLib/tables/G_P_K_G_.py +133 -0
  195. fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  196. fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  197. fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  198. fontTools/ttLib/tables/G__l_a_t.py +235 -0
  199. fontTools/ttLib/tables/G__l_o_c.py +85 -0
  200. fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  201. fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  202. fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  203. fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  204. fontTools/ttLib/tables/M_E_T_A_.py +352 -0
  205. fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  206. fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  207. fontTools/ttLib/tables/S_I_N_G_.py +99 -0
  208. fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  209. fontTools/ttLib/tables/S_V_G_.py +223 -0
  210. fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  211. fontTools/ttLib/tables/S__i_l_l.py +92 -0
  212. fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  213. fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  214. fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  215. fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  216. fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  217. fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  218. fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  219. fontTools/ttLib/tables/T_S_I__0.py +70 -0
  220. fontTools/ttLib/tables/T_S_I__1.py +163 -0
  221. fontTools/ttLib/tables/T_S_I__2.py +17 -0
  222. fontTools/ttLib/tables/T_S_I__3.py +22 -0
  223. fontTools/ttLib/tables/T_S_I__5.py +60 -0
  224. fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  225. fontTools/ttLib/tables/TupleVariation.py +884 -0
  226. fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  227. fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  228. fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  229. fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  230. fontTools/ttLib/tables/__init__.py +98 -0
  231. fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  232. fontTools/ttLib/tables/_a_v_a_r.py +191 -0
  233. fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  234. fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  235. fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
  236. fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  237. fontTools/ttLib/tables/_c_v_t.py +56 -0
  238. fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  239. fontTools/ttLib/tables/_f_p_g_m.py +62 -0
  240. fontTools/ttLib/tables/_f_v_a_r.py +261 -0
  241. fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  242. fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  243. fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
  244. fontTools/ttLib/tables/_g_v_a_r.py +340 -0
  245. fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  246. fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  247. fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  248. fontTools/ttLib/tables/_h_m_t_x.py +164 -0
  249. fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  250. fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  251. fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  252. fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  253. fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  254. fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  255. fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  256. fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  257. fontTools/ttLib/tables/_n_a_m_e.py +1237 -0
  258. fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  259. fontTools/ttLib/tables/_p_o_s_t.py +319 -0
  260. fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  261. fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  262. fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  263. fontTools/ttLib/tables/_t_r_a_k.py +332 -0
  264. fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  265. fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  266. fontTools/ttLib/tables/asciiTable.py +20 -0
  267. fontTools/ttLib/tables/grUtils.py +92 -0
  268. fontTools/ttLib/tables/otBase.py +1464 -0
  269. fontTools/ttLib/tables/otConverters.py +2068 -0
  270. fontTools/ttLib/tables/otData.py +6400 -0
  271. fontTools/ttLib/tables/otTables.py +2703 -0
  272. fontTools/ttLib/tables/otTraverse.py +163 -0
  273. fontTools/ttLib/tables/sbixGlyph.py +149 -0
  274. fontTools/ttLib/tables/sbixStrike.py +177 -0
  275. fontTools/ttLib/tables/table_API_readme.txt +91 -0
  276. fontTools/ttLib/tables/ttProgram.py +594 -0
  277. fontTools/ttLib/ttCollection.py +125 -0
  278. fontTools/ttLib/ttFont.py +1148 -0
  279. fontTools/ttLib/ttGlyphSet.py +490 -0
  280. fontTools/ttLib/ttVisitor.py +32 -0
  281. fontTools/ttLib/woff2.py +1680 -0
  282. fontTools/ttx.py +479 -0
  283. fontTools/ufoLib/__init__.py +2472 -0
  284. fontTools/ufoLib/converters.py +398 -0
  285. fontTools/ufoLib/errors.py +30 -0
  286. fontTools/ufoLib/etree.py +6 -0
  287. fontTools/ufoLib/filenames.py +346 -0
  288. fontTools/ufoLib/glifLib.py +2024 -0
  289. fontTools/ufoLib/kerning.py +121 -0
  290. fontTools/ufoLib/plistlib.py +47 -0
  291. fontTools/ufoLib/pointPen.py +6 -0
  292. fontTools/ufoLib/utils.py +79 -0
  293. fontTools/ufoLib/validators.py +1184 -0
  294. fontTools/unicode.py +50 -0
  295. fontTools/unicodedata/Blocks.py +801 -0
  296. fontTools/unicodedata/Mirrored.py +446 -0
  297. fontTools/unicodedata/OTTags.py +50 -0
  298. fontTools/unicodedata/ScriptExtensions.py +826 -0
  299. fontTools/unicodedata/Scripts.py +3617 -0
  300. fontTools/unicodedata/__init__.py +304 -0
  301. fontTools/varLib/__init__.py +1517 -0
  302. fontTools/varLib/__main__.py +6 -0
  303. fontTools/varLib/avar.py +260 -0
  304. fontTools/varLib/avarPlanner.py +1004 -0
  305. fontTools/varLib/builder.py +215 -0
  306. fontTools/varLib/cff.py +631 -0
  307. fontTools/varLib/errors.py +219 -0
  308. fontTools/varLib/featureVars.py +703 -0
  309. fontTools/varLib/hvar.py +113 -0
  310. fontTools/varLib/instancer/__init__.py +2014 -0
  311. fontTools/varLib/instancer/__main__.py +5 -0
  312. fontTools/varLib/instancer/featureVars.py +190 -0
  313. fontTools/varLib/instancer/names.py +388 -0
  314. fontTools/varLib/instancer/solver.py +309 -0
  315. fontTools/varLib/interpolatable.py +1209 -0
  316. fontTools/varLib/interpolatableHelpers.py +396 -0
  317. fontTools/varLib/interpolatablePlot.py +1269 -0
  318. fontTools/varLib/interpolatableTestContourOrder.py +82 -0
  319. fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
  320. fontTools/varLib/interpolate_layout.py +124 -0
  321. fontTools/varLib/iup.c +19844 -0
  322. fontTools/varLib/iup.cp314-win_amd64.pyd +0 -0
  323. fontTools/varLib/iup.py +490 -0
  324. fontTools/varLib/merger.py +1717 -0
  325. fontTools/varLib/models.py +642 -0
  326. fontTools/varLib/multiVarStore.py +253 -0
  327. fontTools/varLib/mutator.py +529 -0
  328. fontTools/varLib/mvar.py +40 -0
  329. fontTools/varLib/plot.py +238 -0
  330. fontTools/varLib/stat.py +149 -0
  331. fontTools/varLib/varStore.py +739 -0
  332. fontTools/voltLib/__init__.py +5 -0
  333. fontTools/voltLib/__main__.py +206 -0
  334. fontTools/voltLib/ast.py +452 -0
  335. fontTools/voltLib/error.py +12 -0
  336. fontTools/voltLib/lexer.py +99 -0
  337. fontTools/voltLib/parser.py +664 -0
  338. fontTools/voltLib/voltToFea.py +911 -0
  339. fonttools-4.59.1.data/data/share/man/man1/ttx.1 +225 -0
  340. fonttools-4.59.1.dist-info/METADATA +2175 -0
  341. fonttools-4.59.1.dist-info/RECORD +346 -0
  342. fonttools-4.59.1.dist-info/WHEEL +5 -0
  343. fonttools-4.59.1.dist-info/entry_points.txt +5 -0
  344. fonttools-4.59.1.dist-info/licenses/LICENSE +21 -0
  345. fonttools-4.59.1.dist-info/licenses/LICENSE.external +388 -0
  346. fonttools-4.59.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,531 @@
1
+ # cython: language_level=3
2
+ # distutils: define_macros=CYTHON_TRACE_NOGIL=1
3
+
4
+ # Copyright 2015 Google Inc. All Rights Reserved.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ try:
19
+ import cython
20
+ except (AttributeError, ImportError):
21
+ # if cython not installed, use mock module with no-op decorators and types
22
+ from fontTools.misc import cython
23
+ COMPILED = cython.compiled
24
+
25
+ import math
26
+
27
+ from .errors import Error as Cu2QuError, ApproxNotFoundError
28
+
29
+
30
+ __all__ = ["curve_to_quadratic", "curves_to_quadratic"]
31
+
32
+ MAX_N = 100
33
+
34
+ NAN = float("NaN")
35
+
36
+
37
+ @cython.cfunc
38
+ @cython.inline
39
+ @cython.returns(cython.double)
40
+ @cython.locals(v1=cython.complex, v2=cython.complex)
41
+ def dot(v1, v2):
42
+ """Return the dot product of two vectors.
43
+
44
+ Args:
45
+ v1 (complex): First vector.
46
+ v2 (complex): Second vector.
47
+
48
+ Returns:
49
+ double: Dot product.
50
+ """
51
+ return (v1 * v2.conjugate()).real
52
+
53
+
54
+ @cython.cfunc
55
+ @cython.inline
56
+ @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
57
+ @cython.locals(
58
+ _1=cython.complex, _2=cython.complex, _3=cython.complex, _4=cython.complex
59
+ )
60
+ def calc_cubic_points(a, b, c, d):
61
+ _1 = d
62
+ _2 = (c / 3.0) + d
63
+ _3 = (b + c) / 3.0 + _2
64
+ _4 = a + d + c + b
65
+ return _1, _2, _3, _4
66
+
67
+
68
+ @cython.cfunc
69
+ @cython.inline
70
+ @cython.locals(
71
+ p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex
72
+ )
73
+ @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
74
+ def calc_cubic_parameters(p0, p1, p2, p3):
75
+ c = (p1 - p0) * 3.0
76
+ b = (p2 - p1) * 3.0 - c
77
+ d = p0
78
+ a = p3 - d - c - b
79
+ return a, b, c, d
80
+
81
+
82
+ @cython.cfunc
83
+ @cython.inline
84
+ @cython.locals(
85
+ p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex
86
+ )
87
+ def split_cubic_into_n_iter(p0, p1, p2, p3, n):
88
+ """Split a cubic Bezier into n equal parts.
89
+
90
+ Splits the curve into `n` equal parts by curve time.
91
+ (t=0..1/n, t=1/n..2/n, ...)
92
+
93
+ Args:
94
+ p0 (complex): Start point of curve.
95
+ p1 (complex): First handle of curve.
96
+ p2 (complex): Second handle of curve.
97
+ p3 (complex): End point of curve.
98
+
99
+ Returns:
100
+ An iterator yielding the control points (four complex values) of the
101
+ subcurves.
102
+ """
103
+ # Hand-coded special-cases
104
+ if n == 2:
105
+ return iter(split_cubic_into_two(p0, p1, p2, p3))
106
+ if n == 3:
107
+ return iter(split_cubic_into_three(p0, p1, p2, p3))
108
+ if n == 4:
109
+ a, b = split_cubic_into_two(p0, p1, p2, p3)
110
+ return iter(
111
+ split_cubic_into_two(a[0], a[1], a[2], a[3])
112
+ + split_cubic_into_two(b[0], b[1], b[2], b[3])
113
+ )
114
+ if n == 6:
115
+ a, b = split_cubic_into_two(p0, p1, p2, p3)
116
+ return iter(
117
+ split_cubic_into_three(a[0], a[1], a[2], a[3])
118
+ + split_cubic_into_three(b[0], b[1], b[2], b[3])
119
+ )
120
+
121
+ return _split_cubic_into_n_gen(p0, p1, p2, p3, n)
122
+
123
+
124
+ @cython.locals(
125
+ p0=cython.complex,
126
+ p1=cython.complex,
127
+ p2=cython.complex,
128
+ p3=cython.complex,
129
+ n=cython.int,
130
+ )
131
+ @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
132
+ @cython.locals(
133
+ dt=cython.double, delta_2=cython.double, delta_3=cython.double, i=cython.int
134
+ )
135
+ @cython.locals(
136
+ a1=cython.complex, b1=cython.complex, c1=cython.complex, d1=cython.complex
137
+ )
138
+ def _split_cubic_into_n_gen(p0, p1, p2, p3, n):
139
+ a, b, c, d = calc_cubic_parameters(p0, p1, p2, p3)
140
+ dt = 1 / n
141
+ delta_2 = dt * dt
142
+ delta_3 = dt * delta_2
143
+ for i in range(n):
144
+ t1 = i * dt
145
+ t1_2 = t1 * t1
146
+ # calc new a, b, c and d
147
+ a1 = a * delta_3
148
+ b1 = (3 * a * t1 + b) * delta_2
149
+ c1 = (2 * b * t1 + c + 3 * a * t1_2) * dt
150
+ d1 = a * t1 * t1_2 + b * t1_2 + c * t1 + d
151
+ yield calc_cubic_points(a1, b1, c1, d1)
152
+
153
+
154
+ @cython.cfunc
155
+ @cython.inline
156
+ @cython.locals(
157
+ p0=cython.complex, p1=cython.complex, p2=cython.complex, p3=cython.complex
158
+ )
159
+ @cython.locals(mid=cython.complex, deriv3=cython.complex)
160
+ def split_cubic_into_two(p0, p1, p2, p3):
161
+ """Split a cubic Bezier into two equal parts.
162
+
163
+ Splits the curve into two equal parts at t = 0.5
164
+
165
+ Args:
166
+ p0 (complex): Start point of curve.
167
+ p1 (complex): First handle of curve.
168
+ p2 (complex): Second handle of curve.
169
+ p3 (complex): End point of curve.
170
+
171
+ Returns:
172
+ tuple: Two cubic Beziers (each expressed as a tuple of four complex
173
+ values).
174
+ """
175
+ mid = (p0 + 3 * (p1 + p2) + p3) * 0.125
176
+ deriv3 = (p3 + p2 - p1 - p0) * 0.125
177
+ return (
178
+ (p0, (p0 + p1) * 0.5, mid - deriv3, mid),
179
+ (mid, mid + deriv3, (p2 + p3) * 0.5, p3),
180
+ )
181
+
182
+
183
+ @cython.cfunc
184
+ @cython.inline
185
+ @cython.locals(
186
+ p0=cython.complex,
187
+ p1=cython.complex,
188
+ p2=cython.complex,
189
+ p3=cython.complex,
190
+ )
191
+ @cython.locals(
192
+ mid1=cython.complex,
193
+ deriv1=cython.complex,
194
+ mid2=cython.complex,
195
+ deriv2=cython.complex,
196
+ )
197
+ def split_cubic_into_three(p0, p1, p2, p3):
198
+ """Split a cubic Bezier into three equal parts.
199
+
200
+ Splits the curve into three equal parts at t = 1/3 and t = 2/3
201
+
202
+ Args:
203
+ p0 (complex): Start point of curve.
204
+ p1 (complex): First handle of curve.
205
+ p2 (complex): Second handle of curve.
206
+ p3 (complex): End point of curve.
207
+
208
+ Returns:
209
+ tuple: Three cubic Beziers (each expressed as a tuple of four complex
210
+ values).
211
+ """
212
+ mid1 = (8 * p0 + 12 * p1 + 6 * p2 + p3) * (1 / 27)
213
+ deriv1 = (p3 + 3 * p2 - 4 * p0) * (1 / 27)
214
+ mid2 = (p0 + 6 * p1 + 12 * p2 + 8 * p3) * (1 / 27)
215
+ deriv2 = (4 * p3 - 3 * p1 - p0) * (1 / 27)
216
+ return (
217
+ (p0, (2 * p0 + p1) / 3.0, mid1 - deriv1, mid1),
218
+ (mid1, mid1 + deriv1, mid2 - deriv2, mid2),
219
+ (mid2, mid2 + deriv2, (p2 + 2 * p3) / 3.0, p3),
220
+ )
221
+
222
+
223
+ @cython.cfunc
224
+ @cython.inline
225
+ @cython.returns(cython.complex)
226
+ @cython.locals(
227
+ t=cython.double,
228
+ p0=cython.complex,
229
+ p1=cython.complex,
230
+ p2=cython.complex,
231
+ p3=cython.complex,
232
+ )
233
+ @cython.locals(_p1=cython.complex, _p2=cython.complex)
234
+ def cubic_approx_control(t, p0, p1, p2, p3):
235
+ """Approximate a cubic Bezier using a quadratic one.
236
+
237
+ Args:
238
+ t (double): Position of control point.
239
+ p0 (complex): Start point of curve.
240
+ p1 (complex): First handle of curve.
241
+ p2 (complex): Second handle of curve.
242
+ p3 (complex): End point of curve.
243
+
244
+ Returns:
245
+ complex: Location of candidate control point on quadratic curve.
246
+ """
247
+ _p1 = p0 + (p1 - p0) * 1.5
248
+ _p2 = p3 + (p2 - p3) * 1.5
249
+ return _p1 + (_p2 - _p1) * t
250
+
251
+
252
+ @cython.cfunc
253
+ @cython.inline
254
+ @cython.returns(cython.complex)
255
+ @cython.locals(a=cython.complex, b=cython.complex, c=cython.complex, d=cython.complex)
256
+ @cython.locals(ab=cython.complex, cd=cython.complex, p=cython.complex, h=cython.double)
257
+ def calc_intersect(a, b, c, d):
258
+ """Calculate the intersection of two lines.
259
+
260
+ Args:
261
+ a (complex): Start point of first line.
262
+ b (complex): End point of first line.
263
+ c (complex): Start point of second line.
264
+ d (complex): End point of second line.
265
+
266
+ Returns:
267
+ complex: Location of intersection if one present, ``complex(NaN,NaN)``
268
+ if no intersection was found.
269
+ """
270
+ ab = b - a
271
+ cd = d - c
272
+ p = ab * 1j
273
+ try:
274
+ h = dot(p, a - c) / dot(p, cd)
275
+ except ZeroDivisionError:
276
+ return complex(NAN, NAN)
277
+ return c + cd * h
278
+
279
+
280
+ @cython.cfunc
281
+ @cython.returns(cython.int)
282
+ @cython.locals(
283
+ tolerance=cython.double,
284
+ p0=cython.complex,
285
+ p1=cython.complex,
286
+ p2=cython.complex,
287
+ p3=cython.complex,
288
+ )
289
+ @cython.locals(mid=cython.complex, deriv3=cython.complex)
290
+ def cubic_farthest_fit_inside(p0, p1, p2, p3, tolerance):
291
+ """Check if a cubic Bezier lies within a given distance of the origin.
292
+
293
+ "Origin" means *the* origin (0,0), not the start of the curve. Note that no
294
+ checks are made on the start and end positions of the curve; this function
295
+ only checks the inside of the curve.
296
+
297
+ Args:
298
+ p0 (complex): Start point of curve.
299
+ p1 (complex): First handle of curve.
300
+ p2 (complex): Second handle of curve.
301
+ p3 (complex): End point of curve.
302
+ tolerance (double): Distance from origin.
303
+
304
+ Returns:
305
+ bool: True if the cubic Bezier ``p`` entirely lies within a distance
306
+ ``tolerance`` of the origin, False otherwise.
307
+ """
308
+ # First check p2 then p1, as p2 has higher error early on.
309
+ if abs(p2) <= tolerance and abs(p1) <= tolerance:
310
+ return True
311
+
312
+ # Split.
313
+ mid = (p0 + 3 * (p1 + p2) + p3) * 0.125
314
+ if abs(mid) > tolerance:
315
+ return False
316
+ deriv3 = (p3 + p2 - p1 - p0) * 0.125
317
+ return cubic_farthest_fit_inside(
318
+ p0, (p0 + p1) * 0.5, mid - deriv3, mid, tolerance
319
+ ) and cubic_farthest_fit_inside(mid, mid + deriv3, (p2 + p3) * 0.5, p3, tolerance)
320
+
321
+
322
+ @cython.cfunc
323
+ @cython.inline
324
+ @cython.locals(tolerance=cython.double)
325
+ @cython.locals(
326
+ q1=cython.complex,
327
+ c0=cython.complex,
328
+ c1=cython.complex,
329
+ c2=cython.complex,
330
+ c3=cython.complex,
331
+ )
332
+ def cubic_approx_quadratic(cubic, tolerance):
333
+ """Approximate a cubic Bezier with a single quadratic within a given tolerance.
334
+
335
+ Args:
336
+ cubic (sequence): Four complex numbers representing control points of
337
+ the cubic Bezier curve.
338
+ tolerance (double): Permitted deviation from the original curve.
339
+
340
+ Returns:
341
+ Three complex numbers representing control points of the quadratic
342
+ curve if it fits within the given tolerance, or ``None`` if no suitable
343
+ curve could be calculated.
344
+ """
345
+
346
+ q1 = calc_intersect(cubic[0], cubic[1], cubic[2], cubic[3])
347
+ if math.isnan(q1.imag):
348
+ return None
349
+ c0 = cubic[0]
350
+ c3 = cubic[3]
351
+ c1 = c0 + (q1 - c0) * (2 / 3)
352
+ c2 = c3 + (q1 - c3) * (2 / 3)
353
+ if not cubic_farthest_fit_inside(0, c1 - cubic[1], c2 - cubic[2], 0, tolerance):
354
+ return None
355
+ return c0, q1, c3
356
+
357
+
358
+ @cython.cfunc
359
+ @cython.locals(n=cython.int, tolerance=cython.double)
360
+ @cython.locals(i=cython.int)
361
+ @cython.locals(all_quadratic=cython.int)
362
+ @cython.locals(
363
+ c0=cython.complex, c1=cython.complex, c2=cython.complex, c3=cython.complex
364
+ )
365
+ @cython.locals(
366
+ q0=cython.complex,
367
+ q1=cython.complex,
368
+ next_q1=cython.complex,
369
+ q2=cython.complex,
370
+ d1=cython.complex,
371
+ )
372
+ def cubic_approx_spline(cubic, n, tolerance, all_quadratic):
373
+ """Approximate a cubic Bezier curve with a spline of n quadratics.
374
+
375
+ Args:
376
+ cubic (sequence): Four complex numbers representing control points of
377
+ the cubic Bezier curve.
378
+ n (int): Number of quadratic Bezier curves in the spline.
379
+ tolerance (double): Permitted deviation from the original curve.
380
+
381
+ Returns:
382
+ A list of ``n+2`` complex numbers, representing control points of the
383
+ quadratic spline if it fits within the given tolerance, or ``None`` if
384
+ no suitable spline could be calculated.
385
+ """
386
+
387
+ if n == 1:
388
+ return cubic_approx_quadratic(cubic, tolerance)
389
+ if n == 2 and all_quadratic == False:
390
+ return cubic
391
+
392
+ cubics = split_cubic_into_n_iter(cubic[0], cubic[1], cubic[2], cubic[3], n)
393
+
394
+ # calculate the spline of quadratics and check errors at the same time.
395
+ next_cubic = next(cubics)
396
+ next_q1 = cubic_approx_control(
397
+ 0, next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3]
398
+ )
399
+ q2 = cubic[0]
400
+ d1 = 0j
401
+ spline = [cubic[0], next_q1]
402
+ for i in range(1, n + 1):
403
+ # Current cubic to convert
404
+ c0, c1, c2, c3 = next_cubic
405
+
406
+ # Current quadratic approximation of current cubic
407
+ q0 = q2
408
+ q1 = next_q1
409
+ if i < n:
410
+ next_cubic = next(cubics)
411
+ next_q1 = cubic_approx_control(
412
+ i / (n - 1), next_cubic[0], next_cubic[1], next_cubic[2], next_cubic[3]
413
+ )
414
+ spline.append(next_q1)
415
+ q2 = (q1 + next_q1) * 0.5
416
+ else:
417
+ q2 = c3
418
+
419
+ # End-point deltas
420
+ d0 = d1
421
+ d1 = q2 - c3
422
+
423
+ if abs(d1) > tolerance or not cubic_farthest_fit_inside(
424
+ d0,
425
+ q0 + (q1 - q0) * (2 / 3) - c1,
426
+ q2 + (q1 - q2) * (2 / 3) - c2,
427
+ d1,
428
+ tolerance,
429
+ ):
430
+ return None
431
+ spline.append(cubic[3])
432
+
433
+ return spline
434
+
435
+
436
+ @cython.locals(max_err=cython.double)
437
+ @cython.locals(n=cython.int)
438
+ @cython.locals(all_quadratic=cython.int)
439
+ def curve_to_quadratic(curve, max_err, all_quadratic=True):
440
+ """Approximate a cubic Bezier curve with a spline of n quadratics.
441
+
442
+ Args:
443
+ cubic (sequence): Four 2D tuples representing control points of
444
+ the cubic Bezier curve.
445
+ max_err (double): Permitted deviation from the original curve.
446
+ all_quadratic (bool): If True (default) returned value is a
447
+ quadratic spline. If False, it's either a single quadratic
448
+ curve or a single cubic curve.
449
+
450
+ Returns:
451
+ If all_quadratic is True: A list of 2D tuples, representing
452
+ control points of the quadratic spline if it fits within the
453
+ given tolerance, or ``None`` if no suitable spline could be
454
+ calculated.
455
+
456
+ If all_quadratic is False: Either a quadratic curve (if length
457
+ of output is 3), or a cubic curve (if length of output is 4).
458
+ """
459
+
460
+ curve = [complex(*p) for p in curve]
461
+
462
+ for n in range(1, MAX_N + 1):
463
+ spline = cubic_approx_spline(curve, n, max_err, all_quadratic)
464
+ if spline is not None:
465
+ # done. go home
466
+ return [(s.real, s.imag) for s in spline]
467
+
468
+ raise ApproxNotFoundError(curve)
469
+
470
+
471
+ @cython.locals(l=cython.int, last_i=cython.int, i=cython.int)
472
+ @cython.locals(all_quadratic=cython.int)
473
+ def curves_to_quadratic(curves, max_errors, all_quadratic=True):
474
+ """Return quadratic Bezier splines approximating the input cubic Beziers.
475
+
476
+ Args:
477
+ curves: A sequence of *n* curves, each curve being a sequence of four
478
+ 2D tuples.
479
+ max_errors: A sequence of *n* floats representing the maximum permissible
480
+ deviation from each of the cubic Bezier curves.
481
+ all_quadratic (bool): If True (default) returned values are a
482
+ quadratic spline. If False, they are either a single quadratic
483
+ curve or a single cubic curve.
484
+
485
+ Example::
486
+
487
+ >>> curves_to_quadratic( [
488
+ ... [ (50,50), (100,100), (150,100), (200,50) ],
489
+ ... [ (75,50), (120,100), (150,75), (200,60) ]
490
+ ... ], [1,1] )
491
+ [[(50.0, 50.0), (75.0, 75.0), (125.0, 91.66666666666666), (175.0, 75.0), (200.0, 50.0)], [(75.0, 50.0), (97.5, 75.0), (135.41666666666666, 82.08333333333333), (175.0, 67.5), (200.0, 60.0)]]
492
+
493
+ The returned splines have "implied oncurve points" suitable for use in
494
+ TrueType ``glif`` outlines - i.e. in the first spline returned above,
495
+ the first quadratic segment runs from (50,50) to
496
+ ( (75 + 125)/2 , (120 + 91.666..)/2 ) = (100, 83.333...).
497
+
498
+ Returns:
499
+ If all_quadratic is True, a list of splines, each spline being a list
500
+ of 2D tuples.
501
+
502
+ If all_quadratic is False, a list of curves, each curve being a quadratic
503
+ (length 3), or cubic (length 4).
504
+
505
+ Raises:
506
+ fontTools.cu2qu.Errors.ApproxNotFoundError: if no suitable approximation
507
+ can be found for all curves with the given parameters.
508
+ """
509
+
510
+ curves = [[complex(*p) for p in curve] for curve in curves]
511
+ assert len(max_errors) == len(curves)
512
+
513
+ l = len(curves)
514
+ splines = [None] * l
515
+ last_i = i = 0
516
+ n = 1
517
+ while True:
518
+ spline = cubic_approx_spline(curves[i], n, max_errors[i], all_quadratic)
519
+ if spline is None:
520
+ if n == MAX_N:
521
+ break
522
+ n += 1
523
+ last_i = i
524
+ continue
525
+ splines[i] = spline
526
+ i = (i + 1) % l
527
+ if i == last_i:
528
+ # done. go home
529
+ return [[(s.real, s.imag) for s in spline] for spline in splines]
530
+
531
+ raise ApproxNotFoundError(curves)
@@ -0,0 +1,77 @@
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
+
16
+ class Error(Exception):
17
+ """Base Cu2Qu exception class for all other errors."""
18
+
19
+
20
+ class ApproxNotFoundError(Error):
21
+ def __init__(self, curve):
22
+ message = "no approximation found: %s" % curve
23
+ super().__init__(message)
24
+ self.curve = curve
25
+
26
+
27
+ class UnequalZipLengthsError(Error):
28
+ pass
29
+
30
+
31
+ class IncompatibleGlyphsError(Error):
32
+ def __init__(self, glyphs):
33
+ assert len(glyphs) > 1
34
+ self.glyphs = glyphs
35
+ names = set(repr(g.name) for g in glyphs)
36
+ if len(names) > 1:
37
+ self.combined_name = "{%s}" % ", ".join(sorted(names))
38
+ else:
39
+ self.combined_name = names.pop()
40
+
41
+ def __repr__(self):
42
+ return "<%s %s>" % (type(self).__name__, self.combined_name)
43
+
44
+
45
+ class IncompatibleSegmentNumberError(IncompatibleGlyphsError):
46
+ def __str__(self):
47
+ return "Glyphs named %s have different number of segments" % (
48
+ self.combined_name
49
+ )
50
+
51
+
52
+ class IncompatibleSegmentTypesError(IncompatibleGlyphsError):
53
+ def __init__(self, glyphs, segments):
54
+ IncompatibleGlyphsError.__init__(self, glyphs)
55
+ self.segments = segments
56
+
57
+ def __str__(self):
58
+ lines = []
59
+ ndigits = len(str(max(self.segments)))
60
+ for i, tags in sorted(self.segments.items()):
61
+ lines.append(
62
+ "%s: (%s)" % (str(i).rjust(ndigits), ", ".join(repr(t) for t in tags))
63
+ )
64
+ return "Glyphs named %s have incompatible segment types:\n %s" % (
65
+ self.combined_name,
66
+ "\n ".join(lines),
67
+ )
68
+
69
+
70
+ class IncompatibleFontsError(Error):
71
+ def __init__(self, glyph_errors):
72
+ self.glyph_errors = glyph_errors
73
+
74
+ def __str__(self):
75
+ return "fonts contains incompatible glyphs: %s" % (
76
+ ", ".join(repr(g) for g in sorted(self.glyph_errors.keys()))
77
+ )