core-pdf 0.0.2__py3-none-any.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 (741) hide show
  1. core_pdf/__init__.py +22 -0
  2. core_pdf/__main__.py +7 -0
  3. core_pdf/cli.py +65 -0
  4. core_pdf/impl/__init__.py +2 -0
  5. core_pdf/impl/engine/__init__.py +16 -0
  6. core_pdf/impl/engine/extraction/__init__.py +4 -0
  7. core_pdf/impl/engine/extraction/cache.py +16 -0
  8. core_pdf/impl/engine/extraction/common/__init__.py +2 -0
  9. core_pdf/impl/engine/extraction/common/observation_resolver.py +211 -0
  10. core_pdf/impl/engine/extraction/common/ordering.py +625 -0
  11. core_pdf/impl/engine/extraction/common/page_content.py +472 -0
  12. core_pdf/impl/engine/extraction/common/page_geometry.py +1560 -0
  13. core_pdf/impl/engine/extraction/common/page_profile.py +485 -0
  14. core_pdf/impl/engine/extraction/common/render.py +1803 -0
  15. core_pdf/impl/engine/extraction/document.py +38 -0
  16. core_pdf/impl/engine/extraction/document_extraction.py +397 -0
  17. core_pdf/impl/engine/extraction/document_structured.py +384 -0
  18. core_pdf/impl/engine/extraction/document_text.py +89 -0
  19. core_pdf/impl/engine/extraction/ocr/__init__.py +2 -0
  20. core_pdf/impl/engine/extraction/ocr/backend.py +1799 -0
  21. core_pdf/impl/engine/extraction/ocr/candidate_generation.py +1618 -0
  22. core_pdf/impl/engine/extraction/ocr/candidates.py +40 -0
  23. core_pdf/impl/engine/extraction/ocr/execution.py +566 -0
  24. core_pdf/impl/engine/extraction/ocr/full_page.py +853 -0
  25. core_pdf/impl/engine/extraction/ocr/geometry.py +158 -0
  26. core_pdf/impl/engine/extraction/ocr/glyph_recognizer.py +596 -0
  27. core_pdf/impl/engine/extraction/ocr/iterator_layout.py +994 -0
  28. core_pdf/impl/engine/extraction/ocr/layout.py +897 -0
  29. core_pdf/impl/engine/extraction/ocr/line_reconciliation.py +2836 -0
  30. core_pdf/impl/engine/extraction/ocr/page_analysis.py +653 -0
  31. core_pdf/impl/engine/extraction/ocr/postprocess.py +5202 -0
  32. core_pdf/impl/engine/extraction/ocr/rendering.py +405 -0
  33. core_pdf/impl/engine/extraction/ocr/schematic.py +2779 -0
  34. core_pdf/impl/engine/extraction/ocr/selection.py +720 -0
  35. core_pdf/impl/engine/extraction/ocr/session.py +401 -0
  36. core_pdf/impl/engine/extraction/ocr/table_regions.py +1943 -0
  37. core_pdf/impl/engine/extraction/ocr/text_analysis.py +884 -0
  38. core_pdf/impl/engine/extraction/ocr/tiling.py +551 -0
  39. core_pdf/impl/engine/extraction/ocr/types.py +283 -0
  40. core_pdf/impl/engine/extraction/ocr/vector_text.py +867 -0
  41. core_pdf/impl/engine/extraction/page.py +46 -0
  42. core_pdf/impl/engine/extraction/page_text/__init__.py +2 -0
  43. core_pdf/impl/engine/extraction/page_text/decisions.py +67 -0
  44. core_pdf/impl/engine/extraction/page_text/engine.py +466 -0
  45. core_pdf/impl/engine/extraction/page_text/mixin.py +13425 -0
  46. core_pdf/impl/engine/extraction/page_text/native.py +639 -0
  47. core_pdf/impl/engine/extraction/page_text/output.py +140 -0
  48. core_pdf/impl/engine/extraction/page_text/policy.py +1225 -0
  49. core_pdf/impl/engine/extraction/redactions.py +579 -0
  50. core_pdf/impl/engine/extraction/tables/__init__.py +2 -0
  51. core_pdf/impl/engine/extraction/tables/api.py +325 -0
  52. core_pdf/impl/engine/extraction/tables/core.py +746 -0
  53. core_pdf/impl/engine/extraction/tables/exports.py +310 -0
  54. core_pdf/impl/engine/extraction/tables/extract.py +856 -0
  55. core_pdf/impl/engine/extraction/tables/grid.py +443 -0
  56. core_pdf/impl/engine/extraction/tables/options.py +296 -0
  57. core_pdf/impl/engine/extraction/tables/protocols.py +63 -0
  58. core_pdf/impl/engine/extraction/tables/quality.py +71 -0
  59. core_pdf/impl/engine/extraction/tables/stream.py +591 -0
  60. core_pdf/impl/engine/extraction/tables/text_geometry.py +36 -0
  61. core_pdf/impl/engine/extraction/tables/types.py +60 -0
  62. core_pdf/impl/engine/layout/__init__.py +54 -0
  63. core_pdf/impl/engine/layout/data/wordlists/LICENSE_BartMassey_wordlists.txt +27 -0
  64. core_pdf/impl/engine/layout/data/wordlists/LICENSE_wordninja.txt +21 -0
  65. core_pdf/impl/engine/layout/data/wordlists/README.md +23 -0
  66. core_pdf/impl/engine/layout/data/wordlists/README_BartMassey_count_1w.md +16 -0
  67. core_pdf/impl/engine/layout/data/wordlists/norvig_count_1w.txt.gz +0 -0
  68. core_pdf/impl/engine/layout/data/wordlists/wordninja_words.txt.gz +0 -0
  69. core_pdf/impl/engine/layout/geometry.py +238 -0
  70. core_pdf/impl/engine/layout/geometry_quality.py +578 -0
  71. core_pdf/impl/engine/layout/glyphs.py +173 -0
  72. core_pdf/impl/engine/layout/models.py +806 -0
  73. core_pdf/impl/engine/layout/text_lines.py +1498 -0
  74. core_pdf/impl/engine/layout/word_frequencies.py +117 -0
  75. core_pdf/impl/engine/rendering/__init__.py +13 -0
  76. core_pdf/impl/engine/rendering/models.py +2871 -0
  77. core_pdf/impl/engine/rendering/page.py +289 -0
  78. core_pdf/impl/engine/spec/__init__.py +4 -0
  79. core_pdf/impl/engine/spec/s_07_content/__init__.py +24 -0
  80. core_pdf/impl/engine/spec/s_07_content/capture.py +2274 -0
  81. core_pdf/impl/engine/spec/s_07_content/inline_images.py +230 -0
  82. core_pdf/impl/engine/spec/s_07_content/marked_content.py +134 -0
  83. core_pdf/impl/engine/spec/s_07_content/operations.py +1056 -0
  84. core_pdf/impl/engine/spec/s_07_content/operators.py +1417 -0
  85. core_pdf/impl/engine/spec/s_07_content/state.py +1141 -0
  86. core_pdf/impl/engine/spec/s_07_content/text_helpers.py +257 -0
  87. core_pdf/impl/engine/spec/s_07_content/xobjects.py +167 -0
  88. core_pdf/impl/engine/spec/s_07_document/__init__.py +32 -0
  89. core_pdf/impl/engine/spec/s_07_document/document.py +169 -0
  90. core_pdf/impl/engine/spec/s_07_document/document_catalog.py +96 -0
  91. core_pdf/impl/engine/spec/s_07_document/document_embedded.py +92 -0
  92. core_pdf/impl/engine/spec/s_07_document/document_labels.py +109 -0
  93. core_pdf/impl/engine/spec/s_07_document/document_page_labels.py +79 -0
  94. core_pdf/impl/engine/spec/s_07_document/document_page_list.py +95 -0
  95. core_pdf/impl/engine/spec/s_07_document/document_page_recovery.py +220 -0
  96. core_pdf/impl/engine/spec/s_07_document/document_pages.py +220 -0
  97. core_pdf/impl/engine/spec/s_07_document/document_security.py +82 -0
  98. core_pdf/impl/engine/spec/s_07_document/document_selection.py +79 -0
  99. core_pdf/impl/engine/spec/s_07_document/document_source.py +78 -0
  100. core_pdf/impl/engine/spec/s_07_document/document_xref.py +415 -0
  101. core_pdf/impl/engine/spec/s_07_document/forms.py +260 -0
  102. core_pdf/impl/engine/spec/s_07_document/layers.py +120 -0
  103. core_pdf/impl/engine/spec/s_07_document/metadata.py +132 -0
  104. core_pdf/impl/engine/spec/s_07_document/metadata_types.py +49 -0
  105. core_pdf/impl/engine/spec/s_07_document/name_trees.py +130 -0
  106. core_pdf/impl/engine/spec/s_07_document/navigation.py +265 -0
  107. core_pdf/impl/engine/spec/s_07_document/page.py +332 -0
  108. core_pdf/impl/engine/spec/s_07_document/page_boxes.py +158 -0
  109. core_pdf/impl/engine/spec/s_07_document/page_interactions.py +250 -0
  110. core_pdf/impl/engine/spec/s_07_document/page_links.py +98 -0
  111. core_pdf/impl/engine/spec/s_07_document/page_state.py +157 -0
  112. core_pdf/impl/engine/spec/s_07_document/protocols.py +119 -0
  113. core_pdf/impl/engine/spec/s_07_filters/__init__.py +4 -0
  114. core_pdf/impl/engine/spec/s_07_filters/codecs.py +277 -0
  115. core_pdf/impl/engine/spec/s_07_filters/decode_spec.py +309 -0
  116. core_pdf/impl/engine/spec/s_07_filters/decoders.py +167 -0
  117. core_pdf/impl/engine/spec/s_07_filters/flate.py +144 -0
  118. core_pdf/impl/engine/spec/s_07_filters/pipeline.py +224 -0
  119. core_pdf/impl/engine/spec/s_07_filters/predictors.py +55 -0
  120. core_pdf/impl/engine/spec/s_07_objects/__init__.py +2 -0
  121. core_pdf/impl/engine/spec/s_07_objects/coercion.py +199 -0
  122. core_pdf/impl/engine/spec/s_07_objects/indirect_headers.py +46 -0
  123. core_pdf/impl/engine/spec/s_07_objects/object_cache.py +57 -0
  124. core_pdf/impl/engine/spec/s_07_objects/pdfdict.py +120 -0
  125. core_pdf/impl/engine/spec/s_07_objects/resolver.py +253 -0
  126. core_pdf/impl/engine/spec/s_07_objects/resolver_values.py +190 -0
  127. core_pdf/impl/engine/spec/s_07_security/__init__.py +4 -0
  128. core_pdf/impl/engine/spec/s_07_security/aes.py +215 -0
  129. core_pdf/impl/engine/spec/s_07_security/crypto_constants.py +550 -0
  130. core_pdf/impl/engine/spec/s_07_security/crypto_handlers.py +19 -0
  131. core_pdf/impl/engine/spec/s_07_security/errors.py +10 -0
  132. core_pdf/impl/engine/spec/s_07_security/rc4.py +33 -0
  133. core_pdf/impl/engine/spec/s_07_security/saslprep.py +47 -0
  134. core_pdf/impl/engine/spec/s_07_security/standard.py +174 -0
  135. core_pdf/impl/engine/spec/s_07_security/standard_v4.py +95 -0
  136. core_pdf/impl/engine/spec/s_07_security/standard_v5.py +113 -0
  137. core_pdf/impl/engine/spec/s_07_security/values.py +27 -0
  138. core_pdf/impl/engine/spec/s_07_syntax/__init__.py +2 -0
  139. core_pdf/impl/engine/spec/s_07_syntax/lexer.py +1110 -0
  140. core_pdf/impl/engine/spec/s_07_syntax/lexer_helpers.py +170 -0
  141. core_pdf/impl/engine/spec/s_07_syntax/objects.py +153 -0
  142. core_pdf/impl/engine/spec/s_07_syntax/tokens.py +30 -0
  143. core_pdf/impl/engine/spec/s_07_syntax/xref.py +715 -0
  144. core_pdf/impl/engine/spec/s_08_graphics/__init__.py +2 -0
  145. core_pdf/impl/engine/spec/s_08_graphics/color.py +623 -0
  146. core_pdf/impl/engine/spec/s_08_graphics/color_math.py +36 -0
  147. core_pdf/impl/engine/spec/s_08_graphics/color_spec.py +255 -0
  148. core_pdf/impl/engine/spec/s_08_graphics/icc_profiles.py +617 -0
  149. core_pdf/impl/engine/spec/s_08_graphics/matrix.py +45 -0
  150. core_pdf/impl/engine/spec/s_09_fonts/__init__.py +2 -0
  151. core_pdf/impl/engine/spec/s_09_fonts/cff.py +90 -0
  152. core_pdf/impl/engine/spec/s_09_fonts/data/__init__.py +4 -0
  153. core_pdf/impl/engine/spec/s_09_fonts/data/core14.py +13214 -0
  154. core_pdf/impl/engine/spec/s_09_fonts/decoder.py +745 -0
  155. core_pdf/impl/engine/spec/s_09_fonts/encoding.py +47 -0
  156. core_pdf/impl/engine/spec/s_09_fonts/font_names.py +27 -0
  157. core_pdf/impl/engine/spec/s_09_fonts/glyph_decode.py +137 -0
  158. core_pdf/impl/engine/spec/s_09_fonts/glyphs.py +141 -0
  159. core_pdf/impl/engine/spec/s_09_fonts/helpers.py +93 -0
  160. core_pdf/impl/engine/spec/s_09_fonts/metrics.py +68 -0
  161. core_pdf/impl/engine/spec/s_09_fonts/truetype.py +37 -0
  162. core_pdf/impl/engine/spec/s_09_fonts/widths.py +138 -0
  163. core_pdf/impl/engine/spec/s_14_structure/__init__.py +4 -0
  164. core_pdf/impl/engine/spec/s_14_structure/content.py +48 -0
  165. core_pdf/impl/engine/spec/s_14_structure/tree.py +564 -0
  166. core_pdf/impl/exceptions.py +18 -0
  167. core_pdf/impl/integrations/__init__.py +4 -0
  168. core_pdf/impl/models.py +301 -0
  169. core_pdf/impl/objects.py +90 -0
  170. core_pdf/impl/primitives.py +156 -0
  171. core_pdf/impl/protocols.py +20 -0
  172. core_pdf/impl/third_party/__init__.py +3 -0
  173. core_pdf/impl/third_party/_vendor/README.rst +16 -0
  174. core_pdf/impl/third_party/_vendor/__init__.py +6 -0
  175. core_pdf/impl/third_party/_vendor/fontTools/LICENSE +21 -0
  176. core_pdf/impl/third_party/_vendor/fontTools/LICENSE.external +388 -0
  177. core_pdf/impl/third_party/_vendor/fontTools/__init__.py +8 -0
  178. core_pdf/impl/third_party/_vendor/fontTools/__main__.py +35 -0
  179. core_pdf/impl/third_party/_vendor/fontTools/afmLib.py +439 -0
  180. core_pdf/impl/third_party/_vendor/fontTools/agl.py +5233 -0
  181. core_pdf/impl/third_party/_vendor/fontTools/annotations.py +30 -0
  182. core_pdf/impl/third_party/_vendor/fontTools/cffLib/CFF2ToCFF.py +258 -0
  183. core_pdf/impl/third_party/_vendor/fontTools/cffLib/CFFToCFF2.py +305 -0
  184. core_pdf/impl/third_party/_vendor/fontTools/cffLib/__init__.py +3694 -0
  185. core_pdf/impl/third_party/_vendor/fontTools/cffLib/specializer.py +927 -0
  186. core_pdf/impl/third_party/_vendor/fontTools/cffLib/transforms.py +495 -0
  187. core_pdf/impl/third_party/_vendor/fontTools/cffLib/width.py +210 -0
  188. core_pdf/impl/third_party/_vendor/fontTools/colorLib/__init__.py +0 -0
  189. core_pdf/impl/third_party/_vendor/fontTools/colorLib/builder.py +684 -0
  190. core_pdf/impl/third_party/_vendor/fontTools/colorLib/errors.py +2 -0
  191. core_pdf/impl/third_party/_vendor/fontTools/colorLib/geometry.py +143 -0
  192. core_pdf/impl/third_party/_vendor/fontTools/colorLib/table_builder.py +223 -0
  193. core_pdf/impl/third_party/_vendor/fontTools/colorLib/unbuilder.py +81 -0
  194. core_pdf/impl/third_party/_vendor/fontTools/config/__init__.py +90 -0
  195. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/__init__.py +15 -0
  196. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/__main__.py +6 -0
  197. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/benchmark.py +54 -0
  198. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/cli.py +198 -0
  199. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/cu2qu.py +569 -0
  200. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/errors.py +77 -0
  201. core_pdf/impl/third_party/_vendor/fontTools/cu2qu/ufo.py +383 -0
  202. core_pdf/impl/third_party/_vendor/fontTools/designspaceLib/__init__.py +3358 -0
  203. core_pdf/impl/third_party/_vendor/fontTools/designspaceLib/__main__.py +6 -0
  204. core_pdf/impl/third_party/_vendor/fontTools/designspaceLib/split.py +475 -0
  205. core_pdf/impl/third_party/_vendor/fontTools/designspaceLib/statNames.py +260 -0
  206. core_pdf/impl/third_party/_vendor/fontTools/designspaceLib/types.py +147 -0
  207. core_pdf/impl/third_party/_vendor/fontTools/diff/__init__.py +441 -0
  208. core_pdf/impl/third_party/_vendor/fontTools/diff/__main__.py +6 -0
  209. core_pdf/impl/third_party/_vendor/fontTools/diff/color.py +44 -0
  210. core_pdf/impl/third_party/_vendor/fontTools/diff/diff.py +294 -0
  211. core_pdf/impl/third_party/_vendor/fontTools/diff/utils.py +28 -0
  212. core_pdf/impl/third_party/_vendor/fontTools/encodings/MacRoman.py +258 -0
  213. core_pdf/impl/third_party/_vendor/fontTools/encodings/StandardEncoding.py +258 -0
  214. core_pdf/impl/third_party/_vendor/fontTools/encodings/__init__.py +1 -0
  215. core_pdf/impl/third_party/_vendor/fontTools/encodings/codecs.py +135 -0
  216. core_pdf/impl/third_party/_vendor/fontTools/feaLib/__init__.py +4 -0
  217. core_pdf/impl/third_party/_vendor/fontTools/feaLib/__main__.py +78 -0
  218. core_pdf/impl/third_party/_vendor/fontTools/feaLib/ast.py +2143 -0
  219. core_pdf/impl/third_party/_vendor/fontTools/feaLib/builder.py +1838 -0
  220. core_pdf/impl/third_party/_vendor/fontTools/feaLib/error.py +22 -0
  221. core_pdf/impl/third_party/_vendor/fontTools/feaLib/lexer.py +287 -0
  222. core_pdf/impl/third_party/_vendor/fontTools/feaLib/location.py +12 -0
  223. core_pdf/impl/third_party/_vendor/fontTools/feaLib/lookupDebugInfo.py +12 -0
  224. core_pdf/impl/third_party/_vendor/fontTools/feaLib/parser.py +2395 -0
  225. core_pdf/impl/third_party/_vendor/fontTools/feaLib/variableScalar.py +265 -0
  226. core_pdf/impl/third_party/_vendor/fontTools/fontBuilder.py +1014 -0
  227. core_pdf/impl/third_party/_vendor/fontTools/help.py +36 -0
  228. core_pdf/impl/third_party/_vendor/fontTools/merge/__init__.py +248 -0
  229. core_pdf/impl/third_party/_vendor/fontTools/merge/__main__.py +6 -0
  230. core_pdf/impl/third_party/_vendor/fontTools/merge/base.py +81 -0
  231. core_pdf/impl/third_party/_vendor/fontTools/merge/cmap.py +173 -0
  232. core_pdf/impl/third_party/_vendor/fontTools/merge/layout.py +526 -0
  233. core_pdf/impl/third_party/_vendor/fontTools/merge/options.py +85 -0
  234. core_pdf/impl/third_party/_vendor/fontTools/merge/tables.py +352 -0
  235. core_pdf/impl/third_party/_vendor/fontTools/merge/unicode.py +78 -0
  236. core_pdf/impl/third_party/_vendor/fontTools/merge/util.py +143 -0
  237. core_pdf/impl/third_party/_vendor/fontTools/misc/__init__.py +1 -0
  238. core_pdf/impl/third_party/_vendor/fontTools/misc/arrayTools.py +424 -0
  239. core_pdf/impl/third_party/_vendor/fontTools/misc/bezierTools.py +1500 -0
  240. core_pdf/impl/third_party/_vendor/fontTools/misc/classifyTools.py +170 -0
  241. core_pdf/impl/third_party/_vendor/fontTools/misc/cliTools.py +53 -0
  242. core_pdf/impl/third_party/_vendor/fontTools/misc/configTools.py +351 -0
  243. core_pdf/impl/third_party/_vendor/fontTools/misc/cython.py +27 -0
  244. core_pdf/impl/third_party/_vendor/fontTools/misc/dictTools.py +83 -0
  245. core_pdf/impl/third_party/_vendor/fontTools/misc/eexec.py +119 -0
  246. core_pdf/impl/third_party/_vendor/fontTools/misc/encodingTools.py +72 -0
  247. core_pdf/impl/third_party/_vendor/fontTools/misc/enumTools.py +23 -0
  248. core_pdf/impl/third_party/_vendor/fontTools/misc/etree.py +456 -0
  249. core_pdf/impl/third_party/_vendor/fontTools/misc/filenames.py +245 -0
  250. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/__init__.py +68 -0
  251. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_base.py +134 -0
  252. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_copy.py +45 -0
  253. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_errors.py +54 -0
  254. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_info.py +75 -0
  255. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_osfs.py +164 -0
  256. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_path.py +67 -0
  257. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_subfs.py +92 -0
  258. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_tempfs.py +34 -0
  259. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_tools.py +34 -0
  260. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_walk.py +55 -0
  261. core_pdf/impl/third_party/_vendor/fontTools/misc/filesystem/_zipfs.py +204 -0
  262. core_pdf/impl/third_party/_vendor/fontTools/misc/fixedTools.py +253 -0
  263. core_pdf/impl/third_party/_vendor/fontTools/misc/iftSparseBitSet.py +311 -0
  264. core_pdf/impl/third_party/_vendor/fontTools/misc/intTools.py +25 -0
  265. core_pdf/impl/third_party/_vendor/fontTools/misc/iterTools.py +12 -0
  266. core_pdf/impl/third_party/_vendor/fontTools/misc/lazyTools.py +42 -0
  267. core_pdf/impl/third_party/_vendor/fontTools/misc/loggingTools.py +543 -0
  268. core_pdf/impl/third_party/_vendor/fontTools/misc/macCreatorType.py +56 -0
  269. core_pdf/impl/third_party/_vendor/fontTools/misc/macRes.py +261 -0
  270. core_pdf/impl/third_party/_vendor/fontTools/misc/plistlib/__init__.py +681 -0
  271. core_pdf/impl/third_party/_vendor/fontTools/misc/plistlib/py.typed +0 -0
  272. core_pdf/impl/third_party/_vendor/fontTools/misc/psCharStrings.py +1511 -0
  273. core_pdf/impl/third_party/_vendor/fontTools/misc/psLib.py +398 -0
  274. core_pdf/impl/third_party/_vendor/fontTools/misc/psOperators.py +572 -0
  275. core_pdf/impl/third_party/_vendor/fontTools/misc/py23.py +96 -0
  276. core_pdf/impl/third_party/_vendor/fontTools/misc/roundTools.py +110 -0
  277. core_pdf/impl/third_party/_vendor/fontTools/misc/sstruct.py +227 -0
  278. core_pdf/impl/third_party/_vendor/fontTools/misc/symfont.py +242 -0
  279. core_pdf/impl/third_party/_vendor/fontTools/misc/testTools.py +233 -0
  280. core_pdf/impl/third_party/_vendor/fontTools/misc/textTools.py +156 -0
  281. core_pdf/impl/third_party/_vendor/fontTools/misc/timeTools.py +88 -0
  282. core_pdf/impl/third_party/_vendor/fontTools/misc/transform.py +516 -0
  283. core_pdf/impl/third_party/_vendor/fontTools/misc/treeTools.py +45 -0
  284. core_pdf/impl/third_party/_vendor/fontTools/misc/vector.py +147 -0
  285. core_pdf/impl/third_party/_vendor/fontTools/misc/visitor.py +158 -0
  286. core_pdf/impl/third_party/_vendor/fontTools/misc/xmlReader.py +188 -0
  287. core_pdf/impl/third_party/_vendor/fontTools/misc/xmlWriter.py +240 -0
  288. core_pdf/impl/third_party/_vendor/fontTools/mtiLib/__init__.py +1400 -0
  289. core_pdf/impl/third_party/_vendor/fontTools/mtiLib/__main__.py +5 -0
  290. core_pdf/impl/third_party/_vendor/fontTools/otlLib/__init__.py +1 -0
  291. core_pdf/impl/third_party/_vendor/fontTools/otlLib/builder.py +3481 -0
  292. core_pdf/impl/third_party/_vendor/fontTools/otlLib/error.py +11 -0
  293. core_pdf/impl/third_party/_vendor/fontTools/otlLib/maxContextCalc.py +96 -0
  294. core_pdf/impl/third_party/_vendor/fontTools/otlLib/optimize/__init__.py +53 -0
  295. core_pdf/impl/third_party/_vendor/fontTools/otlLib/optimize/__main__.py +6 -0
  296. core_pdf/impl/third_party/_vendor/fontTools/otlLib/optimize/gpos.py +439 -0
  297. core_pdf/impl/third_party/_vendor/fontTools/pens/__init__.py +1 -0
  298. core_pdf/impl/third_party/_vendor/fontTools/pens/areaPen.py +52 -0
  299. core_pdf/impl/third_party/_vendor/fontTools/pens/basePen.py +475 -0
  300. core_pdf/impl/third_party/_vendor/fontTools/pens/boundsPen.py +98 -0
  301. core_pdf/impl/third_party/_vendor/fontTools/pens/cairoPen.py +26 -0
  302. core_pdf/impl/third_party/_vendor/fontTools/pens/cocoaPen.py +26 -0
  303. core_pdf/impl/third_party/_vendor/fontTools/pens/cu2quPen.py +325 -0
  304. core_pdf/impl/third_party/_vendor/fontTools/pens/explicitClosingLinePen.py +101 -0
  305. core_pdf/impl/third_party/_vendor/fontTools/pens/filterPen.py +433 -0
  306. core_pdf/impl/third_party/_vendor/fontTools/pens/freetypePen.py +462 -0
  307. core_pdf/impl/third_party/_vendor/fontTools/pens/hashPointPen.py +89 -0
  308. core_pdf/impl/third_party/_vendor/fontTools/pens/momentsPen.py +879 -0
  309. core_pdf/impl/third_party/_vendor/fontTools/pens/perimeterPen.py +69 -0
  310. core_pdf/impl/third_party/_vendor/fontTools/pens/pointInsidePen.py +192 -0
  311. core_pdf/impl/third_party/_vendor/fontTools/pens/pointPen.py +653 -0
  312. core_pdf/impl/third_party/_vendor/fontTools/pens/qtPen.py +29 -0
  313. core_pdf/impl/third_party/_vendor/fontTools/pens/qu2cuPen.py +105 -0
  314. core_pdf/impl/third_party/_vendor/fontTools/pens/quartzPen.py +43 -0
  315. core_pdf/impl/third_party/_vendor/fontTools/pens/recordingPen.py +335 -0
  316. core_pdf/impl/third_party/_vendor/fontTools/pens/reportLabPen.py +79 -0
  317. core_pdf/impl/third_party/_vendor/fontTools/pens/reverseContourPen.py +96 -0
  318. core_pdf/impl/third_party/_vendor/fontTools/pens/roundingPen.py +130 -0
  319. core_pdf/impl/third_party/_vendor/fontTools/pens/statisticsPen.py +312 -0
  320. core_pdf/impl/third_party/_vendor/fontTools/pens/svgPathPen.py +310 -0
  321. core_pdf/impl/third_party/_vendor/fontTools/pens/t2CharStringPen.py +88 -0
  322. core_pdf/impl/third_party/_vendor/fontTools/pens/teePen.py +55 -0
  323. core_pdf/impl/third_party/_vendor/fontTools/pens/transformPen.py +115 -0
  324. core_pdf/impl/third_party/_vendor/fontTools/pens/ttGlyphPen.py +335 -0
  325. core_pdf/impl/third_party/_vendor/fontTools/pens/wxPen.py +29 -0
  326. core_pdf/impl/third_party/_vendor/fontTools/qu2cu/__init__.py +15 -0
  327. core_pdf/impl/third_party/_vendor/fontTools/qu2cu/__main__.py +7 -0
  328. core_pdf/impl/third_party/_vendor/fontTools/qu2cu/benchmark.py +56 -0
  329. core_pdf/impl/third_party/_vendor/fontTools/qu2cu/cli.py +129 -0
  330. core_pdf/impl/third_party/_vendor/fontTools/qu2cu/qu2cu.py +433 -0
  331. core_pdf/impl/third_party/_vendor/fontTools/subset/__init__.py +4096 -0
  332. core_pdf/impl/third_party/_vendor/fontTools/subset/__main__.py +6 -0
  333. core_pdf/impl/third_party/_vendor/fontTools/subset/cff.py +184 -0
  334. core_pdf/impl/third_party/_vendor/fontTools/subset/svg.py +252 -0
  335. core_pdf/impl/third_party/_vendor/fontTools/subset/util.py +25 -0
  336. core_pdf/impl/third_party/_vendor/fontTools/svgLib/__init__.py +3 -0
  337. core_pdf/impl/third_party/_vendor/fontTools/svgLib/path/__init__.py +65 -0
  338. core_pdf/impl/third_party/_vendor/fontTools/svgLib/path/arc.py +154 -0
  339. core_pdf/impl/third_party/_vendor/fontTools/svgLib/path/parser.py +322 -0
  340. core_pdf/impl/third_party/_vendor/fontTools/svgLib/path/shapes.py +185 -0
  341. core_pdf/impl/third_party/_vendor/fontTools/t1Lib/__init__.py +648 -0
  342. core_pdf/impl/third_party/_vendor/fontTools/tfmLib.py +460 -0
  343. core_pdf/impl/third_party/_vendor/fontTools/ttLib/__init__.py +30 -0
  344. core_pdf/impl/third_party/_vendor/fontTools/ttLib/__main__.py +148 -0
  345. core_pdf/impl/third_party/_vendor/fontTools/ttLib/macUtils.py +54 -0
  346. core_pdf/impl/third_party/_vendor/fontTools/ttLib/removeOverlaps.py +395 -0
  347. core_pdf/impl/third_party/_vendor/fontTools/ttLib/reorderGlyphs.py +285 -0
  348. core_pdf/impl/third_party/_vendor/fontTools/ttLib/scaleUpem.py +436 -0
  349. core_pdf/impl/third_party/_vendor/fontTools/ttLib/sfnt.py +664 -0
  350. core_pdf/impl/third_party/_vendor/fontTools/ttLib/standardGlyphOrder.py +271 -0
  351. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/B_A_S_E_.py +14 -0
  352. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
  353. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/C_B_D_T_.py +113 -0
  354. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/C_B_L_C_.py +19 -0
  355. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/C_F_F_.py +61 -0
  356. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/C_F_F__2.py +26 -0
  357. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/C_O_L_R_.py +165 -0
  358. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/C_P_A_L_.py +305 -0
  359. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/D_S_I_G_.py +170 -0
  360. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/D__e_b_g.py +35 -0
  361. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/DefaultTable.py +63 -0
  362. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/E_B_D_T_.py +835 -0
  363. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/E_B_L_C_.py +718 -0
  364. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/F_F_T_M_.py +52 -0
  365. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/F__e_a_t.py +159 -0
  366. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/G_D_E_F_.py +13 -0
  367. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/G_P_O_S_.py +14 -0
  368. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/G_S_U_B_.py +13 -0
  369. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/G_V_A_R_.py +5 -0
  370. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/G__l_a_t.py +235 -0
  371. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/G__l_o_c.py +85 -0
  372. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/H_V_A_R_.py +13 -0
  373. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/I_F_T_.py +12 -0
  374. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/I_F_T_X_.py +12 -0
  375. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/J_S_T_F_.py +13 -0
  376. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/L_T_S_H_.py +58 -0
  377. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/M_A_T_H_.py +13 -0
  378. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/M_V_A_R_.py +13 -0
  379. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/O_S_2f_2.py +752 -0
  380. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/S_T_A_T_.py +15 -0
  381. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/S_V_G_.py +223 -0
  382. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/S__i_l_f.py +1040 -0
  383. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/S__i_l_l.py +92 -0
  384. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_B_.py +13 -0
  385. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_C_.py +14 -0
  386. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_D_.py +13 -0
  387. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_J_.py +13 -0
  388. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_P_.py +13 -0
  389. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_S_.py +13 -0
  390. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I_V_.py +26 -0
  391. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I__0.py +70 -0
  392. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I__1.py +163 -0
  393. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I__2.py +17 -0
  394. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I__3.py +22 -0
  395. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_S_I__5.py +60 -0
  396. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/T_T_F_A_.py +14 -0
  397. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/TupleVariation.py +886 -0
  398. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/V_A_R_C_.py +12 -0
  399. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/V_D_M_X_.py +249 -0
  400. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/V_O_R_G_.py +165 -0
  401. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/V_V_A_R_.py +13 -0
  402. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/__init__.py +97 -0
  403. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_a_n_k_r.py +15 -0
  404. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_a_v_a_r.py +200 -0
  405. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_b_g_c_l.py +136 -0
  406. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_b_s_l_n.py +15 -0
  407. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_c_i_d_g.py +24 -0
  408. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_c_m_a_p.py +1597 -0
  409. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_c_v_a_r.py +94 -0
  410. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_c_v_t.py +56 -0
  411. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_f_e_a_t.py +15 -0
  412. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_f_p_g_m.py +62 -0
  413. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_f_v_a_r.py +259 -0
  414. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_g_a_s_p.py +63 -0
  415. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_g_c_i_d.py +13 -0
  416. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_g_l_y_f.py +2302 -0
  417. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_g_v_a_r.py +340 -0
  418. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_h_d_m_x.py +127 -0
  419. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_h_e_a_d.py +130 -0
  420. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_h_h_e_a.py +147 -0
  421. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_h_m_t_x.py +164 -0
  422. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_k_e_r_n.py +289 -0
  423. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_l_c_a_r.py +13 -0
  424. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_l_o_c_a.py +70 -0
  425. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_l_t_a_g.py +72 -0
  426. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_m_a_x_p.py +147 -0
  427. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_m_e_t_a.py +112 -0
  428. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_m_o_r_t.py +14 -0
  429. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_m_o_r_x.py +15 -0
  430. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_n_a_m_e.py +1242 -0
  431. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_o_p_b_d.py +14 -0
  432. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_p_o_s_t.py +319 -0
  433. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_p_r_e_p.py +16 -0
  434. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_p_r_o_p.py +12 -0
  435. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_s_b_i_x.py +129 -0
  436. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_t_r_a_k.py +330 -0
  437. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_v_h_e_a.py +139 -0
  438. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/_v_m_t_x.py +19 -0
  439. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/asciiTable.py +20 -0
  440. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/grUtils.py +92 -0
  441. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/otBase.py +1467 -0
  442. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/otConverters.py +2334 -0
  443. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/otData.py +5983 -0
  444. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/otDataSchema.py +37 -0
  445. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/otTables.py +2733 -0
  446. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/otTraverse.py +163 -0
  447. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/sbixGlyph.py +149 -0
  448. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/sbixStrike.py +177 -0
  449. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/table_API_readme.txt +91 -0
  450. core_pdf/impl/third_party/_vendor/fontTools/ttLib/tables/ttProgram.py +596 -0
  451. core_pdf/impl/third_party/_vendor/fontTools/ttLib/ttCollection.py +125 -0
  452. core_pdf/impl/third_party/_vendor/fontTools/ttLib/ttFont.py +1696 -0
  453. core_pdf/impl/third_party/_vendor/fontTools/ttLib/ttGlyphSet.py +490 -0
  454. core_pdf/impl/third_party/_vendor/fontTools/ttLib/ttVisitor.py +32 -0
  455. core_pdf/impl/third_party/_vendor/fontTools/ttLib/woff2.py +1680 -0
  456. core_pdf/impl/third_party/_vendor/fontTools/ttx.py +479 -0
  457. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/__init__.py +2575 -0
  458. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/converters.py +407 -0
  459. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/errors.py +30 -0
  460. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/etree.py +6 -0
  461. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/filenames.py +356 -0
  462. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/glifLib.py +2123 -0
  463. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/kerning.py +141 -0
  464. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/plistlib.py +47 -0
  465. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/pointPen.py +6 -0
  466. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/utils.py +107 -0
  467. core_pdf/impl/third_party/_vendor/fontTools/ufoLib/validators.py +1197 -0
  468. core_pdf/impl/third_party/_vendor/fontTools/unicode.py +50 -0
  469. core_pdf/impl/third_party/_vendor/fontTools/unicodedata/Blocks.py +817 -0
  470. core_pdf/impl/third_party/_vendor/fontTools/unicodedata/Mirrored.py +446 -0
  471. core_pdf/impl/third_party/_vendor/fontTools/unicodedata/OTTags.py +50 -0
  472. core_pdf/impl/third_party/_vendor/fontTools/unicodedata/ScriptExtensions.py +832 -0
  473. core_pdf/impl/third_party/_vendor/fontTools/unicodedata/Scripts.py +3639 -0
  474. core_pdf/impl/third_party/_vendor/fontTools/unicodedata/__init__.py +306 -0
  475. core_pdf/impl/third_party/_vendor/fontTools/varLib/__init__.py +1582 -0
  476. core_pdf/impl/third_party/_vendor/fontTools/varLib/__main__.py +6 -0
  477. core_pdf/impl/third_party/_vendor/fontTools/varLib/avar/__init__.py +0 -0
  478. core_pdf/impl/third_party/_vendor/fontTools/varLib/avar/__main__.py +72 -0
  479. core_pdf/impl/third_party/_vendor/fontTools/varLib/avar/build.py +79 -0
  480. core_pdf/impl/third_party/_vendor/fontTools/varLib/avar/map.py +124 -0
  481. core_pdf/impl/third_party/_vendor/fontTools/varLib/avar/plan.py +1004 -0
  482. core_pdf/impl/third_party/_vendor/fontTools/varLib/avar/unbuild.py +274 -0
  483. core_pdf/impl/third_party/_vendor/fontTools/varLib/avarPlanner.py +8 -0
  484. core_pdf/impl/third_party/_vendor/fontTools/varLib/builder.py +215 -0
  485. core_pdf/impl/third_party/_vendor/fontTools/varLib/cff.py +631 -0
  486. core_pdf/impl/third_party/_vendor/fontTools/varLib/errors.py +219 -0
  487. core_pdf/impl/third_party/_vendor/fontTools/varLib/featureVars.py +703 -0
  488. core_pdf/impl/third_party/_vendor/fontTools/varLib/hvar.py +113 -0
  489. core_pdf/impl/third_party/_vendor/fontTools/varLib/instancer/__init__.py +2049 -0
  490. core_pdf/impl/third_party/_vendor/fontTools/varLib/instancer/__main__.py +5 -0
  491. core_pdf/impl/third_party/_vendor/fontTools/varLib/instancer/featureVars.py +190 -0
  492. core_pdf/impl/third_party/_vendor/fontTools/varLib/instancer/names.py +388 -0
  493. core_pdf/impl/third_party/_vendor/fontTools/varLib/instancer/solver.py +309 -0
  494. core_pdf/impl/third_party/_vendor/fontTools/varLib/interpolatable.py +1209 -0
  495. core_pdf/impl/third_party/_vendor/fontTools/varLib/interpolatableHelpers.py +360 -0
  496. core_pdf/impl/third_party/_vendor/fontTools/varLib/interpolatablePlot.py +1264 -0
  497. core_pdf/impl/third_party/_vendor/fontTools/varLib/interpolatableTestContourOrder.py +81 -0
  498. core_pdf/impl/third_party/_vendor/fontTools/varLib/interpolatableTestStartingPoint.py +109 -0
  499. core_pdf/impl/third_party/_vendor/fontTools/varLib/interpolate_layout.py +124 -0
  500. core_pdf/impl/third_party/_vendor/fontTools/varLib/iup.py +490 -0
  501. core_pdf/impl/third_party/_vendor/fontTools/varLib/merger.py +1717 -0
  502. core_pdf/impl/third_party/_vendor/fontTools/varLib/models.py +663 -0
  503. core_pdf/impl/third_party/_vendor/fontTools/varLib/multiVarStore.py +253 -0
  504. core_pdf/impl/third_party/_vendor/fontTools/varLib/mutator.py +529 -0
  505. core_pdf/impl/third_party/_vendor/fontTools/varLib/mvar.py +40 -0
  506. core_pdf/impl/third_party/_vendor/fontTools/varLib/plot.py +238 -0
  507. core_pdf/impl/third_party/_vendor/fontTools/varLib/stat.py +149 -0
  508. core_pdf/impl/third_party/_vendor/fontTools/varLib/varStore.py +739 -0
  509. core_pdf/impl/third_party/_vendor/fontTools/voltLib/__init__.py +5 -0
  510. core_pdf/impl/third_party/_vendor/fontTools/voltLib/__main__.py +206 -0
  511. core_pdf/impl/third_party/_vendor/fontTools/voltLib/ast.py +452 -0
  512. core_pdf/impl/third_party/_vendor/fontTools/voltLib/error.py +12 -0
  513. core_pdf/impl/third_party/_vendor/fontTools/voltLib/lexer.py +99 -0
  514. core_pdf/impl/third_party/_vendor/fontTools/voltLib/parser.py +664 -0
  515. core_pdf/impl/third_party/_vendor/fontTools/voltLib/voltToFea.py +911 -0
  516. core_pdf/impl/third_party/_vendor/fontTools.pyi +1 -0
  517. core_pdf/impl/third_party/_vendor/vendor.txt +1 -0
  518. core_pdf/impl/third_party/ccitt.py +789 -0
  519. core_pdf/impl/third_party/cff.py +830 -0
  520. core_pdf/impl/third_party/cid/5014.CIDFont_Spec.pdf +0 -0
  521. core_pdf/impl/third_party/cid/__init__.py +26 -0
  522. core_pdf/impl/third_party/cid/cmap.py +909 -0
  523. core_pdf/impl/third_party/cid/encoding.py +24 -0
  524. core_pdf/impl/third_party/cid/pdf_string.py +67 -0
  525. core_pdf/impl/third_party/cid/resource_loader.py +81 -0
  526. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-0 +134 -0
  527. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-1 +145 -0
  528. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-2 +146 -0
  529. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-3 +151 -0
  530. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-4 +152 -0
  531. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-5 +152 -0
  532. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-6 +152 -0
  533. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/Adobe-CNS1-7 +150 -0
  534. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/B5-H +331 -0
  535. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/B5-V +88 -0
  536. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/B5pc-H +335 -0
  537. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/B5pc-V +88 -0
  538. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/CNS-EUC-H +488 -0
  539. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/CNS-EUC-V +536 -0
  540. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/CNS1-H +235 -0
  541. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/CNS1-V +88 -0
  542. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/CNS2-H +158 -0
  543. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/CNS2-V +74 -0
  544. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/ETHK-B5-H +1326 -0
  545. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/ETHK-B5-V +88 -0
  546. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/ETen-B5-H +341 -0
  547. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/ETen-B5-V +89 -0
  548. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/ETenms-B5-H +77 -0
  549. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/ETenms-B5-V +97 -0
  550. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKdla-B5-H +1132 -0
  551. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKdla-B5-V +87 -0
  552. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKdlb-B5-H +1014 -0
  553. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKdlb-B5-V +87 -0
  554. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKgccs-B5-H +647 -0
  555. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKgccs-B5-V +87 -0
  556. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKm314-B5-H +637 -0
  557. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKm314-B5-V +87 -0
  558. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKm471-B5-H +787 -0
  559. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKm471-B5-V +87 -0
  560. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKscs-B5-H +1329 -0
  561. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/HKscs-B5-V +88 -0
  562. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UCS2-H +16990 -0
  563. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UCS2-V +88 -0
  564. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UTF16-H +19146 -0
  565. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UTF16-V +92 -0
  566. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UTF32-H +19144 -0
  567. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UTF32-V +92 -0
  568. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UTF8-H +19209 -0
  569. core_pdf/impl/third_party/cid/resources/Adobe-CNS1-7/CMap/UniCNS-UTF8-V +92 -0
  570. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-0 +109 -0
  571. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-1 +117 -0
  572. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-2 +165 -0
  573. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-3 +165 -0
  574. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-4 +195 -0
  575. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-5 +200 -0
  576. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/Adobe-GB1-6 +199 -0
  577. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GB-EUC-H +171 -0
  578. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GB-EUC-V +96 -0
  579. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GB-H +164 -0
  580. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GB-V +96 -0
  581. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBK-EUC-H +4271 -0
  582. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBK-EUC-V +95 -0
  583. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBK2K-H +5517 -0
  584. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBK2K-V +116 -0
  585. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBKp-EUC-H +4270 -0
  586. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBKp-EUC-V +95 -0
  587. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBT-EUC-H +2430 -0
  588. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBT-EUC-V +96 -0
  589. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBT-H +2423 -0
  590. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBT-V +96 -0
  591. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBTpc-EUC-H +2432 -0
  592. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBTpc-EUC-V +96 -0
  593. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBpc-EUC-H +173 -0
  594. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/GBpc-EUC-V +96 -0
  595. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UCS2-H +14319 -0
  596. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UCS2-V +99 -0
  597. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UTF16-H +14567 -0
  598. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UTF16-V +102 -0
  599. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UTF32-H +14565 -0
  600. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UTF32-V +102 -0
  601. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UTF8-H +14772 -0
  602. core_pdf/impl/third_party/cid/resources/Adobe-GB1-6/CMap/UniGB-UTF8-V +102 -0
  603. core_pdf/impl/third_party/cid/resources/Adobe-Identity-0/CMap/Identity-H +337 -0
  604. core_pdf/impl/third_party/cid/resources/Adobe-Identity-0/CMap/Identity-V +71 -0
  605. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78-EUC-H +724 -0
  606. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78-EUC-V +102 -0
  607. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78-H +716 -0
  608. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78-RKSJ-H +726 -0
  609. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78-RKSJ-V +102 -0
  610. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78-V +102 -0
  611. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78ms-RKSJ-H +816 -0
  612. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/78ms-RKSJ-V +153 -0
  613. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/83pv-RKSJ-H +312 -0
  614. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/90ms-RKSJ-H +257 -0
  615. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/90ms-RKSJ-V +154 -0
  616. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/90msp-RKSJ-H +255 -0
  617. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/90msp-RKSJ-V +153 -0
  618. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/90pv-RKSJ-H +353 -0
  619. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/90pv-RKSJ-V +127 -0
  620. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Add-H +725 -0
  621. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Add-RKSJ-H +736 -0
  622. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Add-RKSJ-V +133 -0
  623. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Add-V +133 -0
  624. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-0 +111 -0
  625. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-1 +111 -0
  626. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-2 +113 -0
  627. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-3 +114 -0
  628. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-4 +138 -0
  629. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-5 +157 -0
  630. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-6 +168 -0
  631. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Adobe-Japan1-7 +166 -0
  632. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/EUC-H +205 -0
  633. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/EUC-V +103 -0
  634. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Ext-H +755 -0
  635. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Ext-RKSJ-H +766 -0
  636. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Ext-RKSJ-V +115 -0
  637. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Ext-V +115 -0
  638. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/H +198 -0
  639. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Hankaku +86 -0
  640. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Hiragana +84 -0
  641. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Katakana +78 -0
  642. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/NWP-H +855 -0
  643. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/NWP-V +123 -0
  644. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/RKSJ-H +208 -0
  645. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/RKSJ-V +103 -0
  646. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/Roman +77 -0
  647. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-H +8868 -0
  648. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-HW-H +79 -0
  649. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-HW-V +277 -0
  650. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UCS2-V +273 -0
  651. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UTF16-H +14483 -0
  652. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UTF16-V +305 -0
  653. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UTF32-H +14481 -0
  654. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UTF32-V +305 -0
  655. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UTF8-H +14511 -0
  656. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS-UTF8-V +306 -0
  657. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS2004-UTF16-H +14486 -0
  658. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS2004-UTF16-V +305 -0
  659. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS2004-UTF32-H +14484 -0
  660. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS2004-UTF32-V +305 -0
  661. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS2004-UTF8-H +14514 -0
  662. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJIS2004-UTF8-V +306 -0
  663. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISPro-UCS2-HW-V +285 -0
  664. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISPro-UCS2-V +278 -0
  665. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISPro-UTF8-V +282 -0
  666. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISX0213-UTF32-H +14475 -0
  667. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISX0213-UTF32-V +301 -0
  668. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISX02132004-UTF32-H +14478 -0
  669. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/UniJISX02132004-UTF32-V +301 -0
  670. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/V +103 -0
  671. core_pdf/impl/third_party/cid/resources/Adobe-Japan1-7/CMap/WP-Symbol +103 -0
  672. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-0 +87 -0
  673. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-1 +94 -0
  674. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-2 +120 -0
  675. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-3 +121 -0
  676. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-4 +122 -0
  677. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-5 +123 -0
  678. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-6 +131 -0
  679. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-7 +149 -0
  680. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-8 +163 -0
  681. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/Adobe-KR-9 +165 -0
  682. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/UniAKR-UTF16-H +12595 -0
  683. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/UniAKR-UTF32-H +12589 -0
  684. core_pdf/impl/third_party/cid/resources/Adobe-KR-9/CMap/UniAKR-UTF8-H +12687 -0
  685. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/Adobe-Korea1-0 +114 -0
  686. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/Adobe-Korea1-1 +149 -0
  687. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/Adobe-Korea1-2 +149 -0
  688. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSC-EUC-H +560 -0
  689. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSC-EUC-V +92 -0
  690. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSC-H +554 -0
  691. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSC-Johab-H +4343 -0
  692. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSC-Johab-V +92 -0
  693. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSC-V +92 -0
  694. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSCms-UHC-H +774 -0
  695. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSCms-UHC-HW-H +773 -0
  696. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSCms-UHC-HW-V +91 -0
  697. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSCms-UHC-V +92 -0
  698. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSCpc-EUC-H +606 -0
  699. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/KSCpc-EUC-V +92 -0
  700. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UCS2-H +8723 -0
  701. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UCS2-V +93 -0
  702. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UTF16-H +8893 -0
  703. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UTF16-V +97 -0
  704. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UTF32-H +8891 -0
  705. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UTF32-V +97 -0
  706. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UTF8-H +8989 -0
  707. core_pdf/impl/third_party/cid/resources/Adobe-Korea1-2/CMap/UniKS-UTF8-V +97 -0
  708. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/Adobe-Manga1-0 +147 -0
  709. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/UniManga-UTF16-H +5831 -0
  710. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/UniManga-UTF16-V +82 -0
  711. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/UniManga-UTF32-H +5829 -0
  712. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/UniManga-UTF32-V +82 -0
  713. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/UniManga-UTF8-H +5955 -0
  714. core_pdf/impl/third_party/cid/resources/Adobe-Manga1-0/CMap/UniManga-UTF8-V +83 -0
  715. core_pdf/impl/third_party/cid/resources/LICENSE.md +28 -0
  716. core_pdf/impl/third_party/cid/resources/README.md +378 -0
  717. core_pdf/impl/third_party/cid/resources/VERSIONS.txt +218 -0
  718. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/Adobe-Japan2-0 +102 -0
  719. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/Hojo-EUC-H +160 -0
  720. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/Hojo-EUC-V +74 -0
  721. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/Hojo-H +160 -0
  722. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/Hojo-V +74 -0
  723. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UCS2-H +4434 -0
  724. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UCS2-V +73 -0
  725. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UTF16-H +4466 -0
  726. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UTF16-V +73 -0
  727. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UTF32-H +4460 -0
  728. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UTF32-V +73 -0
  729. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UTF8-H +4489 -0
  730. core_pdf/impl/third_party/cid/resources/deprecated/Adobe-Japan2-0/CMap/UniHojo-UTF8-V +73 -0
  731. core_pdf/impl/third_party/cid/widths.py +198 -0
  732. core_pdf/impl/third_party/filters/__init__.py +0 -0
  733. core_pdf/impl/third_party/filters/predictors.py +193 -0
  734. core_pdf/impl/third_party/jbig2.py +992 -0
  735. core_pdf/impl/third_party/truetype.py +407 -0
  736. core_pdf/impl/types.py +62 -0
  737. core_pdf/py.typed +1 -0
  738. core_pdf-0.0.2.dist-info/METADATA +32 -0
  739. core_pdf-0.0.2.dist-info/RECORD +741 -0
  740. core_pdf-0.0.2.dist-info/WHEEL +4 -0
  741. core_pdf-0.0.2.dist-info/licenses/LICENSE.txt +661 -0
