pagyra-js 0.0.1

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 (540) hide show
  1. package/.eslintrc.json +30 -0
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +275 -0
  4. package/UA_Styles_Chromium.md +93 -0
  5. package/_ext/woff2_conversion/brotli-decode.d.ts +139 -0
  6. package/_ext/woff2_conversion/brotli-encode.d.ts +129 -0
  7. package/_ext/woff2_conversion/brotli-port.d.ts +12 -0
  8. package/_ext/woff2_conversion/brotli-shared-dictionary.d.ts +25 -0
  9. package/_ext/woff2_conversion/brotli-types.d.ts +15 -0
  10. package/_ext/woff2_conversion/woff2-common.d.ts +37 -0
  11. package/_ext/woff2_conversion/woff2-decode.d.ts +32 -0
  12. package/_ext/woff2_conversion/woff2-encode.d.ts +31 -0
  13. package/_ext/woff2_conversion/woff2-output.d.ts +39 -0
  14. package/_ext/woff2_original_cpp/brotli/brotli.c +1559 -0
  15. package/_ext/woff2_original_cpp/brotli/brotli.md +116 -0
  16. package/_ext/woff2_original_cpp/brotli/decode.h +409 -0
  17. package/_ext/woff2_original_cpp/brotli/encode.h +505 -0
  18. package/_ext/woff2_original_cpp/brotli/port.h +302 -0
  19. package/_ext/woff2_original_cpp/brotli/shared_dictionary.h +100 -0
  20. package/_ext/woff2_original_cpp/brotli/types.h +83 -0
  21. package/_ext/woff2_original_cpp/cmake/FindBrotliDec.cmake +35 -0
  22. package/_ext/woff2_original_cpp/cmake/FindBrotliEnc.cmake +35 -0
  23. package/_ext/woff2_original_cpp/include/woff2/decode.h +36 -0
  24. package/_ext/woff2_original_cpp/include/woff2/encode.h +43 -0
  25. package/_ext/woff2_original_cpp/include/woff2/output.h +86 -0
  26. package/_ext/woff2_original_cpp/src/buffer.h +164 -0
  27. package/_ext/woff2_original_cpp/src/convert_woff2ttf_fuzzer.cc +13 -0
  28. package/_ext/woff2_original_cpp/src/convert_woff2ttf_fuzzer_new_entry.cc +12 -0
  29. package/_ext/woff2_original_cpp/src/file.h +30 -0
  30. package/_ext/woff2_original_cpp/src/font.cc +400 -0
  31. package/_ext/woff2_original_cpp/src/font.h +105 -0
  32. package/_ext/woff2_original_cpp/src/glyph.cc +383 -0
  33. package/_ext/woff2_original_cpp/src/glyph.h +71 -0
  34. package/_ext/woff2_original_cpp/src/normalize.cc +314 -0
  35. package/_ext/woff2_original_cpp/src/normalize.h +39 -0
  36. package/_ext/woff2_original_cpp/src/port.h +66 -0
  37. package/_ext/woff2_original_cpp/src/round.h +27 -0
  38. package/_ext/woff2_original_cpp/src/store_bytes.h +55 -0
  39. package/_ext/woff2_original_cpp/src/table_tags.cc +82 -0
  40. package/_ext/woff2_original_cpp/src/table_tags.h +30 -0
  41. package/_ext/woff2_original_cpp/src/transform.cc +430 -0
  42. package/_ext/woff2_original_cpp/src/transform.h +26 -0
  43. package/_ext/woff2_original_cpp/src/variable_length.cc +129 -0
  44. package/_ext/woff2_original_cpp/src/variable_length.h +30 -0
  45. package/_ext/woff2_original_cpp/src/woff2_common.cc +50 -0
  46. package/_ext/woff2_original_cpp/src/woff2_common.h +64 -0
  47. package/_ext/woff2_original_cpp/src/woff2_compress.cc +43 -0
  48. package/_ext/woff2_original_cpp/src/woff2_dec.cc +1398 -0
  49. package/_ext/woff2_original_cpp/src/woff2_decompress.cc +41 -0
  50. package/_ext/woff2_original_cpp/src/woff2_enc.cc +458 -0
  51. package/_ext/woff2_original_cpp/src/woff2_info.cc +142 -0
  52. package/_ext/woff2_original_cpp/src/woff2_out.cc +63 -0
  53. package/assets/fonts/ttf/arimo/Arimo-Bold.ttf +0 -0
  54. package/assets/fonts/ttf/arimo/Arimo-BoldItalic.ttf +0 -0
  55. package/assets/fonts/ttf/arimo/Arimo-Italic.ttf +0 -0
  56. package/assets/fonts/ttf/arimo/Arimo-Regular.ttf +0 -0
  57. package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Black.ttf +0 -0
  58. package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Bold.ttf +0 -0
  59. package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Regular.ttf +0 -0
  60. package/assets/fonts/ttf/dejavu/DejaVuSans.ttf +0 -0
  61. package/assets/fonts/ttf/firecode/FiraCode-Bold.ttf +0 -0
  62. package/assets/fonts/ttf/firecode/FiraCode-Light.ttf +0 -0
  63. package/assets/fonts/ttf/firecode/FiraCode-Medium.ttf +0 -0
  64. package/assets/fonts/ttf/firecode/FiraCode-Regular.ttf +0 -0
  65. package/assets/fonts/ttf/firecode/FiraCode-SemiBold.ttf +0 -0
  66. package/assets/fonts/ttf/notoemoji/NotoEmoji-Bold.ttf +0 -0
  67. package/assets/fonts/ttf/notoemoji/NotoEmoji-Light.ttf +0 -0
  68. package/assets/fonts/ttf/notoemoji/NotoEmoji-Medium.ttf +0 -0
  69. package/assets/fonts/ttf/notoemoji/NotoEmoji-Regular.ttf +0 -0
  70. package/assets/fonts/ttf/notoemoji/NotoEmoji-SemiBold.ttf +0 -0
  71. package/assets/fonts/ttf/notosans/NotoSans-Regular.ttf +0 -0
  72. package/assets/fonts/ttf/roboto/Roboto-Bold.ttf +0 -0
  73. package/assets/fonts/ttf/roboto/Roboto-BoldItalic.ttf +0 -0
  74. package/assets/fonts/ttf/roboto/Roboto-Italic.ttf +0 -0
  75. package/assets/fonts/ttf/roboto/Roboto-Regular.ttf +0 -0
  76. package/assets/fonts/ttf/stixtwomath/STIXTwoMath-Regular.ttf +0 -0
  77. package/assets/fonts/ttf/tinos/Tinos-Bold.ttf +0 -0
  78. package/assets/fonts/ttf/tinos/Tinos-BoldItalic.ttf +0 -0
  79. package/assets/fonts/ttf/tinos/Tinos-Italic.ttf +0 -0
  80. package/assets/fonts/ttf/tinos/Tinos-Regular.ttf +0 -0
  81. package/assets/fonts/woff/lato/lato-latin-400-italic.woff +0 -0
  82. package/assets/fonts/woff/lato/lato-latin-400-normal.woff +0 -0
  83. package/assets/fonts/woff/lato/lato-latin-700-italic.woff +0 -0
  84. package/assets/fonts/woff/lato/lato-latin-700-normal.woff +0 -0
  85. package/assets/fonts/woff2/caveat/Caveat-Bold.woff2 +0 -0
  86. package/assets/fonts/woff2/caveat/Caveat-Regular.woff2 +0 -0
  87. package/assets/fonts/woff2/lato/lato-latin-400-italic.woff2 +0 -0
  88. package/assets/fonts/woff2/lato/lato-latin-400-normal.woff2 +0 -0
  89. package/assets/fonts/woff2/lato/lato-latin-700-italic.woff2 +0 -0
  90. package/assets/fonts/woff2/lato/lato-latin-700-normal.woff2 +0 -0
  91. package/docs/AGENTS.md +288 -0
  92. package/docs/BACKGROUND-REPEAT-IMPLEMENTATION.md +127 -0
  93. package/docs/BACKGROUND-REPEAT-REFERENCE.md +127 -0
  94. package/docs/BACKGROUND-REPEAT-SPACE-ROUND.md +164 -0
  95. package/docs/css-properties-support.md +256 -0
  96. package/docs/src_modules_table.md +172 -0
  97. package/docs/text-overlap-fix.md +85 -0
  98. package/docs/text-overlap-investigation.md +27 -0
  99. package/eslint.config.js +36 -0
  100. package/glyph_measure.htm +1458 -0
  101. package/package.json +50 -0
  102. package/playground/browser-entry.ts +2 -0
  103. package/playground/exports/background-text-debug.pdf +0 -0
  104. package/playground/public/app.js +875 -0
  105. package/playground/public/assets/1.webp +0 -0
  106. package/playground/public/examples/accents-test.html +24 -0
  107. package/playground/public/examples/advanced-selectors-demo.html +118 -0
  108. package/playground/public/examples/background-advanced-showcase.html +82 -0
  109. package/playground/public/examples/background-clip-text.html +36 -0
  110. package/playground/public/examples/background-origin-showcase.html +137 -0
  111. package/playground/public/examples/background-position-showcase.html +83 -0
  112. package/playground/public/examples/background-repeat-showcase.html +83 -0
  113. package/playground/public/examples/background-repeat-space-round.html +348 -0
  114. package/playground/public/examples/background-size-showcase.html +82 -0
  115. package/playground/public/examples/background-text-debug.html +18 -0
  116. package/playground/public/examples/baseline-test.html +24 -0
  117. package/playground/public/examples/bold-showcase.html +150 -0
  118. package/playground/public/examples/bold-strike-example.html +12 -0
  119. package/playground/public/examples/border-collapse-test.html +23 -0
  120. package/playground/public/examples/centered-shadow-div.html +72 -0
  121. package/playground/public/examples/css-variables.html +50 -0
  122. package/playground/public/examples/debug-accents.html +11 -0
  123. package/playground/public/examples/debug-text-overlap.html +46 -0
  124. package/playground/public/examples/flex-gap-column.html +130 -0
  125. package/playground/public/examples/flex-gap-row.html +137 -0
  126. package/playground/public/examples/flex-padding-test.html +29 -0
  127. package/playground/public/examples/flexbox-text-test.html +193 -0
  128. package/playground/public/examples/fonts-demo.html +126 -0
  129. package/playground/public/examples/footer-example.html +4 -0
  130. package/playground/public/examples/gradient-text.html +54 -0
  131. package/playground/public/examples/grid-gap-demo.html +156 -0
  132. package/playground/public/examples/header-example.html +4 -0
  133. package/playground/public/examples/header-footer-example.html +27 -0
  134. package/playground/public/examples/image-showcase.html +33 -0
  135. package/playground/public/examples/justify-text.html +22 -0
  136. package/playground/public/examples/linear-gradient-example.html +38 -0
  137. package/playground/public/examples/lorem-span.html +14 -0
  138. package/playground/public/examples/margin-block-showcase.html +21 -0
  139. package/playground/public/examples/margin-inline-showcase.html +21 -0
  140. package/playground/public/examples/monthly-summary.html +95 -0
  141. package/playground/public/examples/multi-page-lorem.html +190 -0
  142. package/playground/public/examples/opacity-debug.html +39 -0
  143. package/playground/public/examples/opacity-example.html +70 -0
  144. package/playground/public/examples/png-image-example.html +13 -0
  145. package/playground/public/examples/red-rectangle.html +18 -0
  146. package/playground/public/examples/repro.html +24 -0
  147. package/playground/public/examples/rounded-borders-test.html +24 -0
  148. package/playground/public/examples/simple-list.html +89 -0
  149. package/playground/public/examples/simple-svg.html +37 -0
  150. package/playground/public/examples/simple-table.html +52 -0
  151. package/playground/public/examples/skew-div.html +138 -0
  152. package/playground/public/examples/skew-text.html +21 -0
  153. package/playground/public/examples/starter-report.css +51 -0
  154. package/playground/public/examples/starter-report.html +23 -0
  155. package/playground/public/examples/svg-aspect-ratio-showcase.html +116 -0
  156. package/playground/public/examples/svg-gradients-linear.html +28 -0
  157. package/playground/public/examples/svg-gradients-radial.html +29 -0
  158. package/playground/public/examples/svg-gradients-showcase.html +66 -0
  159. package/playground/public/examples/svg-image-path-test.html +43 -0
  160. package/playground/public/examples/svg-images-clipping.html +27 -0
  161. package/playground/public/examples/svg-path-gallery.html +118 -0
  162. package/playground/public/examples/svg-radial-transform-demo.html +78 -0
  163. package/playground/public/examples/svg-transform-stack.html +103 -0
  164. package/playground/public/examples/svg-transforms-demo.html +127 -0
  165. package/playground/public/examples/table-merge-test.html +34 -0
  166. package/playground/public/examples/text-decoration-showcase.html +138 -0
  167. package/playground/public/examples/text-indent-showcase.html +137 -0
  168. package/playground/public/examples/text-shadow-example.html +29 -0
  169. package/playground/public/examples/very-complex-css.html +293 -0
  170. package/playground/public/examples/webp-example.html +13 -0
  171. package/playground/public/examples/z-index-demo.html +93 -0
  172. package/playground/public/examples.json +240 -0
  173. package/playground/public/images/dice.png +0 -0
  174. package/playground/public/images/duck.jpg +0 -0
  175. package/playground/public/index.html +149 -0
  176. package/playground/public/mode.js +1 -0
  177. package/playground/public/styles.css +382 -0
  178. package/playground/public/tmp-h2-debug.html +33 -0
  179. package/playground/public/tmp-italic-debug.html +32 -0
  180. package/playground/public/vendor/codemirror/codemirror.min.css +1 -0
  181. package/playground/public/vendor/codemirror/codemirror.min.js +1 -0
  182. package/playground/public/vendor/codemirror/css.min.js +1 -0
  183. package/playground/public/vendor/codemirror/darcula.min.css +1 -0
  184. package/playground/public/vendor/codemirror/htmlmixed.min.js +1 -0
  185. package/playground/public/vendor/codemirror/javascript.min.js +1 -0
  186. package/playground/public/vendor/codemirror/xml.min.js +1 -0
  187. package/playground/public/vendor/pagyra-playground-browser.js +165966 -0
  188. package/playground/public/vendor/pagyra-playground-browser.js.map +7 -0
  189. package/playground/server.d.ts +1 -0
  190. package/playground/server.js +68 -0
  191. package/playground/server.ts +128 -0
  192. package/scripts/browser-build.ts +101 -0
  193. package/scripts/build-browser-bundle.ts +52 -0
  194. package/scripts/glyph-comparison/simulate.ts +744 -0
  195. package/scripts/playground-browser-server.ts +57 -0
  196. package/scripts/probe-roboto.ts +6 -0
  197. package/scripts/render-playground-example.ts +121 -0
  198. package/scripts/run-glyph-atlas-tuner-runner.mjs +113 -0
  199. package/scripts/run-glyph-atlas-tuner.ts +141 -0
  200. package/scripts/top-ts-files.ps1 +39 -0
  201. package/scripts/top-ts-files.sh +37 -0
  202. package/scripts/woff2_info.ps1 +132 -0
  203. package/src/browser-entry.ts +14 -0
  204. package/src/compression/adler32.ts +45 -0
  205. package/src/compression/brotli/brotli.ts +463 -0
  206. package/src/compression/brotli/index.ts +15 -0
  207. package/src/compression/brotli/transform.ts +184 -0
  208. package/src/compression/brotli/types.ts +58 -0
  209. package/src/compression/brotli/utils.ts +157 -0
  210. package/src/compression/brotli/vendor/bit_reader.js +124 -0
  211. package/src/compression/brotli/vendor/context.js +250 -0
  212. package/src/compression/brotli/vendor/decode.d.ts +2 -0
  213. package/src/compression/brotli/vendor/decode.js +938 -0
  214. package/src/compression/brotli/vendor/dictionary-data.js +9469 -0
  215. package/src/compression/brotli/vendor/dictionary.js +36 -0
  216. package/src/compression/brotli/vendor/huffman.js +123 -0
  217. package/src/compression/brotli/vendor/package.json +3 -0
  218. package/src/compression/brotli/vendor/prefix.js +60 -0
  219. package/src/compression/brotli/vendor/streams.js +31 -0
  220. package/src/compression/brotli/vendor/transform.js +247 -0
  221. package/src/compression/brotli/vendor-decode.d.ts +4 -0
  222. package/src/compression/brotli/woff2-glyf-transform.ts +623 -0
  223. package/src/compression/decompress.ts +16 -0
  224. package/src/compression/deflate.ts +295 -0
  225. package/src/compression/index.ts +4 -0
  226. package/src/compression/types.ts +26 -0
  227. package/src/compression/utils.ts +107 -0
  228. package/src/core.ts +18 -0
  229. package/src/css/apply-declarations.ts +86 -0
  230. package/src/css/background-types.ts +65 -0
  231. package/src/css/browser-defaults.ts +16 -0
  232. package/src/css/clip-path-types.ts +13 -0
  233. package/src/css/compute-style.ts +494 -0
  234. package/src/css/css-unit-resolver.ts +65 -0
  235. package/src/css/custom-properties.ts +215 -0
  236. package/src/css/enums.ts +127 -0
  237. package/src/css/font-face-parser.ts +233 -0
  238. package/src/css/font-weight.ts +65 -0
  239. package/src/css/inline-style-parser.ts +27 -0
  240. package/src/css/layout-property-resolver.ts +75 -0
  241. package/src/css/length.ts +141 -0
  242. package/src/css/line-height.ts +96 -0
  243. package/src/css/named-colors.ts +150 -0
  244. package/src/css/parsers/background-parser-extended.ts +111 -0
  245. package/src/css/parsers/background-parser.ts +456 -0
  246. package/src/css/parsers/border-block-parser.ts +26 -0
  247. package/src/css/parsers/border-inline-parser.ts +26 -0
  248. package/src/css/parsers/border-parser-extended.ts +256 -0
  249. package/src/css/parsers/border-parser.ts +175 -0
  250. package/src/css/parsers/box-shadow-parser.ts +106 -0
  251. package/src/css/parsers/clip-path-parser.ts +92 -0
  252. package/src/css/parsers/color-parser.ts +14 -0
  253. package/src/css/parsers/dimension-parser.ts +117 -0
  254. package/src/css/parsers/display-flex-parser.ts +59 -0
  255. package/src/css/parsers/flex-parser.ts +144 -0
  256. package/src/css/parsers/font-parser.ts +40 -0
  257. package/src/css/parsers/gradient-parser.ts +366 -0
  258. package/src/css/parsers/grid-parser-extended.ts +55 -0
  259. package/src/css/parsers/grid-parser.ts +218 -0
  260. package/src/css/parsers/length-parser.ts +95 -0
  261. package/src/css/parsers/list-style-parser.ts +39 -0
  262. package/src/css/parsers/margin-block-parser.ts +12 -0
  263. package/src/css/parsers/margin-inline-parser.ts +12 -0
  264. package/src/css/parsers/margin-parser.ts +30 -0
  265. package/src/css/parsers/opacity-parser.ts +32 -0
  266. package/src/css/parsers/overflow-wrap-parser.ts +38 -0
  267. package/src/css/parsers/padding-block-parser.ts +12 -0
  268. package/src/css/parsers/padding-inline-parser.ts +12 -0
  269. package/src/css/parsers/padding-parser.ts +30 -0
  270. package/src/css/parsers/position-parser.ts +75 -0
  271. package/src/css/parsers/register-parsers.ts +302 -0
  272. package/src/css/parsers/registry.ts +18 -0
  273. package/src/css/parsers/text-parser-extended.ts +144 -0
  274. package/src/css/parsers/text-parser.ts +25 -0
  275. package/src/css/parsers/text-shadow-parser.ts +94 -0
  276. package/src/css/properties/box-model.ts +82 -0
  277. package/src/css/properties/flexbox.ts +44 -0
  278. package/src/css/properties/gap.ts +14 -0
  279. package/src/css/properties/grid.ts +94 -0
  280. package/src/css/properties/layout.ts +59 -0
  281. package/src/css/properties/misc.ts +44 -0
  282. package/src/css/properties/typography.ts +71 -0
  283. package/src/css/properties/visual.ts +68 -0
  284. package/src/css/selectors/matcher.ts +219 -0
  285. package/src/css/selectors/parser.ts +163 -0
  286. package/src/css/selectors/simple-key.ts +31 -0
  287. package/src/css/selectors/specificity.ts +41 -0
  288. package/src/css/selectors/types.ts +31 -0
  289. package/src/css/shorthands/border-shorthand.ts +68 -0
  290. package/src/css/shorthands/box-shorthand.ts +33 -0
  291. package/src/css/style-inheritance.ts +50 -0
  292. package/src/css/style.ts +402 -0
  293. package/src/css/ua-defaults/base-defaults.ts +266 -0
  294. package/src/css/ua-defaults/browser-defaults.ts +134 -0
  295. package/src/css/ua-defaults/element-defaults.ts +374 -0
  296. package/src/css/ua-defaults/types.ts +43 -0
  297. package/src/css/unit-conversion.ts +24 -0
  298. package/src/css/utils.ts +108 -0
  299. package/src/css/viewport.ts +17 -0
  300. package/src/debug/audit.ts +20 -0
  301. package/src/debug/ids.ts +13 -0
  302. package/src/debug/log.js +28 -0
  303. package/src/debug/log.ts +52 -0
  304. package/src/debug/tree.ts +57 -0
  305. package/src/dom/node.ts +133 -0
  306. package/src/environment/browser-environment.ts +78 -0
  307. package/src/environment/environment.ts +35 -0
  308. package/src/environment/global.ts +13 -0
  309. package/src/environment/node-environment.browser.ts +28 -0
  310. package/src/environment/node-environment.ts +64 -0
  311. package/src/fonts/detector.ts +28 -0
  312. package/src/fonts/engines/ttf-engine.ts +28 -0
  313. package/src/fonts/engines/woff-engine.ts +38 -0
  314. package/src/fonts/engines/woff2-engine.ts +41 -0
  315. package/src/fonts/extractors/metrics-extractor.ts +362 -0
  316. package/src/fonts/font-registry-resolver.ts +132 -0
  317. package/src/fonts/index.ts +3 -0
  318. package/src/fonts/orchestrator.ts +92 -0
  319. package/src/fonts/parsers/base-parser.ts +23 -0
  320. package/src/fonts/types.ts +85 -0
  321. package/src/fonts/utils/ttf-reconstructor.ts +120 -0
  322. package/src/fonts/woff/decoder.ts +105 -0
  323. package/src/fonts/woff2/buffer.ts +106 -0
  324. package/src/fonts/woff2/decoder.ts +981 -0
  325. package/src/geometry/box.ts +48 -0
  326. package/src/geometry/matrix.ts +59 -0
  327. package/src/html/css/parse-css.ts +85 -0
  328. package/src/html/dom-converter.ts +433 -0
  329. package/src/html/image-converter.ts +200 -0
  330. package/src/html-to-pdf.ts +410 -0
  331. package/src/image/base-decoder.ts +149 -0
  332. package/src/image/image-service.ts +188 -0
  333. package/src/image/jpeg-decoder.ts +73 -0
  334. package/src/image/png-decoder.ts +550 -0
  335. package/src/image/types.ts +20 -0
  336. package/src/image/webp-decoder.ts +242 -0
  337. package/src/image/webp-huffman.ts +218 -0
  338. package/src/image/webp-riff-parser.ts +54 -0
  339. package/src/image/webp-vp8l-decoder.ts +199 -0
  340. package/src/index.ts +35 -0
  341. package/src/layout/context/float-context.ts +62 -0
  342. package/src/layout/context/layout-environment.ts +29 -0
  343. package/src/layout/debug.ts +18 -0
  344. package/src/layout/inline/bounding-box-calculator.ts +132 -0
  345. package/src/layout/inline/font-baseline-calculator.ts +76 -0
  346. package/src/layout/inline/inline-utils.ts +94 -0
  347. package/src/layout/inline/layout.ts +285 -0
  348. package/src/layout/inline/line_breaker.ts +109 -0
  349. package/src/layout/inline/measurement.ts +144 -0
  350. package/src/layout/inline/run-placer.ts +139 -0
  351. package/src/layout/inline/text-alignment.ts +70 -0
  352. package/src/layout/inline/tokenizer.ts +195 -0
  353. package/src/layout/inline/types.ts +76 -0
  354. package/src/layout/pipeline/context-factory.ts +16 -0
  355. package/src/layout/pipeline/default-engine.ts +24 -0
  356. package/src/layout/pipeline/engine.ts +59 -0
  357. package/src/layout/pipeline/layout-tree.ts +13 -0
  358. package/src/layout/pipeline/out-of-flow-manager.ts +73 -0
  359. package/src/layout/pipeline/strategy.ts +12 -0
  360. package/src/layout/pipeline/text-metrics-initializer.ts +13 -0
  361. package/src/layout/strategies/block.ts +236 -0
  362. package/src/layout/strategies/display-none.ts +14 -0
  363. package/src/layout/strategies/fallback.ts +15 -0
  364. package/src/layout/strategies/flex.ts +477 -0
  365. package/src/layout/strategies/fragmentation.ts +17 -0
  366. package/src/layout/strategies/grid.ts +247 -0
  367. package/src/layout/strategies/image.ts +342 -0
  368. package/src/layout/strategies/inline.ts +128 -0
  369. package/src/layout/strategies/table.ts +595 -0
  370. package/src/layout/table/cell_layout.ts +31 -0
  371. package/src/layout/table/diagnostics.ts +19 -0
  372. package/src/layout/text-run.ts +42 -0
  373. package/src/layout/utils/content-measurer.ts +117 -0
  374. package/src/layout/utils/display-utils.ts +24 -0
  375. package/src/layout/utils/floats.ts +98 -0
  376. package/src/layout/utils/gap-calculator.ts +167 -0
  377. package/src/layout/utils/inline-formatter.ts +31 -0
  378. package/src/layout/utils/inline-formatting.ts +9 -0
  379. package/src/layout/utils/margin.ts +140 -0
  380. package/src/layout/utils/node-math.ts +237 -0
  381. package/src/layout/utils/overflow.ts +14 -0
  382. package/src/layout/utils/sizing.ts +12 -0
  383. package/src/layout/utils/text-metrics.ts +361 -0
  384. package/src/logging/debug.ts +58 -0
  385. package/src/pdf/font/base14/widths-courier-bold.ts +159 -0
  386. package/src/pdf/font/base14/widths-courier.ts +159 -0
  387. package/src/pdf/font/base14/widths-helvetica-bold.ts +158 -0
  388. package/src/pdf/font/base14/widths-helvetica.ts +158 -0
  389. package/src/pdf/font/base14/widths-times-bold.ts +158 -0
  390. package/src/pdf/font/base14/widths-times-roman.ts +158 -0
  391. package/src/pdf/font/base14/widths-types.ts +25 -0
  392. package/src/pdf/font/base14-widths.ts +32 -0
  393. package/src/pdf/font/blur.ts +81 -0
  394. package/src/pdf/font/builtin-fonts.browser.ts +262 -0
  395. package/src/pdf/font/builtin-fonts.ts +126 -0
  396. package/src/pdf/font/composite-glyph-parser.ts +242 -0
  397. package/src/pdf/font/embedder.ts +395 -0
  398. package/src/pdf/font/font-config.ts +190 -0
  399. package/src/pdf/font/font-registry.ts +263 -0
  400. package/src/pdf/font/font-subset.ts +258 -0
  401. package/src/pdf/font/glyph-atlas-maxrects.ts +305 -0
  402. package/src/pdf/font/glyph-atlas-tuner.ts +98 -0
  403. package/src/pdf/font/glyph-atlas.ts +226 -0
  404. package/src/pdf/font/glyph-cache.ts +127 -0
  405. package/src/pdf/font/loca-reader.ts +109 -0
  406. package/src/pdf/font/managers/font-resource-manager.ts +73 -0
  407. package/src/pdf/font/managers/subset-resource-manager.ts +164 -0
  408. package/src/pdf/font/rasterizer.ts +270 -0
  409. package/src/pdf/font/resolvers/base-font-mapper.ts +77 -0
  410. package/src/pdf/font/resolvers/family-resolver.ts +33 -0
  411. package/src/pdf/font/resolvers/weight-style-applicator.ts +63 -0
  412. package/src/pdf/font/simple-glyph-parser.ts +289 -0
  413. package/src/pdf/font/to-unicode.ts +109 -0
  414. package/src/pdf/font/transformation-matrix.ts +136 -0
  415. package/src/pdf/font/ttf-cmap.ts +180 -0
  416. package/src/pdf/font/ttf-global-metrics.ts +58 -0
  417. package/src/pdf/font/ttf-glyf.ts +125 -0
  418. package/src/pdf/font/ttf-glyph-metrics.ts +43 -0
  419. package/src/pdf/font/ttf-lite.ts +269 -0
  420. package/src/pdf/font/ttf-table-parser.ts +132 -0
  421. package/src/pdf/font/ttf-table-provider.ts +61 -0
  422. package/src/pdf/font/widths.ts +79 -0
  423. package/src/pdf/font-subset/font-registry.ts +127 -0
  424. package/src/pdf/header-footer-layout.ts +153 -0
  425. package/src/pdf/header-footer-painter.ts +209 -0
  426. package/src/pdf/header-footer-renderer.ts +357 -0
  427. package/src/pdf/header-footer-tokens.ts +55 -0
  428. package/src/pdf/header-footer.ts +25 -0
  429. package/src/pdf/layout-tree-builder.ts +261 -0
  430. package/src/pdf/page-painter.ts +241 -0
  431. package/src/pdf/pagination.ts +155 -0
  432. package/src/pdf/primitives/pdf-builder.ts +378 -0
  433. package/src/pdf/primitives/pdf-bytes.ts +40 -0
  434. package/src/pdf/primitives/pdf-document.ts +108 -0
  435. package/src/pdf/primitives/pdf-reference-manager.ts +47 -0
  436. package/src/pdf/primitives/pdf-resource-registries.ts +255 -0
  437. package/src/pdf/primitives/pdf-serializers.ts +194 -0
  438. package/src/pdf/primitives/pdf-types.ts +73 -0
  439. package/src/pdf/render.ts +210 -0
  440. package/src/pdf/renderer/box-painter.ts +236 -0
  441. package/src/pdf/renderer/page-paint.ts +102 -0
  442. package/src/pdf/renderer/paint-box-shadows.ts +218 -0
  443. package/src/pdf/renderer/radius.ts +58 -0
  444. package/src/pdf/renderers/graphics-state-manager.ts +40 -0
  445. package/src/pdf/renderers/image-renderer.ts +127 -0
  446. package/src/pdf/renderers/radius-utils.ts +80 -0
  447. package/src/pdf/renderers/rectangle-renderer.ts +129 -0
  448. package/src/pdf/renderers/rounded-rect-path.ts +120 -0
  449. package/src/pdf/renderers/shape-renderer.ts +563 -0
  450. package/src/pdf/renderers/shape-utils.ts +194 -0
  451. package/src/pdf/renderers/text-decoration-renderer.ts +313 -0
  452. package/src/pdf/renderers/text-encoder.ts +41 -0
  453. package/src/pdf/renderers/text-font-resolver.ts +75 -0
  454. package/src/pdf/renderers/text-renderer-utils.ts +28 -0
  455. package/src/pdf/renderers/text-renderer.ts +391 -0
  456. package/src/pdf/renderers/text-shadow-renderer.ts +300 -0
  457. package/src/pdf/shading/gradient-service.ts +525 -0
  458. package/src/pdf/shading/index.ts +1 -0
  459. package/src/pdf/stacking/build-stacking-contexts.ts +93 -0
  460. package/src/pdf/stacking/resolve-paint-order.ts +157 -0
  461. package/src/pdf/stacking/types.ts +40 -0
  462. package/src/pdf/svg/aspect-ratio.ts +81 -0
  463. package/src/pdf/svg/coordinate-mapper.ts +81 -0
  464. package/src/pdf/svg/geometry-builder.ts +45 -0
  465. package/src/pdf/svg/render-svg.ts +296 -0
  466. package/src/pdf/svg/shape-renderer.ts +463 -0
  467. package/src/pdf/svg/style-computer.ts +246 -0
  468. package/src/pdf/transform-adapter.ts +26 -0
  469. package/src/pdf/types.ts +377 -0
  470. package/src/pdf/utils/background-layer-resolver.ts +439 -0
  471. package/src/pdf/utils/background-tiles.ts +192 -0
  472. package/src/pdf/utils/border-dashes.ts +109 -0
  473. package/src/pdf/utils/border-radius-utils.ts +86 -0
  474. package/src/pdf/utils/box-dimensions-utils.ts +47 -0
  475. package/src/pdf/utils/clip-path-resolver.ts +50 -0
  476. package/src/pdf/utils/clipping-path-builder.ts +190 -0
  477. package/src/pdf/utils/color-utils.ts +102 -0
  478. package/src/pdf/utils/coordinate-transformer.ts +30 -0
  479. package/src/pdf/utils/drop-shadow-raster.ts +233 -0
  480. package/src/pdf/utils/encoding.ts +98 -0
  481. package/src/pdf/utils/glyph-atlas-registrar.ts +13 -0
  482. package/src/pdf/utils/glyph-run-renderer.ts +129 -0
  483. package/src/pdf/utils/image-command-partitioner.ts +28 -0
  484. package/src/pdf/utils/image-matrix-builder.ts +31 -0
  485. package/src/pdf/utils/image-utils.ts +26 -0
  486. package/src/pdf/utils/list-utils.ts +194 -0
  487. package/src/pdf/utils/node-text-run-factory.ts +202 -0
  488. package/src/pdf/utils/page-resource-registrar.ts +46 -0
  489. package/src/pdf/utils/result-combiner.ts +102 -0
  490. package/src/pdf/utils/shadow-utils.ts +127 -0
  491. package/src/pdf/utils/text-alignment-resolver.ts +76 -0
  492. package/src/pdf/utils/text-decoration-utils.ts +64 -0
  493. package/src/pdf/utils/text-layout-adjuster.ts +185 -0
  494. package/src/pdf/utils/text-utils.ts +193 -0
  495. package/src/pdf/utils/transform-scope-manager.ts +69 -0
  496. package/src/render/offset.ts +170 -0
  497. package/src/shim/empty.ts +2 -0
  498. package/src/shim/fs-empty.ts +5 -0
  499. package/src/shim/url-empty.ts +7 -0
  500. package/src/shim/zlib-empty.ts +9 -0
  501. package/src/style/shorthands/index.ts +19 -0
  502. package/src/style/ua/defaults.ts +69 -0
  503. package/src/svg/index.ts +4 -0
  504. package/src/svg/parser-registry.ts +71 -0
  505. package/src/svg/parser.ts +486 -0
  506. package/src/svg/path-data.ts +515 -0
  507. package/src/svg/types.ts +194 -0
  508. package/src/text/line-breaker.ts +321 -0
  509. package/src/text/text-transform.ts +43 -0
  510. package/src/text/text.ts +33 -0
  511. package/src/transform/css-parser.ts +95 -0
  512. package/src/types/fonts.ts +62 -0
  513. package/src/types/public.ts +19 -0
  514. package/src/units/page-utils.ts +58 -0
  515. package/src/units/units.ts +50 -0
  516. package/src/utils/base64.ts +24 -0
  517. package/test-output.txt +79 -0
  518. package/tests/css/background-parser.spec.ts +14 -0
  519. package/tests/css/clip-path-parser.spec.ts +66 -0
  520. package/tests/environment/path-resolution.spec.ts +104 -0
  521. package/tests/helpers/ai-layout-diagnostics.ts +141 -0
  522. package/tests/helpers/render-utils.ts +52 -0
  523. package/tests/helpers/text-geometry.ts +56 -0
  524. package/tests/layout/custom-properties.test.ts +38 -0
  525. package/tests/layout/gap-calculator.spec.ts +196 -0
  526. package/tests/layout/inline-background-alignment.spec.ts +93 -0
  527. package/tests/layout/inline-fragments.spec.ts +26 -0
  528. package/tests/layout/run-placer-baseline.spec.ts +108 -0
  529. package/tests/pdf/alignments.spec.ts +26 -0
  530. package/tests/pdf/background-clip.spec.ts +57 -0
  531. package/tests/pdf/background-repeat-space-round.spec.ts +35 -0
  532. package/tests/pdf/background-repeat.spec.ts +137 -0
  533. package/tests/pdf/border-radius.spec.ts +151 -0
  534. package/tests/pdf/clip-path.spec.ts +92 -0
  535. package/tests/pdf/radial-gradient.spec.ts +50 -0
  536. package/tests/pdf/svg-stroke-dash.spec.ts +81 -0
  537. package/tests/pdf/text-transform-matrix.spec.ts +43 -0
  538. package/tsconfig.json +17 -0
  539. package/types/fonts.js +10 -0
  540. package/vitest.config.ts +9 -0
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Calculates Adler-32 checksum as required by zlib format
3
+ * Used in WOFF 1.0 for data integrity verification
4
+ */
5
+ export class Adler32 {
6
+ private static readonly MOD_ADLER = 65521;
7
+
8
+ /**
9
+ * Calculate Adler-32 checksum for the given data
10
+ */
11
+ static calculate(data: Uint8Array): number {
12
+ let a = 1;
13
+ let b = 0;
14
+
15
+ for (let i = 0; i < data.length; i++) {
16
+ a = (a + data[i]) % this.MOD_ADLER;
17
+ b = (b + a) % this.MOD_ADLER;
18
+ }
19
+
20
+ return (b << 16) | a;
21
+ }
22
+
23
+ /**
24
+ * Verify Adler-32 checksum
25
+ */
26
+ static verify(data: Uint8Array, expectedChecksum: number): boolean {
27
+ const calculated = this.calculate(data);
28
+ return calculated === expectedChecksum;
29
+ }
30
+
31
+ /**
32
+ * Update running Adler-32 checksum with new data
33
+ */
34
+ static update(adler: number, data: Uint8Array): number {
35
+ let a = adler & 0xffff;
36
+ let b = (adler >>> 16) & 0xffff;
37
+
38
+ for (let i = 0; i < data.length; i++) {
39
+ a = (a + data[i]) % this.MOD_ADLER;
40
+ b = (b + a) % this.MOD_ADLER;
41
+ }
42
+
43
+ return (b << 16) | a;
44
+ }
45
+ }
@@ -0,0 +1,463 @@
1
+ import type {
2
+ BrotliOptions,
3
+ BrotliResult,
4
+ CompressionStats,
5
+ DecompressOptions,
6
+ WOFF2TableEntry,
7
+ } from './types.js';
8
+ import { BrotliMode } from './types.js';
9
+ import {
10
+ toUint8Array,
11
+ concatUint8Arrays,
12
+ padTo4Bytes,
13
+ } from './utils.js';
14
+ import { WOFF2Transform } from './transform.js';
15
+
16
+ // Cache Node.js zlib module to avoid repeated imports
17
+ let nodeZlib: typeof import('zlib') | null = null;
18
+ let nodeUtil: typeof import('util') | null = null;
19
+
20
+ /**
21
+ * Brotli compression/decompression module for WOFF 2.0
22
+ */
23
+ export class WOFF2Brotli {
24
+ private static readonly DEFAULT_QUALITY = 11; // Maximum compression for fonts
25
+ private static readonly DEFAULT_MODE = BrotliMode.FONT;
26
+ private static readonly DEFAULT_LGWIN = 22; // 4MB window
27
+ private static readonly DEFAULT_LGBLOCK = 0; // Auto
28
+
29
+ /**
30
+ * Compress data using Brotli algorithm
31
+ */
32
+ static async compress(
33
+ input: Uint8Array | ArrayBuffer,
34
+ options: BrotliOptions = {}
35
+ ): Promise<BrotliResult> {
36
+ const data = toUint8Array(input);
37
+ const quality = options.quality ?? this.DEFAULT_QUALITY;
38
+ const mode = options.mode ?? this.DEFAULT_MODE;
39
+ const lgwin = options.lgwin ?? this.DEFAULT_LGWIN;
40
+ const lgblock = options.lgblock ?? this.DEFAULT_LGBLOCK;
41
+
42
+ if (quality < 0 || quality > 11) {
43
+ throw new Error('Brotli quality must be between 0 and 11');
44
+ }
45
+
46
+ const compressed = await this.brotliCompress(data, {
47
+ quality,
48
+ mode,
49
+ lgwin,
50
+ lgblock,
51
+ });
52
+
53
+ return {
54
+ data: compressed,
55
+ compressedSize: compressed.length,
56
+ uncompressedSize: data.length,
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Decompress Brotli data
62
+ */
63
+ static async decompress(
64
+ input: Uint8Array | ArrayBuffer,
65
+ options: DecompressOptions = {}
66
+ ): Promise<Uint8Array> {
67
+ const data = toUint8Array(input);
68
+ const decompressed = await this.brotliDecompress(data);
69
+
70
+ if (options.expectedSize && options.validateSize) {
71
+ if (decompressed.length !== options.expectedSize) {
72
+ throw new Error(
73
+ `Size mismatch: expected ${options.expectedSize}, got ${decompressed.length}`
74
+ );
75
+ }
76
+ }
77
+
78
+ return decompressed;
79
+ }
80
+
81
+ /**
82
+ * Compress with table transformation (WOFF 2.0 specific)
83
+ */
84
+ static async compressWithTransform(
85
+ input: Uint8Array,
86
+ tableTag: string,
87
+ entry: WOFF2TableEntry,
88
+ options: BrotliOptions = {}
89
+ ): Promise<BrotliResult> {
90
+ const transformed = WOFF2Transform.transform(tableTag, input, entry);
91
+ const transformLength = WOFF2Transform.getTransformedLength(tableTag, input);
92
+ const result = await this.compress(transformed, options);
93
+
94
+ return {
95
+ ...result,
96
+ transformLength,
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Decompress with reverse transformation (WOFF 2.0 specific)
102
+ */
103
+ static async decompressWithTransform(
104
+ input: Uint8Array,
105
+ tableTag: string,
106
+ entry: WOFF2TableEntry,
107
+ options: DecompressOptions = {}
108
+ ): Promise<Uint8Array> {
109
+ const decompressed = await this.decompress(input, options);
110
+ const untransformed = WOFF2Transform.untransform(tableTag, decompressed, entry);
111
+ return untransformed;
112
+ }
113
+
114
+ /**
115
+ * Get compression statistics
116
+ */
117
+ static getCompressionStats(
118
+ original: Uint8Array,
119
+ compressed: Uint8Array,
120
+ transformed?: Uint8Array
121
+ ): CompressionStats {
122
+ return {
123
+ originalSize: original.length,
124
+ compressedSize: compressed.length,
125
+ compressionRatio: compressed.length / original.length,
126
+ transformedSize: transformed?.length,
127
+ transformApplied: !!transformed && transformed.length !== original.length,
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Platform-specific Brotli compression
133
+ */
134
+ private static async brotliCompress(
135
+ data: Uint8Array,
136
+ options: BrotliOptions
137
+ ): Promise<Uint8Array> {
138
+ if (typeof process !== 'undefined' && process.versions?.node) {
139
+ return this.nodeBrotliCompress(data, options);
140
+ }
141
+ if (typeof CompressionStream !== 'undefined') {
142
+ return this.browserBrotliCompress(data);
143
+ }
144
+ throw new Error('No Brotli implementation available (Platform not supported)');
145
+ }
146
+
147
+ /**
148
+ * Platform-specific Brotli decompression
149
+ */
150
+ private static async brotliDecompress(data: Uint8Array): Promise<Uint8Array> {
151
+ if (typeof process !== 'undefined' && process.versions?.node) {
152
+ return this.nodeBrotliDecompress(data);
153
+ }
154
+ if (typeof DecompressionStream !== 'undefined') {
155
+ try {
156
+ return await this.browserBrotliDecompress(data);
157
+ } catch {
158
+ // fall through to JS fallback
159
+ }
160
+ }
161
+ return this.jsBrotliDecompress(data);
162
+ }
163
+
164
+ /**
165
+ * Node.js Brotli compression
166
+ */
167
+ private static async nodeBrotliCompress(
168
+ data: Uint8Array,
169
+ options: BrotliOptions
170
+ ): Promise<Uint8Array> {
171
+ if (!nodeZlib || !nodeUtil) {
172
+ nodeZlib = await import('zlib');
173
+ nodeUtil = await import('util');
174
+ }
175
+
176
+ const brotliCompress = nodeUtil.promisify(nodeZlib.brotliCompress);
177
+
178
+ const params: Record<number, number> = {
179
+ [nodeZlib.constants.BROTLI_PARAM_QUALITY]: options.quality ?? this.DEFAULT_QUALITY,
180
+ [nodeZlib.constants.BROTLI_PARAM_MODE]: options.mode ?? this.DEFAULT_MODE,
181
+ };
182
+
183
+ if (options.lgwin !== undefined) {
184
+ params[nodeZlib.constants.BROTLI_PARAM_LGWIN] = options.lgwin;
185
+ }
186
+
187
+ if (options.lgblock !== undefined && options.lgblock > 0) {
188
+ params[nodeZlib.constants.BROTLI_PARAM_LGBLOCK] = options.lgblock;
189
+ }
190
+
191
+ const compressed = await brotliCompress(data, { params });
192
+ return new Uint8Array(compressed);
193
+ }
194
+
195
+ /**
196
+ * Node.js Brotli decompression
197
+ */
198
+ private static async nodeBrotliDecompress(data: Uint8Array): Promise<Uint8Array> {
199
+ if (!nodeZlib || !nodeUtil) {
200
+ nodeZlib = await import('zlib');
201
+ nodeUtil = await import('util');
202
+ }
203
+ const brotliDecompress = nodeUtil.promisify(nodeZlib.brotliDecompress);
204
+
205
+ const decompressed = await brotliDecompress(data);
206
+ return new Uint8Array(decompressed);
207
+ }
208
+
209
+ /**
210
+ * Browser Brotli compression using CompressionStream API
211
+ */
212
+ private static async browserBrotliCompress(data: Uint8Array): Promise<Uint8Array> {
213
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
214
+ const stream = new CompressionStream('br' as any);
215
+ const writer = stream.writable.getWriter();
216
+
217
+ // Forçamos o cast para BufferSource para evitar conflito com tipos do Node
218
+ writer.write(data as BufferSource).catch(() => { /* ignore write errors here */ });
219
+ writer.close();
220
+
221
+ const chunks: Uint8Array[] = [];
222
+ const reader = stream.readable.getReader();
223
+
224
+ try {
225
+ while (true) {
226
+ const { done, value } = await reader.read();
227
+ if (done) break;
228
+ if (value) chunks.push(value);
229
+ }
230
+ } catch (e) {
231
+ throw new Error('Browser Brotli compression failed: ' + e);
232
+ }
233
+
234
+ return concatUint8Arrays(chunks);
235
+ }
236
+
237
+ /**
238
+ * Browser Brotli decompression using DecompressionStream API
239
+ */
240
+ private static async browserBrotliDecompress(data: Uint8Array): Promise<Uint8Array> {
241
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
+ const stream = new DecompressionStream('br' as any);
243
+ const writer = stream.writable.getWriter();
244
+
245
+ writer.write(data as BufferSource).catch(() => { /* ignore */ });
246
+ writer.close();
247
+
248
+ const chunks: Uint8Array[] = [];
249
+ const reader = stream.readable.getReader();
250
+
251
+ try {
252
+ while (true) {
253
+ const { done, value } = await reader.read();
254
+ if (done) break;
255
+ if (value) chunks.push(value);
256
+ }
257
+ } catch (e) {
258
+ throw new Error('Browser Brotli decompression failed: ' + e);
259
+ }
260
+
261
+ return concatUint8Arrays(chunks);
262
+ }
263
+
264
+ /**
265
+ * Pure JS fallback using vendored decoder (CommonJS converted by bundler).
266
+ * This is slower but keeps compatibility when DecompressionStream('br') is unavailable.
267
+ */
268
+ private static async jsBrotliDecompress(data: Uint8Array): Promise<Uint8Array> {
269
+ const mod = await import("./vendor/decode.js");
270
+ const decoder = mod.BrotliDecompressBuffer ?? mod.BrotliDecompress;
271
+ if (typeof decoder !== "function") {
272
+ throw new Error("No JS Brotli decoder available");
273
+ }
274
+ const out = decoder(data);
275
+ return out instanceof Uint8Array ? out : new Uint8Array(out);
276
+ }
277
+
278
+ /**
279
+ * Validate Brotli compressed data
280
+ */
281
+ static async validateCompressedData(data: Uint8Array): Promise<boolean> {
282
+ try {
283
+ const decompressed = await this.decompress(data);
284
+ return decompressed.length > 0;
285
+ } catch {
286
+ return false;
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Compress multiple tables into single stream (WOFF 2.0 spec)
292
+ */
293
+ static async compressMultipleTables(
294
+ tables: Array<{ tag: string; data: Uint8Array; entry: WOFF2TableEntry }>,
295
+ options: BrotliOptions = {}
296
+ ): Promise<BrotliResult> {
297
+ const concatenated = concatUint8Arrays(
298
+ tables.map(({ data }) => padTo4Bytes(data))
299
+ );
300
+
301
+ return this.compress(concatenated, {
302
+ ...options,
303
+ mode: BrotliMode.FONT,
304
+ quality: options.quality ?? 11,
305
+ });
306
+ }
307
+
308
+ /**
309
+ * Decompress single stream into multiple tables (WOFF 2.0 spec)
310
+ */
311
+ static async decompressMultipleTables(
312
+ compressed: Uint8Array,
313
+ tables: WOFF2TableEntry[],
314
+ options: DecompressOptions = {}
315
+ ): Promise<Map<string, Uint8Array>> {
316
+ const expectedSize = tables.reduce((sum, entry) =>
317
+ sum + (entry.transformLength ?? entry.origLength), 0);
318
+
319
+ const decompressed = await this.decompress(compressed, {
320
+ ...options,
321
+ expectedSize,
322
+ validateSize: false, // Don't validate size strictly due to padding
323
+ });
324
+
325
+ const result = new Map<string, Uint8Array>();
326
+ let offset = 0;
327
+
328
+ // First pass: extract all tables from the compressed stream
329
+ console.log(`WOFF2-BROTLI: Extracting ${tables.length} tables from ${decompressed.length} bytes`);
330
+
331
+ for (const entry of tables) {
332
+ const lengthInStream = entry.transformLength ?? entry.origLength;
333
+
334
+ console.log(`WOFF2-BROTLI: Processing table ${entry.tag} - origLength: ${entry.origLength}, transformLength: ${entry.transformLength}, transformVersion: ${entry.transformVersion}`);
335
+
336
+ if (offset + lengthInStream > decompressed.length) {
337
+ console.warn(`Table ${entry.tag} extends beyond decompressed data, using available data`);
338
+ const availableData = decompressed.subarray(offset);
339
+ if (availableData.length > 0) {
340
+ result.set(entry.tag, availableData);
341
+ }
342
+ break;
343
+ }
344
+
345
+ const tableData = decompressed.subarray(offset, offset + lengthInStream);
346
+ offset += lengthInStream;
347
+
348
+ const final = WOFF2Transform.untransform(entry.tag, tableData, entry, result);
349
+ result.set(entry.tag, final);
350
+ console.log(`WOFF2-BROTLI: Added table ${entry.tag} (${final.length} bytes)`);
351
+ }
352
+
353
+ console.log(`WOFF2-BROTLI: Extracted tables: ${Array.from(result.keys()).join(', ')}`);
354
+
355
+ // Second pass: handle glyf/loca transformation
356
+ // Check for gloc table OR separate transformed glyf/loca tables
357
+ // WOFF2 spec allows glyf/loca to be separate but transformed (transformVersion 0)
358
+ const hasGloc = result.has('gloc');
359
+ const glyfEntry = tables.find(t => t.tag === 'glyf');
360
+ const hasTransformedGlyf = result.has('glyf') && glyfEntry?.transformVersion === 0;
361
+
362
+ if (hasGloc || hasTransformedGlyf) {
363
+ console.log('WOFF2: Found transformed glyf/loca data, reconstructing...');
364
+
365
+ let glocData: Uint8Array;
366
+
367
+ if (hasGloc) {
368
+ console.log('WOFF2: Using gloc table');
369
+ glocData = result.get('gloc')!;
370
+ result.delete('gloc');
371
+ } else {
372
+ console.log('WOFF2: Using transformed glyf table');
373
+ // If glyf is transformed, it contains the streams needed for reconstruction
374
+ glocData = result.get('glyf')!;
375
+ }
376
+
377
+ console.log(`WOFF2: Transform data size: ${glocData.length} bytes`);
378
+
379
+ // We need maxp table to get numGlyphs and head table to get indexToLocFormat
380
+ const maxpData = result.get('maxp');
381
+ const headData = result.get('head');
382
+
383
+ console.log(`WOFF2: maxp table present: ${!!maxpData}, head table present: ${!!headData}`);
384
+
385
+ if (maxpData && headData) {
386
+ // Read numGlyphs from maxp table (offset 4, UInt16)
387
+ const numGlyphs = new DataView(maxpData.buffer, maxpData.byteOffset).getUint16(4, false);
388
+
389
+ // Read indexToLocFormat from head table (offset 50, Int16)
390
+ const indexFormat = new DataView(headData.buffer, headData.byteOffset).getInt16(50, false);
391
+
392
+ console.log(`WOFF2: Reconstructing glyf/loca with numGlyphs=${numGlyphs}, indexFormat=${indexFormat}`);
393
+
394
+ // Reconstruct glyf and loca tables
395
+ const { glyf, loca } = WOFF2Transform.reconstructGlyfLoca(glocData, numGlyphs, indexFormat);
396
+
397
+ console.log(`WOFF2: Reconstructed glyf size: ${glyf.length}, loca size: ${loca.length}`);
398
+
399
+ result.set('glyf', glyf);
400
+ result.set('loca', loca);
401
+
402
+ console.log('WOFF2: Successfully reconstructed glyf/loca tables');
403
+ } else {
404
+ console.warn('Cannot reconstruct glyf/loca: missing maxp or head table');
405
+ }
406
+ console.log(`WOFF2: Available tables: ${Array.from(result.keys()).join(', ')}`);
407
+ }
408
+
409
+ // Third pass: reconstruct hmtx if needed
410
+ this.reconstructHmtxIfNeeded(result, tables);
411
+
412
+ return result;
413
+ }
414
+
415
+ /**
416
+ * Helper to reconstruct hmtx table if needed
417
+ */
418
+ private static reconstructHmtxIfNeeded(
419
+ result: Map<string, Uint8Array>,
420
+ tables: WOFF2TableEntry[]
421
+ ): void {
422
+ const hmtxEntry = tables.find(t => t.tag === 'hmtx');
423
+ if (!hmtxEntry || !result.has('hmtx')) return;
424
+
425
+ // Check if hmtx is transformed (version 0 or 1 usually indicates transform in WOFF2)
426
+ // But strictly, we should check if the data size matches the expected untransformed size.
427
+ // If the data is smaller than expected, it's likely transformed.
428
+ // Or we can check the flags byte if we assume it's transformed.
429
+
430
+ // Better check: if transformVersion is 0, it IS transformed.
431
+ if (hmtxEntry.transformVersion !== 0) return;
432
+
433
+ // If transformLength is missing, it means the table length matches origLength.
434
+ // For hmtx, transformed data is usually smaller (or larger by 1 byte).
435
+ // If it matches origLength exactly, it's likely raw data despite the version flag.
436
+ if (hmtxEntry.transformLength === undefined) return;
437
+
438
+ const hmtxData = result.get('hmtx')!;
439
+ const hheaData = result.get('hhea');
440
+ const maxpData = result.get('maxp');
441
+
442
+ if (!hheaData || !maxpData) {
443
+ console.warn('WOFF2: Cannot reconstruct hmtx: missing hhea or maxp');
444
+ return;
445
+ }
446
+
447
+ const numHMetrics = new DataView(hheaData.buffer, hheaData.byteOffset).getUint16(34, false);
448
+ const numGlyphs = new DataView(maxpData.buffer, maxpData.byteOffset).getUint16(4, false);
449
+
450
+ const reconstructed = WOFF2Transform.reconstructHmtx(hmtxData, numHMetrics, numGlyphs);
451
+ result.set('hmtx', reconstructed);
452
+ }
453
+ }
454
+
455
+ // Export convenience functions
456
+ export const compress = WOFF2Brotli.compress.bind(WOFF2Brotli);
457
+ export const decompress = WOFF2Brotli.decompress.bind(WOFF2Brotli);
458
+ export const compressWithTransform = WOFF2Brotli.compressWithTransform.bind(WOFF2Brotli);
459
+ export const decompressWithTransform = WOFF2Brotli.decompressWithTransform.bind(WOFF2Brotli);
460
+ export const getCompressionStats = WOFF2Brotli.getCompressionStats.bind(WOFF2Brotli);
461
+ export const validateCompressedData = WOFF2Brotli.validateCompressedData.bind(WOFF2Brotli);
462
+ export const compressMultipleTables = WOFF2Brotli.compressMultipleTables.bind(WOFF2Brotli);
463
+ export const decompressMultipleTables = WOFF2Brotli.decompressMultipleTables.bind(WOFF2Brotli);
@@ -0,0 +1,15 @@
1
+ export {
2
+ WOFF2Brotli,
3
+ compress,
4
+ decompress,
5
+ compressWithTransform,
6
+ decompressWithTransform,
7
+ getCompressionStats,
8
+ validateCompressedData,
9
+ compressMultipleTables,
10
+ decompressMultipleTables,
11
+ } from './brotli.js';
12
+
13
+ export { WOFF2Transform } from './transform.js';
14
+ export * from './types.js';
15
+ export * from './utils.js';
@@ -0,0 +1,184 @@
1
+ import type { WOFF2TableEntry } from './types.js';
2
+ import { WOFF2GlyfTransform } from './woff2-glyf-transform.js';
3
+
4
+ /**
5
+ * WOFF 2.0 table transformations
6
+ * Specific transformations for glyf, loca, and hmtx tables
7
+ */
8
+ export class WOFF2Transform {
9
+ /**
10
+ * Check if a table should be transformed
11
+ */
12
+ static shouldTransform(tag: string): boolean {
13
+ return tag === 'glyf' || tag === 'loca' || tag === 'hmtx';
14
+ }
15
+
16
+ /**
17
+ * Get transformation version for a table
18
+ */
19
+ static getTransformVersion(tag: string): number {
20
+ switch (tag) {
21
+ case 'glyf':
22
+ case 'loca':
23
+ return 0; // Version 0 for glyf/loca transformation
24
+ case 'hmtx':
25
+ return 0; // Version 0 for hmtx transformation
26
+ default:
27
+ return 255; // No transformation
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Apply transformation to table data
33
+ * Note: This is for encoding WOFF2, not typically used in this library
34
+ */
35
+ static transform(tag: string, data: Uint8Array, _entry: WOFF2TableEntry): Uint8Array {
36
+ const version = this.getTransformVersion(tag);
37
+
38
+ if (version === 255) {
39
+ return data; // No transformation
40
+ }
41
+
42
+ // Encoding transformations not implemented (we only decode WOFF2)
43
+ console.warn(`Transformation for ${tag} not implemented (encoding not supported)`);
44
+ return data;
45
+ }
46
+
47
+ /**
48
+ * Reverse transformation (for decompression)
49
+ * This is the critical path for WOFF2 decoding
50
+ */
51
+ static untransform(
52
+ tag: string,
53
+ data: Uint8Array,
54
+ entry: WOFF2TableEntry,
55
+ allTables?: Map<string, Uint8Array>
56
+ ): Uint8Array {
57
+ const version = entry.transformVersion;
58
+
59
+ // No transformation needed
60
+ if (version === 255 || version === 3) {
61
+ return data;
62
+ }
63
+
64
+ // Handle glyf/loca transformation
65
+ if ((tag === 'glyf' || tag === 'loca') && version === 0) {
66
+ // For glyf/loca, we need information from other tables
67
+ // The transformation produces a 'gloc' table that contains both glyf and loca data
68
+ // We'll handle this specially in the decompression logic
69
+ return data;
70
+ }
71
+
72
+ // Other transformations not implemented
73
+ return data;
74
+ }
75
+
76
+ /**
77
+ * Calculate transformed length
78
+ */
79
+ static getTransformedLength(tag: string, data: Uint8Array): number | undefined {
80
+ if (!this.shouldTransform(tag)) {
81
+ return undefined;
82
+ }
83
+
84
+ // Actual implementation would calculate transformed size
85
+ return data.length;
86
+ }
87
+
88
+ /**
89
+ * Reconstruct glyf and loca tables from transformed 'gloc' data
90
+ */
91
+ /**
92
+ * Reconstruct glyf and loca tables from transformed 'gloc' data
93
+ */
94
+ static reconstructGlyfLoca(
95
+ glocData: Uint8Array,
96
+ numGlyphs: number,
97
+ indexFormat: number
98
+ ): { glyf: Uint8Array; loca: Uint8Array } {
99
+ return WOFF2GlyfTransform.untransformGlyf(glocData, numGlyphs, indexFormat);
100
+ }
101
+
102
+ /**
103
+ * Reconstruct hmtx table from transformed data
104
+ */
105
+ static reconstructHmtx(
106
+ hmtxData: Uint8Array,
107
+ numHMetrics: number,
108
+ numGlyphs: number,
109
+ glyfTable?: Uint8Array,
110
+ locaTable?: Uint8Array
111
+ ): Uint8Array {
112
+ if (hmtxData.length < 1) {
113
+ return hmtxData;
114
+ }
115
+
116
+ const flags = hmtxData[0];
117
+ const hasLsbArray = (flags & 1) !== 0;
118
+ const hasLeftSideBearingArray = (flags & 2) !== 0;
119
+
120
+ let offset = 1;
121
+ const advanceWidths: number[] = [];
122
+
123
+ // Read advance widths
124
+ for (let i = 0; i < numHMetrics; i++) {
125
+ if (offset + 2 > hmtxData.length) break;
126
+ advanceWidths.push((hmtxData[offset] << 8) | hmtxData[offset + 1]);
127
+ offset += 2;
128
+ }
129
+
130
+ const lsbs: number[] = [];
131
+ if (hasLsbArray) {
132
+ for (let i = 0; i < numHMetrics; i++) {
133
+ if (offset + 2 > hmtxData.length) break;
134
+ const val = (hmtxData[offset] << 8) | hmtxData[offset + 1];
135
+ lsbs.push(val > 0x7FFF ? val - 0x10000 : val);
136
+ offset += 2;
137
+ }
138
+ } else {
139
+ // Reconstruct LSBs from glyf table (xMin)
140
+ // Since we might have simplified glyf table, this might be inaccurate but safe
141
+ for (let i = 0; i < numHMetrics; i++) {
142
+ lsbs.push(0); // Default to 0 if derived
143
+ }
144
+ }
145
+
146
+ const leftSideBearings: number[] = [];
147
+ if (hasLeftSideBearingArray) {
148
+ for (let i = numHMetrics; i < numGlyphs; i++) {
149
+ if (offset + 2 > hmtxData.length) break;
150
+ const val = (hmtxData[offset] << 8) | hmtxData[offset + 1];
151
+ leftSideBearings.push(val > 0x7FFF ? val - 0x10000 : val);
152
+ offset += 2;
153
+ }
154
+ } else {
155
+ // Reconstruct LSBs from glyf table (xMin)
156
+ for (let i = numHMetrics; i < numGlyphs; i++) {
157
+ leftSideBearings.push(0); // Default to 0 if derived
158
+ }
159
+ }
160
+
161
+ // Reconstruct standard hmtx table
162
+ // Format:
163
+ // hMetrics[numHMetrics] { advanceWidth: uint16, lsb: int16 }
164
+ // leftSideBearing[numGlyphs - numHMetrics]: int16
165
+
166
+ const hmtxSize = numHMetrics * 4 + (numGlyphs - numHMetrics) * 2;
167
+ const hmtx = new Uint8Array(hmtxSize);
168
+ const view = new DataView(hmtx.buffer);
169
+ let writeOffset = 0;
170
+
171
+ for (let i = 0; i < numHMetrics; i++) {
172
+ view.setUint16(writeOffset, advanceWidths[i] || 0, false);
173
+ view.setInt16(writeOffset + 2, lsbs[i] || 0, false);
174
+ writeOffset += 4;
175
+ }
176
+
177
+ for (let i = 0; i < leftSideBearings.length; i++) {
178
+ view.setInt16(writeOffset, leftSideBearings[i], false);
179
+ writeOffset += 2;
180
+ }
181
+
182
+ return hmtx;
183
+ }
184
+ }