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,57 @@
1
+ #!/usr/bin/env tsx
2
+ import express from "express";
3
+ import path from "node:path";
4
+ import { mkdir } from "node:fs/promises";
5
+ import { buildBrowserBundle } from "./browser-build.js";
6
+
7
+ const PORT = Number.parseInt(process.env.PORT ?? "", 10) || 5177;
8
+ const PUBLIC_DIR = path.resolve("playground", "public");
9
+ const ENTRY = "playground/browser-entry.ts";
10
+ const OUTFILE = "playground/public/vendor/pagyra-playground-browser.js";
11
+
12
+ async function start() {
13
+ await mkdir(path.dirname(path.resolve(OUTFILE)), { recursive: true });
14
+ const buildResult = await buildBrowserBundle({
15
+ entry: ENTRY,
16
+ outfile: OUTFILE,
17
+ minify: false,
18
+ sourcemap: true,
19
+ watch: true,
20
+ onRebuild(error) {
21
+ if (error) {
22
+ console.error("[playground bundle] rebuild failed:", error);
23
+ } else {
24
+ console.log("[playground bundle] rebuild finished.");
25
+ }
26
+ },
27
+ });
28
+
29
+ const app = express();
30
+
31
+ app.get("/mode.js", (_req, res) => {
32
+ res.type("application/javascript");
33
+ res.send('window.__PLAYGROUND_MODE = "browser";');
34
+ });
35
+
36
+ // Expose shared assets (fonts, images) for the browser bundle.
37
+ app.use("/assets", express.static(path.resolve("assets")));
38
+ app.use(express.static(PUBLIC_DIR));
39
+
40
+ const server = app.listen(PORT, () => {
41
+ console.log(`[playground:browser] serving http://localhost:${PORT}`);
42
+ });
43
+
44
+ const cleanup = async () => {
45
+ server.close(() => console.log("[playground:browser] server stopped"));
46
+ await buildResult.stop?.();
47
+ process.exit();
48
+ };
49
+
50
+ process.once("SIGINT", cleanup);
51
+ process.once("SIGTERM", cleanup);
52
+ }
53
+
54
+ start().catch((error) => {
55
+ console.error("[playground:browser] failed to start:", error);
56
+ process.exit(1);
57
+ });
@@ -0,0 +1,6 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { parseTtfBuffer } from "../src/pdf/font/ttf-lite.js";
3
+
4
+ const data = await readFile("assets/fonts/Roboto-Regular.ttf");
5
+ const metrics = parseTtfBuffer(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
6
+ console.log("glyphId", metrics.cmap.getGlyphId(0x25AA));
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env tsx
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { renderHtmlToPdf } from '../src/html-to-pdf.js';
6
+ import { DEFAULT_PAGE_WIDTH_PX, DEFAULT_PAGE_HEIGHT_PX } from '../src/units/page-utils.js';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+
11
+ async function main() {
12
+ // Parse command line arguments
13
+ const args = process.argv.slice(2);
14
+ let debugLevel: string | undefined;
15
+ let debugCats: string[] | undefined;
16
+ let examplePathArg: string | undefined;
17
+ let pageWidth: number | undefined;
18
+ let pageHeight: number | undefined;
19
+ let margins: { top: number; right: number; bottom: number; left: number } | undefined;
20
+
21
+ for (let i = 0; i < args.length; i++) {
22
+ const arg = args[i];
23
+ if (arg === '--debug-level' && i + 1 < args.length) {
24
+ debugLevel = args[i + 1] as any; // will validate later
25
+ i++;
26
+ } else if (arg === '--debug-cats' && i + 1 < args.length) {
27
+ debugCats = args[i + 1].split(',').map(cat => cat.trim()).filter(Boolean);
28
+ i++;
29
+ } else if (arg === '--page-width' && i + 1 < args.length) {
30
+ pageWidth = parseFloat(args[i + 1]);
31
+ i++;
32
+ } else if (arg === '--page-height' && i + 1 < args.length) {
33
+ pageHeight = parseFloat(args[i + 1]);
34
+ i++;
35
+ } else if (arg === '--margins' && i + 1 < args.length) {
36
+ const marginValues = args[i + 1].split(',').map(m => parseFloat(m.trim()));
37
+ if (marginValues.length === 1) {
38
+ margins = { top: marginValues[0], right: marginValues[0], bottom: marginValues[0], left: marginValues[0] };
39
+ } else if (marginValues.length === 2) {
40
+ margins = { top: marginValues[0], right: marginValues[1], bottom: marginValues[0], left: marginValues[1] };
41
+ } else if (marginValues.length === 4) {
42
+ margins = { top: marginValues[0], right: marginValues[1], bottom: marginValues[2], left: marginValues[3] };
43
+ } else {
44
+ console.warn('Invalid --margins argument. Expected 1, 2, or 4 comma-separated numbers (e.g., "10", "10,20", "10,20,30,40").');
45
+ }
46
+ i++;
47
+ } else if (!arg.startsWith('--')) {
48
+ examplePathArg = arg;
49
+ }
50
+ }
51
+
52
+ const repoRoot = path.resolve(__dirname, '..');
53
+ const examplesDir = path.join(repoRoot, 'playground', 'public', 'examples');
54
+ // Allow passing an example path or filename as the first argument. If it's a filename,
55
+ // resolve it under playground/public/examples. Otherwise use the default demo.
56
+ const arg = examplePathArg;
57
+ let examplePath: string;
58
+ if (arg) {
59
+ // Try a few sensible resolutions for the provided argument.
60
+ const candidateAbsolute = path.isAbsolute(arg) ? arg : path.join(repoRoot, arg);
61
+ const candidateExamples = path.join(examplesDir, arg);
62
+ try {
63
+ await fs.stat(candidateAbsolute);
64
+ examplePath = candidateAbsolute;
65
+ } catch {
66
+ try {
67
+ await fs.stat(candidateExamples);
68
+ examplePath = candidateExamples;
69
+ } catch {
70
+ const withHtml = candidateExamples.endsWith('.html') ? '' : '.html';
71
+ const candidateWithExt = candidateExamples + withHtml;
72
+ try {
73
+ await fs.stat(candidateWithExt);
74
+ examplePath = candidateWithExt;
75
+ } catch {
76
+ // Fallback: resolve under examplesDir (may still error later when reading)
77
+ examplePath = candidateExamples;
78
+ }
79
+ }
80
+ }
81
+ } else {
82
+ examplePath = path.join(examplesDir, 'svg-radial-transform-demo.html');
83
+ }
84
+ const outDir = path.join(repoRoot, 'playground', 'exports');
85
+ await fs.mkdir(outDir, { recursive: true });
86
+
87
+ const html = await fs.readFile(examplePath, 'utf8');
88
+
89
+ const finalPageWidth = pageWidth ?? DEFAULT_PAGE_WIDTH_PX;
90
+ const finalPageHeight = pageHeight ?? DEFAULT_PAGE_HEIGHT_PX;
91
+
92
+ console.log('Rendering playground example to PDF:', examplePath);
93
+ // Provide resource/asset roots so example-relative and absolute (/images/...) URLs resolve
94
+ const resourceBaseDir = path.dirname(examplePath);
95
+ const assetRootDir = path.join(repoRoot, 'playground', 'public');
96
+
97
+ const pdf = await renderHtmlToPdf({
98
+ html,
99
+ css: '',
100
+ viewportWidth: finalPageWidth,
101
+ viewportHeight: finalPageHeight,
102
+ pageWidth: finalPageWidth,
103
+ pageHeight: finalPageHeight,
104
+ margins: margins ?? { top: 0, right: 0, bottom: 0, left: 0 },
105
+ debug: !!(debugLevel || debugCats),
106
+ debugLevel: debugLevel as any,
107
+ debugCats,
108
+ resourceBaseDir,
109
+ assetRootDir,
110
+ });
111
+
112
+ const outName = path.basename(examplePath).replace(/\.html?$/i, '') + '.pdf';
113
+ const outPath = path.join(outDir, outName);
114
+ await fs.writeFile(outPath, pdf);
115
+ console.log('PDF written to:', outPath);
116
+ }
117
+
118
+ main().catch(err => {
119
+ console.error('Error rendering playground example:', err instanceof Error ? err.stack : err);
120
+ process.exit(1);
121
+ });
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Runner that imports compiled JS from dist and runs the atlas tuner.
3
+ * Use after building the project: `npm run build`
4
+ *
5
+ * Run with: `node scripts/run-glyph-atlas-tuner-runner.mjs`
6
+ *
7
+ * This avoids ts-node resolution issues by using the compiled output.
8
+ */
9
+
10
+ import fs from "fs";
11
+ import path from "path";
12
+
13
+ import { parseTtfFont } from "../dist/src/pdf/font/ttf-lite.js";
14
+ import { getGlyphMask, clearGlyphMaskCache } from "../dist/src/pdf/font/glyph-cache.js";
15
+ import { pickAtlasSettingsFromSamples } from "../dist/src/pdf/font/glyph-atlas-tuner.js";
16
+
17
+ async function sampleFromFont(fontPath, opts = {}) {
18
+ const samples = [];
19
+ const maxGlyphs = opts.maxGlyphs ?? 200;
20
+ const fontSizePx = opts.fontSizePx ?? 64;
21
+
22
+ try {
23
+ const metrics = parseTtfFont(fontPath);
24
+ const glyphCount = metrics.glyphMetrics ? metrics.glyphMetrics.size : Math.max(256, maxGlyphs);
25
+ const limit = Math.min(maxGlyphs, glyphCount);
26
+
27
+ if (metrics.glyphMetrics && metrics.glyphMetrics.size > 0) {
28
+ let i = 0;
29
+ for (const [gid] of metrics.glyphMetrics) {
30
+ if (i >= limit) break;
31
+ try {
32
+ const mask = getGlyphMask(metrics, gid, fontSizePx, 4);
33
+ if (mask && mask.width > 0 && mask.height > 0) {
34
+ samples.push({ width: mask.width, height: mask.height });
35
+ i++;
36
+ }
37
+ } catch (e) {
38
+ // ignore
39
+ }
40
+ }
41
+ } else {
42
+ for (let gid = 0; gid < limit; gid++) {
43
+ try {
44
+ const mask = getGlyphMask(metrics, gid, fontSizePx, 4);
45
+ if (mask && mask.width > 0 && mask.height > 0) {
46
+ samples.push({ width: mask.width, height: mask.height });
47
+ }
48
+ } catch (e) {}
49
+ }
50
+ }
51
+
52
+ clearGlyphMaskCache();
53
+ } catch (err) {
54
+ console.error("Failed to parse font", fontPath, err && err.message ? err.message : err);
55
+ }
56
+
57
+ return samples;
58
+ }
59
+
60
+ function syntheticSamples() {
61
+ const arr = [];
62
+ for (let i = 0; i < 40; i++) arr.push({ width: 8, height: 10 });
63
+ for (let i = 0; i < 40; i++) arr.push({ width: 20 + (i % 10), height: 24 + (i % 8) });
64
+ for (let i = 0; i < 20; i++) arr.push({ width: 48 + (i % 16), height: 56 + (i % 10) });
65
+ for (let i = 0; i < 6; i++) arr.push({ width: 128, height: 140 });
66
+ return arr;
67
+ }
68
+
69
+ async function run() {
70
+ const fontDir = path.resolve(process.cwd(), "assets", "fonts");
71
+ let fontFiles = [];
72
+ try {
73
+ const files = fs.readdirSync(fontDir);
74
+ fontFiles = files.filter((f) => /\.(ttf|otf|woff2?)$/i.test(f)).map((f) => path.join(fontDir, f));
75
+ } catch (e) {
76
+ console.warn("No bundled fonts found in assets/fonts — continuing with synthetic samples only");
77
+ }
78
+
79
+ console.log("Found fonts:", fontFiles.map((p) => path.basename(p)));
80
+ const allSamples = [];
81
+
82
+ for (const fontPath of fontFiles) {
83
+ console.log("Sampling font:", path.basename(fontPath));
84
+ const s = await sampleFromFont(fontPath, { maxGlyphs: 200, fontSizePx: 64 });
85
+ console.log(` -> collected ${s.length} samples from ${path.basename(fontPath)}`);
86
+ allSamples.push(...s);
87
+ }
88
+
89
+ const synth = syntheticSamples();
90
+ console.log("Adding", synth.length, "synthetic samples");
91
+ allSamples.push(...synth);
92
+
93
+ if (allSamples.length === 0) {
94
+ console.warn("No samples gathered — returning conservative defaults");
95
+ console.log("Suggested settings: pageSize=2048, padding=1");
96
+ return;
97
+ }
98
+
99
+ const settings = pickAtlasSettingsFromSamples(allSamples, { candidates: [1024, 2048, 4096], paddings: [0, 1, 2, 3] });
100
+ console.log("Tuner result:", settings);
101
+ console.log("");
102
+ console.log("Recommended values to apply to MaxRects packer:");
103
+ console.log(` pageSize: ${settings.pageSize}`);
104
+ console.log(` padding: ${settings.padding}`);
105
+ console.log(`Estimated pages: ${settings.estimatedPages}, wastedRatio: ${settings.wastedRatio.toFixed(3)}`);
106
+ console.log("");
107
+ console.log("If you want me to apply these settings to src/pdf/font/glyph-atlas-maxrects.ts I can do that now.");
108
+ }
109
+
110
+ run().catch((err) => {
111
+ console.error("Error running tuner runner:", err);
112
+ process.exit(1);
113
+ });
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Run glyph atlas tuner (sample fonts + synthetic) and print recommended atlas settings.
3
+ *
4
+ * Usage (from repo root):
5
+ * - With ts-node (recommended):
6
+ * npx ts-node scripts/run-glyph-atlas-tuner.ts
7
+ * - Or via node if you have ts-node registered:
8
+ * node -r ts-node/register scripts/run-glyph-atlas-tuner.ts
9
+ *
10
+ * Notes:
11
+ * - This script imports project modules (TS sources). When running with ts-node,
12
+ * TypeScript files are resolved directly (we import .ts paths here to avoid
13
+ * Node ESM resolving .js which caused ERR_MODULE_NOT_FOUND).
14
+ *
15
+ * What it does:
16
+ * - Loads fonts from ./assets/fonts
17
+ * - For each font samples up to N glyphs (attempts to rasterize glyph masks at fontSizePx)
18
+ * - Adds synthetic samples (small/medium/large)
19
+ * - Runs pickAtlasSettingsFromSamples(...) and prints the chosen settings
20
+ */
21
+
22
+ import fs from "fs";
23
+ import path from "path";
24
+
25
+ // IMPORTANT: import the .ts modules (ts-node resolves .ts imports). This avoids Node ESM looking for .js files.
26
+ import { parseTtfFont } from "../src/pdf/font/ttf-lite.ts";
27
+ import { getGlyphMask, clearGlyphMaskCache } from "../src/pdf/font/glyph-cache.ts";
28
+ import { pickAtlasSettingsFromSamples } from "../src/pdf/font/glyph-atlas-tuner.ts";
29
+
30
+ async function sampleFromFont(fontPath: string, opts: { maxGlyphs?: number; fontSizePx?: number } = {}) {
31
+ const samples: Array<{ width: number; height: number }> = [];
32
+ const maxGlyphs = opts.maxGlyphs ?? 200;
33
+ const fontSizePx = opts.fontSizePx ?? 64;
34
+
35
+ try {
36
+ const metrics = parseTtfFont(fontPath);
37
+ // Try to sample from glyphMetrics map if available
38
+ const glyphCount = metrics.glyphMetrics ? metrics.glyphMetrics.size : Math.max(256, maxGlyphs);
39
+ const limit = Math.min(maxGlyphs, glyphCount);
40
+
41
+ // Prefer to sample glyph IDs present in the metrics map
42
+ if (metrics.glyphMetrics && metrics.glyphMetrics.size > 0) {
43
+ let i = 0;
44
+ for (const [gid] of metrics.glyphMetrics) {
45
+ if (i >= limit) break;
46
+ try {
47
+ const mask = getGlyphMask(metrics as any, gid, fontSizePx, 4);
48
+ if (mask && mask.width > 0 && mask.height > 0) {
49
+ samples.push({ width: mask.width, height: mask.height });
50
+ i++;
51
+ }
52
+ } catch (e) {
53
+ // ignore glyphs that fail during rasterization
54
+ }
55
+ }
56
+ } else {
57
+ // Fallback: try glyph ids 0..limit-1
58
+ for (let gid = 0; gid < limit; gid++) {
59
+ try {
60
+ const mask = getGlyphMask(metrics as any, gid, fontSizePx, 4);
61
+ if (mask && mask.width > 0 && mask.height > 0) {
62
+ samples.push({ width: mask.width, height: mask.height });
63
+ }
64
+ } catch (e) {
65
+ // continue
66
+ }
67
+ }
68
+ }
69
+
70
+ // Clear any packed atlas/cache artifacts between fonts to avoid skew
71
+ clearGlyphMaskCache();
72
+ } catch (err) {
73
+ console.error("Failed to parse font", fontPath, err instanceof Error ? err.message : err);
74
+ }
75
+
76
+ return samples;
77
+ }
78
+
79
+ function syntheticSamples(): Array<{ width: number; height: number }> {
80
+ // Provide a sensible mixture of sizes: small glyphs, punctuation, medium letters, large capitals
81
+ const arr: Array<{ width: number; height: number }> = [];
82
+ // many small
83
+ for (let i = 0; i < 40; i++) arr.push({ width: 8, height: 10 });
84
+ // medium
85
+ for (let i = 0; i < 40; i++) arr.push({ width: 20 + (i % 10), height: 24 + (i % 8) });
86
+ // larger
87
+ for (let i = 0; i < 20; i++) arr.push({ width: 48 + (i % 16), height: 56 + (i % 10) });
88
+ // some very large glyphs (accents, icons)
89
+ for (let i = 0; i < 6; i++) arr.push({ width: 128, height: 140 });
90
+ return arr;
91
+ }
92
+
93
+ async function run() {
94
+ const fontDir = path.resolve(process.cwd(), "assets", "fonts");
95
+ let fontFiles: string[] = [];
96
+ try {
97
+ const files = fs.readdirSync(fontDir);
98
+ fontFiles = files
99
+ .filter((f) => /\.(ttf|otf|woff2?)$/i.test(f))
100
+ .map((f) => path.join(fontDir, f));
101
+ } catch (e) {
102
+ console.warn("No bundled fonts found in assets/fonts — continuing with synthetic samples only");
103
+ }
104
+
105
+ console.log("Found fonts:", fontFiles.map((p) => path.basename(p)));
106
+ const allSamples: Array<{ width: number; height: number }> = [];
107
+
108
+ for (const fontPath of fontFiles) {
109
+ console.log("Sampling font:", path.basename(fontPath));
110
+ const s = await sampleFromFont(fontPath, { maxGlyphs: 200, fontSizePx: 64 });
111
+ console.log(` -> collected ${s.length} samples from ${path.basename(fontPath)}`);
112
+ allSamples.push(...s);
113
+ }
114
+
115
+ // add synthetic
116
+ const synth = syntheticSamples();
117
+ console.log("Adding", synth.length, "synthetic samples");
118
+ allSamples.push(...synth);
119
+
120
+ if (allSamples.length === 0) {
121
+ console.warn("No samples gathered — returning conservative defaults");
122
+ console.log("Suggested settings: pageSize=2048, padding=1");
123
+ return;
124
+ }
125
+
126
+ // Run tuner
127
+ const settings = pickAtlasSettingsFromSamples(allSamples, { candidates: [1024, 2048, 4096], paddings: [0, 1, 2, 3] });
128
+ console.log("Tuner result:", settings);
129
+ console.log("");
130
+ console.log("If you want to apply these settings to the MaxRects packer in-code, the recommended values are:");
131
+ console.log(` pageSize: ${settings.pageSize}`);
132
+ console.log(` padding: ${settings.padding}`);
133
+ console.log(`Estimated pages: ${settings.estimatedPages}, wastedRatio: ${settings.wastedRatio.toFixed(3)}`);
134
+ console.log("");
135
+ console.log("To apply, update the MaxRects packer defaults in src/pdf/font/glyph-atlas-maxrects.ts (constructor or export) or pass these values when constructing the packer.");
136
+ }
137
+
138
+ run().catch((err) => {
139
+ console.error("Error running tuner script:", err);
140
+ process.exit(1);
141
+ });
@@ -0,0 +1,39 @@
1
+ # Top 10 arquivos .ts por numero de linhas (recursivo, com progresso)
2
+ $Path = "." # diretorio inicial
3
+ $Top = 10 # quantidade a exibir
4
+ $Pattern = "*.ts"
5
+ $SkipPattern = '(\\|/)(?:node_modules|dist|\.git|bin|obj|\.venv|\.tox)(\\|/)'
6
+
7
+ Write-Host "Buscando arquivos $Pattern em $Path..." -ForegroundColor Cyan
8
+
9
+ # filtra apenas .ts e ignora pastas grandes
10
+ $files = Get-ChildItem -LiteralPath $Path -Recurse -File -Filter $Pattern -Force |
11
+ Where-Object { $_.FullName -notmatch $SkipPattern }
12
+
13
+ $total = $files.Count
14
+
15
+ $i = 0
16
+ $results = New-Object System.Collections.Generic.List[object]
17
+
18
+ foreach ($f in $files) {
19
+ $i++
20
+ Write-Progress -Activity "Contando linhas..." -Status $f.FullName -PercentComplete (($i / $total) * 100)
21
+ try {
22
+ $lineCount = [int]([System.Linq.Enumerable]::Count([System.IO.File]::ReadLines($f.FullName)))
23
+ $results.Add([pscustomobject]@{
24
+ Lines = $lineCount
25
+ SizeBytes = $f.Length
26
+ Path = $f.FullName
27
+ })
28
+ } catch {
29
+ Write-Warning "Falha ao ler: $($f.FullName) -> $($_.Exception.Message)"
30
+ }
31
+ }
32
+
33
+ Write-Progress -Activity "Contando linhas..." -Completed
34
+ Write-Host "`nTop $Top arquivos $Pattern por numero de linhas:`n" -ForegroundColor Green
35
+
36
+ $results |
37
+ Sort-Object Lines -Descending |
38
+ Select-Object -First $Top |
39
+ Format-Table Lines, SizeBytes, Path -AutoSize
@@ -0,0 +1,37 @@
1
+ #!/bin/bash
2
+
3
+ # Top 10 arquivos .ts por número de linhas (recursivo, com progresso)
4
+ PATH="."
5
+ TOP=10
6
+ PATTERN="*.ts"
7
+ SKIP_PATTERN="(node_modules|dist|\.git|bin|obj|\.venv|\.tox)"
8
+
9
+ echo "🔍 Buscando arquivos $PATTERN em $PATH..."
10
+
11
+ # filtra apenas .ts e ignora pastas grandes
12
+ files=$(find "$PATH" -type f -name "$PATTERN" 2>/dev/null | grep -v -E "$SKIP_PATTERN")
13
+
14
+ total=$(echo "$files" | wc -l)
15
+ if [ "$total" -eq 0 ]; then
16
+ echo "Nenhum arquivo $PATTERN encontrado (verifique filtros)."
17
+ exit 1
18
+ fi
19
+
20
+ i=0
21
+ temp=$(mktemp)
22
+
23
+ echo "$files" | while read -r f; do
24
+ i=$((i+1))
25
+ echo -ne "Contando linhas... $i/$total\r"
26
+ lines=$(wc -l < "$f" 2>/dev/null || echo 0)
27
+ size=$(stat -c%s "$f" 2>/dev/null || echo 0)
28
+ echo "$lines|$size|$f" >> "$temp"
29
+ done
30
+
31
+ echo ""
32
+ echo "📊 Top $TOP arquivos $PATTERN por número de linhas:"
33
+ echo ""
34
+
35
+ sort -nr "$temp" | head -n $TOP | awk -F'|' '{printf "%-10s %-10s %s\n", $1, $2, $3}'
36
+
37
+ rm "$temp"
@@ -0,0 +1,132 @@
1
+ param(
2
+ # Caminho da fonte (TTF/OTF/WOFF/WOFF2)
3
+ [Parameter(Mandatory = $true)]
4
+ [string]$File,
5
+
6
+ # ttx (CLI da FontTools)
7
+ [string]$Ttx = "ttx",
8
+
9
+ # Nome base do arquivo de saída TTX (sem ou com .ttx)
10
+ # O script vai adicionar automaticamente o sufixo com o nome da fonte.
11
+ [string]$OutFile = "font_dump.ttx",
12
+
13
+ # Formato da saída do script
14
+ # xml = só gera TTX XML (default)
15
+ # json = converte o XML inteiro pra JSON
16
+ # fulljson = JSON completo sem compressão
17
+ # name = só tabela name (metadados)
18
+ # cmap = só cmap
19
+ # metrics = só head / hhea / OS/2
20
+ [ValidateSet("xml", "json", "fulljson", "name", "cmap", "metrics")]
21
+ [string]$Format = "xml",
22
+
23
+ # Forçar overwrite
24
+ [switch]$Force
25
+ )
26
+
27
+ ### 1. Resolve paths
28
+ $fullPath = (Resolve-Path $File).Path
29
+
30
+ # Nome da fonte baseado no arquivo (sem extensão)
31
+ $fontBaseName = [System.IO.Path]::GetFileNameWithoutExtension($fullPath)
32
+
33
+ # Se o usuário passou um caminho com diretório em $OutFile, respeita.
34
+ # Caso contrário, usa o diretório do script.
35
+ $outDir = Split-Path -Path $OutFile -Parent
36
+ if ([string]::IsNullOrWhiteSpace($outDir)) {
37
+ $outDir = $PSScriptRoot
38
+ }
39
+
40
+ $outName = [System.IO.Path]::GetFileName($OutFile)
41
+
42
+ # Se não tiver extensão, assume .ttx
43
+ $outBase = [System.IO.Path]::GetFileNameWithoutExtension($outName)
44
+ $outExt = [System.IO.Path]::GetExtension($outName)
45
+ if ([string]::IsNullOrWhiteSpace($outExt)) {
46
+ $outExt = ".ttx"
47
+ }
48
+
49
+ # Monta o nome final com sufixo da fonte
50
+ $finalOutName = "{0}-{1}{2}" -f $outBase, $fontBaseName, $outExt
51
+ $ttxOut = Join-Path $outDir $finalOutName
52
+
53
+ if ((Test-Path $ttxOut) -and (-not $Force)) {
54
+ Write-Output "[ERROR] Output file already exists: $ttxOut"
55
+ Write-Output "Use -Force to overwrite."
56
+ exit 1
57
+ }
58
+
59
+ if ($Force -and (Test-Path $ttxOut)) {
60
+ Remove-Item $ttxOut -Force
61
+ }
62
+
63
+ Write-Output "[INFO] Generating TTX to: $ttxOut"
64
+
65
+ ### 2. Gera o TTX (XML)
66
+ $cmd = "$Ttx -o `"$ttxOut`" `"$fullPath`" 2>&1"
67
+ $output = Invoke-Expression $cmd
68
+
69
+ if (-not (Test-Path $ttxOut)) {
70
+ Write-Output "[ERROR] Failed to generate TTX dump."
71
+ Write-Output $output
72
+ exit 1
73
+ }
74
+
75
+ ### 3. Se o usuário pediu só XML
76
+ if ($Format -eq "xml") {
77
+ Write-Output "[DUMP] $((Resolve-Path $ttxOut).Path)"
78
+ exit 0
79
+ }
80
+
81
+ ### 4. Carrega XML como objeto
82
+ [xml]$xml = Get-Content $ttxOut
83
+
84
+ ### 5. Funções auxiliares
85
+ function Convert-ToJsonCompact($obj) {
86
+ return ($obj | ConvertTo-Json -Depth 20 -Compress)
87
+ }
88
+
89
+ function Convert-ToJsonPretty($obj) {
90
+ return ($obj | ConvertTo-Json -Depth 20)
91
+ }
92
+
93
+ ### 6. Modos especializados
94
+ switch ($Format) {
95
+
96
+ "json" {
97
+ $json = Convert-ToJsonCompact $xml
98
+ Write-Output $json
99
+ exit 0
100
+ }
101
+
102
+ "fulljson" {
103
+ $json = Convert-ToJsonPretty $xml
104
+ Write-Output $json
105
+ exit 0
106
+ }
107
+
108
+ "name" {
109
+ $name = $xml.ttFont.name
110
+ $json = Convert-ToJsonPretty $name
111
+ Write-Output $json
112
+ exit 0
113
+ }
114
+
115
+ "cmap" {
116
+ $cmap = $xml.ttFont.cmap
117
+ $json = Convert-ToJsonPretty $cmap
118
+ Write-Output $json
119
+ exit 0
120
+ }
121
+
122
+ "metrics" {
123
+ $metrics = [ordered]@{
124
+ head = $xml.ttFont.head
125
+ hhea = $xml.ttFont.hhea
126
+ os2 = $xml.ttFont."OS_2"
127
+ }
128
+ $json = Convert-ToJsonPretty $metrics
129
+ Write-Output $json
130
+ exit 0
131
+ }
132
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Browser entrypoint: minimal surface that wires the BrowserEnvironment.
3
+ * Expect callers to provide HTML/CSS strings and optional fontConfig with preloaded ArrayBuffers.
4
+ */
5
+ import { BrowserEnvironment } from "./environment/browser-environment.js";
6
+ import { setGlobalEnvironment } from "./environment/global.js";
7
+ import type { RenderHtmlOptions } from "./html-to-pdf.js";
8
+ import { renderHtmlToPdf } from "./html-to-pdf.js";
9
+
10
+ export async function renderHtmlToPdfBrowser(options: Omit<RenderHtmlOptions, "environment">): Promise<Uint8Array> {
11
+ const environment = new BrowserEnvironment();
12
+ setGlobalEnvironment(environment);
13
+ return renderHtmlToPdf({ ...options, environment });
14
+ }