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,529 @@
1
+ """
2
+ Instantiate a variation font. Run, eg:
3
+
4
+ .. code-block:: sh
5
+
6
+ $ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
7
+
8
+ .. warning::
9
+ ``fontTools.varLib.mutator`` is deprecated in favor of :mod:`fontTools.varLib.instancer`
10
+ which provides equivalent full instancing and also supports partial instancing.
11
+ Please migrate CLI usage to ``fonttools varLib.instancer`` and API usage to
12
+ :func:`fontTools.varLib.instancer.instantiateVariableFont`.
13
+ """
14
+
15
+ from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed
16
+ from fontTools.misc.loggingTools import deprecateFunction
17
+ from fontTools.misc.roundTools import otRound
18
+ from fontTools.pens.boundsPen import BoundsPen
19
+ from fontTools.ttLib import TTFont, newTable
20
+ from fontTools.ttLib.tables import ttProgram
21
+ from fontTools.ttLib.tables._g_l_y_f import (
22
+ GlyphCoordinates,
23
+ flagOverlapSimple,
24
+ OVERLAP_COMPOUND,
25
+ )
26
+ from fontTools.varLib.models import (
27
+ supportScalar,
28
+ normalizeLocation,
29
+ piecewiseLinearMap,
30
+ )
31
+ from fontTools.varLib.merger import MutatorMerger
32
+ from fontTools.varLib.varStore import VarStoreInstancer
33
+ from fontTools.varLib.mvar import MVAR_ENTRIES
34
+ from fontTools.varLib.iup import iup_delta
35
+ import fontTools.subset.cff
36
+ import os.path
37
+ import logging
38
+ from io import BytesIO
39
+
40
+
41
+ log = logging.getLogger("fontTools.varlib.mutator")
42
+
43
+ # map 'wdth' axis (1..200) to OS/2.usWidthClass (1..9), rounding to closest
44
+ OS2_WIDTH_CLASS_VALUES = {}
45
+ percents = [50.0, 62.5, 75.0, 87.5, 100.0, 112.5, 125.0, 150.0, 200.0]
46
+ for i, (prev, curr) in enumerate(zip(percents[:-1], percents[1:]), start=1):
47
+ half = (prev + curr) / 2
48
+ OS2_WIDTH_CLASS_VALUES[half] = i
49
+
50
+
51
+ def interpolate_cff2_PrivateDict(topDict, interpolateFromDeltas):
52
+ pd_blend_lists = (
53
+ "BlueValues",
54
+ "OtherBlues",
55
+ "FamilyBlues",
56
+ "FamilyOtherBlues",
57
+ "StemSnapH",
58
+ "StemSnapV",
59
+ )
60
+ pd_blend_values = ("BlueScale", "BlueShift", "BlueFuzz", "StdHW", "StdVW")
61
+ for fontDict in topDict.FDArray:
62
+ pd = fontDict.Private
63
+ vsindex = pd.vsindex if (hasattr(pd, "vsindex")) else 0
64
+ for key, value in pd.rawDict.items():
65
+ if (key in pd_blend_values) and isinstance(value, list):
66
+ delta = interpolateFromDeltas(vsindex, value[1:])
67
+ pd.rawDict[key] = otRound(value[0] + delta)
68
+ elif (key in pd_blend_lists) and isinstance(value[0], list):
69
+ """If any argument in a BlueValues list is a blend list,
70
+ then they all are. The first value of each list is an
71
+ absolute value. The delta tuples are calculated from
72
+ relative master values, hence we need to append all the
73
+ deltas to date to each successive absolute value."""
74
+ delta = 0
75
+ for i, val_list in enumerate(value):
76
+ delta += otRound(interpolateFromDeltas(vsindex, val_list[1:]))
77
+ value[i] = val_list[0] + delta
78
+
79
+
80
+ def interpolate_cff2_charstrings(topDict, interpolateFromDeltas, glyphOrder):
81
+ charstrings = topDict.CharStrings
82
+ for gname in glyphOrder:
83
+ # Interpolate charstring
84
+ # e.g replace blend op args with regular args,
85
+ # and use and discard vsindex op.
86
+ charstring = charstrings[gname]
87
+ new_program = []
88
+ vsindex = 0
89
+ last_i = 0
90
+ for i, token in enumerate(charstring.program):
91
+ if token == "vsindex":
92
+ vsindex = charstring.program[i - 1]
93
+ if last_i != 0:
94
+ new_program.extend(charstring.program[last_i : i - 1])
95
+ last_i = i + 1
96
+ elif token == "blend":
97
+ num_regions = charstring.getNumRegions(vsindex)
98
+ numMasters = 1 + num_regions
99
+ num_args = charstring.program[i - 1]
100
+ # The program list starting at program[i] is now:
101
+ # ..args for following operations
102
+ # num_args values from the default font
103
+ # num_args tuples, each with numMasters-1 delta values
104
+ # num_blend_args
105
+ # 'blend'
106
+ argi = i - (num_args * numMasters + 1)
107
+ end_args = tuplei = argi + num_args
108
+ while argi < end_args:
109
+ next_ti = tuplei + num_regions
110
+ deltas = charstring.program[tuplei:next_ti]
111
+ delta = interpolateFromDeltas(vsindex, deltas)
112
+ charstring.program[argi] += otRound(delta)
113
+ tuplei = next_ti
114
+ argi += 1
115
+ new_program.extend(charstring.program[last_i:end_args])
116
+ last_i = i + 1
117
+ if last_i != 0:
118
+ new_program.extend(charstring.program[last_i:])
119
+ charstring.program = new_program
120
+
121
+
122
+ def interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc):
123
+ """Unlike TrueType glyphs, neither advance width nor bounding box
124
+ info is stored in a CFF2 charstring. The width data exists only in
125
+ the hmtx and HVAR tables. Since LSB data cannot be interpolated
126
+ reliably from the master LSB values in the hmtx table, we traverse
127
+ the charstring to determine the actual bound box."""
128
+
129
+ charstrings = topDict.CharStrings
130
+ boundsPen = BoundsPen(glyphOrder)
131
+ hmtx = varfont["hmtx"]
132
+ hvar_table = None
133
+ if "HVAR" in varfont:
134
+ hvar_table = varfont["HVAR"].table
135
+ fvar = varfont["fvar"]
136
+ varStoreInstancer = VarStoreInstancer(hvar_table.VarStore, fvar.axes, loc)
137
+
138
+ for gid, gname in enumerate(glyphOrder):
139
+ entry = list(hmtx[gname])
140
+ # get width delta.
141
+ if hvar_table:
142
+ if hvar_table.AdvWidthMap:
143
+ width_idx = hvar_table.AdvWidthMap.mapping[gname]
144
+ else:
145
+ width_idx = gid
146
+ width_delta = otRound(varStoreInstancer[width_idx])
147
+ else:
148
+ width_delta = 0
149
+
150
+ # get LSB.
151
+ boundsPen.init()
152
+ charstring = charstrings[gname]
153
+ charstring.draw(boundsPen)
154
+ if boundsPen.bounds is None:
155
+ # Happens with non-marking glyphs
156
+ lsb_delta = 0
157
+ else:
158
+ lsb = otRound(boundsPen.bounds[0])
159
+ lsb_delta = entry[1] - lsb
160
+
161
+ if lsb_delta or width_delta:
162
+ if width_delta:
163
+ entry[0] = max(0, entry[0] + width_delta)
164
+ if lsb_delta:
165
+ entry[1] = lsb
166
+ hmtx[gname] = tuple(entry)
167
+
168
+
169
+ @deprecateFunction(
170
+ "use fontTools.varLib.instancer.instantiateVariableFont instead "
171
+ "for either full or partial instancing",
172
+ )
173
+ def instantiateVariableFont(varfont, location, inplace=False, overlap=True):
174
+ """Generate a static instance from a variable TTFont and a dictionary
175
+ defining the desired location along the variable font's axes.
176
+ The location values must be specified as user-space coordinates, e.g.:
177
+
178
+ .. code-block::
179
+
180
+ {'wght': 400, 'wdth': 100}
181
+
182
+ By default, a new TTFont object is returned. If ``inplace`` is True, the
183
+ input varfont is modified and reduced to a static font.
184
+
185
+ When the overlap parameter is defined as True,
186
+ OVERLAP_SIMPLE and OVERLAP_COMPOUND bits are set to 1. See
187
+ https://docs.microsoft.com/en-us/typography/opentype/spec/glyf
188
+ """
189
+ if not inplace:
190
+ # make a copy to leave input varfont unmodified
191
+ stream = BytesIO()
192
+ varfont.save(stream)
193
+ stream.seek(0)
194
+ varfont = TTFont(stream)
195
+
196
+ fvar = varfont["fvar"]
197
+ axes = {a.axisTag: (a.minValue, a.defaultValue, a.maxValue) for a in fvar.axes}
198
+ loc = normalizeLocation(location, axes)
199
+ if "avar" in varfont:
200
+ maps = varfont["avar"].segments
201
+ loc = {k: piecewiseLinearMap(v, maps[k]) for k, v in loc.items()}
202
+ # Quantize to F2Dot14, to avoid surprise interpolations.
203
+ loc = {k: floatToFixedToFloat(v, 14) for k, v in loc.items()}
204
+ # Location is normalized now
205
+ log.info("Normalized location: %s", loc)
206
+
207
+ if "gvar" in varfont:
208
+ log.info("Mutating glyf/gvar tables")
209
+ gvar = varfont["gvar"]
210
+ glyf = varfont["glyf"]
211
+ hMetrics = varfont["hmtx"].metrics
212
+ vMetrics = getattr(varfont.get("vmtx"), "metrics", None)
213
+ # get list of glyph names in gvar sorted by component depth
214
+ glyphnames = sorted(
215
+ gvar.variations.keys(),
216
+ key=lambda name: (
217
+ (
218
+ glyf[name].getCompositeMaxpValues(glyf).maxComponentDepth
219
+ if glyf[name].isComposite()
220
+ else 0
221
+ ),
222
+ name,
223
+ ),
224
+ )
225
+ for glyphname in glyphnames:
226
+ variations = gvar.variations[glyphname]
227
+ coordinates, _ = glyf._getCoordinatesAndControls(
228
+ glyphname, hMetrics, vMetrics
229
+ )
230
+ origCoords, endPts = None, None
231
+ for var in variations:
232
+ scalar = supportScalar(loc, var.axes)
233
+ if not scalar:
234
+ continue
235
+ delta = var.coordinates
236
+ if None in delta:
237
+ if origCoords is None:
238
+ origCoords, g = glyf._getCoordinatesAndControls(
239
+ glyphname, hMetrics, vMetrics
240
+ )
241
+ delta = iup_delta(delta, origCoords, g.endPts)
242
+ coordinates += GlyphCoordinates(delta) * scalar
243
+ glyf._setCoordinates(glyphname, coordinates, hMetrics, vMetrics)
244
+ else:
245
+ glyf = None
246
+
247
+ if "DSIG" in varfont:
248
+ del varfont["DSIG"]
249
+
250
+ if "cvar" in varfont:
251
+ log.info("Mutating cvt/cvar tables")
252
+ cvar = varfont["cvar"]
253
+ cvt = varfont["cvt "]
254
+ deltas = {}
255
+ for var in cvar.variations:
256
+ scalar = supportScalar(loc, var.axes)
257
+ if not scalar:
258
+ continue
259
+ for i, c in enumerate(var.coordinates):
260
+ if c is not None:
261
+ deltas[i] = deltas.get(i, 0) + scalar * c
262
+ for i, delta in deltas.items():
263
+ cvt[i] += otRound(delta)
264
+
265
+ if "CFF2" in varfont:
266
+ log.info("Mutating CFF2 table")
267
+ glyphOrder = varfont.getGlyphOrder()
268
+ CFF2 = varfont["CFF2"]
269
+ topDict = CFF2.cff.topDictIndex[0]
270
+ vsInstancer = VarStoreInstancer(topDict.VarStore.otVarStore, fvar.axes, loc)
271
+ interpolateFromDeltas = vsInstancer.interpolateFromDeltas
272
+ interpolate_cff2_PrivateDict(topDict, interpolateFromDeltas)
273
+ CFF2.desubroutinize()
274
+ interpolate_cff2_charstrings(topDict, interpolateFromDeltas, glyphOrder)
275
+ interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc)
276
+ del topDict.rawDict["VarStore"]
277
+ del topDict.VarStore
278
+
279
+ if "MVAR" in varfont:
280
+ log.info("Mutating MVAR table")
281
+ mvar = varfont["MVAR"].table
282
+ varStoreInstancer = VarStoreInstancer(mvar.VarStore, fvar.axes, loc)
283
+ records = mvar.ValueRecord
284
+ for rec in records:
285
+ mvarTag = rec.ValueTag
286
+ if mvarTag not in MVAR_ENTRIES:
287
+ continue
288
+ tableTag, itemName = MVAR_ENTRIES[mvarTag]
289
+ delta = otRound(varStoreInstancer[rec.VarIdx])
290
+ if not delta:
291
+ continue
292
+ setattr(
293
+ varfont[tableTag],
294
+ itemName,
295
+ getattr(varfont[tableTag], itemName) + delta,
296
+ )
297
+
298
+ log.info("Mutating FeatureVariations")
299
+ for tableTag in "GSUB", "GPOS":
300
+ if not tableTag in varfont:
301
+ continue
302
+ table = varfont[tableTag].table
303
+ if not getattr(table, "FeatureVariations", None):
304
+ continue
305
+ variations = table.FeatureVariations
306
+ for record in variations.FeatureVariationRecord:
307
+ applies = True
308
+ for condition in record.ConditionSet.ConditionTable:
309
+ if condition.Format == 1:
310
+ axisIdx = condition.AxisIndex
311
+ axisTag = fvar.axes[axisIdx].axisTag
312
+ Min = condition.FilterRangeMinValue
313
+ Max = condition.FilterRangeMaxValue
314
+ v = loc[axisTag]
315
+ if not (Min <= v <= Max):
316
+ applies = False
317
+ else:
318
+ applies = False
319
+ if not applies:
320
+ break
321
+
322
+ if applies:
323
+ assert record.FeatureTableSubstitution.Version == 0x00010000
324
+ for rec in record.FeatureTableSubstitution.SubstitutionRecord:
325
+ table.FeatureList.FeatureRecord[rec.FeatureIndex].Feature = (
326
+ rec.Feature
327
+ )
328
+ break
329
+ del table.FeatureVariations
330
+
331
+ if "GDEF" in varfont and varfont["GDEF"].table.Version >= 0x00010003:
332
+ log.info("Mutating GDEF/GPOS/GSUB tables")
333
+ gdef = varfont["GDEF"].table
334
+ instancer = VarStoreInstancer(gdef.VarStore, fvar.axes, loc)
335
+
336
+ merger = MutatorMerger(varfont, instancer)
337
+ merger.mergeTables(varfont, [varfont], ["GDEF", "GPOS"])
338
+
339
+ # Downgrade GDEF.
340
+ del gdef.VarStore
341
+ gdef.Version = 0x00010002
342
+ if gdef.MarkGlyphSetsDef is None:
343
+ del gdef.MarkGlyphSetsDef
344
+ gdef.Version = 0x00010000
345
+
346
+ if not (
347
+ gdef.LigCaretList
348
+ or gdef.MarkAttachClassDef
349
+ or gdef.GlyphClassDef
350
+ or gdef.AttachList
351
+ or (gdef.Version >= 0x00010002 and gdef.MarkGlyphSetsDef)
352
+ ):
353
+ del varfont["GDEF"]
354
+
355
+ addidef = False
356
+ if glyf:
357
+ for glyph in glyf.glyphs.values():
358
+ if hasattr(glyph, "program"):
359
+ instructions = glyph.program.getAssembly()
360
+ # If GETVARIATION opcode is used in bytecode of any glyph add IDEF
361
+ addidef = any(op.startswith("GETVARIATION") for op in instructions)
362
+ if addidef:
363
+ break
364
+ if overlap:
365
+ for glyph_name in glyf.keys():
366
+ glyph = glyf[glyph_name]
367
+ # Set OVERLAP_COMPOUND bit for compound glyphs
368
+ if glyph.isComposite():
369
+ glyph.components[0].flags |= OVERLAP_COMPOUND
370
+ # Set OVERLAP_SIMPLE bit for simple glyphs
371
+ elif glyph.numberOfContours > 0:
372
+ glyph.flags[0] |= flagOverlapSimple
373
+ if addidef:
374
+ log.info("Adding IDEF to fpgm table for GETVARIATION opcode")
375
+ asm = []
376
+ if "fpgm" in varfont:
377
+ fpgm = varfont["fpgm"]
378
+ asm = fpgm.program.getAssembly()
379
+ else:
380
+ fpgm = newTable("fpgm")
381
+ fpgm.program = ttProgram.Program()
382
+ varfont["fpgm"] = fpgm
383
+ asm.append("PUSHB[000] 145")
384
+ asm.append("IDEF[ ]")
385
+ args = [str(len(loc))]
386
+ for a in fvar.axes:
387
+ args.append(str(floatToFixed(loc[a.axisTag], 14)))
388
+ asm.append("NPUSHW[ ] " + " ".join(args))
389
+ asm.append("ENDF[ ]")
390
+ fpgm.program.fromAssembly(asm)
391
+
392
+ # Change maxp attributes as IDEF is added
393
+ if "maxp" in varfont:
394
+ maxp = varfont["maxp"]
395
+ setattr(
396
+ maxp, "maxInstructionDefs", 1 + getattr(maxp, "maxInstructionDefs", 0)
397
+ )
398
+ setattr(
399
+ maxp,
400
+ "maxStackElements",
401
+ max(len(loc), getattr(maxp, "maxStackElements", 0)),
402
+ )
403
+
404
+ if "name" in varfont:
405
+ log.info("Pruning name table")
406
+ exclude = {a.axisNameID for a in fvar.axes}
407
+ for i in fvar.instances:
408
+ exclude.add(i.subfamilyNameID)
409
+ exclude.add(i.postscriptNameID)
410
+ if "ltag" in varfont:
411
+ # Drop the whole 'ltag' table if all its language tags are referenced by
412
+ # name records to be pruned.
413
+ # TODO: prune unused ltag tags and re-enumerate langIDs accordingly
414
+ excludedUnicodeLangIDs = [
415
+ n.langID
416
+ for n in varfont["name"].names
417
+ if n.nameID in exclude and n.platformID == 0 and n.langID != 0xFFFF
418
+ ]
419
+ if set(excludedUnicodeLangIDs) == set(range(len((varfont["ltag"].tags)))):
420
+ del varfont["ltag"]
421
+ varfont["name"].names[:] = [
422
+ n
423
+ for n in varfont["name"].names
424
+ if n.nameID < 256 or n.nameID not in exclude
425
+ ]
426
+
427
+ if "wght" in location and "OS/2" in varfont:
428
+ varfont["OS/2"].usWeightClass = otRound(max(1, min(location["wght"], 1000)))
429
+ if "wdth" in location:
430
+ wdth = location["wdth"]
431
+ for percent, widthClass in sorted(OS2_WIDTH_CLASS_VALUES.items()):
432
+ if wdth < percent:
433
+ varfont["OS/2"].usWidthClass = widthClass
434
+ break
435
+ else:
436
+ varfont["OS/2"].usWidthClass = 9
437
+ if "slnt" in location and "post" in varfont:
438
+ varfont["post"].italicAngle = max(-90, min(location["slnt"], 90))
439
+
440
+ log.info("Removing variable tables")
441
+ for tag in ("avar", "cvar", "fvar", "gvar", "HVAR", "MVAR", "VVAR", "STAT"):
442
+ if tag in varfont:
443
+ del varfont[tag]
444
+
445
+ return varfont
446
+
447
+
448
+ def main(args=None):
449
+ """Instantiate a variation font"""
450
+ from fontTools import configLogger
451
+ import argparse
452
+
453
+ parser = argparse.ArgumentParser(
454
+ "fonttools varLib.mutator", description="Instantiate a variable font"
455
+ )
456
+ parser.add_argument("input", metavar="INPUT.ttf", help="Input variable TTF file.")
457
+ parser.add_argument(
458
+ "locargs",
459
+ metavar="AXIS=LOC",
460
+ nargs="*",
461
+ help="List of space separated locations. A location consist in "
462
+ "the name of a variation axis, followed by '=' and a number. E.g.: "
463
+ " wght=700 wdth=80. The default is the location of the base master.",
464
+ )
465
+ parser.add_argument(
466
+ "-o",
467
+ "--output",
468
+ metavar="OUTPUT.ttf",
469
+ default=None,
470
+ help="Output instance TTF file (default: INPUT-instance.ttf).",
471
+ )
472
+ parser.add_argument(
473
+ "--no-recalc-timestamp",
474
+ dest="recalc_timestamp",
475
+ action="store_false",
476
+ help="Don't set the output font's timestamp to the current time.",
477
+ )
478
+ logging_group = parser.add_mutually_exclusive_group(required=False)
479
+ logging_group.add_argument(
480
+ "-v", "--verbose", action="store_true", help="Run more verbosely."
481
+ )
482
+ logging_group.add_argument(
483
+ "-q", "--quiet", action="store_true", help="Turn verbosity off."
484
+ )
485
+ parser.add_argument(
486
+ "--no-overlap",
487
+ dest="overlap",
488
+ action="store_false",
489
+ help="Don't set OVERLAP_SIMPLE/OVERLAP_COMPOUND glyf flags.",
490
+ )
491
+ options = parser.parse_args(args)
492
+
493
+ varfilename = options.input
494
+ outfile = (
495
+ os.path.splitext(varfilename)[0] + "-instance.ttf"
496
+ if not options.output
497
+ else options.output
498
+ )
499
+ configLogger(
500
+ level=("DEBUG" if options.verbose else "ERROR" if options.quiet else "INFO")
501
+ )
502
+
503
+ loc = {}
504
+ for arg in options.locargs:
505
+ try:
506
+ tag, val = arg.split("=")
507
+ assert len(tag) <= 4
508
+ loc[tag.ljust(4)] = float(val)
509
+ except (ValueError, AssertionError):
510
+ parser.error("invalid location argument format: %r" % arg)
511
+ log.info("Location: %s", loc)
512
+
513
+ log.info("Loading variable font")
514
+ varfont = TTFont(varfilename, recalcTimestamp=options.recalc_timestamp)
515
+
516
+ instantiateVariableFont(varfont, loc, inplace=True, overlap=options.overlap)
517
+
518
+ log.info("Saving instance font %s", outfile)
519
+ varfont.save(outfile)
520
+
521
+
522
+ if __name__ == "__main__":
523
+ import sys
524
+
525
+ if len(sys.argv) > 1:
526
+ sys.exit(main())
527
+ import doctest
528
+
529
+ sys.exit(doctest.testmod().failed)
@@ -0,0 +1,40 @@
1
+ MVAR_ENTRIES = {
2
+ "hasc": ("OS/2", "sTypoAscender"), # horizontal ascender
3
+ "hdsc": ("OS/2", "sTypoDescender"), # horizontal descender
4
+ "hlgp": ("OS/2", "sTypoLineGap"), # horizontal line gap
5
+ "hcla": ("OS/2", "usWinAscent"), # horizontal clipping ascent
6
+ "hcld": ("OS/2", "usWinDescent"), # horizontal clipping descent
7
+ "vasc": ("vhea", "ascent"), # vertical ascender
8
+ "vdsc": ("vhea", "descent"), # vertical descender
9
+ "vlgp": ("vhea", "lineGap"), # vertical line gap
10
+ "hcrs": ("hhea", "caretSlopeRise"), # horizontal caret rise
11
+ "hcrn": ("hhea", "caretSlopeRun"), # horizontal caret run
12
+ "hcof": ("hhea", "caretOffset"), # horizontal caret offset
13
+ "vcrs": ("vhea", "caretSlopeRise"), # vertical caret rise
14
+ "vcrn": ("vhea", "caretSlopeRun"), # vertical caret run
15
+ "vcof": ("vhea", "caretOffset"), # vertical caret offset
16
+ "xhgt": ("OS/2", "sxHeight"), # x height
17
+ "cpht": ("OS/2", "sCapHeight"), # cap height
18
+ "sbxs": ("OS/2", "ySubscriptXSize"), # subscript em x size
19
+ "sbys": ("OS/2", "ySubscriptYSize"), # subscript em y size
20
+ "sbxo": ("OS/2", "ySubscriptXOffset"), # subscript em x offset
21
+ "sbyo": ("OS/2", "ySubscriptYOffset"), # subscript em y offset
22
+ "spxs": ("OS/2", "ySuperscriptXSize"), # superscript em x size
23
+ "spys": ("OS/2", "ySuperscriptYSize"), # superscript em y size
24
+ "spxo": ("OS/2", "ySuperscriptXOffset"), # superscript em x offset
25
+ "spyo": ("OS/2", "ySuperscriptYOffset"), # superscript em y offset
26
+ "strs": ("OS/2", "yStrikeoutSize"), # strikeout size
27
+ "stro": ("OS/2", "yStrikeoutPosition"), # strikeout offset
28
+ "unds": ("post", "underlineThickness"), # underline size
29
+ "undo": ("post", "underlinePosition"), # underline offset
30
+ #'gsp0': ('gasp', 'gaspRange[0].rangeMaxPPEM'), # gaspRange[0]
31
+ #'gsp1': ('gasp', 'gaspRange[1].rangeMaxPPEM'), # gaspRange[1]
32
+ #'gsp2': ('gasp', 'gaspRange[2].rangeMaxPPEM'), # gaspRange[2]
33
+ #'gsp3': ('gasp', 'gaspRange[3].rangeMaxPPEM'), # gaspRange[3]
34
+ #'gsp4': ('gasp', 'gaspRange[4].rangeMaxPPEM'), # gaspRange[4]
35
+ #'gsp5': ('gasp', 'gaspRange[5].rangeMaxPPEM'), # gaspRange[5]
36
+ #'gsp6': ('gasp', 'gaspRange[6].rangeMaxPPEM'), # gaspRange[6]
37
+ #'gsp7': ('gasp', 'gaspRange[7].rangeMaxPPEM'), # gaspRange[7]
38
+ #'gsp8': ('gasp', 'gaspRange[8].rangeMaxPPEM'), # gaspRange[8]
39
+ #'gsp9': ('gasp', 'gaspRange[9].rangeMaxPPEM'), # gaspRange[9]
40
+ }