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,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates Adler-32 checksum as required by zlib format
|
|
3
|
+
* Used in WOFF 1.0 for data integrity verification
|
|
4
|
+
*/
|
|
5
|
+
export class Adler32 {
|
|
6
|
+
private static readonly MOD_ADLER = 65521;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Calculate Adler-32 checksum for the given data
|
|
10
|
+
*/
|
|
11
|
+
static calculate(data: Uint8Array): number {
|
|
12
|
+
let a = 1;
|
|
13
|
+
let b = 0;
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < data.length; i++) {
|
|
16
|
+
a = (a + data[i]) % this.MOD_ADLER;
|
|
17
|
+
b = (b + a) % this.MOD_ADLER;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (b << 16) | a;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Verify Adler-32 checksum
|
|
25
|
+
*/
|
|
26
|
+
static verify(data: Uint8Array, expectedChecksum: number): boolean {
|
|
27
|
+
const calculated = this.calculate(data);
|
|
28
|
+
return calculated === expectedChecksum;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Update running Adler-32 checksum with new data
|
|
33
|
+
*/
|
|
34
|
+
static update(adler: number, data: Uint8Array): number {
|
|
35
|
+
let a = adler & 0xffff;
|
|
36
|
+
let b = (adler >>> 16) & 0xffff;
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < data.length; i++) {
|
|
39
|
+
a = (a + data[i]) % this.MOD_ADLER;
|
|
40
|
+
b = (b + a) % this.MOD_ADLER;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (b << 16) | a;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BrotliOptions,
|
|
3
|
+
BrotliResult,
|
|
4
|
+
CompressionStats,
|
|
5
|
+
DecompressOptions,
|
|
6
|
+
WOFF2TableEntry,
|
|
7
|
+
} from './types.js';
|
|
8
|
+
import { BrotliMode } from './types.js';
|
|
9
|
+
import {
|
|
10
|
+
toUint8Array,
|
|
11
|
+
concatUint8Arrays,
|
|
12
|
+
padTo4Bytes,
|
|
13
|
+
} from './utils.js';
|
|
14
|
+
import { WOFF2Transform } from './transform.js';
|
|
15
|
+
|
|
16
|
+
// Cache Node.js zlib module to avoid repeated imports
|
|
17
|
+
let nodeZlib: typeof import('zlib') | null = null;
|
|
18
|
+
let nodeUtil: typeof import('util') | null = null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Brotli compression/decompression module for WOFF 2.0
|
|
22
|
+
*/
|
|
23
|
+
export class WOFF2Brotli {
|
|
24
|
+
private static readonly DEFAULT_QUALITY = 11; // Maximum compression for fonts
|
|
25
|
+
private static readonly DEFAULT_MODE = BrotliMode.FONT;
|
|
26
|
+
private static readonly DEFAULT_LGWIN = 22; // 4MB window
|
|
27
|
+
private static readonly DEFAULT_LGBLOCK = 0; // Auto
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Compress data using Brotli algorithm
|
|
31
|
+
*/
|
|
32
|
+
static async compress(
|
|
33
|
+
input: Uint8Array | ArrayBuffer,
|
|
34
|
+
options: BrotliOptions = {}
|
|
35
|
+
): Promise<BrotliResult> {
|
|
36
|
+
const data = toUint8Array(input);
|
|
37
|
+
const quality = options.quality ?? this.DEFAULT_QUALITY;
|
|
38
|
+
const mode = options.mode ?? this.DEFAULT_MODE;
|
|
39
|
+
const lgwin = options.lgwin ?? this.DEFAULT_LGWIN;
|
|
40
|
+
const lgblock = options.lgblock ?? this.DEFAULT_LGBLOCK;
|
|
41
|
+
|
|
42
|
+
if (quality < 0 || quality > 11) {
|
|
43
|
+
throw new Error('Brotli quality must be between 0 and 11');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const compressed = await this.brotliCompress(data, {
|
|
47
|
+
quality,
|
|
48
|
+
mode,
|
|
49
|
+
lgwin,
|
|
50
|
+
lgblock,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
data: compressed,
|
|
55
|
+
compressedSize: compressed.length,
|
|
56
|
+
uncompressedSize: data.length,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Decompress Brotli data
|
|
62
|
+
*/
|
|
63
|
+
static async decompress(
|
|
64
|
+
input: Uint8Array | ArrayBuffer,
|
|
65
|
+
options: DecompressOptions = {}
|
|
66
|
+
): Promise<Uint8Array> {
|
|
67
|
+
const data = toUint8Array(input);
|
|
68
|
+
const decompressed = await this.brotliDecompress(data);
|
|
69
|
+
|
|
70
|
+
if (options.expectedSize && options.validateSize) {
|
|
71
|
+
if (decompressed.length !== options.expectedSize) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Size mismatch: expected ${options.expectedSize}, got ${decompressed.length}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return decompressed;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Compress with table transformation (WOFF 2.0 specific)
|
|
83
|
+
*/
|
|
84
|
+
static async compressWithTransform(
|
|
85
|
+
input: Uint8Array,
|
|
86
|
+
tableTag: string,
|
|
87
|
+
entry: WOFF2TableEntry,
|
|
88
|
+
options: BrotliOptions = {}
|
|
89
|
+
): Promise<BrotliResult> {
|
|
90
|
+
const transformed = WOFF2Transform.transform(tableTag, input, entry);
|
|
91
|
+
const transformLength = WOFF2Transform.getTransformedLength(tableTag, input);
|
|
92
|
+
const result = await this.compress(transformed, options);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
...result,
|
|
96
|
+
transformLength,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Decompress with reverse transformation (WOFF 2.0 specific)
|
|
102
|
+
*/
|
|
103
|
+
static async decompressWithTransform(
|
|
104
|
+
input: Uint8Array,
|
|
105
|
+
tableTag: string,
|
|
106
|
+
entry: WOFF2TableEntry,
|
|
107
|
+
options: DecompressOptions = {}
|
|
108
|
+
): Promise<Uint8Array> {
|
|
109
|
+
const decompressed = await this.decompress(input, options);
|
|
110
|
+
const untransformed = WOFF2Transform.untransform(tableTag, decompressed, entry);
|
|
111
|
+
return untransformed;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get compression statistics
|
|
116
|
+
*/
|
|
117
|
+
static getCompressionStats(
|
|
118
|
+
original: Uint8Array,
|
|
119
|
+
compressed: Uint8Array,
|
|
120
|
+
transformed?: Uint8Array
|
|
121
|
+
): CompressionStats {
|
|
122
|
+
return {
|
|
123
|
+
originalSize: original.length,
|
|
124
|
+
compressedSize: compressed.length,
|
|
125
|
+
compressionRatio: compressed.length / original.length,
|
|
126
|
+
transformedSize: transformed?.length,
|
|
127
|
+
transformApplied: !!transformed && transformed.length !== original.length,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Platform-specific Brotli compression
|
|
133
|
+
*/
|
|
134
|
+
private static async brotliCompress(
|
|
135
|
+
data: Uint8Array,
|
|
136
|
+
options: BrotliOptions
|
|
137
|
+
): Promise<Uint8Array> {
|
|
138
|
+
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
139
|
+
return this.nodeBrotliCompress(data, options);
|
|
140
|
+
}
|
|
141
|
+
if (typeof CompressionStream !== 'undefined') {
|
|
142
|
+
return this.browserBrotliCompress(data);
|
|
143
|
+
}
|
|
144
|
+
throw new Error('No Brotli implementation available (Platform not supported)');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Platform-specific Brotli decompression
|
|
149
|
+
*/
|
|
150
|
+
private static async brotliDecompress(data: Uint8Array): Promise<Uint8Array> {
|
|
151
|
+
if (typeof process !== 'undefined' && process.versions?.node) {
|
|
152
|
+
return this.nodeBrotliDecompress(data);
|
|
153
|
+
}
|
|
154
|
+
if (typeof DecompressionStream !== 'undefined') {
|
|
155
|
+
try {
|
|
156
|
+
return await this.browserBrotliDecompress(data);
|
|
157
|
+
} catch {
|
|
158
|
+
// fall through to JS fallback
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return this.jsBrotliDecompress(data);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Node.js Brotli compression
|
|
166
|
+
*/
|
|
167
|
+
private static async nodeBrotliCompress(
|
|
168
|
+
data: Uint8Array,
|
|
169
|
+
options: BrotliOptions
|
|
170
|
+
): Promise<Uint8Array> {
|
|
171
|
+
if (!nodeZlib || !nodeUtil) {
|
|
172
|
+
nodeZlib = await import('zlib');
|
|
173
|
+
nodeUtil = await import('util');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const brotliCompress = nodeUtil.promisify(nodeZlib.brotliCompress);
|
|
177
|
+
|
|
178
|
+
const params: Record<number, number> = {
|
|
179
|
+
[nodeZlib.constants.BROTLI_PARAM_QUALITY]: options.quality ?? this.DEFAULT_QUALITY,
|
|
180
|
+
[nodeZlib.constants.BROTLI_PARAM_MODE]: options.mode ?? this.DEFAULT_MODE,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
if (options.lgwin !== undefined) {
|
|
184
|
+
params[nodeZlib.constants.BROTLI_PARAM_LGWIN] = options.lgwin;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (options.lgblock !== undefined && options.lgblock > 0) {
|
|
188
|
+
params[nodeZlib.constants.BROTLI_PARAM_LGBLOCK] = options.lgblock;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const compressed = await brotliCompress(data, { params });
|
|
192
|
+
return new Uint8Array(compressed);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Node.js Brotli decompression
|
|
197
|
+
*/
|
|
198
|
+
private static async nodeBrotliDecompress(data: Uint8Array): Promise<Uint8Array> {
|
|
199
|
+
if (!nodeZlib || !nodeUtil) {
|
|
200
|
+
nodeZlib = await import('zlib');
|
|
201
|
+
nodeUtil = await import('util');
|
|
202
|
+
}
|
|
203
|
+
const brotliDecompress = nodeUtil.promisify(nodeZlib.brotliDecompress);
|
|
204
|
+
|
|
205
|
+
const decompressed = await brotliDecompress(data);
|
|
206
|
+
return new Uint8Array(decompressed);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Browser Brotli compression using CompressionStream API
|
|
211
|
+
*/
|
|
212
|
+
private static async browserBrotliCompress(data: Uint8Array): Promise<Uint8Array> {
|
|
213
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
214
|
+
const stream = new CompressionStream('br' as any);
|
|
215
|
+
const writer = stream.writable.getWriter();
|
|
216
|
+
|
|
217
|
+
// Forçamos o cast para BufferSource para evitar conflito com tipos do Node
|
|
218
|
+
writer.write(data as BufferSource).catch(() => { /* ignore write errors here */ });
|
|
219
|
+
writer.close();
|
|
220
|
+
|
|
221
|
+
const chunks: Uint8Array[] = [];
|
|
222
|
+
const reader = stream.readable.getReader();
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
while (true) {
|
|
226
|
+
const { done, value } = await reader.read();
|
|
227
|
+
if (done) break;
|
|
228
|
+
if (value) chunks.push(value);
|
|
229
|
+
}
|
|
230
|
+
} catch (e) {
|
|
231
|
+
throw new Error('Browser Brotli compression failed: ' + e);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return concatUint8Arrays(chunks);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Browser Brotli decompression using DecompressionStream API
|
|
239
|
+
*/
|
|
240
|
+
private static async browserBrotliDecompress(data: Uint8Array): Promise<Uint8Array> {
|
|
241
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
242
|
+
const stream = new DecompressionStream('br' as any);
|
|
243
|
+
const writer = stream.writable.getWriter();
|
|
244
|
+
|
|
245
|
+
writer.write(data as BufferSource).catch(() => { /* ignore */ });
|
|
246
|
+
writer.close();
|
|
247
|
+
|
|
248
|
+
const chunks: Uint8Array[] = [];
|
|
249
|
+
const reader = stream.readable.getReader();
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
while (true) {
|
|
253
|
+
const { done, value } = await reader.read();
|
|
254
|
+
if (done) break;
|
|
255
|
+
if (value) chunks.push(value);
|
|
256
|
+
}
|
|
257
|
+
} catch (e) {
|
|
258
|
+
throw new Error('Browser Brotli decompression failed: ' + e);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return concatUint8Arrays(chunks);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Pure JS fallback using vendored decoder (CommonJS converted by bundler).
|
|
266
|
+
* This is slower but keeps compatibility when DecompressionStream('br') is unavailable.
|
|
267
|
+
*/
|
|
268
|
+
private static async jsBrotliDecompress(data: Uint8Array): Promise<Uint8Array> {
|
|
269
|
+
const mod = await import("./vendor/decode.js");
|
|
270
|
+
const decoder = mod.BrotliDecompressBuffer ?? mod.BrotliDecompress;
|
|
271
|
+
if (typeof decoder !== "function") {
|
|
272
|
+
throw new Error("No JS Brotli decoder available");
|
|
273
|
+
}
|
|
274
|
+
const out = decoder(data);
|
|
275
|
+
return out instanceof Uint8Array ? out : new Uint8Array(out);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Validate Brotli compressed data
|
|
280
|
+
*/
|
|
281
|
+
static async validateCompressedData(data: Uint8Array): Promise<boolean> {
|
|
282
|
+
try {
|
|
283
|
+
const decompressed = await this.decompress(data);
|
|
284
|
+
return decompressed.length > 0;
|
|
285
|
+
} catch {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Compress multiple tables into single stream (WOFF 2.0 spec)
|
|
292
|
+
*/
|
|
293
|
+
static async compressMultipleTables(
|
|
294
|
+
tables: Array<{ tag: string; data: Uint8Array; entry: WOFF2TableEntry }>,
|
|
295
|
+
options: BrotliOptions = {}
|
|
296
|
+
): Promise<BrotliResult> {
|
|
297
|
+
const concatenated = concatUint8Arrays(
|
|
298
|
+
tables.map(({ data }) => padTo4Bytes(data))
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return this.compress(concatenated, {
|
|
302
|
+
...options,
|
|
303
|
+
mode: BrotliMode.FONT,
|
|
304
|
+
quality: options.quality ?? 11,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Decompress single stream into multiple tables (WOFF 2.0 spec)
|
|
310
|
+
*/
|
|
311
|
+
static async decompressMultipleTables(
|
|
312
|
+
compressed: Uint8Array,
|
|
313
|
+
tables: WOFF2TableEntry[],
|
|
314
|
+
options: DecompressOptions = {}
|
|
315
|
+
): Promise<Map<string, Uint8Array>> {
|
|
316
|
+
const expectedSize = tables.reduce((sum, entry) =>
|
|
317
|
+
sum + (entry.transformLength ?? entry.origLength), 0);
|
|
318
|
+
|
|
319
|
+
const decompressed = await this.decompress(compressed, {
|
|
320
|
+
...options,
|
|
321
|
+
expectedSize,
|
|
322
|
+
validateSize: false, // Don't validate size strictly due to padding
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const result = new Map<string, Uint8Array>();
|
|
326
|
+
let offset = 0;
|
|
327
|
+
|
|
328
|
+
// First pass: extract all tables from the compressed stream
|
|
329
|
+
console.log(`WOFF2-BROTLI: Extracting ${tables.length} tables from ${decompressed.length} bytes`);
|
|
330
|
+
|
|
331
|
+
for (const entry of tables) {
|
|
332
|
+
const lengthInStream = entry.transformLength ?? entry.origLength;
|
|
333
|
+
|
|
334
|
+
console.log(`WOFF2-BROTLI: Processing table ${entry.tag} - origLength: ${entry.origLength}, transformLength: ${entry.transformLength}, transformVersion: ${entry.transformVersion}`);
|
|
335
|
+
|
|
336
|
+
if (offset + lengthInStream > decompressed.length) {
|
|
337
|
+
console.warn(`Table ${entry.tag} extends beyond decompressed data, using available data`);
|
|
338
|
+
const availableData = decompressed.subarray(offset);
|
|
339
|
+
if (availableData.length > 0) {
|
|
340
|
+
result.set(entry.tag, availableData);
|
|
341
|
+
}
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const tableData = decompressed.subarray(offset, offset + lengthInStream);
|
|
346
|
+
offset += lengthInStream;
|
|
347
|
+
|
|
348
|
+
const final = WOFF2Transform.untransform(entry.tag, tableData, entry, result);
|
|
349
|
+
result.set(entry.tag, final);
|
|
350
|
+
console.log(`WOFF2-BROTLI: Added table ${entry.tag} (${final.length} bytes)`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
console.log(`WOFF2-BROTLI: Extracted tables: ${Array.from(result.keys()).join(', ')}`);
|
|
354
|
+
|
|
355
|
+
// Second pass: handle glyf/loca transformation
|
|
356
|
+
// Check for gloc table OR separate transformed glyf/loca tables
|
|
357
|
+
// WOFF2 spec allows glyf/loca to be separate but transformed (transformVersion 0)
|
|
358
|
+
const hasGloc = result.has('gloc');
|
|
359
|
+
const glyfEntry = tables.find(t => t.tag === 'glyf');
|
|
360
|
+
const hasTransformedGlyf = result.has('glyf') && glyfEntry?.transformVersion === 0;
|
|
361
|
+
|
|
362
|
+
if (hasGloc || hasTransformedGlyf) {
|
|
363
|
+
console.log('WOFF2: Found transformed glyf/loca data, reconstructing...');
|
|
364
|
+
|
|
365
|
+
let glocData: Uint8Array;
|
|
366
|
+
|
|
367
|
+
if (hasGloc) {
|
|
368
|
+
console.log('WOFF2: Using gloc table');
|
|
369
|
+
glocData = result.get('gloc')!;
|
|
370
|
+
result.delete('gloc');
|
|
371
|
+
} else {
|
|
372
|
+
console.log('WOFF2: Using transformed glyf table');
|
|
373
|
+
// If glyf is transformed, it contains the streams needed for reconstruction
|
|
374
|
+
glocData = result.get('glyf')!;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
console.log(`WOFF2: Transform data size: ${glocData.length} bytes`);
|
|
378
|
+
|
|
379
|
+
// We need maxp table to get numGlyphs and head table to get indexToLocFormat
|
|
380
|
+
const maxpData = result.get('maxp');
|
|
381
|
+
const headData = result.get('head');
|
|
382
|
+
|
|
383
|
+
console.log(`WOFF2: maxp table present: ${!!maxpData}, head table present: ${!!headData}`);
|
|
384
|
+
|
|
385
|
+
if (maxpData && headData) {
|
|
386
|
+
// Read numGlyphs from maxp table (offset 4, UInt16)
|
|
387
|
+
const numGlyphs = new DataView(maxpData.buffer, maxpData.byteOffset).getUint16(4, false);
|
|
388
|
+
|
|
389
|
+
// Read indexToLocFormat from head table (offset 50, Int16)
|
|
390
|
+
const indexFormat = new DataView(headData.buffer, headData.byteOffset).getInt16(50, false);
|
|
391
|
+
|
|
392
|
+
console.log(`WOFF2: Reconstructing glyf/loca with numGlyphs=${numGlyphs}, indexFormat=${indexFormat}`);
|
|
393
|
+
|
|
394
|
+
// Reconstruct glyf and loca tables
|
|
395
|
+
const { glyf, loca } = WOFF2Transform.reconstructGlyfLoca(glocData, numGlyphs, indexFormat);
|
|
396
|
+
|
|
397
|
+
console.log(`WOFF2: Reconstructed glyf size: ${glyf.length}, loca size: ${loca.length}`);
|
|
398
|
+
|
|
399
|
+
result.set('glyf', glyf);
|
|
400
|
+
result.set('loca', loca);
|
|
401
|
+
|
|
402
|
+
console.log('WOFF2: Successfully reconstructed glyf/loca tables');
|
|
403
|
+
} else {
|
|
404
|
+
console.warn('Cannot reconstruct glyf/loca: missing maxp or head table');
|
|
405
|
+
}
|
|
406
|
+
console.log(`WOFF2: Available tables: ${Array.from(result.keys()).join(', ')}`);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Third pass: reconstruct hmtx if needed
|
|
410
|
+
this.reconstructHmtxIfNeeded(result, tables);
|
|
411
|
+
|
|
412
|
+
return result;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Helper to reconstruct hmtx table if needed
|
|
417
|
+
*/
|
|
418
|
+
private static reconstructHmtxIfNeeded(
|
|
419
|
+
result: Map<string, Uint8Array>,
|
|
420
|
+
tables: WOFF2TableEntry[]
|
|
421
|
+
): void {
|
|
422
|
+
const hmtxEntry = tables.find(t => t.tag === 'hmtx');
|
|
423
|
+
if (!hmtxEntry || !result.has('hmtx')) return;
|
|
424
|
+
|
|
425
|
+
// Check if hmtx is transformed (version 0 or 1 usually indicates transform in WOFF2)
|
|
426
|
+
// But strictly, we should check if the data size matches the expected untransformed size.
|
|
427
|
+
// If the data is smaller than expected, it's likely transformed.
|
|
428
|
+
// Or we can check the flags byte if we assume it's transformed.
|
|
429
|
+
|
|
430
|
+
// Better check: if transformVersion is 0, it IS transformed.
|
|
431
|
+
if (hmtxEntry.transformVersion !== 0) return;
|
|
432
|
+
|
|
433
|
+
// If transformLength is missing, it means the table length matches origLength.
|
|
434
|
+
// For hmtx, transformed data is usually smaller (or larger by 1 byte).
|
|
435
|
+
// If it matches origLength exactly, it's likely raw data despite the version flag.
|
|
436
|
+
if (hmtxEntry.transformLength === undefined) return;
|
|
437
|
+
|
|
438
|
+
const hmtxData = result.get('hmtx')!;
|
|
439
|
+
const hheaData = result.get('hhea');
|
|
440
|
+
const maxpData = result.get('maxp');
|
|
441
|
+
|
|
442
|
+
if (!hheaData || !maxpData) {
|
|
443
|
+
console.warn('WOFF2: Cannot reconstruct hmtx: missing hhea or maxp');
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const numHMetrics = new DataView(hheaData.buffer, hheaData.byteOffset).getUint16(34, false);
|
|
448
|
+
const numGlyphs = new DataView(maxpData.buffer, maxpData.byteOffset).getUint16(4, false);
|
|
449
|
+
|
|
450
|
+
const reconstructed = WOFF2Transform.reconstructHmtx(hmtxData, numHMetrics, numGlyphs);
|
|
451
|
+
result.set('hmtx', reconstructed);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// Export convenience functions
|
|
456
|
+
export const compress = WOFF2Brotli.compress.bind(WOFF2Brotli);
|
|
457
|
+
export const decompress = WOFF2Brotli.decompress.bind(WOFF2Brotli);
|
|
458
|
+
export const compressWithTransform = WOFF2Brotli.compressWithTransform.bind(WOFF2Brotli);
|
|
459
|
+
export const decompressWithTransform = WOFF2Brotli.decompressWithTransform.bind(WOFF2Brotli);
|
|
460
|
+
export const getCompressionStats = WOFF2Brotli.getCompressionStats.bind(WOFF2Brotli);
|
|
461
|
+
export const validateCompressedData = WOFF2Brotli.validateCompressedData.bind(WOFF2Brotli);
|
|
462
|
+
export const compressMultipleTables = WOFF2Brotli.compressMultipleTables.bind(WOFF2Brotli);
|
|
463
|
+
export const decompressMultipleTables = WOFF2Brotli.decompressMultipleTables.bind(WOFF2Brotli);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
WOFF2Brotli,
|
|
3
|
+
compress,
|
|
4
|
+
decompress,
|
|
5
|
+
compressWithTransform,
|
|
6
|
+
decompressWithTransform,
|
|
7
|
+
getCompressionStats,
|
|
8
|
+
validateCompressedData,
|
|
9
|
+
compressMultipleTables,
|
|
10
|
+
decompressMultipleTables,
|
|
11
|
+
} from './brotli.js';
|
|
12
|
+
|
|
13
|
+
export { WOFF2Transform } from './transform.js';
|
|
14
|
+
export * from './types.js';
|
|
15
|
+
export * from './utils.js';
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import type { WOFF2TableEntry } from './types.js';
|
|
2
|
+
import { WOFF2GlyfTransform } from './woff2-glyf-transform.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* WOFF 2.0 table transformations
|
|
6
|
+
* Specific transformations for glyf, loca, and hmtx tables
|
|
7
|
+
*/
|
|
8
|
+
export class WOFF2Transform {
|
|
9
|
+
/**
|
|
10
|
+
* Check if a table should be transformed
|
|
11
|
+
*/
|
|
12
|
+
static shouldTransform(tag: string): boolean {
|
|
13
|
+
return tag === 'glyf' || tag === 'loca' || tag === 'hmtx';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get transformation version for a table
|
|
18
|
+
*/
|
|
19
|
+
static getTransformVersion(tag: string): number {
|
|
20
|
+
switch (tag) {
|
|
21
|
+
case 'glyf':
|
|
22
|
+
case 'loca':
|
|
23
|
+
return 0; // Version 0 for glyf/loca transformation
|
|
24
|
+
case 'hmtx':
|
|
25
|
+
return 0; // Version 0 for hmtx transformation
|
|
26
|
+
default:
|
|
27
|
+
return 255; // No transformation
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Apply transformation to table data
|
|
33
|
+
* Note: This is for encoding WOFF2, not typically used in this library
|
|
34
|
+
*/
|
|
35
|
+
static transform(tag: string, data: Uint8Array, _entry: WOFF2TableEntry): Uint8Array {
|
|
36
|
+
const version = this.getTransformVersion(tag);
|
|
37
|
+
|
|
38
|
+
if (version === 255) {
|
|
39
|
+
return data; // No transformation
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Encoding transformations not implemented (we only decode WOFF2)
|
|
43
|
+
console.warn(`Transformation for ${tag} not implemented (encoding not supported)`);
|
|
44
|
+
return data;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Reverse transformation (for decompression)
|
|
49
|
+
* This is the critical path for WOFF2 decoding
|
|
50
|
+
*/
|
|
51
|
+
static untransform(
|
|
52
|
+
tag: string,
|
|
53
|
+
data: Uint8Array,
|
|
54
|
+
entry: WOFF2TableEntry,
|
|
55
|
+
allTables?: Map<string, Uint8Array>
|
|
56
|
+
): Uint8Array {
|
|
57
|
+
const version = entry.transformVersion;
|
|
58
|
+
|
|
59
|
+
// No transformation needed
|
|
60
|
+
if (version === 255 || version === 3) {
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Handle glyf/loca transformation
|
|
65
|
+
if ((tag === 'glyf' || tag === 'loca') && version === 0) {
|
|
66
|
+
// For glyf/loca, we need information from other tables
|
|
67
|
+
// The transformation produces a 'gloc' table that contains both glyf and loca data
|
|
68
|
+
// We'll handle this specially in the decompression logic
|
|
69
|
+
return data;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Other transformations not implemented
|
|
73
|
+
return data;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Calculate transformed length
|
|
78
|
+
*/
|
|
79
|
+
static getTransformedLength(tag: string, data: Uint8Array): number | undefined {
|
|
80
|
+
if (!this.shouldTransform(tag)) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Actual implementation would calculate transformed size
|
|
85
|
+
return data.length;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Reconstruct glyf and loca tables from transformed 'gloc' data
|
|
90
|
+
*/
|
|
91
|
+
/**
|
|
92
|
+
* Reconstruct glyf and loca tables from transformed 'gloc' data
|
|
93
|
+
*/
|
|
94
|
+
static reconstructGlyfLoca(
|
|
95
|
+
glocData: Uint8Array,
|
|
96
|
+
numGlyphs: number,
|
|
97
|
+
indexFormat: number
|
|
98
|
+
): { glyf: Uint8Array; loca: Uint8Array } {
|
|
99
|
+
return WOFF2GlyfTransform.untransformGlyf(glocData, numGlyphs, indexFormat);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Reconstruct hmtx table from transformed data
|
|
104
|
+
*/
|
|
105
|
+
static reconstructHmtx(
|
|
106
|
+
hmtxData: Uint8Array,
|
|
107
|
+
numHMetrics: number,
|
|
108
|
+
numGlyphs: number,
|
|
109
|
+
glyfTable?: Uint8Array,
|
|
110
|
+
locaTable?: Uint8Array
|
|
111
|
+
): Uint8Array {
|
|
112
|
+
if (hmtxData.length < 1) {
|
|
113
|
+
return hmtxData;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const flags = hmtxData[0];
|
|
117
|
+
const hasLsbArray = (flags & 1) !== 0;
|
|
118
|
+
const hasLeftSideBearingArray = (flags & 2) !== 0;
|
|
119
|
+
|
|
120
|
+
let offset = 1;
|
|
121
|
+
const advanceWidths: number[] = [];
|
|
122
|
+
|
|
123
|
+
// Read advance widths
|
|
124
|
+
for (let i = 0; i < numHMetrics; i++) {
|
|
125
|
+
if (offset + 2 > hmtxData.length) break;
|
|
126
|
+
advanceWidths.push((hmtxData[offset] << 8) | hmtxData[offset + 1]);
|
|
127
|
+
offset += 2;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const lsbs: number[] = [];
|
|
131
|
+
if (hasLsbArray) {
|
|
132
|
+
for (let i = 0; i < numHMetrics; i++) {
|
|
133
|
+
if (offset + 2 > hmtxData.length) break;
|
|
134
|
+
const val = (hmtxData[offset] << 8) | hmtxData[offset + 1];
|
|
135
|
+
lsbs.push(val > 0x7FFF ? val - 0x10000 : val);
|
|
136
|
+
offset += 2;
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
// Reconstruct LSBs from glyf table (xMin)
|
|
140
|
+
// Since we might have simplified glyf table, this might be inaccurate but safe
|
|
141
|
+
for (let i = 0; i < numHMetrics; i++) {
|
|
142
|
+
lsbs.push(0); // Default to 0 if derived
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const leftSideBearings: number[] = [];
|
|
147
|
+
if (hasLeftSideBearingArray) {
|
|
148
|
+
for (let i = numHMetrics; i < numGlyphs; i++) {
|
|
149
|
+
if (offset + 2 > hmtxData.length) break;
|
|
150
|
+
const val = (hmtxData[offset] << 8) | hmtxData[offset + 1];
|
|
151
|
+
leftSideBearings.push(val > 0x7FFF ? val - 0x10000 : val);
|
|
152
|
+
offset += 2;
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
// Reconstruct LSBs from glyf table (xMin)
|
|
156
|
+
for (let i = numHMetrics; i < numGlyphs; i++) {
|
|
157
|
+
leftSideBearings.push(0); // Default to 0 if derived
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Reconstruct standard hmtx table
|
|
162
|
+
// Format:
|
|
163
|
+
// hMetrics[numHMetrics] { advanceWidth: uint16, lsb: int16 }
|
|
164
|
+
// leftSideBearing[numGlyphs - numHMetrics]: int16
|
|
165
|
+
|
|
166
|
+
const hmtxSize = numHMetrics * 4 + (numGlyphs - numHMetrics) * 2;
|
|
167
|
+
const hmtx = new Uint8Array(hmtxSize);
|
|
168
|
+
const view = new DataView(hmtx.buffer);
|
|
169
|
+
let writeOffset = 0;
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < numHMetrics; i++) {
|
|
172
|
+
view.setUint16(writeOffset, advanceWidths[i] || 0, false);
|
|
173
|
+
view.setInt16(writeOffset + 2, lsbs[i] || 0, false);
|
|
174
|
+
writeOffset += 4;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
for (let i = 0; i < leftSideBearings.length; i++) {
|
|
178
|
+
view.setInt16(writeOffset, leftSideBearings[i], false);
|
|
179
|
+
writeOffset += 2;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return hmtx;
|
|
183
|
+
}
|
|
184
|
+
}
|