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,321 @@
|
|
|
1
|
+
// ===== text/line-breaker.ts =====
|
|
2
|
+
|
|
3
|
+
import { WhiteSpace } from "../css/enums.js";
|
|
4
|
+
import { ComputedStyle } from "../css/style.js";
|
|
5
|
+
import { estimateLineWidth, measureTextWithGlyphs } from "../layout/utils/text-metrics.js";
|
|
6
|
+
import type { FontEmbedder } from "../pdf/font/embedder.js";
|
|
7
|
+
import { applyTextTransform } from "./text-transform.js"; // Precisaremos exportar esta função
|
|
8
|
+
|
|
9
|
+
// Representa uma unidade inquebrável (palavra) ou um espaço flexível (cola).
|
|
10
|
+
export interface TextItem {
|
|
11
|
+
type: 'word' | 'space';
|
|
12
|
+
text: string;
|
|
13
|
+
width: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// O resultado da quebra de linha para um nó de texto.
|
|
17
|
+
export interface LineBox {
|
|
18
|
+
text: string;
|
|
19
|
+
width: number;
|
|
20
|
+
spaceCount: number;
|
|
21
|
+
targetWidth: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Segmenta uma string de texto em palavras e espaços.
|
|
26
|
+
*/
|
|
27
|
+
function segmentText(text: string): { type: 'word' | 'space', text: string }[] {
|
|
28
|
+
// Uma segmentação simples baseada em espaços. Uma implementação mais robusta
|
|
29
|
+
// poderia usar Intl.Segmenter ou lidar com múltiplos tipos de espaços.
|
|
30
|
+
const segments: { type: 'word' | 'space', text: string }[] = [];
|
|
31
|
+
const regex = /(\s+)|([^\s]+)/g;
|
|
32
|
+
let match;
|
|
33
|
+
while ((match = regex.exec(text)) !== null) {
|
|
34
|
+
if (match[1]) { // É um espaço
|
|
35
|
+
segments.push({ type: 'space', text: match[1] });
|
|
36
|
+
} else if (match[2]) { // É uma palavra
|
|
37
|
+
segments.push({ type: 'word', text: match[2] });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return segments;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Mede a largura de cada palavra e espaço.
|
|
45
|
+
*/
|
|
46
|
+
function measureItems(
|
|
47
|
+
segments: { type: 'word' | 'space', text: string }[],
|
|
48
|
+
style: ComputedStyle,
|
|
49
|
+
fontEmbedder: FontEmbedder | null
|
|
50
|
+
): TextItem[] {
|
|
51
|
+
const fontWeight = typeof style.fontWeight === "number" ? style.fontWeight : 400;
|
|
52
|
+
const fontStyle = style.fontStyle ?? "normal";
|
|
53
|
+
const fontMetrics = fontEmbedder?.getMetrics(style.fontFamily ?? "", fontWeight, fontStyle);
|
|
54
|
+
|
|
55
|
+
return segments.map(s => {
|
|
56
|
+
const glyphWidth = measureTextWithGlyphs(s.text, style, fontMetrics ?? null);
|
|
57
|
+
return {
|
|
58
|
+
...s,
|
|
59
|
+
width: glyphWidth ?? estimateLineWidth(s.text, style),
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function splitWordItem(
|
|
65
|
+
item: TextItem,
|
|
66
|
+
style: ComputedStyle,
|
|
67
|
+
availableWidth: number
|
|
68
|
+
): TextItem[] {
|
|
69
|
+
if (availableWidth <= 0) {
|
|
70
|
+
return [item];
|
|
71
|
+
}
|
|
72
|
+
const pieces: TextItem[] = [];
|
|
73
|
+
let buffer = "";
|
|
74
|
+
let bufferWidth = 0;
|
|
75
|
+
|
|
76
|
+
const flush = () => {
|
|
77
|
+
if (!buffer) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
pieces.push({ type: "word", text: buffer, width: bufferWidth });
|
|
81
|
+
buffer = "";
|
|
82
|
+
bufferWidth = 0;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
for (const char of Array.from(item.text)) {
|
|
86
|
+
const candidate = buffer + char;
|
|
87
|
+
const candidateWidth = estimateLineWidth(candidate, style);
|
|
88
|
+
|
|
89
|
+
if (buffer && candidateWidth > availableWidth) {
|
|
90
|
+
flush();
|
|
91
|
+
buffer = char;
|
|
92
|
+
bufferWidth = estimateLineWidth(char, style);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!buffer && candidateWidth > availableWidth) {
|
|
97
|
+
pieces.push({ type: "word", text: char, width: candidateWidth });
|
|
98
|
+
buffer = "";
|
|
99
|
+
bufferWidth = 0;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
buffer = candidate;
|
|
104
|
+
bufferWidth = candidateWidth;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
flush();
|
|
108
|
+
return pieces.length ? pieces : [item];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function enforceOverflowWrap(
|
|
112
|
+
items: TextItem[],
|
|
113
|
+
style: ComputedStyle,
|
|
114
|
+
availableWidth: number,
|
|
115
|
+
mode: ComputedStyle["overflowWrap"] | undefined
|
|
116
|
+
): TextItem[] {
|
|
117
|
+
if (!mode || mode === "normal") {
|
|
118
|
+
return items;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const adjusted: TextItem[] = [];
|
|
122
|
+
for (const item of items) {
|
|
123
|
+
if (item.type !== "word") {
|
|
124
|
+
adjusted.push(item);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (item.width <= availableWidth) {
|
|
128
|
+
adjusted.push(item);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
adjusted.push(...splitWordItem(item, style, availableWidth));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return adjusted.length ? adjusted : items;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function countJustifiableSpaces(items: TextItem[]): number {
|
|
138
|
+
let count = 0;
|
|
139
|
+
for (let index = 0; index < items.length; index++) {
|
|
140
|
+
const item = items[index];
|
|
141
|
+
if (item.type !== "space") {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const hasWordBefore = items.slice(0, index).some((candidate) => candidate.type === "word");
|
|
145
|
+
if (!hasWordBefore) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const hasWordAfter = items.slice(index + 1).some((candidate) => candidate.type === "word");
|
|
149
|
+
if (hasWordAfter) {
|
|
150
|
+
count += 1;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return count;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function shouldTrimLineEdges(style: ComputedStyle): boolean {
|
|
157
|
+
const mode = style.whiteSpace;
|
|
158
|
+
return (
|
|
159
|
+
mode === WhiteSpace.Normal ||
|
|
160
|
+
mode === WhiteSpace.NoWrap ||
|
|
161
|
+
mode === WhiteSpace.PreLine
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function buildLineBox(items: TextItem[], availableWidth: number, trimEdges: boolean): LineBox | null {
|
|
166
|
+
let start = 0;
|
|
167
|
+
let end = items.length;
|
|
168
|
+
|
|
169
|
+
if (trimEdges) {
|
|
170
|
+
while (start < end && items[start].type === "space") {
|
|
171
|
+
start += 1;
|
|
172
|
+
}
|
|
173
|
+
while (end > start && items[end - 1].type === "space") {
|
|
174
|
+
end -= 1;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (start >= end) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const trimmed = items.slice(start, end);
|
|
183
|
+
const text = trimmed.map((it) => it.text).join("");
|
|
184
|
+
const width = trimmed.reduce((sum, it) => sum + it.width, 0);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
text,
|
|
188
|
+
width,
|
|
189
|
+
spaceCount: countJustifiableSpaces(trimmed),
|
|
190
|
+
targetWidth: availableWidth,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Implementa um algoritmo de quebra de linha inspirado em Knuth-Plass
|
|
196
|
+
* usando programação dinâmica para encontrar o layout ótimo.
|
|
197
|
+
*
|
|
198
|
+
* @param text O texto a ser quebrado.
|
|
199
|
+
* @param style O estilo computado a ser usado para medição.
|
|
200
|
+
* @param availableWidth A largura disponível para o texto.
|
|
201
|
+
* @returns Um array de objetos LineBox representando as linhas ótimas.
|
|
202
|
+
*/
|
|
203
|
+
export function breakTextIntoLines(
|
|
204
|
+
text: string,
|
|
205
|
+
style: ComputedStyle,
|
|
206
|
+
availableWidth: number,
|
|
207
|
+
fontEmbedder: FontEmbedder | null = null
|
|
208
|
+
): LineBox[] {
|
|
209
|
+
const effectiveText = applyTextTransform(text, style.textTransform);
|
|
210
|
+
if (effectiveText.length === 0) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const rawItems = segmentText(effectiveText);
|
|
215
|
+
let items = measureItems(rawItems, style, fontEmbedder);
|
|
216
|
+
items = enforceOverflowWrap(items, style, availableWidth, style.overflowWrap);
|
|
217
|
+
const n = items.length;
|
|
218
|
+
if (n === 0) return [];
|
|
219
|
+
const trimEdges = shouldTrimLineEdges(style);
|
|
220
|
+
|
|
221
|
+
// Check if entire text fits on one line - if so, keep a single trimmed line
|
|
222
|
+
const totalWidth = items.reduce((sum, it) => sum + it.width, 0);
|
|
223
|
+
if (totalWidth <= availableWidth) {
|
|
224
|
+
const singleLine = buildLineBox(items, availableWidth, trimEdges);
|
|
225
|
+
return singleLine ? [singleLine] : [];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// memo[i] armazena o custo mínimo (feiura) para quebrar os primeiros `i` itens.
|
|
229
|
+
const memo: number[] = new Array(n + 1).fill(Infinity);
|
|
230
|
+
// breaks[i] armazena o índice do início da última linha na quebra ótima para os primeiros `i` itens.
|
|
231
|
+
const breaks: number[] = new Array(n + 1).fill(0);
|
|
232
|
+
|
|
233
|
+
memo[0] = 0;
|
|
234
|
+
|
|
235
|
+
for (let i = 1; i <= n; i++) {
|
|
236
|
+
let lineWidth = 0;
|
|
237
|
+
let hasWord = false;
|
|
238
|
+
for (let j = i; j > 0; j--) {
|
|
239
|
+
const item = items[j - 1];
|
|
240
|
+
|
|
241
|
+
if (item.type === "space") {
|
|
242
|
+
if (!hasWord && trimEdges) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
lineWidth += item.width;
|
|
246
|
+
if (lineWidth > availableWidth) {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
if (!trimEdges && !hasWord) {
|
|
250
|
+
const slack = availableWidth - lineWidth;
|
|
251
|
+
const cost = 100 + slack * slack;
|
|
252
|
+
if (memo[j - 1] + cost < memo[i]) {
|
|
253
|
+
memo[i] = memo[j - 1] + cost;
|
|
254
|
+
breaks[i] = j - 1;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
lineWidth += item.width;
|
|
261
|
+
hasWord = true;
|
|
262
|
+
|
|
263
|
+
if (lineWidth > availableWidth) {
|
|
264
|
+
break; // Esta linha é longa demais, não há como continuar a partir deste `j`.
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const slack = availableWidth - lineWidth;
|
|
268
|
+
const cost = 100 + slack * slack;
|
|
269
|
+
|
|
270
|
+
if (memo[j - 1] + cost < memo[i]) {
|
|
271
|
+
memo[i] = memo[j - 1] + cost;
|
|
272
|
+
breaks[i] = j - 1;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Se memo[n] é infinito, significa que uma única palavra é mais larga que
|
|
278
|
+
// a linha, então recorremos a uma quebra forçada.
|
|
279
|
+
if (!isFinite(memo[n])) {
|
|
280
|
+
const lines: LineBox[] = [];
|
|
281
|
+
let currentWidth = 0;
|
|
282
|
+
let currentItems: TextItem[] = [];
|
|
283
|
+
const pushCurrent = () => {
|
|
284
|
+
const line = buildLineBox(currentItems, availableWidth, trimEdges);
|
|
285
|
+
if (line) {
|
|
286
|
+
lines.push(line);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
for (const item of items) {
|
|
290
|
+
if (trimEdges && item.type === "space" && currentItems.length === 0) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
if (item.type === 'word' && currentItems.length > 0 && currentWidth + item.width > availableWidth) {
|
|
294
|
+
pushCurrent();
|
|
295
|
+
currentWidth = 0;
|
|
296
|
+
currentItems = [];
|
|
297
|
+
}
|
|
298
|
+
currentItems.push(item);
|
|
299
|
+
currentWidth += item.width;
|
|
300
|
+
}
|
|
301
|
+
if (currentItems.length > 0) {
|
|
302
|
+
pushCurrent();
|
|
303
|
+
}
|
|
304
|
+
return lines;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Reconstitui o caminho ótimo usando os backpointers em `breaks`.
|
|
308
|
+
const lines: LineBox[] = [];
|
|
309
|
+
let current = n;
|
|
310
|
+
while (current > 0) {
|
|
311
|
+
const prev = breaks[current];
|
|
312
|
+
const lineItems = items.slice(prev, current);
|
|
313
|
+
const line = buildLineBox(lineItems, availableWidth, trimEdges);
|
|
314
|
+
if (line) {
|
|
315
|
+
lines.unshift(line);
|
|
316
|
+
}
|
|
317
|
+
current = prev;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return lines;
|
|
321
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { TextTransform } from "../css/style.js";
|
|
2
|
+
|
|
3
|
+
const LETTER_OR_NUMBER = /[\p{L}\p{N}]/u;
|
|
4
|
+
const DEFAULT_LOCALE = "en-US";
|
|
5
|
+
|
|
6
|
+
function capitalizeText(text: string): string {
|
|
7
|
+
let result = "";
|
|
8
|
+
let capitalizeNext = true;
|
|
9
|
+
|
|
10
|
+
for (const char of text) {
|
|
11
|
+
if (LETTER_OR_NUMBER.test(char)) {
|
|
12
|
+
if (capitalizeNext) {
|
|
13
|
+
result += char.toLocaleUpperCase(DEFAULT_LOCALE);
|
|
14
|
+
capitalizeNext = false;
|
|
15
|
+
} else {
|
|
16
|
+
result += char.toLocaleLowerCase(DEFAULT_LOCALE);
|
|
17
|
+
}
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
capitalizeNext = true;
|
|
22
|
+
result += char;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function applyTextTransform(text: string, transform?: TextTransform): string {
|
|
29
|
+
if (!text || !transform || transform === "none") {
|
|
30
|
+
return text;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
switch (transform) {
|
|
34
|
+
case "uppercase":
|
|
35
|
+
return text.toLocaleUpperCase(DEFAULT_LOCALE);
|
|
36
|
+
case "lowercase":
|
|
37
|
+
return text.toLocaleLowerCase(DEFAULT_LOCALE);
|
|
38
|
+
case "capitalize":
|
|
39
|
+
return capitalizeText(text);
|
|
40
|
+
default:
|
|
41
|
+
return text;
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/text/text.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* The UNICODE_TO_WIN_ANSI map is defined in pdf/utils/encoding.ts */
|
|
2
|
+
import { UNICODE_TO_WIN_ANSI } from "../pdf/utils/encoding.js";
|
|
3
|
+
|
|
4
|
+
export function needsUnicode(text: string): boolean {
|
|
5
|
+
for (const ch of Array.from(text)) {
|
|
6
|
+
const cp = ch.codePointAt(0)!;
|
|
7
|
+
if (!UNICODE_TO_WIN_ANSI.has(cp)) return true; // ✓ ★, combining, etc.
|
|
8
|
+
}
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Extend Intl type for Segmenter
|
|
13
|
+
declare global {
|
|
14
|
+
namespace Intl {
|
|
15
|
+
class Segmenter {
|
|
16
|
+
constructor(locales?: string | string[], options?: any);
|
|
17
|
+
segment(input: string): any;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// @ts-ignore: Intl.Segmenter may not be available in older environments
|
|
23
|
+
export function normalizeAndSegment(text: string): string[] {
|
|
24
|
+
const normalized = text.normalize("NFC");
|
|
25
|
+
// Fallback for environments without Intl.Segmenter
|
|
26
|
+
if (typeof Intl !== "undefined" && Intl.Segmenter) {
|
|
27
|
+
const seg = new Intl.Segmenter("pt", { granularity: "grapheme" });
|
|
28
|
+
return [...seg.segment(normalized)].map(s => s.segment);
|
|
29
|
+
} else {
|
|
30
|
+
// Simple grapheme splitting by character (not perfect but better than nothing)
|
|
31
|
+
return Array.from(normalized);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { identityMatrix, multiplyMatrices } from "../geometry/matrix.js";
|
|
2
|
+
import type { Matrix } from "../geometry/matrix.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Parse CSS/SVG transform string into a Matrix using the SVG convention.
|
|
6
|
+
* This parser follows the SVG/CSS syntax and semantics and does NOT adapt
|
|
7
|
+
* the resulting matrix to any target coordinate system (e.g., PDF).
|
|
8
|
+
*
|
|
9
|
+
* Returned matrix components are in the same units as the input values
|
|
10
|
+
* (typically px for translate).
|
|
11
|
+
*/
|
|
12
|
+
export function parseTransform(raw: string | undefined): Matrix | null {
|
|
13
|
+
if (!raw) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const regex = /([a-zA-Z]+)\(([^)]*)\)/g;
|
|
17
|
+
let match: RegExpExecArray | null;
|
|
18
|
+
let current = identityMatrix();
|
|
19
|
+
let found = false;
|
|
20
|
+
while ((match = regex.exec(raw)) !== null) {
|
|
21
|
+
const type = match[1].toLowerCase();
|
|
22
|
+
const params = parseNumberList(match[2]);
|
|
23
|
+
const matrix = transformFromValues(type, params);
|
|
24
|
+
if (matrix) {
|
|
25
|
+
current = multiplyMatrices(current, matrix);
|
|
26
|
+
found = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return found ? current : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function transformFromValues(type: string, values: number[]): Matrix | null {
|
|
33
|
+
switch (type) {
|
|
34
|
+
case "matrix":
|
|
35
|
+
if (values.length >= 6) {
|
|
36
|
+
return {
|
|
37
|
+
a: values[0],
|
|
38
|
+
b: values[1],
|
|
39
|
+
c: values[2],
|
|
40
|
+
d: values[3],
|
|
41
|
+
e: values[4],
|
|
42
|
+
f: values[5],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
case "translate": {
|
|
47
|
+
const tx = Number.isFinite(values[0]) ? values[0] : 0;
|
|
48
|
+
const ty = Number.isFinite(values[1]) ? values[1] : 0;
|
|
49
|
+
return { a: 1, b: 0, c: 0, d: 1, e: tx, f: ty };
|
|
50
|
+
}
|
|
51
|
+
case "scale": {
|
|
52
|
+
const sx = Number.isFinite(values[0]) ? values[0] : 1;
|
|
53
|
+
const sy = Number.isFinite(values[1]) ? values[1] : sx;
|
|
54
|
+
return { a: sx, b: 0, c: 0, d: sy, e: 0, f: 0 };
|
|
55
|
+
}
|
|
56
|
+
case "rotate": {
|
|
57
|
+
// SVG rotate(angle [, cx, cy])
|
|
58
|
+
const angle = (Number.isFinite(values[0]) ? values[0] : 0) * (Math.PI / 180);
|
|
59
|
+
const cos = Math.cos(angle);
|
|
60
|
+
const sin = Math.sin(angle);
|
|
61
|
+
let base: Matrix = { a: cos, b: sin, c: -sin, d: cos, e: 0, f: 0 };
|
|
62
|
+
if (values.length >= 3 && Number.isFinite(values[1]) && Number.isFinite(values[2])) {
|
|
63
|
+
const cx = values[1];
|
|
64
|
+
const cy = values[2];
|
|
65
|
+
const translateTo: Matrix = { a: 1, b: 0, c: 0, d: 1, e: cx, f: cy };
|
|
66
|
+
const translateBack: Matrix = { a: 1, b: 0, c: 0, d: 1, e: -cx, f: -cy };
|
|
67
|
+
base = multiplyMatrices(translateTo, multiplyMatrices(base, translateBack));
|
|
68
|
+
}
|
|
69
|
+
return base;
|
|
70
|
+
}
|
|
71
|
+
case "skewx": {
|
|
72
|
+
const angle = (Number.isFinite(values[0]) ? values[0] : 0) * (Math.PI / 180);
|
|
73
|
+
return { a: 1, b: 0, c: Math.tan(angle), d: 1, e: 0, f: 0 };
|
|
74
|
+
}
|
|
75
|
+
case "skewy": {
|
|
76
|
+
const angle = (Number.isFinite(values[0]) ? values[0] : 0) * (Math.PI / 180);
|
|
77
|
+
return { a: 1, b: Math.tan(angle), c: 0, d: 1, e: 0, f: 0 };
|
|
78
|
+
}
|
|
79
|
+
default:
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function parseNumberList(value: string): number[] {
|
|
85
|
+
const result: number[] = [];
|
|
86
|
+
const regex = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/g;
|
|
87
|
+
let match: RegExpExecArray | null;
|
|
88
|
+
while ((match = regex.exec(value)) !== null) {
|
|
89
|
+
const parsed = Number.parseFloat(match[0]);
|
|
90
|
+
if (Number.isFinite(parsed)) {
|
|
91
|
+
result.push(parsed);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface FontConfig {
|
|
2
|
+
readonly fontFaceDefs: FontFaceDef[];
|
|
3
|
+
readonly defaultStack: string[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface FontFaceDef {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly family: string;
|
|
9
|
+
readonly weight: number;
|
|
10
|
+
readonly style: 'normal' | 'italic';
|
|
11
|
+
readonly src: string; // path to TTF file
|
|
12
|
+
readonly data?: ArrayBuffer;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TtfMetrics {
|
|
16
|
+
readonly unitsPerEm: number;
|
|
17
|
+
readonly ascender: number;
|
|
18
|
+
readonly descender: number;
|
|
19
|
+
readonly lineGap: number;
|
|
20
|
+
readonly capHeight: number;
|
|
21
|
+
readonly xHeight: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface GlyphMetrics {
|
|
25
|
+
readonly advanceWidth: number;
|
|
26
|
+
readonly leftSideBearing: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type KerningMap = Map<number, Map<number, number>>;
|
|
30
|
+
|
|
31
|
+
export interface CmapData {
|
|
32
|
+
readonly getGlyphId: (codePoint: number) => number;
|
|
33
|
+
readonly hasCodePoint: (codePoint: number) => boolean;
|
|
34
|
+
readonly unicodeMap: Map<number, number>; // Internal access for CMap generation
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type GlyphOutlineCmd =
|
|
38
|
+
| { type: "moveTo"; x: number; y: number }
|
|
39
|
+
| { type: "lineTo"; x: number; y: number }
|
|
40
|
+
| { type: "quadTo"; cx: number; cy: number; x: number; y: number } // quadratic Bézier
|
|
41
|
+
| { type: "cubicTo"; cx1: number; cy1: number; cx2: number; cy2: number; x: number; y: number } // cubic Bézier
|
|
42
|
+
| { type: "close" };
|
|
43
|
+
|
|
44
|
+
export class TtfFontMetrics {
|
|
45
|
+
constructor(
|
|
46
|
+
public readonly metrics: TtfMetrics,
|
|
47
|
+
public readonly glyphMetrics: Map<number, GlyphMetrics>,
|
|
48
|
+
public readonly cmap: CmapData,
|
|
49
|
+
// optional head bbox in font units [xMin, yMin, xMax, yMax]
|
|
50
|
+
public readonly headBBox?: readonly [number, number, number, number],
|
|
51
|
+
/**
|
|
52
|
+
* Optional hook that returns a glyph's outline command sequence.
|
|
53
|
+
* Present to prepare the API for future glyf / CFF parsing; placeholder
|
|
54
|
+
* implementations should return null when outlines aren't available.
|
|
55
|
+
*/
|
|
56
|
+
public readonly getGlyphOutline?: (gid: number) => GlyphOutlineCmd[] | null,
|
|
57
|
+
/**
|
|
58
|
+
* Optional kerning map (left GID -> right GID -> adjustment in font units).
|
|
59
|
+
*/
|
|
60
|
+
public readonly kerning?: KerningMap
|
|
61
|
+
) {}
|
|
62
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ViewportPx { width: number; height: number; }
|
|
2
|
+
export interface PageMarginsPx { top: number; right: number; bottom: number; left: number; }
|
|
3
|
+
|
|
4
|
+
export interface RenderHtmlOptions {
|
|
5
|
+
html: string;
|
|
6
|
+
css?: string;
|
|
7
|
+
viewport: ViewportPx;
|
|
8
|
+
page: { widthPx: number; heightPx: number; marginsPx: PageMarginsPx };
|
|
9
|
+
debug?: { level?: 'trace'|'debug'|'info'|'warn'|'error'; cats?: string[] };
|
|
10
|
+
fontConfig?: unknown; // keep your current type if you have one
|
|
11
|
+
resourceBaseDir?: string;
|
|
12
|
+
assetRootDir?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface PreparedRender {
|
|
16
|
+
layoutRoot: unknown; // use your LayoutNode
|
|
17
|
+
renderTree: unknown; // use your RenderTree
|
|
18
|
+
pageSizePt: { width: number; height: number };
|
|
19
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// src/units/page-utils.ts
|
|
2
|
+
|
|
3
|
+
import { ptToPx } from "./units.js";
|
|
4
|
+
|
|
5
|
+
export interface PageMarginsPx {
|
|
6
|
+
top: number;
|
|
7
|
+
right: number;
|
|
8
|
+
bottom: number;
|
|
9
|
+
left: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_PAGE_SIZE_PT = { width: 595.28, height: 841.89 };
|
|
13
|
+
export const DEFAULT_PAGE_MARGINS_PT = { top: 36, right: 36, bottom: 36, left: 36 };
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_PAGE_WIDTH_PX = ptToPx(DEFAULT_PAGE_SIZE_PT.width);
|
|
16
|
+
export const DEFAULT_PAGE_HEIGHT_PX = ptToPx(DEFAULT_PAGE_SIZE_PT.height);
|
|
17
|
+
|
|
18
|
+
export const DEFAULT_PAGE_MARGINS_PX = {
|
|
19
|
+
top: ptToPx(DEFAULT_PAGE_MARGINS_PT.top),
|
|
20
|
+
right: ptToPx(DEFAULT_PAGE_MARGINS_PT.right),
|
|
21
|
+
bottom: ptToPx(DEFAULT_PAGE_MARGINS_PT.bottom),
|
|
22
|
+
left: ptToPx(DEFAULT_PAGE_MARGINS_PT.left),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function resolvePageMarginsPx(pageWidthPx: number, pageHeightPx: number): PageMarginsPx {
|
|
26
|
+
// ... (implementation from html-to-pdf.ts)
|
|
27
|
+
const margins = { ...DEFAULT_PAGE_MARGINS_PX };
|
|
28
|
+
const horizontalSum = margins.left + margins.right;
|
|
29
|
+
const verticalSum = margins.top + margins.bottom;
|
|
30
|
+
const usableWidth = maxContentDimension(pageWidthPx, 0);
|
|
31
|
+
const usableHeight = maxContentDimension(pageHeightPx, 0);
|
|
32
|
+
|
|
33
|
+
if (horizontalSum > usableWidth) {
|
|
34
|
+
const scale = usableWidth / (horizontalSum || 1);
|
|
35
|
+
margins.left *= scale;
|
|
36
|
+
margins.right *= scale;
|
|
37
|
+
}
|
|
38
|
+
if (verticalSum > usableHeight) {
|
|
39
|
+
const scale = usableHeight / (verticalSum || 1);
|
|
40
|
+
margins.top *= scale;
|
|
41
|
+
margins.bottom *= scale;
|
|
42
|
+
}
|
|
43
|
+
return margins;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function sanitizeDimension(value: number | undefined, fallback: number): number {
|
|
47
|
+
// ... (implementation from html-to-pdf.ts)
|
|
48
|
+
if (!Number.isFinite(value ?? NaN)) {
|
|
49
|
+
return fallback;
|
|
50
|
+
}
|
|
51
|
+
const sanitized = Number(value);
|
|
52
|
+
return sanitized > 0 ? sanitized : fallback;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function maxContentDimension(total: number, marginsSum: number): number {
|
|
56
|
+
// ... (implementation from html-to-pdf.ts)
|
|
57
|
+
return Math.max(1, total - marginsSum);
|
|
58
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// src/units/units.ts
|
|
2
|
+
|
|
3
|
+
import { parseLength, parseLengthOrPercent } from "../css/parsers/length-parser.js";
|
|
4
|
+
|
|
5
|
+
const DPI = 96;
|
|
6
|
+
const INCHES_PER_CM = 1 / 2.54;
|
|
7
|
+
|
|
8
|
+
export function cmToPx(cm: number): number {
|
|
9
|
+
return cm * INCHES_PER_CM * DPI;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function mmToPx(mm: number): number {
|
|
13
|
+
return (mm / 10) * INCHES_PER_CM * DPI;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function qToPx(q: number): number {
|
|
17
|
+
return (q / 40) * INCHES_PER_CM * DPI;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function inToPx(inches: number): number {
|
|
21
|
+
return inches * DPI;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function pcToPx(pc: number): number {
|
|
25
|
+
return pc * (DPI / 6);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ptToPx(pt: number): number {
|
|
29
|
+
return pt * (DPI / 72);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function pxToPt(px: number): number {
|
|
33
|
+
return px * (72 / DPI);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface UnitCtx {
|
|
37
|
+
viewport: {
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function makeUnitParsers(ctx: UnitCtx) {
|
|
44
|
+
return {
|
|
45
|
+
parseLength: (value: string) => parseLength(value),
|
|
46
|
+
parseLengthOrPercent: (value: string) => parseLengthOrPercent(value),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type UnitParsers = ReturnType<typeof makeUnitParsers>;
|