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,242 @@
1
+ import type { ImageInfo } from "./types.js";
2
+ import { WebpRiffParser } from "./webp-riff-parser.js";
3
+ import { Vp8lDecoder } from "./webp-vp8l-decoder.js";
4
+
5
+ // ============================================================================
6
+ // Types & Interfaces
7
+ // ============================================================================
8
+
9
+ export interface DecodeOptions {
10
+ maxWidth?: number;
11
+ maxHeight?: number;
12
+ scale?: number;
13
+ }
14
+
15
+ // ============================================================================
16
+ // Constants
17
+ // ============================================================================
18
+
19
+ const TEXT_DECODER = new TextDecoder("ascii");
20
+
21
+ // ============================================================================
22
+ // DataReader Class
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Sequential binary data reader with automatic offset tracking
27
+ */
28
+ export class DataReader {
29
+ private view: DataView;
30
+ private offset: number = 0;
31
+
32
+ constructor(buffer: ArrayBuffer) {
33
+ this.view = new DataView(buffer);
34
+ }
35
+
36
+ public seek(offset: number): void {
37
+ if (offset < 0 || offset > this.view.byteLength) {
38
+ throw new RangeError(`Seek offset ${offset} out of bounds [0, ${this.view.byteLength}]`);
39
+ }
40
+ this.offset = offset;
41
+ }
42
+
43
+ public tell(): number {
44
+ return this.offset;
45
+ }
46
+
47
+ public hasMore(): boolean {
48
+ return this.offset < this.view.byteLength;
49
+ }
50
+
51
+ public getUint8(): number {
52
+ this.checkBounds(1);
53
+ const value = this.view.getUint8(this.offset);
54
+ this.offset += 1;
55
+ return value;
56
+ }
57
+
58
+ public getUint16(littleEndian: boolean = false): number {
59
+ this.checkBounds(2);
60
+ const value = this.view.getUint16(this.offset, littleEndian);
61
+ this.offset += 2;
62
+ return value;
63
+ }
64
+
65
+ public getUint32(littleEndian: boolean = false): number {
66
+ this.checkBounds(4);
67
+ const value = this.view.getUint32(this.offset, littleEndian);
68
+ this.offset += 4;
69
+ return value;
70
+ }
71
+
72
+ public getString(length: number): string {
73
+ this.checkBounds(length);
74
+ const bytes = new Uint8Array(this.view.buffer, this.view.byteOffset + this.offset, length);
75
+ this.offset += length;
76
+ return TEXT_DECODER.decode(bytes);
77
+ }
78
+
79
+ public getView(length: number): DataView {
80
+ this.checkBounds(length);
81
+ const view = new DataView(this.view.buffer, this.view.byteOffset + this.offset, length);
82
+ this.offset += length;
83
+ return view;
84
+ }
85
+
86
+ private checkBounds(length: number): void {
87
+ if (this.offset + length > this.view.byteLength) {
88
+ throw new RangeError(`Read beyond buffer bounds: ${this.offset + length} > ${this.view.byteLength}`);
89
+ }
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Reads individual bits from a DataView (LSB first)
95
+ */
96
+ export class BitReader {
97
+ private view: DataView;
98
+ private bytePos: number = 0;
99
+ private bitPos: number = 0;
100
+
101
+ constructor(view: DataView) {
102
+ this.view = view;
103
+ }
104
+
105
+ public readBits(n: number): number {
106
+ if (n > 32) {
107
+ throw new Error("Cannot read more than 32 bits at once");
108
+ }
109
+
110
+ let value = 0;
111
+ for (let i = 0; i < n; i++) {
112
+ if (this.bytePos >= this.view.byteLength) {
113
+ // Pad with zeros if we run out of data (end of stream)
114
+ return value;
115
+ }
116
+
117
+ const byte = this.view.getUint8(this.bytePos);
118
+ const bit = (byte >> this.bitPos) & 1;
119
+ value |= bit << i;
120
+
121
+ this.bitPos++;
122
+ if (this.bitPos === 8) {
123
+ this.bitPos = 0;
124
+ this.bytePos++;
125
+ }
126
+ }
127
+ return value;
128
+ }
129
+
130
+ public hasMore(): boolean {
131
+ return this.bytePos < this.view.byteLength;
132
+ }
133
+
134
+ // For debugging - peek at next bits without consuming them
135
+ public peekBits(n: number): number {
136
+ const oldBytePos = this.bytePos;
137
+ const oldBitPos = this.bitPos;
138
+ const value = this.readBits(n);
139
+ this.bytePos = oldBytePos;
140
+ this.bitPos = oldBitPos;
141
+ return value;
142
+ }
143
+ }
144
+
145
+ export abstract class BaseDecoder {
146
+
147
+ protected static calculateDimensions(
148
+ width: number,
149
+ height: number,
150
+ options: DecodeOptions
151
+ ): { targetWidth: number; targetHeight: number } {
152
+ let targetWidth = width;
153
+ let targetHeight = height;
154
+
155
+ if (options.scale && options.scale > 0) {
156
+ targetWidth = Math.max(1, Math.round(width * options.scale));
157
+ targetHeight = Math.max(1, Math.round(height * options.scale));
158
+ } else if (options.maxWidth || options.maxHeight) {
159
+ const scale = Math.min(
160
+ options.maxWidth ? options.maxWidth / width : Infinity,
161
+ options.maxHeight ? options.maxHeight / height : Infinity
162
+ );
163
+
164
+ if (scale > 0 && scale < 1) {
165
+ targetWidth = Math.max(1, Math.round(width * scale));
166
+ targetHeight = Math.max(1, Math.round(height * scale));
167
+ }
168
+ }
169
+
170
+ return { targetWidth, targetHeight };
171
+ }
172
+
173
+ protected static resizeNN(
174
+ src: Uint8Array,
175
+ sw: number,
176
+ sh: number,
177
+ tw: number,
178
+ th: number,
179
+ channels: number,
180
+ ): Uint8Array {
181
+ if (sw === tw && sh === th) return src;
182
+
183
+ const dst = new Uint8Array(tw * th * channels);
184
+ const xRatio = sw / tw;
185
+ const yRatio = sh / th;
186
+
187
+ for (let y = 0; y < th; y++) {
188
+ const sy = Math.min(sh - 1, Math.floor(y * yRatio));
189
+ const srcRowOffset = sy * sw * channels;
190
+ const dstRowOffset = y * tw * channels;
191
+
192
+ for (let x = 0; x < tw; x++) {
193
+ const sx = Math.min(sw - 1, Math.floor(x * xRatio));
194
+ const si = srcRowOffset + sx * channels;
195
+ const di = dstRowOffset + x * channels;
196
+
197
+ for (let c = 0; c < channels; c++) {
198
+ dst[di + c] = src[si + c];
199
+ }
200
+ }
201
+ }
202
+ return dst;
203
+ }
204
+
205
+ public abstract decode(buffer: ArrayBuffer, options?: DecodeOptions): Promise<ImageInfo>;
206
+ }
207
+
208
+ export class WebpDecoder extends BaseDecoder {
209
+ private riffParser = new WebpRiffParser();
210
+ private vp8lDecoder = new Vp8lDecoder();
211
+
212
+ public async decode(
213
+ buffer: ArrayBuffer,
214
+ options: DecodeOptions = {},
215
+ ): Promise<ImageInfo> {
216
+ const reader = new DataReader(buffer);
217
+
218
+ // Validate RIFF header
219
+ this.riffParser.validateHeader(reader);
220
+
221
+ // Parse chunks
222
+ const chunks = this.riffParser.parseChunks(reader);
223
+
224
+ // Determine format and decode
225
+ const vp8xChunk = chunks.find(c => c.fourCC === 'VP8X');
226
+ if (vp8xChunk) {
227
+ return this.vp8lDecoder.decodeVp8x(vp8xChunk, chunks, options, WebpDecoder.calculateDimensions, WebpDecoder.resizeNN);
228
+ }
229
+
230
+ const vp8lChunk = chunks.find(c => c.fourCC === 'VP8L');
231
+ if (vp8lChunk) {
232
+ return this.vp8lDecoder.decodeVp8l(vp8lChunk, options, WebpDecoder.calculateDimensions, WebpDecoder.resizeNN);
233
+ }
234
+
235
+ const vp8Chunk = chunks.find(c => c.fourCC === 'VP8 ');
236
+ if (vp8Chunk) {
237
+ throw new Error("VP8 (lossy) WebP format is not yet supported");
238
+ }
239
+
240
+ throw new Error("Unsupported WebP format: No recognized image chunk found");
241
+ }
242
+ }
@@ -0,0 +1,218 @@
1
+ import { BitReader } from "./webp-decoder.js";
2
+
3
+ /**
4
+ * Huffman code representation
5
+ */
6
+ export interface HuffmanCode {
7
+ symbol: number;
8
+ length: number;
9
+ code: number;
10
+ }
11
+
12
+ /**
13
+ * Huffman tree with optional lookup table for performance
14
+ */
15
+ export interface HuffmanTree {
16
+ codes: HuffmanCode[];
17
+ maxLength: number;
18
+ lookupTable?: Map<number, number>;
19
+ }
20
+
21
+ const CODE_LENGTH_ORDER = [17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] as const;
22
+ const HUFFMAN_GROUPS = 5;
23
+
24
+ /**
25
+ * Huffman code decoder for WebP VP8L format
26
+ * Responsibility: Build and decode Huffman trees
27
+ */
28
+ export class WebpHuffmanDecoder {
29
+ /**
30
+ * Read all Huffman code groups (5 groups for VP8L)
31
+ */
32
+ readHuffmanCodes(br: BitReader): HuffmanTree[] {
33
+ const huffmanCodes: HuffmanTree[] = [];
34
+
35
+ for (let i = 0; i < HUFFMAN_GROUPS; i++) {
36
+ const alphabetSize = i === 4 ? 40 : 280; // 256 + 24 = 280
37
+ huffmanCodes[i] = this.readHuffmanCode(br, alphabetSize);
38
+ }
39
+
40
+ return huffmanCodes;
41
+ }
42
+
43
+ /**
44
+ * Read a single Huffman code
45
+ */
46
+ private readHuffmanCode(br: BitReader, alphabetSize: number): HuffmanTree {
47
+ const simple = br.readBits(1);
48
+
49
+ if (simple) {
50
+ return this.readSimpleHuffmanCode(br);
51
+ }
52
+
53
+ // Read code length codes
54
+ const codeLengthCodeLengths = new Array(19).fill(0);
55
+ const numCodeLengthCodes = 4 + br.readBits(4);
56
+
57
+ for (let i = 0; i < numCodeLengthCodes; i++) {
58
+ codeLengthCodeLengths[CODE_LENGTH_ORDER[i]] = br.readBits(3);
59
+ }
60
+
61
+ const codeLengthTree = this.buildHuffmanTree(codeLengthCodeLengths);
62
+ const codeLengths = this.readCodeLengths(br, codeLengthTree, alphabetSize);
63
+
64
+ return this.buildHuffmanTree(codeLengths);
65
+ }
66
+
67
+ /**
68
+ * Read simple Huffman code (1 or 2 symbols)
69
+ */
70
+ private readSimpleHuffmanCode(br: BitReader): HuffmanTree {
71
+ const numSymbols = br.readBits(1) + 1;
72
+ const symbols: number[] = [];
73
+
74
+ const is8Bits = br.readBits(1);
75
+ const bitCount = is8Bits ? 8 : 1;
76
+
77
+ symbols.push(br.readBits(bitCount));
78
+ if (numSymbols === 2) {
79
+ symbols.push(br.readBits(bitCount));
80
+ }
81
+
82
+ return this.buildSimpleHuffman(symbols);
83
+ }
84
+
85
+ /**
86
+ * Read code lengths for symbols
87
+ */
88
+ private readCodeLengths(br: BitReader, codeLengthTree: HuffmanTree, alphabetSize: number): number[] {
89
+ const codeLengths = new Array(alphabetSize).fill(0);
90
+ let i = 0;
91
+
92
+ while (i < alphabetSize) {
93
+ const code = this.readSymbol(br, codeLengthTree);
94
+
95
+ if (code < 16) {
96
+ codeLengths[i++] = code;
97
+ } else {
98
+ let repeatCount = 0;
99
+ let repeatValue = 0;
100
+
101
+ if (code === 16) {
102
+ repeatCount = 3 + br.readBits(2);
103
+ repeatValue = codeLengths[i - 1];
104
+ } else if (code === 17) {
105
+ repeatCount = 3 + br.readBits(3);
106
+ } else if (code === 18) {
107
+ repeatCount = 11 + br.readBits(7);
108
+ }
109
+
110
+ for (let j = 0; j < repeatCount && i < alphabetSize; j++) {
111
+ codeLengths[i++] = repeatValue;
112
+ }
113
+ }
114
+ }
115
+
116
+ return codeLengths;
117
+ }
118
+
119
+ /**
120
+ * Build simple Huffman tree from 1-2 symbols
121
+ */
122
+ private buildSimpleHuffman(symbols: number[]): HuffmanTree {
123
+ if (symbols.length === 1) {
124
+ return { codes: [{ symbol: symbols[0], length: 0, code: 0 }], maxLength: 0 };
125
+ }
126
+
127
+ return {
128
+ codes: [
129
+ { symbol: symbols[0], length: 1, code: 0 },
130
+ { symbol: symbols[1], length: 1, code: 1 }
131
+ ],
132
+ maxLength: 1
133
+ };
134
+ }
135
+
136
+ /**
137
+ * Build Huffman tree from code lengths using canonical Huffman code algorithm
138
+ */
139
+ buildHuffmanTree(codeLengths: number[]): HuffmanTree {
140
+ // Filter out invalid values and find the max length
141
+ const validLengths = codeLengths.filter(len => len > 0 && Number.isFinite(len));
142
+ const maxLength = validLengths.length > 0 ? Math.max(...validLengths) : 0;
143
+ const codes: HuffmanCode[] = [];
144
+
145
+ if (maxLength === 0) {
146
+ return { codes: [], maxLength: 0, lookupTable: new Map() };
147
+ }
148
+
149
+ const bl_count = new Array(maxLength + 1).fill(0);
150
+ const next_code = new Array(maxLength + 1).fill(0);
151
+
152
+ // Count codes per length
153
+ for (const len of codeLengths) {
154
+ if (len > 0 && Number.isFinite(len)) bl_count[len]++;
155
+ }
156
+
157
+ // Calculate starting codes for each length
158
+ next_code[1] = 0;
159
+ for (let bits = 2; bits <= maxLength; bits++) {
160
+ next_code[bits] = (next_code[bits - 1] + bl_count[bits - 1]) << 1;
161
+ }
162
+
163
+ // Assign codes to symbols
164
+ const lookupTable = new Map<number, number>();
165
+ for (let n = 0; n < codeLengths.length; n++) {
166
+ const len = codeLengths[n];
167
+ if (len > 0 && Number.isFinite(len)) {
168
+ const codeValue = next_code[len];
169
+ codes.push({ symbol: n, length: len, code: codeValue });
170
+ // Create lookup key using a bit shift approach
171
+ // Store as (code << 4) | length for fast lookup
172
+ const key = (codeValue << 4) | len;
173
+ lookupTable.set(key, n);
174
+ next_code[len]++;
175
+ }
176
+ }
177
+
178
+ return { codes, maxLength, lookupTable };
179
+ }
180
+
181
+ /**
182
+ * Read a symbol from the bitstream using the Huffman tree
183
+ */
184
+ readSymbol(br: BitReader, tree: HuffmanTree): number {
185
+ if (tree.maxLength === 0) {
186
+ return tree.codes[0].symbol;
187
+ }
188
+
189
+ // Use lookup table for O(1) access
190
+ if (tree.lookupTable) {
191
+ let code = 0;
192
+ for (let i = 0; i < tree.maxLength; i++) {
193
+ code = (code << 1) | br.readBits(1);
194
+ // Check if this code with the current length exists
195
+ const key = (code << 4) | (i + 1);
196
+ const symbol = tree.lookupTable.get(key);
197
+ if (symbol !== undefined) {
198
+ return symbol;
199
+ }
200
+ }
201
+ }
202
+
203
+ // Fallback to linear search through codes
204
+ for (const codeInfo of tree.codes) {
205
+ let code = 0;
206
+ for (let i = 0; i < codeInfo.length; i++) {
207
+ code = (code << 1) | br.readBits(1);
208
+ }
209
+ if (code === codeInfo.code) {
210
+ return codeInfo.symbol;
211
+ }
212
+ }
213
+
214
+ // If no symbol is found, return 0 as fallback
215
+ // This prevents the decoder from failing completely
216
+ return 0;
217
+ }
218
+ }
@@ -0,0 +1,54 @@
1
+ import { DataReader } from "./webp-decoder.js";
2
+
3
+ /**
4
+ * Represents a single RIFF chunk
5
+ */
6
+ export interface RiffChunk {
7
+ fourCC: string;
8
+ size: number;
9
+ data: DataView;
10
+ }
11
+
12
+ /**
13
+ * Parser for WebP RIFF container structure
14
+ * Responsibility: Parse and validate RIFF chunks
15
+ */
16
+ export class WebpRiffParser {
17
+ /**
18
+ * Validate RIFF header signature
19
+ */
20
+ validateHeader(reader: DataReader): void {
21
+ const riff = reader.getString(4);
22
+ if (riff !== 'RIFF') {
23
+ throw new Error("Invalid WebP: Missing RIFF header");
24
+ }
25
+
26
+ reader.getUint32(true); // File size (unused)
27
+
28
+ const webp = reader.getString(4);
29
+ if (webp !== 'WEBP') {
30
+ throw new Error("Invalid WebP: Missing WEBP signature");
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Parse all chunks from the RIFF container
36
+ */
37
+ parseChunks(reader: DataReader): RiffChunk[] {
38
+ const chunks: RiffChunk[] = [];
39
+
40
+ while (reader.hasMore()) {
41
+ const fourCC = reader.getString(4);
42
+ const size = reader.getUint32(true);
43
+ const data = reader.getView(size);
44
+ chunks.push({ fourCC, size, data });
45
+
46
+ // Skip padding byte if chunk size is odd
47
+ if (size % 2 === 1 && reader.hasMore()) {
48
+ reader.seek(reader.tell() + 1);
49
+ }
50
+ }
51
+
52
+ return chunks;
53
+ }
54
+ }
@@ -0,0 +1,199 @@
1
+ import { BitReader, type DecodeOptions } from "./webp-decoder.js";
2
+ import type { ImageInfo } from "./types.js";
3
+ import { WebpHuffmanDecoder, type HuffmanTree } from "./webp-huffman.js";
4
+ import type { RiffChunk } from "./webp-riff-parser.js";
5
+
6
+ const VP8L_SIGNATURE = 0x2f;
7
+
8
+ /**
9
+ * VP8L (lossless WebP) decoder
10
+ * Responsibility: Decode VP8L image data
11
+ */
12
+ export class Vp8lDecoder {
13
+ private huffmanDecoder = new WebpHuffmanDecoder();
14
+
15
+ /**
16
+ * Decode a VP8L chunk into image data
17
+ */
18
+ decodeVp8l(chunk: RiffChunk, options: DecodeOptions, calculateDimensions: (w: number, h: number, opts: DecodeOptions) => { targetWidth: number; targetHeight: number }, resizeNN: (src: Uint8Array, sw: number, sh: number, tw: number, th: number, channels: number) => Uint8Array): ImageInfo {
19
+ const br = new BitReader(chunk.data);
20
+
21
+ // Read signature
22
+ const signature = br.readBits(8);
23
+ if (signature !== VP8L_SIGNATURE) {
24
+ throw new Error("Invalid VP8L signature");
25
+ }
26
+
27
+ // Read dimensions
28
+ const width = br.readBits(14) + 1;
29
+ const height = br.readBits(14) + 1;
30
+ const version = br.readBits(3);
31
+
32
+ if (version !== 0) {
33
+ throw new Error(`Unsupported VP8L version: ${version}`);
34
+ }
35
+
36
+ // Skip transforms for now (they're complex)
37
+ let transformsPresent = br.readBits(1);
38
+ while (transformsPresent) {
39
+ const transformType = br.readBits(2);
40
+
41
+ if (transformType === 0 || transformType === 1) { // Predictor/Color Transform
42
+ const sizeBits = br.readBits(3) + 2;
43
+ const blockWidth = this.subSampleSize(width, sizeBits);
44
+ const blockHeight = this.subSampleSize(height, sizeBits);
45
+ this.skipTransformImage(br, blockWidth, blockHeight);
46
+ } else if (transformType === 3) { // Color Indexing
47
+ // Skip palette reading for simplicity
48
+ }
49
+
50
+ transformsPresent = br.readBits(1);
51
+ }
52
+
53
+ // Read Huffman codes and decode pixel data
54
+ const huffmanCodes = this.huffmanDecoder.readHuffmanCodes(br);
55
+ const pixels = this.decodePixelData(br, width, height, huffmanCodes);
56
+
57
+ // Calculate target dimensions and resize if needed
58
+ const { targetWidth, targetHeight } = calculateDimensions(width, height, options);
59
+ const finalPixels = resizeNN(pixels, width, height, targetWidth, targetHeight, 4);
60
+
61
+ return {
62
+ width: targetWidth,
63
+ height: targetHeight,
64
+ format: "webp",
65
+ channels: 4,
66
+ bitsPerChannel: 8,
67
+ data: finalPixels.buffer as ArrayBuffer,
68
+ };
69
+ }
70
+
71
+ /**
72
+ * Decode pixel data from VP8L bitstream
73
+ */
74
+ private decodePixelData(
75
+ br: BitReader,
76
+ width: number,
77
+ height: number,
78
+ huffmanCodes: HuffmanTree[]
79
+ ): Uint8Array {
80
+ const pixels = new Uint8Array(width * height * 4);
81
+ let pixelIndex = 0;
82
+ const totalPixels = width * height;
83
+
84
+ for (let i = 0; i < totalPixels; i++) {
85
+ const green = this.huffmanDecoder.readSymbol(br, huffmanCodes[0]);
86
+
87
+ if (green < 256) {
88
+ // Literal pixel
89
+ const red = this.huffmanDecoder.readSymbol(br, huffmanCodes[1]);
90
+ const blue = this.huffmanDecoder.readSymbol(br, huffmanCodes[2]);
91
+ const alpha = this.huffmanDecoder.readSymbol(br, huffmanCodes[3]);
92
+
93
+ pixels[pixelIndex++] = red;
94
+ pixels[pixelIndex++] = green;
95
+ pixels[pixelIndex++] = blue;
96
+ pixels[pixelIndex++] = alpha;
97
+ } else {
98
+ // Backward reference (LZ77)
99
+ const lengthSymbol = green - 256;
100
+ const length = this.getLengthFromSymbol(lengthSymbol, br);
101
+ const distSymbol = this.huffmanDecoder.readSymbol(br, huffmanCodes[4]);
102
+ const distance = this.getDistanceFromSymbol(distSymbol, br);
103
+
104
+ // Copy pixels from earlier in the stream
105
+ for (let j = 0; j < length && i + j < totalPixels; j++) {
106
+ const srcIdx = pixelIndex - distance * 4;
107
+ if (srcIdx >= 0) {
108
+ pixels[pixelIndex++] = pixels[srcIdx];
109
+ pixels[pixelIndex++] = pixels[srcIdx + 1];
110
+ pixels[pixelIndex++] = pixels[srcIdx + 2];
111
+ pixels[pixelIndex++] = pixels[srcIdx + 3];
112
+ }
113
+ }
114
+ i += length - 1;
115
+ }
116
+ }
117
+
118
+ return pixels;
119
+ }
120
+
121
+ /**
122
+ * Calculate subsampled size
123
+ */
124
+ private subSampleSize(size: number, samplingBits: number): number {
125
+ return (size + (1 << samplingBits) - 1) >> samplingBits;
126
+ }
127
+
128
+ /**
129
+ * Skip transform image data (simplified skip logic)
130
+ */
131
+ private skipTransformImage(br: BitReader, width: number, height: number): void {
132
+ // Skip the Huffman codes and pixel data for transforms
133
+ try {
134
+ this.huffmanDecoder.readHuffmanCodes(br); // Skip Huffman codes
135
+ } catch {
136
+ // If reading Huffman codes fails, skip a reasonable amount of bits
137
+ const maxBitsToSkip = Math.min(width * height * 4, 10000);
138
+ for (let i = 0; i < maxBitsToSkip && br.hasMore(); i++) {
139
+ br.readBits(1);
140
+ }
141
+ return;
142
+ }
143
+ const totalPixels = width * height;
144
+ // For simplicity, just skip a reasonable amount of data
145
+ // This is not accurate but avoids the complex decoding
146
+ for (let i = 0; i < Math.min(totalPixels * 4, 10000); i++) {
147
+ if (!br.hasMore()) break;
148
+ br.readBits(1);
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Get length from LZ77 symbol
154
+ */
155
+ private getLengthFromSymbol(symbol: number, br: BitReader): number {
156
+ if (symbol < 4) return symbol + 1;
157
+ const extraBits = (symbol - 2) >> 1;
158
+ const offset = (2 + (symbol & 1)) << extraBits;
159
+ return offset + br.readBits(extraBits) + 1;
160
+ }
161
+
162
+ /**
163
+ * Get distance from LZ77 symbol
164
+ */
165
+ private getDistanceFromSymbol(symbol: number, br: BitReader): number {
166
+ if (symbol < 4) return symbol + 1;
167
+ const extraBits = (symbol - 2) >> 1;
168
+ const offset = (2 + (symbol & 1)) << extraBits;
169
+ return offset + br.readBits(extraBits) + 1;
170
+ }
171
+
172
+ /**
173
+ * Decode VP8X extended format
174
+ */
175
+ decodeVp8x(chunk: RiffChunk, chunks: RiffChunk[], options: DecodeOptions, calculateDimensions: (w: number, h: number, opts: DecodeOptions) => { targetWidth: number; targetHeight: number }, resizeNN: (src: Uint8Array, sw: number, sh: number, tw: number, th: number, channels: number) => Uint8Array): ImageInfo {
176
+ const data = new Uint8Array(chunk.data.buffer, chunk.data.byteOffset, chunk.data.byteLength);
177
+
178
+ // VP8X flags (currently unused but available for future features)
179
+ const flags = data[0];
180
+ const hasAnimation = (flags & 0x02) !== 0;
181
+
182
+ if (hasAnimation) {
183
+ throw new Error("Animated WebP is not supported");
184
+ }
185
+
186
+ // Find the actual image data chunk
187
+ const vp8lChunk = chunks.find(c => c.fourCC === 'VP8L');
188
+ if (vp8lChunk) {
189
+ return this.decodeVp8l(vp8lChunk, options, calculateDimensions, resizeNN);
190
+ }
191
+
192
+ const vp8Chunk = chunks.find(c => c.fourCC === 'VP8 ');
193
+ if (vp8Chunk) {
194
+ throw new Error("VP8 (lossy) WebP format is not yet supported");
195
+ }
196
+
197
+ throw new Error("No image data found in VP8X container");
198
+ }
199
+ }