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.
- package/.eslintrc.json +30 -0
- package/CHANGELOG.md +13 -0
- package/README.md +275 -0
- package/UA_Styles_Chromium.md +93 -0
- package/_ext/woff2_conversion/brotli-decode.d.ts +139 -0
- package/_ext/woff2_conversion/brotli-encode.d.ts +129 -0
- package/_ext/woff2_conversion/brotli-port.d.ts +12 -0
- package/_ext/woff2_conversion/brotli-shared-dictionary.d.ts +25 -0
- package/_ext/woff2_conversion/brotli-types.d.ts +15 -0
- package/_ext/woff2_conversion/woff2-common.d.ts +37 -0
- package/_ext/woff2_conversion/woff2-decode.d.ts +32 -0
- package/_ext/woff2_conversion/woff2-encode.d.ts +31 -0
- package/_ext/woff2_conversion/woff2-output.d.ts +39 -0
- package/_ext/woff2_original_cpp/brotli/brotli.c +1559 -0
- package/_ext/woff2_original_cpp/brotli/brotli.md +116 -0
- package/_ext/woff2_original_cpp/brotli/decode.h +409 -0
- package/_ext/woff2_original_cpp/brotli/encode.h +505 -0
- package/_ext/woff2_original_cpp/brotli/port.h +302 -0
- package/_ext/woff2_original_cpp/brotli/shared_dictionary.h +100 -0
- package/_ext/woff2_original_cpp/brotli/types.h +83 -0
- package/_ext/woff2_original_cpp/cmake/FindBrotliDec.cmake +35 -0
- package/_ext/woff2_original_cpp/cmake/FindBrotliEnc.cmake +35 -0
- package/_ext/woff2_original_cpp/include/woff2/decode.h +36 -0
- package/_ext/woff2_original_cpp/include/woff2/encode.h +43 -0
- package/_ext/woff2_original_cpp/include/woff2/output.h +86 -0
- package/_ext/woff2_original_cpp/src/buffer.h +164 -0
- package/_ext/woff2_original_cpp/src/convert_woff2ttf_fuzzer.cc +13 -0
- package/_ext/woff2_original_cpp/src/convert_woff2ttf_fuzzer_new_entry.cc +12 -0
- package/_ext/woff2_original_cpp/src/file.h +30 -0
- package/_ext/woff2_original_cpp/src/font.cc +400 -0
- package/_ext/woff2_original_cpp/src/font.h +105 -0
- package/_ext/woff2_original_cpp/src/glyph.cc +383 -0
- package/_ext/woff2_original_cpp/src/glyph.h +71 -0
- package/_ext/woff2_original_cpp/src/normalize.cc +314 -0
- package/_ext/woff2_original_cpp/src/normalize.h +39 -0
- package/_ext/woff2_original_cpp/src/port.h +66 -0
- package/_ext/woff2_original_cpp/src/round.h +27 -0
- package/_ext/woff2_original_cpp/src/store_bytes.h +55 -0
- package/_ext/woff2_original_cpp/src/table_tags.cc +82 -0
- package/_ext/woff2_original_cpp/src/table_tags.h +30 -0
- package/_ext/woff2_original_cpp/src/transform.cc +430 -0
- package/_ext/woff2_original_cpp/src/transform.h +26 -0
- package/_ext/woff2_original_cpp/src/variable_length.cc +129 -0
- package/_ext/woff2_original_cpp/src/variable_length.h +30 -0
- package/_ext/woff2_original_cpp/src/woff2_common.cc +50 -0
- package/_ext/woff2_original_cpp/src/woff2_common.h +64 -0
- package/_ext/woff2_original_cpp/src/woff2_compress.cc +43 -0
- package/_ext/woff2_original_cpp/src/woff2_dec.cc +1398 -0
- package/_ext/woff2_original_cpp/src/woff2_decompress.cc +41 -0
- package/_ext/woff2_original_cpp/src/woff2_enc.cc +458 -0
- package/_ext/woff2_original_cpp/src/woff2_info.cc +142 -0
- package/_ext/woff2_original_cpp/src/woff2_out.cc +63 -0
- package/assets/fonts/ttf/arimo/Arimo-Bold.ttf +0 -0
- package/assets/fonts/ttf/arimo/Arimo-BoldItalic.ttf +0 -0
- package/assets/fonts/ttf/arimo/Arimo-Italic.ttf +0 -0
- package/assets/fonts/ttf/arimo/Arimo-Regular.ttf +0 -0
- package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Black.ttf +0 -0
- package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Bold.ttf +0 -0
- package/assets/fonts/ttf/cinzeldecorative/CinzelDecorative-Regular.ttf +0 -0
- package/assets/fonts/ttf/dejavu/DejaVuSans.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Bold.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Light.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Medium.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-Regular.ttf +0 -0
- package/assets/fonts/ttf/firecode/FiraCode-SemiBold.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Bold.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Light.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Medium.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-Regular.ttf +0 -0
- package/assets/fonts/ttf/notoemoji/NotoEmoji-SemiBold.ttf +0 -0
- package/assets/fonts/ttf/notosans/NotoSans-Regular.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-Bold.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-BoldItalic.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-Italic.ttf +0 -0
- package/assets/fonts/ttf/roboto/Roboto-Regular.ttf +0 -0
- package/assets/fonts/ttf/stixtwomath/STIXTwoMath-Regular.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-Bold.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-BoldItalic.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-Italic.ttf +0 -0
- package/assets/fonts/ttf/tinos/Tinos-Regular.ttf +0 -0
- package/assets/fonts/woff/lato/lato-latin-400-italic.woff +0 -0
- package/assets/fonts/woff/lato/lato-latin-400-normal.woff +0 -0
- package/assets/fonts/woff/lato/lato-latin-700-italic.woff +0 -0
- package/assets/fonts/woff/lato/lato-latin-700-normal.woff +0 -0
- package/assets/fonts/woff2/caveat/Caveat-Bold.woff2 +0 -0
- package/assets/fonts/woff2/caveat/Caveat-Regular.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-400-italic.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-400-normal.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-700-italic.woff2 +0 -0
- package/assets/fonts/woff2/lato/lato-latin-700-normal.woff2 +0 -0
- package/docs/AGENTS.md +288 -0
- package/docs/BACKGROUND-REPEAT-IMPLEMENTATION.md +127 -0
- package/docs/BACKGROUND-REPEAT-REFERENCE.md +127 -0
- package/docs/BACKGROUND-REPEAT-SPACE-ROUND.md +164 -0
- package/docs/css-properties-support.md +256 -0
- package/docs/src_modules_table.md +172 -0
- package/docs/text-overlap-fix.md +85 -0
- package/docs/text-overlap-investigation.md +27 -0
- package/eslint.config.js +36 -0
- package/glyph_measure.htm +1458 -0
- package/package.json +50 -0
- package/playground/browser-entry.ts +2 -0
- package/playground/exports/background-text-debug.pdf +0 -0
- package/playground/public/app.js +875 -0
- package/playground/public/assets/1.webp +0 -0
- package/playground/public/examples/accents-test.html +24 -0
- package/playground/public/examples/advanced-selectors-demo.html +118 -0
- package/playground/public/examples/background-advanced-showcase.html +82 -0
- package/playground/public/examples/background-clip-text.html +36 -0
- package/playground/public/examples/background-origin-showcase.html +137 -0
- package/playground/public/examples/background-position-showcase.html +83 -0
- package/playground/public/examples/background-repeat-showcase.html +83 -0
- package/playground/public/examples/background-repeat-space-round.html +348 -0
- package/playground/public/examples/background-size-showcase.html +82 -0
- package/playground/public/examples/background-text-debug.html +18 -0
- package/playground/public/examples/baseline-test.html +24 -0
- package/playground/public/examples/bold-showcase.html +150 -0
- package/playground/public/examples/bold-strike-example.html +12 -0
- package/playground/public/examples/border-collapse-test.html +23 -0
- package/playground/public/examples/centered-shadow-div.html +72 -0
- package/playground/public/examples/css-variables.html +50 -0
- package/playground/public/examples/debug-accents.html +11 -0
- package/playground/public/examples/debug-text-overlap.html +46 -0
- package/playground/public/examples/flex-gap-column.html +130 -0
- package/playground/public/examples/flex-gap-row.html +137 -0
- package/playground/public/examples/flex-padding-test.html +29 -0
- package/playground/public/examples/flexbox-text-test.html +193 -0
- package/playground/public/examples/fonts-demo.html +126 -0
- package/playground/public/examples/footer-example.html +4 -0
- package/playground/public/examples/gradient-text.html +54 -0
- package/playground/public/examples/grid-gap-demo.html +156 -0
- package/playground/public/examples/header-example.html +4 -0
- package/playground/public/examples/header-footer-example.html +27 -0
- package/playground/public/examples/image-showcase.html +33 -0
- package/playground/public/examples/justify-text.html +22 -0
- package/playground/public/examples/linear-gradient-example.html +38 -0
- package/playground/public/examples/lorem-span.html +14 -0
- package/playground/public/examples/margin-block-showcase.html +21 -0
- package/playground/public/examples/margin-inline-showcase.html +21 -0
- package/playground/public/examples/monthly-summary.html +95 -0
- package/playground/public/examples/multi-page-lorem.html +190 -0
- package/playground/public/examples/opacity-debug.html +39 -0
- package/playground/public/examples/opacity-example.html +70 -0
- package/playground/public/examples/png-image-example.html +13 -0
- package/playground/public/examples/red-rectangle.html +18 -0
- package/playground/public/examples/repro.html +24 -0
- package/playground/public/examples/rounded-borders-test.html +24 -0
- package/playground/public/examples/simple-list.html +89 -0
- package/playground/public/examples/simple-svg.html +37 -0
- package/playground/public/examples/simple-table.html +52 -0
- package/playground/public/examples/skew-div.html +138 -0
- package/playground/public/examples/skew-text.html +21 -0
- package/playground/public/examples/starter-report.css +51 -0
- package/playground/public/examples/starter-report.html +23 -0
- package/playground/public/examples/svg-aspect-ratio-showcase.html +116 -0
- package/playground/public/examples/svg-gradients-linear.html +28 -0
- package/playground/public/examples/svg-gradients-radial.html +29 -0
- package/playground/public/examples/svg-gradients-showcase.html +66 -0
- package/playground/public/examples/svg-image-path-test.html +43 -0
- package/playground/public/examples/svg-images-clipping.html +27 -0
- package/playground/public/examples/svg-path-gallery.html +118 -0
- package/playground/public/examples/svg-radial-transform-demo.html +78 -0
- package/playground/public/examples/svg-transform-stack.html +103 -0
- package/playground/public/examples/svg-transforms-demo.html +127 -0
- package/playground/public/examples/table-merge-test.html +34 -0
- package/playground/public/examples/text-decoration-showcase.html +138 -0
- package/playground/public/examples/text-indent-showcase.html +137 -0
- package/playground/public/examples/text-shadow-example.html +29 -0
- package/playground/public/examples/very-complex-css.html +293 -0
- package/playground/public/examples/webp-example.html +13 -0
- package/playground/public/examples/z-index-demo.html +93 -0
- package/playground/public/examples.json +240 -0
- package/playground/public/images/dice.png +0 -0
- package/playground/public/images/duck.jpg +0 -0
- package/playground/public/index.html +149 -0
- package/playground/public/mode.js +1 -0
- package/playground/public/styles.css +382 -0
- package/playground/public/tmp-h2-debug.html +33 -0
- package/playground/public/tmp-italic-debug.html +32 -0
- package/playground/public/vendor/codemirror/codemirror.min.css +1 -0
- package/playground/public/vendor/codemirror/codemirror.min.js +1 -0
- package/playground/public/vendor/codemirror/css.min.js +1 -0
- package/playground/public/vendor/codemirror/darcula.min.css +1 -0
- package/playground/public/vendor/codemirror/htmlmixed.min.js +1 -0
- package/playground/public/vendor/codemirror/javascript.min.js +1 -0
- package/playground/public/vendor/codemirror/xml.min.js +1 -0
- package/playground/public/vendor/pagyra-playground-browser.js +165966 -0
- package/playground/public/vendor/pagyra-playground-browser.js.map +7 -0
- package/playground/server.d.ts +1 -0
- package/playground/server.js +68 -0
- package/playground/server.ts +128 -0
- package/scripts/browser-build.ts +101 -0
- package/scripts/build-browser-bundle.ts +52 -0
- package/scripts/glyph-comparison/simulate.ts +744 -0
- package/scripts/playground-browser-server.ts +57 -0
- package/scripts/probe-roboto.ts +6 -0
- package/scripts/render-playground-example.ts +121 -0
- package/scripts/run-glyph-atlas-tuner-runner.mjs +113 -0
- package/scripts/run-glyph-atlas-tuner.ts +141 -0
- package/scripts/top-ts-files.ps1 +39 -0
- package/scripts/top-ts-files.sh +37 -0
- package/scripts/woff2_info.ps1 +132 -0
- package/src/browser-entry.ts +14 -0
- package/src/compression/adler32.ts +45 -0
- package/src/compression/brotli/brotli.ts +463 -0
- package/src/compression/brotli/index.ts +15 -0
- package/src/compression/brotli/transform.ts +184 -0
- package/src/compression/brotli/types.ts +58 -0
- package/src/compression/brotli/utils.ts +157 -0
- package/src/compression/brotli/vendor/bit_reader.js +124 -0
- package/src/compression/brotli/vendor/context.js +250 -0
- package/src/compression/brotli/vendor/decode.d.ts +2 -0
- package/src/compression/brotli/vendor/decode.js +938 -0
- package/src/compression/brotli/vendor/dictionary-data.js +9469 -0
- package/src/compression/brotli/vendor/dictionary.js +36 -0
- package/src/compression/brotli/vendor/huffman.js +123 -0
- package/src/compression/brotli/vendor/package.json +3 -0
- package/src/compression/brotli/vendor/prefix.js +60 -0
- package/src/compression/brotli/vendor/streams.js +31 -0
- package/src/compression/brotli/vendor/transform.js +247 -0
- package/src/compression/brotli/vendor-decode.d.ts +4 -0
- package/src/compression/brotli/woff2-glyf-transform.ts +623 -0
- package/src/compression/decompress.ts +16 -0
- package/src/compression/deflate.ts +295 -0
- package/src/compression/index.ts +4 -0
- package/src/compression/types.ts +26 -0
- package/src/compression/utils.ts +107 -0
- package/src/core.ts +18 -0
- package/src/css/apply-declarations.ts +86 -0
- package/src/css/background-types.ts +65 -0
- package/src/css/browser-defaults.ts +16 -0
- package/src/css/clip-path-types.ts +13 -0
- package/src/css/compute-style.ts +494 -0
- package/src/css/css-unit-resolver.ts +65 -0
- package/src/css/custom-properties.ts +215 -0
- package/src/css/enums.ts +127 -0
- package/src/css/font-face-parser.ts +233 -0
- package/src/css/font-weight.ts +65 -0
- package/src/css/inline-style-parser.ts +27 -0
- package/src/css/layout-property-resolver.ts +75 -0
- package/src/css/length.ts +141 -0
- package/src/css/line-height.ts +96 -0
- package/src/css/named-colors.ts +150 -0
- package/src/css/parsers/background-parser-extended.ts +111 -0
- package/src/css/parsers/background-parser.ts +456 -0
- package/src/css/parsers/border-block-parser.ts +26 -0
- package/src/css/parsers/border-inline-parser.ts +26 -0
- package/src/css/parsers/border-parser-extended.ts +256 -0
- package/src/css/parsers/border-parser.ts +175 -0
- package/src/css/parsers/box-shadow-parser.ts +106 -0
- package/src/css/parsers/clip-path-parser.ts +92 -0
- package/src/css/parsers/color-parser.ts +14 -0
- package/src/css/parsers/dimension-parser.ts +117 -0
- package/src/css/parsers/display-flex-parser.ts +59 -0
- package/src/css/parsers/flex-parser.ts +144 -0
- package/src/css/parsers/font-parser.ts +40 -0
- package/src/css/parsers/gradient-parser.ts +366 -0
- package/src/css/parsers/grid-parser-extended.ts +55 -0
- package/src/css/parsers/grid-parser.ts +218 -0
- package/src/css/parsers/length-parser.ts +95 -0
- package/src/css/parsers/list-style-parser.ts +39 -0
- package/src/css/parsers/margin-block-parser.ts +12 -0
- package/src/css/parsers/margin-inline-parser.ts +12 -0
- package/src/css/parsers/margin-parser.ts +30 -0
- package/src/css/parsers/opacity-parser.ts +32 -0
- package/src/css/parsers/overflow-wrap-parser.ts +38 -0
- package/src/css/parsers/padding-block-parser.ts +12 -0
- package/src/css/parsers/padding-inline-parser.ts +12 -0
- package/src/css/parsers/padding-parser.ts +30 -0
- package/src/css/parsers/position-parser.ts +75 -0
- package/src/css/parsers/register-parsers.ts +302 -0
- package/src/css/parsers/registry.ts +18 -0
- package/src/css/parsers/text-parser-extended.ts +144 -0
- package/src/css/parsers/text-parser.ts +25 -0
- package/src/css/parsers/text-shadow-parser.ts +94 -0
- package/src/css/properties/box-model.ts +82 -0
- package/src/css/properties/flexbox.ts +44 -0
- package/src/css/properties/gap.ts +14 -0
- package/src/css/properties/grid.ts +94 -0
- package/src/css/properties/layout.ts +59 -0
- package/src/css/properties/misc.ts +44 -0
- package/src/css/properties/typography.ts +71 -0
- package/src/css/properties/visual.ts +68 -0
- package/src/css/selectors/matcher.ts +219 -0
- package/src/css/selectors/parser.ts +163 -0
- package/src/css/selectors/simple-key.ts +31 -0
- package/src/css/selectors/specificity.ts +41 -0
- package/src/css/selectors/types.ts +31 -0
- package/src/css/shorthands/border-shorthand.ts +68 -0
- package/src/css/shorthands/box-shorthand.ts +33 -0
- package/src/css/style-inheritance.ts +50 -0
- package/src/css/style.ts +402 -0
- package/src/css/ua-defaults/base-defaults.ts +266 -0
- package/src/css/ua-defaults/browser-defaults.ts +134 -0
- package/src/css/ua-defaults/element-defaults.ts +374 -0
- package/src/css/ua-defaults/types.ts +43 -0
- package/src/css/unit-conversion.ts +24 -0
- package/src/css/utils.ts +108 -0
- package/src/css/viewport.ts +17 -0
- package/src/debug/audit.ts +20 -0
- package/src/debug/ids.ts +13 -0
- package/src/debug/log.js +28 -0
- package/src/debug/log.ts +52 -0
- package/src/debug/tree.ts +57 -0
- package/src/dom/node.ts +133 -0
- package/src/environment/browser-environment.ts +78 -0
- package/src/environment/environment.ts +35 -0
- package/src/environment/global.ts +13 -0
- package/src/environment/node-environment.browser.ts +28 -0
- package/src/environment/node-environment.ts +64 -0
- package/src/fonts/detector.ts +28 -0
- package/src/fonts/engines/ttf-engine.ts +28 -0
- package/src/fonts/engines/woff-engine.ts +38 -0
- package/src/fonts/engines/woff2-engine.ts +41 -0
- package/src/fonts/extractors/metrics-extractor.ts +362 -0
- package/src/fonts/font-registry-resolver.ts +132 -0
- package/src/fonts/index.ts +3 -0
- package/src/fonts/orchestrator.ts +92 -0
- package/src/fonts/parsers/base-parser.ts +23 -0
- package/src/fonts/types.ts +85 -0
- package/src/fonts/utils/ttf-reconstructor.ts +120 -0
- package/src/fonts/woff/decoder.ts +105 -0
- package/src/fonts/woff2/buffer.ts +106 -0
- package/src/fonts/woff2/decoder.ts +981 -0
- package/src/geometry/box.ts +48 -0
- package/src/geometry/matrix.ts +59 -0
- package/src/html/css/parse-css.ts +85 -0
- package/src/html/dom-converter.ts +433 -0
- package/src/html/image-converter.ts +200 -0
- package/src/html-to-pdf.ts +410 -0
- package/src/image/base-decoder.ts +149 -0
- package/src/image/image-service.ts +188 -0
- package/src/image/jpeg-decoder.ts +73 -0
- package/src/image/png-decoder.ts +550 -0
- package/src/image/types.ts +20 -0
- package/src/image/webp-decoder.ts +242 -0
- package/src/image/webp-huffman.ts +218 -0
- package/src/image/webp-riff-parser.ts +54 -0
- package/src/image/webp-vp8l-decoder.ts +199 -0
- package/src/index.ts +35 -0
- package/src/layout/context/float-context.ts +62 -0
- package/src/layout/context/layout-environment.ts +29 -0
- package/src/layout/debug.ts +18 -0
- package/src/layout/inline/bounding-box-calculator.ts +132 -0
- package/src/layout/inline/font-baseline-calculator.ts +76 -0
- package/src/layout/inline/inline-utils.ts +94 -0
- package/src/layout/inline/layout.ts +285 -0
- package/src/layout/inline/line_breaker.ts +109 -0
- package/src/layout/inline/measurement.ts +144 -0
- package/src/layout/inline/run-placer.ts +139 -0
- package/src/layout/inline/text-alignment.ts +70 -0
- package/src/layout/inline/tokenizer.ts +195 -0
- package/src/layout/inline/types.ts +76 -0
- package/src/layout/pipeline/context-factory.ts +16 -0
- package/src/layout/pipeline/default-engine.ts +24 -0
- package/src/layout/pipeline/engine.ts +59 -0
- package/src/layout/pipeline/layout-tree.ts +13 -0
- package/src/layout/pipeline/out-of-flow-manager.ts +73 -0
- package/src/layout/pipeline/strategy.ts +12 -0
- package/src/layout/pipeline/text-metrics-initializer.ts +13 -0
- package/src/layout/strategies/block.ts +236 -0
- package/src/layout/strategies/display-none.ts +14 -0
- package/src/layout/strategies/fallback.ts +15 -0
- package/src/layout/strategies/flex.ts +477 -0
- package/src/layout/strategies/fragmentation.ts +17 -0
- package/src/layout/strategies/grid.ts +247 -0
- package/src/layout/strategies/image.ts +342 -0
- package/src/layout/strategies/inline.ts +128 -0
- package/src/layout/strategies/table.ts +595 -0
- package/src/layout/table/cell_layout.ts +31 -0
- package/src/layout/table/diagnostics.ts +19 -0
- package/src/layout/text-run.ts +42 -0
- package/src/layout/utils/content-measurer.ts +117 -0
- package/src/layout/utils/display-utils.ts +24 -0
- package/src/layout/utils/floats.ts +98 -0
- package/src/layout/utils/gap-calculator.ts +167 -0
- package/src/layout/utils/inline-formatter.ts +31 -0
- package/src/layout/utils/inline-formatting.ts +9 -0
- package/src/layout/utils/margin.ts +140 -0
- package/src/layout/utils/node-math.ts +237 -0
- package/src/layout/utils/overflow.ts +14 -0
- package/src/layout/utils/sizing.ts +12 -0
- package/src/layout/utils/text-metrics.ts +361 -0
- package/src/logging/debug.ts +58 -0
- package/src/pdf/font/base14/widths-courier-bold.ts +159 -0
- package/src/pdf/font/base14/widths-courier.ts +159 -0
- package/src/pdf/font/base14/widths-helvetica-bold.ts +158 -0
- package/src/pdf/font/base14/widths-helvetica.ts +158 -0
- package/src/pdf/font/base14/widths-times-bold.ts +158 -0
- package/src/pdf/font/base14/widths-times-roman.ts +158 -0
- package/src/pdf/font/base14/widths-types.ts +25 -0
- package/src/pdf/font/base14-widths.ts +32 -0
- package/src/pdf/font/blur.ts +81 -0
- package/src/pdf/font/builtin-fonts.browser.ts +262 -0
- package/src/pdf/font/builtin-fonts.ts +126 -0
- package/src/pdf/font/composite-glyph-parser.ts +242 -0
- package/src/pdf/font/embedder.ts +395 -0
- package/src/pdf/font/font-config.ts +190 -0
- package/src/pdf/font/font-registry.ts +263 -0
- package/src/pdf/font/font-subset.ts +258 -0
- package/src/pdf/font/glyph-atlas-maxrects.ts +305 -0
- package/src/pdf/font/glyph-atlas-tuner.ts +98 -0
- package/src/pdf/font/glyph-atlas.ts +226 -0
- package/src/pdf/font/glyph-cache.ts +127 -0
- package/src/pdf/font/loca-reader.ts +109 -0
- package/src/pdf/font/managers/font-resource-manager.ts +73 -0
- package/src/pdf/font/managers/subset-resource-manager.ts +164 -0
- package/src/pdf/font/rasterizer.ts +270 -0
- package/src/pdf/font/resolvers/base-font-mapper.ts +77 -0
- package/src/pdf/font/resolvers/family-resolver.ts +33 -0
- package/src/pdf/font/resolvers/weight-style-applicator.ts +63 -0
- package/src/pdf/font/simple-glyph-parser.ts +289 -0
- package/src/pdf/font/to-unicode.ts +109 -0
- package/src/pdf/font/transformation-matrix.ts +136 -0
- package/src/pdf/font/ttf-cmap.ts +180 -0
- package/src/pdf/font/ttf-global-metrics.ts +58 -0
- package/src/pdf/font/ttf-glyf.ts +125 -0
- package/src/pdf/font/ttf-glyph-metrics.ts +43 -0
- package/src/pdf/font/ttf-lite.ts +269 -0
- package/src/pdf/font/ttf-table-parser.ts +132 -0
- package/src/pdf/font/ttf-table-provider.ts +61 -0
- package/src/pdf/font/widths.ts +79 -0
- package/src/pdf/font-subset/font-registry.ts +127 -0
- package/src/pdf/header-footer-layout.ts +153 -0
- package/src/pdf/header-footer-painter.ts +209 -0
- package/src/pdf/header-footer-renderer.ts +357 -0
- package/src/pdf/header-footer-tokens.ts +55 -0
- package/src/pdf/header-footer.ts +25 -0
- package/src/pdf/layout-tree-builder.ts +261 -0
- package/src/pdf/page-painter.ts +241 -0
- package/src/pdf/pagination.ts +155 -0
- package/src/pdf/primitives/pdf-builder.ts +378 -0
- package/src/pdf/primitives/pdf-bytes.ts +40 -0
- package/src/pdf/primitives/pdf-document.ts +108 -0
- package/src/pdf/primitives/pdf-reference-manager.ts +47 -0
- package/src/pdf/primitives/pdf-resource-registries.ts +255 -0
- package/src/pdf/primitives/pdf-serializers.ts +194 -0
- package/src/pdf/primitives/pdf-types.ts +73 -0
- package/src/pdf/render.ts +210 -0
- package/src/pdf/renderer/box-painter.ts +236 -0
- package/src/pdf/renderer/page-paint.ts +102 -0
- package/src/pdf/renderer/paint-box-shadows.ts +218 -0
- package/src/pdf/renderer/radius.ts +58 -0
- package/src/pdf/renderers/graphics-state-manager.ts +40 -0
- package/src/pdf/renderers/image-renderer.ts +127 -0
- package/src/pdf/renderers/radius-utils.ts +80 -0
- package/src/pdf/renderers/rectangle-renderer.ts +129 -0
- package/src/pdf/renderers/rounded-rect-path.ts +120 -0
- package/src/pdf/renderers/shape-renderer.ts +563 -0
- package/src/pdf/renderers/shape-utils.ts +194 -0
- package/src/pdf/renderers/text-decoration-renderer.ts +313 -0
- package/src/pdf/renderers/text-encoder.ts +41 -0
- package/src/pdf/renderers/text-font-resolver.ts +75 -0
- package/src/pdf/renderers/text-renderer-utils.ts +28 -0
- package/src/pdf/renderers/text-renderer.ts +391 -0
- package/src/pdf/renderers/text-shadow-renderer.ts +300 -0
- package/src/pdf/shading/gradient-service.ts +525 -0
- package/src/pdf/shading/index.ts +1 -0
- package/src/pdf/stacking/build-stacking-contexts.ts +93 -0
- package/src/pdf/stacking/resolve-paint-order.ts +157 -0
- package/src/pdf/stacking/types.ts +40 -0
- package/src/pdf/svg/aspect-ratio.ts +81 -0
- package/src/pdf/svg/coordinate-mapper.ts +81 -0
- package/src/pdf/svg/geometry-builder.ts +45 -0
- package/src/pdf/svg/render-svg.ts +296 -0
- package/src/pdf/svg/shape-renderer.ts +463 -0
- package/src/pdf/svg/style-computer.ts +246 -0
- package/src/pdf/transform-adapter.ts +26 -0
- package/src/pdf/types.ts +377 -0
- package/src/pdf/utils/background-layer-resolver.ts +439 -0
- package/src/pdf/utils/background-tiles.ts +192 -0
- package/src/pdf/utils/border-dashes.ts +109 -0
- package/src/pdf/utils/border-radius-utils.ts +86 -0
- package/src/pdf/utils/box-dimensions-utils.ts +47 -0
- package/src/pdf/utils/clip-path-resolver.ts +50 -0
- package/src/pdf/utils/clipping-path-builder.ts +190 -0
- package/src/pdf/utils/color-utils.ts +102 -0
- package/src/pdf/utils/coordinate-transformer.ts +30 -0
- package/src/pdf/utils/drop-shadow-raster.ts +233 -0
- package/src/pdf/utils/encoding.ts +98 -0
- package/src/pdf/utils/glyph-atlas-registrar.ts +13 -0
- package/src/pdf/utils/glyph-run-renderer.ts +129 -0
- package/src/pdf/utils/image-command-partitioner.ts +28 -0
- package/src/pdf/utils/image-matrix-builder.ts +31 -0
- package/src/pdf/utils/image-utils.ts +26 -0
- package/src/pdf/utils/list-utils.ts +194 -0
- package/src/pdf/utils/node-text-run-factory.ts +202 -0
- package/src/pdf/utils/page-resource-registrar.ts +46 -0
- package/src/pdf/utils/result-combiner.ts +102 -0
- package/src/pdf/utils/shadow-utils.ts +127 -0
- package/src/pdf/utils/text-alignment-resolver.ts +76 -0
- package/src/pdf/utils/text-decoration-utils.ts +64 -0
- package/src/pdf/utils/text-layout-adjuster.ts +185 -0
- package/src/pdf/utils/text-utils.ts +193 -0
- package/src/pdf/utils/transform-scope-manager.ts +69 -0
- package/src/render/offset.ts +170 -0
- package/src/shim/empty.ts +2 -0
- package/src/shim/fs-empty.ts +5 -0
- package/src/shim/url-empty.ts +7 -0
- package/src/shim/zlib-empty.ts +9 -0
- package/src/style/shorthands/index.ts +19 -0
- package/src/style/ua/defaults.ts +69 -0
- package/src/svg/index.ts +4 -0
- package/src/svg/parser-registry.ts +71 -0
- package/src/svg/parser.ts +486 -0
- package/src/svg/path-data.ts +515 -0
- package/src/svg/types.ts +194 -0
- package/src/text/line-breaker.ts +321 -0
- package/src/text/text-transform.ts +43 -0
- package/src/text/text.ts +33 -0
- package/src/transform/css-parser.ts +95 -0
- package/src/types/fonts.ts +62 -0
- package/src/types/public.ts +19 -0
- package/src/units/page-utils.ts +58 -0
- package/src/units/units.ts +50 -0
- package/src/utils/base64.ts +24 -0
- package/test-output.txt +79 -0
- package/tests/css/background-parser.spec.ts +14 -0
- package/tests/css/clip-path-parser.spec.ts +66 -0
- package/tests/environment/path-resolution.spec.ts +104 -0
- package/tests/helpers/ai-layout-diagnostics.ts +141 -0
- package/tests/helpers/render-utils.ts +52 -0
- package/tests/helpers/text-geometry.ts +56 -0
- package/tests/layout/custom-properties.test.ts +38 -0
- package/tests/layout/gap-calculator.spec.ts +196 -0
- package/tests/layout/inline-background-alignment.spec.ts +93 -0
- package/tests/layout/inline-fragments.spec.ts +26 -0
- package/tests/layout/run-placer-baseline.spec.ts +108 -0
- package/tests/pdf/alignments.spec.ts +26 -0
- package/tests/pdf/background-clip.spec.ts +57 -0
- package/tests/pdf/background-repeat-space-round.spec.ts +35 -0
- package/tests/pdf/background-repeat.spec.ts +137 -0
- package/tests/pdf/border-radius.spec.ts +151 -0
- package/tests/pdf/clip-path.spec.ts +92 -0
- package/tests/pdf/radial-gradient.spec.ts +50 -0
- package/tests/pdf/svg-stroke-dash.spec.ts +81 -0
- package/tests/pdf/text-transform-matrix.spec.ts +43 -0
- package/tsconfig.json +17 -0
- package/types/fonts.js +10 -0
- package/vitest.config.ts +9 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { log } from "../logging/debug.js";
|
|
2
|
+
|
|
3
|
+
export function auditRuns(lineRuns: { text: string, face: string }[]) {
|
|
4
|
+
const recon = lineRuns.map(r => r.text).join("");
|
|
5
|
+
const isolates = lineRuns
|
|
6
|
+
.map((r, i) => ({ i, r }))
|
|
7
|
+
.filter(x => [...x.r.text].length === 1 && /[^\u0000-\u007f]/.test(x.r.text));
|
|
8
|
+
const switches = lineRuns.reduce((acc, r, i, arr) => i > 0 && arr[i - 1].face !== r.face ? acc + 1 : acc, 0);
|
|
9
|
+
|
|
10
|
+
log("layout", "info", "Line audit", {
|
|
11
|
+
recon: recon.length > 80 ? recon.slice(0, 77) + "..." : recon,
|
|
12
|
+
isolates: isolates.map(x => ({
|
|
13
|
+
idx: x.i,
|
|
14
|
+
ch: x.r.text,
|
|
15
|
+
cp: x.r.text.codePointAt(0)!.toString(16),
|
|
16
|
+
face: x.r.face
|
|
17
|
+
})),
|
|
18
|
+
switches
|
|
19
|
+
});
|
|
20
|
+
}
|
package/src/debug/ids.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
let seq = 1;
|
|
2
|
+
export type UID = number;
|
|
3
|
+
export function newId(): UID { return seq++; }
|
|
4
|
+
|
|
5
|
+
export const DomIds = new WeakMap<object, UID>();
|
|
6
|
+
export const RenderIds = new WeakMap<object, UID>();
|
|
7
|
+
export const LayoutIds = new WeakMap<object, UID>();
|
|
8
|
+
|
|
9
|
+
export function ensureId<T extends object>(map: WeakMap<object, UID>, node: T): UID {
|
|
10
|
+
let id = map.get(node);
|
|
11
|
+
if (!id) { id = newId(); map.set(node, id); }
|
|
12
|
+
return id;
|
|
13
|
+
}
|
package/src/debug/log.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configureDebug = configureDebug;
|
|
4
|
+
exports.log = log;
|
|
5
|
+
exports.preview = preview;
|
|
6
|
+
var CURRENT_LEVEL = "INFO";
|
|
7
|
+
var ENABLED = new Set();
|
|
8
|
+
function configureDebug(level, cats) {
|
|
9
|
+
if (cats === void 0) { cats = []; }
|
|
10
|
+
CURRENT_LEVEL = level;
|
|
11
|
+
ENABLED = new Set(cats);
|
|
12
|
+
}
|
|
13
|
+
var order = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"];
|
|
14
|
+
function allowed(level, cat) {
|
|
15
|
+
return order.indexOf(level) <= order.indexOf(CURRENT_LEVEL) && (ENABLED.size === 0 || ENABLED.has(cat));
|
|
16
|
+
}
|
|
17
|
+
function log(cat, level, msg, extra) {
|
|
18
|
+
if (!allowed(level, cat))
|
|
19
|
+
return;
|
|
20
|
+
var prefix = "[".concat(cat, "] ").concat(level);
|
|
21
|
+
extra ? console.log(prefix, msg, extra) : console.log(prefix, msg);
|
|
22
|
+
}
|
|
23
|
+
function preview(s, n) {
|
|
24
|
+
if (n === void 0) { n = 60; }
|
|
25
|
+
if (s == null)
|
|
26
|
+
return s;
|
|
27
|
+
return s.length > n ? s.slice(0, n - 3) + "..." : s;
|
|
28
|
+
}
|
package/src/debug/log.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { configureDebug as configureNewDebug, log as newLog, type LogLevel as NewLogLevel } from "../logging/debug.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use src/logging/debug.ts instead. This shim forwards to the new logger.
|
|
5
|
+
*/
|
|
6
|
+
export type LogLevel = "ERROR" | "WARN" | "INFO" | "DEBUG" | "TRACE";
|
|
7
|
+
|
|
8
|
+
export type LogCat = "PARSE" | "STYLE" | "LAYOUT" | "RENDER_TREE" | "PAINT" | "ENCODING" | "FONT" | "SHADING" | "PDF" | "PAINT_TRACE";
|
|
9
|
+
|
|
10
|
+
const LEVEL_MAP: Record<LogLevel, NewLogLevel> = {
|
|
11
|
+
ERROR: "error",
|
|
12
|
+
WARN: "warn",
|
|
13
|
+
INFO: "info",
|
|
14
|
+
DEBUG: "debug",
|
|
15
|
+
TRACE: "trace",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
let warned = false;
|
|
19
|
+
function warnDeprecated(): void {
|
|
20
|
+
if (!warned) {
|
|
21
|
+
console.warn("[pagyra] src/debug/log.ts is deprecated; import from src/logging/debug.ts instead.");
|
|
22
|
+
warned = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeCategory(cat: LogCat): string {
|
|
27
|
+
switch (cat) {
|
|
28
|
+
case "RENDER_TREE":
|
|
29
|
+
return "layout";
|
|
30
|
+
case "PAINT_TRACE":
|
|
31
|
+
case "SHADING":
|
|
32
|
+
return "paint";
|
|
33
|
+
default:
|
|
34
|
+
return cat.toLowerCase();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function configureDebug(level: LogLevel, cats: LogCat[] = []): void {
|
|
39
|
+
warnDeprecated();
|
|
40
|
+
const normalizedCats = cats.map(normalizeCategory);
|
|
41
|
+
configureNewDebug({ level: LEVEL_MAP[level], cats: normalizedCats });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function log(cat: LogCat, level: LogLevel, msg: string, extra?: unknown): void {
|
|
45
|
+
warnDeprecated();
|
|
46
|
+
newLog(normalizeCategory(cat), LEVEL_MAP[level], msg, extra);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function preview(s: string, n = 60) {
|
|
50
|
+
if (s == null) return s;
|
|
51
|
+
return s.length > n ? s.slice(0, n - 3) + "..." : s;
|
|
52
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ensureId, DomIds } from "./ids.js";
|
|
2
|
+
import type { UID } from "./ids.js";
|
|
3
|
+
import { log } from "../logging/debug.js";
|
|
4
|
+
|
|
5
|
+
export interface TreeMeta {
|
|
6
|
+
id: UID; depth: number; parentId?: UID;
|
|
7
|
+
prevSiblingId?: UID; nextSiblingId?: UID;
|
|
8
|
+
siblingIndex: number; siblingCount: number;
|
|
9
|
+
path: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function analyzeDomNode(node: Node, parent?: Node, depth = 0): TreeMeta {
|
|
13
|
+
const id = ensureId(DomIds, node);
|
|
14
|
+
const parentId = parent ? ensureId(DomIds, parent) : undefined;
|
|
15
|
+
|
|
16
|
+
const siblings = parent ? Array.from((parent as Element).childNodes) : [node];
|
|
17
|
+
const idx = siblings.indexOf(node);
|
|
18
|
+
const siblingCount = siblings.length;
|
|
19
|
+
const prev = idx > 0 ? siblings[idx - 1] : undefined;
|
|
20
|
+
const next = idx >= 0 && idx < siblingCount - 1 ? siblings[idx + 1] : undefined;
|
|
21
|
+
const prevSiblingId = prev ? ensureId(DomIds, prev) : undefined;
|
|
22
|
+
const nextSiblingId = next ? ensureId(DomIds, next) : undefined;
|
|
23
|
+
|
|
24
|
+
const path = computeDomPath(node as Element);
|
|
25
|
+
const meta: TreeMeta = { id, depth, parentId, prevSiblingId, nextSiblingId, siblingIndex: idx, siblingCount, path };
|
|
26
|
+
|
|
27
|
+
log("parse","trace","DOM node", {
|
|
28
|
+
...meta,
|
|
29
|
+
tag: (node as Element).nodeType === 1 ? (node as Element).tagName.toLowerCase() : "#text",
|
|
30
|
+
textPreview: node.nodeType === 3 ? (node.textContent ?? "").slice(0,60) : undefined
|
|
31
|
+
});
|
|
32
|
+
return meta;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function computeDomPath(el: Element): string {
|
|
36
|
+
if (!el || el.nodeType !== 1) return "#text";
|
|
37
|
+
const parts: string[] = [];
|
|
38
|
+
let cur: Element | null = el;
|
|
39
|
+
while (cur && cur.nodeType === 1) {
|
|
40
|
+
const current: Element = cur;
|
|
41
|
+
const tag = current.tagName.toLowerCase();
|
|
42
|
+
const parent: Element | null = current.parentElement;
|
|
43
|
+
let nth = 1;
|
|
44
|
+
if (parent) {
|
|
45
|
+
const siblings = Array.from(parent.children) as Element[];
|
|
46
|
+
const sameTagSiblings = siblings.filter((candidate) => candidate.tagName === current.tagName);
|
|
47
|
+
if (sameTagSiblings.length > 1) {
|
|
48
|
+
nth = sameTagSiblings.indexOf(current) + 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const id = current.id ? `#${current.id}` : "";
|
|
52
|
+
const cls = current.classList?.length ? "." + Array.from(current.classList).join(".") : "";
|
|
53
|
+
parts.unshift(`${tag}${id}${cls}${parent && nth>1 ? `:nth-of-type(${nth})` : ""}`);
|
|
54
|
+
cur = parent;
|
|
55
|
+
}
|
|
56
|
+
return parts.join(">");
|
|
57
|
+
}
|
package/src/dom/node.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { ComputedStyle } from "../css/style.js";
|
|
2
|
+
import { Box } from "../geometry/box.js";
|
|
3
|
+
import type { LineBox } from "../text/line-breaker.js";
|
|
4
|
+
|
|
5
|
+
export interface InlineRun {
|
|
6
|
+
lineIndex: number;
|
|
7
|
+
startX: number;
|
|
8
|
+
baseline: number;
|
|
9
|
+
text: string;
|
|
10
|
+
width: number;
|
|
11
|
+
lineWidth: number;
|
|
12
|
+
spaceCount: number;
|
|
13
|
+
targetWidth: number;
|
|
14
|
+
isLastLine: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface NodeVisitor {
|
|
18
|
+
(node: LayoutNode): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface LayoutNodeOptions {
|
|
22
|
+
intrinsicInlineSize?: number;
|
|
23
|
+
intrinsicBlockSize?: number;
|
|
24
|
+
textContent?: string;
|
|
25
|
+
tagName?: string;
|
|
26
|
+
lineBoxes?: LineBox[];
|
|
27
|
+
inlineRuns?: InlineRun[];
|
|
28
|
+
customData?: Record<string, unknown>;
|
|
29
|
+
tableColSpan?: number;
|
|
30
|
+
tableRowSpan?: number;
|
|
31
|
+
tableCellOrigin?: { row: number; col: number };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class LayoutNode {
|
|
35
|
+
readonly box = new Box();
|
|
36
|
+
parent: LayoutNode | null = null;
|
|
37
|
+
private readonly childrenInternal: LayoutNode[] = [];
|
|
38
|
+
|
|
39
|
+
establishesBFC = false;
|
|
40
|
+
establishesIFC = false;
|
|
41
|
+
establishesFFC = false;
|
|
42
|
+
establishesGFC = false;
|
|
43
|
+
establishesTFC = false;
|
|
44
|
+
|
|
45
|
+
intrinsicInlineSize?: number;
|
|
46
|
+
intrinsicBlockSize?: number;
|
|
47
|
+
textContent?: string;
|
|
48
|
+
tagName?: string;
|
|
49
|
+
lineBoxes?: LineBox[];
|
|
50
|
+
inlineRuns?: InlineRun[];
|
|
51
|
+
customData?: Record<string, unknown>;
|
|
52
|
+
tableColSpan?: number;
|
|
53
|
+
tableRowSpan?: number;
|
|
54
|
+
tableCellOrigin?: { row: number; col: number };
|
|
55
|
+
|
|
56
|
+
constructor(public readonly style: ComputedStyle, children: Iterable<LayoutNode> = [], options?: LayoutNodeOptions) {
|
|
57
|
+
this.intrinsicInlineSize = options?.intrinsicInlineSize;
|
|
58
|
+
this.intrinsicBlockSize = options?.intrinsicBlockSize;
|
|
59
|
+
this.textContent = options?.textContent;
|
|
60
|
+
this.tagName = options?.tagName;
|
|
61
|
+
this.lineBoxes = options?.lineBoxes;
|
|
62
|
+
this.inlineRuns = options?.inlineRuns;
|
|
63
|
+
this.customData = options?.customData;
|
|
64
|
+
this.tableColSpan = options?.tableColSpan;
|
|
65
|
+
this.tableRowSpan = options?.tableRowSpan;
|
|
66
|
+
this.tableCellOrigin = options?.tableCellOrigin;
|
|
67
|
+
for (const child of children) {
|
|
68
|
+
this.appendChild(child);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get children(): readonly LayoutNode[] {
|
|
73
|
+
return this.childrenInternal;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
appendChild(child: LayoutNode): this {
|
|
77
|
+
child.parent = this;
|
|
78
|
+
this.childrenInternal.push(child);
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
removeChild(child: LayoutNode): void {
|
|
83
|
+
const idx = this.childrenInternal.indexOf(child);
|
|
84
|
+
if (idx >= 0) {
|
|
85
|
+
this.childrenInternal.splice(idx, 1);
|
|
86
|
+
child.parent = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
nearestAncestor(predicate: (node: LayoutNode) => boolean): LayoutNode | null {
|
|
91
|
+
let current: LayoutNode | null = this.parent;
|
|
92
|
+
while (current) {
|
|
93
|
+
if (predicate(current)) {
|
|
94
|
+
return current;
|
|
95
|
+
}
|
|
96
|
+
current = current.parent;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
walk(visitor: NodeVisitor, includeSelf = true): void {
|
|
102
|
+
if (includeSelf) {
|
|
103
|
+
visitor(this);
|
|
104
|
+
}
|
|
105
|
+
for (const child of this.childrenInternal) {
|
|
106
|
+
child.walk(visitor, true);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
postOrder(visitor: NodeVisitor): void {
|
|
111
|
+
for (const child of this.childrenInternal) {
|
|
112
|
+
child.postOrder(visitor);
|
|
113
|
+
}
|
|
114
|
+
visitor(this);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
shift(dx: number, dy: number): void {
|
|
118
|
+
this.box.x += dx;
|
|
119
|
+
this.box.y += dy;
|
|
120
|
+
this.box.baseline += dy;
|
|
121
|
+
|
|
122
|
+
if (this.inlineRuns) {
|
|
123
|
+
for (const run of this.inlineRuns) {
|
|
124
|
+
run.startX += dx;
|
|
125
|
+
run.baseline += dy;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (const child of this.childrenInternal) {
|
|
130
|
+
child.shift(dx, dy);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser implementation of the Environment interfaces.
|
|
3
|
+
* Uses fetch for loading and DecompressionStream for inflateRaw (with a guard).
|
|
4
|
+
*/
|
|
5
|
+
import type { Compression, Environment, ResourceLoader } from "./environment.js";
|
|
6
|
+
|
|
7
|
+
class BrowserLoader implements ResourceLoader {
|
|
8
|
+
async load(source: string): Promise<ArrayBuffer> {
|
|
9
|
+
const response = await fetch(source);
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
throw new Error(`Failed to fetch resource: ${source} (${response.status})`);
|
|
12
|
+
}
|
|
13
|
+
return await response.arrayBuffer();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const DecompressionStreamCtor: typeof DecompressionStream | undefined = (globalThis as any).DecompressionStream;
|
|
18
|
+
|
|
19
|
+
class BrowserCompression implements Compression {
|
|
20
|
+
async inflateRaw(data: Uint8Array): Promise<Uint8Array> {
|
|
21
|
+
if (!DecompressionStreamCtor) {
|
|
22
|
+
throw new Error("DecompressionStream not available; provide a polyfill (e.g., pako) for inflateRaw.");
|
|
23
|
+
}
|
|
24
|
+
const stream = new DecompressionStreamCtor("deflate-raw");
|
|
25
|
+
const writer = stream.writable.getWriter();
|
|
26
|
+
await writer.write(new Uint8Array(data) as BufferSource);
|
|
27
|
+
await writer.close();
|
|
28
|
+
const reader = stream.readable.getReader();
|
|
29
|
+
const chunks: Uint8Array[] = [];
|
|
30
|
+
let total = 0;
|
|
31
|
+
for (; ;) {
|
|
32
|
+
const { done, value } = await reader.read();
|
|
33
|
+
if (done) break;
|
|
34
|
+
chunks.push(value);
|
|
35
|
+
total += value.byteLength;
|
|
36
|
+
}
|
|
37
|
+
const out = new Uint8Array(total);
|
|
38
|
+
let offset = 0;
|
|
39
|
+
for (const chunk of chunks) {
|
|
40
|
+
out.set(chunk, offset);
|
|
41
|
+
offset += chunk.byteLength;
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class BrowserEnvironment implements Environment {
|
|
48
|
+
readonly loader: ResourceLoader;
|
|
49
|
+
readonly compression: Compression;
|
|
50
|
+
|
|
51
|
+
constructor() {
|
|
52
|
+
this.loader = new BrowserLoader();
|
|
53
|
+
this.compression = new BrowserCompression();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
resolveLocal(source: string, base?: string): string {
|
|
57
|
+
if (/^data:/i.test(source)) return source;
|
|
58
|
+
if (/^[a-z][a-z0-9+\-.]*:\/\//i.test(source) || source.startsWith("//")) {
|
|
59
|
+
return source;
|
|
60
|
+
}
|
|
61
|
+
if (base) {
|
|
62
|
+
try {
|
|
63
|
+
return new URL(source, base).toString();
|
|
64
|
+
} catch {
|
|
65
|
+
// ignore and fall through
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`Local path resolution is not supported in browser environment: ${source}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
now(): number {
|
|
72
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
getEnv(_name: string): string | undefined {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment abstractions to decouple platform-specific I/O from core logic.
|
|
3
|
+
* Node and browser builds should provide their own implementations.
|
|
4
|
+
*/
|
|
5
|
+
export interface ResourceLoader {
|
|
6
|
+
/**
|
|
7
|
+
* Load a binary resource (font, image, etc.) from a URL or path.
|
|
8
|
+
*/
|
|
9
|
+
load(source: string): Promise<ArrayBuffer>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface Compression {
|
|
13
|
+
/**
|
|
14
|
+
* Inflate raw deflate-compressed data (no zlib headers).
|
|
15
|
+
*/
|
|
16
|
+
inflateRaw(data: Uint8Array): Promise<Uint8Array>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface Environment {
|
|
20
|
+
readonly loader: ResourceLoader;
|
|
21
|
+
readonly compression: Compression;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a local reference (path or URL-like) relative to a base.
|
|
24
|
+
* Implementations may throw if local resolution isn't supported (e.g., browser).
|
|
25
|
+
*/
|
|
26
|
+
resolveLocal?(source: string, base?: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Monotonic-ish clock for timing/debug (milliseconds).
|
|
29
|
+
*/
|
|
30
|
+
now(): number;
|
|
31
|
+
/**
|
|
32
|
+
* Get an environment variable.
|
|
33
|
+
*/
|
|
34
|
+
getEnv(name: string): string | undefined;
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper to set the global environment for browser builds.
|
|
3
|
+
* Use this to avoid threading Environment through every call when bootstrapping.
|
|
4
|
+
*/
|
|
5
|
+
import type { Environment } from "./environment.js";
|
|
6
|
+
|
|
7
|
+
export function setGlobalEnvironment(env: Environment): void {
|
|
8
|
+
(globalThis as any).__PAGYRA_ENV__ = env;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getGlobalEnvironment(): Environment | undefined {
|
|
12
|
+
return (globalThis as any).__PAGYRA_ENV__ as Environment | undefined;
|
|
13
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Browser stub: NodeEnvironment is unavailable in browser builds.
|
|
2
|
+
import type { Environment, ResourceLoader, Compression } from "./environment.js";
|
|
3
|
+
|
|
4
|
+
class NoopLoader implements ResourceLoader {
|
|
5
|
+
async load(_source: string): Promise<ArrayBuffer> {
|
|
6
|
+
throw new Error("NodeEnvironment is not available in browser builds");
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class NoopCompression implements Compression {
|
|
11
|
+
async inflateRaw(_data: Uint8Array): Promise<Uint8Array> {
|
|
12
|
+
throw new Error("NodeEnvironment compression is not available in browser builds");
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class NodeEnvironment implements Environment {
|
|
17
|
+
readonly loader: ResourceLoader = new NoopLoader();
|
|
18
|
+
readonly compression: Compression = new NoopCompression();
|
|
19
|
+
resolveLocal(): string {
|
|
20
|
+
throw new Error("NodeEnvironment resolveLocal is not available in browser builds");
|
|
21
|
+
}
|
|
22
|
+
now(): number {
|
|
23
|
+
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
24
|
+
}
|
|
25
|
+
getEnv(_name: string): string | undefined {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { inflateRawSync } from "node:zlib";
|
|
4
|
+
import type { Compression, Environment, ResourceLoader } from "./environment.js";
|
|
5
|
+
|
|
6
|
+
class NodeLoader implements ResourceLoader {
|
|
7
|
+
constructor(private readonly baseDir?: string) { }
|
|
8
|
+
|
|
9
|
+
async load(source: string): Promise<ArrayBuffer> {
|
|
10
|
+
if (/^https?:\/\//i.test(source)) {
|
|
11
|
+
const res = await fetch(source);
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
throw new Error(`Failed to fetch resource: ${source} (${res.status})`);
|
|
14
|
+
}
|
|
15
|
+
return await res.arrayBuffer();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const resolved = this.baseDir ? path.resolve(this.baseDir, source) : source;
|
|
19
|
+
const buffer = await readFile(resolved);
|
|
20
|
+
const bytes = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
21
|
+
return bytes.slice().buffer;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class NodeCompression implements Compression {
|
|
26
|
+
async inflateRaw(data: Uint8Array): Promise<Uint8Array> {
|
|
27
|
+
const inflated = inflateRawSync(data);
|
|
28
|
+
return new Uint8Array(inflated.buffer, inflated.byteOffset, inflated.byteLength);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Default Node environment implementation.
|
|
34
|
+
* Base directory is optional and used for resolving relative file paths.
|
|
35
|
+
*/
|
|
36
|
+
export class NodeEnvironment implements Environment {
|
|
37
|
+
readonly loader: ResourceLoader;
|
|
38
|
+
readonly compression: Compression;
|
|
39
|
+
|
|
40
|
+
constructor(baseDir?: string) {
|
|
41
|
+
this.loader = new NodeLoader(baseDir);
|
|
42
|
+
this.compression = new NodeCompression();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resolveLocal(source: string, base?: string): string {
|
|
46
|
+
// URLs and data URIs pass through unchanged
|
|
47
|
+
if (/^(https?:)?\/\//i.test(source) || /^data:/i.test(source)) {
|
|
48
|
+
return source;
|
|
49
|
+
}
|
|
50
|
+
// Strip leading slash to treat as document-relative (not filesystem-absolute)
|
|
51
|
+
// This ensures /images/duck.jpg resolves to {base}/images/duck.jpg, not C:\images\duck.jpg on Windows
|
|
52
|
+
const normalized = source.startsWith('/') ? source.slice(1) : source;
|
|
53
|
+
const resolved = base ? path.resolve(base, normalized) : path.resolve(normalized);
|
|
54
|
+
return resolved;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
now(): number {
|
|
58
|
+
return Date.now();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getEnv(name: string): string | undefined {
|
|
62
|
+
return process.env[name];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { FontFormat } from './types.js';
|
|
2
|
+
|
|
3
|
+
export function detectFontFormat(fontData: Uint8Array): FontFormat | null {
|
|
4
|
+
if (fontData.length < 4) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Read the first 4 bytes as signature
|
|
9
|
+
const signature = String.fromCharCode(...fontData.slice(0, 4));
|
|
10
|
+
|
|
11
|
+
switch (signature) {
|
|
12
|
+
case 'wOFF':
|
|
13
|
+
return 'woff';
|
|
14
|
+
case 'wOF2':
|
|
15
|
+
return 'woff2';
|
|
16
|
+
case '\x00\x01\x00\x00': // TTF/OTF signature
|
|
17
|
+
case 'OTTO': // OTF signature
|
|
18
|
+
// For simplicity, we'll treat both TTF and OTF as 'ttf' for now
|
|
19
|
+
// Later we can differentiate if needed
|
|
20
|
+
return fontData[0] === 0 && fontData[1] === 1 ? 'ttf' : 'otf';
|
|
21
|
+
default:
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isSupportedFontFormat(fontData: Uint8Array): boolean {
|
|
27
|
+
return detectFontFormat(fontData) !== null;
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { parseTtfBuffer } from '../../pdf/font/ttf-lite.js';
|
|
2
|
+
import type { TtfFontMetrics } from '../../types/fonts.js';
|
|
3
|
+
import type { UnifiedFont, FontFormat } from '../types.js';
|
|
4
|
+
|
|
5
|
+
export class TtfEngine {
|
|
6
|
+
parse(fontData: Uint8Array): TtfFontMetrics {
|
|
7
|
+
const arrayBuffer = new ArrayBuffer(fontData.length);
|
|
8
|
+
const view = new Uint8Array(arrayBuffer);
|
|
9
|
+
view.set(fontData);
|
|
10
|
+
return parseTtfBuffer(arrayBuffer);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
convertToUnified(parsedFont: TtfFontMetrics): UnifiedFont {
|
|
14
|
+
return {
|
|
15
|
+
metrics: {
|
|
16
|
+
metrics: parsedFont.metrics,
|
|
17
|
+
glyphMetrics: parsedFont.glyphMetrics,
|
|
18
|
+
cmap: parsedFont.cmap,
|
|
19
|
+
headBBox: parsedFont.headBBox,
|
|
20
|
+
},
|
|
21
|
+
program: {
|
|
22
|
+
sourceFormat: 'ttf' as FontFormat,
|
|
23
|
+
getRawTableData: undefined, // TTF engine doesn't have raw table access
|
|
24
|
+
getGlyphOutline: parsedFont.getGlyphOutline,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { decodeWoff } from "../woff/decoder.js";
|
|
2
|
+
import { reconstructTtf } from "../utils/ttf-reconstructor.js";
|
|
3
|
+
import type { FontFormat, ParsedFont, UnifiedFont } from "../types.js";
|
|
4
|
+
import { parseTtfBuffer } from "../../pdf/font/ttf-lite.js";
|
|
5
|
+
|
|
6
|
+
export class WoffEngine {
|
|
7
|
+
async parse(fontData: Uint8Array): Promise<ParsedFont> {
|
|
8
|
+
return decodeWoff(fontData);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
convertToUnified(parsedFont: ParsedFont): UnifiedFont {
|
|
12
|
+
const ttfBuffer = reconstructTtf(parsedFont);
|
|
13
|
+
const metrics = parseTtfBuffer(ttfBuffer);
|
|
14
|
+
|
|
15
|
+
// Capture raw table data for callers that need it (PDF embedding/tests)
|
|
16
|
+
const tableMap = new Map<string, Uint8Array>();
|
|
17
|
+
for (const [tag, data] of Object.entries(parsedFont.tables)) {
|
|
18
|
+
tableMap.set(tag, data);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
metrics: {
|
|
23
|
+
metrics: metrics.metrics,
|
|
24
|
+
glyphMetrics: metrics.glyphMetrics,
|
|
25
|
+
cmap: metrics.cmap,
|
|
26
|
+
headBBox: metrics.headBBox,
|
|
27
|
+
kerning: metrics.kerning,
|
|
28
|
+
},
|
|
29
|
+
program: {
|
|
30
|
+
sourceFormat: "woff" as FontFormat,
|
|
31
|
+
unitsPerEm: metrics.metrics.unitsPerEm,
|
|
32
|
+
glyphCount: metrics.glyphMetrics.size,
|
|
33
|
+
getRawTableData: (tag: string) => tableMap.get(tag) ?? null,
|
|
34
|
+
getGlyphOutline: metrics.getGlyphOutline,
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { parseTtfBuffer } from "../../pdf/font/ttf-lite.js";
|
|
2
|
+
import type { FontFormat, ParsedFont, UnifiedFont } from "../types.js";
|
|
3
|
+
import { decodeWoff2 } from "../woff2/decoder.js";
|
|
4
|
+
|
|
5
|
+
type ParsedWoff2 = ParsedFont & { ttfBuffer: Uint8Array };
|
|
6
|
+
|
|
7
|
+
export class Woff2Engine {
|
|
8
|
+
async parse(fontData: Uint8Array): Promise<ParsedWoff2> {
|
|
9
|
+
const { parsed, ttfBuffer } = await decodeWoff2(fontData);
|
|
10
|
+
return { ...parsed, ttfBuffer };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
convertToUnified(parsedFont: ParsedWoff2): UnifiedFont {
|
|
14
|
+
// Create an ArrayBuffer copy to avoid SharedArrayBuffer unions
|
|
15
|
+
const ttfCopy = parsedFont.ttfBuffer.slice();
|
|
16
|
+
const ttfArrayBuffer = ttfCopy.buffer;
|
|
17
|
+
const metrics = parseTtfBuffer(ttfArrayBuffer);
|
|
18
|
+
|
|
19
|
+
const tableMap = new Map<string, Uint8Array>();
|
|
20
|
+
for (const [tag, data] of Object.entries(parsedFont.tables)) {
|
|
21
|
+
tableMap.set(tag, data);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
metrics: {
|
|
26
|
+
metrics: metrics.metrics,
|
|
27
|
+
glyphMetrics: metrics.glyphMetrics,
|
|
28
|
+
cmap: metrics.cmap,
|
|
29
|
+
headBBox: metrics.headBBox,
|
|
30
|
+
kerning: metrics.kerning
|
|
31
|
+
},
|
|
32
|
+
program: {
|
|
33
|
+
sourceFormat: "woff2" as FontFormat,
|
|
34
|
+
unitsPerEm: metrics.metrics.unitsPerEm,
|
|
35
|
+
glyphCount: metrics.glyphMetrics.size,
|
|
36
|
+
getRawTableData: (tag: string) => tableMap.get(tag) ?? null,
|
|
37
|
+
getGlyphOutline: metrics.getGlyphOutline
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|