@@ -0,0 +1,2733 @@
1
+ # coding: utf-8
2
+ """fontTools.ttLib.tables.otTables -- A collection of classes representing the various
3
+ OpenType subtables.
4
+
5
+ Most are constructed upon import from data in otData.py, all are populated with
6
+ converter objects from otConverters.py.
7
+ """
8
+
9
+ import copy
10
+ from enum import IntEnum
11
+ from functools import reduce
12
+ from math import radians
13
+ import itertools
14
+ from collections import defaultdict, namedtuple
15
+ from core_pdf.impl.third_party._vendor.fontTools.ttLib import OPTIMIZE_FONT_SPEED
16
+ from core_pdf.impl.third_party._vendor.fontTools.ttLib.tables.TupleVariation import TupleVariation
17
+ from core_pdf.impl.third_party._vendor.fontTools.ttLib.tables.otTraverse import dfs_base_table
18
+ from core_pdf.impl.third_party._vendor.fontTools.misc.arrayTools import quantizeRect
19
+ from core_pdf.impl.third_party._vendor.fontTools.misc.roundTools import otRound
20
+ from core_pdf.impl.third_party._vendor.fontTools.misc.transform import Transform, Identity, DecomposedTransform
21
+ from core_pdf.impl.third_party._vendor.fontTools.misc.textTools import bytesjoin, pad, safeEval
22
+ from core_pdf.impl.third_party._vendor.fontTools.misc.vector import Vector
23
+ from core_pdf.impl.third_party._vendor.fontTools.pens.boundsPen import ControlBoundsPen
24
+ from core_pdf.impl.third_party._vendor.fontTools.pens.transformPen import TransformPen
25
+ from .otBase import (
26
+ BaseTable,
27
+ FormatSwitchingBaseTable,
28
+ ValueRecord,
29
+ CountReference,
30
+ getFormatSwitchingBaseTableClass,
31
+ )
32
+ from core_pdf.impl.third_party._vendor.fontTools.misc.fixedTools import (
33
+ fixedToFloat as fi2fl,
34
+ floatToFixed as fl2fi,
35
+ floatToFixedToStr as fl2str,
36
+ strToFixedToFloat as str2fl,
37
+ )
38
+ from core_pdf.impl.third_party._vendor.fontTools.feaLib.lookupDebugInfo import LookupDebugInfo, LOOKUP_DEBUG_INFO_KEY
39
+ import logging
40
+ import struct
41
+ import array
42
+ import sys
43
+ from enum import IntFlag
44
+ from typing import TYPE_CHECKING, Iterator, List, Optional, Set
45
+
46
+ if TYPE_CHECKING:
47
+ from core_pdf.impl.third_party._vendor.fontTools.ttLib.ttGlyphSet import _TTGlyphSet
48
+
49
+
50
+ log = logging.getLogger(__name__)
51
+
52
+
53
+ class VarComponentFlags(IntFlag):
54
+ RESET_UNSPECIFIED_AXES = 1 << 0
55
+
56
+ HAVE_AXES = 1 << 1
57
+
58
+ AXIS_VALUES_HAVE_VARIATION = 1 << 2
59
+ TRANSFORM_HAS_VARIATION = 1 << 3
60
+
61
+ HAVE_TRANSLATE_X = 1 << 4
62
+ HAVE_TRANSLATE_Y = 1 << 5
63
+ HAVE_ROTATION = 1 << 6
64
+
65
+ HAVE_CONDITION = 1 << 7
66
+
67
+ HAVE_SCALE_X = 1 << 8
68
+ HAVE_SCALE_Y = 1 << 9
69
+ HAVE_TCENTER_X = 1 << 10
70
+ HAVE_TCENTER_Y = 1 << 11
71
+
72
+ GID_IS_24BIT = 1 << 12
73
+
74
+ HAVE_SKEW_X = 1 << 13
75
+ HAVE_SKEW_Y = 1 << 14
76
+
77
+ RESERVED_MASK = (1 << 32) - (1 << 15)
78
+
79
+
80
+ VarTransformMappingValues = namedtuple(
81
+ "VarTransformMappingValues",
82
+ ["flag", "fractionalBits", "scale", "defaultValue"],
83
+ )
84
+
85
+ VAR_TRANSFORM_MAPPING = {
86
+ "translateX": VarTransformMappingValues(
87
+ VarComponentFlags.HAVE_TRANSLATE_X, 0, 1, 0
88
+ ),
89
+ "translateY": VarTransformMappingValues(
90
+ VarComponentFlags.HAVE_TRANSLATE_Y, 0, 1, 0
91
+ ),
92
+ "rotation": VarTransformMappingValues(VarComponentFlags.HAVE_ROTATION, 12, 180, 0),
93
+ "scaleX": VarTransformMappingValues(VarComponentFlags.HAVE_SCALE_X, 10, 1, 1),
94
+ "scaleY": VarTransformMappingValues(VarComponentFlags.HAVE_SCALE_Y, 10, 1, 1),
95
+ "skewX": VarTransformMappingValues(VarComponentFlags.HAVE_SKEW_X, 12, -180, 0),
96
+ "skewY": VarTransformMappingValues(VarComponentFlags.HAVE_SKEW_Y, 12, 180, 0),
97
+ "tCenterX": VarTransformMappingValues(VarComponentFlags.HAVE_TCENTER_X, 0, 1, 0),
98
+ "tCenterY": VarTransformMappingValues(VarComponentFlags.HAVE_TCENTER_Y, 0, 1, 0),
99
+ }
100
+
101
+ # Probably should be somewhere in fontTools.misc
102
+ _packer = {
103
+ 1: lambda v: struct.pack(">B", v),
104
+ 2: lambda v: struct.pack(">H", v),
105
+ 3: lambda v: struct.pack(">L", v)[1:],
106
+ 4: lambda v: struct.pack(">L", v),
107
+ }
108
+ _unpacker = {
109
+ 1: lambda v: struct.unpack(">B", v)[0],
110
+ 2: lambda v: struct.unpack(">H", v)[0],
111
+ 3: lambda v: struct.unpack(">L", b"\0" + v)[0],
112
+ 4: lambda v: struct.unpack(">L", v)[0],
113
+ }
114
+
115
+
116
+ def _read_uint32var(data, i):
117
+ """Read a variable-length number from data starting at index i.
118
+
119
+ Return the number and the next index.
120
+ """
121
+
122
+ b0 = data[i]
123
+ if b0 < 0x80:
124
+ return b0, i + 1
125
+ elif b0 < 0xC0:
126
+ return (b0 - 0x80) << 8 | data[i + 1], i + 2
127
+ elif b0 < 0xE0:
128
+ return (b0 - 0xC0) << 16 | data[i + 1] << 8 | data[i + 2], i + 3
129
+ elif b0 < 0xF0:
130
+ return (b0 - 0xE0) << 24 | data[i + 1] << 16 | data[i + 2] << 8 | data[
131
+ i + 3
132
+ ], i + 4
133
+ else:
134
+ return (b0 - 0xF0) << 32 | data[i + 1] << 24 | data[i + 2] << 16 | data[
135
+ i + 3
136
+ ] << 8 | data[i + 4], i + 5
137
+
138
+
139
+ def _write_uint32var(v):
140
+ """Write a variable-length number.
141
+
142
+ Return the data.
143
+ """
144
+ if v < 0x80:
145
+ return struct.pack(">B", v)
146
+ elif v < 0x4000:
147
+ return struct.pack(">H", (v | 0x8000))
148
+ elif v < 0x200000:
149
+ return struct.pack(">L", (v | 0xC00000))[1:]
150
+ elif v < 0x10000000:
151
+ return struct.pack(">L", (v | 0xE0000000))
152
+ else:
153
+ return struct.pack(">B", 0xF0) + struct.pack(">L", v)
154
+
155
+
156
+ class VarComponent:
157
+ def __init__(self):
158
+ self.populateDefaults()
159
+
160
+ def populateDefaults(self, propagator=None):
161
+ self.flags = 0
162
+ self.glyphName = None
163
+ self.conditionIndex = None
164
+ self.axisIndicesIndex = None
165
+ self.axisValues = ()
166
+ self.axisValuesVarIndex = NO_VARIATION_INDEX
167
+ self.transformVarIndex = NO_VARIATION_INDEX
168
+ self.transform = DecomposedTransform()
169
+
170
+ def decompile(self, data, font, localState):
171
+ i = 0
172
+ self.flags, i = _read_uint32var(data, i)
173
+ flags = self.flags
174
+
175
+ gidSize = 3 if flags & VarComponentFlags.GID_IS_24BIT else 2
176
+ glyphID = _unpacker[gidSize](data[i : i + gidSize])
177
+ i += gidSize
178
+ self.glyphName = font.glyphOrder[glyphID]
179
+
180
+ if flags & VarComponentFlags.HAVE_CONDITION:
181
+ self.conditionIndex, i = _read_uint32var(data, i)
182
+
183
+ if flags & VarComponentFlags.HAVE_AXES:
184
+ self.axisIndicesIndex, i = _read_uint32var(data, i)
185
+ else:
186
+ self.axisIndicesIndex = None
187
+
188
+ if self.axisIndicesIndex is None:
189
+ numAxes = 0
190
+ else:
191
+ axisIndices = localState["AxisIndicesList"].Item[self.axisIndicesIndex]
192
+ numAxes = len(axisIndices)
193
+
194
+ if flags & VarComponentFlags.HAVE_AXES:
195
+ axisValues, i = TupleVariation.decompileDeltas_(numAxes, data, i)
196
+ self.axisValues = tuple(fi2fl(v, 14) for v in axisValues)
197
+ else:
198
+ self.axisValues = ()
199
+ assert len(self.axisValues) == numAxes
200
+
201
+ if flags & VarComponentFlags.AXIS_VALUES_HAVE_VARIATION:
202
+ self.axisValuesVarIndex, i = _read_uint32var(data, i)
203
+ else:
204
+ self.axisValuesVarIndex = NO_VARIATION_INDEX
205
+ if flags & VarComponentFlags.TRANSFORM_HAS_VARIATION:
206
+ self.transformVarIndex, i = _read_uint32var(data, i)
207
+ else:
208
+ self.transformVarIndex = NO_VARIATION_INDEX
209
+
210
+ self.transform = DecomposedTransform()
211
+
212
+ def read_transform_component(values):
213
+ nonlocal i
214
+ if flags & values.flag:
215
+ v = (
216
+ fi2fl(
217
+ struct.unpack(">h", data[i : i + 2])[0], values.fractionalBits
218
+ )
219
+ * values.scale
220
+ )
221
+ i += 2
222
+ return v
223
+ else:
224
+ return values.defaultValue
225
+
226
+ for attr_name, mapping_values in VAR_TRANSFORM_MAPPING.items():
227
+ value = read_transform_component(mapping_values)
228
+ setattr(self.transform, attr_name, value)
229
+
230
+ if not (flags & VarComponentFlags.HAVE_SCALE_Y):
231
+ self.transform.scaleY = self.transform.scaleX
232
+
233
+ n = flags & VarComponentFlags.RESERVED_MASK
234
+ while n:
235
+ _, i = _read_uint32var(data, i)
236
+ n &= n - 1
237
+
238
+ return data[i:]
239
+
240
+ def compile(self, font):
241
+ optimizeSpeed = font.cfg[OPTIMIZE_FONT_SPEED]
242
+
243
+ data = []
244
+
245
+ flags = self.flags
246
+
247
+ glyphID = font.getGlyphID(self.glyphName)
248
+ if glyphID > 65535:
249
+ flags |= VarComponentFlags.GID_IS_24BIT
250
+ data.append(_packer[3](glyphID))
251
+ else:
252
+ flags &= ~VarComponentFlags.GID_IS_24BIT
253
+ data.append(_packer[2](glyphID))
254
+
255
+ if self.conditionIndex is not None:
256
+ flags |= VarComponentFlags.HAVE_CONDITION
257
+ data.append(_write_uint32var(self.conditionIndex))
258
+
259
+ numAxes = len(self.axisValues)
260
+
261
+ if numAxes:
262
+ flags |= VarComponentFlags.HAVE_AXES
263
+ data.append(_write_uint32var(self.axisIndicesIndex))
264
+ data.append(
265
+ TupleVariation.compileDeltaValues_(
266
+ [fl2fi(v, 14) for v in self.axisValues],
267
+ optimizeSize=not optimizeSpeed,
268
+ )
269
+ )
270
+ else:
271
+ flags &= ~VarComponentFlags.HAVE_AXES
272
+
273
+ if self.axisValuesVarIndex != NO_VARIATION_INDEX:
274
+ flags |= VarComponentFlags.AXIS_VALUES_HAVE_VARIATION
275
+ data.append(_write_uint32var(self.axisValuesVarIndex))
276
+ else:
277
+ flags &= ~VarComponentFlags.AXIS_VALUES_HAVE_VARIATION
278
+ if self.transformVarIndex != NO_VARIATION_INDEX:
279
+ flags |= VarComponentFlags.TRANSFORM_HAS_VARIATION
280
+ data.append(_write_uint32var(self.transformVarIndex))
281
+ else:
282
+ flags &= ~VarComponentFlags.TRANSFORM_HAS_VARIATION
283
+
284
+ def write_transform_component(value, values):
285
+ if flags & values.flag:
286
+ return struct.pack(
287
+ ">h", fl2fi(value / values.scale, values.fractionalBits)
288
+ )
289
+ else:
290
+ return b""
291
+
292
+ for attr_name, mapping_values in VAR_TRANSFORM_MAPPING.items():
293
+ value = getattr(self.transform, attr_name)
294
+ data.append(write_transform_component(value, mapping_values))
295
+
296
+ return _write_uint32var(flags) + bytesjoin(data)
297
+
298
+ def toXML(self, writer, ttFont, attrs):
299
+ writer.begintag("VarComponent", attrs)
300
+ writer.newline()
301
+
302
+ def write(name, value, attrs=()):
303
+ if value is not None:
304
+ writer.simpletag(name, (("value", value),) + attrs)
305
+ writer.newline()
306
+
307
+ write("glyphName", self.glyphName)
308
+
309
+ if self.conditionIndex is not None:
310
+ write("conditionIndex", self.conditionIndex)
311
+ if self.axisIndicesIndex is not None:
312
+ write("axisIndicesIndex", self.axisIndicesIndex)
313
+ if (
314
+ self.axisIndicesIndex is not None
315
+ or self.flags & VarComponentFlags.RESET_UNSPECIFIED_AXES
316
+ ):
317
+ if self.flags & VarComponentFlags.RESET_UNSPECIFIED_AXES:
318
+ attrs = (("resetUnspecifiedAxes", 1),)
319
+ else:
320
+ attrs = ()
321
+ write("axisValues", [float(fl2str(v, 14)) for v in self.axisValues], attrs)
322
+
323
+ if self.axisValuesVarIndex != NO_VARIATION_INDEX:
324
+ write("axisValuesVarIndex", self.axisValuesVarIndex)
325
+ if self.transformVarIndex != NO_VARIATION_INDEX:
326
+ write("transformVarIndex", self.transformVarIndex)
327
+
328
+ # Only write transform components that are specified in the
329
+ # flags, even if they are the default value.
330
+ for attr_name, mapping in VAR_TRANSFORM_MAPPING.items():
331
+ if not (self.flags & mapping.flag):
332
+ continue
333
+ v = getattr(self.transform, attr_name)
334
+ write(attr_name, fl2str(v, mapping.fractionalBits))
335
+
336
+ writer.endtag("VarComponent")
337
+ writer.newline()
338
+
339
+ def fromXML(self, name, attrs, content, ttFont):
340
+ content = [c for c in content if isinstance(c, tuple)]
341
+
342
+ self.populateDefaults()
343
+
344
+ for name, attrs, content in content:
345
+ assert not content
346
+ v = attrs["value"]
347
+
348
+ if name == "glyphName":
349
+ self.glyphName = v
350
+ elif name == "conditionIndex":
351
+ self.conditionIndex = safeEval(v)
352
+ elif name == "axisIndicesIndex":
353
+ self.axisIndicesIndex = safeEval(v)
354
+ elif name == "axisValues":
355
+ self.axisValues = tuple(str2fl(v, 14) for v in safeEval(v))
356
+ if safeEval(attrs.get("resetUnspecifiedAxes", "0")):
357
+ self.flags |= VarComponentFlags.RESET_UNSPECIFIED_AXES
358
+ elif name == "axisValuesVarIndex":
359
+ self.axisValuesVarIndex = safeEval(v)
360
+ elif name == "transformVarIndex":
361
+ self.transformVarIndex = safeEval(v)
362
+ elif name in VAR_TRANSFORM_MAPPING:
363
+ setattr(
364
+ self.transform,
365
+ name,
366
+ safeEval(v),
367
+ )
368
+ self.flags |= VAR_TRANSFORM_MAPPING[name].flag
369
+ else:
370
+ assert False, name
371
+
372
+ def applyTransformDeltas(self, deltas):
373
+ i = 0
374
+
375
+ def read_transform_component_delta(values):
376
+ nonlocal i
377
+ if self.flags & values.flag:
378
+ v = fi2fl(deltas[i], values.fractionalBits) * values.scale
379
+ i += 1
380
+ return v
381
+ else:
382
+ return 0
383
+
384
+ for attr_name, mapping_values in VAR_TRANSFORM_MAPPING.items():
385
+ value = read_transform_component_delta(mapping_values)
386
+ setattr(
387
+ self.transform, attr_name, getattr(self.transform, attr_name) + value
388
+ )
389
+
390
+ if not (self.flags & VarComponentFlags.HAVE_SCALE_Y):
391
+ self.transform.scaleY = self.transform.scaleX
392
+
393
+ assert i == len(deltas), (i, len(deltas))
394
+
395
+ def __eq__(self, other):
396
+ if type(self) != type(other):
397
+ return NotImplemented
398
+ return self.__dict__ == other.__dict__
399
+
400
+ def __ne__(self, other):
401
+ result = self.__eq__(other)
402
+ return result if result is NotImplemented else not result
403
+
404
+
405
+ class VarCompositeGlyph:
406
+ def __init__(self, components=None):
407
+ self.components = components if components is not None else []
408
+
409
+ def decompile(self, data, font, localState):
410
+ self.components = []
411
+ while data:
412
+ component = VarComponent()
413
+ data = component.decompile(data, font, localState)
414
+ self.components.append(component)
415
+
416
+ def compile(self, font):
417
+ data = []
418
+ for component in self.components:
419
+ data.append(component.compile(font))
420
+ return bytesjoin(data)
421
+
422
+ def toXML(self, xmlWriter, font, attrs, name):
423
+ xmlWriter.begintag("VarCompositeGlyph", attrs)
424
+ xmlWriter.newline()
425
+ for i, component in enumerate(self.components):
426
+ component.toXML(xmlWriter, font, [("index", i)])
427
+ xmlWriter.endtag("VarCompositeGlyph")
428
+ xmlWriter.newline()
429
+
430
+ def fromXML(self, name, attrs, content, font):
431
+ content = [c for c in content if isinstance(c, tuple)]
432
+ for name, attrs, content in content:
433
+ assert name == "VarComponent"
434
+ component = VarComponent()
435
+ component.fromXML(name, attrs, content, font)
436
+ self.components.append(component)
437
+
438
+
439
+ class AATStateTable(object):
440
+ def __init__(self):
441
+ self.GlyphClasses = {} # GlyphID --> GlyphClass
442
+ self.States = [] # List of AATState, indexed by state number
443
+ self.PerGlyphLookups = [] # [{GlyphID:GlyphID}, ...]
444
+
445
+
446
+ class AATState(object):
447
+ def __init__(self):
448
+ self.Transitions = {} # GlyphClass --> AATAction
449
+
450
+
451
+ class AATAction(object):
452
+ _FLAGS = None
453
+
454
+ @staticmethod
455
+ def compileActions(font, states):
456
+ return (None, None)
457
+
458
+ def _writeFlagsToXML(self, xmlWriter):
459
+ flags = [f for f in self._FLAGS if self.__dict__[f]]
460
+ if flags:
461
+ xmlWriter.simpletag("Flags", value=",".join(flags))
462
+ xmlWriter.newline()
463
+ if self.ReservedFlags != 0:
464
+ xmlWriter.simpletag("ReservedFlags", value="0x%04X" % self.ReservedFlags)
465
+ xmlWriter.newline()
466
+
467
+ def _setFlag(self, flag):
468
+ assert flag in self._FLAGS, "unsupported flag %s" % flag
469
+ self.__dict__[flag] = True
470
+
471
+
472
+ class RearrangementMorphAction(AATAction):
473
+ staticSize = 4
474
+ actionHeaderSize = 0
475
+ _FLAGS = ["MarkFirst", "DontAdvance", "MarkLast"]
476
+
477
+ _VERBS = {
478
+ 0: "no change",
479
+ 1: "Ax ⇒ xA",
480
+ 2: "xD ⇒ Dx",
481
+ 3: "AxD ⇒ DxA",
482
+ 4: "ABx ⇒ xAB",
483
+ 5: "ABx ⇒ xBA",
484
+ 6: "xCD ⇒ CDx",
485
+ 7: "xCD ⇒ DCx",
486
+ 8: "AxCD ⇒ CDxA",
487
+ 9: "AxCD ⇒ DCxA",
488
+ 10: "ABxD ⇒ DxAB",
489
+ 11: "ABxD ⇒ DxBA",
490
+ 12: "ABxCD ⇒ CDxAB",
491
+ 13: "ABxCD ⇒ CDxBA",
492
+ 14: "ABxCD ⇒ DCxAB",
493
+ 15: "ABxCD ⇒ DCxBA",
494
+ }
495
+
496
+ def __init__(self):
497
+ self.NewState = 0
498
+ self.Verb = 0
499
+ self.MarkFirst = False
500
+ self.DontAdvance = False
501
+ self.MarkLast = False
502
+ self.ReservedFlags = 0
503
+
504
+ def compile(self, writer, font, actionIndex):
505
+ assert actionIndex is None
506
+ writer.writeUShort(self.NewState)
507
+ assert self.Verb >= 0 and self.Verb <= 15, self.Verb
508
+ flags = self.Verb | self.ReservedFlags
509
+ if self.MarkFirst:
510
+ flags |= 0x8000
511
+ if self.DontAdvance:
512
+ flags |= 0x4000
513
+ if self.MarkLast:
514
+ flags |= 0x2000
515
+ writer.writeUShort(flags)
516
+
517
+ def decompile(self, reader, font, actionReader):
518
+ assert actionReader is None
519
+ self.NewState = reader.readUShort()
520
+ flags = reader.readUShort()
521
+ self.Verb = flags & 0xF
522
+ self.MarkFirst = bool(flags & 0x8000)
523
+ self.DontAdvance = bool(flags & 0x4000)
524
+ self.MarkLast = bool(flags & 0x2000)
525
+ self.ReservedFlags = flags & 0x1FF0
526
+
527
+ def toXML(self, xmlWriter, font, attrs, name):
528
+ xmlWriter.begintag(name, **attrs)
529
+ xmlWriter.newline()
530
+ xmlWriter.simpletag("NewState", value=self.NewState)
531
+ xmlWriter.newline()
532
+ self._writeFlagsToXML(xmlWriter)
533
+ xmlWriter.simpletag("Verb", value=self.Verb)
534
+ verbComment = self._VERBS.get(self.Verb)
535
+ if verbComment is not None:
536
+ xmlWriter.comment(verbComment)
537
+ xmlWriter.newline()
538
+ xmlWriter.endtag(name)
539
+ xmlWriter.newline()
540
+
541
+ def fromXML(self, name, attrs, content, font):
542
+ self.NewState = self.Verb = self.ReservedFlags = 0
543
+ self.MarkFirst = self.DontAdvance = self.MarkLast = False
544
+ content = [t for t in content if isinstance(t, tuple)]
545
+ for eltName, eltAttrs, eltContent in content:
546
+ if eltName == "NewState":
547
+ self.NewState = safeEval(eltAttrs["value"])
548
+ elif eltName == "Verb":
549
+ self.Verb = safeEval(eltAttrs["value"])
550
+ elif eltName == "ReservedFlags":
551
+ self.ReservedFlags = safeEval(eltAttrs["value"])
552
+ elif eltName == "Flags":
553
+ for flag in eltAttrs["value"].split(","):
554
+ self._setFlag(flag.strip())
555
+
556
+
557
+ class ContextualMorphAction(AATAction):
558
+ staticSize = 8
559
+ actionHeaderSize = 0
560
+ _FLAGS = ["SetMark", "DontAdvance"]
561
+
562
+ def __init__(self):
563
+ self.NewState = 0
564
+ self.SetMark, self.DontAdvance = False, False
565
+ self.ReservedFlags = 0
566
+ self.MarkIndex, self.CurrentIndex = 0xFFFF, 0xFFFF
567
+
568
+ def compile(self, writer, font, actionIndex):
569
+ assert actionIndex is None
570
+ writer.writeUShort(self.NewState)
571
+ flags = self.ReservedFlags
572
+ if self.SetMark:
573
+ flags |= 0x8000
574
+ if self.DontAdvance:
575
+ flags |= 0x4000
576
+ writer.writeUShort(flags)
577
+ writer.writeUShort(self.MarkIndex)
578
+ writer.writeUShort(self.CurrentIndex)
579
+
580
+ def decompile(self, reader, font, actionReader):
581
+ assert actionReader is None
582
+ self.NewState = reader.readUShort()
583
+ flags = reader.readUShort()
584
+ self.SetMark = bool(flags & 0x8000)
585
+ self.DontAdvance = bool(flags & 0x4000)
586
+ self.ReservedFlags = flags & 0x3FFF
587
+ self.MarkIndex = reader.readUShort()
588
+ self.CurrentIndex = reader.readUShort()
589
+
590
+ def toXML(self, xmlWriter, font, attrs, name):
591
+ xmlWriter.begintag(name, **attrs)
592
+ xmlWriter.newline()
593
+ xmlWriter.simpletag("NewState", value=self.NewState)
594
+ xmlWriter.newline()
595
+ self._writeFlagsToXML(xmlWriter)
596
+ xmlWriter.simpletag("MarkIndex", value=self.MarkIndex)
597
+ xmlWriter.newline()
598
+ xmlWriter.simpletag("CurrentIndex", value=self.CurrentIndex)
599
+ xmlWriter.newline()
600
+ xmlWriter.endtag(name)
601
+ xmlWriter.newline()
602
+
603
+ def fromXML(self, name, attrs, content, font):
604
+ self.NewState = self.ReservedFlags = 0
605
+ self.SetMark = self.DontAdvance = False
606
+ self.MarkIndex, self.CurrentIndex = 0xFFFF, 0xFFFF
607
+ content = [t for t in content if isinstance(t, tuple)]
608
+ for eltName, eltAttrs, eltContent in content:
609
+ if eltName == "NewState":
610
+ self.NewState = safeEval(eltAttrs["value"])
611
+ elif eltName == "Flags":
612
+ for flag in eltAttrs["value"].split(","):
613
+ self._setFlag(flag.strip())
614
+ elif eltName == "ReservedFlags":
615
+ self.ReservedFlags = safeEval(eltAttrs["value"])
616
+ elif eltName == "MarkIndex":
617
+ self.MarkIndex = safeEval(eltAttrs["value"])
618
+ elif eltName == "CurrentIndex":
619
+ self.CurrentIndex = safeEval(eltAttrs["value"])
620
+
621
+
622
+ class LigAction(object):
623
+ def __init__(self):
624
+ self.Store = False
625
+ # GlyphIndexDelta is a (possibly negative) delta that gets
626
+ # added to the glyph ID at the top of the AAT runtime
627
+ # execution stack. It is *not* a byte offset into the
628
+ # morx table. The result of the addition, which is performed
629
+ # at run time by the shaping engine, is an index into
630
+ # the ligature components table. See 'morx' specification.
631
+ # In the AAT specification, this field is called Offset;
632
+ # but its meaning is quite different from other offsets
633
+ # in either AAT or OpenType, so we use a different name.
634
+ self.GlyphIndexDelta = 0
635
+
636
+
637
+ class LigatureMorphAction(AATAction):
638
+ staticSize = 6
639
+
640
+ # 4 bytes for each of {action,ligComponents,ligatures}Offset
641
+ actionHeaderSize = 12
642
+
643
+ _FLAGS = ["SetComponent", "DontAdvance"]
644
+
645
+ def __init__(self):
646
+ self.NewState = 0
647
+ self.SetComponent, self.DontAdvance = False, False
648
+ self.ReservedFlags = 0
649
+ self.Actions = []
650
+
651
+ def compile(self, writer, font, actionIndex):
652
+ assert actionIndex is not None
653
+ writer.writeUShort(self.NewState)
654
+ flags = self.ReservedFlags
655
+ if self.SetComponent:
656
+ flags |= 0x8000
657
+ if self.DontAdvance:
658
+ flags |= 0x4000
659
+ if len(self.Actions) > 0:
660
+ flags |= 0x2000
661
+ writer.writeUShort(flags)
662
+ if len(self.Actions) > 0:
663
+ actions = self.compileLigActions()
664
+ writer.writeUShort(actionIndex[actions])
665
+ else:
666
+ writer.writeUShort(0)
667
+
668
+ def decompile(self, reader, font, actionReader):
669
+ assert actionReader is not None
670
+ self.NewState = reader.readUShort()
671
+ flags = reader.readUShort()
672
+ self.SetComponent = bool(flags & 0x8000)
673
+ self.DontAdvance = bool(flags & 0x4000)
674
+ performAction = bool(flags & 0x2000)
675
+ # As of 2017-09-12, the 'morx' specification says that
676
+ # the reserved bitmask in ligature subtables is 0x3FFF.
677
+ # However, the specification also defines a flag 0x2000,
678
+ # so the reserved value should actually be 0x1FFF.
679
+ # TODO: Report this specification bug to Apple.
680
+ self.ReservedFlags = flags & 0x1FFF
681
+ actionIndex = reader.readUShort()
682
+ if performAction:
683
+ self.Actions = self._decompileLigActions(actionReader, actionIndex)
684
+ else:
685
+ self.Actions = []
686
+
687
+ @staticmethod
688
+ def compileActions(font, states):
689
+ result, actions, actionIndex = b"", set(), {}
690
+ for state in states:
691
+ for _glyphClass, trans in state.Transitions.items():
692
+ actions.add(trans.compileLigActions())
693
+ # Sort the compiled actions in decreasing order of
694
+ # length, so that the longer sequence come before the
695
+ # shorter ones. For each compiled action ABCD, its
696
+ # suffixes BCD, CD, and D do not be encoded separately
697
+ # (in case they occur); instead, we can just store an
698
+ # index that points into the middle of the longer
699
+ # sequence. Every compiled AAT ligature sequence is
700
+ # terminated with an end-of-sequence flag, which can
701
+ # only be set on the last element of the sequence.
702
+ # Therefore, it is sufficient to consider just the
703
+ # suffixes.
704
+ for a in sorted(actions, key=lambda x: (-len(x), x)):
705
+ if a not in actionIndex:
706
+ for i in range(0, len(a), 4):
707
+ suffix = a[i:]
708
+ suffixIndex = (len(result) + i) // 4
709
+ actionIndex.setdefault(suffix, suffixIndex)
710
+ result += a
711
+ result = pad(result, 4)
712
+ return (result, actionIndex)
713
+
714
+ def compileLigActions(self):
715
+ result = []
716
+ for i, action in enumerate(self.Actions):
717
+ last = i == len(self.Actions) - 1
718
+ value = action.GlyphIndexDelta & 0x3FFFFFFF
719
+ value |= 0x80000000 if last else 0
720
+ value |= 0x40000000 if action.Store else 0
721
+ result.append(struct.pack(">L", value))
722
+ return bytesjoin(result)
723
+
724
+ def _decompileLigActions(self, actionReader, actionIndex):
725
+ actions = []
726
+ last = False
727
+ reader = actionReader.getSubReader(actionReader.pos + actionIndex * 4)
728
+ while not last:
729
+ value = reader.readULong()
730
+ last = bool(value & 0x80000000)
731
+ action = LigAction()
732
+ actions.append(action)
733
+ action.Store = bool(value & 0x40000000)
734
+ delta = value & 0x3FFFFFFF
735
+ if delta >= 0x20000000: # sign-extend 30-bit value
736
+ delta = -0x40000000 + delta
737
+ action.GlyphIndexDelta = delta
738
+ return actions
739
+
740
+ def fromXML(self, name, attrs, content, font):
741
+ self.NewState = self.ReservedFlags = 0
742
+ self.SetComponent = self.DontAdvance = False
743
+ self.ReservedFlags = 0
744
+ self.Actions = []
745
+ content = [t for t in content if isinstance(t, tuple)]
746
+ for eltName, eltAttrs, eltContent in content:
747
+ if eltName == "NewState":
748
+ self.NewState = safeEval(eltAttrs["value"])
749
+ elif eltName == "Flags":
750
+ for flag in eltAttrs["value"].split(","):
751
+ self._setFlag(flag.strip())
752
+ elif eltName == "ReservedFlags":
753
+ self.ReservedFlags = safeEval(eltAttrs["value"])
754
+ elif eltName == "Action":
755
+ action = LigAction()
756
+ flags = eltAttrs.get("Flags", "").split(",")
757
+ flags = [f.strip() for f in flags]
758
+ action.Store = "Store" in flags
759
+ action.GlyphIndexDelta = safeEval(eltAttrs["GlyphIndexDelta"])
760
+ self.Actions.append(action)
761
+
762
+ def toXML(self, xmlWriter, font, attrs, name):
763
+ xmlWriter.begintag(name, **attrs)
764
+ xmlWriter.newline()
765
+ xmlWriter.simpletag("NewState", value=self.NewState)
766
+ xmlWriter.newline()
767
+ self._writeFlagsToXML(xmlWriter)
768
+ for action in self.Actions:
769
+ attribs = [("GlyphIndexDelta", action.GlyphIndexDelta)]
770
+ if action.Store:
771
+ attribs.append(("Flags", "Store"))
772
+ xmlWriter.simpletag("Action", attribs)
773
+ xmlWriter.newline()
774
+ xmlWriter.endtag(name)
775
+ xmlWriter.newline()
776
+
777
+
778
+ class InsertionMorphAction(AATAction):
779
+ staticSize = 8
780
+ actionHeaderSize = 4 # 4 bytes for actionOffset
781
+ _FLAGS = [
782
+ "SetMark",
783
+ "DontAdvance",
784
+ "CurrentIsKashidaLike",
785
+ "MarkedIsKashidaLike",
786
+ "CurrentInsertBefore",
787
+ "MarkedInsertBefore",
788
+ ]
789
+
790
+ def __init__(self):
791
+ self.NewState = 0
792
+ for flag in self._FLAGS:
793
+ setattr(self, flag, False)
794
+ self.ReservedFlags = 0
795
+ self.CurrentInsertionAction, self.MarkedInsertionAction = [], []
796
+
797
+ def compile(self, writer, font, actionIndex):
798
+ assert actionIndex is not None
799
+ writer.writeUShort(self.NewState)
800
+ flags = self.ReservedFlags
801
+ if self.SetMark:
802
+ flags |= 0x8000
803
+ if self.DontAdvance:
804
+ flags |= 0x4000
805
+ if self.CurrentIsKashidaLike:
806
+ flags |= 0x2000
807
+ if self.MarkedIsKashidaLike:
808
+ flags |= 0x1000
809
+ if self.CurrentInsertBefore:
810
+ flags |= 0x0800
811
+ if self.MarkedInsertBefore:
812
+ flags |= 0x0400
813
+ flags |= len(self.CurrentInsertionAction) << 5
814
+ flags |= len(self.MarkedInsertionAction)
815
+ writer.writeUShort(flags)
816
+ if len(self.CurrentInsertionAction) > 0:
817
+ currentIndex = actionIndex[tuple(self.CurrentInsertionAction)]
818
+ else:
819
+ currentIndex = 0xFFFF
820
+ writer.writeUShort(currentIndex)
821
+ if len(self.MarkedInsertionAction) > 0:
822
+ markedIndex = actionIndex[tuple(self.MarkedInsertionAction)]
823
+ else:
824
+ markedIndex = 0xFFFF
825
+ writer.writeUShort(markedIndex)
826
+
827
+ def decompile(self, reader, font, actionReader):
828
+ assert actionReader is not None
829
+ self.NewState = reader.readUShort()
830
+ flags = reader.readUShort()
831
+ self.SetMark = bool(flags & 0x8000)
832
+ self.DontAdvance = bool(flags & 0x4000)
833
+ self.CurrentIsKashidaLike = bool(flags & 0x2000)
834
+ self.MarkedIsKashidaLike = bool(flags & 0x1000)
835
+ self.CurrentInsertBefore = bool(flags & 0x0800)
836
+ self.MarkedInsertBefore = bool(flags & 0x0400)
837
+ self.CurrentInsertionAction = self._decompileInsertionAction(
838
+ actionReader, font, index=reader.readUShort(), count=((flags & 0x03E0) >> 5)
839
+ )
840
+ self.MarkedInsertionAction = self._decompileInsertionAction(
841
+ actionReader, font, index=reader.readUShort(), count=(flags & 0x001F)
842
+ )
843
+
844
+ def _decompileInsertionAction(self, actionReader, font, index, count):
845
+ if index == 0xFFFF or count == 0:
846
+ return []
847
+ reader = actionReader.getSubReader(actionReader.pos + index * 2)
848
+ return font.getGlyphNameMany(reader.readUShortArray(count))
849
+
850
+ def toXML(self, xmlWriter, font, attrs, name):
851
+ xmlWriter.begintag(name, **attrs)
852
+ xmlWriter.newline()
853
+ xmlWriter.simpletag("NewState", value=self.NewState)
854
+ xmlWriter.newline()
855
+ self._writeFlagsToXML(xmlWriter)
856
+ for g in self.CurrentInsertionAction:
857
+ xmlWriter.simpletag("CurrentInsertionAction", glyph=g)
858
+ xmlWriter.newline()
859
+ for g in self.MarkedInsertionAction:
860
+ xmlWriter.simpletag("MarkedInsertionAction", glyph=g)
861
+ xmlWriter.newline()
862
+ xmlWriter.endtag(name)
863
+ xmlWriter.newline()
864
+
865
+ def fromXML(self, name, attrs, content, font):
866
+ self.__init__()
867
+ content = [t for t in content if isinstance(t, tuple)]
868
+ for eltName, eltAttrs, eltContent in content:
869
+ if eltName == "NewState":
870
+ self.NewState = safeEval(eltAttrs["value"])
871
+ elif eltName == "Flags":
872
+ for flag in eltAttrs["value"].split(","):
873
+ self._setFlag(flag.strip())
874
+ elif eltName == "CurrentInsertionAction":
875
+ self.CurrentInsertionAction.append(eltAttrs["glyph"])
876
+ elif eltName == "MarkedInsertionAction":
877
+ self.MarkedInsertionAction.append(eltAttrs["glyph"])
878
+ else:
879
+ assert False, eltName
880
+
881
+ @staticmethod
882
+ def compileActions(font, states):
883
+ actions, actionIndex, result = set(), {}, b""
884
+ for state in states:
885
+ for _glyphClass, trans in state.Transitions.items():
886
+ if trans.CurrentInsertionAction is not None:
887
+ actions.add(tuple(trans.CurrentInsertionAction))
888
+ if trans.MarkedInsertionAction is not None:
889
+ actions.add(tuple(trans.MarkedInsertionAction))
890
+ # Sort the compiled actions in decreasing order of
891
+ # length, so that the longer sequence come before the
892
+ # shorter ones.
893
+ for action in sorted(actions, key=lambda x: (-len(x), x)):
894
+ # We insert all sub-sequences of the action glyph sequence
895
+ # into actionIndex. For example, if one action triggers on
896
+ # glyph sequence [A, B, C, D, E] and another action triggers
897
+ # on [C, D], we return result=[A, B, C, D, E] (as list of
898
+ # encoded glyph IDs), and actionIndex={('A','B','C','D','E'): 0,
899
+ # ('C','D'): 2}.
900
+ if action in actionIndex:
901
+ continue
902
+ for start in range(0, len(action)):
903
+ startIndex = (len(result) // 2) + start
904
+ for limit in range(start, len(action)):
905
+ glyphs = action[start : limit + 1]
906
+ actionIndex.setdefault(glyphs, startIndex)
907
+ for glyph in action:
908
+ glyphID = font.getGlyphID(glyph)
909
+ result += struct.pack(">H", glyphID)
910
+ return result, actionIndex
911
+
912
+
913
+ class FeatureParams(BaseTable):
914
+ def compile(self, writer, font):
915
+ assert (
916
+ featureParamTypes.get(writer["FeatureTag"]) == self.__class__
917
+ ), "Wrong FeatureParams type for feature '%s': %s" % (
918
+ writer["FeatureTag"],
919
+ self.__class__.__name__,
920
+ )
921
+ BaseTable.compile(self, writer, font)
922
+
923
+ def toXML(self, xmlWriter, font, attrs=None, name=None):
924
+ BaseTable.toXML(self, xmlWriter, font, attrs, name=self.__class__.__name__)
925
+
926
+
927
+ class FeatureParamsSize(FeatureParams):
928
+ pass
929
+
930
+
931
+ class FeatureParamsStylisticSet(FeatureParams):
932
+ pass
933
+
934
+
935
+ class FeatureParamsCharacterVariants(FeatureParams):
936
+ pass
937
+
938
+
939
+ class Coverage(FormatSwitchingBaseTable):
940
+ # manual implementation to get rid of glyphID dependencies
941
+
942
+ def populateDefaults(self, propagator=None):
943
+ if not hasattr(self, "glyphs"):
944
+ self.glyphs = []
945
+
946
+ def postRead(self, rawTable, font):
947
+ if self.Format == 1:
948
+ self.glyphs = rawTable["GlyphArray"]
949
+ elif self.Format == 2:
950
+ glyphs = self.glyphs = []
951
+ ranges = rawTable["RangeRecord"]
952
+ # Some SIL fonts have coverage entries that don't have sorted
953
+ # StartCoverageIndex. If it is so, fixup and warn. We undo
954
+ # this when writing font out.
955
+ sorted_ranges = sorted(ranges, key=lambda a: a.StartCoverageIndex)
956
+ if ranges != sorted_ranges:
957
+ log.warning("GSUB/GPOS Coverage is not sorted by glyph ids.")
958
+ ranges = sorted_ranges
959
+ del sorted_ranges
960
+ for r in ranges:
961
+ start = r.Start
962
+ end = r.End
963
+ startID = font.getGlyphID(start)
964
+ endID = font.getGlyphID(end) + 1
965
+ glyphs.extend(font.getGlyphNameMany(range(startID, endID)))
966
+ else:
967
+ self.glyphs = []
968
+ log.warning("Unknown Coverage format: %s", self.Format)
969
+ del self.Format # Don't need this anymore
970
+
971
+ def preWrite(self, font):
972
+ glyphs = getattr(self, "glyphs", None)
973
+ if glyphs is None:
974
+ glyphs = self.glyphs = []
975
+ format = 1
976
+ rawTable = {"GlyphArray": glyphs}
977
+ if glyphs:
978
+ # find out whether Format 2 is more compact or not
979
+ glyphIDs = font.getGlyphIDMany(glyphs)
980
+ brokenOrder = sorted(glyphIDs) != glyphIDs
981
+
982
+ last = glyphIDs[0]
983
+ ranges = [[last]]
984
+ for glyphID in glyphIDs[1:]:
985
+ if glyphID != last + 1:
986
+ ranges[-1].append(last)
987
+ ranges.append([glyphID])
988
+ last = glyphID
989
+ ranges[-1].append(last)
990
+
991
+ if brokenOrder or len(ranges) * 3 < len(glyphs): # 3 words vs. 1 word
992
+ # Format 2 is more compact
993
+ index = 0
994
+ for i, (start, end) in enumerate(ranges):
995
+ r = RangeRecord()
996
+ r.StartID = start
997
+ r.Start = font.getGlyphName(start)
998
+ r.End = font.getGlyphName(end)
999
+ r.StartCoverageIndex = index
1000
+ ranges[i] = r
1001
+ index = index + end - start + 1
1002
+ if brokenOrder:
1003
+ log.warning("GSUB/GPOS Coverage is not sorted by glyph ids.")
1004
+ ranges.sort(key=lambda a: a.StartID)
1005
+ for r in ranges:
1006
+ del r.StartID
1007
+ format = 2
1008
+ rawTable = {"RangeRecord": ranges}
1009
+ # else:
1010
+ # fallthrough; Format 1 is more compact
1011
+ self.Format = format
1012
+ return rawTable
1013
+
1014
+ def toXML2(self, xmlWriter, font):
1015
+ for glyphName in getattr(self, "glyphs", []):
1016
+ xmlWriter.simpletag("Glyph", value=glyphName)
1017
+ xmlWriter.newline()
1018
+
1019
+ def fromXML(self, name, attrs, content, font):
1020
+ glyphs = getattr(self, "glyphs", None)
1021
+ if glyphs is None:
1022
+ glyphs = []
1023
+ self.glyphs = glyphs
1024
+ glyphs.append(attrs["value"])
1025
+
1026
+
1027
+ # The special 0xFFFFFFFF delta-set index is used to indicate that there
1028
+ # is no variation data in the ItemVariationStore for a given variable field
1029
+ NO_VARIATION_INDEX = 0xFFFFFFFF
1030
+
1031
+
1032
+ class DeltaSetIndexMap(getFormatSwitchingBaseTableClass("uint8")):
1033
+ def populateDefaults(self, propagator=None):
1034
+ if not hasattr(self, "mapping"):
1035
+ self.mapping = []
1036
+
1037
+ def postRead(self, rawTable, font):
1038
+ assert (rawTable["EntryFormat"] & 0xFFC0) == 0
1039
+ self.mapping = rawTable["mapping"]
1040
+
1041
+ @staticmethod
1042
+ def getEntryFormat(mapping):
1043
+ ored = 0
1044
+ for idx in mapping:
1045
+ ored |= idx
1046
+
1047
+ inner = ored & 0xFFFF
1048
+ innerBits = 0
1049
+ while inner:
1050
+ innerBits += 1
1051
+ inner >>= 1
1052
+ innerBits = max(innerBits, 1)
1053
+ assert innerBits <= 16
1054
+
1055
+ ored = (ored >> (16 - innerBits)) | (ored & ((1 << innerBits) - 1))
1056
+ if ored <= 0x000000FF:
1057
+ entrySize = 1
1058
+ elif ored <= 0x0000FFFF:
1059
+ entrySize = 2
1060
+ elif ored <= 0x00FFFFFF:
1061
+ entrySize = 3
1062
+ else:
1063
+ entrySize = 4
1064
+
1065
+ return ((entrySize - 1) << 4) | (innerBits - 1)
1066
+
1067
+ def preWrite(self, font):
1068
+ mapping = getattr(self, "mapping", None)
1069
+ if mapping is None:
1070
+ mapping = self.mapping = []
1071
+ self.Format = 1 if len(mapping) > 0xFFFF else 0
1072
+ rawTable = self.__dict__.copy()
1073
+ rawTable["MappingCount"] = len(mapping)
1074
+ rawTable["EntryFormat"] = self.getEntryFormat(mapping)
1075
+ return rawTable
1076
+
1077
+ def toXML2(self, xmlWriter, font):
1078
+ # Make xml dump less verbose, by omitting no-op entries like:
1079
+ # <Map index="..." outer="65535" inner="65535"/>
1080
+ xmlWriter.comment("Omitted values default to 0xFFFF/0xFFFF (no variations)")
1081
+ xmlWriter.newline()
1082
+ for i, value in enumerate(getattr(self, "mapping", [])):
1083
+ attrs = [("index", i)]
1084
+ if value != NO_VARIATION_INDEX:
1085
+ attrs.extend(
1086
+ [
1087
+ ("outer", value >> 16),
1088
+ ("inner", value & 0xFFFF),
1089
+ ]
1090
+ )
1091
+ xmlWriter.simpletag("Map", attrs)
1092
+ xmlWriter.newline()
1093
+
1094
+ def fromXML(self, name, attrs, content, font):
1095
+ mapping = getattr(self, "mapping", None)
1096
+ if mapping is None:
1097
+ self.mapping = mapping = []
1098
+ index = safeEval(attrs["index"])
1099
+ outer = safeEval(attrs.get("outer", "0xFFFF"))
1100
+ inner = safeEval(attrs.get("inner", "0xFFFF"))
1101
+ assert inner <= 0xFFFF
1102
+ mapping.insert(index, (outer << 16) | inner)
1103
+
1104
+ def __getitem__(self, i):
1105
+ return self.mapping[i] if i < len(self.mapping) else NO_VARIATION_INDEX
1106
+
1107
+
1108
+ class VarIdxMap(BaseTable):
1109
+ def populateDefaults(self, propagator=None):
1110
+ if not hasattr(self, "mapping"):
1111
+ self.mapping = {}
1112
+
1113
+ def postRead(self, rawTable, font):
1114
+ assert (rawTable["EntryFormat"] & 0xFFC0) == 0
1115
+ glyphOrder = font.getGlyphOrder()
1116
+ mapList = rawTable["mapping"]
1117
+ mapList.extend([mapList[-1]] * (len(glyphOrder) - len(mapList)))
1118
+ self.mapping = dict(zip(glyphOrder, mapList))
1119
+
1120
+ def preWrite(self, font):
1121
+ mapping = getattr(self, "mapping", None)
1122
+ if mapping is None:
1123
+ mapping = self.mapping = {}
1124
+
1125
+ glyphOrder = font.getGlyphOrder()
1126
+ mapping = [mapping[g] for g in glyphOrder]
1127
+ while len(mapping) > 1 and mapping[-2] == mapping[-1]:
1128
+ del mapping[-1]
1129
+
1130
+ rawTable = {"mapping": mapping}
1131
+ rawTable["MappingCount"] = len(mapping)
1132
+ rawTable["EntryFormat"] = DeltaSetIndexMap.getEntryFormat(mapping)
1133
+ return rawTable
1134
+
1135
+ def toXML2(self, xmlWriter, font):
1136
+ for glyph, value in sorted(getattr(self, "mapping", {}).items()):
1137
+ attrs = (
1138
+ ("glyph", glyph),
1139
+ ("outer", value >> 16),
1140
+ ("inner", value & 0xFFFF),
1141
+ )
1142
+ xmlWriter.simpletag("Map", attrs)
1143
+ xmlWriter.newline()
1144
+
1145
+ def fromXML(self, name, attrs, content, font):
1146
+ mapping = getattr(self, "mapping", None)
1147
+ if mapping is None:
1148
+ mapping = {}
1149
+ self.mapping = mapping
1150
+ try:
1151
+ glyph = attrs["glyph"]
1152
+ except: # https://github.com/fonttools/fonttools/commit/21cbab8ce9ded3356fef3745122da64dcaf314e9#commitcomment-27649836
1153
+ glyph = font.getGlyphOrder()[attrs["index"]]
1154
+ outer = safeEval(attrs["outer"])
1155
+ inner = safeEval(attrs["inner"])
1156
+ assert inner <= 0xFFFF
1157
+ mapping[glyph] = (outer << 16) | inner
1158
+
1159
+ def __getitem__(self, glyphName):
1160
+ return self.mapping.get(glyphName, NO_VARIATION_INDEX)
1161
+
1162
+
1163
+ class VarRegionList(BaseTable):
1164
+ def preWrite(self, font):
1165
+ # The OT spec says VarStore.VarRegionList.RegionAxisCount should always
1166
+ # be equal to the fvar.axisCount, and OTS < v8.0.0 enforces this rule
1167
+ # even when the VarRegionList is empty. We can't treat RegionAxisCount
1168
+ # like a normal propagated count (== len(Region[i].VarRegionAxis)),
1169
+ # otherwise it would default to 0 if VarRegionList is empty.
1170
+ # Thus, we force it to always be equal to fvar.axisCount.
1171
+ # https://github.com/khaledhosny/ots/pull/192
1172
+ fvarTable = font.get("fvar")
1173
+ if fvarTable:
1174
+ self.RegionAxisCount = len(fvarTable.axes)
1175
+ return {
1176
+ **self.__dict__,
1177
+ "RegionAxisCount": CountReference(self.__dict__, "RegionAxisCount"),
1178
+ }
1179
+
1180
+
1181
+ class SingleSubst(FormatSwitchingBaseTable):
1182
+ def populateDefaults(self, propagator=None):
1183
+ if not hasattr(self, "mapping"):
1184
+ self.mapping = {}
1185
+
1186
+ def postRead(self, rawTable, font):
1187
+ mapping = {}
1188
+ input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
1189
+ if self.Format == 1:
1190
+ delta = rawTable["DeltaGlyphID"]
1191
+ inputGIDS = font.getGlyphIDMany(input)
1192
+ outGIDS = [(glyphID + delta) % 65536 for glyphID in inputGIDS]
1193
+ outNames = font.getGlyphNameMany(outGIDS)
1194
+ for inp, out in zip(input, outNames):
1195
+ mapping[inp] = out
1196
+ elif self.Format == 2:
1197
+ assert (
1198
+ len(input) == rawTable["GlyphCount"]
1199
+ ), "invalid SingleSubstFormat2 table"
1200
+ subst = rawTable["Substitute"]
1201
+ for inp, sub in zip(input, subst):
1202
+ mapping[inp] = sub
1203
+ else:
1204
+ assert 0, "unknown format: %s" % self.Format
1205
+ self.mapping = mapping
1206
+ del self.Format # Don't need this anymore
1207
+
1208
+ def preWrite(self, font):
1209
+ mapping = getattr(self, "mapping", None)
1210
+ if mapping is None:
1211
+ mapping = self.mapping = {}
1212
+ items = list(mapping.items())
1213
+ getGlyphID = font.getGlyphID
1214
+ gidItems = [(getGlyphID(a), getGlyphID(b)) for a, b in items]
1215
+ sortableItems = sorted(zip(gidItems, items))
1216
+
1217
+ # figure out format
1218
+ format = 2
1219
+ delta = None
1220
+ for inID, outID in gidItems:
1221
+ if delta is None:
1222
+ delta = (outID - inID) % 65536
1223
+
1224
+ if (inID + delta) % 65536 != outID:
1225
+ break
1226
+ else:
1227
+ if delta is None:
1228
+ # the mapping is empty, better use format 2
1229
+ format = 2
1230
+ else:
1231
+ format = 1
1232
+
1233
+ rawTable = {}
1234
+ self.Format = format
1235
+ cov = Coverage()
1236
+ input = [item[1][0] for item in sortableItems]
1237
+ subst = [item[1][1] for item in sortableItems]
1238
+ cov.glyphs = input
1239
+ rawTable["Coverage"] = cov
1240
+ if format == 1:
1241
+ assert delta is not None
1242
+ rawTable["DeltaGlyphID"] = delta
1243
+ else:
1244
+ rawTable["Substitute"] = subst
1245
+ return rawTable
1246
+
1247
+ def toXML2(self, xmlWriter, font):
1248
+ items = sorted(self.mapping.items())
1249
+ for inGlyph, outGlyph in items:
1250
+ xmlWriter.simpletag("Substitution", [("in", inGlyph), ("out", outGlyph)])
1251
+ xmlWriter.newline()
1252
+
1253
+ def fromXML(self, name, attrs, content, font):
1254
+ mapping = getattr(self, "mapping", None)
1255
+ if mapping is None:
1256
+ mapping = {}
1257
+ self.mapping = mapping
1258
+ mapping[attrs["in"]] = attrs["out"]
1259
+
1260
+
1261
+ class MultipleSubst(FormatSwitchingBaseTable):
1262
+ def populateDefaults(self, propagator=None):
1263
+ if not hasattr(self, "mapping"):
1264
+ self.mapping = {}
1265
+
1266
+ def postRead(self, rawTable, font):
1267
+ mapping = {}
1268
+ if self.Format == 1:
1269
+ glyphs = _getGlyphsFromCoverageTable(rawTable["Coverage"])
1270
+ subst = [s.Substitute for s in rawTable["Sequence"]]
1271
+ mapping = dict(zip(glyphs, subst))
1272
+ else:
1273
+ assert 0, "unknown format: %s" % self.Format
1274
+ self.mapping = mapping
1275
+ del self.Format # Don't need this anymore
1276
+
1277
+ def preWrite(self, font):
1278
+ mapping = getattr(self, "mapping", None)
1279
+ if mapping is None:
1280
+ mapping = self.mapping = {}
1281
+ cov = Coverage()
1282
+ cov.glyphs = sorted(list(mapping.keys()), key=font.getGlyphID)
1283
+ self.Format = 1
1284
+ rawTable = {
1285
+ "Coverage": cov,
1286
+ "Sequence": [self.makeSequence_(mapping[glyph]) for glyph in cov.glyphs],
1287
+ }
1288
+ return rawTable
1289
+
1290
+ def toXML2(self, xmlWriter, font):
1291
+ items = sorted(self.mapping.items())
1292
+ for inGlyph, outGlyphs in items:
1293
+ out = ",".join(outGlyphs)
1294
+ xmlWriter.simpletag("Substitution", [("in", inGlyph), ("out", out)])
1295
+ xmlWriter.newline()
1296
+
1297
+ def fromXML(self, name, attrs, content, font):
1298
+ mapping = getattr(self, "mapping", None)
1299
+ if mapping is None:
1300
+ mapping = {}
1301
+ self.mapping = mapping
1302
+
1303
+ # TTX v3.0 and earlier.
1304
+ if name == "Coverage":
1305
+ self.old_coverage_ = []
1306
+ for element in content:
1307
+ if not isinstance(element, tuple):
1308
+ continue
1309
+ element_name, element_attrs, _ = element
1310
+ if element_name == "Glyph":
1311
+ self.old_coverage_.append(element_attrs["value"])
1312
+ return
1313
+ if name == "Sequence":
1314
+ index = int(attrs.get("index", len(mapping)))
1315
+ glyph = self.old_coverage_[index]
1316
+ glyph_mapping = mapping[glyph] = []
1317
+ for element in content:
1318
+ if not isinstance(element, tuple):
1319
+ continue
1320
+ element_name, element_attrs, _ = element
1321
+ if element_name == "Substitute":
1322
+ glyph_mapping.append(element_attrs["value"])
1323
+ return
1324
+
1325
+ # TTX v3.1 and later.
1326
+ outGlyphs = attrs["out"].split(",") if attrs["out"] else []
1327
+ mapping[attrs["in"]] = [g.strip() for g in outGlyphs]
1328
+
1329
+ @staticmethod
1330
+ def makeSequence_(g):
1331
+ seq = Sequence()
1332
+ seq.Substitute = g
1333
+ return seq
1334
+
1335
+
1336
+ class ClassDef(FormatSwitchingBaseTable):
1337
+ def populateDefaults(self, propagator=None):
1338
+ if not hasattr(self, "classDefs"):
1339
+ self.classDefs = {}
1340
+
1341
+ def postRead(self, rawTable, font):
1342
+ classDefs = {}
1343
+
1344
+ if self.Format == 1:
1345
+ start = rawTable["StartGlyph"]
1346
+ classList = rawTable["ClassValueArray"]
1347
+ startID = font.getGlyphID(start)
1348
+ endID = startID + len(classList)
1349
+ glyphNames = font.getGlyphNameMany(range(startID, endID))
1350
+ for glyphName, cls in zip(glyphNames, classList):
1351
+ if cls:
1352
+ classDefs[glyphName] = cls
1353
+
1354
+ elif self.Format == 2:
1355
+ records = rawTable["ClassRangeRecord"]
1356
+ for rec in records:
1357
+ cls = rec.Class
1358
+ if not cls:
1359
+ continue
1360
+ start = rec.Start
1361
+ end = rec.End
1362
+ startID = font.getGlyphID(start)
1363
+ endID = font.getGlyphID(end) + 1
1364
+ glyphNames = font.getGlyphNameMany(range(startID, endID))
1365
+ for glyphName in glyphNames:
1366
+ classDefs[glyphName] = cls
1367
+ else:
1368
+ log.warning("Unknown ClassDef format: %s", self.Format)
1369
+ self.classDefs = classDefs
1370
+ del self.Format # Don't need this anymore
1371
+
1372
+ def _getClassRanges(self, font):
1373
+ classDefs = getattr(self, "classDefs", None)
1374
+ if classDefs is None:
1375
+ self.classDefs = {}
1376
+ return
1377
+ getGlyphID = font.getGlyphID
1378
+ items = []
1379
+ for glyphName, cls in classDefs.items():
1380
+ if not cls:
1381
+ continue
1382
+ items.append((getGlyphID(glyphName), glyphName, cls))
1383
+ if items:
1384
+ items.sort()
1385
+ last, lastName, lastCls = items[0]
1386
+ ranges = [[lastCls, last, lastName]]
1387
+ for glyphID, glyphName, cls in items[1:]:
1388
+ if glyphID != last + 1 or cls != lastCls:
1389
+ ranges[-1].extend([last, lastName])
1390
+ ranges.append([cls, glyphID, glyphName])
1391
+ last = glyphID
1392
+ lastName = glyphName
1393
+ lastCls = cls
1394
+ ranges[-1].extend([last, lastName])
1395
+ return ranges
1396
+
1397
+ def preWrite(self, font):
1398
+ format = 2
1399
+ rawTable = {"ClassRangeRecord": []}
1400
+ ranges = self._getClassRanges(font)
1401
+ if ranges:
1402
+ startGlyph = ranges[0][1]
1403
+ endGlyph = ranges[-1][3]
1404
+ glyphCount = endGlyph - startGlyph + 1
1405
+ if len(ranges) * 3 < glyphCount + 1:
1406
+ # Format 2 is more compact
1407
+ for i, (cls, start, startName, end, endName) in enumerate(ranges):
1408
+ rec = ClassRangeRecord()
1409
+ rec.Start = startName
1410
+ rec.End = endName
1411
+ rec.Class = cls
1412
+ ranges[i] = rec
1413
+ format = 2
1414
+ rawTable = {"ClassRangeRecord": ranges}
1415
+ else:
1416
+ # Format 1 is more compact
1417
+ startGlyphName = ranges[0][2]
1418
+ classes = [0] * glyphCount
1419
+ for cls, start, startName, end, endName in ranges:
1420
+ for g in range(start - startGlyph, end - startGlyph + 1):
1421
+ classes[g] = cls
1422
+ format = 1
1423
+ rawTable = {"StartGlyph": startGlyphName, "ClassValueArray": classes}
1424
+ self.Format = format
1425
+ return rawTable
1426
+
1427
+ def toXML2(self, xmlWriter, font):
1428
+ items = sorted(self.classDefs.items())
1429
+ for glyphName, cls in items:
1430
+ xmlWriter.simpletag("ClassDef", [("glyph", glyphName), ("class", cls)])
1431
+ xmlWriter.newline()
1432
+
1433
+ def fromXML(self, name, attrs, content, font):
1434
+ classDefs = getattr(self, "classDefs", None)
1435
+ if classDefs is None:
1436
+ classDefs = {}
1437
+ self.classDefs = classDefs
1438
+ classDefs[attrs["glyph"]] = int(attrs["class"])
1439
+
1440
+
1441
+ class AlternateSubst(FormatSwitchingBaseTable):
1442
+ def populateDefaults(self, propagator=None):
1443
+ if not hasattr(self, "alternates"):
1444
+ self.alternates = {}
1445
+
1446
+ def postRead(self, rawTable, font):
1447
+ alternates = {}
1448
+ if self.Format == 1:
1449
+ input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
1450
+ alts = rawTable["AlternateSet"]
1451
+ assert len(input) == len(alts)
1452
+ for inp, alt in zip(input, alts):
1453
+ alternates[inp] = alt.Alternate
1454
+ else:
1455
+ assert 0, "unknown format: %s" % self.Format
1456
+ self.alternates = alternates
1457
+ del self.Format # Don't need this anymore
1458
+
1459
+ def preWrite(self, font):
1460
+ self.Format = 1
1461
+ alternates = getattr(self, "alternates", None)
1462
+ if alternates is None:
1463
+ alternates = self.alternates = {}
1464
+ items = list(alternates.items())
1465
+ for i, (glyphName, set) in enumerate(items):
1466
+ items[i] = font.getGlyphID(glyphName), glyphName, set
1467
+ items.sort()
1468
+ cov = Coverage()
1469
+ cov.glyphs = [item[1] for item in items]
1470
+ alternates = []
1471
+ setList = [item[-1] for item in items]
1472
+ for set in setList:
1473
+ alts = AlternateSet()
1474
+ alts.Alternate = set
1475
+ alternates.append(alts)
1476
+ # a special case to deal with the fact that several hundred Adobe Japan1-5
1477
+ # CJK fonts will overflow an offset if the coverage table isn't pushed to the end.
1478
+ # Also useful in that when splitting a sub-table because of an offset overflow
1479
+ # I don't need to calculate the change in the subtable offset due to the change in the coverage table size.
1480
+ # Allows packing more rules in subtable.
1481
+ self.sortCoverageLast = 1
1482
+ return {"Coverage": cov, "AlternateSet": alternates}
1483
+
1484
+ def toXML2(self, xmlWriter, font):
1485
+ items = sorted(self.alternates.items())
1486
+ for glyphName, alternates in items:
1487
+ xmlWriter.begintag("AlternateSet", glyph=glyphName)
1488
+ xmlWriter.newline()
1489
+ for alt in alternates:
1490
+ xmlWriter.simpletag("Alternate", glyph=alt)
1491
+ xmlWriter.newline()
1492
+ xmlWriter.endtag("AlternateSet")
1493
+ xmlWriter.newline()
1494
+
1495
+ def fromXML(self, name, attrs, content, font):
1496
+ alternates = getattr(self, "alternates", None)
1497
+ if alternates is None:
1498
+ alternates = {}
1499
+ self.alternates = alternates
1500
+ glyphName = attrs["glyph"]
1501
+ set = []
1502
+ alternates[glyphName] = set
1503
+ for element in content:
1504
+ if not isinstance(element, tuple):
1505
+ continue
1506
+ name, attrs, content = element
1507
+ set.append(attrs["glyph"])
1508
+
1509
+
1510
+ class LigatureSubst(FormatSwitchingBaseTable):
1511
+ def populateDefaults(self, propagator=None):
1512
+ if not hasattr(self, "ligatures"):
1513
+ self.ligatures = {}
1514
+
1515
+ def postRead(self, rawTable, font):
1516
+ ligatures = {}
1517
+ if self.Format == 1:
1518
+ input = _getGlyphsFromCoverageTable(rawTable["Coverage"])
1519
+ ligSets = rawTable["LigatureSet"]
1520
+ assert len(input) == len(ligSets)
1521
+ for i, inp in enumerate(input):
1522
+ ligatures[inp] = ligSets[i].Ligature
1523
+ else:
1524
+ assert 0, "unknown format: %s" % self.Format
1525
+ self.ligatures = ligatures
1526
+ del self.Format # Don't need this anymore
1527
+
1528
+ @staticmethod
1529
+ def _getLigatureSortKey(components):
1530
+ # Computes a key for ordering ligatures in a GSUB Type-4 lookup.
1531
+
1532
+ # When building the OpenType lookup, we need to make sure that
1533
+ # the longest sequence of components is listed first, so we
1534
+ # use the negative length as the key for sorting.
1535
+ # Note, we no longer need to worry about deterministic order because the
1536
+ # ligature mapping `dict` remembers the insertion order, and this in
1537
+ # turn depends on the order in which the ligatures are written in the FEA.
1538
+ # Since python sort algorithm is stable, the ligatures of equal length
1539
+ # will keep the relative order in which they appear in the feature file.
1540
+ # For example, given the following ligatures (all starting with 'f' and
1541
+ # thus belonging to the same LigatureSet):
1542
+ #
1543
+ # feature liga {
1544
+ # sub f i by f_i;
1545
+ # sub f f f by f_f_f;
1546
+ # sub f f by f_f;
1547
+ # sub f f i by f_f_i;
1548
+ # } liga;
1549
+ #
1550
+ # this should sort to: f_f_f, f_f_i, f_i, f_f
1551
+ # This is also what fea-rs does, see:
1552
+ # https://github.com/adobe-type-tools/afdko/issues/1727
1553
+ # https://github.com/fonttools/fonttools/issues/3428
1554
+ # https://github.com/googlefonts/fontc/pull/680
1555
+ return -len(components)
1556
+
1557
+ def preWrite(self, font):
1558
+ self.Format = 1
1559
+ ligatures = getattr(self, "ligatures", None)
1560
+ if ligatures is None:
1561
+ ligatures = self.ligatures = {}
1562
+
1563
+ if ligatures and isinstance(next(iter(ligatures)), tuple):
1564
+ # New high-level API in v3.1 and later. Note that we just support compiling this
1565
+ # for now. We don't load to this API, and don't do XML with it.
1566
+
1567
+ # ligatures is map from components-sequence to lig-glyph
1568
+ newLigatures = dict()
1569
+ for comps in sorted(ligatures.keys(), key=self._getLigatureSortKey):
1570
+ ligature = Ligature()
1571
+ ligature.Component = comps[1:]
1572
+ ligature.CompCount = len(comps)
1573
+ ligature.LigGlyph = ligatures[comps]
1574
+ newLigatures.setdefault(comps[0], []).append(ligature)
1575
+ ligatures = newLigatures
1576
+
1577
+ items = list(ligatures.items())
1578
+ for i, (glyphName, set) in enumerate(items):
1579
+ items[i] = font.getGlyphID(glyphName), glyphName, set
1580
+ items.sort()
1581
+ cov = Coverage()
1582
+ cov.glyphs = [item[1] for item in items]
1583
+
1584
+ ligSets = []
1585
+ setList = [item[-1] for item in items]
1586
+ for set in setList:
1587
+ ligSet = LigatureSet()
1588
+ ligs = ligSet.Ligature = []
1589
+ for lig in set:
1590
+ ligs.append(lig)
1591
+ ligSets.append(ligSet)
1592
+ # Useful in that when splitting a sub-table because of an offset overflow
1593
+ # I don't need to calculate the change in subtabl offset due to the coverage table size.
1594
+ # Allows packing more rules in subtable.
1595
+ self.sortCoverageLast = 1
1596
+ return {"Coverage": cov, "LigatureSet": ligSets}
1597
+
1598
+ def toXML2(self, xmlWriter, font):
1599
+ items = sorted(self.ligatures.items())
1600
+ for glyphName, ligSets in items:
1601
+ xmlWriter.begintag("LigatureSet", glyph=glyphName)
1602
+ xmlWriter.newline()
1603
+ for lig in ligSets:
1604
+ xmlWriter.simpletag(
1605
+ "Ligature", glyph=lig.LigGlyph, components=",".join(lig.Component)
1606
+ )
1607
+ xmlWriter.newline()
1608
+ xmlWriter.endtag("LigatureSet")
1609
+ xmlWriter.newline()
1610
+
1611
+ def fromXML(self, name, attrs, content, font):
1612
+ ligatures = getattr(self, "ligatures", None)
1613
+ if ligatures is None:
1614
+ ligatures = {}
1615
+ self.ligatures = ligatures
1616
+ glyphName = attrs["glyph"]
1617
+ ligs = []
1618
+ ligatures[glyphName] = ligs
1619
+ for element in content:
1620
+ if not isinstance(element, tuple):
1621
+ continue
1622
+ name, attrs, content = element
1623
+ lig = Ligature()
1624
+ lig.LigGlyph = attrs["glyph"]
1625
+ components = attrs["components"]
1626
+ lig.Component = components.split(",") if components else []
1627
+ lig.CompCount = len(lig.Component)
1628
+ ligs.append(lig)
1629
+
1630
+
1631
+ class COLR(BaseTable):
1632
+ def decompile(self, reader, font):
1633
+ # COLRv0 is exceptional in that LayerRecordCount appears *after* the
1634
+ # LayerRecordArray it counts, but the parser logic expects Count fields
1635
+ # to always precede the arrays. Here we work around this by parsing the
1636
+ # LayerRecordCount before the rest of the table, and storing it in
1637
+ # the reader's local state.
1638
+ subReader = reader.getSubReader(offset=0)
1639
+ for conv in self.getConverters():
1640
+ if conv.name != "LayerRecordCount":
1641
+ subReader.advance(conv.staticSize)
1642
+ continue
1643
+ reader[conv.name] = conv.read(subReader, font, tableDict={})
1644
+ break
1645
+ else:
1646
+ raise AssertionError("LayerRecordCount converter not found")
1647
+ return BaseTable.decompile(self, reader, font)
1648
+
1649
+ def preWrite(self, font):
1650
+ # The writer similarly assumes Count values precede the things counted,
1651
+ # thus here we pre-initialize a CountReference; the actual count value
1652
+ # will be set to the lenght of the array by the time this is assembled.
1653
+ self.LayerRecordCount = None
1654
+ return {
1655
+ **self.__dict__,
1656
+ "LayerRecordCount": CountReference(self.__dict__, "LayerRecordCount"),
1657
+ }
1658
+
1659
+ def computeClipBoxes(self, glyphSet: "_TTGlyphSet", quantization: int = 1):
1660
+ if self.Version == 0:
1661
+ return
1662
+
1663
+ clips = {}
1664
+ for rec in self.BaseGlyphList.BaseGlyphPaintRecord:
1665
+ try:
1666
+ clipBox = rec.Paint.computeClipBox(self, glyphSet, quantization)
1667
+ except Exception as e:
1668
+ from core_pdf.impl.third_party._vendor.fontTools.ttLib import TTLibError
1669
+
1670
+ raise TTLibError(
1671
+ f"Failed to compute COLR ClipBox for {rec.BaseGlyph!r}"
1672
+ ) from e
1673
+
1674
+ if clipBox is not None:
1675
+ clips[rec.BaseGlyph] = clipBox
1676
+
1677
+ hasClipList = hasattr(self, "ClipList") and self.ClipList is not None
1678
+ if not clips:
1679
+ if hasClipList:
1680
+ self.ClipList = None
1681
+ else:
1682
+ if not hasClipList:
1683
+ self.ClipList = ClipList()
1684
+ self.ClipList.Format = 1
1685
+ self.ClipList.clips = clips
1686
+
1687
+
1688
+ class LookupList(BaseTable):
1689
+ @property
1690
+ def table(self):
1691
+ for l in self.Lookup:
1692
+ for st in l.SubTable:
1693
+ if type(st).__name__.endswith("Subst"):
1694
+ return "GSUB"
1695
+ if type(st).__name__.endswith("Pos"):
1696
+ return "GPOS"
1697
+ raise ValueError
1698
+
1699
+ def toXML2(self, xmlWriter, font):
1700
+ if (
1701
+ not font
1702
+ or "Debg" not in font
1703
+ or LOOKUP_DEBUG_INFO_KEY not in font["Debg"].data
1704
+ ):
1705
+ return super().toXML2(xmlWriter, font)
1706
+ debugData = font["Debg"].data[LOOKUP_DEBUG_INFO_KEY][self.table]
1707
+ for conv in self.getConverters():
1708
+ if conv.repeat:
1709
+ value = getattr(self, conv.name, [])
1710
+ for lookupIndex, item in enumerate(value):
1711
+ if str(lookupIndex) in debugData:
1712
+ info = LookupDebugInfo(*debugData[str(lookupIndex)])
1713
+ tag = info.location
1714
+ if info.name:
1715
+ tag = f"{info.name}: {tag}"
1716
+ if info.feature:
1717
+ script, language, feature = info.feature
1718
+ tag = f"{tag} in {feature} ({script}/{language})"
1719
+ xmlWriter.comment(tag)
1720
+ xmlWriter.newline()
1721
+
1722
+ conv.xmlWrite(
1723
+ xmlWriter, font, item, conv.name, [("index", lookupIndex)]
1724
+ )
1725
+ else:
1726
+ if conv.aux and not eval(conv.aux, None, vars(self)):
1727
+ continue
1728
+ value = getattr(
1729
+ self, conv.name, None
1730
+ ) # TODO Handle defaults instead of defaulting to None!
1731
+ conv.xmlWrite(xmlWriter, font, value, conv.name, [])
1732
+
1733
+
1734
+ class BaseGlyphRecordArray(BaseTable):
1735
+ def preWrite(self, font):
1736
+ self.BaseGlyphRecord = sorted(
1737
+ self.BaseGlyphRecord, key=lambda rec: font.getGlyphID(rec.BaseGlyph)
1738
+ )
1739
+ return self.__dict__.copy()
1740
+
1741
+
1742
+ class BaseGlyphList(BaseTable):
1743
+ def preWrite(self, font):
1744
+ self.BaseGlyphPaintRecord = sorted(
1745
+ self.BaseGlyphPaintRecord, key=lambda rec: font.getGlyphID(rec.BaseGlyph)
1746
+ )
1747
+ return self.__dict__.copy()
1748
+
1749
+
1750
+ class ClipBoxFormat(IntEnum):
1751
+ Static = 1
1752
+ Variable = 2
1753
+
1754
+ def is_variable(self):
1755
+ return self is self.Variable
1756
+
1757
+ def as_variable(self):
1758
+ return self.Variable
1759
+
1760
+
1761
+ class ClipBox(getFormatSwitchingBaseTableClass("uint8")):
1762
+ formatEnum = ClipBoxFormat
1763
+
1764
+ def as_tuple(self):
1765
+ return tuple(getattr(self, conv.name) for conv in self.getConverters())
1766
+
1767
+ def __repr__(self):
1768
+ return f"{self.__class__.__name__}{self.as_tuple()}"
1769
+
1770
+
1771
+ class ClipList(getFormatSwitchingBaseTableClass("uint8")):
1772
+ def populateDefaults(self, propagator=None):
1773
+ if not hasattr(self, "clips"):
1774
+ self.clips = {}
1775
+
1776
+ def postRead(self, rawTable, font):
1777
+ clips = {}
1778
+ glyphOrder = font.getGlyphOrder()
1779
+ for i, rec in enumerate(rawTable["ClipRecord"]):
1780
+ if rec.StartGlyphID > rec.EndGlyphID:
1781
+ log.warning(
1782
+ "invalid ClipRecord[%i].StartGlyphID (%i) > "
1783
+ "EndGlyphID (%i); skipped",
1784
+ i,
1785
+ rec.StartGlyphID,
1786
+ rec.EndGlyphID,
1787
+ )
1788
+ continue
1789
+ redefinedGlyphs = []
1790
+ missingGlyphs = []
1791
+ for glyphID in range(rec.StartGlyphID, rec.EndGlyphID + 1):
1792
+ try:
1793
+ glyph = glyphOrder[glyphID]
1794
+ except IndexError:
1795
+ missingGlyphs.append(glyphID)
1796
+ continue
1797
+ if glyph not in clips:
1798
+ clips[glyph] = copy.copy(rec.ClipBox)
1799
+ else:
1800
+ redefinedGlyphs.append(glyphID)
1801
+ if redefinedGlyphs:
1802
+ log.warning(
1803
+ "ClipRecord[%i] overlaps previous records; "
1804
+ "ignoring redefined clip boxes for the "
1805
+ "following glyph ID range: [%i-%i]",
1806
+ i,
1807
+ min(redefinedGlyphs),
1808
+ max(redefinedGlyphs),
1809
+ )
1810
+ if missingGlyphs:
1811
+ log.warning(
1812
+ "ClipRecord[%i] range references missing " "glyph IDs: [%i-%i]",
1813
+ i,
1814
+ min(missingGlyphs),
1815
+ max(missingGlyphs),
1816
+ )
1817
+ self.clips = clips
1818
+
1819
+ def groups(self):
1820
+ glyphsByClip = defaultdict(list)
1821
+ uniqueClips = {}
1822
+ for glyphName, clipBox in self.clips.items():
1823
+ key = clipBox.as_tuple()
1824
+ glyphsByClip[key].append(glyphName)
1825
+ if key not in uniqueClips:
1826
+ uniqueClips[key] = clipBox
1827
+ return {
1828
+ frozenset(glyphs): uniqueClips[key] for key, glyphs in glyphsByClip.items()
1829
+ }
1830
+
1831
+ def preWrite(self, font):
1832
+ if not hasattr(self, "clips"):
1833
+ self.clips = {}
1834
+ clipBoxRanges = {}
1835
+ glyphMap = font.getReverseGlyphMap()
1836
+ for glyphs, clipBox in self.groups().items():
1837
+ glyphIDs = sorted(
1838
+ glyphMap[glyphName] for glyphName in glyphs if glyphName in glyphMap
1839
+ )
1840
+ if not glyphIDs:
1841
+ continue
1842
+ last = glyphIDs[0]
1843
+ ranges = [[last]]
1844
+ for glyphID in glyphIDs[1:]:
1845
+ if glyphID != last + 1:
1846
+ ranges[-1].append(last)
1847
+ ranges.append([glyphID])
1848
+ last = glyphID
1849
+ ranges[-1].append(last)
1850
+ for start, end in ranges:
1851
+ assert (start, end) not in clipBoxRanges
1852
+ clipBoxRanges[(start, end)] = clipBox
1853
+
1854
+ clipRecords = []
1855
+ for (start, end), clipBox in sorted(clipBoxRanges.items()):
1856
+ record = ClipRecord()
1857
+ record.StartGlyphID = start
1858
+ record.EndGlyphID = end
1859
+ record.ClipBox = clipBox
1860
+ clipRecords.append(record)
1861
+ rawTable = {
1862
+ "ClipCount": len(clipRecords),
1863
+ "ClipRecord": clipRecords,
1864
+ }
1865
+ return rawTable
1866
+
1867
+ def toXML(self, xmlWriter, font, attrs=None, name=None):
1868
+ tableName = name if name else self.__class__.__name__
1869
+ if attrs is None:
1870
+ attrs = []
1871
+ if hasattr(self, "Format"):
1872
+ attrs.append(("Format", self.Format))
1873
+ xmlWriter.begintag(tableName, attrs)
1874
+ xmlWriter.newline()
1875
+ # sort clips alphabetically to ensure deterministic XML dump
1876
+ for glyphs, clipBox in sorted(
1877
+ self.groups().items(), key=lambda item: min(item[0])
1878
+ ):
1879
+ xmlWriter.begintag("Clip")
1880
+ xmlWriter.newline()
1881
+ for glyphName in sorted(glyphs):
1882
+ xmlWriter.simpletag("Glyph", value=glyphName)
1883
+ xmlWriter.newline()
1884
+ xmlWriter.begintag("ClipBox", [("Format", clipBox.Format)])
1885
+ xmlWriter.newline()
1886
+ clipBox.toXML2(xmlWriter, font)
1887
+ xmlWriter.endtag("ClipBox")
1888
+ xmlWriter.newline()
1889
+ xmlWriter.endtag("Clip")
1890
+ xmlWriter.newline()
1891
+ xmlWriter.endtag(tableName)
1892
+ xmlWriter.newline()
1893
+
1894
+ def fromXML(self, name, attrs, content, font):
1895
+ clips = getattr(self, "clips", None)
1896
+ if clips is None:
1897
+ self.clips = clips = {}
1898
+ assert name == "Clip"
1899
+ glyphs = []
1900
+ clipBox = None
1901
+ for elem in content:
1902
+ if not isinstance(elem, tuple):
1903
+ continue
1904
+ name, attrs, content = elem
1905
+ if name == "Glyph":
1906
+ glyphs.append(attrs["value"])
1907
+ elif name == "ClipBox":
1908
+ clipBox = ClipBox()
1909
+ clipBox.Format = safeEval(attrs["Format"])
1910
+ for elem in content:
1911
+ if not isinstance(elem, tuple):
1912
+ continue
1913
+ name, attrs, content = elem
1914
+ clipBox.fromXML(name, attrs, content, font)
1915
+ if clipBox:
1916
+ for glyphName in glyphs:
1917
+ clips[glyphName] = clipBox
1918
+
1919
+
1920
+ class ExtendMode(IntEnum):
1921
+ PAD = 0
1922
+ REPEAT = 1
1923
+ REFLECT = 2
1924
+
1925
+
1926
+ # Porter-Duff modes for COLRv1 PaintComposite:
1927
+ # https://github.com/googlefonts/colr-gradients-spec/tree/off_sub_1#compositemode-enumeration
1928
+ class CompositeMode(IntEnum):
1929
+ CLEAR = 0
1930
+ SRC = 1
1931
+ DEST = 2
1932
+ SRC_OVER = 3
1933
+ DEST_OVER = 4
1934
+ SRC_IN = 5
1935
+ DEST_IN = 6
1936
+ SRC_OUT = 7
1937
+ DEST_OUT = 8
1938
+ SRC_ATOP = 9
1939
+ DEST_ATOP = 10
1940
+ XOR = 11
1941
+ PLUS = 12
1942
+ SCREEN = 13
1943
+ OVERLAY = 14
1944
+ DARKEN = 15
1945
+ LIGHTEN = 16
1946
+ COLOR_DODGE = 17
1947
+ COLOR_BURN = 18
1948
+ HARD_LIGHT = 19
1949
+ SOFT_LIGHT = 20
1950
+ DIFFERENCE = 21
1951
+ EXCLUSION = 22
1952
+ MULTIPLY = 23
1953
+ HSL_HUE = 24
1954
+ HSL_SATURATION = 25
1955
+ HSL_COLOR = 26
1956
+ HSL_LUMINOSITY = 27
1957
+
1958
+
1959
+ class PaintFormat(IntEnum):
1960
+ PaintColrLayers = 1
1961
+ PaintSolid = 2
1962
+ PaintVarSolid = 3
1963
+ PaintLinearGradient = 4
1964
+ PaintVarLinearGradient = 5
1965
+ PaintRadialGradient = 6
1966
+ PaintVarRadialGradient = 7
1967
+ PaintSweepGradient = 8
1968
+ PaintVarSweepGradient = 9
1969
+ PaintGlyph = 10
1970
+ PaintColrGlyph = 11
1971
+ PaintTransform = 12
1972
+ PaintVarTransform = 13
1973
+ PaintTranslate = 14
1974
+ PaintVarTranslate = 15
1975
+ PaintScale = 16
1976
+ PaintVarScale = 17
1977
+ PaintScaleAroundCenter = 18
1978
+ PaintVarScaleAroundCenter = 19
1979
+ PaintScaleUniform = 20
1980
+ PaintVarScaleUniform = 21
1981
+ PaintScaleUniformAroundCenter = 22
1982
+ PaintVarScaleUniformAroundCenter = 23
1983
+ PaintRotate = 24
1984
+ PaintVarRotate = 25
1985
+ PaintRotateAroundCenter = 26
1986
+ PaintVarRotateAroundCenter = 27
1987
+ PaintSkew = 28
1988
+ PaintVarSkew = 29
1989
+ PaintSkewAroundCenter = 30
1990
+ PaintVarSkewAroundCenter = 31
1991
+ PaintComposite = 32
1992
+
1993
+ def is_variable(self):
1994
+ return self.name.startswith("PaintVar")
1995
+
1996
+ def as_variable(self):
1997
+ if self.is_variable():
1998
+ return self
1999
+ try:
2000
+ return PaintFormat.__members__[f"PaintVar{self.name[5:]}"]
2001
+ except KeyError:
2002
+ return None
2003
+
2004
+
2005
+ class Paint(getFormatSwitchingBaseTableClass("uint8")):
2006
+ formatEnum = PaintFormat
2007
+
2008
+ def getFormatName(self):
2009
+ try:
2010
+ return self.formatEnum(self.Format).name
2011
+ except ValueError:
2012
+ raise NotImplementedError(f"Unknown Paint format: {self.Format}")
2013
+
2014
+ def toXML(self, xmlWriter, font, attrs=None, name=None):
2015
+ tableName = name if name else self.__class__.__name__
2016
+ if attrs is None:
2017
+ attrs = []
2018
+ attrs.append(("Format", self.Format))
2019
+ xmlWriter.begintag(tableName, attrs)
2020
+ xmlWriter.comment(self.getFormatName())
2021
+ xmlWriter.newline()
2022
+ self.toXML2(xmlWriter, font)
2023
+ xmlWriter.endtag(tableName)
2024
+ xmlWriter.newline()
2025
+
2026
+ def iterPaintSubTables(self, colr: COLR) -> Iterator[BaseTable.SubTableEntry]:
2027
+ if self.Format == PaintFormat.PaintColrLayers:
2028
+ # https://github.com/fonttools/fonttools/issues/2438: don't die when no LayerList exists
2029
+ layers = []
2030
+ if colr.LayerList is not None:
2031
+ layers = colr.LayerList.Paint
2032
+ yield from (
2033
+ BaseTable.SubTableEntry(name="Layers", value=v, index=i)
2034
+ for i, v in enumerate(
2035
+ layers[self.FirstLayerIndex : self.FirstLayerIndex + self.NumLayers]
2036
+ )
2037
+ )
2038
+ return
2039
+
2040
+ if self.Format == PaintFormat.PaintColrGlyph:
2041
+ for record in colr.BaseGlyphList.BaseGlyphPaintRecord:
2042
+ if record.BaseGlyph == self.Glyph:
2043
+ yield BaseTable.SubTableEntry(name="BaseGlyph", value=record.Paint)
2044
+ return
2045
+ else:
2046
+ raise KeyError(f"{self.Glyph!r} not in colr.BaseGlyphList")
2047
+
2048
+ for conv in self.getConverters():
2049
+ if conv.tableClass is not None and issubclass(conv.tableClass, type(self)):
2050
+ value = getattr(self, conv.name)
2051
+ yield BaseTable.SubTableEntry(name=conv.name, value=value)
2052
+
2053
+ def getChildren(self, colr) -> List["Paint"]:
2054
+ # this is kept for backward compatibility (e.g. it's used by the subsetter)
2055
+ return [p.value for p in self.iterPaintSubTables(colr)]
2056
+
2057
+ def traverse(self, colr: COLR, callback):
2058
+ """Depth-first traversal of graph rooted at self, callback on each node."""
2059
+ if not callable(callback):
2060
+ raise TypeError("callback must be callable")
2061
+
2062
+ for path in dfs_base_table(
2063
+ self, iter_subtables_fn=lambda paint: paint.iterPaintSubTables(colr)
2064
+ ):
2065
+ paint = path[-1].value
2066
+ callback(paint)
2067
+
2068
+ def getTransform(self) -> Transform:
2069
+ if self.Format == PaintFormat.PaintTransform:
2070
+ t = self.Transform
2071
+ return Transform(t.xx, t.yx, t.xy, t.yy, t.dx, t.dy)
2072
+ elif self.Format == PaintFormat.PaintTranslate:
2073
+ return Identity.translate(self.dx, self.dy)
2074
+ elif self.Format == PaintFormat.PaintScale:
2075
+ return Identity.scale(self.scaleX, self.scaleY)
2076
+ elif self.Format == PaintFormat.PaintScaleAroundCenter:
2077
+ return (
2078
+ Identity.translate(self.centerX, self.centerY)
2079
+ .scale(self.scaleX, self.scaleY)
2080
+ .translate(-self.centerX, -self.centerY)
2081
+ )
2082
+ elif self.Format == PaintFormat.PaintScaleUniform:
2083
+ return Identity.scale(self.scale)
2084
+ elif self.Format == PaintFormat.PaintScaleUniformAroundCenter:
2085
+ return (
2086
+ Identity.translate(self.centerX, self.centerY)
2087
+ .scale(self.scale)
2088
+ .translate(-self.centerX, -self.centerY)
2089
+ )
2090
+ elif self.Format == PaintFormat.PaintRotate:
2091
+ return Identity.rotate(radians(self.angle))
2092
+ elif self.Format == PaintFormat.PaintRotateAroundCenter:
2093
+ return (
2094
+ Identity.translate(self.centerX, self.centerY)
2095
+ .rotate(radians(self.angle))
2096
+ .translate(-self.centerX, -self.centerY)
2097
+ )
2098
+ elif self.Format == PaintFormat.PaintSkew:
2099
+ return Identity.skew(radians(-self.xSkewAngle), radians(self.ySkewAngle))
2100
+ elif self.Format == PaintFormat.PaintSkewAroundCenter:
2101
+ return (
2102
+ Identity.translate(self.centerX, self.centerY)
2103
+ .skew(radians(-self.xSkewAngle), radians(self.ySkewAngle))
2104
+ .translate(-self.centerX, -self.centerY)
2105
+ )
2106
+ if PaintFormat(self.Format).is_variable():
2107
+ raise NotImplementedError(f"Variable Paints not supported: {self.Format}")
2108
+
2109
+ return Identity
2110
+
2111
+ def computeClipBox(
2112
+ self, colr: COLR, glyphSet: "_TTGlyphSet", quantization: int = 1
2113
+ ) -> Optional[ClipBox]:
2114
+ pen = ControlBoundsPen(glyphSet)
2115
+ for path in dfs_base_table(
2116
+ self, iter_subtables_fn=lambda paint: paint.iterPaintSubTables(colr)
2117
+ ):
2118
+ paint = path[-1].value
2119
+ if paint.Format == PaintFormat.PaintGlyph:
2120
+ transformation = reduce(
2121
+ Transform.transform,
2122
+ (st.value.getTransform() for st in path),
2123
+ Identity,
2124
+ )
2125
+ glyphSet[paint.Glyph].draw(TransformPen(pen, transformation))
2126
+
2127
+ if pen.bounds is None:
2128
+ return None
2129
+
2130
+ cb = ClipBox()
2131
+ cb.Format = int(ClipBoxFormat.Static)
2132
+ cb.xMin, cb.yMin, cb.xMax, cb.yMax = quantizeRect(pen.bounds, quantization)
2133
+ return cb
2134
+
2135
+
2136
+ # For each subtable format there is a class. However, we don't really distinguish
2137
+ # between "field name" and "format name": often these are the same. Yet there's
2138
+ # a whole bunch of fields with different names. The following dict is a mapping
2139
+ # from "format name" to "field name". _buildClasses() uses this to create a
2140
+ # subclass for each alternate field name.
2141
+ #
2142
+ _equivalents = {
2143
+ "PatchMap": ("IFT ", "IFTX"),
2144
+ "MarkArray": ("Mark1Array",),
2145
+ "LangSys": ("DefaultLangSys",),
2146
+ "Coverage": (
2147
+ "MarkCoverage",
2148
+ "BaseCoverage",
2149
+ "LigatureCoverage",
2150
+ "Mark1Coverage",
2151
+ "Mark2Coverage",
2152
+ "BacktrackCoverage",
2153
+ "InputCoverage",
2154
+ "LookAheadCoverage",
2155
+ "VertGlyphCoverage",
2156
+ "HorizGlyphCoverage",
2157
+ "TopAccentCoverage",
2158
+ "ExtendedShapeCoverage",
2159
+ "MathKernCoverage",
2160
+ ),
2161
+ "ClassDef": (
2162
+ "ClassDef1",
2163
+ "ClassDef2",
2164
+ "BacktrackClassDef",
2165
+ "InputClassDef",
2166
+ "LookAheadClassDef",
2167
+ "GlyphClassDef",
2168
+ "MarkAttachClassDef",
2169
+ ),
2170
+ "Anchor": (
2171
+ "EntryAnchor",
2172
+ "ExitAnchor",
2173
+ "BaseAnchor",
2174
+ "LigatureAnchor",
2175
+ "Mark2Anchor",
2176
+ "MarkAnchor",
2177
+ ),
2178
+ "Device": (
2179
+ "XPlaDevice",
2180
+ "YPlaDevice",
2181
+ "XAdvDevice",
2182
+ "YAdvDevice",
2183
+ "XDeviceTable",
2184
+ "YDeviceTable",
2185
+ "DeviceTable",
2186
+ ),
2187
+ "Axis": (
2188
+ "HorizAxis",
2189
+ "VertAxis",
2190
+ ),
2191
+ "MinMax": ("DefaultMinMax",),
2192
+ "BaseCoord": (
2193
+ "MinCoord",
2194
+ "MaxCoord",
2195
+ ),
2196
+ "JstfLangSys": ("DefJstfLangSys",),
2197
+ "JstfGSUBModList": (
2198
+ "ShrinkageEnableGSUB",
2199
+ "ShrinkageDisableGSUB",
2200
+ "ExtensionEnableGSUB",
2201
+ "ExtensionDisableGSUB",
2202
+ ),
2203
+ "JstfGPOSModList": (
2204
+ "ShrinkageEnableGPOS",
2205
+ "ShrinkageDisableGPOS",
2206
+ "ExtensionEnableGPOS",
2207
+ "ExtensionDisableGPOS",
2208
+ ),
2209
+ "JstfMax": (
2210
+ "ShrinkageJstfMax",
2211
+ "ExtensionJstfMax",
2212
+ ),
2213
+ "MathKern": (
2214
+ "TopRightMathKern",
2215
+ "TopLeftMathKern",
2216
+ "BottomRightMathKern",
2217
+ "BottomLeftMathKern",
2218
+ ),
2219
+ "MathGlyphConstruction": ("VertGlyphConstruction", "HorizGlyphConstruction"),
2220
+ }
2221
+
2222
+ #
2223
+ # OverFlow logic, to automatically create ExtensionLookups
2224
+ # XXX This should probably move to otBase.py
2225
+ #
2226
+
2227
+
2228
+ def fixLookupOverFlows(ttf, overflowRecord):
2229
+ """Either the offset from the LookupList to a lookup overflowed, or
2230
+ an offset from a lookup to a subtable overflowed.
2231
+
2232
+ The table layout is::
2233
+
2234
+ GPSO/GUSB
2235
+ Script List
2236
+ Feature List
2237
+ LookUpList
2238
+ Lookup[0] and contents
2239
+ SubTable offset list
2240
+ SubTable[0] and contents
2241
+ ...
2242
+ SubTable[n] and contents
2243
+ ...
2244
+ Lookup[n] and contents
2245
+ SubTable offset list
2246
+ SubTable[0] and contents
2247
+ ...
2248
+ SubTable[n] and contents
2249
+
2250
+ If the offset to a lookup overflowed (SubTableIndex is None)
2251
+ we must promote the *previous* lookup to an Extension type.
2252
+
2253
+ If the offset from a lookup to subtable overflowed, then we must promote it
2254
+ to an Extension Lookup type.
2255
+ """
2256
+ ok = 0
2257
+ lookupIndex = overflowRecord.LookupListIndex
2258
+ if overflowRecord.SubTableIndex is None:
2259
+ lookupIndex = lookupIndex - 1
2260
+ if lookupIndex < 0:
2261
+ return ok
2262
+ if overflowRecord.tableType == "GSUB":
2263
+ extType = 7
2264
+ elif overflowRecord.tableType == "GPOS":
2265
+ extType = 9
2266
+
2267
+ lookups = ttf[overflowRecord.tableType].table.LookupList.Lookup
2268
+ lookup = lookups[lookupIndex]
2269
+ # If the previous lookup is an extType, look further back. Very unlikely, but possible.
2270
+ while lookup.SubTable[0].__class__.LookupType == extType:
2271
+ lookupIndex = lookupIndex - 1
2272
+ if lookupIndex < 0:
2273
+ return ok
2274
+ lookup = lookups[lookupIndex]
2275
+
2276
+ for lookupIndex in range(lookupIndex, len(lookups)):
2277
+ lookup = lookups[lookupIndex]
2278
+ if lookup.LookupType != extType:
2279
+ lookup.LookupType = extType
2280
+ for si, subTable in enumerate(lookup.SubTable):
2281
+ extSubTableClass = lookupTypes[overflowRecord.tableType][extType]
2282
+ extSubTable = extSubTableClass()
2283
+ extSubTable.Format = 1
2284
+ extSubTable.ExtSubTable = subTable
2285
+ lookup.SubTable[si] = extSubTable
2286
+ ok = 1
2287
+ return ok
2288
+
2289
+
2290
+ def splitMultipleSubst(oldSubTable, newSubTable, overflowRecord):
2291
+ ok = 1
2292
+ oldMapping = sorted(oldSubTable.mapping.items())
2293
+ oldLen = len(oldMapping)
2294
+
2295
+ if overflowRecord.itemName in ["Coverage", "RangeRecord"]:
2296
+ # Coverage table is written last. Overflow is to or within the
2297
+ # the coverage table. We will just cut the subtable in half.
2298
+ newLen = oldLen // 2
2299
+
2300
+ elif overflowRecord.itemName == "Sequence":
2301
+ # We just need to back up by two items from the overflowed
2302
+ # Sequence index to make sure the offset to the Coverage table
2303
+ # doesn't overflow.
2304
+ newLen = overflowRecord.itemIndex - 1
2305
+
2306
+ newSubTable.mapping = {}
2307
+ for i in range(newLen, oldLen):
2308
+ item = oldMapping[i]
2309
+ key = item[0]
2310
+ newSubTable.mapping[key] = item[1]
2311
+ del oldSubTable.mapping[key]
2312
+
2313
+ return ok
2314
+
2315
+
2316
+ def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord):
2317
+ ok = 1
2318
+ if hasattr(oldSubTable, "sortCoverageLast"):
2319
+ newSubTable.sortCoverageLast = oldSubTable.sortCoverageLast
2320
+
2321
+ oldAlts = sorted(oldSubTable.alternates.items())
2322
+ oldLen = len(oldAlts)
2323
+
2324
+ if overflowRecord.itemName in ["Coverage", "RangeRecord"]:
2325
+ # Coverage table is written last. overflow is to or within the
2326
+ # the coverage table. We will just cut the subtable in half.
2327
+ newLen = oldLen // 2
2328
+
2329
+ elif overflowRecord.itemName == "AlternateSet":
2330
+ # We just need to back up by two items
2331
+ # from the overflowed AlternateSet index to make sure the offset
2332
+ # to the Coverage table doesn't overflow.
2333
+ newLen = overflowRecord.itemIndex - 1
2334
+
2335
+ newSubTable.alternates = {}
2336
+ for i in range(newLen, oldLen):
2337
+ item = oldAlts[i]
2338
+ key = item[0]
2339
+ newSubTable.alternates[key] = item[1]
2340
+ del oldSubTable.alternates[key]
2341
+
2342
+ return ok
2343
+
2344
+
2345
+ def splitLigatureSubst(oldSubTable, newSubTable, overflowRecord):
2346
+ ok = 1
2347
+ oldLigs = sorted(oldSubTable.ligatures.items())
2348
+ oldLen = len(oldLigs)
2349
+
2350
+ if overflowRecord.itemName in ["Coverage", "RangeRecord"]:
2351
+ # Coverage table is written last. overflow is to or within the
2352
+ # the coverage table. We will just cut the subtable in half.
2353
+ newLen = oldLen // 2
2354
+
2355
+ elif overflowRecord.itemName == "LigatureSet":
2356
+ # We just need to back up by two items
2357
+ # from the overflowed AlternateSet index to make sure the offset
2358
+ # to the Coverage table doesn't overflow.
2359
+ newLen = overflowRecord.itemIndex - 1
2360
+
2361
+ newSubTable.ligatures = {}
2362
+ for i in range(newLen, oldLen):
2363
+ item = oldLigs[i]
2364
+ key = item[0]
2365
+ newSubTable.ligatures[key] = item[1]
2366
+ del oldSubTable.ligatures[key]
2367
+
2368
+ return ok
2369
+
2370
+
2371
+ def splitPairPos(oldSubTable, newSubTable, overflowRecord):
2372
+ st = oldSubTable
2373
+ ok = False
2374
+ newSubTable.Format = oldSubTable.Format
2375
+ if oldSubTable.Format == 1 and len(oldSubTable.PairSet) > 1:
2376
+ for name in "ValueFormat1", "ValueFormat2":
2377
+ setattr(newSubTable, name, getattr(oldSubTable, name))
2378
+
2379
+ # Move top half of coverage to new subtable
2380
+
2381
+ newSubTable.Coverage = oldSubTable.Coverage.__class__()
2382
+
2383
+ coverage = oldSubTable.Coverage.glyphs
2384
+ records = oldSubTable.PairSet
2385
+
2386
+ oldCount = len(oldSubTable.PairSet) // 2
2387
+
2388
+ oldSubTable.Coverage.glyphs = coverage[:oldCount]
2389
+ oldSubTable.PairSet = records[:oldCount]
2390
+
2391
+ newSubTable.Coverage.glyphs = coverage[oldCount:]
2392
+ newSubTable.PairSet = records[oldCount:]
2393
+
2394
+ oldSubTable.PairSetCount = len(oldSubTable.PairSet)
2395
+ newSubTable.PairSetCount = len(newSubTable.PairSet)
2396
+
2397
+ ok = True
2398
+
2399
+ elif oldSubTable.Format == 2 and len(oldSubTable.Class1Record) > 1:
2400
+ if not hasattr(oldSubTable, "Class2Count"):
2401
+ oldSubTable.Class2Count = len(oldSubTable.Class1Record[0].Class2Record)
2402
+ for name in "Class2Count", "ClassDef2", "ValueFormat1", "ValueFormat2":
2403
+ setattr(newSubTable, name, getattr(oldSubTable, name))
2404
+
2405
+ # The two subtables will still have the same ClassDef2 and the table
2406
+ # sharing will still cause the sharing to overflow. As such, disable
2407
+ # sharing on the one that is serialized second (that's oldSubTable).
2408
+ oldSubTable.DontShare = True
2409
+
2410
+ # Move top half of class numbers to new subtable
2411
+
2412
+ newSubTable.Coverage = oldSubTable.Coverage.__class__()
2413
+ newSubTable.ClassDef1 = oldSubTable.ClassDef1.__class__()
2414
+
2415
+ coverage = oldSubTable.Coverage.glyphs
2416
+ classDefs = oldSubTable.ClassDef1.classDefs
2417
+ records = oldSubTable.Class1Record
2418
+
2419
+ oldCount = len(oldSubTable.Class1Record) // 2
2420
+ newGlyphs = set(k for k, v in classDefs.items() if v >= oldCount)
2421
+
2422
+ oldSubTable.Coverage.glyphs = [g for g in coverage if g not in newGlyphs]
2423
+ oldSubTable.ClassDef1.classDefs = {
2424
+ k: v for k, v in classDefs.items() if v < oldCount
2425
+ }
2426
+ oldSubTable.Class1Record = records[:oldCount]
2427
+
2428
+ newSubTable.Coverage.glyphs = [g for g in coverage if g in newGlyphs]
2429
+ newSubTable.ClassDef1.classDefs = {
2430
+ k: (v - oldCount) for k, v in classDefs.items() if v > oldCount
2431
+ }
2432
+ newSubTable.Class1Record = records[oldCount:]
2433
+
2434
+ oldSubTable.Class1Count = len(oldSubTable.Class1Record)
2435
+ newSubTable.Class1Count = len(newSubTable.Class1Record)
2436
+
2437
+ ok = True
2438
+
2439
+ return ok
2440
+
2441
+
2442
+ def splitMarkBasePos(oldSubTable, newSubTable, overflowRecord):
2443
+ # split half of the mark classes to the new subtable
2444
+ classCount = oldSubTable.ClassCount
2445
+ if classCount < 2:
2446
+ # oh well, not much left to split...
2447
+ return False
2448
+
2449
+ oldClassCount = classCount // 2
2450
+ newClassCount = classCount - oldClassCount
2451
+
2452
+ oldMarkCoverage, oldMarkRecords = [], []
2453
+ newMarkCoverage, newMarkRecords = [], []
2454
+ for glyphName, markRecord in zip(
2455
+ oldSubTable.MarkCoverage.glyphs, oldSubTable.MarkArray.MarkRecord
2456
+ ):
2457
+ if markRecord.Class < oldClassCount:
2458
+ oldMarkCoverage.append(glyphName)
2459
+ oldMarkRecords.append(markRecord)
2460
+ else:
2461
+ markRecord.Class -= oldClassCount
2462
+ newMarkCoverage.append(glyphName)
2463
+ newMarkRecords.append(markRecord)
2464
+
2465
+ oldBaseRecords, newBaseRecords = [], []
2466
+ for rec in oldSubTable.BaseArray.BaseRecord:
2467
+ oldBaseRecord, newBaseRecord = rec.__class__(), rec.__class__()
2468
+ oldBaseRecord.BaseAnchor = rec.BaseAnchor[:oldClassCount]
2469
+ newBaseRecord.BaseAnchor = rec.BaseAnchor[oldClassCount:]
2470
+ oldBaseRecords.append(oldBaseRecord)
2471
+ newBaseRecords.append(newBaseRecord)
2472
+
2473
+ newSubTable.Format = oldSubTable.Format
2474
+
2475
+ oldSubTable.MarkCoverage.glyphs = oldMarkCoverage
2476
+ newSubTable.MarkCoverage = oldSubTable.MarkCoverage.__class__()
2477
+ newSubTable.MarkCoverage.glyphs = newMarkCoverage
2478
+
2479
+ # share the same BaseCoverage in both halves
2480
+ newSubTable.BaseCoverage = oldSubTable.BaseCoverage
2481
+
2482
+ oldSubTable.ClassCount = oldClassCount
2483
+ newSubTable.ClassCount = newClassCount
2484
+
2485
+ oldSubTable.MarkArray.MarkRecord = oldMarkRecords
2486
+ newSubTable.MarkArray = oldSubTable.MarkArray.__class__()
2487
+ newSubTable.MarkArray.MarkRecord = newMarkRecords
2488
+
2489
+ oldSubTable.MarkArray.MarkCount = len(oldMarkRecords)
2490
+ newSubTable.MarkArray.MarkCount = len(newMarkRecords)
2491
+
2492
+ oldSubTable.BaseArray.BaseRecord = oldBaseRecords
2493
+ newSubTable.BaseArray = oldSubTable.BaseArray.__class__()
2494
+ newSubTable.BaseArray.BaseRecord = newBaseRecords
2495
+
2496
+ oldSubTable.BaseArray.BaseCount = len(oldBaseRecords)
2497
+ newSubTable.BaseArray.BaseCount = len(newBaseRecords)
2498
+
2499
+ return True
2500
+
2501
+
2502
+ splitTable = {
2503
+ "GSUB": {
2504
+ # 1: splitSingleSubst,
2505
+ 2: splitMultipleSubst,
2506
+ 3: splitAlternateSubst,
2507
+ 4: splitLigatureSubst,
2508
+ # 5: splitContextSubst,
2509
+ # 6: splitChainContextSubst,
2510
+ # 7: splitExtensionSubst,
2511
+ # 8: splitReverseChainSingleSubst,
2512
+ },
2513
+ "GPOS": {
2514
+ # 1: splitSinglePos,
2515
+ 2: splitPairPos,
2516
+ # 3: splitCursivePos,
2517
+ 4: splitMarkBasePos,
2518
+ # 5: splitMarkLigPos,
2519
+ # 6: splitMarkMarkPos,
2520
+ # 7: splitContextPos,
2521
+ # 8: splitChainContextPos,
2522
+ # 9: splitExtensionPos,
2523
+ },
2524
+ }
2525
+
2526
+
2527
+ def fixSubTableOverFlows(ttf, overflowRecord):
2528
+ """
2529
+ An offset has overflowed within a sub-table. We need to divide this subtable into smaller parts.
2530
+ """
2531
+ table = ttf[overflowRecord.tableType].table
2532
+ lookup = table.LookupList.Lookup[overflowRecord.LookupListIndex]
2533
+ subIndex = overflowRecord.SubTableIndex
2534
+ subtable = lookup.SubTable[subIndex]
2535
+
2536
+ # First, try not sharing anything for this subtable...
2537
+ if not hasattr(subtable, "DontShare"):
2538
+ subtable.DontShare = True
2539
+ return True
2540
+
2541
+ if hasattr(subtable, "ExtSubTable"):
2542
+ # We split the subtable of the Extension table, and add a new Extension table
2543
+ # to contain the new subtable.
2544
+
2545
+ subTableType = subtable.ExtSubTable.__class__.LookupType
2546
+ extSubTable = subtable
2547
+ subtable = extSubTable.ExtSubTable
2548
+ newExtSubTableClass = lookupTypes[overflowRecord.tableType][
2549
+ extSubTable.__class__.LookupType
2550
+ ]
2551
+ newExtSubTable = newExtSubTableClass()
2552
+ newExtSubTable.Format = extSubTable.Format
2553
+ toInsert = newExtSubTable
2554
+
2555
+ newSubTableClass = lookupTypes[overflowRecord.tableType][subTableType]
2556
+ newSubTable = newSubTableClass()
2557
+ newExtSubTable.ExtSubTable = newSubTable
2558
+ else:
2559
+ subTableType = subtable.__class__.LookupType
2560
+ newSubTableClass = lookupTypes[overflowRecord.tableType][subTableType]
2561
+ newSubTable = newSubTableClass()
2562
+ toInsert = newSubTable
2563
+
2564
+ if hasattr(lookup, "SubTableCount"): # may not be defined yet.
2565
+ lookup.SubTableCount = lookup.SubTableCount + 1
2566
+
2567
+ try:
2568
+ splitFunc = splitTable[overflowRecord.tableType][subTableType]
2569
+ except KeyError:
2570
+ log.error(
2571
+ "Don't know how to split %s lookup type %s",
2572
+ overflowRecord.tableType,
2573
+ subTableType,
2574
+ )
2575
+ return False
2576
+
2577
+ ok = splitFunc(subtable, newSubTable, overflowRecord)
2578
+ if ok:
2579
+ lookup.SubTable.insert(subIndex + 1, toInsert)
2580
+ return ok
2581
+
2582
+
2583
+ # End of OverFlow logic
2584
+
2585
+
2586
+ # ---------------------------------------------------------------------------
2587
+ # IFT - Incremental Font Transfer tables
2588
+ # ---------------------------------------------------------------------------
2589
+
2590
+
2591
+ class EntryIdStringData(BaseTable):
2592
+ """IFT entry ID string data block (raw bytes pool)."""
2593
+
2594
+ def decompile(self, reader, font):
2595
+ # This subtable is reached via an LOffset, so the reader's data buffer
2596
+ # is already scoped to the bytes starting at the subtable's offset within
2597
+ # the IFT table blob. Reading to the end of that buffer is correct; the
2598
+ # actual bytes consumed are determined by the entryIdStringLength fields
2599
+ # in the MappingEntries records.
2600
+ self.data = bytes(reader.data[reader.pos :])
2601
+
2602
+ def compile(self, writer, font):
2603
+ writer.writeData(self.data)
2604
+
2605
+ def toXML2(self, xmlWriter, font):
2606
+ xmlWriter.simpletag("data", value=self.data.hex())
2607
+ xmlWriter.newline()
2608
+
2609
+ def fromXML(self, name, attrs, content, font):
2610
+ if name == "data":
2611
+ self.data = bytes.fromhex(attrs["value"])
2612
+
2613
+
2614
+ def _buildClasses():
2615
+ import re
2616
+ from .otData import otData
2617
+
2618
+ formatPat = re.compile(r"([A-Za-z0-9]+)Format(\d+)$")
2619
+ namespace = globals()
2620
+
2621
+ # populate module with classes
2622
+ for name, fields in otData:
2623
+ baseClass = BaseTable
2624
+ m = formatPat.match(name)
2625
+ if m:
2626
+ # XxxFormatN subtable, we only add the "base" table
2627
+ name = m.group(1)
2628
+ # the first row of a format-switching otData table describes the Format;
2629
+ # the first column defines the type of the Format field.
2630
+ # Currently this can be either 'uint16' or 'uint8'.
2631
+ formatType = fields[0].type
2632
+ baseClass = getFormatSwitchingBaseTableClass(formatType)
2633
+ if name not in namespace:
2634
+ # the class doesn't exist yet, so the base implementation is used.
2635
+ cls = type(name, (baseClass,), {})
2636
+ if name in ("GSUB", "GPOS"):
2637
+ cls.DontShare = True
2638
+ namespace[name] = cls
2639
+
2640
+ # link Var{Table} <-> {Table} (e.g. ColorStop <-> VarColorStop, etc.)
2641
+ for name, _ in otData:
2642
+ if name.startswith("Var") and len(name) > 3 and name[3:] in namespace:
2643
+ varType = namespace[name]
2644
+ noVarType = namespace[name[3:]]
2645
+ varType.NoVarType = noVarType
2646
+ noVarType.VarType = varType
2647
+
2648
+ for base, alts in _equivalents.items():
2649
+ base = namespace[base]
2650
+ for alt in alts:
2651
+ namespace[alt] = base
2652
+
2653
+ global lookupTypes
2654
+ lookupTypes = {
2655
+ "GSUB": {
2656
+ 1: SingleSubst,
2657
+ 2: MultipleSubst,
2658
+ 3: AlternateSubst,
2659
+ 4: LigatureSubst,
2660
+ 5: ContextSubst,
2661
+ 6: ChainContextSubst,
2662
+ 7: ExtensionSubst,
2663
+ 8: ReverseChainSingleSubst,
2664
+ },
2665
+ "GPOS": {
2666
+ 1: SinglePos,
2667
+ 2: PairPos,
2668
+ 3: CursivePos,
2669
+ 4: MarkBasePos,
2670
+ 5: MarkLigPos,
2671
+ 6: MarkMarkPos,
2672
+ 7: ContextPos,
2673
+ 8: ChainContextPos,
2674
+ 9: ExtensionPos,
2675
+ },
2676
+ "mort": {
2677
+ 4: NoncontextualMorph,
2678
+ },
2679
+ "morx": {
2680
+ 0: RearrangementMorph,
2681
+ 1: ContextualMorph,
2682
+ 2: LigatureMorph,
2683
+ # 3: Reserved,
2684
+ 4: NoncontextualMorph,
2685
+ 5: InsertionMorph,
2686
+ },
2687
+ }
2688
+ lookupTypes["JSTF"] = lookupTypes["GPOS"] # JSTF contains GPOS
2689
+ for lookupEnum in lookupTypes.values():
2690
+ for enum, cls in lookupEnum.items():
2691
+ cls.LookupType = enum
2692
+
2693
+ global featureParamTypes
2694
+ featureParamTypes = {
2695
+ "size": FeatureParamsSize,
2696
+ }
2697
+ for i in range(1, 20 + 1):
2698
+ featureParamTypes["ss%02d" % i] = FeatureParamsStylisticSet
2699
+ for i in range(1, 99 + 1):
2700
+ featureParamTypes["cv%02d" % i] = FeatureParamsCharacterVariants
2701
+
2702
+ # add converters to classes
2703
+ from .otConverters import buildConverters
2704
+
2705
+ for name, fields in otData:
2706
+ m = formatPat.match(name)
2707
+ if m:
2708
+ # XxxFormatN subtable, add converter to "base" table
2709
+ name, format = m.groups()
2710
+ format = int(format)
2711
+ cls = namespace[name]
2712
+ if not hasattr(cls, "converters"):
2713
+ cls.converters = {}
2714
+ cls.convertersByName = {}
2715
+ converters, convertersByName = buildConverters(fields[1:], namespace)
2716
+ cls.converters[format] = converters
2717
+ cls.convertersByName[format] = convertersByName
2718
+ # XXX Add staticSize?
2719
+ else:
2720
+ cls = namespace[name]
2721
+ cls.converters, cls.convertersByName = buildConverters(fields, namespace)
2722
+ # XXX Add staticSize?
2723
+
2724
+
2725
+ _buildClasses()
2726
+
2727
+
2728
+ def _getGlyphsFromCoverageTable(coverage):
2729
+ if coverage is None:
2730
+ # empty coverage table
2731
+ return []
2732
+ else:
2733
+ return coverage.glyphs