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,718 @@
1
+ from fontTools.misc import sstruct
2
+ from . import DefaultTable
3
+ from fontTools.misc.textTools import bytesjoin, safeEval
4
+ from .BitmapGlyphMetrics import (
5
+ BigGlyphMetrics,
6
+ bigGlyphMetricsFormat,
7
+ SmallGlyphMetrics,
8
+ smallGlyphMetricsFormat,
9
+ )
10
+ import struct
11
+ import itertools
12
+ from collections import deque
13
+ import logging
14
+
15
+
16
+ log = logging.getLogger(__name__)
17
+
18
+ eblcHeaderFormat = """
19
+ > # big endian
20
+ version: 16.16F
21
+ numSizes: I
22
+ """
23
+ # The table format string is split to handle sbitLineMetrics simply.
24
+ bitmapSizeTableFormatPart1 = """
25
+ > # big endian
26
+ indexSubTableArrayOffset: I
27
+ indexTablesSize: I
28
+ numberOfIndexSubTables: I
29
+ colorRef: I
30
+ """
31
+ # The compound type for hori and vert.
32
+ sbitLineMetricsFormat = """
33
+ > # big endian
34
+ ascender: b
35
+ descender: b
36
+ widthMax: B
37
+ caretSlopeNumerator: b
38
+ caretSlopeDenominator: b
39
+ caretOffset: b
40
+ minOriginSB: b
41
+ minAdvanceSB: b
42
+ maxBeforeBL: b
43
+ minAfterBL: b
44
+ pad1: b
45
+ pad2: b
46
+ """
47
+ # hori and vert go between the two parts.
48
+ bitmapSizeTableFormatPart2 = """
49
+ > # big endian
50
+ startGlyphIndex: H
51
+ endGlyphIndex: H
52
+ ppemX: B
53
+ ppemY: B
54
+ bitDepth: B
55
+ flags: b
56
+ """
57
+
58
+ indexSubTableArrayFormat = ">HHL"
59
+ indexSubTableArraySize = struct.calcsize(indexSubTableArrayFormat)
60
+
61
+ indexSubHeaderFormat = ">HHL"
62
+ indexSubHeaderSize = struct.calcsize(indexSubHeaderFormat)
63
+
64
+ codeOffsetPairFormat = ">HH"
65
+ codeOffsetPairSize = struct.calcsize(codeOffsetPairFormat)
66
+
67
+
68
+ class table_E_B_L_C_(DefaultTable.DefaultTable):
69
+ """Embedded Bitmap Location table
70
+
71
+ The ``EBLC`` table contains the locations of monochrome or grayscale
72
+ bitmaps for glyphs. It must be used in concert with the ``EBDT`` table.
73
+
74
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/eblc
75
+ """
76
+
77
+ dependencies = ["EBDT"]
78
+
79
+ # This method can be overridden in subclasses to support new formats
80
+ # without changing the other implementation. Also can be used as a
81
+ # convenience method for coverting a font file to an alternative format.
82
+ def getIndexFormatClass(self, indexFormat):
83
+ return eblc_sub_table_classes[indexFormat]
84
+
85
+ def decompile(self, data, ttFont):
86
+ # Save the original data because offsets are from the start of the table.
87
+ origData = data
88
+ i = 0
89
+
90
+ dummy = sstruct.unpack(eblcHeaderFormat, data[:8], self)
91
+ i += 8
92
+
93
+ self.strikes = []
94
+ for curStrikeIndex in range(self.numSizes):
95
+ curStrike = Strike()
96
+ self.strikes.append(curStrike)
97
+ curTable = curStrike.bitmapSizeTable
98
+ dummy = sstruct.unpack2(
99
+ bitmapSizeTableFormatPart1, data[i : i + 16], curTable
100
+ )
101
+ i += 16
102
+ for metric in ("hori", "vert"):
103
+ metricObj = SbitLineMetrics()
104
+ vars(curTable)[metric] = metricObj
105
+ dummy = sstruct.unpack2(
106
+ sbitLineMetricsFormat, data[i : i + 12], metricObj
107
+ )
108
+ i += 12
109
+ dummy = sstruct.unpack(
110
+ bitmapSizeTableFormatPart2, data[i : i + 8], curTable
111
+ )
112
+ i += 8
113
+
114
+ for curStrike in self.strikes:
115
+ curTable = curStrike.bitmapSizeTable
116
+ for subtableIndex in range(curTable.numberOfIndexSubTables):
117
+ i = (
118
+ curTable.indexSubTableArrayOffset
119
+ + subtableIndex * indexSubTableArraySize
120
+ )
121
+
122
+ tup = struct.unpack(
123
+ indexSubTableArrayFormat, data[i : i + indexSubTableArraySize]
124
+ )
125
+ (firstGlyphIndex, lastGlyphIndex, additionalOffsetToIndexSubtable) = tup
126
+ i = curTable.indexSubTableArrayOffset + additionalOffsetToIndexSubtable
127
+
128
+ tup = struct.unpack(
129
+ indexSubHeaderFormat, data[i : i + indexSubHeaderSize]
130
+ )
131
+ (indexFormat, imageFormat, imageDataOffset) = tup
132
+
133
+ indexFormatClass = self.getIndexFormatClass(indexFormat)
134
+ indexSubTable = indexFormatClass(data[i + indexSubHeaderSize :], ttFont)
135
+ indexSubTable.firstGlyphIndex = firstGlyphIndex
136
+ indexSubTable.lastGlyphIndex = lastGlyphIndex
137
+ indexSubTable.additionalOffsetToIndexSubtable = (
138
+ additionalOffsetToIndexSubtable
139
+ )
140
+ indexSubTable.indexFormat = indexFormat
141
+ indexSubTable.imageFormat = imageFormat
142
+ indexSubTable.imageDataOffset = imageDataOffset
143
+ indexSubTable.decompile() # https://github.com/fonttools/fonttools/issues/317
144
+ curStrike.indexSubTables.append(indexSubTable)
145
+
146
+ def compile(self, ttFont):
147
+ dataList = []
148
+ self.numSizes = len(self.strikes)
149
+ dataList.append(sstruct.pack(eblcHeaderFormat, self))
150
+
151
+ # Data size of the header + bitmapSizeTable needs to be calculated
152
+ # in order to form offsets. This value will hold the size of the data
153
+ # in dataList after all the data is consolidated in dataList.
154
+ dataSize = len(dataList[0])
155
+
156
+ # The table will be structured in the following order:
157
+ # (0) header
158
+ # (1) Each bitmapSizeTable [1 ... self.numSizes]
159
+ # (2) Alternate between indexSubTableArray and indexSubTable
160
+ # for each bitmapSizeTable present.
161
+ #
162
+ # The issue is maintaining the proper offsets when table information
163
+ # gets moved around. All offsets and size information must be recalculated
164
+ # when building the table to allow editing within ttLib and also allow easy
165
+ # import/export to and from XML. All of this offset information is lost
166
+ # when exporting to XML so everything must be calculated fresh so importing
167
+ # from XML will work cleanly. Only byte offset and size information is
168
+ # calculated fresh. Count information like numberOfIndexSubTables is
169
+ # checked through assertions. If the information in this table was not
170
+ # touched or was changed properly then these types of values should match.
171
+ #
172
+ # The table will be rebuilt the following way:
173
+ # (0) Precompute the size of all the bitmapSizeTables. This is needed to
174
+ # compute the offsets properly.
175
+ # (1) For each bitmapSizeTable compute the indexSubTable and
176
+ # indexSubTableArray pair. The indexSubTable must be computed first
177
+ # so that the offset information in indexSubTableArray can be
178
+ # calculated. Update the data size after each pairing.
179
+ # (2) Build each bitmapSizeTable.
180
+ # (3) Consolidate all the data into the main dataList in the correct order.
181
+
182
+ for _ in self.strikes:
183
+ dataSize += sstruct.calcsize(bitmapSizeTableFormatPart1)
184
+ dataSize += len(("hori", "vert")) * sstruct.calcsize(sbitLineMetricsFormat)
185
+ dataSize += sstruct.calcsize(bitmapSizeTableFormatPart2)
186
+
187
+ indexSubTablePairDataList = []
188
+ for curStrike in self.strikes:
189
+ curTable = curStrike.bitmapSizeTable
190
+ curTable.numberOfIndexSubTables = len(curStrike.indexSubTables)
191
+ curTable.indexSubTableArrayOffset = dataSize
192
+
193
+ # Precompute the size of the indexSubTableArray. This information
194
+ # is important for correctly calculating the new value for
195
+ # additionalOffsetToIndexSubtable.
196
+ sizeOfSubTableArray = (
197
+ curTable.numberOfIndexSubTables * indexSubTableArraySize
198
+ )
199
+ lowerBound = dataSize
200
+ dataSize += sizeOfSubTableArray
201
+ upperBound = dataSize
202
+
203
+ indexSubTableDataList = []
204
+ for indexSubTable in curStrike.indexSubTables:
205
+ indexSubTable.additionalOffsetToIndexSubtable = (
206
+ dataSize - curTable.indexSubTableArrayOffset
207
+ )
208
+ glyphIds = list(map(ttFont.getGlyphID, indexSubTable.names))
209
+ indexSubTable.firstGlyphIndex = min(glyphIds)
210
+ indexSubTable.lastGlyphIndex = max(glyphIds)
211
+ data = indexSubTable.compile(ttFont)
212
+ indexSubTableDataList.append(data)
213
+ dataSize += len(data)
214
+ curTable.startGlyphIndex = min(
215
+ ist.firstGlyphIndex for ist in curStrike.indexSubTables
216
+ )
217
+ curTable.endGlyphIndex = max(
218
+ ist.lastGlyphIndex for ist in curStrike.indexSubTables
219
+ )
220
+
221
+ for i in curStrike.indexSubTables:
222
+ data = struct.pack(
223
+ indexSubHeaderFormat,
224
+ i.firstGlyphIndex,
225
+ i.lastGlyphIndex,
226
+ i.additionalOffsetToIndexSubtable,
227
+ )
228
+ indexSubTablePairDataList.append(data)
229
+ indexSubTablePairDataList.extend(indexSubTableDataList)
230
+ curTable.indexTablesSize = dataSize - curTable.indexSubTableArrayOffset
231
+
232
+ for curStrike in self.strikes:
233
+ curTable = curStrike.bitmapSizeTable
234
+ data = sstruct.pack(bitmapSizeTableFormatPart1, curTable)
235
+ dataList.append(data)
236
+ for metric in ("hori", "vert"):
237
+ metricObj = vars(curTable)[metric]
238
+ data = sstruct.pack(sbitLineMetricsFormat, metricObj)
239
+ dataList.append(data)
240
+ data = sstruct.pack(bitmapSizeTableFormatPart2, curTable)
241
+ dataList.append(data)
242
+ dataList.extend(indexSubTablePairDataList)
243
+
244
+ return bytesjoin(dataList)
245
+
246
+ def toXML(self, writer, ttFont):
247
+ writer.simpletag("header", [("version", self.version)])
248
+ writer.newline()
249
+ for curIndex, curStrike in enumerate(self.strikes):
250
+ curStrike.toXML(curIndex, writer, ttFont)
251
+
252
+ def fromXML(self, name, attrs, content, ttFont):
253
+ if name == "header":
254
+ self.version = safeEval(attrs["version"])
255
+ elif name == "strike":
256
+ if not hasattr(self, "strikes"):
257
+ self.strikes = []
258
+ strikeIndex = safeEval(attrs["index"])
259
+ curStrike = Strike()
260
+ curStrike.fromXML(name, attrs, content, ttFont, self)
261
+
262
+ # Grow the strike array to the appropriate size. The XML format
263
+ # allows for the strike index value to be out of order.
264
+ if strikeIndex >= len(self.strikes):
265
+ self.strikes += [None] * (strikeIndex + 1 - len(self.strikes))
266
+ assert self.strikes[strikeIndex] is None, "Duplicate strike EBLC indices."
267
+ self.strikes[strikeIndex] = curStrike
268
+
269
+
270
+ class Strike(object):
271
+ def __init__(self):
272
+ self.bitmapSizeTable = BitmapSizeTable()
273
+ self.indexSubTables = []
274
+
275
+ def toXML(self, strikeIndex, writer, ttFont):
276
+ writer.begintag("strike", [("index", strikeIndex)])
277
+ writer.newline()
278
+ self.bitmapSizeTable.toXML(writer, ttFont)
279
+ writer.comment(
280
+ "GlyphIds are written but not read. The firstGlyphIndex and\nlastGlyphIndex values will be recalculated by the compiler."
281
+ )
282
+ writer.newline()
283
+ for indexSubTable in self.indexSubTables:
284
+ indexSubTable.toXML(writer, ttFont)
285
+ writer.endtag("strike")
286
+ writer.newline()
287
+
288
+ def fromXML(self, name, attrs, content, ttFont, locator):
289
+ for element in content:
290
+ if not isinstance(element, tuple):
291
+ continue
292
+ name, attrs, content = element
293
+ if name == "bitmapSizeTable":
294
+ self.bitmapSizeTable.fromXML(name, attrs, content, ttFont)
295
+ elif name.startswith(_indexSubTableSubclassPrefix):
296
+ indexFormat = safeEval(name[len(_indexSubTableSubclassPrefix) :])
297
+ indexFormatClass = locator.getIndexFormatClass(indexFormat)
298
+ indexSubTable = indexFormatClass(None, None)
299
+ indexSubTable.indexFormat = indexFormat
300
+ indexSubTable.fromXML(name, attrs, content, ttFont)
301
+ self.indexSubTables.append(indexSubTable)
302
+
303
+
304
+ class BitmapSizeTable(object):
305
+ # Returns all the simple metric names that bitmap size table
306
+ # cares about in terms of XML creation.
307
+ def _getXMLMetricNames(self):
308
+ dataNames = sstruct.getformat(bitmapSizeTableFormatPart1)[1]
309
+ dataNames = {**dataNames, **sstruct.getformat(bitmapSizeTableFormatPart2)[1]}
310
+ # Skip the first 3 data names because they are byte offsets and counts.
311
+ return list(dataNames.keys())[3:]
312
+
313
+ def toXML(self, writer, ttFont):
314
+ writer.begintag("bitmapSizeTable")
315
+ writer.newline()
316
+ for metric in ("hori", "vert"):
317
+ getattr(self, metric).toXML(metric, writer, ttFont)
318
+ for metricName in self._getXMLMetricNames():
319
+ writer.simpletag(metricName, value=getattr(self, metricName))
320
+ writer.newline()
321
+ writer.endtag("bitmapSizeTable")
322
+ writer.newline()
323
+
324
+ def fromXML(self, name, attrs, content, ttFont):
325
+ # Create a lookup for all the simple names that make sense to
326
+ # bitmap size table. Only read the information from these names.
327
+ dataNames = set(self._getXMLMetricNames())
328
+ for element in content:
329
+ if not isinstance(element, tuple):
330
+ continue
331
+ name, attrs, content = element
332
+ if name == "sbitLineMetrics":
333
+ direction = attrs["direction"]
334
+ assert direction in (
335
+ "hori",
336
+ "vert",
337
+ ), "SbitLineMetrics direction specified invalid."
338
+ metricObj = SbitLineMetrics()
339
+ metricObj.fromXML(name, attrs, content, ttFont)
340
+ vars(self)[direction] = metricObj
341
+ elif name in dataNames:
342
+ vars(self)[name] = safeEval(attrs["value"])
343
+ else:
344
+ log.warning("unknown name '%s' being ignored in BitmapSizeTable.", name)
345
+
346
+
347
+ class SbitLineMetrics(object):
348
+ def toXML(self, name, writer, ttFont):
349
+ writer.begintag("sbitLineMetrics", [("direction", name)])
350
+ writer.newline()
351
+ for metricName in sstruct.getformat(sbitLineMetricsFormat)[1]:
352
+ writer.simpletag(metricName, value=getattr(self, metricName))
353
+ writer.newline()
354
+ writer.endtag("sbitLineMetrics")
355
+ writer.newline()
356
+
357
+ def fromXML(self, name, attrs, content, ttFont):
358
+ metricNames = set(sstruct.getformat(sbitLineMetricsFormat)[1])
359
+ for element in content:
360
+ if not isinstance(element, tuple):
361
+ continue
362
+ name, attrs, content = element
363
+ if name in metricNames:
364
+ vars(self)[name] = safeEval(attrs["value"])
365
+
366
+
367
+ # Important information about the naming scheme. Used for identifying subtables.
368
+ _indexSubTableSubclassPrefix = "eblc_index_sub_table_"
369
+
370
+
371
+ class EblcIndexSubTable(object):
372
+ def __init__(self, data, ttFont):
373
+ self.data = data
374
+ self.ttFont = ttFont
375
+ # TODO Currently non-lazy decompiling doesn't work for this class...
376
+ # if not ttFont.lazy:
377
+ # self.decompile()
378
+ # del self.data, self.ttFont
379
+
380
+ def __getattr__(self, attr):
381
+ # Allow lazy decompile.
382
+ if attr[:2] == "__":
383
+ raise AttributeError(attr)
384
+ if attr == "data":
385
+ raise AttributeError(attr)
386
+ self.decompile()
387
+ return getattr(self, attr)
388
+
389
+ def ensureDecompiled(self, recurse=False):
390
+ if hasattr(self, "data"):
391
+ self.decompile()
392
+
393
+ # This method just takes care of the indexSubHeader. Implementing subclasses
394
+ # should call it to compile the indexSubHeader and then continue compiling
395
+ # the remainder of their unique format.
396
+ def compile(self, ttFont):
397
+ return struct.pack(
398
+ indexSubHeaderFormat,
399
+ self.indexFormat,
400
+ self.imageFormat,
401
+ self.imageDataOffset,
402
+ )
403
+
404
+ # Creates the XML for bitmap glyphs. Each index sub table basically makes
405
+ # the same XML except for specific metric information that is written
406
+ # out via a method call that a subclass implements optionally.
407
+ def toXML(self, writer, ttFont):
408
+ writer.begintag(
409
+ self.__class__.__name__,
410
+ [
411
+ ("imageFormat", self.imageFormat),
412
+ ("firstGlyphIndex", self.firstGlyphIndex),
413
+ ("lastGlyphIndex", self.lastGlyphIndex),
414
+ ],
415
+ )
416
+ writer.newline()
417
+ self.writeMetrics(writer, ttFont)
418
+ # Write out the names as thats all thats needed to rebuild etc.
419
+ # For font debugging of consecutive formats the ids are also written.
420
+ # The ids are not read when moving from the XML format.
421
+ glyphIds = map(ttFont.getGlyphID, self.names)
422
+ for glyphName, glyphId in zip(self.names, glyphIds):
423
+ writer.simpletag("glyphLoc", name=glyphName, id=glyphId)
424
+ writer.newline()
425
+ writer.endtag(self.__class__.__name__)
426
+ writer.newline()
427
+
428
+ def fromXML(self, name, attrs, content, ttFont):
429
+ # Read all the attributes. Even though the glyph indices are
430
+ # recalculated, they are still read in case there needs to
431
+ # be an immediate export of the data.
432
+ self.imageFormat = safeEval(attrs["imageFormat"])
433
+ self.firstGlyphIndex = safeEval(attrs["firstGlyphIndex"])
434
+ self.lastGlyphIndex = safeEval(attrs["lastGlyphIndex"])
435
+
436
+ self.readMetrics(name, attrs, content, ttFont)
437
+
438
+ self.names = []
439
+ for element in content:
440
+ if not isinstance(element, tuple):
441
+ continue
442
+ name, attrs, content = element
443
+ if name == "glyphLoc":
444
+ self.names.append(attrs["name"])
445
+
446
+ # A helper method that writes the metrics for the index sub table. It also
447
+ # is responsible for writing the image size for fixed size data since fixed
448
+ # size is not recalculated on compile. Default behavior is to do nothing.
449
+ def writeMetrics(self, writer, ttFont):
450
+ pass
451
+
452
+ # A helper method that is the inverse of writeMetrics.
453
+ def readMetrics(self, name, attrs, content, ttFont):
454
+ pass
455
+
456
+ # This method is for fixed glyph data sizes. There are formats where
457
+ # the glyph data is fixed but are actually composite glyphs. To handle
458
+ # this the font spec in indexSubTable makes the data the size of the
459
+ # fixed size by padding the component arrays. This function abstracts
460
+ # out this padding process. Input is data unpadded. Output is data
461
+ # padded only in fixed formats. Default behavior is to return the data.
462
+ def padBitmapData(self, data):
463
+ return data
464
+
465
+ # Remove any of the glyph locations and names that are flagged as skipped.
466
+ # This only occurs in formats {1,3}.
467
+ def removeSkipGlyphs(self):
468
+ # Determines if a name, location pair is a valid data location.
469
+ # Skip glyphs are marked when the size is equal to zero.
470
+ def isValidLocation(args):
471
+ (name, (startByte, endByte)) = args
472
+ return startByte < endByte
473
+
474
+ # Remove all skip glyphs.
475
+ dataPairs = list(filter(isValidLocation, zip(self.names, self.locations)))
476
+ self.names, self.locations = list(map(list, zip(*dataPairs)))
477
+
478
+
479
+ # A closure for creating a custom mixin. This is done because formats 1 and 3
480
+ # are very similar. The only difference between them is the size per offset
481
+ # value. Code put in here should handle both cases generally.
482
+ def _createOffsetArrayIndexSubTableMixin(formatStringForDataType):
483
+ # Prep the data size for the offset array data format.
484
+ dataFormat = ">" + formatStringForDataType
485
+ offsetDataSize = struct.calcsize(dataFormat)
486
+
487
+ class OffsetArrayIndexSubTableMixin(object):
488
+ def decompile(self):
489
+ numGlyphs = self.lastGlyphIndex - self.firstGlyphIndex + 1
490
+ indexingOffsets = [
491
+ glyphIndex * offsetDataSize for glyphIndex in range(numGlyphs + 2)
492
+ ]
493
+ indexingLocations = zip(indexingOffsets, indexingOffsets[1:])
494
+ offsetArray = [
495
+ struct.unpack(dataFormat, self.data[slice(*loc)])[0]
496
+ for loc in indexingLocations
497
+ ]
498
+
499
+ glyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex + 1))
500
+ modifiedOffsets = [offset + self.imageDataOffset for offset in offsetArray]
501
+ self.locations = list(zip(modifiedOffsets, modifiedOffsets[1:]))
502
+
503
+ self.names = list(map(self.ttFont.getGlyphName, glyphIds))
504
+ self.removeSkipGlyphs()
505
+ del self.data, self.ttFont
506
+
507
+ def compile(self, ttFont):
508
+ # First make sure that all the data lines up properly. Formats 1 and 3
509
+ # must have all its data lined up consecutively. If not this will fail.
510
+ for curLoc, nxtLoc in zip(self.locations, self.locations[1:]):
511
+ assert (
512
+ curLoc[1] == nxtLoc[0]
513
+ ), "Data must be consecutive in indexSubTable offset formats"
514
+
515
+ glyphIds = list(map(ttFont.getGlyphID, self.names))
516
+ # Make sure that all ids are sorted strictly increasing.
517
+ assert all(glyphIds[i] < glyphIds[i + 1] for i in range(len(glyphIds) - 1))
518
+
519
+ # Run a simple algorithm to add skip glyphs to the data locations at
520
+ # the places where an id is not present.
521
+ idQueue = deque(glyphIds)
522
+ locQueue = deque(self.locations)
523
+ allGlyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex + 1))
524
+ allLocations = []
525
+ for curId in allGlyphIds:
526
+ if curId != idQueue[0]:
527
+ allLocations.append((locQueue[0][0], locQueue[0][0]))
528
+ else:
529
+ idQueue.popleft()
530
+ allLocations.append(locQueue.popleft())
531
+
532
+ # Now that all the locations are collected, pack them appropriately into
533
+ # offsets. This is the form where offset[i] is the location and
534
+ # offset[i+1]-offset[i] is the size of the data location.
535
+ offsets = list(allLocations[0]) + [loc[1] for loc in allLocations[1:]]
536
+ # Image data offset must be less than or equal to the minimum of locations.
537
+ # This offset may change the value for round tripping but is safer and
538
+ # allows imageDataOffset to not be required to be in the XML version.
539
+ self.imageDataOffset = min(offsets)
540
+ offsetArray = [offset - self.imageDataOffset for offset in offsets]
541
+
542
+ dataList = [EblcIndexSubTable.compile(self, ttFont)]
543
+ dataList += [
544
+ struct.pack(dataFormat, offsetValue) for offsetValue in offsetArray
545
+ ]
546
+ # Take care of any padding issues. Only occurs in format 3.
547
+ if offsetDataSize * len(offsetArray) % 4 != 0:
548
+ dataList.append(struct.pack(dataFormat, 0))
549
+ return bytesjoin(dataList)
550
+
551
+ return OffsetArrayIndexSubTableMixin
552
+
553
+
554
+ # A Mixin for functionality shared between the different kinds
555
+ # of fixed sized data handling. Both kinds have big metrics so
556
+ # that kind of special processing is also handled in this mixin.
557
+ class FixedSizeIndexSubTableMixin(object):
558
+ def writeMetrics(self, writer, ttFont):
559
+ writer.simpletag("imageSize", value=self.imageSize)
560
+ writer.newline()
561
+ self.metrics.toXML(writer, ttFont)
562
+
563
+ def readMetrics(self, name, attrs, content, ttFont):
564
+ for element in content:
565
+ if not isinstance(element, tuple):
566
+ continue
567
+ name, attrs, content = element
568
+ if name == "imageSize":
569
+ self.imageSize = safeEval(attrs["value"])
570
+ elif name == BigGlyphMetrics.__name__:
571
+ self.metrics = BigGlyphMetrics()
572
+ self.metrics.fromXML(name, attrs, content, ttFont)
573
+ elif name == SmallGlyphMetrics.__name__:
574
+ log.warning(
575
+ "SmallGlyphMetrics being ignored in format %d.", self.indexFormat
576
+ )
577
+
578
+ def padBitmapData(self, data):
579
+ # Make sure that the data isn't bigger than the fixed size.
580
+ assert len(data) <= self.imageSize, (
581
+ "Data in indexSubTable format %d must be less than the fixed size."
582
+ % self.indexFormat
583
+ )
584
+ # Pad the data so that it matches the fixed size.
585
+ pad = (self.imageSize - len(data)) * b"\0"
586
+ return data + pad
587
+
588
+
589
+ class eblc_index_sub_table_1(
590
+ _createOffsetArrayIndexSubTableMixin("L"), EblcIndexSubTable
591
+ ):
592
+ pass
593
+
594
+
595
+ class eblc_index_sub_table_2(FixedSizeIndexSubTableMixin, EblcIndexSubTable):
596
+ def decompile(self):
597
+ (self.imageSize,) = struct.unpack(">L", self.data[:4])
598
+ self.metrics = BigGlyphMetrics()
599
+ sstruct.unpack2(bigGlyphMetricsFormat, self.data[4:], self.metrics)
600
+ glyphIds = list(range(self.firstGlyphIndex, self.lastGlyphIndex + 1))
601
+ offsets = [
602
+ self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds) + 1)
603
+ ]
604
+ self.locations = list(zip(offsets, offsets[1:]))
605
+ self.names = list(map(self.ttFont.getGlyphName, glyphIds))
606
+ del self.data, self.ttFont
607
+
608
+ def compile(self, ttFont):
609
+ glyphIds = list(map(ttFont.getGlyphID, self.names))
610
+ # Make sure all the ids are consecutive. This is required by Format 2.
611
+ assert glyphIds == list(
612
+ range(self.firstGlyphIndex, self.lastGlyphIndex + 1)
613
+ ), "Format 2 ids must be consecutive."
614
+ self.imageDataOffset = min(next(iter(zip(*self.locations))))
615
+
616
+ dataList = [EblcIndexSubTable.compile(self, ttFont)]
617
+ dataList.append(struct.pack(">L", self.imageSize))
618
+ dataList.append(sstruct.pack(bigGlyphMetricsFormat, self.metrics))
619
+ return bytesjoin(dataList)
620
+
621
+
622
+ class eblc_index_sub_table_3(
623
+ _createOffsetArrayIndexSubTableMixin("H"), EblcIndexSubTable
624
+ ):
625
+ pass
626
+
627
+
628
+ class eblc_index_sub_table_4(EblcIndexSubTable):
629
+ def decompile(self):
630
+ (numGlyphs,) = struct.unpack(">L", self.data[:4])
631
+ data = self.data[4:]
632
+ indexingOffsets = [
633
+ glyphIndex * codeOffsetPairSize for glyphIndex in range(numGlyphs + 2)
634
+ ]
635
+ indexingLocations = zip(indexingOffsets, indexingOffsets[1:])
636
+ glyphArray = [
637
+ struct.unpack(codeOffsetPairFormat, data[slice(*loc)])
638
+ for loc in indexingLocations
639
+ ]
640
+ glyphIds, offsets = list(map(list, zip(*glyphArray)))
641
+ # There are one too many glyph ids. Get rid of the last one.
642
+ glyphIds.pop()
643
+
644
+ offsets = [offset + self.imageDataOffset for offset in offsets]
645
+ self.locations = list(zip(offsets, offsets[1:]))
646
+ self.names = list(map(self.ttFont.getGlyphName, glyphIds))
647
+ del self.data, self.ttFont
648
+
649
+ def compile(self, ttFont):
650
+ # First make sure that all the data lines up properly. Format 4
651
+ # must have all its data lined up consecutively. If not this will fail.
652
+ for curLoc, nxtLoc in zip(self.locations, self.locations[1:]):
653
+ assert (
654
+ curLoc[1] == nxtLoc[0]
655
+ ), "Data must be consecutive in indexSubTable format 4"
656
+
657
+ offsets = list(self.locations[0]) + [loc[1] for loc in self.locations[1:]]
658
+ # Image data offset must be less than or equal to the minimum of locations.
659
+ # Resetting this offset may change the value for round tripping but is safer
660
+ # and allows imageDataOffset to not be required to be in the XML version.
661
+ self.imageDataOffset = min(offsets)
662
+ offsets = [offset - self.imageDataOffset for offset in offsets]
663
+ glyphIds = list(map(ttFont.getGlyphID, self.names))
664
+ # Create an iterator over the ids plus a padding value.
665
+ idsPlusPad = list(itertools.chain(glyphIds, [0]))
666
+
667
+ dataList = [EblcIndexSubTable.compile(self, ttFont)]
668
+ dataList.append(struct.pack(">L", len(glyphIds)))
669
+ tmp = [
670
+ struct.pack(codeOffsetPairFormat, *cop) for cop in zip(idsPlusPad, offsets)
671
+ ]
672
+ dataList += tmp
673
+ data = bytesjoin(dataList)
674
+ return data
675
+
676
+
677
+ class eblc_index_sub_table_5(FixedSizeIndexSubTableMixin, EblcIndexSubTable):
678
+ def decompile(self):
679
+ self.origDataLen = 0
680
+ (self.imageSize,) = struct.unpack(">L", self.data[:4])
681
+ data = self.data[4:]
682
+ self.metrics, data = sstruct.unpack2(
683
+ bigGlyphMetricsFormat, data, BigGlyphMetrics()
684
+ )
685
+ (numGlyphs,) = struct.unpack(">L", data[:4])
686
+ data = data[4:]
687
+ glyphIds = [
688
+ struct.unpack(">H", data[2 * i : 2 * (i + 1)])[0] for i in range(numGlyphs)
689
+ ]
690
+
691
+ offsets = [
692
+ self.imageSize * i + self.imageDataOffset for i in range(len(glyphIds) + 1)
693
+ ]
694
+ self.locations = list(zip(offsets, offsets[1:]))
695
+ self.names = list(map(self.ttFont.getGlyphName, glyphIds))
696
+ del self.data, self.ttFont
697
+
698
+ def compile(self, ttFont):
699
+ self.imageDataOffset = min(next(iter(zip(*self.locations))))
700
+ dataList = [EblcIndexSubTable.compile(self, ttFont)]
701
+ dataList.append(struct.pack(">L", self.imageSize))
702
+ dataList.append(sstruct.pack(bigGlyphMetricsFormat, self.metrics))
703
+ glyphIds = list(map(ttFont.getGlyphID, self.names))
704
+ dataList.append(struct.pack(">L", len(glyphIds)))
705
+ dataList += [struct.pack(">H", curId) for curId in glyphIds]
706
+ if len(glyphIds) % 2 == 1:
707
+ dataList.append(struct.pack(">H", 0))
708
+ return bytesjoin(dataList)
709
+
710
+
711
+ # Dictionary of indexFormat to the class representing that format.
712
+ eblc_sub_table_classes = {
713
+ 1: eblc_index_sub_table_1,
714
+ 2: eblc_index_sub_table_2,
715
+ 3: eblc_index_sub_table_3,
716
+ 4: eblc_index_sub_table_4,
717
+ 5: eblc_index_sub_table_5,
718
+ }