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,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TtfTableParser
|
|
3
|
+
* Small utility to read table directory and provide safe big-endian reads.
|
|
4
|
+
*
|
|
5
|
+
* This file was extracted from ttf-lite.ts as part of SRP refactor. Keep the
|
|
6
|
+
* implementation minimal and focused on DataView/table-directory logic.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { log } from "../../logging/debug.js";
|
|
10
|
+
|
|
11
|
+
export interface TableDirectoryEntry {
|
|
12
|
+
tag: number;
|
|
13
|
+
checksum: number;
|
|
14
|
+
offset: number;
|
|
15
|
+
length: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class TtfTableParser {
|
|
19
|
+
private readonly dataView: DataView;
|
|
20
|
+
private readonly tableDirectory = new Map<number, TableDirectoryEntry>();
|
|
21
|
+
|
|
22
|
+
constructor(buffer: ArrayBuffer) {
|
|
23
|
+
this.dataView = new DataView(buffer);
|
|
24
|
+
this.parseTableDirectory();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
private parseTableDirectory(): void {
|
|
28
|
+
// Validate minimal header present
|
|
29
|
+
if (this.dataView.byteLength < 12) {
|
|
30
|
+
throw new Error("Truncated TTF header");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const numTables = this.dataView.getUint16(4, false); // big-endian
|
|
34
|
+
const tableDirOffset = 12;
|
|
35
|
+
const requiredDirBytes = tableDirOffset + numTables * 16;
|
|
36
|
+
if (requiredDirBytes > this.dataView.byteLength) {
|
|
37
|
+
throw new Error("Truncated table directory");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < numTables; i++) {
|
|
41
|
+
const offset = tableDirOffset + i * 16;
|
|
42
|
+
const tag = this.dataView.getUint32(offset, false);
|
|
43
|
+
const checksum = this.dataView.getUint32(offset + 4, false);
|
|
44
|
+
const tableOffset = this.dataView.getUint32(offset + 8, false);
|
|
45
|
+
const length = this.dataView.getUint32(offset + 12, false);
|
|
46
|
+
|
|
47
|
+
// CAVEAT FIX: Interception point for problematic tables
|
|
48
|
+
const tagString = String.fromCharCode(
|
|
49
|
+
(tag >> 24) & 0xFF,
|
|
50
|
+
(tag >> 16) & 0xFF,
|
|
51
|
+
(tag >> 8) & 0xFF,
|
|
52
|
+
tag & 0xFF
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// CAVEAT SPECIFIC FIX: Force skip ONLY the exact problematic table
|
|
56
|
+
if (tagString === 'gloc') {
|
|
57
|
+
log('font', 'warn', `🚫 CAVEAT TTF PARSER: FORCE SKIPPING problematic table 'gloc' (0x${tag.toString(16)})`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Essential TTF tables that MUST NOT be filtered out
|
|
62
|
+
const essentialTables = ['cmap', 'head', 'hhea', 'hmtx', 'maxp', 'name', 'OS/2', 'post'];
|
|
63
|
+
|
|
64
|
+
// Bounds validation - allow graceful skip for non-essential tables
|
|
65
|
+
if (tableOffset + length > this.dataView.byteLength) {
|
|
66
|
+
if (essentialTables.includes(tagString)) {
|
|
67
|
+
log('font', 'warn', `WOFF2 TTF: ESSENTIAL table ${tagString} has bounds issues - attempting to proceed with clamped length`);
|
|
68
|
+
// For essential tables, clamp the length to fit within file bounds
|
|
69
|
+
const clampedLength = Math.min(length, this.dataView.byteLength - tableOffset);
|
|
70
|
+
if (clampedLength > 0) {
|
|
71
|
+
this.tableDirectory.set(tag, {
|
|
72
|
+
tag,
|
|
73
|
+
checksum,
|
|
74
|
+
offset: tableOffset,
|
|
75
|
+
length: clampedLength
|
|
76
|
+
});
|
|
77
|
+
log('font', 'debug', `✅ CAVEAT TTF PARSER: KEPT essential table ${tagString} with clamped length ${clampedLength}`);
|
|
78
|
+
} else {
|
|
79
|
+
log('font', 'warn', `WOFF2 TTF: Essential table ${tagString} completely out of bounds - skipping`);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
log('font', 'warn', `WOFF2 TTF: Skipping optional table ${tagString} due to bounds issues`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
this.tableDirectory.set(tag, {
|
|
87
|
+
tag,
|
|
88
|
+
checksum,
|
|
89
|
+
offset: tableOffset,
|
|
90
|
+
length
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getTable(tag: number): DataView | null {
|
|
97
|
+
const entry = this.tableDirectory.get(tag);
|
|
98
|
+
if (!entry) return null;
|
|
99
|
+
|
|
100
|
+
// Extra guard for safety before creating a DataView
|
|
101
|
+
if (entry.offset + entry.length > this.dataView.byteLength) {
|
|
102
|
+
throw new Error(`Invalid table entry for tag 0x${tag.toString(16)}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return new DataView(this.dataView.buffer, entry.offset, entry.length);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getUint16(table: DataView, offset: number): number {
|
|
109
|
+
if (offset + 2 > table.byteLength) throw new Error("Read beyond table bounds (getUint16)");
|
|
110
|
+
return table.getUint16(offset, false); // big-endian
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
getInt16(table: DataView, offset: number): number {
|
|
114
|
+
if (offset + 2 > table.byteLength) throw new Error("Read beyond table bounds (getInt16)");
|
|
115
|
+
return table.getInt16(offset, false); // big-endian
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getInt8(table: DataView, offset: number): number {
|
|
119
|
+
if (offset + 1 > table.byteLength) throw new Error("Read beyond table bounds (getInt8)");
|
|
120
|
+
return table.getInt8(offset);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getUint8(table: DataView, offset: number): number {
|
|
124
|
+
if (offset + 1 > table.byteLength) throw new Error("Read beyond table bounds (getUint8)");
|
|
125
|
+
return table.getUint8(offset);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getUint32(table: DataView, offset: number): number {
|
|
129
|
+
if (offset + 4 > table.byteLength) throw new Error("Read beyond table bounds (getUint32)");
|
|
130
|
+
return table.getUint32(offset, false); // big-endian
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TrueType table provider interfaces.
|
|
3
|
+
*
|
|
4
|
+
* These interfaces are segregated following the Interface Segregation Principle (ISP).
|
|
5
|
+
* Clients can depend only on the interfaces they actually need.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Provides access to TrueType font tables.
|
|
10
|
+
*/
|
|
11
|
+
export interface TableProvider {
|
|
12
|
+
/**
|
|
13
|
+
* Retrieves a font table by its 4-byte tag.
|
|
14
|
+
* @param tag - Table tag as a 32-bit integer (e.g., 0x676c7966 for 'glyf')
|
|
15
|
+
* @returns DataView of the table data, or null if table doesn't exist
|
|
16
|
+
*/
|
|
17
|
+
getTable(tag: number): DataView | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Provides methods for reading binary data from DataViews.
|
|
22
|
+
* Abstracts the byte-order and offset calculations.
|
|
23
|
+
*/
|
|
24
|
+
export interface DataViewReader {
|
|
25
|
+
getUint16(view: DataView, offset: number): number;
|
|
26
|
+
getUint32(view: DataView, offset: number): number;
|
|
27
|
+
getInt16(view: DataView, offset: number): number;
|
|
28
|
+
getInt8(view: DataView, offset: number): number;
|
|
29
|
+
getUint8(view: DataView, offset: number): number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Combined interface for backward compatibility.
|
|
34
|
+
* Provides both table access and binary reading capabilities.
|
|
35
|
+
*/
|
|
36
|
+
export interface GlyphTableProvider extends TableProvider, DataViewReader { }
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Default implementation of DataViewReader using big-endian byte order (TrueType standard).
|
|
40
|
+
*/
|
|
41
|
+
export class DefaultDataViewReader implements DataViewReader {
|
|
42
|
+
getUint16(view: DataView, offset: number): number {
|
|
43
|
+
return view.getUint16(offset, false);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getUint32(view: DataView, offset: number): number {
|
|
47
|
+
return view.getUint32(offset, false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getInt16(view: DataView, offset: number): number {
|
|
51
|
+
return view.getInt16(offset, false);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
getInt8(view: DataView, offset: number): number {
|
|
55
|
+
return view.getInt8(offset);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getUint8(view: DataView, offset: number): number {
|
|
59
|
+
return view.getUint8(offset);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { TtfFontMetrics } from "../../types/fonts.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Compute DW (default width) and compressed W array from glyph metrics.
|
|
5
|
+
* Shared utility used by font embedding and tests.
|
|
6
|
+
*/
|
|
7
|
+
export function computeWidths(metrics: TtfFontMetrics): { DW: number; W: (number | number[])[] } {
|
|
8
|
+
const count = metrics.glyphMetrics.size;
|
|
9
|
+
const widths: number[] = new Array(count).fill(0);
|
|
10
|
+
for (const [gid, gm] of metrics.glyphMetrics) {
|
|
11
|
+
widths[gid] = Math.round((gm.advanceWidth / metrics.metrics.unitsPerEm) * 1000);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const computeDW = (arr: number[]) => {
|
|
15
|
+
const freq = new Map<number, number>();
|
|
16
|
+
for (const v of arr) {
|
|
17
|
+
// Skip zero widths; a DW of 0 breaks Identity-H rendering in some viewers.
|
|
18
|
+
if (v === 0) continue;
|
|
19
|
+
freq.set(v, (freq.get(v) ?? 0) + 1);
|
|
20
|
+
}
|
|
21
|
+
// Fallback to 1000 if we only saw zeros.
|
|
22
|
+
if (freq.size === 0) {
|
|
23
|
+
return 1000;
|
|
24
|
+
}
|
|
25
|
+
let best = 1000;
|
|
26
|
+
let bestCount = -1;
|
|
27
|
+
for (const [v, c] of freq.entries()) {
|
|
28
|
+
if (c > bestCount || (c === bestCount && v < best)) {
|
|
29
|
+
best = v;
|
|
30
|
+
bestCount = c;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return best;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const DW = computeDW(widths);
|
|
37
|
+
|
|
38
|
+
// Compress widths into W entries using ranges for repeating values and arrays for heterogenous runs
|
|
39
|
+
// The PDF spec requires a flat array of mixed types:
|
|
40
|
+
// c [w1 w2 ... wn]
|
|
41
|
+
// c_first c_last w
|
|
42
|
+
const result: (number | number[])[] = [];
|
|
43
|
+
let i = 0;
|
|
44
|
+
while (i < count) {
|
|
45
|
+
// skip DW values
|
|
46
|
+
if (widths[i] === DW) {
|
|
47
|
+
i++;
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// try find long run of identical width (use range if length >= 4)
|
|
52
|
+
const start = i;
|
|
53
|
+
const val = widths[i];
|
|
54
|
+
let j = i + 1;
|
|
55
|
+
while (j < count && widths[j] === val) j++;
|
|
56
|
+
const runLen = j - start;
|
|
57
|
+
if (runLen >= 4) {
|
|
58
|
+
// c_first c_last w
|
|
59
|
+
result.push(start);
|
|
60
|
+
result.push(j - 1);
|
|
61
|
+
result.push(val);
|
|
62
|
+
i = j;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// otherwise build a heterogenous list until we hit DW or reach a reasonable chunk (32)
|
|
67
|
+
const listStart = i;
|
|
68
|
+
const list: number[] = [];
|
|
69
|
+
while (i < count && widths[i] !== DW && list.length < 32) {
|
|
70
|
+
list.push(widths[i]);
|
|
71
|
+
i++;
|
|
72
|
+
}
|
|
73
|
+
// c [w1 ... wn]
|
|
74
|
+
result.push(listStart);
|
|
75
|
+
result.push(list);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { DW, W: result };
|
|
79
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { UnifiedFont } from "../../fonts/types.js";
|
|
2
|
+
import type { GlyphRun } from "../../layout/text-run.js";
|
|
3
|
+
import { createPdfFontSubset, type PdfFontSubset } from "../font/font-subset.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Combines a PDF font subset with its source UnifiedFont.
|
|
7
|
+
*/
|
|
8
|
+
export interface PdfFontHandle {
|
|
9
|
+
subset: PdfFontSubset;
|
|
10
|
+
unifiedFont: UnifiedFont;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Manages font subsets for PDF generation.
|
|
15
|
+
* Collects glyph usage across the document and creates font subsets on demand.
|
|
16
|
+
*/
|
|
17
|
+
export class PdfFontRegistry {
|
|
18
|
+
// Map from font key to set of used glyph IDs
|
|
19
|
+
private readonly glyphUsage = new Map<string, Set<number>>();
|
|
20
|
+
|
|
21
|
+
// Map from font key to PdfFontHandle (lazily created)
|
|
22
|
+
private readonly fonts = new Map<string, PdfFontHandle>();
|
|
23
|
+
|
|
24
|
+
// Counter for generating unique font resource names
|
|
25
|
+
private fontCounter = 0;
|
|
26
|
+
|
|
27
|
+
constructor(private readonly encoding: "identity" | "sequential" = "identity") {}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Generates a stable key for a UnifiedFont.
|
|
31
|
+
* Uses CSS metadata if available, otherwise falls back to a generic key.
|
|
32
|
+
*/
|
|
33
|
+
private fontKey(font: UnifiedFont): string {
|
|
34
|
+
if (font.css) {
|
|
35
|
+
const { family, weight, style } = font.css;
|
|
36
|
+
return `${family}|${weight}|${style}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Fallback: use unitsPerEm and ascender as a fingerprint
|
|
40
|
+
const { unitsPerEm, ascender } = font.metrics.metrics;
|
|
41
|
+
return `_fallback_${unitsPerEm}_${ascender}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Registers a GlyphRun, collecting its glyph IDs for later subsetting.
|
|
46
|
+
*/
|
|
47
|
+
registerGlyphRun(run: GlyphRun): void {
|
|
48
|
+
const key = this.fontKey(run.font);
|
|
49
|
+
let usage = this.glyphUsage.get(key);
|
|
50
|
+
|
|
51
|
+
if (!usage) {
|
|
52
|
+
usage = new Set<number>();
|
|
53
|
+
this.glyphUsage.set(key, usage);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Add all glyph IDs from this run
|
|
57
|
+
for (const gid of run.glyphIds) {
|
|
58
|
+
usage.add(gid);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Ensures a font subset exists for the given UnifiedFont.
|
|
64
|
+
* Creates the subset lazily if it doesn't exist yet.
|
|
65
|
+
*/
|
|
66
|
+
ensureSubsetFor(font: UnifiedFont): PdfFontHandle {
|
|
67
|
+
const key = this.fontKey(font);
|
|
68
|
+
|
|
69
|
+
// Get the collected glyph IDs for this font
|
|
70
|
+
const usedGlyphIds = this.glyphUsage.get(key) ?? new Set<number>([0]);
|
|
71
|
+
if (!this.glyphUsage.has(key)) {
|
|
72
|
+
this.glyphUsage.set(key, usedGlyphIds);
|
|
73
|
+
}
|
|
74
|
+
usedGlyphIds.add(0);
|
|
75
|
+
|
|
76
|
+
const existing = this.fonts.get(key);
|
|
77
|
+
if (existing && this.subsetCoversGlyphs(existing.subset, usedGlyphIds)) {
|
|
78
|
+
return existing;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Re-use the prior base name when refreshing a subset so aliases stay stable.
|
|
82
|
+
const existingBaseName = existing?.subset.name.startsWith("/") ? existing.subset.name.slice(1) : undefined;
|
|
83
|
+
const baseName = existingBaseName ?? `F${++this.fontCounter}`;
|
|
84
|
+
const subset = createPdfFontSubset({
|
|
85
|
+
baseName,
|
|
86
|
+
fontMetrics: font.metrics,
|
|
87
|
+
fontProgram: font.program,
|
|
88
|
+
usedGlyphIds,
|
|
89
|
+
encoding: this.encoding,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const handle: PdfFontHandle = {
|
|
93
|
+
subset,
|
|
94
|
+
unifiedFont: font,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
this.fonts.set(key, handle);
|
|
98
|
+
return handle;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Checks whether an existing subset already contains every glyph we've seen.
|
|
103
|
+
*/
|
|
104
|
+
private subsetCoversGlyphs(subset: PdfFontSubset, glyphs: Set<number>): boolean {
|
|
105
|
+
const inSubset = new Set(subset.glyphIds);
|
|
106
|
+
for (const gid of glyphs) {
|
|
107
|
+
if (!inSubset.has(gid)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Returns all font subsets created so far.
|
|
116
|
+
*/
|
|
117
|
+
getAllSubsets(): Iterable<PdfFontHandle> {
|
|
118
|
+
return this.fonts.values();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Returns the total number of fonts registered.
|
|
123
|
+
*/
|
|
124
|
+
getFontCount(): number {
|
|
125
|
+
return this.fonts.size;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import type { HeaderFooterHTML, LayerMode, PageSize, Rect } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export interface HeaderFooterContext {
|
|
4
|
+
readonly hf: HeaderFooterHTML;
|
|
5
|
+
readonly pageSize: PageSize;
|
|
6
|
+
readonly baseBox: Rect;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface HeaderFooterLayout {
|
|
10
|
+
readonly headerHeightPt: number;
|
|
11
|
+
readonly footerHeightPt: number;
|
|
12
|
+
readonly headerHeightPx: number;
|
|
13
|
+
readonly footerHeightPx: number;
|
|
14
|
+
readonly layerMode: LayerMode;
|
|
15
|
+
readonly header: HeaderFooterVariants;
|
|
16
|
+
readonly footer: HeaderFooterVariants;
|
|
17
|
+
readonly clipOverflow: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface HeaderFooterVariants {
|
|
21
|
+
readonly defaultVariant?: HeaderFooterVariant;
|
|
22
|
+
readonly firstVariant?: HeaderFooterVariant;
|
|
23
|
+
readonly evenVariant?: HeaderFooterVariant;
|
|
24
|
+
readonly oddVariant?: HeaderFooterVariant;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface HeaderFooterVariant {
|
|
28
|
+
readonly content: unknown;
|
|
29
|
+
readonly maxHeightPt: number;
|
|
30
|
+
readonly maxHeightPx: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function initHeaderFooterContext(hf: HeaderFooterHTML, pageSize: PageSize, basePageBox: Rect): HeaderFooterContext {
|
|
34
|
+
return { hf, pageSize, baseBox: basePageBox };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function layoutHeaderFooterTrees(ctx: HeaderFooterContext, pxToPt: (px: number) => number): HeaderFooterLayout {
|
|
38
|
+
const headerVariants = prepareVariants(ctx.hf, pxToPt, "header");
|
|
39
|
+
const footerVariants = prepareVariants(ctx.hf, pxToPt, "footer");
|
|
40
|
+
const headerHeightPt = resolveVariantHeight(headerVariants);
|
|
41
|
+
const footerHeightPt = resolveVariantHeight(footerVariants);
|
|
42
|
+
const headerHeightPx = resolveVariantHeightPx(headerVariants);
|
|
43
|
+
const footerHeightPx = resolveVariantHeightPx(footerVariants);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
headerHeightPt,
|
|
47
|
+
footerHeightPt,
|
|
48
|
+
headerHeightPx,
|
|
49
|
+
footerHeightPx,
|
|
50
|
+
layerMode: ctx.hf.layerMode,
|
|
51
|
+
header: headerVariants,
|
|
52
|
+
footer: footerVariants,
|
|
53
|
+
clipOverflow: ctx.hf.clipOverflow,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function adjustPageBoxForHf(baseBox: Rect, layout: HeaderFooterLayout): Rect {
|
|
58
|
+
return {
|
|
59
|
+
x: baseBox.x,
|
|
60
|
+
y: baseBox.y + layout.headerHeightPx,
|
|
61
|
+
width: baseBox.width,
|
|
62
|
+
height: Math.max(0, baseBox.height - layout.headerHeightPx - layout.footerHeightPx),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function pickHeaderVariant(
|
|
67
|
+
layout: HeaderFooterLayout,
|
|
68
|
+
pageIndex: number,
|
|
69
|
+
totalPages: number,
|
|
70
|
+
): HeaderFooterVariant | undefined {
|
|
71
|
+
return pickVariant(layout.header, pageIndex, totalPages);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function pickFooterVariant(
|
|
75
|
+
layout: HeaderFooterLayout,
|
|
76
|
+
pageIndex: number,
|
|
77
|
+
totalPages: number,
|
|
78
|
+
): HeaderFooterVariant | undefined {
|
|
79
|
+
return pickVariant(layout.footer, pageIndex, totalPages);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function prepareVariants(
|
|
83
|
+
hf: HeaderFooterHTML,
|
|
84
|
+
pxToPt: (value: number) => number,
|
|
85
|
+
position: "header" | "footer",
|
|
86
|
+
): HeaderFooterVariants {
|
|
87
|
+
const maxHeightPx = position === "header" ? hf.maxHeaderHeightPx ?? 0 : hf.maxFooterHeightPx ?? 0;
|
|
88
|
+
const createVariant = (content: unknown | undefined): HeaderFooterVariant | undefined => {
|
|
89
|
+
if (!content) {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
content,
|
|
94
|
+
maxHeightPt: pxToPt(maxHeightPx),
|
|
95
|
+
maxHeightPx,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
if (position === "header") {
|
|
100
|
+
return {
|
|
101
|
+
defaultVariant: createVariant(hf.headerHtml),
|
|
102
|
+
firstVariant: createVariant(hf.headerFirstHtml),
|
|
103
|
+
evenVariant: createVariant(hf.headerEvenHtml),
|
|
104
|
+
oddVariant: createVariant(hf.headerOddHtml),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
defaultVariant: createVariant(hf.footerHtml),
|
|
110
|
+
firstVariant: createVariant(hf.footerFirstHtml),
|
|
111
|
+
evenVariant: createVariant(hf.footerEvenHtml),
|
|
112
|
+
oddVariant: createVariant(hf.footerOddHtml),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function resolveVariantHeight(variants: HeaderFooterVariants): number {
|
|
117
|
+
const heights = [
|
|
118
|
+
variants.defaultVariant?.maxHeightPt ?? 0,
|
|
119
|
+
variants.firstVariant?.maxHeightPt ?? 0,
|
|
120
|
+
variants.evenVariant?.maxHeightPt ?? 0,
|
|
121
|
+
variants.oddVariant?.maxHeightPt ?? 0,
|
|
122
|
+
];
|
|
123
|
+
return Math.max(...heights);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function resolveVariantHeightPx(variants: HeaderFooterVariants): number {
|
|
127
|
+
const heights = [
|
|
128
|
+
variants.defaultVariant?.maxHeightPx ?? 0,
|
|
129
|
+
variants.firstVariant?.maxHeightPx ?? 0,
|
|
130
|
+
variants.evenVariant?.maxHeightPx ?? 0,
|
|
131
|
+
variants.oddVariant?.maxHeightPx ?? 0,
|
|
132
|
+
];
|
|
133
|
+
return Math.max(...heights);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function pickVariant(
|
|
137
|
+
variants: HeaderFooterVariants,
|
|
138
|
+
pageIndex: number,
|
|
139
|
+
totalPages: number,
|
|
140
|
+
): HeaderFooterVariant | undefined {
|
|
141
|
+
if (pageIndex === 1 && variants.firstVariant) {
|
|
142
|
+
return variants.firstVariant;
|
|
143
|
+
}
|
|
144
|
+
if (totalPages > 1) {
|
|
145
|
+
if (pageIndex % 2 === 0 && variants.evenVariant) {
|
|
146
|
+
return variants.evenVariant;
|
|
147
|
+
}
|
|
148
|
+
if (pageIndex % 2 === 1 && variants.oddVariant) {
|
|
149
|
+
return variants.oddVariant;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return variants.defaultVariant;
|
|
153
|
+
}
|