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,165 @@
1
+ # Copyright 2013 Google, Inc. All Rights Reserved.
2
+ #
3
+ # Google Author(s): Behdad Esfahbod
4
+
5
+ from fontTools.misc.textTools import safeEval
6
+ from . import DefaultTable
7
+
8
+
9
+ class table_C_O_L_R_(DefaultTable.DefaultTable):
10
+ """Color table
11
+
12
+ The ``COLR`` table defines color presentation of outline glyphs. It must
13
+ be used in concert with the ``CPAL`` table, which contains the color
14
+ descriptors used.
15
+
16
+ This table is structured so that you can treat it like a dictionary keyed by glyph name.
17
+
18
+ ``ttFont['COLR'][<glyphName>]`` will return the color layers for any glyph.
19
+
20
+ ``ttFont['COLR'][<glyphName>] = <value>`` will set the color layers for any glyph.
21
+
22
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/colr
23
+ """
24
+
25
+ @staticmethod
26
+ def _decompileColorLayersV0(table):
27
+ if not table.LayerRecordArray:
28
+ return {}
29
+ colorLayerLists = {}
30
+ layerRecords = table.LayerRecordArray.LayerRecord
31
+ numLayerRecords = len(layerRecords)
32
+ for baseRec in table.BaseGlyphRecordArray.BaseGlyphRecord:
33
+ baseGlyph = baseRec.BaseGlyph
34
+ firstLayerIndex = baseRec.FirstLayerIndex
35
+ numLayers = baseRec.NumLayers
36
+ assert firstLayerIndex + numLayers <= numLayerRecords
37
+ layers = []
38
+ for i in range(firstLayerIndex, firstLayerIndex + numLayers):
39
+ layerRec = layerRecords[i]
40
+ layers.append(LayerRecord(layerRec.LayerGlyph, layerRec.PaletteIndex))
41
+ colorLayerLists[baseGlyph] = layers
42
+ return colorLayerLists
43
+
44
+ def _toOTTable(self, ttFont):
45
+ from . import otTables
46
+ from fontTools.colorLib.builder import populateCOLRv0
47
+
48
+ tableClass = getattr(otTables, self.tableTag)
49
+ table = tableClass()
50
+ table.Version = self.version
51
+
52
+ populateCOLRv0(
53
+ table,
54
+ {
55
+ baseGlyph: [(layer.name, layer.colorID) for layer in layers]
56
+ for baseGlyph, layers in self.ColorLayers.items()
57
+ },
58
+ glyphMap=ttFont.getReverseGlyphMap(rebuild=True),
59
+ )
60
+ return table
61
+
62
+ def decompile(self, data, ttFont):
63
+ from .otBase import OTTableReader
64
+ from . import otTables
65
+
66
+ # We use otData to decompile, but we adapt the decompiled otTables to the
67
+ # existing COLR v0 API for backward compatibility.
68
+ reader = OTTableReader(data, tableTag=self.tableTag)
69
+ tableClass = getattr(otTables, self.tableTag)
70
+ table = tableClass()
71
+ table.decompile(reader, ttFont)
72
+
73
+ self.version = table.Version
74
+ if self.version == 0:
75
+ self.ColorLayers = self._decompileColorLayersV0(table)
76
+ else:
77
+ # for new versions, keep the raw otTables around
78
+ self.table = table
79
+
80
+ def compile(self, ttFont):
81
+ from .otBase import OTTableWriter
82
+
83
+ if hasattr(self, "table"):
84
+ table = self.table
85
+ else:
86
+ table = self._toOTTable(ttFont)
87
+
88
+ writer = OTTableWriter(tableTag=self.tableTag)
89
+ table.compile(writer, ttFont)
90
+ return writer.getAllData()
91
+
92
+ def toXML(self, writer, ttFont):
93
+ if hasattr(self, "table"):
94
+ self.table.toXML2(writer, ttFont)
95
+ else:
96
+ writer.simpletag("version", value=self.version)
97
+ writer.newline()
98
+ for baseGlyph in sorted(self.ColorLayers.keys(), key=ttFont.getGlyphID):
99
+ writer.begintag("ColorGlyph", name=baseGlyph)
100
+ writer.newline()
101
+ for layer in self.ColorLayers[baseGlyph]:
102
+ layer.toXML(writer, ttFont)
103
+ writer.endtag("ColorGlyph")
104
+ writer.newline()
105
+
106
+ def fromXML(self, name, attrs, content, ttFont):
107
+ if name == "version": # old COLR v0 API
108
+ setattr(self, name, safeEval(attrs["value"]))
109
+ elif name == "ColorGlyph":
110
+ if not hasattr(self, "ColorLayers"):
111
+ self.ColorLayers = {}
112
+ glyphName = attrs["name"]
113
+ for element in content:
114
+ if isinstance(element, str):
115
+ continue
116
+ layers = []
117
+ for element in content:
118
+ if isinstance(element, str):
119
+ continue
120
+ layer = LayerRecord()
121
+ layer.fromXML(element[0], element[1], element[2], ttFont)
122
+ layers.append(layer)
123
+ self.ColorLayers[glyphName] = layers
124
+ else: # new COLR v1 API
125
+ from . import otTables
126
+
127
+ if not hasattr(self, "table"):
128
+ tableClass = getattr(otTables, self.tableTag)
129
+ self.table = tableClass()
130
+ self.table.fromXML(name, attrs, content, ttFont)
131
+ self.table.populateDefaults()
132
+ self.version = self.table.Version
133
+
134
+ def __getitem__(self, glyphName):
135
+ if not isinstance(glyphName, str):
136
+ raise TypeError(f"expected str, found {type(glyphName).__name__}")
137
+ return self.ColorLayers[glyphName]
138
+
139
+ def __setitem__(self, glyphName, value):
140
+ if not isinstance(glyphName, str):
141
+ raise TypeError(f"expected str, found {type(glyphName).__name__}")
142
+ if value is not None:
143
+ self.ColorLayers[glyphName] = value
144
+ elif glyphName in self.ColorLayers:
145
+ del self.ColorLayers[glyphName]
146
+
147
+ def __delitem__(self, glyphName):
148
+ del self.ColorLayers[glyphName]
149
+
150
+
151
+ class LayerRecord(object):
152
+ def __init__(self, name=None, colorID=None):
153
+ self.name = name
154
+ self.colorID = colorID
155
+
156
+ def toXML(self, writer, ttFont):
157
+ writer.simpletag("layer", name=self.name, colorID=self.colorID)
158
+ writer.newline()
159
+
160
+ def fromXML(self, eltname, attrs, content, ttFont):
161
+ for name, value in attrs.items():
162
+ if name == "name":
163
+ setattr(self, name, value)
164
+ else:
165
+ setattr(self, name, safeEval(value))
@@ -0,0 +1,305 @@
1
+ # Copyright 2013 Google, Inc. All Rights Reserved.
2
+ #
3
+ # Google Author(s): Behdad Esfahbod
4
+
5
+ from fontTools.misc.textTools import bytesjoin, safeEval
6
+ from . import DefaultTable
7
+ import array
8
+ from collections import namedtuple
9
+ import struct
10
+ import sys
11
+
12
+
13
+ class table_C_P_A_L_(DefaultTable.DefaultTable):
14
+ """Color Palette table
15
+
16
+ The ``CPAL`` table contains a set of one or more color palettes. The color
17
+ records in each palette can be referenced by the ``COLR`` table to specify
18
+ the colors used in a color glyph.
19
+
20
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/cpal
21
+ """
22
+
23
+ NO_NAME_ID = 0xFFFF
24
+ DEFAULT_PALETTE_TYPE = 0
25
+
26
+ def __init__(self, tag=None):
27
+ DefaultTable.DefaultTable.__init__(self, tag)
28
+ self.palettes = []
29
+ self.paletteTypes = []
30
+ self.paletteLabels = []
31
+ self.paletteEntryLabels = []
32
+
33
+ def decompile(self, data, ttFont):
34
+ (
35
+ self.version,
36
+ self.numPaletteEntries,
37
+ numPalettes,
38
+ numColorRecords,
39
+ goffsetFirstColorRecord,
40
+ ) = struct.unpack(">HHHHL", data[:12])
41
+ assert (
42
+ self.version <= 1
43
+ ), "Version of CPAL table is higher than I know how to handle"
44
+ self.palettes = []
45
+ pos = 12
46
+ for i in range(numPalettes):
47
+ startIndex = struct.unpack(">H", data[pos : pos + 2])[0]
48
+ assert startIndex + self.numPaletteEntries <= numColorRecords
49
+ pos += 2
50
+ palette = []
51
+ ppos = goffsetFirstColorRecord + startIndex * 4
52
+ for j in range(self.numPaletteEntries):
53
+ palette.append(Color(*struct.unpack(">BBBB", data[ppos : ppos + 4])))
54
+ ppos += 4
55
+ self.palettes.append(palette)
56
+ if self.version == 0:
57
+ offsetToPaletteTypeArray = 0
58
+ offsetToPaletteLabelArray = 0
59
+ offsetToPaletteEntryLabelArray = 0
60
+ else:
61
+ pos = 12 + numPalettes * 2
62
+ (
63
+ offsetToPaletteTypeArray,
64
+ offsetToPaletteLabelArray,
65
+ offsetToPaletteEntryLabelArray,
66
+ ) = struct.unpack(">LLL", data[pos : pos + 12])
67
+ self.paletteTypes = self._decompileUInt32Array(
68
+ data,
69
+ offsetToPaletteTypeArray,
70
+ numPalettes,
71
+ default=self.DEFAULT_PALETTE_TYPE,
72
+ )
73
+ self.paletteLabels = self._decompileUInt16Array(
74
+ data, offsetToPaletteLabelArray, numPalettes, default=self.NO_NAME_ID
75
+ )
76
+ self.paletteEntryLabels = self._decompileUInt16Array(
77
+ data,
78
+ offsetToPaletteEntryLabelArray,
79
+ self.numPaletteEntries,
80
+ default=self.NO_NAME_ID,
81
+ )
82
+
83
+ def _decompileUInt16Array(self, data, offset, numElements, default=0):
84
+ if offset == 0:
85
+ return [default] * numElements
86
+ result = array.array("H", data[offset : offset + 2 * numElements])
87
+ if sys.byteorder != "big":
88
+ result.byteswap()
89
+ assert len(result) == numElements, result
90
+ return result.tolist()
91
+
92
+ def _decompileUInt32Array(self, data, offset, numElements, default=0):
93
+ if offset == 0:
94
+ return [default] * numElements
95
+ result = array.array("I", data[offset : offset + 4 * numElements])
96
+ if sys.byteorder != "big":
97
+ result.byteswap()
98
+ assert len(result) == numElements, result
99
+ return result.tolist()
100
+
101
+ def compile(self, ttFont):
102
+ colorRecordIndices, colorRecords = self._compileColorRecords()
103
+ paletteTypes = self._compilePaletteTypes()
104
+ paletteLabels = self._compilePaletteLabels()
105
+ paletteEntryLabels = self._compilePaletteEntryLabels()
106
+ numColorRecords = len(colorRecords) // 4
107
+ offsetToFirstColorRecord = 12 + len(colorRecordIndices)
108
+ if self.version >= 1:
109
+ offsetToFirstColorRecord += 12
110
+ header = struct.pack(
111
+ ">HHHHL",
112
+ self.version,
113
+ self.numPaletteEntries,
114
+ len(self.palettes),
115
+ numColorRecords,
116
+ offsetToFirstColorRecord,
117
+ )
118
+ if self.version == 0:
119
+ dataList = [header, colorRecordIndices, colorRecords]
120
+ else:
121
+ pos = offsetToFirstColorRecord + len(colorRecords)
122
+ if len(paletteTypes) == 0:
123
+ offsetToPaletteTypeArray = 0
124
+ else:
125
+ offsetToPaletteTypeArray = pos
126
+ pos += len(paletteTypes)
127
+ if len(paletteLabels) == 0:
128
+ offsetToPaletteLabelArray = 0
129
+ else:
130
+ offsetToPaletteLabelArray = pos
131
+ pos += len(paletteLabels)
132
+ if len(paletteEntryLabels) == 0:
133
+ offsetToPaletteEntryLabelArray = 0
134
+ else:
135
+ offsetToPaletteEntryLabelArray = pos
136
+ pos += len(paletteLabels)
137
+ header1 = struct.pack(
138
+ ">LLL",
139
+ offsetToPaletteTypeArray,
140
+ offsetToPaletteLabelArray,
141
+ offsetToPaletteEntryLabelArray,
142
+ )
143
+ dataList = [
144
+ header,
145
+ colorRecordIndices,
146
+ header1,
147
+ colorRecords,
148
+ paletteTypes,
149
+ paletteLabels,
150
+ paletteEntryLabels,
151
+ ]
152
+ return bytesjoin(dataList)
153
+
154
+ def _compilePalette(self, palette):
155
+ assert len(palette) == self.numPaletteEntries
156
+ pack = lambda c: struct.pack(">BBBB", c.blue, c.green, c.red, c.alpha)
157
+ return bytesjoin([pack(color) for color in palette])
158
+
159
+ def _compileColorRecords(self):
160
+ colorRecords, colorRecordIndices, pool = [], [], {}
161
+ for palette in self.palettes:
162
+ packedPalette = self._compilePalette(palette)
163
+ if packedPalette in pool:
164
+ index = pool[packedPalette]
165
+ else:
166
+ index = len(colorRecords)
167
+ colorRecords.append(packedPalette)
168
+ pool[packedPalette] = index
169
+ colorRecordIndices.append(struct.pack(">H", index * self.numPaletteEntries))
170
+ return bytesjoin(colorRecordIndices), bytesjoin(colorRecords)
171
+
172
+ def _compilePaletteTypes(self):
173
+ if self.version == 0 or not any(self.paletteTypes):
174
+ return b""
175
+ assert len(self.paletteTypes) == len(self.palettes)
176
+ result = bytesjoin([struct.pack(">I", ptype) for ptype in self.paletteTypes])
177
+ assert len(result) == 4 * len(self.palettes)
178
+ return result
179
+
180
+ def _compilePaletteLabels(self):
181
+ if self.version == 0 or all(l == self.NO_NAME_ID for l in self.paletteLabels):
182
+ return b""
183
+ assert len(self.paletteLabels) == len(self.palettes)
184
+ result = bytesjoin([struct.pack(">H", label) for label in self.paletteLabels])
185
+ assert len(result) == 2 * len(self.palettes)
186
+ return result
187
+
188
+ def _compilePaletteEntryLabels(self):
189
+ if self.version == 0 or all(
190
+ l == self.NO_NAME_ID for l in self.paletteEntryLabels
191
+ ):
192
+ return b""
193
+ assert len(self.paletteEntryLabels) == self.numPaletteEntries
194
+ result = bytesjoin(
195
+ [struct.pack(">H", label) for label in self.paletteEntryLabels]
196
+ )
197
+ assert len(result) == 2 * self.numPaletteEntries
198
+ return result
199
+
200
+ def toXML(self, writer, ttFont):
201
+ numPalettes = len(self.palettes)
202
+ paletteLabels = {i: nameID for (i, nameID) in enumerate(self.paletteLabels)}
203
+ paletteTypes = {i: typ for (i, typ) in enumerate(self.paletteTypes)}
204
+ writer.simpletag("version", value=self.version)
205
+ writer.newline()
206
+ writer.simpletag("numPaletteEntries", value=self.numPaletteEntries)
207
+ writer.newline()
208
+ for index, palette in enumerate(self.palettes):
209
+ attrs = {"index": index}
210
+ paletteType = paletteTypes.get(index, self.DEFAULT_PALETTE_TYPE)
211
+ paletteLabel = paletteLabels.get(index, self.NO_NAME_ID)
212
+ if self.version > 0 and paletteLabel != self.NO_NAME_ID:
213
+ attrs["label"] = paletteLabel
214
+ if self.version > 0 and paletteType != self.DEFAULT_PALETTE_TYPE:
215
+ attrs["type"] = paletteType
216
+ writer.begintag("palette", **attrs)
217
+ writer.newline()
218
+ if (
219
+ self.version > 0
220
+ and paletteLabel != self.NO_NAME_ID
221
+ and ttFont
222
+ and "name" in ttFont
223
+ ):
224
+ name = ttFont["name"].getDebugName(paletteLabel)
225
+ if name is not None:
226
+ writer.comment(name)
227
+ writer.newline()
228
+ assert len(palette) == self.numPaletteEntries
229
+ for cindex, color in enumerate(palette):
230
+ color.toXML(writer, ttFont, cindex)
231
+ writer.endtag("palette")
232
+ writer.newline()
233
+ if self.version > 0 and not all(
234
+ l == self.NO_NAME_ID for l in self.paletteEntryLabels
235
+ ):
236
+ writer.begintag("paletteEntryLabels")
237
+ writer.newline()
238
+ for index, label in enumerate(self.paletteEntryLabels):
239
+ if label != self.NO_NAME_ID:
240
+ writer.simpletag("label", index=index, value=label)
241
+ if self.version > 0 and label and ttFont and "name" in ttFont:
242
+ name = ttFont["name"].getDebugName(label)
243
+ if name is not None:
244
+ writer.comment(name)
245
+ writer.newline()
246
+ writer.endtag("paletteEntryLabels")
247
+ writer.newline()
248
+
249
+ def fromXML(self, name, attrs, content, ttFont):
250
+ if name == "palette":
251
+ self.paletteLabels.append(int(attrs.get("label", self.NO_NAME_ID)))
252
+ self.paletteTypes.append(int(attrs.get("type", self.DEFAULT_PALETTE_TYPE)))
253
+ palette = []
254
+ for element in content:
255
+ if isinstance(element, str):
256
+ continue
257
+ attrs = element[1]
258
+ color = Color.fromHex(attrs["value"])
259
+ palette.append(color)
260
+ self.palettes.append(palette)
261
+ elif name == "paletteEntryLabels":
262
+ colorLabels = {}
263
+ for element in content:
264
+ if isinstance(element, str):
265
+ continue
266
+ elementName, elementAttr, _ = element
267
+ if elementName == "label":
268
+ labelIndex = safeEval(elementAttr["index"])
269
+ nameID = safeEval(elementAttr["value"])
270
+ colorLabels[labelIndex] = nameID
271
+ self.paletteEntryLabels = [
272
+ colorLabels.get(i, self.NO_NAME_ID)
273
+ for i in range(self.numPaletteEntries)
274
+ ]
275
+ elif "value" in attrs:
276
+ value = safeEval(attrs["value"])
277
+ setattr(self, name, value)
278
+ if name == "numPaletteEntries":
279
+ self.paletteEntryLabels = [self.NO_NAME_ID] * self.numPaletteEntries
280
+
281
+
282
+ class Color(namedtuple("Color", "blue green red alpha")):
283
+ def hex(self):
284
+ return "#%02X%02X%02X%02X" % (self.red, self.green, self.blue, self.alpha)
285
+
286
+ def __repr__(self):
287
+ return self.hex()
288
+
289
+ def toXML(self, writer, ttFont, index=None):
290
+ writer.simpletag("color", value=self.hex(), index=index)
291
+ writer.newline()
292
+
293
+ @classmethod
294
+ def fromHex(cls, value):
295
+ if value[0] == "#":
296
+ value = value[1:]
297
+ red = int(value[0:2], 16)
298
+ green = int(value[2:4], 16)
299
+ blue = int(value[4:6], 16)
300
+ alpha = int(value[6:8], 16) if len(value) >= 8 else 0xFF
301
+ return cls(red=red, green=green, blue=blue, alpha=alpha)
302
+
303
+ @classmethod
304
+ def fromRGBA(cls, red, green, blue, alpha):
305
+ return cls(red=red, green=green, blue=blue, alpha=alpha)
@@ -0,0 +1,158 @@
1
+ from fontTools.misc.textTools import bytesjoin, strjoin, tobytes, tostr, safeEval
2
+ from fontTools.misc import sstruct
3
+ from . import DefaultTable
4
+ import base64
5
+
6
+ DSIG_HeaderFormat = """
7
+ > # big endian
8
+ ulVersion: L
9
+ usNumSigs: H
10
+ usFlag: H
11
+ """
12
+ # followed by an array of usNumSigs DSIG_Signature records
13
+ DSIG_SignatureFormat = """
14
+ > # big endian
15
+ ulFormat: L
16
+ ulLength: L # length includes DSIG_SignatureBlock header
17
+ ulOffset: L
18
+ """
19
+ # followed by an array of usNumSigs DSIG_SignatureBlock records,
20
+ # each followed immediately by the pkcs7 bytes
21
+ DSIG_SignatureBlockFormat = """
22
+ > # big endian
23
+ usReserved1: H
24
+ usReserved2: H
25
+ cbSignature: l # length of following raw pkcs7 data
26
+ """
27
+
28
+ #
29
+ # NOTE
30
+ # the DSIG table format allows for SignatureBlocks residing
31
+ # anywhere in the table and possibly in a different order as
32
+ # listed in the array after the first table header
33
+ #
34
+ # this implementation does not keep track of any gaps and/or data
35
+ # before or after the actual signature blocks while decompiling,
36
+ # and puts them in the same physical order as listed in the header
37
+ # on compilation with no padding whatsoever.
38
+ #
39
+
40
+
41
+ class table_D_S_I_G_(DefaultTable.DefaultTable):
42
+ """Digital Signature table
43
+
44
+ The ``DSIG`` table contains cryptographic signatures for the font.
45
+
46
+ See also https://learn.microsoft.com/en-us/typography/opentype/spec/dsig
47
+ """
48
+
49
+ def decompile(self, data, ttFont):
50
+ dummy, newData = sstruct.unpack2(DSIG_HeaderFormat, data, self)
51
+ assert self.ulVersion == 1, "DSIG ulVersion must be 1"
52
+ assert self.usFlag & ~1 == 0, "DSIG usFlag must be 0x1 or 0x0"
53
+ self.signatureRecords = sigrecs = []
54
+ for n in range(self.usNumSigs):
55
+ sigrec, newData = sstruct.unpack2(
56
+ DSIG_SignatureFormat, newData, SignatureRecord()
57
+ )
58
+ assert sigrec.ulFormat == 1, (
59
+ "DSIG signature record #%d ulFormat must be 1" % n
60
+ )
61
+ sigrecs.append(sigrec)
62
+ for sigrec in sigrecs:
63
+ dummy, newData = sstruct.unpack2(
64
+ DSIG_SignatureBlockFormat, data[sigrec.ulOffset :], sigrec
65
+ )
66
+ assert sigrec.usReserved1 == 0, (
67
+ "DSIG signature record #%d usReserverd1 must be 0" % n
68
+ )
69
+ assert sigrec.usReserved2 == 0, (
70
+ "DSIG signature record #%d usReserverd2 must be 0" % n
71
+ )
72
+ sigrec.pkcs7 = newData[: sigrec.cbSignature]
73
+
74
+ def compile(self, ttFont):
75
+ packed = sstruct.pack(DSIG_HeaderFormat, self)
76
+ headers = [packed]
77
+ offset = len(packed) + self.usNumSigs * sstruct.calcsize(DSIG_SignatureFormat)
78
+ data = []
79
+ for sigrec in self.signatureRecords:
80
+ # first pack signature block
81
+ sigrec.cbSignature = len(sigrec.pkcs7)
82
+ packed = sstruct.pack(DSIG_SignatureBlockFormat, sigrec) + sigrec.pkcs7
83
+ data.append(packed)
84
+ # update redundant length field
85
+ sigrec.ulLength = len(packed)
86
+ # update running table offset
87
+ sigrec.ulOffset = offset
88
+ headers.append(sstruct.pack(DSIG_SignatureFormat, sigrec))
89
+ offset += sigrec.ulLength
90
+ if offset % 2:
91
+ # Pad to even bytes
92
+ data.append(b"\0")
93
+ return bytesjoin(headers + data)
94
+
95
+ def toXML(self, xmlWriter, ttFont):
96
+ xmlWriter.comment(
97
+ "note that the Digital Signature will be invalid after recompilation!"
98
+ )
99
+ xmlWriter.newline()
100
+ xmlWriter.simpletag(
101
+ "tableHeader",
102
+ version=self.ulVersion,
103
+ numSigs=self.usNumSigs,
104
+ flag="0x%X" % self.usFlag,
105
+ )
106
+ for sigrec in self.signatureRecords:
107
+ xmlWriter.newline()
108
+ sigrec.toXML(xmlWriter, ttFont)
109
+ xmlWriter.newline()
110
+
111
+ def fromXML(self, name, attrs, content, ttFont):
112
+ if name == "tableHeader":
113
+ self.signatureRecords = []
114
+ self.ulVersion = safeEval(attrs["version"])
115
+ self.usNumSigs = safeEval(attrs["numSigs"])
116
+ self.usFlag = safeEval(attrs["flag"])
117
+ return
118
+ if name == "SignatureRecord":
119
+ sigrec = SignatureRecord()
120
+ sigrec.fromXML(name, attrs, content, ttFont)
121
+ self.signatureRecords.append(sigrec)
122
+
123
+
124
+ pem_spam = lambda l, spam={
125
+ "-----BEGIN PKCS7-----": True,
126
+ "-----END PKCS7-----": True,
127
+ "": True,
128
+ }: not spam.get(l.strip())
129
+
130
+
131
+ def b64encode(b):
132
+ s = base64.b64encode(b)
133
+ # Line-break at 76 chars.
134
+ items = []
135
+ while s:
136
+ items.append(tostr(s[:76]))
137
+ items.append("\n")
138
+ s = s[76:]
139
+ return strjoin(items)
140
+
141
+
142
+ class SignatureRecord(object):
143
+ def __repr__(self):
144
+ return "<%s: %s>" % (self.__class__.__name__, self.__dict__)
145
+
146
+ def toXML(self, writer, ttFont):
147
+ writer.begintag(self.__class__.__name__, format=self.ulFormat)
148
+ writer.newline()
149
+ writer.write_noindent("-----BEGIN PKCS7-----\n")
150
+ writer.write_noindent(b64encode(self.pkcs7))
151
+ writer.write_noindent("-----END PKCS7-----\n")
152
+ writer.endtag(self.__class__.__name__)
153
+
154
+ def fromXML(self, name, attrs, content, ttFont):
155
+ self.ulFormat = safeEval(attrs["format"])
156
+ self.usReserved1 = safeEval(attrs.get("reserved1", "0"))
157
+ self.usReserved2 = safeEval(attrs.get("reserved2", "0"))
158
+ self.pkcs7 = base64.b64decode(tobytes(strjoin(filter(pem_spam, content))))
@@ -0,0 +1,35 @@
1
+ import json
2
+ from textwrap import indent
3
+
4
+ from . import DefaultTable
5
+ from fontTools.misc.textTools import tostr
6
+
7
+
8
+ class table_D__e_b_g(DefaultTable.DefaultTable):
9
+ def __init__(self, tag=None):
10
+ DefaultTable.DefaultTable.__init__(self, tag)
11
+ self.data = {}
12
+
13
+ def decompile(self, data, ttFont):
14
+ self.data = json.loads(data)
15
+
16
+ def compile(self, ttFont):
17
+ return json.dumps(self.data).encode("utf-8")
18
+
19
+ def toXML(self, writer, ttFont):
20
+ # make sure json indentation inside CDATA block matches XMLWriter's
21
+ data = json.dumps(self.data, indent=len(writer.indentwhite))
22
+ prefix = tostr(writer.indentwhite) * (writer.indentlevel + 1)
23
+ # but don't indent the first json line so it's adjacent to `<![CDATA[{`
24
+ cdata = indent(data, prefix, lambda ln: ln != "{\n")
25
+
26
+ writer.begintag("json")
27
+ writer.newline()
28
+ writer.writecdata(cdata)
29
+ writer.newline()
30
+ writer.endtag("json")
31
+ writer.newline()
32
+
33
+ def fromXML(self, name, attrs, content, ttFont):
34
+ if name == "json":
35
+ self.data = json.loads("".join(content))