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,260 @@
1
+ """Compute name information for a given location in user-space coordinates
2
+ using STAT data. This can be used to fill-in automatically the names of an
3
+ instance:
4
+
5
+ .. code:: python
6
+
7
+ instance = doc.instances[0]
8
+ names = getStatNames(doc, instance.getFullUserLocation(doc))
9
+ print(names.styleNames)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from dataclasses import dataclass
15
+ from typing import Dict, Literal, Optional, Tuple, Union
16
+ import logging
17
+
18
+ from fontTools.designspaceLib import (
19
+ AxisDescriptor,
20
+ AxisLabelDescriptor,
21
+ DesignSpaceDocument,
22
+ DiscreteAxisDescriptor,
23
+ SimpleLocationDict,
24
+ SourceDescriptor,
25
+ )
26
+
27
+ LOGGER = logging.getLogger(__name__)
28
+
29
+ RibbiStyleName = Union[
30
+ Literal["regular"],
31
+ Literal["bold"],
32
+ Literal["italic"],
33
+ Literal["bold italic"],
34
+ ]
35
+
36
+ BOLD_ITALIC_TO_RIBBI_STYLE = {
37
+ (False, False): "regular",
38
+ (False, True): "italic",
39
+ (True, False): "bold",
40
+ (True, True): "bold italic",
41
+ }
42
+
43
+
44
+ @dataclass
45
+ class StatNames:
46
+ """Name data generated from the STAT table information."""
47
+
48
+ familyNames: Dict[str, str]
49
+ styleNames: Dict[str, str]
50
+ postScriptFontName: Optional[str]
51
+ styleMapFamilyNames: Dict[str, str]
52
+ styleMapStyleName: Optional[RibbiStyleName]
53
+
54
+
55
+ def getStatNames(
56
+ doc: DesignSpaceDocument, userLocation: SimpleLocationDict
57
+ ) -> StatNames:
58
+ """Compute the family, style, PostScript names of the given ``userLocation``
59
+ using the document's STAT information.
60
+
61
+ Also computes localizations.
62
+
63
+ If not enough STAT data is available for a given name, either its dict of
64
+ localized names will be empty (family and style names), or the name will be
65
+ None (PostScript name).
66
+
67
+ Note: this method does not consider info attached to the instance, like
68
+ family name. The user needs to override all names on an instance that STAT
69
+ information would compute differently than desired.
70
+
71
+ .. versionadded:: 5.0
72
+ """
73
+ familyNames: Dict[str, str] = {}
74
+ defaultSource: Optional[SourceDescriptor] = doc.findDefault()
75
+ if defaultSource is None:
76
+ LOGGER.warning("Cannot determine default source to look up family name.")
77
+ elif defaultSource.familyName is None:
78
+ LOGGER.warning(
79
+ "Cannot look up family name, assign the 'familyname' attribute to the default source."
80
+ )
81
+ else:
82
+ familyNames = {
83
+ "en": defaultSource.familyName,
84
+ **defaultSource.localisedFamilyName,
85
+ }
86
+
87
+ styleNames: Dict[str, str] = {}
88
+ # If a free-standing label matches the location, use it for name generation.
89
+ label = doc.labelForUserLocation(userLocation)
90
+ if label is not None:
91
+ styleNames = {"en": label.name, **label.labelNames}
92
+ # Otherwise, scour the axis labels for matches.
93
+ else:
94
+ # Gather all languages in which at least one translation is provided
95
+ # Then build names for all these languages, but fallback to English
96
+ # whenever a translation is missing.
97
+ labels = _getAxisLabelsForUserLocation(doc.axes, userLocation)
98
+ if labels:
99
+ languages = set(
100
+ language for label in labels for language in label.labelNames
101
+ )
102
+ languages.add("en")
103
+ for language in languages:
104
+ styleName = " ".join(
105
+ label.labelNames.get(language, label.defaultName)
106
+ for label in labels
107
+ if not label.elidable
108
+ )
109
+ if not styleName and doc.elidedFallbackName is not None:
110
+ styleName = doc.elidedFallbackName
111
+ styleNames[language] = styleName
112
+
113
+ if "en" not in familyNames or "en" not in styleNames:
114
+ # Not enough information to compute PS names of styleMap names
115
+ return StatNames(
116
+ familyNames=familyNames,
117
+ styleNames=styleNames,
118
+ postScriptFontName=None,
119
+ styleMapFamilyNames={},
120
+ styleMapStyleName=None,
121
+ )
122
+
123
+ postScriptFontName = f"{familyNames['en']}-{styleNames['en']}".replace(" ", "")
124
+
125
+ styleMapStyleName, regularUserLocation = _getRibbiStyle(doc, userLocation)
126
+
127
+ styleNamesForStyleMap = styleNames
128
+ if regularUserLocation != userLocation:
129
+ regularStatNames = getStatNames(doc, regularUserLocation)
130
+ styleNamesForStyleMap = regularStatNames.styleNames
131
+
132
+ styleMapFamilyNames = {}
133
+ for language in set(familyNames).union(styleNames.keys()):
134
+ familyName = familyNames.get(language, familyNames["en"])
135
+ styleName = styleNamesForStyleMap.get(language, styleNamesForStyleMap["en"])
136
+ styleMapFamilyNames[language] = (familyName + " " + styleName).strip()
137
+
138
+ return StatNames(
139
+ familyNames=familyNames,
140
+ styleNames=styleNames,
141
+ postScriptFontName=postScriptFontName,
142
+ styleMapFamilyNames=styleMapFamilyNames,
143
+ styleMapStyleName=styleMapStyleName,
144
+ )
145
+
146
+
147
+ def _getSortedAxisLabels(
148
+ axes: list[Union[AxisDescriptor, DiscreteAxisDescriptor]],
149
+ ) -> Dict[str, list[AxisLabelDescriptor]]:
150
+ """Returns axis labels sorted by their ordering, with unordered ones appended as
151
+ they are listed."""
152
+
153
+ # First, get the axis labels with explicit ordering...
154
+ sortedAxes = sorted(
155
+ (axis for axis in axes if axis.axisOrdering is not None),
156
+ key=lambda a: a.axisOrdering,
157
+ )
158
+ sortedLabels: Dict[str, list[AxisLabelDescriptor]] = {
159
+ axis.name: axis.axisLabels for axis in sortedAxes
160
+ }
161
+
162
+ # ... then append the others in the order they appear.
163
+ # NOTE: This relies on Python 3.7+ dict's preserved insertion order.
164
+ for axis in axes:
165
+ if axis.axisOrdering is None:
166
+ sortedLabels[axis.name] = axis.axisLabels
167
+
168
+ return sortedLabels
169
+
170
+
171
+ def _getAxisLabelsForUserLocation(
172
+ axes: list[Union[AxisDescriptor, DiscreteAxisDescriptor]],
173
+ userLocation: SimpleLocationDict,
174
+ ) -> list[AxisLabelDescriptor]:
175
+ labels: list[AxisLabelDescriptor] = []
176
+
177
+ allAxisLabels = _getSortedAxisLabels(axes)
178
+ if allAxisLabels.keys() != userLocation.keys():
179
+ LOGGER.warning(
180
+ f"Mismatch between user location '{userLocation.keys()}' and available "
181
+ f"labels for '{allAxisLabels.keys()}'."
182
+ )
183
+
184
+ for axisName, axisLabels in allAxisLabels.items():
185
+ userValue = userLocation[axisName]
186
+ label: Optional[AxisLabelDescriptor] = next(
187
+ (
188
+ l
189
+ for l in axisLabels
190
+ if l.userValue == userValue
191
+ or (
192
+ l.userMinimum is not None
193
+ and l.userMaximum is not None
194
+ and l.userMinimum <= userValue <= l.userMaximum
195
+ )
196
+ ),
197
+ None,
198
+ )
199
+ if label is None:
200
+ LOGGER.debug(
201
+ f"Document needs a label for axis '{axisName}', user value '{userValue}'."
202
+ )
203
+ else:
204
+ labels.append(label)
205
+
206
+ return labels
207
+
208
+
209
+ def _getRibbiStyle(
210
+ self: DesignSpaceDocument, userLocation: SimpleLocationDict
211
+ ) -> Tuple[RibbiStyleName, SimpleLocationDict]:
212
+ """Compute the RIBBI style name of the given user location,
213
+ return the location of the matching Regular in the RIBBI group.
214
+
215
+ .. versionadded:: 5.0
216
+ """
217
+ regularUserLocation = {}
218
+ axes_by_tag = {axis.tag: axis for axis in self.axes}
219
+
220
+ bold: bool = False
221
+ italic: bool = False
222
+
223
+ axis = axes_by_tag.get("wght")
224
+ if axis is not None:
225
+ for regular_label in axis.axisLabels:
226
+ if (
227
+ regular_label.linkedUserValue == userLocation[axis.name]
228
+ # In the "recursive" case where both the Regular has
229
+ # linkedUserValue pointing the Bold, and the Bold has
230
+ # linkedUserValue pointing to the Regular, only consider the
231
+ # first case: Regular (e.g. 400) has linkedUserValue pointing to
232
+ # Bold (e.g. 700, higher than Regular)
233
+ and regular_label.userValue < regular_label.linkedUserValue
234
+ ):
235
+ regularUserLocation[axis.name] = regular_label.userValue
236
+ bold = True
237
+ break
238
+
239
+ axis = axes_by_tag.get("ital") or axes_by_tag.get("slnt")
240
+ if axis is not None:
241
+ for upright_label in axis.axisLabels:
242
+ if (
243
+ upright_label.linkedUserValue == userLocation[axis.name]
244
+ # In the "recursive" case where both the Upright has
245
+ # linkedUserValue pointing the Italic, and the Italic has
246
+ # linkedUserValue pointing to the Upright, only consider the
247
+ # first case: Upright (e.g. ital=0, slant=0) has
248
+ # linkedUserValue pointing to Italic (e.g ital=1, slant=-12 or
249
+ # slant=12 for backwards italics, in any case higher than
250
+ # Upright in absolute value, hence the abs() below.
251
+ and abs(upright_label.userValue) < abs(upright_label.linkedUserValue)
252
+ ):
253
+ regularUserLocation[axis.name] = upright_label.userValue
254
+ italic = True
255
+ break
256
+
257
+ return BOLD_ITALIC_TO_RIBBI_STYLE[bold, italic], {
258
+ **userLocation,
259
+ **regularUserLocation,
260
+ }
@@ -0,0 +1,147 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Dict, List, Optional, Union, cast
5
+
6
+ from fontTools.designspaceLib import (
7
+ AxisDescriptor,
8
+ DesignSpaceDocument,
9
+ DesignSpaceDocumentError,
10
+ RangeAxisSubsetDescriptor,
11
+ SimpleLocationDict,
12
+ ValueAxisSubsetDescriptor,
13
+ VariableFontDescriptor,
14
+ )
15
+
16
+
17
+ def clamp(value, minimum, maximum):
18
+ return min(max(value, minimum), maximum)
19
+
20
+
21
+ @dataclass
22
+ class Range:
23
+ minimum: float
24
+ """Inclusive minimum of the range."""
25
+ maximum: float
26
+ """Inclusive maximum of the range."""
27
+ default: float = 0
28
+ """Default value"""
29
+
30
+ def __post_init__(self):
31
+ self.minimum, self.maximum = sorted((self.minimum, self.maximum))
32
+ self.default = clamp(self.default, self.minimum, self.maximum)
33
+
34
+ def __contains__(self, value: Union[float, Range]) -> bool:
35
+ if isinstance(value, Range):
36
+ return self.minimum <= value.minimum and value.maximum <= self.maximum
37
+ return self.minimum <= value <= self.maximum
38
+
39
+ def intersection(self, other: Range) -> Optional[Range]:
40
+ if self.maximum < other.minimum or self.minimum > other.maximum:
41
+ return None
42
+ else:
43
+ return Range(
44
+ max(self.minimum, other.minimum),
45
+ min(self.maximum, other.maximum),
46
+ self.default, # We don't care about the default in this use-case
47
+ )
48
+
49
+
50
+ # A region selection is either a range or a single value, as a Designspace v5
51
+ # axis-subset element only allows a single discrete value or a range for a
52
+ # variable-font element.
53
+ Region = Dict[str, Union[Range, float]]
54
+
55
+ # A conditionset is a set of named ranges.
56
+ ConditionSet = Dict[str, Range]
57
+
58
+ # A rule is a list of conditionsets where any has to be relevant for the whole rule to be relevant.
59
+ Rule = List[ConditionSet]
60
+ Rules = Dict[str, Rule]
61
+
62
+
63
+ def locationInRegion(location: SimpleLocationDict, region: Region) -> bool:
64
+ for name, value in location.items():
65
+ if name not in region:
66
+ return False
67
+ regionValue = region[name]
68
+ if isinstance(regionValue, (float, int)):
69
+ if value != regionValue:
70
+ return False
71
+ else:
72
+ if value not in regionValue:
73
+ return False
74
+ return True
75
+
76
+
77
+ def regionInRegion(region: Region, superRegion: Region) -> bool:
78
+ for name, value in region.items():
79
+ if not name in superRegion:
80
+ return False
81
+ superValue = superRegion[name]
82
+ if isinstance(superValue, (float, int)):
83
+ if value != superValue:
84
+ return False
85
+ else:
86
+ if value not in superValue:
87
+ return False
88
+ return True
89
+
90
+
91
+ def userRegionToDesignRegion(doc: DesignSpaceDocument, userRegion: Region) -> Region:
92
+ designRegion = {}
93
+ for name, value in userRegion.items():
94
+ axis = doc.getAxis(name)
95
+ if axis is None:
96
+ raise DesignSpaceDocumentError(
97
+ f"Cannot find axis named '{name}' for region."
98
+ )
99
+ if isinstance(value, (float, int)):
100
+ designRegion[name] = axis.map_forward(value)
101
+ else:
102
+ designRegion[name] = Range(
103
+ axis.map_forward(value.minimum),
104
+ axis.map_forward(value.maximum),
105
+ axis.map_forward(value.default),
106
+ )
107
+ return designRegion
108
+
109
+
110
+ def getVFUserRegion(doc: DesignSpaceDocument, vf: VariableFontDescriptor) -> Region:
111
+ vfUserRegion: Region = {}
112
+ # For each axis, 2 cases:
113
+ # - it has a range = it's an axis in the VF DS
114
+ # - it's a single location = use it to know which rules should apply in the VF
115
+ for axisSubset in vf.axisSubsets:
116
+ axis = doc.getAxis(axisSubset.name)
117
+ if axis is None:
118
+ raise DesignSpaceDocumentError(
119
+ f"Cannot find axis named '{axisSubset.name}' for variable font '{vf.name}'."
120
+ )
121
+ if hasattr(axisSubset, "userMinimum"):
122
+ # Mypy doesn't support narrowing union types via hasattr()
123
+ # TODO(Python 3.10): use TypeGuard
124
+ # https://mypy.readthedocs.io/en/stable/type_narrowing.html
125
+ axisSubset = cast(RangeAxisSubsetDescriptor, axisSubset)
126
+ if not hasattr(axis, "minimum"):
127
+ raise DesignSpaceDocumentError(
128
+ f"Cannot select a range over '{axis.name}' for variable font '{vf.name}' "
129
+ "because it's a discrete axis, use only 'userValue' instead."
130
+ )
131
+ axis = cast(AxisDescriptor, axis)
132
+ vfUserRegion[axis.name] = Range(
133
+ max(axisSubset.userMinimum, axis.minimum),
134
+ min(axisSubset.userMaximum, axis.maximum),
135
+ axisSubset.userDefault or axis.default,
136
+ )
137
+ else:
138
+ axisSubset = cast(ValueAxisSubsetDescriptor, axisSubset)
139
+ vfUserRegion[axis.name] = axisSubset.userValue
140
+ # Any axis not mentioned explicitly has a single location = default value
141
+ for axis in doc.axes:
142
+ if axis.name not in vfUserRegion:
143
+ assert isinstance(
144
+ axis.default, (int, float)
145
+ ), f"Axis '{axis.name}' has no valid default value."
146
+ vfUserRegion[axis.name] = axis.default
147
+ return vfUserRegion
@@ -0,0 +1,258 @@
1
+ MacRoman = [
2
+ "NUL",
3
+ "Eth",
4
+ "eth",
5
+ "Lslash",
6
+ "lslash",
7
+ "Scaron",
8
+ "scaron",
9
+ "Yacute",
10
+ "yacute",
11
+ "HT",
12
+ "LF",
13
+ "Thorn",
14
+ "thorn",
15
+ "CR",
16
+ "Zcaron",
17
+ "zcaron",
18
+ "DLE",
19
+ "DC1",
20
+ "DC2",
21
+ "DC3",
22
+ "DC4",
23
+ "onehalf",
24
+ "onequarter",
25
+ "onesuperior",
26
+ "threequarters",
27
+ "threesuperior",
28
+ "twosuperior",
29
+ "brokenbar",
30
+ "minus",
31
+ "multiply",
32
+ "RS",
33
+ "US",
34
+ "space",
35
+ "exclam",
36
+ "quotedbl",
37
+ "numbersign",
38
+ "dollar",
39
+ "percent",
40
+ "ampersand",
41
+ "quotesingle",
42
+ "parenleft",
43
+ "parenright",
44
+ "asterisk",
45
+ "plus",
46
+ "comma",
47
+ "hyphen",
48
+ "period",
49
+ "slash",
50
+ "zero",
51
+ "one",
52
+ "two",
53
+ "three",
54
+ "four",
55
+ "five",
56
+ "six",
57
+ "seven",
58
+ "eight",
59
+ "nine",
60
+ "colon",
61
+ "semicolon",
62
+ "less",
63
+ "equal",
64
+ "greater",
65
+ "question",
66
+ "at",
67
+ "A",
68
+ "B",
69
+ "C",
70
+ "D",
71
+ "E",
72
+ "F",
73
+ "G",
74
+ "H",
75
+ "I",
76
+ "J",
77
+ "K",
78
+ "L",
79
+ "M",
80
+ "N",
81
+ "O",
82
+ "P",
83
+ "Q",
84
+ "R",
85
+ "S",
86
+ "T",
87
+ "U",
88
+ "V",
89
+ "W",
90
+ "X",
91
+ "Y",
92
+ "Z",
93
+ "bracketleft",
94
+ "backslash",
95
+ "bracketright",
96
+ "asciicircum",
97
+ "underscore",
98
+ "grave",
99
+ "a",
100
+ "b",
101
+ "c",
102
+ "d",
103
+ "e",
104
+ "f",
105
+ "g",
106
+ "h",
107
+ "i",
108
+ "j",
109
+ "k",
110
+ "l",
111
+ "m",
112
+ "n",
113
+ "o",
114
+ "p",
115
+ "q",
116
+ "r",
117
+ "s",
118
+ "t",
119
+ "u",
120
+ "v",
121
+ "w",
122
+ "x",
123
+ "y",
124
+ "z",
125
+ "braceleft",
126
+ "bar",
127
+ "braceright",
128
+ "asciitilde",
129
+ "DEL",
130
+ "Adieresis",
131
+ "Aring",
132
+ "Ccedilla",
133
+ "Eacute",
134
+ "Ntilde",
135
+ "Odieresis",
136
+ "Udieresis",
137
+ "aacute",
138
+ "agrave",
139
+ "acircumflex",
140
+ "adieresis",
141
+ "atilde",
142
+ "aring",
143
+ "ccedilla",
144
+ "eacute",
145
+ "egrave",
146
+ "ecircumflex",
147
+ "edieresis",
148
+ "iacute",
149
+ "igrave",
150
+ "icircumflex",
151
+ "idieresis",
152
+ "ntilde",
153
+ "oacute",
154
+ "ograve",
155
+ "ocircumflex",
156
+ "odieresis",
157
+ "otilde",
158
+ "uacute",
159
+ "ugrave",
160
+ "ucircumflex",
161
+ "udieresis",
162
+ "dagger",
163
+ "degree",
164
+ "cent",
165
+ "sterling",
166
+ "section",
167
+ "bullet",
168
+ "paragraph",
169
+ "germandbls",
170
+ "registered",
171
+ "copyright",
172
+ "trademark",
173
+ "acute",
174
+ "dieresis",
175
+ "notequal",
176
+ "AE",
177
+ "Oslash",
178
+ "infinity",
179
+ "plusminus",
180
+ "lessequal",
181
+ "greaterequal",
182
+ "yen",
183
+ "mu",
184
+ "partialdiff",
185
+ "summation",
186
+ "product",
187
+ "pi",
188
+ "integral",
189
+ "ordfeminine",
190
+ "ordmasculine",
191
+ "Omega",
192
+ "ae",
193
+ "oslash",
194
+ "questiondown",
195
+ "exclamdown",
196
+ "logicalnot",
197
+ "radical",
198
+ "florin",
199
+ "approxequal",
200
+ "Delta",
201
+ "guillemotleft",
202
+ "guillemotright",
203
+ "ellipsis",
204
+ "nbspace",
205
+ "Agrave",
206
+ "Atilde",
207
+ "Otilde",
208
+ "OE",
209
+ "oe",
210
+ "endash",
211
+ "emdash",
212
+ "quotedblleft",
213
+ "quotedblright",
214
+ "quoteleft",
215
+ "quoteright",
216
+ "divide",
217
+ "lozenge",
218
+ "ydieresis",
219
+ "Ydieresis",
220
+ "fraction",
221
+ "currency",
222
+ "guilsinglleft",
223
+ "guilsinglright",
224
+ "fi",
225
+ "fl",
226
+ "daggerdbl",
227
+ "periodcentered",
228
+ "quotesinglbase",
229
+ "quotedblbase",
230
+ "perthousand",
231
+ "Acircumflex",
232
+ "Ecircumflex",
233
+ "Aacute",
234
+ "Edieresis",
235
+ "Egrave",
236
+ "Iacute",
237
+ "Icircumflex",
238
+ "Idieresis",
239
+ "Igrave",
240
+ "Oacute",
241
+ "Ocircumflex",
242
+ "apple",
243
+ "Ograve",
244
+ "Uacute",
245
+ "Ucircumflex",
246
+ "Ugrave",
247
+ "dotlessi",
248
+ "circumflex",
249
+ "tilde",
250
+ "macron",
251
+ "breve",
252
+ "dotaccent",
253
+ "ring",
254
+ "cedilla",
255
+ "hungarumlaut",
256
+ "ogonek",
257
+ "caron",
258
+ ]