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
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export * from "./core.js";
|
|
2
|
+
export * from "./html-to-pdf.js";
|
|
3
|
+
export * from "./svg/index.js";
|
|
4
|
+
|
|
5
|
+
import { LayoutNode } from "./dom/node.js";
|
|
6
|
+
import { ComputedStyle } from "./css/style.js";
|
|
7
|
+
import { layoutTree } from "./layout/pipeline/layout-tree.js";
|
|
8
|
+
import type { Viewport } from "./geometry/box.js";
|
|
9
|
+
|
|
10
|
+
export function demoLayout(viewport: Viewport = { width: 800, height: 600 }): LayoutNode {
|
|
11
|
+
const root = new LayoutNode(new ComputedStyle());
|
|
12
|
+
const paragraph = new LayoutNode(
|
|
13
|
+
new ComputedStyle({
|
|
14
|
+
marginTop: 16,
|
|
15
|
+
marginBottom: 16,
|
|
16
|
+
}),
|
|
17
|
+
);
|
|
18
|
+
root.appendChild(paragraph);
|
|
19
|
+
|
|
20
|
+
layoutTree(root, viewport);
|
|
21
|
+
return root;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
25
|
+
import { log } from "./logging/debug.js";
|
|
26
|
+
|
|
27
|
+
const isMain = fileURLToPath(import.meta.url) === process.argv[1];
|
|
28
|
+
if (isMain) {
|
|
29
|
+
const tree = demoLayout();
|
|
30
|
+
log('INDEX', 'debug', "Root layout:", {
|
|
31
|
+
width: tree.box.contentWidth,
|
|
32
|
+
height: tree.box.contentHeight,
|
|
33
|
+
children: tree.children.length,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface FloatRect {
|
|
2
|
+
readonly top: number;
|
|
3
|
+
readonly bottom: number;
|
|
4
|
+
readonly inlineStart: number;
|
|
5
|
+
readonly inlineEnd: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface RegisteredFloat {
|
|
9
|
+
readonly side: "left" | "right";
|
|
10
|
+
readonly rect: FloatRect;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class FloatContext {
|
|
14
|
+
private readonly floats: RegisteredFloat[] = [];
|
|
15
|
+
|
|
16
|
+
register(side: "left" | "right", rect: FloatRect): void {
|
|
17
|
+
this.floats.push({ side, rect });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
bottom(side: "left" | "right"): number {
|
|
21
|
+
let result = 0;
|
|
22
|
+
for (const entry of this.floats) {
|
|
23
|
+
if (entry.side === side) {
|
|
24
|
+
result = Math.max(result, entry.rect.bottom);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
inlineOffsets(top: number, bottom: number, containingBlockWidth: number): { start: number; end: number } {
|
|
31
|
+
let leftOffset = 0;
|
|
32
|
+
let rightOffset = 0;
|
|
33
|
+
for (const { side, rect } of this.floats) {
|
|
34
|
+
if (!rangesOverlap(rect.top, rect.bottom, top, bottom)) {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (side === "left") {
|
|
38
|
+
leftOffset = Math.max(leftOffset, rect.inlineEnd);
|
|
39
|
+
} else {
|
|
40
|
+
rightOffset = Math.max(rightOffset, containingBlockWidth - rect.inlineStart);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
start: leftOffset,
|
|
45
|
+
end: containingBlockWidth - rightOffset,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
nextUnblockedY(top: number, bottom: number): number | null {
|
|
50
|
+
let candidate: number | null = null;
|
|
51
|
+
for (const { rect } of this.floats) {
|
|
52
|
+
if (rangesOverlap(rect.top, rect.bottom, top, bottom)) {
|
|
53
|
+
candidate = candidate === null ? rect.bottom : Math.min(candidate, rect.bottom);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return candidate;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function rangesOverlap(aStart: number, aEnd: number, bStart: number, bEnd: number): boolean {
|
|
61
|
+
return Math.max(aStart, bStart) < Math.min(aEnd, bEnd);
|
|
62
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Viewport } from "../../geometry/box.js";
|
|
2
|
+
import type { FontEmbedder } from "../../pdf/font/embedder.js";
|
|
3
|
+
import type { Environment } from "../../environment/environment.js";
|
|
4
|
+
|
|
5
|
+
export interface LayoutEnvironmentOptions {
|
|
6
|
+
viewport: Viewport;
|
|
7
|
+
fontEmbedder: FontEmbedder | null;
|
|
8
|
+
getEnv?: Environment["getEnv"];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class LayoutEnvironment {
|
|
12
|
+
private readonly envAccessor: Environment["getEnv"];
|
|
13
|
+
|
|
14
|
+
constructor(private readonly options: LayoutEnvironmentOptions) {
|
|
15
|
+
this.envAccessor = options.getEnv ?? (() => undefined);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
get viewport(): Viewport {
|
|
19
|
+
return this.options.viewport;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get fontEmbedder(): FontEmbedder | null {
|
|
23
|
+
return this.options.fontEmbedder;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
getEnv(name: string): string | undefined {
|
|
27
|
+
return this.envAccessor(name);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LayoutContext } from "./pipeline/strategy.js";
|
|
2
|
+
|
|
3
|
+
let LAYOUT_DEBUG: boolean | undefined;
|
|
4
|
+
|
|
5
|
+
const initialize = (context: LayoutContext) => {
|
|
6
|
+
if (LAYOUT_DEBUG === undefined) {
|
|
7
|
+
LAYOUT_DEBUG = context.env.getEnv("PAGYRA_DEBUG_LAYOUT") === "1";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const createLayoutDebug = (context: LayoutContext) => {
|
|
12
|
+
initialize(context);
|
|
13
|
+
return (...args: unknown[]): void => {
|
|
14
|
+
if (LAYOUT_DEBUG) {
|
|
15
|
+
console.log(...args);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { LayoutNode, type InlineRun } from "../../dom/node.js";
|
|
2
|
+
import { resolvedLineHeight } from "../../css/style.js";
|
|
3
|
+
import { isInlineDisplay } from "./inline-utils.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents a bounding rectangle with min/max coordinates
|
|
7
|
+
*/
|
|
8
|
+
interface BoundingRect {
|
|
9
|
+
minX: number;
|
|
10
|
+
minY: number;
|
|
11
|
+
maxX: number;
|
|
12
|
+
maxY: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Responsible for computing and propagating bounding boxes for inline nodes.
|
|
17
|
+
* Handles both the initial box calculation from runs and the propagation to ancestors.
|
|
18
|
+
*/
|
|
19
|
+
export class BoundingBoxCalculator {
|
|
20
|
+
private boundingBoxes = new Map<LayoutNode, BoundingRect>();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Compute per-node box sizes from their inline runs.
|
|
24
|
+
* Assigns box dimensions based on the runs' position and sizes.
|
|
25
|
+
*/
|
|
26
|
+
computeNodeBoxes(nodeRuns: Map<LayoutNode, InlineRun[]>): void {
|
|
27
|
+
for (const [node, runs] of nodeRuns.entries()) {
|
|
28
|
+
node.inlineRuns = runs;
|
|
29
|
+
node.lineBoxes = undefined;
|
|
30
|
+
|
|
31
|
+
const lineCount = runs.reduce((max, run) => Math.max(max, run.lineIndex + 1), 0);
|
|
32
|
+
const lh = resolvedLineHeight(node.style);
|
|
33
|
+
node.box.contentHeight = lineCount * lh;
|
|
34
|
+
|
|
35
|
+
// Calculate actual content width by finding the extent of all runs
|
|
36
|
+
// relative to the node's box.x position
|
|
37
|
+
if (runs.length > 0) {
|
|
38
|
+
// Find the actual extent of all runs from their positions and widths
|
|
39
|
+
// Initialize with the first run's values to avoid Infinity edge cases
|
|
40
|
+
const firstRun = runs[0];
|
|
41
|
+
let minX = firstRun.startX;
|
|
42
|
+
let maxX = firstRun.startX + firstRun.width;
|
|
43
|
+
for (let i = 1; i < runs.length; i++) {
|
|
44
|
+
const run = runs[i];
|
|
45
|
+
minX = Math.min(minX, run.startX);
|
|
46
|
+
maxX = Math.max(maxX, run.startX + run.width);
|
|
47
|
+
}
|
|
48
|
+
// The content width is the span from minX to maxX
|
|
49
|
+
// Since node.box.x is set to minX in run-placer, the content width is maxX - minX
|
|
50
|
+
const actualWidth = maxX - minX;
|
|
51
|
+
node.box.contentWidth = actualWidth;
|
|
52
|
+
} else {
|
|
53
|
+
node.box.contentWidth = 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
node.box.borderBoxWidth = node.box.contentWidth;
|
|
57
|
+
node.box.borderBoxHeight = node.box.contentHeight;
|
|
58
|
+
node.box.marginBoxWidth = node.box.borderBoxWidth;
|
|
59
|
+
node.box.marginBoxHeight = node.box.borderBoxHeight;
|
|
60
|
+
node.box.scrollWidth = Math.max(node.box.scrollWidth, node.box.contentWidth);
|
|
61
|
+
node.box.scrollHeight = Math.max(node.box.scrollHeight, node.box.contentHeight);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Propagate bounding boxes from text nodes to their inline ancestors.
|
|
67
|
+
* This ensures that container nodes (like spans) have a bounding box that encompasses their content,
|
|
68
|
+
* even if they didn't generate box items themselves (e.g. no padding/border).
|
|
69
|
+
*/
|
|
70
|
+
propagateBoundingBoxes(nodeRuns: Map<LayoutNode, InlineRun[]>, container: LayoutNode): void {
|
|
71
|
+
// Collect bounding boxes from all nodes with runs
|
|
72
|
+
for (const [node] of nodeRuns.entries()) {
|
|
73
|
+
const rect: BoundingRect = {
|
|
74
|
+
minX: node.box.x,
|
|
75
|
+
minY: node.box.y,
|
|
76
|
+
maxX: node.box.x + node.box.contentWidth,
|
|
77
|
+
maxY: node.box.y + node.box.contentHeight,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Propagate upwards to inline ancestors
|
|
81
|
+
let curr = node.parent;
|
|
82
|
+
while (curr && curr !== container && isInlineDisplay(curr.style.display)) {
|
|
83
|
+
this.updateBox(curr, rect);
|
|
84
|
+
curr = curr.parent;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Apply computed bounding boxes back to the nodes
|
|
89
|
+
for (const [node, rect] of this.boundingBoxes.entries()) {
|
|
90
|
+
node.box.x = rect.minX;
|
|
91
|
+
node.box.y = rect.minY;
|
|
92
|
+
node.box.contentWidth = rect.maxX - rect.minX;
|
|
93
|
+
node.box.contentHeight = rect.maxY - rect.minY;
|
|
94
|
+
node.box.borderBoxWidth = Math.max(node.box.borderBoxWidth, node.box.contentWidth);
|
|
95
|
+
node.box.borderBoxHeight = Math.max(node.box.borderBoxHeight, node.box.contentHeight);
|
|
96
|
+
node.box.marginBoxWidth = Math.max(node.box.marginBoxWidth, node.box.borderBoxWidth);
|
|
97
|
+
node.box.marginBoxHeight = Math.max(node.box.marginBoxHeight, node.box.borderBoxHeight);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Update or create a bounding box for a node by incorporating a new rectangle.
|
|
103
|
+
* Expands the existing bounding box to include the new rect.
|
|
104
|
+
*/
|
|
105
|
+
private updateBox(node: LayoutNode, rect: BoundingRect): void {
|
|
106
|
+
let current = this.boundingBoxes.get(node);
|
|
107
|
+
if (!current) {
|
|
108
|
+
// Seed with existing box if it appears valid (non-zero size), otherwise start with the new rect.
|
|
109
|
+
if (node.box.contentWidth > 0 || node.box.contentHeight > 0) {
|
|
110
|
+
current = {
|
|
111
|
+
minX: node.box.x,
|
|
112
|
+
minY: node.box.y,
|
|
113
|
+
maxX: node.box.x + node.box.contentWidth,
|
|
114
|
+
maxY: node.box.y + node.box.contentHeight,
|
|
115
|
+
};
|
|
116
|
+
// Union with the new rect
|
|
117
|
+
current.minX = Math.min(current.minX, rect.minX);
|
|
118
|
+
current.minY = Math.min(current.minY, rect.minY);
|
|
119
|
+
current.maxX = Math.max(current.maxX, rect.maxX);
|
|
120
|
+
current.maxY = Math.max(current.maxY, rect.maxY);
|
|
121
|
+
} else {
|
|
122
|
+
current = { ...rect };
|
|
123
|
+
}
|
|
124
|
+
this.boundingBoxes.set(node, current);
|
|
125
|
+
} else {
|
|
126
|
+
current.minX = Math.min(current.minX, rect.minX);
|
|
127
|
+
current.minY = Math.min(current.minY, rect.minY);
|
|
128
|
+
current.maxX = Math.max(current.maxX, rect.maxX);
|
|
129
|
+
current.maxY = Math.max(current.maxY, rect.maxY);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { FontMetrics } from "../../fonts/types.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default ascent ratio for fonts when metrics are unavailable.
|
|
5
|
+
* Most fonts have an ascent around 75-80% of the font size.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_ASCENT_RATIO = 0.75;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Calculate the baseline position for a line of text.
|
|
11
|
+
*
|
|
12
|
+
* The baseline is the invisible line on which text sits. In proper typography,
|
|
13
|
+
* the baseline should be positioned based on the font's ascent (the height
|
|
14
|
+
* above the baseline where ascenders like 'h', 'b' extend).
|
|
15
|
+
*
|
|
16
|
+
* When line-height is larger than font-size, we need to account for "half-leading"
|
|
17
|
+
* (the extra space distributed equally above and below the text).
|
|
18
|
+
*
|
|
19
|
+
* @param lineTop - The Y coordinate of the top of the line box
|
|
20
|
+
* @param fontSize - The font size in pixels
|
|
21
|
+
* @param lineHeight - The line height in pixels
|
|
22
|
+
* @param fontMetrics - Optional font metrics for precise calculations
|
|
23
|
+
* @returns The Y coordinate of the baseline
|
|
24
|
+
*/
|
|
25
|
+
export function calculateBaseline(
|
|
26
|
+
lineTop: number,
|
|
27
|
+
fontSize: number,
|
|
28
|
+
lineHeight: number,
|
|
29
|
+
fontMetrics?: FontMetrics | null
|
|
30
|
+
): number {
|
|
31
|
+
let ascent: number;
|
|
32
|
+
|
|
33
|
+
if (fontMetrics) {
|
|
34
|
+
// Use actual font metrics when available
|
|
35
|
+
const { metrics } = fontMetrics;
|
|
36
|
+
const unitsPerEm = metrics.unitsPerEm;
|
|
37
|
+
const ascentUnits = metrics.ascender;
|
|
38
|
+
|
|
39
|
+
// Convert font units to pixels
|
|
40
|
+
ascent = (ascentUnits / unitsPerEm) * fontSize;
|
|
41
|
+
} else {
|
|
42
|
+
// Use heuristic when font metrics unavailable
|
|
43
|
+
ascent = fontSize * DEFAULT_ASCENT_RATIO;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Calculate half-leading (extra space above/below the text)
|
|
47
|
+
const leading = lineHeight - fontSize;
|
|
48
|
+
const halfLeading = leading / 2;
|
|
49
|
+
|
|
50
|
+
// Baseline is at: lineTop + halfLeading + ascent
|
|
51
|
+
return lineTop + halfLeading + ascent;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get font metrics ascent ratio for a given font.
|
|
56
|
+
* Returns the ratio of ascent to font size.
|
|
57
|
+
*
|
|
58
|
+
* @param fontMetrics - Font metrics
|
|
59
|
+
* @returns Ascent ratio (typically 0.7-0.9)
|
|
60
|
+
*/
|
|
61
|
+
export function getAscentRatio(fontMetrics: FontMetrics): number {
|
|
62
|
+
const { metrics } = fontMetrics;
|
|
63
|
+
return metrics.ascender / metrics.unitsPerEm;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get font metrics descent ratio for a given font.
|
|
68
|
+
* Returns the ratio of descent to font size (negative value).
|
|
69
|
+
*
|
|
70
|
+
* @param fontMetrics - Font metrics
|
|
71
|
+
* @returns Descent ratio (typically -0.2 to -0.3)
|
|
72
|
+
*/
|
|
73
|
+
export function getDescentRatio(fontMetrics: FontMetrics): number {
|
|
74
|
+
const { metrics } = fontMetrics;
|
|
75
|
+
return metrics.descender / metrics.unitsPerEm;
|
|
76
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { LayoutNode } from "../../dom/node.js";
|
|
2
|
+
import { Display, FloatMode } from "../../css/enums.js";
|
|
3
|
+
import { resolveLength } from "../../css/length.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resolves the text-align property by walking up the tree to find the first valid value.
|
|
7
|
+
* Returns undefined if no valid value is found.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveInlineTextAlign(node: LayoutNode): string | undefined {
|
|
10
|
+
let current: LayoutNode | null = node;
|
|
11
|
+
while (current) {
|
|
12
|
+
const value = current.style.textAlign;
|
|
13
|
+
if (value) {
|
|
14
|
+
const normalized = value.toLowerCase();
|
|
15
|
+
if (normalized !== "start" && normalized !== "auto") {
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
current = current.parent;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Checks if a display mode is an inline-type display.
|
|
26
|
+
*/
|
|
27
|
+
export function isInlineDisplay(display: Display): boolean {
|
|
28
|
+
switch (display) {
|
|
29
|
+
case Display.Inline:
|
|
30
|
+
case Display.InlineBlock:
|
|
31
|
+
case Display.InlineFlex:
|
|
32
|
+
case Display.InlineGrid:
|
|
33
|
+
case Display.InlineTable:
|
|
34
|
+
return true;
|
|
35
|
+
default:
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Determines if a node should layout its inline children.
|
|
42
|
+
*/
|
|
43
|
+
export function shouldLayoutInlineChildren(node: LayoutNode): boolean {
|
|
44
|
+
if (node.children.length === 0) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (node.style.display !== Display.Inline) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Collects child nodes that participate in inline layout.
|
|
55
|
+
* Filters out nodes with display:none, floated nodes, and non-inline display modes.
|
|
56
|
+
*/
|
|
57
|
+
export function collectInlineParticipants(node: LayoutNode): LayoutNode[] {
|
|
58
|
+
const participants: LayoutNode[] = [];
|
|
59
|
+
for (const child of node.children) {
|
|
60
|
+
if (child.style.display === Display.None) {
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (child.style.float !== FloatMode.None) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (!isInlineDisplay(child.style.display)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
participants.push(child);
|
|
70
|
+
}
|
|
71
|
+
return participants;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Calculates the inline extent (start and end positions) of a node within its container.
|
|
76
|
+
* Includes margins, borders, and padding in the calculation.
|
|
77
|
+
*/
|
|
78
|
+
export function inlineExtentWithinContainer(node: LayoutNode, referenceWidth: number): { start: number; end: number } {
|
|
79
|
+
const marginLeft = resolveLength(node.style.marginLeft, referenceWidth, { auto: "zero" });
|
|
80
|
+
const marginRight = resolveLength(node.style.marginRight, referenceWidth, { auto: "zero" });
|
|
81
|
+
const paddingLeft = resolveLength(node.style.paddingLeft, referenceWidth, { auto: "zero" });
|
|
82
|
+
const paddingRight = resolveLength(node.style.paddingRight, referenceWidth, { auto: "zero" });
|
|
83
|
+
const borderLeft = resolveLength(node.style.borderLeft, referenceWidth, { auto: "zero" });
|
|
84
|
+
const borderRight = resolveLength(node.style.borderRight, referenceWidth, { auto: "zero" });
|
|
85
|
+
|
|
86
|
+
const marginStart = node.box.x - paddingLeft - borderLeft - marginLeft;
|
|
87
|
+
const width =
|
|
88
|
+
node.box.contentWidth + paddingLeft + paddingRight + borderLeft + borderRight + marginLeft + marginRight;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
start: marginStart,
|
|
92
|
+
end: marginStart + width,
|
|
93
|
+
};
|
|
94
|
+
}
|