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,24 @@
1
+ /**
2
+ * Decode a base64 string into a Uint8Array without relying on Node Buffer.
3
+ */
4
+ export function decodeBase64ToUint8Array(base64: string): Uint8Array {
5
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
6
+ const clean = base64.replace(/[^A-Za-z0-9+/=]/g, "");
7
+ const output: number[] = [];
8
+ let buffer = 0;
9
+ let bits = 0;
10
+
11
+ for (const c of clean) {
12
+ if (c === "=") break;
13
+ const value = chars.indexOf(c);
14
+ if (value === -1) continue;
15
+ buffer = (buffer << 6) | value;
16
+ bits += 6;
17
+ if (bits >= 8) {
18
+ bits -= 8;
19
+ output.push((buffer >> bits) & 0xff);
20
+ }
21
+ }
22
+
23
+ return new Uint8Array(output);
24
+ }
@@ -0,0 +1,79 @@
1
+
2
+ > pagyra-js@0.0.1 test
3
+ > vitest run path-resolution
4
+
5
+
6
+  RUN  v1.6.1 C:/Users/celso/pagyra-js
7
+
8
+ ÔØ» tests/environment/path-resolution.spec.ts  (14 tests | 3 failed) 12ms
9
+  ÔØ» tests/environment/path-resolution.spec.ts > Path Resolution > NodeEnvironment > resolves leading-slash paths relative to base
10
+   expected 'C:\var\www\public\images\duck.jpg' to be '\var\www\public\images\duck.jpg' // Object.is equality
11
+  ÔØ» tests/environment/path-resolution.spec.ts > Path Resolution > NodeEnvironment > resolves relative paths normally
12
+   expected 'C:\var\www\public\images\duck.jpg' to be '\var\www\public\images\duck.jpg' // Object.is equality
13
+  ÔØ» tests/environment/path-resolution.spec.ts > Path Resolution > BrowserEnvironment > resolves paths with base URL that has path component
14
+   expected 'http://localhost:3000/examples/images' to be 'http://localhost:3000/images/duck.jpg' // Object.is equality
15
+
16
+ ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ» Failed Tests 3 ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»
17
+
18
+ FAIL tests/environment/path-resolution.spec.ts > Path Resolution > NodeEnvironment > resolves leading-slash paths relative to base
19
+ AssertionError: expected 'C:\var\www\public\images\duck.jpg' to be '\var\www\public\images\duck.jpg' // Object.is equality
20
+
21
+ - Expected
22
+ + Received
23
+
24
+ - \var\www\public\images\duck.jpg
25
+ + C:\var\www\public\images\duck.jpg
26
+
27
+ ÔØ» tests/environment/path-resolution.spec.ts:13:30
28
+ 11| const resolved = env.resolveLocal('/images/duck.jpg', base
29
+ 12| const expected = path.join(base, 'images', 'duck.jpg');
30
+ 13| expect(resolved).toBe(expected);
31
+ | ^
32
+ 14| });
33
+ 15|
34
+
35
+ ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»[1/3]ÔÄ»
36
+
37
+ FAIL tests/environment/path-resolution.spec.ts > Path Resolution > NodeEnvironment > resolves relative paths normally
38
+ AssertionError: expected 'C:\var\www\public\images\duck.jpg' to be '\var\www\public\images\duck.jpg' // Object.is equality
39
+
40
+ - Expected
41
+ + Received
42
+
43
+ - \var\www\public\images\duck.jpg
44
+ + C:\var\www\public\images\duck.jpg
45
+
46
+ ÔØ» tests/environment/path-resolution.spec.ts:21:30
47
+ 19| const resolved = env.resolveLocal('images/duck.jpg', base);
48
+ 20| const expected = path.join(base, 'images', 'duck.jpg');
49
+ 21| expect(resolved).toBe(expected);
50
+  Test Files  1 failed (1)
51
+ | ^
52
+ 22| });
53
+ 23|
54
+  Tests  3 failed | 11 passed (14)
55
+
56
+ ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»[2/3]ÔÄ»
57
+
58
+ FAIL tests/environment/path-resolution.spec.ts > Path Resolution > BrowserEnvironment > resolves paths with base URL that has path component
59
+ AssertionError: expected 'http://localhost:3000/examples/images' to be 'http://localhost:3000/images/duck.jpg' // Object.is equality
60
+
61
+ - Expected
62
+ + Received
63
+
64
+ - http://localhost:3000/images/duck.jpg
65
+ + http://localhost:3000/examples/images/duck.jpg
66
+
67
+ ÔØ» tests/environment/path-resolution.spec.ts:100:30
68
+ 98| const env = new BrowserEnvironment();
69
+ 99| const resolved = env.resolveLocal('/images/duck.jpg', 'htt
70
+ 100| expect(resolved).toBe('http://localhost:3000/images/duck.j
71
+ | ^
72
+ 101| });
73
+ 102| });
74
+
75
+ ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»ÔÄ»[3/3]ÔÄ»
76
+
77
+  Start at  18:22:14
78
+  Duration  585ms (transform 50ms, setup 0ms, collect 59ms, tests 12ms, environment 0ms, prepare 169ms)
79
+
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parseBackground } from "../../src/css/parsers/background-parser-extended.js";
3
+ import type { StyleAccumulator } from "../../src/css/style.js";
4
+
5
+ describe("background shorthand parsing", () => {
6
+ it("recognizes named colors", () => {
7
+ const target: StyleAccumulator = {};
8
+ parseBackground("skyblue", target);
9
+ expect(target.backgroundLayers).toBeDefined();
10
+ expect(
11
+ target.backgroundLayers?.some((layer) => layer.kind === "color" && layer.color === "skyblue"),
12
+ ).toBe(true);
13
+ });
14
+ });
@@ -0,0 +1,66 @@
1
+ import { beforeAll, describe, expect, it } from "vitest";
2
+ import { registerAllPropertyParsers } from "../../src/css/parsers/register-parsers.js";
3
+ import { parseClipPath } from "../../src/css/parsers/clip-path-parser.js";
4
+ import type { StyleAccumulator } from "../../src/css/style.js";
5
+ import { computeStyleForElement } from "../../src/css/compute-style.js";
6
+ import { ComputedStyle } from "../../src/css/style.js";
7
+ import { makeUnitParsers } from "../../src/units/units.js";
8
+
9
+ describe("clip-path parser", () => {
10
+ beforeAll(() => {
11
+ registerAllPropertyParsers();
12
+ });
13
+
14
+ it("parses polygon clip-path with percentages", () => {
15
+ const target: StyleAccumulator = {};
16
+ parseClipPath("polygon(50% 0, 0 100%, 100% 100%)", target);
17
+
18
+ expect(target.clipPath).toBeDefined();
19
+ expect(target.clipPath?.type).toBe("polygon");
20
+ const points = target.clipPath?.points;
21
+ expect(points).toBeDefined();
22
+ expect(points?.length).toBe(3);
23
+ expect(points?.[0].x.unit).toBe("percent");
24
+ expect(points?.[1].y.unit).toBe("percent");
25
+ });
26
+
27
+ it("parses polygon clip-path with px units", () => {
28
+ const target: StyleAccumulator = {};
29
+ parseClipPath("polygon(0px 0px, 100px 0px, 0px 100px)", target);
30
+
31
+ expect(target.clipPath).toBeDefined();
32
+ expect(target.clipPath?.points[2].y.unit).toBe("px");
33
+ expect(target.clipPath?.points[2].y.value).toBe(100);
34
+ });
35
+
36
+ it("ignores unsupported clip-path values", () => {
37
+ const target: StyleAccumulator = {};
38
+ parseClipPath("circle(50%)", target);
39
+
40
+ expect(target.clipPath).toBeUndefined();
41
+ });
42
+
43
+ it("propagates clip-path through computeStyleForElement", () => {
44
+ const element = {
45
+ tagName: "div",
46
+ getAttribute(name: string) {
47
+ if (name === "style") {
48
+ return "clip-path: polygon(50% 0, 0 100%, 100% 100%);";
49
+ }
50
+ return null;
51
+ },
52
+ };
53
+
54
+ const style = computeStyleForElement(
55
+ element,
56
+ [],
57
+ new ComputedStyle(),
58
+ makeUnitParsers({ viewport: { width: 800, height: 600 } }),
59
+ 16,
60
+ );
61
+
62
+ expect(style.clipPath).toBeDefined();
63
+ expect(style.clipPath?.type).toBe("polygon");
64
+ expect(style.clipPath?.points).toHaveLength(3);
65
+ });
66
+ });
@@ -0,0 +1,104 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { NodeEnvironment } from '../../src/environment/node-environment.js';
3
+ import { BrowserEnvironment } from '../../src/environment/browser-environment.js';
4
+ import path from 'node:path';
5
+
6
+ describe('Path Resolution', () => {
7
+ describe('NodeEnvironment', () => {
8
+ it('resolves leading-slash paths relative to base', () => {
9
+ const env = new NodeEnvironment();
10
+ const base = path.resolve('/var/www/public');
11
+ const resolved = env.resolveLocal('/images/duck.jpg', base);
12
+ const expected = path.join(base, 'images', 'duck.jpg');
13
+ expect(path.normalize(resolved)).toBe(path.normalize(expected));
14
+ });
15
+
16
+ it('resolves relative paths normally', () => {
17
+ const env = new NodeEnvironment();
18
+ const base = path.resolve('/var/www/public');
19
+ const resolved = env.resolveLocal('images/duck.jpg', base);
20
+ const expected = path.join(base, 'images', 'duck.jpg');
21
+ expect(path.normalize(resolved)).toBe(path.normalize(expected));
22
+ });
23
+
24
+ it('passes through HTTP URLs unchanged', () => {
25
+ const env = new NodeEnvironment();
26
+ const url = 'https://example.com/image.jpg';
27
+ expect(env.resolveLocal(url)).toBe(url);
28
+ });
29
+
30
+ it('passes through protocol-relative URLs unchanged', () => {
31
+ const env = new NodeEnvironment();
32
+ const url = '//example.com/image.jpg';
33
+ expect(env.resolveLocal(url)).toBe(url);
34
+ });
35
+
36
+ it('passes through data URIs unchanged', () => {
37
+ const env = new NodeEnvironment();
38
+ const dataUri = 'data:image/png;base64,iVBORw0KGgo=';
39
+ expect(env.resolveLocal(dataUri)).toBe(dataUri);
40
+ });
41
+
42
+ it('resolves paths without base using current directory', () => {
43
+ const env = new NodeEnvironment();
44
+ const resolved = env.resolveLocal('test.jpg');
45
+ expect(path.isAbsolute(resolved)).toBe(true);
46
+ expect(resolved).toContain('test.jpg');
47
+ });
48
+
49
+ it('strips leading slash even on Windows', () => {
50
+ const env = new NodeEnvironment();
51
+ const base = 'C:\\Users\\test\\public';
52
+ const resolved = env.resolveLocal('/images/duck.jpg', base);
53
+ // Should resolve to C:\Users\test\public\images\duck.jpg, not C:\images\duck.jpg
54
+ expect(resolved).toContain('public');
55
+ expect(resolved).toContain('images');
56
+ expect(resolved).toContain('duck.jpg');
57
+ expect(resolved).not.toBe(path.join('C:', 'images', 'duck.jpg'));
58
+ });
59
+ });
60
+
61
+ describe('BrowserEnvironment', () => {
62
+ it('resolves leading-slash paths relative to base URL', () => {
63
+ const env = new BrowserEnvironment();
64
+ const resolved = env.resolveLocal('/images/duck.jpg', 'http://localhost:3000/');
65
+ expect(resolved).toBe('http://localhost:3000/images/duck.jpg');
66
+ });
67
+
68
+ it('resolves relative paths normally', () => {
69
+ const env = new BrowserEnvironment();
70
+ const resolved = env.resolveLocal('images/duck.jpg', 'http://localhost:3000/');
71
+ expect(resolved).toBe('http://localhost:3000/images/duck.jpg');
72
+ });
73
+
74
+ it('passes through absolute URLs unchanged', () => {
75
+ const env = new BrowserEnvironment();
76
+ const url = 'https://example.com/image.jpg';
77
+ expect(env.resolveLocal(url)).toBe(url);
78
+ });
79
+
80
+ it('passes through protocol-relative URLs unchanged', () => {
81
+ const env = new BrowserEnvironment();
82
+ const url = '//example.com/image.jpg';
83
+ expect(env.resolveLocal(url)).toBe(url);
84
+ });
85
+
86
+ it('passes through data URIs unchanged', () => {
87
+ const env = new BrowserEnvironment();
88
+ const dataUri = 'data:image/png;base64,iVBORw0KGgo=';
89
+ expect(env.resolveLocal(dataUri)).toBe(dataUri);
90
+ });
91
+
92
+ it('throws error when resolving without base', () => {
93
+ const env = new BrowserEnvironment();
94
+ expect(() => env.resolveLocal('test.jpg')).toThrow('Local path resolution is not supported');
95
+ });
96
+
97
+ it('resolves leading-slash paths to origin root (standard URL behavior)', () => {
98
+ const env = new BrowserEnvironment();
99
+ const resolved = env.resolveLocal('/images/duck.jpg', 'http://localhost:3000/examples/');
100
+ // Leading slash in URL context resolves to origin root, not relative to base path
101
+ expect(resolved).toBe('http://localhost:3000/images/duck.jpg');
102
+ });
103
+ });
104
+ });
@@ -0,0 +1,141 @@
1
+ type RenderBox = any;
2
+
3
+ export function findBoxWithBorderRadius(box: RenderBox): RenderBox | null {
4
+ if (box?.borderRadius && box.borderRadius.topLeft?.x > 0) {
5
+ return box;
6
+ }
7
+ for (const child of box.children ?? []) {
8
+ const found = findBoxWithBorderRadius(child);
9
+ if (found) return found;
10
+ }
11
+ return null;
12
+ }
13
+
14
+ export function findChildSpan(box: RenderBox): RenderBox | null {
15
+ for (const child of box.children ?? []) {
16
+ if (child.tagName === "span") return child;
17
+ }
18
+ return null;
19
+ }
20
+
21
+ interface DiagnosticCheck {
22
+ actual: number;
23
+ expected: number;
24
+ diff: number;
25
+ tolerance: number;
26
+ label: string;
27
+ pass: boolean;
28
+ }
29
+
30
+ interface DiagnosticContext {
31
+ testId: string;
32
+ css: any;
33
+ browser: any;
34
+ geometry: {
35
+ borderBox: any;
36
+ contentBox: any;
37
+ spanBox: any;
38
+ padding: any;
39
+ border: any;
40
+ };
41
+ checks: DiagnosticCheck[];
42
+ fontDiagnostics?: string;
43
+ ascii?: string;
44
+ }
45
+
46
+ let context: DiagnosticContext | null = null;
47
+
48
+ export function createDiagnosticsContext(
49
+ testId: string,
50
+ css: any,
51
+ browser: any,
52
+ borderBox: any,
53
+ contentBox: any,
54
+ spanBox: any,
55
+ padding: any,
56
+ border: any,
57
+ fontDiagnostics?: string
58
+ ) {
59
+ context = {
60
+ testId,
61
+ css,
62
+ browser,
63
+ geometry: { borderBox, contentBox, spanBox, padding, border },
64
+ checks: [],
65
+ fontDiagnostics,
66
+ };
67
+ }
68
+
69
+ export function addNumericCheck(
70
+ actual: number,
71
+ expected: number,
72
+ tolerance: number,
73
+ label: string
74
+ ) {
75
+ if (!context) throw new Error("Diagnostics context not initialized");
76
+ const diff = actual - expected;
77
+ const pass = Math.abs(diff) <= tolerance;
78
+ context.checks.push({ actual, expected, diff, tolerance, label, pass });
79
+ }
80
+
81
+ export function renderAsciiLayout(): string {
82
+ if (!context) throw new Error("Diagnostics context not initialized");
83
+
84
+ const { geometry } = context;
85
+ const { borderBox, contentBox, spanBox, padding, border } = geometry;
86
+
87
+ // Calculate relative positions
88
+ const contentX = contentBox.x - borderBox.x;
89
+ const contentY = contentBox.y - borderBox.y;
90
+ const spanX = spanBox.x - borderBox.x;
91
+ const spanY = spanBox.y - borderBox.y;
92
+
93
+ // Simple ASCII representation
94
+ const borderW = Math.round(borderBox.width);
95
+ const borderH = Math.round(borderBox.height);
96
+ const contentW = Math.round(contentBox.width);
97
+ const contentH = Math.round(contentBox.height);
98
+ const spanW = Math.round(spanBox.width);
99
+ const spanH = Math.round(spanBox.height);
100
+
101
+ const ascii = `Border Box (W:${borderW}, H:${borderH}) |#########################|
102
+ Content Box at (${Math.round(contentX)}, ${Math.round(contentY)}) (W:${contentW}, H:${contentH}) | +---+ |
103
+ | |###| |
104
+ | +---+ |
105
+ Span Box at (${Math.round(spanX)}, ${Math.round(spanY)}) (W:${spanW}, H:${spanH}) | [xxx] |
106
+ Padding: T:${padding.top}, R:${padding.right}, B:${padding.bottom}, L:${padding.left}
107
+ Border: T:${border.top}, R:${border.right}, B:${border.bottom}, L:${border.left}`;
108
+
109
+ context.ascii = ascii;
110
+ return ascii;
111
+ }
112
+
113
+ export function finalizeDiagnostics() {
114
+ if (!context) throw new Error("Diagnostics context not initialized");
115
+
116
+ const allPass = context.checks.every((c) => c.pass);
117
+ const computedDiffs = context.checks.map((c) => ({
118
+ label: c.label,
119
+ diff: c.diff,
120
+ }));
121
+
122
+ const json = {
123
+ testId: context.testId,
124
+ css: context.css,
125
+ browser: context.browser,
126
+ geometry: context.geometry,
127
+ checks: context.checks,
128
+ computedDiffs,
129
+ fontDiagnostics: context.fontDiagnostics,
130
+ ascii: context.ascii,
131
+ allPass,
132
+ };
133
+
134
+ console.log(`AI_DIAGNOSTIC::${JSON.stringify(json)}`);
135
+ if (context.ascii) {
136
+ console.log(`AI_ASCII_RENDER::${context.ascii}`);
137
+ }
138
+ if (!allPass) {
139
+ throw new Error("Tests failed - see AI_DIAGNOSTIC for details");
140
+ }
141
+ }
@@ -0,0 +1,52 @@
1
+ import { prepareHtmlRender } from "../../src/html-to-pdf.js";
2
+ import type { RenderBox, Run } from "../../src/pdf/types.js";
3
+
4
+ export async function renderRuns(html: string, css = ""): Promise<Run[]> {
5
+ const wrappedHtml =
6
+ /<html[\s>]/i.test(html) ? html : `<html><body>${html}</body></html>`;
7
+
8
+ const { renderTree } = await prepareHtmlRender({
9
+ html: wrappedHtml,
10
+ css,
11
+ viewportWidth: 794,
12
+ viewportHeight: 1123,
13
+ pageWidth: 794,
14
+ pageHeight: 1123,
15
+ margins: { top: 96, right: 96, bottom: 96, left: 96 },
16
+ });
17
+
18
+ return collectRuns(renderTree.root);
19
+ }
20
+
21
+ export async function renderTreeForHtml(html: string, css = "") {
22
+ const wrappedHtml =
23
+ /<html[\s>]/i.test(html) ? html : `<html><body>${html}</body></html>`;
24
+
25
+ const { renderTree } = await prepareHtmlRender({
26
+ html: wrappedHtml,
27
+ css,
28
+ viewportWidth: 794,
29
+ viewportHeight: 1123,
30
+ pageWidth: 794,
31
+ pageHeight: 1123,
32
+ margins: { top: 96, right: 96, bottom: 96, left: 96 },
33
+ });
34
+
35
+ return renderTree;
36
+ }
37
+
38
+ export function collectRuns(box: RenderBox): Run[] {
39
+ const runs: Run[] = [...(box.textRuns ?? [])];
40
+ for (const child of box.children) {
41
+ runs.push(...collectRuns(child));
42
+ }
43
+ return runs;
44
+ }
45
+
46
+ export function collectBoxes(box: RenderBox): RenderBox[] {
47
+ const boxes: RenderBox[] = [box];
48
+ for (const child of box.children) {
49
+ boxes.push(...collectBoxes(child));
50
+ }
51
+ return boxes;
52
+ }
@@ -0,0 +1,56 @@
1
+ import type { RenderBox, Run } from "../../src/pdf/types.js";
2
+
3
+ export interface LineMetrics {
4
+ lineIndex: number;
5
+ runs: Run[];
6
+ xStart: number;
7
+ xEnd: number;
8
+ }
9
+
10
+ /**
11
+ * Group runs by lineIndex and compute xStart/xEnd using lineMatrix.e + advanceWidth.
12
+ */
13
+ export function computeLineMetrics(box: RenderBox): LineMetrics[] {
14
+ const runs = collectRuns(box).filter(
15
+ (run) => typeof run.lineIndex === "number",
16
+ );
17
+
18
+ const byLine = new Map<number, Run[]>();
19
+
20
+ for (const run of runs) {
21
+ const idx = run.lineIndex as number;
22
+ const list = byLine.get(idx);
23
+ if (list) list.push(run);
24
+ else byLine.set(idx, [run]);
25
+ }
26
+
27
+ const lines: LineMetrics[] = [];
28
+
29
+ for (const [lineIndex, lineRuns] of byLine.entries()) {
30
+ lineRuns.sort(
31
+ (a, b) => (a.lineMatrix?.e ?? 0) - (b.lineMatrix?.e ?? 0),
32
+ );
33
+
34
+ const xStart = Math.min(...lineRuns.map((r) => r.lineMatrix?.e ?? 0));
35
+ const xEnd = Math.max(
36
+ ...lineRuns.map((r) => {
37
+ const x = r.lineMatrix?.e ?? 0;
38
+ const width = r.advanceWidth ?? 0;
39
+ return x + width;
40
+ }),
41
+ );
42
+
43
+ lines.push({ lineIndex, runs: lineRuns, xStart, xEnd });
44
+ }
45
+
46
+ lines.sort((a, b) => a.lineIndex - b.lineIndex);
47
+ return lines;
48
+ }
49
+
50
+ function collectRuns(box: RenderBox): Run[] {
51
+ const runs: Run[] = [...(box.textRuns ?? [])];
52
+ for (const child of box.children) {
53
+ runs.push(...collectRuns(child));
54
+ }
55
+ return runs;
56
+ }
@@ -0,0 +1,38 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { CustomPropertiesMap, resolveVariableReferences } from '../../src/css/custom-properties.js';
3
+
4
+ describe('CSS Custom Properties', () => {
5
+
6
+ it('should resolve simple variable references', () => {
7
+ const customProps = new CustomPropertiesMap();
8
+ customProps.set('--main-color', 'red');
9
+
10
+ expect(resolveVariableReferences('var(--main-color)', customProps)).toBe('red');
11
+ expect(resolveVariableReferences('1px solid var(--main-color)', customProps)).toBe('1px solid red');
12
+ });
13
+
14
+ it('should handle fallback values', () => {
15
+ const customProps = new CustomPropertiesMap();
16
+
17
+ expect(resolveVariableReferences('var(--unknown, blue)', customProps)).toBe('blue');
18
+ expect(resolveVariableReferences('var(--unknown, 10px)', customProps)).toBe('10px');
19
+ });
20
+
21
+ it('should handle nested variable references', () => {
22
+ const customProps = new CustomPropertiesMap();
23
+ customProps.set('--primary', 'blue');
24
+ customProps.set('--accent', 'var(--primary)');
25
+
26
+ expect(resolveVariableReferences('var(--accent)', customProps)).toBe('blue');
27
+ });
28
+
29
+ it('should handle circular references gracefully (depth limit)', () => {
30
+ const customProps = new CustomPropertiesMap();
31
+ customProps.set('--a', 'var(--b)');
32
+ customProps.set('--b', 'var(--a)');
33
+
34
+ // Should not crash, but return the unresolved reference eventually
35
+ const result = resolveVariableReferences('var(--a)', customProps);
36
+ expect(result).toContain('var(');
37
+ });
38
+ });