@cj-tech-master/excelts 9.5.4 → 9.5.5
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/dist/browser/modules/archive/compression/streaming-compress.browser.js +29 -0
- package/dist/browser/modules/archive/compression/streaming-compress.js +9 -0
- package/dist/browser/modules/archive/compression/worker-pool/pool.browser.js +26 -1
- package/dist/browser/modules/archive/fs/archive-file.d.ts +8 -5
- package/dist/browser/modules/archive/fs/archive-file.js +78 -16
- package/dist/browser/modules/archive/unzip/stream.browser.js +43 -2
- package/dist/browser/modules/excel/chart/chart-ex-builder.js +7 -2
- package/dist/browser/modules/excel/chart/chart-ex-renderer.js +4 -9
- package/dist/browser/modules/excel/chart/chart-ex-types.d.ts +0 -12
- package/dist/browser/modules/excel/chart/chart.d.ts +1 -5
- package/dist/browser/modules/excel/chart/chart.js +1 -7
- package/dist/browser/modules/excel/chart/types.d.ts +0 -6
- package/dist/browser/modules/excel/stream/workbook-reader.browser.js +25 -1
- package/dist/browser/modules/excel/stream/workbook-reader.js +9 -0
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +40 -0
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +228 -13
- package/dist/browser/modules/excel/utils/string-buf.d.ts +5 -26
- package/dist/browser/modules/excel/utils/string-buf.js +4 -81
- package/dist/browser/modules/excel/workbook.browser.js +135 -25
- package/dist/browser/modules/excel/xlsx/xform/chart/chart-space-xform.js +6 -20
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +19 -9
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +32 -8
- package/dist/browser/modules/excel/xlsx/xlsx.d.ts +10 -2
- package/dist/browser/modules/excel/xlsx/xlsx.js +9 -1
- package/dist/browser/modules/pdf/excel-bridge.d.ts +30 -1
- package/dist/browser/modules/pdf/excel-bridge.js +32 -0
- package/dist/browser/modules/pdf/font/metrics.d.ts +3 -52
- package/dist/browser/modules/pdf/font/metrics.js +3 -237
- package/dist/browser/modules/pdf/index.d.ts +1 -1
- package/dist/browser/modules/pdf/index.js +1 -1
- package/dist/browser/modules/pdf/render-layout-to-pdf.d.ts +66 -0
- package/dist/browser/modules/pdf/render-layout-to-pdf.js +647 -0
- package/dist/browser/modules/pdf/word-bridge.d.ts +80 -12
- package/dist/browser/modules/pdf/word-bridge.js +122 -274
- package/dist/browser/modules/stream/index.base.d.ts +2 -0
- package/dist/browser/modules/stream/index.base.js +2 -1
- package/dist/browser/modules/stream/internal/sink-adapter.d.ts +65 -0
- package/dist/browser/modules/stream/internal/sink-adapter.js +198 -0
- package/dist/browser/modules/stream/pull-stream.d.ts +19 -2
- package/dist/browser/modules/stream/pull-stream.js +51 -5
- package/dist/browser/modules/stream/types.d.ts +13 -1
- package/dist/browser/modules/word/advanced/diff.d.ts +61 -0
- package/dist/browser/modules/word/advanced/diff.js +167 -0
- package/dist/browser/modules/word/advanced/drawing-shapes.d.ts +269 -0
- package/dist/browser/modules/word/advanced/drawing-shapes.js +268 -0
- package/dist/browser/modules/word/advanced/field-engine.d.ts +43 -0
- package/dist/browser/modules/word/advanced/field-engine.js +1225 -0
- package/dist/browser/modules/word/advanced/glossary.d.ts +86 -0
- package/dist/browser/modules/word/advanced/glossary.js +79 -0
- package/dist/browser/modules/word/advanced/math-convert.d.ts +30 -0
- package/dist/browser/modules/word/advanced/math-convert.js +595 -0
- package/dist/browser/modules/word/advanced/ole-objects.d.ts +115 -0
- package/dist/browser/modules/word/advanced/ole-objects.js +271 -0
- package/dist/browser/modules/word/advanced/style-map.d.ts +105 -0
- package/dist/browser/modules/word/advanced/style-map.js +322 -0
- package/dist/browser/modules/word/advanced/validation.d.ts +56 -0
- package/dist/browser/modules/word/advanced/validation.js +1065 -0
- package/dist/browser/modules/word/advanced/vba-project.d.ts +91 -0
- package/dist/browser/modules/word/advanced/vba-project.js +265 -0
- package/dist/browser/modules/word/bridge/excel-bridge.d.ts +127 -0
- package/dist/browser/modules/word/bridge/excel-bridge.js +980 -0
- package/dist/browser/modules/word/builder/document-handle.d.ts +151 -0
- package/dist/browser/modules/word/builder/document-handle.js +664 -0
- package/dist/browser/modules/word/builder/paragraph-builders.d.ts +61 -0
- package/dist/browser/modules/word/builder/paragraph-builders.js +90 -0
- package/dist/browser/modules/word/builder/run-builders.d.ts +374 -0
- package/dist/browser/modules/word/builder/run-builders.js +600 -0
- package/dist/browser/modules/word/builder/table-builders.d.ts +23 -0
- package/dist/browser/modules/word/builder/table-builders.js +45 -0
- package/dist/browser/modules/word/constants.d.ts +39 -1
- package/dist/browser/modules/word/constants.js +109 -1
- package/dist/browser/modules/word/convert/conversion-ir.d.ts +210 -0
- package/dist/browser/modules/word/convert/conversion-ir.js +31 -0
- package/dist/browser/modules/word/convert/docx-to-semantic.d.ts +39 -0
- package/dist/browser/modules/word/convert/docx-to-semantic.js +499 -0
- package/dist/browser/modules/word/convert/flat-opc.d.ts +44 -0
- package/dist/browser/modules/word/convert/flat-opc.js +385 -0
- package/dist/browser/modules/word/convert/html/html-import.d.ts +50 -0
- package/dist/browser/modules/word/convert/html/html-import.js +1907 -0
- package/dist/{types/modules/word → browser/modules/word/convert/html}/html-renderer.d.ts +14 -1
- package/dist/{esm/modules/word → browser/modules/word/convert/html}/html-renderer.js +420 -69
- package/dist/browser/modules/word/convert/html/html.d.ts +15 -0
- package/dist/browser/modules/word/convert/html/html.js +15 -0
- package/dist/browser/modules/word/convert/markdown/markdown-import.d.ts +68 -0
- package/dist/browser/modules/word/convert/markdown/markdown-import.js +1325 -0
- package/dist/browser/modules/word/convert/markdown/markdown-renderer.d.ts +25 -0
- package/dist/browser/modules/word/convert/markdown/markdown-renderer.js +634 -0
- package/dist/browser/modules/word/convert/markdown/markdown.d.ts +15 -0
- package/dist/browser/modules/word/convert/markdown/markdown.js +15 -0
- package/dist/browser/modules/word/convert/odt/odt.d.ts +41 -0
- package/dist/browser/modules/word/convert/odt/odt.js +1932 -0
- package/dist/browser/modules/word/{color-utils.d.ts → core/color-utils.d.ts} +8 -1
- package/dist/browser/modules/word/core/color-utils.js +43 -0
- package/dist/browser/modules/word/core/internal-utils.d.ts +90 -0
- package/dist/browser/modules/word/core/internal-utils.js +209 -0
- package/dist/browser/modules/word/core/mapper.d.ts +44 -0
- package/dist/browser/modules/word/core/mapper.js +427 -0
- package/dist/browser/modules/word/core/opc-paths.d.ts +33 -0
- package/dist/browser/modules/word/core/opc-paths.js +48 -0
- package/dist/browser/modules/word/core/text-utils.d.ts +38 -0
- package/dist/browser/modules/word/core/text-utils.js +202 -0
- package/dist/browser/modules/word/core/walker.d.ts +119 -0
- package/dist/browser/modules/word/core/walker.js +570 -0
- package/dist/browser/modules/word/crypto.d.ts +14 -9
- package/dist/browser/modules/word/crypto.js +13 -7
- package/dist/browser/modules/word/document-io.d.ts +59 -27
- package/dist/browser/modules/word/document-io.js +80 -197
- package/dist/browser/modules/word/errors.d.ts +44 -1
- package/dist/browser/modules/word/errors.js +54 -2
- package/dist/browser/modules/word/excel.d.ts +14 -0
- package/dist/browser/modules/word/excel.js +13 -0
- package/dist/browser/modules/word/font/font-embed.d.ts +112 -0
- package/dist/browser/modules/word/font/font-embed.js +646 -0
- package/dist/{esm/modules/word → browser/modules/word/font}/font-obfuscation.js +4 -9
- package/dist/browser/modules/word/font/hyphenation.d.ts +65 -0
- package/dist/browser/modules/word/font/hyphenation.js +4210 -0
- package/dist/browser/modules/word/font/text-shaping.d.ts +58 -0
- package/dist/browser/modules/word/font/text-shaping.js +635 -0
- package/dist/browser/modules/word/html.d.ts +7 -6
- package/dist/browser/modules/word/html.js +6 -5
- package/dist/browser/modules/word/incremental-edit.d.ts +123 -0
- package/dist/browser/modules/word/incremental-edit.js +361 -0
- package/dist/browser/modules/word/index.base.d.ts +194 -10
- package/dist/browser/modules/word/index.base.js +138 -29
- package/dist/browser/modules/word/layout/layout-constants.d.ts +17 -0
- package/dist/browser/modules/word/layout/layout-constants.js +17 -0
- package/dist/browser/modules/word/layout/layout-full.d.ts +53 -0
- package/dist/browser/modules/word/layout/layout-full.js +1696 -0
- package/dist/browser/modules/word/layout/layout-model.d.ts +344 -0
- package/dist/browser/modules/word/layout/layout-model.js +16 -0
- package/dist/browser/modules/word/layout/layout.d.ts +63 -0
- package/dist/browser/modules/word/layout/layout.js +1167 -0
- package/dist/browser/modules/word/layout/render-page.d.ts +57 -0
- package/dist/browser/modules/word/layout/render-page.js +1238 -0
- package/dist/browser/modules/word/markdown.d.ts +14 -0
- package/dist/browser/modules/word/markdown.js +13 -0
- package/dist/browser/modules/word/patcher.d.ts +62 -0
- package/dist/browser/modules/word/patcher.js +537 -0
- package/dist/browser/modules/word/query/compat.d.ts +25 -0
- package/dist/browser/modules/word/query/compat.js +58 -0
- package/dist/browser/modules/word/query/data-binding.d.ts +22 -0
- package/dist/browser/modules/word/query/data-binding.js +392 -0
- package/dist/browser/modules/word/query/form-fields.d.ts +41 -0
- package/dist/browser/modules/word/query/form-fields.js +268 -0
- package/dist/browser/modules/word/query/format-search.d.ts +99 -0
- package/dist/browser/modules/word/query/format-search.js +329 -0
- package/dist/browser/modules/word/query/mail-merge.d.ts +25 -0
- package/dist/browser/modules/word/query/mail-merge.js +111 -0
- package/dist/browser/modules/word/query/merge.d.ts +50 -0
- package/dist/browser/modules/word/query/merge.js +617 -0
- package/dist/browser/modules/word/query/replace.d.ts +47 -0
- package/dist/browser/modules/word/query/replace.js +301 -0
- package/dist/browser/modules/word/query/revisions.d.ts +67 -0
- package/dist/browser/modules/word/query/revisions.js +879 -0
- package/dist/browser/modules/word/query/search.d.ts +129 -0
- package/dist/browser/modules/word/query/search.js +346 -0
- package/dist/browser/modules/word/query/split.d.ts +44 -0
- package/dist/browser/modules/word/query/split.js +135 -0
- package/dist/browser/modules/word/query/style-resolve.d.ts +104 -0
- package/dist/browser/modules/word/query/style-resolve.js +368 -0
- package/dist/browser/modules/word/reader/chart-parser.d.ts +20 -0
- package/dist/browser/modules/word/reader/chart-parser.js +810 -0
- package/dist/browser/modules/word/reader/comments-parser.d.ts +26 -0
- package/dist/browser/modules/word/reader/comments-parser.js +92 -0
- package/dist/browser/modules/word/reader/doc-props-parsers.d.ts +15 -0
- package/dist/browser/modules/word/reader/doc-props-parsers.js +190 -0
- package/dist/browser/modules/word/reader/docx-reader.d.ts +27 -0
- package/dist/browser/modules/word/reader/docx-reader.js +2557 -0
- package/dist/browser/modules/word/reader/drawing-helpers.d.ts +27 -0
- package/dist/browser/modules/word/reader/drawing-helpers.js +84 -0
- package/dist/browser/modules/word/reader/form-field-parser.d.ts +21 -0
- package/dist/browser/modules/word/reader/form-field-parser.js +82 -0
- package/dist/browser/modules/word/reader/image-parsers.d.ts +11 -0
- package/dist/browser/modules/word/reader/image-parsers.js +291 -0
- package/dist/browser/modules/word/reader/math-parser.d.ts +12 -0
- package/dist/browser/modules/word/reader/math-parser.js +422 -0
- package/dist/browser/modules/word/reader/metadata-parsers.d.ts +17 -0
- package/dist/browser/modules/word/reader/metadata-parsers.js +87 -0
- package/dist/browser/modules/word/reader/numbering-parser.d.ts +13 -0
- package/dist/browser/modules/word/reader/numbering-parser.js +166 -0
- package/dist/browser/modules/word/reader/paragraph-section-parsers.d.ts +12 -0
- package/dist/browser/modules/word/reader/paragraph-section-parsers.js +503 -0
- package/dist/browser/modules/word/reader/parse-utils.d.ts +91 -0
- package/dist/browser/modules/word/reader/parse-utils.js +249 -0
- package/dist/browser/modules/word/reader/properties-parsers.d.ts +21 -0
- package/dist/browser/modules/word/reader/properties-parsers.js +332 -0
- package/dist/browser/modules/word/reader/reader-context.d.ts +69 -0
- package/dist/browser/modules/word/reader/reader-context.js +61 -0
- package/dist/browser/modules/word/reader/sdt-helpers.d.ts +29 -0
- package/dist/browser/modules/word/reader/sdt-helpers.js +111 -0
- package/dist/browser/modules/word/reader/settings-parser.d.ts +8 -0
- package/dist/browser/modules/word/reader/settings-parser.js +263 -0
- package/dist/browser/modules/word/reader/styles-parser.d.ts +12 -0
- package/dist/browser/modules/word/reader/styles-parser.js +147 -0
- package/dist/browser/modules/word/reader/table-properties-parsers.d.ts +12 -0
- package/dist/browser/modules/word/reader/table-properties-parsers.js +234 -0
- package/dist/browser/modules/word/reader/theme-parser.d.ts +8 -0
- package/dist/browser/modules/word/reader/theme-parser.js +167 -0
- package/dist/browser/modules/word/reader/watermark-parser.d.ts +15 -0
- package/dist/browser/modules/word/reader/watermark-parser.js +110 -0
- package/dist/browser/modules/word/security/cfb-reader.d.ts +37 -0
- package/dist/browser/modules/word/security/cfb-reader.js +410 -0
- package/dist/browser/modules/word/{digital-signatures.d.ts → security/digital-signatures.d.ts} +19 -11
- package/dist/browser/modules/word/{digital-signatures.js → security/digital-signatures.js} +34 -34
- package/dist/browser/modules/word/security/document-protection.d.ts +93 -0
- package/dist/browser/modules/word/security/document-protection.js +201 -0
- package/dist/{types/modules/word → browser/modules/word/security}/encryption.d.ts +51 -4
- package/dist/browser/modules/word/security/encryption.js +602 -0
- package/dist/browser/modules/word/security/policy.d.ts +80 -0
- package/dist/browser/modules/word/security/policy.js +102 -0
- package/dist/browser/modules/word/template/template-chart.d.ts +56 -0
- package/dist/browser/modules/word/template/template-chart.js +167 -0
- package/dist/browser/modules/word/template/template-datasource.d.ts +154 -0
- package/dist/browser/modules/word/template/template-datasource.js +541 -0
- package/dist/browser/modules/word/template/template-engine.d.ts +121 -0
- package/dist/browser/modules/word/template/template-engine.js +1435 -0
- package/dist/browser/modules/word/types.d.ts +224 -25
- package/dist/browser/modules/word/units.d.ts +26 -0
- package/dist/browser/modules/word/units.js +43 -14
- package/dist/browser/modules/word/{writers → writer}/chart-writer.js +164 -23
- package/dist/browser/modules/word/writer/checkbox-writer.d.ts +17 -0
- package/dist/browser/modules/word/writer/checkbox-writer.js +79 -0
- package/dist/{types/modules/word/writers → browser/modules/word/writer}/comment-writer.d.ts +2 -1
- package/dist/browser/modules/word/{writers → writer}/comment-writer.js +8 -6
- package/dist/browser/modules/word/writer/common-parts.d.ts +57 -0
- package/dist/browser/modules/word/writer/common-parts.js +101 -0
- package/dist/{types/modules/word → browser/modules/word/writer}/content-types.d.ts +2 -2
- package/dist/{esm/modules/word → browser/modules/word/writer}/content-types.js +14 -6
- package/dist/browser/modules/word/writer/document-writer.d.ts +24 -0
- package/dist/browser/modules/word/writer/document-writer.js +473 -0
- package/dist/browser/modules/word/writer/docx-packager.d.ts +35 -0
- package/dist/browser/modules/word/writer/docx-packager.js +1515 -0
- package/dist/{types/modules/word/writers → browser/modules/word/writer}/footnote-writer.d.ts +3 -2
- package/dist/{esm/modules/word/writers → browser/modules/word/writer}/footnote-writer.js +13 -10
- package/dist/{types/modules/word/writers → browser/modules/word/writer}/header-footer-writer.d.ts +3 -2
- package/dist/{esm/modules/word/writers → browser/modules/word/writer}/header-footer-writer.js +39 -21
- package/dist/{types/modules/word/writers → browser/modules/word/writer}/image-writer.d.ts +1 -1
- package/dist/browser/modules/word/{writers → writer}/image-writer.js +11 -7
- package/dist/browser/modules/word/writer/math-writer.d.ts +20 -0
- package/dist/{esm/modules/word/writers → browser/modules/word/writer}/math-writer.js +21 -1
- package/dist/browser/modules/word/{writers → writer}/numbering-writer.d.ts +1 -1
- package/dist/{esm/modules/word/writers → browser/modules/word/writer}/numbering-writer.js +11 -4
- package/dist/browser/modules/word/{writers → writer}/paragraph-writer.d.ts +2 -1
- package/dist/browser/modules/word/{writers → writer}/paragraph-writer.js +73 -38
- package/dist/browser/modules/word/{writers → writer}/parts-writer.d.ts +3 -3
- package/dist/{esm/modules/word/writers → browser/modules/word/writer}/parts-writer.js +91 -12
- package/dist/browser/modules/word/writer/reference-scanners.d.ts +42 -0
- package/dist/browser/modules/word/writer/reference-scanners.js +111 -0
- package/dist/browser/modules/word/writer/relationships.d.ts +52 -0
- package/dist/browser/modules/word/writer/relationships.js +117 -0
- package/dist/browser/modules/word/writer/render-context.d.ts +124 -0
- package/dist/browser/modules/word/writer/render-context.js +46 -0
- package/dist/browser/modules/word/{writers → writer}/run-writer.d.ts +10 -1
- package/dist/{esm/modules/word/writers → browser/modules/word/writer}/run-writer.js +126 -24
- package/dist/browser/modules/word/writer/sdt-writer.d.ts +25 -0
- package/dist/browser/modules/word/writer/sdt-writer.js +189 -0
- package/dist/browser/modules/word/writer/stream-buf.d.ts +37 -0
- package/dist/browser/modules/word/writer/stream-buf.js +73 -0
- package/dist/browser/modules/word/writer/streaming-writer.d.ts +344 -0
- package/dist/browser/modules/word/writer/streaming-writer.js +1382 -0
- package/dist/browser/modules/word/writer/string-buf.d.ts +8 -0
- package/dist/browser/modules/word/writer/string-buf.js +7 -0
- package/dist/browser/modules/word/{writers → writer}/styles-writer.js +32 -1
- package/dist/browser/modules/word/{writers → writer}/table-writer.d.ts +2 -1
- package/dist/browser/modules/word/{writers → writer}/table-writer.js +94 -11
- package/dist/browser/modules/xml/types.d.ts +22 -0
- package/dist/browser/utils/crypto.browser.d.ts +3 -1
- package/dist/browser/utils/crypto.browser.js +3 -1
- package/dist/browser/utils/crypto.d.ts +4 -1
- package/dist/browser/utils/crypto.js +4 -1
- package/dist/browser/utils/font-metrics.d.ts +63 -0
- package/dist/browser/utils/font-metrics.js +293 -0
- package/dist/browser/utils/string-buf.d.ts +42 -0
- package/dist/browser/utils/string-buf.js +89 -0
- package/dist/browser/utils/theme-colors.d.ts +55 -0
- package/dist/browser/utils/theme-colors.js +120 -0
- package/dist/cjs/modules/archive/compression/streaming-compress.browser.js +29 -0
- package/dist/cjs/modules/archive/compression/streaming-compress.js +9 -0
- package/dist/cjs/modules/archive/compression/worker-pool/pool.browser.js +26 -1
- package/dist/cjs/modules/archive/fs/archive-file.js +78 -16
- package/dist/cjs/modules/archive/unzip/stream.browser.js +43 -2
- package/dist/cjs/modules/excel/chart/chart-ex-builder.js +7 -2
- package/dist/cjs/modules/excel/chart/chart-ex-renderer.js +4 -9
- package/dist/cjs/modules/excel/chart/chart.js +1 -7
- package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +25 -1
- package/dist/cjs/modules/excel/stream/workbook-reader.js +9 -0
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +228 -13
- package/dist/cjs/modules/excel/utils/string-buf.js +5 -81
- package/dist/cjs/modules/excel/workbook.browser.js +135 -25
- package/dist/cjs/modules/excel/xlsx/xform/chart/chart-space-xform.js +6 -20
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +32 -8
- package/dist/cjs/modules/excel/xlsx/xlsx.js +9 -1
- package/dist/cjs/modules/pdf/excel-bridge.js +33 -0
- package/dist/cjs/modules/pdf/font/metrics.js +11 -244
- package/dist/cjs/modules/pdf/index.js +2 -1
- package/dist/cjs/modules/pdf/render-layout-to-pdf.js +651 -0
- package/dist/cjs/modules/pdf/word-bridge.js +155 -274
- package/dist/cjs/modules/stream/index.base.js +4 -2
- package/dist/cjs/modules/stream/internal/sink-adapter.js +202 -0
- package/dist/cjs/modules/stream/pull-stream.js +51 -5
- package/dist/cjs/modules/word/advanced/diff.js +170 -0
- package/dist/cjs/modules/word/advanced/drawing-shapes.js +279 -0
- package/dist/cjs/modules/word/advanced/field-engine.js +1229 -0
- package/dist/cjs/modules/word/advanced/glossary.js +87 -0
- package/dist/cjs/modules/word/advanced/math-convert.js +599 -0
- package/dist/cjs/modules/word/advanced/ole-objects.js +277 -0
- package/dist/cjs/modules/word/advanced/style-map.js +329 -0
- package/dist/cjs/modules/word/advanced/validation.js +1068 -0
- package/dist/cjs/modules/word/advanced/vba-project.js +274 -0
- package/dist/cjs/modules/word/bridge/excel-bridge.js +1020 -0
- package/dist/cjs/modules/word/builder/document-handle.js +667 -0
- package/dist/cjs/modules/word/builder/paragraph-builders.js +109 -0
- package/dist/cjs/modules/word/builder/run-builders.js +676 -0
- package/dist/cjs/modules/word/builder/table-builders.js +53 -0
- package/dist/cjs/modules/word/constants.js +111 -2
- package/dist/cjs/modules/word/convert/conversion-ir.js +34 -0
- package/dist/cjs/modules/word/convert/docx-to-semantic.js +502 -0
- package/dist/cjs/modules/word/convert/flat-opc.js +390 -0
- package/dist/cjs/modules/word/convert/html/html-import.js +1910 -0
- package/dist/cjs/modules/word/{html-renderer.js → convert/html/html-renderer.js} +420 -69
- package/dist/cjs/modules/word/convert/html/html.js +20 -0
- package/dist/cjs/modules/word/convert/markdown/markdown-import.js +1329 -0
- package/dist/cjs/modules/word/convert/markdown/markdown-renderer.js +637 -0
- package/dist/cjs/modules/word/convert/markdown/markdown.js +21 -0
- package/dist/cjs/modules/word/convert/odt/odt.js +1936 -0
- package/dist/cjs/modules/word/core/color-utils.js +47 -0
- package/dist/cjs/modules/word/core/internal-utils.js +219 -0
- package/dist/cjs/modules/word/core/mapper.js +430 -0
- package/dist/cjs/modules/word/core/opc-paths.js +53 -0
- package/dist/cjs/modules/word/core/text-utils.js +210 -0
- package/dist/cjs/modules/word/core/walker.js +577 -0
- package/dist/cjs/modules/word/crypto.js +19 -8
- package/dist/cjs/modules/word/document-io.js +117 -197
- package/dist/cjs/modules/word/errors.js +59 -13
- package/dist/cjs/modules/word/excel.js +22 -0
- package/dist/cjs/modules/word/font/font-embed.js +652 -0
- package/dist/cjs/modules/word/{font-obfuscation.js → font/font-obfuscation.js} +4 -9
- package/dist/cjs/modules/word/font/hyphenation.js +4216 -0
- package/dist/cjs/modules/word/font/text-shaping.js +640 -0
- package/dist/cjs/modules/word/html.js +9 -7
- package/dist/cjs/modules/word/incremental-edit.js +366 -0
- package/dist/cjs/modules/word/index.base.js +370 -137
- package/dist/cjs/modules/word/layout/layout-constants.js +20 -0
- package/dist/cjs/modules/word/layout/layout-full.js +1699 -0
- package/dist/cjs/modules/word/layout/layout-model.js +17 -0
- package/dist/cjs/modules/word/layout/layout.js +1170 -0
- package/dist/cjs/modules/word/layout/render-page.js +1243 -0
- package/dist/cjs/modules/word/markdown.js +19 -0
- package/dist/cjs/modules/word/patcher.js +539 -0
- package/dist/cjs/modules/word/query/compat.js +61 -0
- package/dist/cjs/modules/word/query/data-binding.js +395 -0
- package/dist/cjs/modules/word/query/form-fields.js +272 -0
- package/dist/cjs/modules/word/query/format-search.js +334 -0
- package/dist/cjs/modules/word/query/mail-merge.js +114 -0
- package/dist/cjs/modules/word/query/merge.js +620 -0
- package/dist/cjs/modules/word/query/replace.js +304 -0
- package/dist/cjs/modules/word/query/revisions.js +885 -0
- package/dist/cjs/modules/word/query/search.js +361 -0
- package/dist/cjs/modules/word/query/split.js +138 -0
- package/dist/cjs/modules/word/query/style-resolve.js +374 -0
- package/dist/cjs/modules/word/reader/chart-parser.js +814 -0
- package/dist/cjs/modules/word/reader/comments-parser.js +96 -0
- package/dist/cjs/modules/word/reader/doc-props-parsers.js +194 -0
- package/dist/cjs/modules/word/reader/docx-reader.js +2560 -0
- package/dist/cjs/modules/word/reader/drawing-helpers.js +90 -0
- package/dist/cjs/modules/word/reader/form-field-parser.js +85 -0
- package/dist/cjs/modules/word/reader/image-parsers.js +293 -0
- package/dist/cjs/modules/word/reader/math-parser.js +424 -0
- package/dist/cjs/modules/word/reader/metadata-parsers.js +93 -0
- package/dist/cjs/modules/word/reader/numbering-parser.js +168 -0
- package/dist/cjs/modules/word/reader/paragraph-section-parsers.js +505 -0
- package/dist/cjs/modules/word/reader/parse-utils.js +271 -0
- package/dist/cjs/modules/word/reader/properties-parsers.js +338 -0
- package/dist/cjs/modules/word/reader/reader-context.js +66 -0
- package/dist/cjs/modules/word/reader/sdt-helpers.js +114 -0
- package/dist/cjs/modules/word/reader/settings-parser.js +265 -0
- package/dist/cjs/modules/word/reader/styles-parser.js +149 -0
- package/dist/cjs/modules/word/reader/table-properties-parsers.js +237 -0
- package/dist/cjs/modules/word/reader/theme-parser.js +169 -0
- package/dist/cjs/modules/word/reader/watermark-parser.js +113 -0
- package/dist/cjs/modules/word/security/cfb-reader.js +414 -0
- package/dist/cjs/modules/word/{digital-signatures.js → security/digital-signatures.js} +34 -34
- package/dist/cjs/modules/word/security/document-protection.js +208 -0
- package/dist/cjs/modules/word/security/encryption.js +612 -0
- package/dist/cjs/modules/word/security/policy.js +106 -0
- package/dist/cjs/modules/word/template/template-chart.js +170 -0
- package/dist/cjs/modules/word/template/template-datasource.js +549 -0
- package/dist/cjs/modules/word/template/template-engine.js +1430 -0
- package/dist/cjs/modules/word/units.js +44 -14
- package/dist/cjs/modules/word/{writers → writer}/chart-writer.js +163 -22
- package/dist/cjs/modules/word/writer/checkbox-writer.js +82 -0
- package/dist/cjs/modules/word/{writers → writer}/comment-writer.js +8 -6
- package/dist/cjs/modules/word/writer/common-parts.js +104 -0
- package/dist/cjs/modules/word/{content-types.js → writer/content-types.js} +14 -6
- package/dist/cjs/modules/word/writer/document-writer.js +478 -0
- package/dist/cjs/modules/word/writer/docx-packager.js +1551 -0
- package/dist/cjs/modules/word/{writers → writer}/footnote-writer.js +13 -10
- package/dist/cjs/modules/word/{writers → writer}/header-footer-writer.js +38 -20
- package/dist/cjs/modules/word/{writers → writer}/image-writer.js +11 -7
- package/dist/cjs/modules/word/{writers → writer}/math-writer.js +21 -1
- package/dist/cjs/modules/word/{writers → writer}/numbering-writer.js +11 -4
- package/dist/cjs/modules/word/{writers → writer}/paragraph-writer.js +72 -37
- package/dist/cjs/modules/word/{writers → writer}/parts-writer.js +91 -12
- package/dist/cjs/modules/word/writer/reference-scanners.js +120 -0
- package/dist/cjs/modules/word/writer/relationships.js +124 -0
- package/dist/cjs/modules/word/writer/render-context.js +51 -0
- package/dist/cjs/modules/word/{writers → writer}/run-writer.js +127 -24
- package/dist/cjs/modules/word/writer/sdt-writer.js +192 -0
- package/dist/cjs/modules/word/writer/stream-buf.js +76 -0
- package/dist/cjs/modules/word/writer/streaming-writer.js +1387 -0
- package/dist/cjs/modules/word/writer/string-buf.js +11 -0
- package/dist/cjs/modules/word/{writers → writer}/styles-writer.js +32 -1
- package/dist/cjs/modules/word/{writers → writer}/table-writer.js +94 -11
- package/dist/cjs/utils/crypto.browser.js +3 -1
- package/dist/cjs/utils/crypto.js +4 -1
- package/dist/cjs/utils/font-metrics.js +303 -0
- package/dist/cjs/utils/string-buf.js +92 -0
- package/dist/cjs/utils/theme-colors.js +126 -0
- package/dist/esm/modules/archive/compression/streaming-compress.browser.js +29 -0
- package/dist/esm/modules/archive/compression/streaming-compress.js +9 -0
- package/dist/esm/modules/archive/compression/worker-pool/pool.browser.js +26 -1
- package/dist/esm/modules/archive/fs/archive-file.js +78 -16
- package/dist/esm/modules/archive/unzip/stream.browser.js +43 -2
- package/dist/esm/modules/excel/chart/chart-ex-builder.js +7 -2
- package/dist/esm/modules/excel/chart/chart-ex-renderer.js +4 -9
- package/dist/esm/modules/excel/chart/chart.js +1 -7
- package/dist/esm/modules/excel/stream/workbook-reader.browser.js +25 -1
- package/dist/esm/modules/excel/stream/workbook-reader.js +9 -0
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +228 -13
- package/dist/esm/modules/excel/utils/string-buf.js +4 -81
- package/dist/esm/modules/excel/workbook.browser.js +135 -25
- package/dist/esm/modules/excel/xlsx/xform/chart/chart-space-xform.js +6 -20
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +32 -8
- package/dist/esm/modules/excel/xlsx/xlsx.js +9 -1
- package/dist/esm/modules/pdf/excel-bridge.js +32 -0
- package/dist/esm/modules/pdf/font/metrics.js +3 -237
- package/dist/esm/modules/pdf/index.js +1 -1
- package/dist/esm/modules/pdf/render-layout-to-pdf.js +647 -0
- package/dist/esm/modules/pdf/word-bridge.js +122 -274
- package/dist/esm/modules/stream/index.base.js +2 -1
- package/dist/esm/modules/stream/internal/sink-adapter.js +198 -0
- package/dist/esm/modules/stream/pull-stream.js +51 -5
- package/dist/esm/modules/word/advanced/diff.js +167 -0
- package/dist/esm/modules/word/advanced/drawing-shapes.js +268 -0
- package/dist/esm/modules/word/advanced/field-engine.js +1225 -0
- package/dist/esm/modules/word/advanced/glossary.js +79 -0
- package/dist/esm/modules/word/advanced/math-convert.js +595 -0
- package/dist/esm/modules/word/advanced/ole-objects.js +271 -0
- package/dist/esm/modules/word/advanced/style-map.js +322 -0
- package/dist/esm/modules/word/advanced/validation.js +1065 -0
- package/dist/esm/modules/word/advanced/vba-project.js +265 -0
- package/dist/esm/modules/word/bridge/excel-bridge.js +980 -0
- package/dist/esm/modules/word/builder/document-handle.js +664 -0
- package/dist/esm/modules/word/builder/paragraph-builders.js +90 -0
- package/dist/esm/modules/word/builder/run-builders.js +600 -0
- package/dist/esm/modules/word/builder/table-builders.js +45 -0
- package/dist/esm/modules/word/constants.js +109 -1
- package/dist/esm/modules/word/convert/conversion-ir.js +31 -0
- package/dist/esm/modules/word/convert/docx-to-semantic.js +499 -0
- package/dist/esm/modules/word/convert/flat-opc.js +385 -0
- package/dist/esm/modules/word/convert/html/html-import.js +1907 -0
- package/dist/{browser/modules/word → esm/modules/word/convert/html}/html-renderer.js +420 -69
- package/dist/esm/modules/word/convert/html/html.js +15 -0
- package/dist/esm/modules/word/convert/markdown/markdown-import.js +1325 -0
- package/dist/esm/modules/word/convert/markdown/markdown-renderer.js +634 -0
- package/dist/esm/modules/word/convert/markdown/markdown.js +15 -0
- package/dist/esm/modules/word/convert/odt/odt.js +1932 -0
- package/dist/esm/modules/word/core/color-utils.js +43 -0
- package/dist/esm/modules/word/core/internal-utils.js +209 -0
- package/dist/esm/modules/word/core/mapper.js +427 -0
- package/dist/esm/modules/word/core/opc-paths.js +48 -0
- package/dist/esm/modules/word/core/text-utils.js +202 -0
- package/dist/esm/modules/word/core/walker.js +570 -0
- package/dist/esm/modules/word/crypto.js +13 -7
- package/dist/esm/modules/word/document-io.js +80 -197
- package/dist/esm/modules/word/errors.js +54 -2
- package/dist/esm/modules/word/excel.js +13 -0
- package/dist/esm/modules/word/font/font-embed.js +646 -0
- package/dist/{browser/modules/word → esm/modules/word/font}/font-obfuscation.js +4 -9
- package/dist/esm/modules/word/font/hyphenation.js +4210 -0
- package/dist/esm/modules/word/font/text-shaping.js +635 -0
- package/dist/esm/modules/word/html.js +6 -5
- package/dist/esm/modules/word/incremental-edit.js +361 -0
- package/dist/esm/modules/word/index.base.js +138 -29
- package/dist/esm/modules/word/layout/layout-constants.js +17 -0
- package/dist/esm/modules/word/layout/layout-full.js +1696 -0
- package/dist/esm/modules/word/layout/layout-model.js +16 -0
- package/dist/esm/modules/word/layout/layout.js +1167 -0
- package/dist/esm/modules/word/layout/render-page.js +1238 -0
- package/dist/esm/modules/word/markdown.js +13 -0
- package/dist/esm/modules/word/patcher.js +537 -0
- package/dist/esm/modules/word/query/compat.js +58 -0
- package/dist/esm/modules/word/query/data-binding.js +392 -0
- package/dist/esm/modules/word/query/form-fields.js +268 -0
- package/dist/esm/modules/word/query/format-search.js +329 -0
- package/dist/esm/modules/word/query/mail-merge.js +111 -0
- package/dist/esm/modules/word/query/merge.js +617 -0
- package/dist/esm/modules/word/query/replace.js +301 -0
- package/dist/esm/modules/word/query/revisions.js +879 -0
- package/dist/esm/modules/word/query/search.js +346 -0
- package/dist/esm/modules/word/query/split.js +135 -0
- package/dist/esm/modules/word/query/style-resolve.js +368 -0
- package/dist/esm/modules/word/reader/chart-parser.js +810 -0
- package/dist/esm/modules/word/reader/comments-parser.js +92 -0
- package/dist/esm/modules/word/reader/doc-props-parsers.js +190 -0
- package/dist/esm/modules/word/reader/docx-reader.js +2557 -0
- package/dist/esm/modules/word/reader/drawing-helpers.js +84 -0
- package/dist/esm/modules/word/reader/form-field-parser.js +82 -0
- package/dist/esm/modules/word/reader/image-parsers.js +291 -0
- package/dist/esm/modules/word/reader/math-parser.js +422 -0
- package/dist/esm/modules/word/reader/metadata-parsers.js +87 -0
- package/dist/esm/modules/word/reader/numbering-parser.js +166 -0
- package/dist/esm/modules/word/reader/paragraph-section-parsers.js +503 -0
- package/dist/esm/modules/word/reader/parse-utils.js +249 -0
- package/dist/esm/modules/word/reader/properties-parsers.js +332 -0
- package/dist/esm/modules/word/reader/reader-context.js +61 -0
- package/dist/esm/modules/word/reader/sdt-helpers.js +111 -0
- package/dist/esm/modules/word/reader/settings-parser.js +263 -0
- package/dist/esm/modules/word/reader/styles-parser.js +147 -0
- package/dist/esm/modules/word/reader/table-properties-parsers.js +234 -0
- package/dist/esm/modules/word/reader/theme-parser.js +167 -0
- package/dist/esm/modules/word/reader/watermark-parser.js +110 -0
- package/dist/esm/modules/word/security/cfb-reader.js +410 -0
- package/dist/esm/modules/word/{digital-signatures.js → security/digital-signatures.js} +34 -34
- package/dist/esm/modules/word/security/document-protection.js +201 -0
- package/dist/esm/modules/word/security/encryption.js +602 -0
- package/dist/esm/modules/word/security/policy.js +102 -0
- package/dist/esm/modules/word/template/template-chart.js +167 -0
- package/dist/esm/modules/word/template/template-datasource.js +541 -0
- package/dist/esm/modules/word/template/template-engine.js +1435 -0
- package/dist/esm/modules/word/units.js +43 -14
- package/dist/esm/modules/word/{writers → writer}/chart-writer.js +164 -23
- package/dist/esm/modules/word/writer/checkbox-writer.js +79 -0
- package/dist/esm/modules/word/{writers → writer}/comment-writer.js +8 -6
- package/dist/esm/modules/word/writer/common-parts.js +101 -0
- package/dist/{browser/modules/word → esm/modules/word/writer}/content-types.js +14 -6
- package/dist/esm/modules/word/writer/document-writer.js +473 -0
- package/dist/esm/modules/word/writer/docx-packager.js +1515 -0
- package/dist/{browser/modules/word/writers → esm/modules/word/writer}/footnote-writer.js +13 -10
- package/dist/{browser/modules/word/writers → esm/modules/word/writer}/header-footer-writer.js +39 -21
- package/dist/esm/modules/word/{writers → writer}/image-writer.js +11 -7
- package/dist/{browser/modules/word/writers → esm/modules/word/writer}/math-writer.js +21 -1
- package/dist/{browser/modules/word/writers → esm/modules/word/writer}/numbering-writer.js +11 -4
- package/dist/esm/modules/word/{writers → writer}/paragraph-writer.js +73 -38
- package/dist/{browser/modules/word/writers → esm/modules/word/writer}/parts-writer.js +91 -12
- package/dist/esm/modules/word/writer/reference-scanners.js +111 -0
- package/dist/esm/modules/word/writer/relationships.js +117 -0
- package/dist/esm/modules/word/writer/render-context.js +46 -0
- package/dist/{browser/modules/word/writers → esm/modules/word/writer}/run-writer.js +126 -24
- package/dist/esm/modules/word/writer/sdt-writer.js +189 -0
- package/dist/esm/modules/word/writer/stream-buf.js +73 -0
- package/dist/esm/modules/word/writer/streaming-writer.js +1382 -0
- package/dist/esm/modules/word/writer/string-buf.js +7 -0
- package/dist/esm/modules/word/{writers → writer}/styles-writer.js +32 -1
- package/dist/esm/modules/word/{writers → writer}/table-writer.js +94 -11
- package/dist/esm/utils/crypto.browser.js +3 -1
- package/dist/esm/utils/crypto.js +4 -1
- package/dist/esm/utils/font-metrics.js +293 -0
- package/dist/esm/utils/string-buf.js +89 -0
- package/dist/esm/utils/theme-colors.js +120 -0
- package/dist/iife/excelts.iife.js +70692 -70337
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +57 -57
- package/dist/types/modules/archive/fs/archive-file.d.ts +8 -5
- package/dist/types/modules/excel/chart/chart-ex-types.d.ts +0 -12
- package/dist/types/modules/excel/chart/chart.d.ts +1 -5
- package/dist/types/modules/excel/chart/types.d.ts +0 -6
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +40 -0
- package/dist/types/modules/excel/utils/string-buf.d.ts +5 -26
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +19 -9
- package/dist/types/modules/excel/xlsx/xlsx.d.ts +10 -2
- package/dist/types/modules/pdf/excel-bridge.d.ts +30 -1
- package/dist/types/modules/pdf/font/metrics.d.ts +3 -52
- package/dist/types/modules/pdf/index.d.ts +1 -1
- package/dist/types/modules/pdf/render-layout-to-pdf.d.ts +66 -0
- package/dist/types/modules/pdf/word-bridge.d.ts +80 -12
- package/dist/types/modules/stream/index.base.d.ts +2 -0
- package/dist/types/modules/stream/internal/sink-adapter.d.ts +65 -0
- package/dist/types/modules/stream/pull-stream.d.ts +19 -2
- package/dist/types/modules/stream/types.d.ts +13 -1
- package/dist/types/modules/word/advanced/diff.d.ts +61 -0
- package/dist/types/modules/word/advanced/drawing-shapes.d.ts +269 -0
- package/dist/types/modules/word/advanced/field-engine.d.ts +43 -0
- package/dist/types/modules/word/advanced/glossary.d.ts +86 -0
- package/dist/types/modules/word/advanced/math-convert.d.ts +30 -0
- package/dist/types/modules/word/advanced/ole-objects.d.ts +115 -0
- package/dist/types/modules/word/advanced/style-map.d.ts +105 -0
- package/dist/types/modules/word/advanced/validation.d.ts +56 -0
- package/dist/types/modules/word/advanced/vba-project.d.ts +91 -0
- package/dist/types/modules/word/bridge/excel-bridge.d.ts +127 -0
- package/dist/types/modules/word/builder/document-handle.d.ts +151 -0
- package/dist/types/modules/word/builder/paragraph-builders.d.ts +61 -0
- package/dist/types/modules/word/builder/run-builders.d.ts +374 -0
- package/dist/types/modules/word/builder/table-builders.d.ts +23 -0
- package/dist/types/modules/word/constants.d.ts +39 -1
- package/dist/types/modules/word/convert/conversion-ir.d.ts +210 -0
- package/dist/types/modules/word/convert/docx-to-semantic.d.ts +39 -0
- package/dist/types/modules/word/convert/flat-opc.d.ts +44 -0
- package/dist/types/modules/word/convert/html/html-import.d.ts +50 -0
- package/dist/{browser/modules/word → types/modules/word/convert/html}/html-renderer.d.ts +14 -1
- package/dist/types/modules/word/convert/html/html.d.ts +15 -0
- package/dist/types/modules/word/convert/markdown/markdown-import.d.ts +68 -0
- package/dist/types/modules/word/convert/markdown/markdown-renderer.d.ts +25 -0
- package/dist/types/modules/word/convert/markdown/markdown.d.ts +15 -0
- package/dist/types/modules/word/convert/odt/odt.d.ts +41 -0
- package/dist/types/modules/word/{color-utils.d.ts → core/color-utils.d.ts} +8 -1
- package/dist/types/modules/word/core/internal-utils.d.ts +90 -0
- package/dist/types/modules/word/core/mapper.d.ts +44 -0
- package/dist/types/modules/word/core/opc-paths.d.ts +33 -0
- package/dist/types/modules/word/core/text-utils.d.ts +38 -0
- package/dist/types/modules/word/core/walker.d.ts +119 -0
- package/dist/types/modules/word/crypto.d.ts +14 -9
- package/dist/types/modules/word/document-io.d.ts +59 -27
- package/dist/types/modules/word/errors.d.ts +44 -1
- package/dist/types/modules/word/excel.d.ts +14 -0
- package/dist/types/modules/word/font/font-embed.d.ts +112 -0
- package/dist/types/modules/word/font/hyphenation.d.ts +65 -0
- package/dist/types/modules/word/font/text-shaping.d.ts +58 -0
- package/dist/types/modules/word/html.d.ts +7 -6
- package/dist/types/modules/word/incremental-edit.d.ts +123 -0
- package/dist/types/modules/word/index.base.d.ts +194 -10
- package/dist/types/modules/word/layout/layout-constants.d.ts +17 -0
- package/dist/types/modules/word/layout/layout-full.d.ts +53 -0
- package/dist/types/modules/word/layout/layout-model.d.ts +344 -0
- package/dist/types/modules/word/layout/layout.d.ts +63 -0
- package/dist/types/modules/word/layout/render-page.d.ts +57 -0
- package/dist/types/modules/word/markdown.d.ts +14 -0
- package/dist/types/modules/word/patcher.d.ts +62 -0
- package/dist/types/modules/word/query/compat.d.ts +25 -0
- package/dist/types/modules/word/query/data-binding.d.ts +22 -0
- package/dist/types/modules/word/query/form-fields.d.ts +41 -0
- package/dist/types/modules/word/query/format-search.d.ts +99 -0
- package/dist/types/modules/word/query/mail-merge.d.ts +25 -0
- package/dist/types/modules/word/query/merge.d.ts +50 -0
- package/dist/types/modules/word/query/replace.d.ts +47 -0
- package/dist/types/modules/word/query/revisions.d.ts +67 -0
- package/dist/types/modules/word/query/search.d.ts +129 -0
- package/dist/types/modules/word/query/split.d.ts +44 -0
- package/dist/types/modules/word/query/style-resolve.d.ts +104 -0
- package/dist/types/modules/word/reader/chart-parser.d.ts +20 -0
- package/dist/types/modules/word/reader/comments-parser.d.ts +26 -0
- package/dist/types/modules/word/reader/doc-props-parsers.d.ts +15 -0
- package/dist/types/modules/word/reader/docx-reader.d.ts +27 -0
- package/dist/types/modules/word/reader/drawing-helpers.d.ts +27 -0
- package/dist/types/modules/word/reader/form-field-parser.d.ts +21 -0
- package/dist/types/modules/word/reader/image-parsers.d.ts +11 -0
- package/dist/types/modules/word/reader/math-parser.d.ts +12 -0
- package/dist/types/modules/word/reader/metadata-parsers.d.ts +17 -0
- package/dist/types/modules/word/reader/numbering-parser.d.ts +13 -0
- package/dist/types/modules/word/reader/paragraph-section-parsers.d.ts +12 -0
- package/dist/types/modules/word/reader/parse-utils.d.ts +91 -0
- package/dist/types/modules/word/reader/properties-parsers.d.ts +21 -0
- package/dist/types/modules/word/reader/reader-context.d.ts +69 -0
- package/dist/types/modules/word/reader/sdt-helpers.d.ts +29 -0
- package/dist/types/modules/word/reader/settings-parser.d.ts +8 -0
- package/dist/types/modules/word/reader/styles-parser.d.ts +12 -0
- package/dist/types/modules/word/reader/table-properties-parsers.d.ts +12 -0
- package/dist/types/modules/word/reader/theme-parser.d.ts +8 -0
- package/dist/types/modules/word/reader/watermark-parser.d.ts +15 -0
- package/dist/types/modules/word/security/cfb-reader.d.ts +37 -0
- package/dist/types/modules/word/{digital-signatures.d.ts → security/digital-signatures.d.ts} +19 -11
- package/dist/types/modules/word/security/document-protection.d.ts +93 -0
- package/dist/{browser/modules/word → types/modules/word/security}/encryption.d.ts +51 -4
- package/dist/types/modules/word/security/policy.d.ts +80 -0
- package/dist/types/modules/word/template/template-chart.d.ts +56 -0
- package/dist/types/modules/word/template/template-datasource.d.ts +154 -0
- package/dist/types/modules/word/template/template-engine.d.ts +121 -0
- package/dist/types/modules/word/types.d.ts +224 -25
- package/dist/types/modules/word/units.d.ts +26 -0
- package/dist/types/modules/word/writer/checkbox-writer.d.ts +17 -0
- package/dist/{browser/modules/word/writers → types/modules/word/writer}/comment-writer.d.ts +2 -1
- package/dist/types/modules/word/writer/common-parts.d.ts +57 -0
- package/dist/{browser/modules/word → types/modules/word/writer}/content-types.d.ts +2 -2
- package/dist/types/modules/word/writer/document-writer.d.ts +24 -0
- package/dist/types/modules/word/writer/docx-packager.d.ts +35 -0
- package/dist/{browser/modules/word/writers → types/modules/word/writer}/footnote-writer.d.ts +3 -2
- package/dist/{browser/modules/word/writers → types/modules/word/writer}/header-footer-writer.d.ts +3 -2
- package/dist/{browser/modules/word/writers → types/modules/word/writer}/image-writer.d.ts +1 -1
- package/dist/types/modules/word/writer/math-writer.d.ts +20 -0
- package/dist/types/modules/word/{writers → writer}/numbering-writer.d.ts +1 -1
- package/dist/types/modules/word/{writers → writer}/paragraph-writer.d.ts +2 -1
- package/dist/types/modules/word/{writers → writer}/parts-writer.d.ts +3 -3
- package/dist/types/modules/word/writer/reference-scanners.d.ts +42 -0
- package/dist/types/modules/word/writer/relationships.d.ts +52 -0
- package/dist/types/modules/word/writer/render-context.d.ts +124 -0
- package/dist/types/modules/word/{writers → writer}/run-writer.d.ts +10 -1
- package/dist/types/modules/word/writer/sdt-writer.d.ts +25 -0
- package/dist/types/modules/word/writer/stream-buf.d.ts +37 -0
- package/dist/types/modules/word/writer/streaming-writer.d.ts +344 -0
- package/dist/types/modules/word/writer/string-buf.d.ts +8 -0
- package/dist/types/modules/word/{writers → writer}/table-writer.d.ts +2 -1
- package/dist/types/modules/xml/types.d.ts +22 -0
- package/dist/types/utils/crypto.browser.d.ts +3 -1
- package/dist/types/utils/crypto.d.ts +4 -1
- package/dist/types/utils/font-metrics.d.ts +63 -0
- package/dist/types/utils/string-buf.d.ts +42 -0
- package/dist/types/utils/theme-colors.d.ts +55 -0
- package/package.json +121 -39
- package/dist/browser/modules/word/color-utils.js +0 -94
- package/dist/browser/modules/word/document.d.ts +0 -657
- package/dist/browser/modules/word/document.js +0 -1533
- package/dist/browser/modules/word/docx-packager.d.ts +0 -14
- package/dist/browser/modules/word/docx-packager.js +0 -822
- package/dist/browser/modules/word/docx-reader.d.ts +0 -11
- package/dist/browser/modules/word/docx-reader.js +0 -4929
- package/dist/browser/modules/word/encryption.js +0 -274
- package/dist/browser/modules/word/internal-utils.d.ts +0 -23
- package/dist/browser/modules/word/internal-utils.js +0 -54
- package/dist/browser/modules/word/namespaces.d.ts +0 -159
- package/dist/browser/modules/word/namespaces.js +0 -189
- package/dist/browser/modules/word/relationships.d.ts +0 -30
- package/dist/browser/modules/word/relationships.js +0 -48
- package/dist/browser/modules/word/writers/checkbox-writer.d.ts +0 -9
- package/dist/browser/modules/word/writers/checkbox-writer.js +0 -42
- package/dist/browser/modules/word/writers/document-writer.d.ts +0 -16
- package/dist/browser/modules/word/writers/document-writer.js +0 -461
- package/dist/browser/modules/word/writers/math-writer.d.ts +0 -9
- package/dist/cjs/modules/word/color-utils.js +0 -97
- package/dist/cjs/modules/word/document.js +0 -1645
- package/dist/cjs/modules/word/docx-packager.js +0 -825
- package/dist/cjs/modules/word/docx-reader.js +0 -4932
- package/dist/cjs/modules/word/encryption.js +0 -282
- package/dist/cjs/modules/word/internal-utils.js +0 -59
- package/dist/cjs/modules/word/namespaces.js +0 -192
- package/dist/cjs/modules/word/relationships.js +0 -55
- package/dist/cjs/modules/word/writers/checkbox-writer.js +0 -45
- package/dist/cjs/modules/word/writers/document-writer.js +0 -465
- package/dist/esm/modules/word/color-utils.js +0 -94
- package/dist/esm/modules/word/document.js +0 -1533
- package/dist/esm/modules/word/docx-packager.js +0 -822
- package/dist/esm/modules/word/docx-reader.js +0 -4929
- package/dist/esm/modules/word/encryption.js +0 -274
- package/dist/esm/modules/word/internal-utils.js +0 -54
- package/dist/esm/modules/word/namespaces.js +0 -189
- package/dist/esm/modules/word/relationships.js +0 -48
- package/dist/esm/modules/word/writers/checkbox-writer.js +0 -42
- package/dist/esm/modules/word/writers/document-writer.js +0 -461
- package/dist/types/modules/word/document.d.ts +0 -657
- package/dist/types/modules/word/docx-packager.d.ts +0 -14
- package/dist/types/modules/word/docx-reader.d.ts +0 -11
- package/dist/types/modules/word/internal-utils.d.ts +0 -23
- package/dist/types/modules/word/namespaces.d.ts +0 -159
- package/dist/types/modules/word/relationships.d.ts +0 -30
- package/dist/types/modules/word/writers/checkbox-writer.d.ts +0 -9
- package/dist/types/modules/word/writers/document-writer.d.ts +0 -16
- package/dist/types/modules/word/writers/math-writer.d.ts +0 -9
- /package/dist/browser/modules/word/{font-obfuscation.d.ts → font/font-obfuscation.d.ts} +0 -0
- /package/dist/browser/modules/word/{writers → writer}/chart-writer.d.ts +0 -0
- /package/dist/browser/modules/word/{writers → writer}/section-writer.d.ts +0 -0
- /package/dist/browser/modules/word/{writers → writer}/section-writer.js +0 -0
- /package/dist/browser/modules/word/{writers → writer}/styles-writer.d.ts +0 -0
- /package/dist/browser/modules/word/{writers → writer}/textbox-writer.d.ts +0 -0
- /package/dist/browser/modules/word/{writers → writer}/textbox-writer.js +0 -0
- /package/dist/browser/modules/word/{writers → writer}/toc-writer.d.ts +0 -0
- /package/dist/browser/modules/word/{writers → writer}/toc-writer.js +0 -0
- /package/dist/cjs/modules/word/{writers → writer}/section-writer.js +0 -0
- /package/dist/cjs/modules/word/{writers → writer}/textbox-writer.js +0 -0
- /package/dist/cjs/modules/word/{writers → writer}/toc-writer.js +0 -0
- /package/dist/esm/modules/word/{writers → writer}/section-writer.js +0 -0
- /package/dist/esm/modules/word/{writers → writer}/textbox-writer.js +0 -0
- /package/dist/esm/modules/word/{writers → writer}/toc-writer.js +0 -0
- /package/dist/types/modules/word/{font-obfuscation.d.ts → font/font-obfuscation.d.ts} +0 -0
- /package/dist/types/modules/word/{writers → writer}/chart-writer.d.ts +0 -0
- /package/dist/types/modules/word/{writers → writer}/section-writer.d.ts +0 -0
- /package/dist/types/modules/word/{writers → writer}/styles-writer.d.ts +0 -0
- /package/dist/types/modules/word/{writers → writer}/textbox-writer.d.ts +0 -0
- /package/dist/types/modules/word/{writers → writer}/toc-writer.d.ts +0 -0
|
@@ -0,0 +1,1699 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Full Layout Engine — produces a complete LayoutDocument with positioned elements.
|
|
4
|
+
*
|
|
5
|
+
* Uses the pagination result from layoutDocument() for page assignments,
|
|
6
|
+
* then computes precise positions (x, y, width, height) for every body
|
|
7
|
+
* element on each page.
|
|
8
|
+
*
|
|
9
|
+
* This is the bridge between the page-number-only LayoutResult and the
|
|
10
|
+
* fully positioned LayoutDocument that renderers (SVG, PDF, Canvas) can consume.
|
|
11
|
+
*
|
|
12
|
+
* Coverage: every variant of `BodyContent` from `../types` produces a
|
|
13
|
+
* `PageContent` variant in the output. The `default:` branch of the
|
|
14
|
+
* dispatch switch in `buildPage()` is a `never`-typed exhaustiveness
|
|
15
|
+
* guard — adding a new body variant without a matching layout function
|
|
16
|
+
* is a build error, never a silent drop.
|
|
17
|
+
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.layoutDocumentFull = layoutDocumentFull;
|
|
20
|
+
const font_metrics_1 = require("../../../utils/font-metrics.js");
|
|
21
|
+
const math_convert_1 = require("../advanced/math-convert");
|
|
22
|
+
const text_utils_1 = require("../core/text-utils");
|
|
23
|
+
const units_1 = require("../units");
|
|
24
|
+
const layout_1 = require("./layout");
|
|
25
|
+
const layout_constants_1 = require("./layout-constants");
|
|
26
|
+
/**
|
|
27
|
+
* Perform full document layout, producing a LayoutDocument with precise positions.
|
|
28
|
+
*
|
|
29
|
+
* @param doc - The parsed DOCX document.
|
|
30
|
+
* @param options - Layout and font options.
|
|
31
|
+
* @returns A fully positioned LayoutDocument.
|
|
32
|
+
*/
|
|
33
|
+
function layoutDocumentFull(doc, options) {
|
|
34
|
+
// First pass: get page assignments via the existing lightweight layout
|
|
35
|
+
const layoutResult = (0, layout_1.layoutDocument)(doc, options);
|
|
36
|
+
// Second pass: compute precise positions for each page. Footnote
|
|
37
|
+
// ids that don't fit on a given page are carried over to the next
|
|
38
|
+
// (a later page may still have room thanks to less body content
|
|
39
|
+
// or fewer of its own newly-introduced notes).
|
|
40
|
+
const pages = [];
|
|
41
|
+
const bodyPageCount = layoutResult.pageCount;
|
|
42
|
+
let pendingFootnoteIds = [];
|
|
43
|
+
for (let pageNum = 1; pageNum <= bodyPageCount; pageNum++) {
|
|
44
|
+
const result = buildPage(doc, pageNum, layoutResult, options, pendingFootnoteIds);
|
|
45
|
+
pages.push(result.page);
|
|
46
|
+
pendingFootnoteIds = result.deferredFootnoteIds;
|
|
47
|
+
}
|
|
48
|
+
// Defensive: if the last page still has deferred footnotes, append
|
|
49
|
+
// a synthetic page that hosts them. Without this, references would
|
|
50
|
+
// silently lose their content. This is rare (it only fires when an
|
|
51
|
+
// oversized footnote stack on the last body page didn't fit).
|
|
52
|
+
if (pendingFootnoteIds.length > 0 && bodyPageCount > 0) {
|
|
53
|
+
const overflowResult = buildPage(doc, bodyPageCount + 1,
|
|
54
|
+
// Reuse the last page's `LayoutResult` shape: contentPages
|
|
55
|
+
// entries for already-placed body items still point at earlier
|
|
56
|
+
// pages, so the synthetic page won't pick up extra body
|
|
57
|
+
// content; only the carried footnote queue renders.
|
|
58
|
+
layoutResult, options, pendingFootnoteIds);
|
|
59
|
+
pages.push(overflowResult.page);
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
pages,
|
|
63
|
+
totalPages: pages.length,
|
|
64
|
+
bookmarkPages: layoutResult.bookmarkPages,
|
|
65
|
+
sectionBreaks: computeSectionBreaks(layoutResult)
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// =============================================================================
|
|
69
|
+
// Internal: Page Building
|
|
70
|
+
// =============================================================================
|
|
71
|
+
const DEFAULT_FONT_SIZE_PT = 12;
|
|
72
|
+
/**
|
|
73
|
+
* Compute the longest available horizontal slot on the line whose
|
|
74
|
+
* vertical span is `[lineY, lineY + lineHeight)`. Returns `xOffset`
|
|
75
|
+
* (relative to the content-area's left edge) and `width`. When no
|
|
76
|
+
* exclusion intersects the line the result is `{ xOffset: 0, width:
|
|
77
|
+
* contentWidth }` (full width).
|
|
78
|
+
*
|
|
79
|
+
* Algorithm:
|
|
80
|
+
* 1. Collect all exclusions whose y-band intersects the line.
|
|
81
|
+
* 2. For each, derive the "blocked" x-interval on the content axis
|
|
82
|
+
* based on `wrapSide`:
|
|
83
|
+
* - `bothSides` blocks `[xLeft, xRight]` only.
|
|
84
|
+
* - `left` blocks `[xLeft, contentWidth]` (text wraps on the
|
|
85
|
+
* float's left side only).
|
|
86
|
+
* - `right` blocks `[0, xRight]`.
|
|
87
|
+
* - `largest` picks whichever side of the float is wider; the
|
|
88
|
+
* narrower side is blocked.
|
|
89
|
+
* 3. Subtract every blocked interval from `[0, contentWidth]` and
|
|
90
|
+
* return the longest remaining gap.
|
|
91
|
+
*/
|
|
92
|
+
function availableSlotForLine(ctx, lineY, lineHeight) {
|
|
93
|
+
const lineBottom = lineY + lineHeight;
|
|
94
|
+
const blocked = [];
|
|
95
|
+
for (const ex of ctx.exclusions) {
|
|
96
|
+
// Strict overlap check: a line that just touches the float's
|
|
97
|
+
// bottom edge (`lineY === ex.yBottom`) does NOT need to wrap.
|
|
98
|
+
if (lineBottom <= ex.yTop || lineY >= ex.yBottom) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const exLeft = Math.max(0, ex.xLeft);
|
|
102
|
+
const exRight = Math.min(ctx.contentWidth, ex.xRight);
|
|
103
|
+
if (exLeft >= exRight) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
switch (ex.wrapSide) {
|
|
107
|
+
case "bothSides":
|
|
108
|
+
blocked.push({ lo: exLeft, hi: exRight });
|
|
109
|
+
break;
|
|
110
|
+
case "left":
|
|
111
|
+
// Float blocks the right half of the line.
|
|
112
|
+
blocked.push({ lo: exLeft, hi: ctx.contentWidth });
|
|
113
|
+
break;
|
|
114
|
+
case "right":
|
|
115
|
+
blocked.push({ lo: 0, hi: exRight });
|
|
116
|
+
break;
|
|
117
|
+
case "largest": {
|
|
118
|
+
const leftSpace = exLeft;
|
|
119
|
+
const rightSpace = ctx.contentWidth - exRight;
|
|
120
|
+
if (rightSpace >= leftSpace) {
|
|
121
|
+
// Wrap on the right (block to the left of the float).
|
|
122
|
+
blocked.push({ lo: 0, hi: exRight });
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
blocked.push({ lo: exLeft, hi: ctx.contentWidth });
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (blocked.length === 0) {
|
|
132
|
+
return { xOffset: 0, width: ctx.contentWidth };
|
|
133
|
+
}
|
|
134
|
+
// Merge overlapping blocked intervals.
|
|
135
|
+
blocked.sort((a, b) => a.lo - b.lo);
|
|
136
|
+
const merged = [];
|
|
137
|
+
for (const seg of blocked) {
|
|
138
|
+
const last = merged[merged.length - 1];
|
|
139
|
+
if (last && seg.lo <= last.hi) {
|
|
140
|
+
last.hi = Math.max(last.hi, seg.hi);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
merged.push({ lo: seg.lo, hi: seg.hi });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Build available gaps in [0, contentWidth] minus the merged blocks.
|
|
147
|
+
const gaps = [];
|
|
148
|
+
let cursor = 0;
|
|
149
|
+
for (const seg of merged) {
|
|
150
|
+
if (seg.lo > cursor) {
|
|
151
|
+
gaps.push({ x: cursor, width: seg.lo - cursor });
|
|
152
|
+
}
|
|
153
|
+
cursor = Math.max(cursor, seg.hi);
|
|
154
|
+
}
|
|
155
|
+
if (cursor < ctx.contentWidth) {
|
|
156
|
+
gaps.push({ x: cursor, width: ctx.contentWidth - cursor });
|
|
157
|
+
}
|
|
158
|
+
if (gaps.length === 0) {
|
|
159
|
+
// Line entirely blocked. Fall back to full content width to avoid
|
|
160
|
+
// pathological zero-width wraps that would loop forever; the line
|
|
161
|
+
// visually overlaps the float (fail-safe behaviour).
|
|
162
|
+
return { xOffset: 0, width: ctx.contentWidth };
|
|
163
|
+
}
|
|
164
|
+
// Pick the widest gap.
|
|
165
|
+
let best = gaps[0];
|
|
166
|
+
for (let i = 1; i < gaps.length; i++) {
|
|
167
|
+
if (gaps[i].width > best.width) {
|
|
168
|
+
best = gaps[i];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return { xOffset: best.x, width: best.width };
|
|
172
|
+
}
|
|
173
|
+
function twipsToPt(twips) {
|
|
174
|
+
return twips / 20;
|
|
175
|
+
}
|
|
176
|
+
function buildPage(doc, pageNumber, layout, options, pendingFootnoteIds) {
|
|
177
|
+
const sectionProps = doc.sectionProperties;
|
|
178
|
+
const geometry = computePageGeometry(sectionProps, options?.pageGeometry);
|
|
179
|
+
const content = [];
|
|
180
|
+
const imageMap = buildImageMap(doc.images);
|
|
181
|
+
/**
|
|
182
|
+
* Footnote ids referenced from the raw `BodyContent` items assigned
|
|
183
|
+
* to this page, collected as we iterate so the order is the
|
|
184
|
+
* document-reading order. Pending ids carried over from the
|
|
185
|
+
* previous page are queued ahead so they render before this page's
|
|
186
|
+
* own newly-introduced notes.
|
|
187
|
+
*/
|
|
188
|
+
const footnoteRefIds = [...pendingFootnoteIds];
|
|
189
|
+
/**
|
|
190
|
+
* Wrap exclusion zones from floats with `square` / `tight` /
|
|
191
|
+
* `through` wrap, populated as we iterate so subsequent paragraphs
|
|
192
|
+
* (later in document order) avoid them line-by-line. Floats that
|
|
193
|
+
* appear AFTER a paragraph in the source do not push back into
|
|
194
|
+
* preceding lines — this matches Word's behaviour where re-flow on
|
|
195
|
+
* insertion happens at edit time, not render time.
|
|
196
|
+
*/
|
|
197
|
+
const pageExclusions = [];
|
|
198
|
+
let cursorY = 0; // relative to content area top
|
|
199
|
+
for (let i = 0; i < doc.body.length; i++) {
|
|
200
|
+
if (layout.contentPages[i] !== pageNumber) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const item = doc.body[i];
|
|
204
|
+
collectFootnoteRefsFromBody(item, footnoteRefIds);
|
|
205
|
+
const pageContext = {
|
|
206
|
+
exclusions: pageExclusions,
|
|
207
|
+
contentWidth: geometry.contentWidth
|
|
208
|
+
};
|
|
209
|
+
switch (item.type) {
|
|
210
|
+
case "paragraph": {
|
|
211
|
+
const laid = layoutParagraph(item, cursorY, geometry.contentWidth, options, pageContext, imageMap);
|
|
212
|
+
content.push({ ...laid, sourceIndex: i });
|
|
213
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case "table": {
|
|
217
|
+
const laid = layoutTable(item, cursorY, geometry.contentWidth, i, options, imageMap);
|
|
218
|
+
content.push(laid);
|
|
219
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case "floatingImage": {
|
|
223
|
+
const laid = layoutFloatingImage(item, cursorY, geometry.contentWidth, geometry.contentHeight, geometry, i, imageMap);
|
|
224
|
+
content.push(laid);
|
|
225
|
+
// Cursor advancement strategy:
|
|
226
|
+
// - `wrap.style === "topAndBottom"` (or no wrap and not
|
|
227
|
+
// behindDoc) forces body content to clear the float
|
|
228
|
+
// vertically; advance the cursor to the float's bottom edge
|
|
229
|
+
// plus the wrap.bottom margin.
|
|
230
|
+
// - `square` / `tight` / `through` register an exclusion zone
|
|
231
|
+
// so subsequent paragraph wrap avoids the float laterally;
|
|
232
|
+
// the body cursor is NOT advanced (text wraps around).
|
|
233
|
+
// - Behind-document floats never displace text.
|
|
234
|
+
// - Inline-like floats (no anchor, no behindDoc) keep the
|
|
235
|
+
// backwards-compatible advance behaviour.
|
|
236
|
+
const hasAnchor = item.simplePos != null ||
|
|
237
|
+
item.horizontalPosition != null ||
|
|
238
|
+
item.verticalPosition != null;
|
|
239
|
+
const wrapStyle = item.wrap?.style;
|
|
240
|
+
const isWrapAround = wrapStyle === "square" || wrapStyle === "tight" || wrapStyle === "through";
|
|
241
|
+
const advanceCursor = (!hasAnchor && !item.behindDoc && !isWrapAround) || wrapStyle === "topAndBottom";
|
|
242
|
+
if (advanceCursor) {
|
|
243
|
+
const padBottom = item.wrap?.margins?.bottom ? emuToPt(item.wrap.margins.bottom) : 0;
|
|
244
|
+
cursorY = laid.rect.y + laid.rect.height + padBottom;
|
|
245
|
+
}
|
|
246
|
+
if (isWrapAround && !item.behindDoc) {
|
|
247
|
+
// Add an exclusion band covering the float's rect plus its
|
|
248
|
+
// wrap padding margins. Subsequent paragraphs (later in doc
|
|
249
|
+
// order) will wrap their lines around this rectangle.
|
|
250
|
+
const padL = laid.wrap?.margins?.left ?? 0;
|
|
251
|
+
const padR = laid.wrap?.margins?.right ?? 0;
|
|
252
|
+
const padT = laid.wrap?.margins?.top ?? 0;
|
|
253
|
+
const padB = laid.wrap?.margins?.bottom ?? 0;
|
|
254
|
+
pageExclusions.push({
|
|
255
|
+
xLeft: laid.rect.x - padL,
|
|
256
|
+
xRight: laid.rect.x + laid.rect.width + padR,
|
|
257
|
+
yTop: laid.rect.y - padT,
|
|
258
|
+
yBottom: laid.rect.y + laid.rect.height + padB,
|
|
259
|
+
wrapSide: laid.wrap?.side ?? "bothSides"
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
case "textBox": {
|
|
265
|
+
const laid = layoutTextBox(item, cursorY, geometry.contentWidth, i, options, imageMap);
|
|
266
|
+
content.push(laid);
|
|
267
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
case "drawingShape": {
|
|
271
|
+
const laid = layoutDrawingShape(item, cursorY, geometry.contentWidth, i, options, imageMap);
|
|
272
|
+
content.push(laid);
|
|
273
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
case "chart":
|
|
277
|
+
case "chartEx": {
|
|
278
|
+
const laid = layoutChart(item, cursorY, geometry.contentWidth, i);
|
|
279
|
+
content.push(laid);
|
|
280
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case "sdt": {
|
|
284
|
+
const laid = layoutSdt(item, cursorY, geometry.contentWidth, i, options, imageMap);
|
|
285
|
+
content.push(laid);
|
|
286
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "math": {
|
|
290
|
+
const laid = layoutMath(item, cursorY, geometry.contentWidth, i, options);
|
|
291
|
+
content.push(laid);
|
|
292
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
case "checkBox": {
|
|
296
|
+
const laid = layoutCheckBox(item, cursorY, i, options);
|
|
297
|
+
content.push(laid);
|
|
298
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case "tableOfContents": {
|
|
302
|
+
const laid = layoutTableOfContents(item, cursorY, geometry.contentWidth, i, options, imageMap);
|
|
303
|
+
content.push(laid);
|
|
304
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
case "altChunk": {
|
|
308
|
+
const laid = layoutAltChunk(item, cursorY, geometry.contentWidth, i);
|
|
309
|
+
content.push(laid);
|
|
310
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
case "opaqueDrawing": {
|
|
314
|
+
const laid = layoutOpaqueDrawing(item, cursorY, geometry.contentWidth, i);
|
|
315
|
+
content.push(laid);
|
|
316
|
+
cursorY = laid.rect.y + laid.rect.height;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
default: {
|
|
320
|
+
// Compile-time exhaustiveness check. Adding a new variant to
|
|
321
|
+
// `BodyContent` triggers a TypeScript error here until a
|
|
322
|
+
// corresponding case + layout function are added above. This
|
|
323
|
+
// replaces the previous "Skip unsupported types" silent drop.
|
|
324
|
+
const _exhaustive = item;
|
|
325
|
+
throw new Error(`layoutDocumentFull: unhandled BodyContent variant ${_exhaustive.type}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const header = layoutHeader(doc, pageNumber, geometry, options, imageMap);
|
|
330
|
+
const footer = layoutFooter(doc, pageNumber, geometry, options, imageMap);
|
|
331
|
+
// Compute the absolute (page-y) lower edge of body content so the
|
|
332
|
+
// footnote layout knows how much vertical room is actually free.
|
|
333
|
+
// `cursorY` is content-area-relative; convert by adding `marginTop`.
|
|
334
|
+
const bodyBottomPageY = geometry.marginTop + cursorY;
|
|
335
|
+
const footnoteResult = layoutFootnotes(doc, footnoteRefIds, geometry, options, bodyBottomPageY, imageMap);
|
|
336
|
+
// Decide whether the visual separator above the footnote area is the
|
|
337
|
+
// standard "separator" or the wider "continuationSeparator".
|
|
338
|
+
// A continuation page is one whose footnote area is *entirely*
|
|
339
|
+
// composed of notes deferred from a previous page (no body item on
|
|
340
|
+
// this page introduces a new reference). Detect by comparing the
|
|
341
|
+
// footnote-id sequence against the supplied `pendingFootnoteIds`.
|
|
342
|
+
let footnoteSeparator;
|
|
343
|
+
if (footnoteResult.laid.length > 0) {
|
|
344
|
+
const introducedHere = footnoteRefIds.length > pendingFootnoteIds.length;
|
|
345
|
+
const sepKind = introducedHere
|
|
346
|
+
? "separator"
|
|
347
|
+
: "continuationSeparator";
|
|
348
|
+
// Place the rule a few points above the first footnote paragraph.
|
|
349
|
+
const stackTop = footnoteResult.laid[0].rect.y;
|
|
350
|
+
footnoteSeparator = { y: stackTop - 4, kind: sepKind };
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
page: {
|
|
354
|
+
pageNumber,
|
|
355
|
+
geometry,
|
|
356
|
+
content,
|
|
357
|
+
...(header.length > 0 ? { header } : {}),
|
|
358
|
+
...(footer.length > 0 ? { footer } : {}),
|
|
359
|
+
...(footnoteResult.laid.length > 0 ? { footnoteArea: footnoteResult.laid } : {}),
|
|
360
|
+
...(footnoteSeparator ? { footnoteSeparator } : {})
|
|
361
|
+
},
|
|
362
|
+
deferredFootnoteIds: footnoteResult.deferred
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function layoutFootnotes(doc, ids, geometry, options, bodyBottomPageY, imageMap) {
|
|
366
|
+
if (ids.length === 0 || !doc.footnotes || doc.footnotes.length === 0) {
|
|
367
|
+
return { laid: [], deferred: [] };
|
|
368
|
+
}
|
|
369
|
+
const noteById = new Map();
|
|
370
|
+
for (const note of doc.footnotes) {
|
|
371
|
+
const kind = note.type ?? "normal";
|
|
372
|
+
if (kind === "normal") {
|
|
373
|
+
noteById.set(note.id, note);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const footerOffsetPt = geometry.height - twipsToPt(doc.sectionProperties?.margins?.footer ?? 720);
|
|
377
|
+
/**
|
|
378
|
+
* Vertical room available for the footnote stack on this page.
|
|
379
|
+
* The stack must sit between `bodyBottomPageY` (top) and
|
|
380
|
+
* `footerOffsetPt` (bottom); anything that doesn't fit gets
|
|
381
|
+
* deferred. A small minimum is enforced so a page that's almost
|
|
382
|
+
* full still flushes at least one footnote (the alternative —
|
|
383
|
+
* deferring everything indefinitely — would loop forever in
|
|
384
|
+
* pathological inputs).
|
|
385
|
+
*/
|
|
386
|
+
const availableSpace = Math.max(0, footerOffsetPt - bodyBottomPageY);
|
|
387
|
+
const seen = new Set();
|
|
388
|
+
const laidPerNote = [];
|
|
389
|
+
const heightPerNote = [];
|
|
390
|
+
const idsLaid = [];
|
|
391
|
+
for (const id of ids) {
|
|
392
|
+
if (seen.has(id)) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
seen.add(id);
|
|
396
|
+
const note = noteById.get(id);
|
|
397
|
+
if (!note) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const note_paragraphs = [];
|
|
401
|
+
let cursor = 0;
|
|
402
|
+
for (const para of note.content) {
|
|
403
|
+
if (para.type !== "paragraph") {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
const p = layoutParagraph(para, cursor, geometry.contentWidth, options, undefined, imageMap);
|
|
407
|
+
note_paragraphs.push(p);
|
|
408
|
+
cursor = p.rect.y + p.rect.height;
|
|
409
|
+
}
|
|
410
|
+
laidPerNote.push(note_paragraphs);
|
|
411
|
+
heightPerNote.push(cursor);
|
|
412
|
+
idsLaid.push(id);
|
|
413
|
+
}
|
|
414
|
+
// Greedily fit notes into the available space. The first note is
|
|
415
|
+
// always laid out — even if it overflows — so a page that
|
|
416
|
+
// references a single oversized note still renders something
|
|
417
|
+
// (avoids losing data); the renderer will visually clip into the
|
|
418
|
+
// bottom margin in that pathological case.
|
|
419
|
+
const fitNotes = [];
|
|
420
|
+
const fitHeights = [];
|
|
421
|
+
const deferred = [];
|
|
422
|
+
let stackHeight = 0;
|
|
423
|
+
for (let i = 0; i < idsLaid.length; i++) {
|
|
424
|
+
const noteHeight = heightPerNote[i];
|
|
425
|
+
const wouldBe = stackHeight + noteHeight;
|
|
426
|
+
const fitsCleanly = wouldBe <= availableSpace;
|
|
427
|
+
const isFirstAndForced = fitNotes.length === 0;
|
|
428
|
+
if (fitsCleanly || isFirstAndForced) {
|
|
429
|
+
fitNotes.push(laidPerNote[i]);
|
|
430
|
+
fitHeights.push(noteHeight);
|
|
431
|
+
stackHeight = wouldBe;
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
deferred.push(idsLaid[i]);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
if (fitNotes.length === 0) {
|
|
438
|
+
return { laid: [], deferred };
|
|
439
|
+
}
|
|
440
|
+
// Translate the whole stack so its bottom edge is at footerOffsetPt.
|
|
441
|
+
const top = footerOffsetPt - stackHeight;
|
|
442
|
+
const flat = [];
|
|
443
|
+
let runningOffset = top;
|
|
444
|
+
for (let i = 0; i < fitNotes.length; i++) {
|
|
445
|
+
for (const p of fitNotes[i]) {
|
|
446
|
+
flat.push({
|
|
447
|
+
...p,
|
|
448
|
+
rect: { ...p.rect, y: p.rect.y + runningOffset }
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
runningOffset += fitHeights[i];
|
|
452
|
+
}
|
|
453
|
+
return { laid: flat, deferred };
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Walk a `BodyContent` item's run-level descendants and append every
|
|
457
|
+
* `FootnoteRefContent` id to `out`, in document order. Recurses into
|
|
458
|
+
* the few container variants whose children embed paragraphs (textBox,
|
|
459
|
+
* drawingShape, sdt, tableOfContents, table cells).
|
|
460
|
+
*/
|
|
461
|
+
function collectFootnoteRefsFromBody(item, out) {
|
|
462
|
+
switch (item.type) {
|
|
463
|
+
case "paragraph":
|
|
464
|
+
collectFootnoteRefsFromParagraph(item, out);
|
|
465
|
+
return;
|
|
466
|
+
case "table":
|
|
467
|
+
for (const r of item.rows) {
|
|
468
|
+
for (const c of r.cells) {
|
|
469
|
+
for (const inner of c.content) {
|
|
470
|
+
collectFootnoteRefsFromBody(inner, out);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return;
|
|
475
|
+
case "textBox":
|
|
476
|
+
for (const child of item.content) {
|
|
477
|
+
collectFootnoteRefsFromBody(child, out);
|
|
478
|
+
}
|
|
479
|
+
return;
|
|
480
|
+
case "drawingShape":
|
|
481
|
+
if (item.textContent) {
|
|
482
|
+
for (const child of item.textContent) {
|
|
483
|
+
collectFootnoteRefsFromBody(child, out);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return;
|
|
487
|
+
case "sdt":
|
|
488
|
+
for (const child of item.content) {
|
|
489
|
+
if (child && typeof child === "object" && "type" in child) {
|
|
490
|
+
collectFootnoteRefsFromBody(child, out);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return;
|
|
494
|
+
case "tableOfContents":
|
|
495
|
+
if (item.cachedParagraphs) {
|
|
496
|
+
for (const para of item.cachedParagraphs) {
|
|
497
|
+
collectFootnoteRefsFromBody(para, out);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return;
|
|
501
|
+
case "floatingImage":
|
|
502
|
+
case "math":
|
|
503
|
+
case "checkBox":
|
|
504
|
+
case "chart":
|
|
505
|
+
case "chartEx":
|
|
506
|
+
case "altChunk":
|
|
507
|
+
case "opaqueDrawing":
|
|
508
|
+
return;
|
|
509
|
+
default: {
|
|
510
|
+
const _exhaustive = item;
|
|
511
|
+
void _exhaustive;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function collectFootnoteRefsFromParagraph(para, out) {
|
|
516
|
+
for (const child of para.children) {
|
|
517
|
+
if ("type" in child && child.type === "hyperlink") {
|
|
518
|
+
collectFootnoteRefsFromHyperlink(child, out);
|
|
519
|
+
}
|
|
520
|
+
else if (!("type" in child) || child.type === undefined) {
|
|
521
|
+
// Plain Run (no `type` discriminator).
|
|
522
|
+
collectFootnoteRefsFromRun(child, out);
|
|
523
|
+
}
|
|
524
|
+
else if (child.type === "insertedRun" ||
|
|
525
|
+
child.type === "deletedRun" ||
|
|
526
|
+
child.type === "movedFromRun" ||
|
|
527
|
+
child.type === "movedToRun") {
|
|
528
|
+
// Tracked-change wrappers carry a single `run` (singular) per
|
|
529
|
+
// ECMA-376 — see `InsertedRun.run`, `DeletedRun.run`, etc.
|
|
530
|
+
collectFootnoteRefsFromRun(child.run, out);
|
|
531
|
+
}
|
|
532
|
+
// BookmarkStart / BookmarkEnd / Comment* / MoveRangeMarker /
|
|
533
|
+
// CustomXmlTrackingMarker carry no runnable text — nothing to
|
|
534
|
+
// collect.
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
function collectFootnoteRefsFromHyperlink(link, out) {
|
|
538
|
+
for (const child of link.children) {
|
|
539
|
+
if (!("type" in child) || child.type === undefined) {
|
|
540
|
+
collectFootnoteRefsFromRun(child, out);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function collectFootnoteRefsFromRun(run, out) {
|
|
545
|
+
if (!run || !Array.isArray(run.content)) {
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
for (const c of run.content) {
|
|
549
|
+
if (c.type === "footnoteRef") {
|
|
550
|
+
out.push(c.id);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Resolve which header reference to use for a given page within a
|
|
556
|
+
* section, per ECMA-376 §17.10:
|
|
557
|
+
*
|
|
558
|
+
* - `titlePage === true` and `pageNumber === 1` → the `"first"` reference
|
|
559
|
+
* - `evenAndOddHeaders === true` (settings) and even page number → `"even"`
|
|
560
|
+
* - otherwise → the `"default"` reference
|
|
561
|
+
*
|
|
562
|
+
* Each rule falls back to `"default"` (then to the first available ref)
|
|
563
|
+
* if its preferred type isn't declared in the section's references.
|
|
564
|
+
*/
|
|
565
|
+
function pickHeaderFooterRef(refs, pageNumber, titlePage, evenAndOdd) {
|
|
566
|
+
const find = (t) => refs.find(r => r.type === t);
|
|
567
|
+
if (titlePage && pageNumber === 1) {
|
|
568
|
+
const first = find("first");
|
|
569
|
+
if (first) {
|
|
570
|
+
return first;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
if (evenAndOdd && pageNumber % 2 === 0) {
|
|
574
|
+
const even = find("even");
|
|
575
|
+
if (even) {
|
|
576
|
+
return even;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return find("default") ?? refs[0];
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Lay out the paragraphs and tables of the resolved header for a page.
|
|
583
|
+
*
|
|
584
|
+
* Resolution order: first/even/default per `pickHeaderFooterRef`.
|
|
585
|
+
* The header band's local y-axis starts at the section's
|
|
586
|
+
* `pgMar.header` (in pt) below the page top, mirroring Word's
|
|
587
|
+
* "Header from top" setting; renderers consume the resulting layout-y
|
|
588
|
+
* directly as a page-y offset.
|
|
589
|
+
*
|
|
590
|
+
* Tables in header content are laid out with the same `layoutTable`
|
|
591
|
+
* that body content uses, and surfaced via the union type on
|
|
592
|
+
* `LayoutPage.header` so renderers can pick them up alongside
|
|
593
|
+
* paragraphs without a special path.
|
|
594
|
+
*/
|
|
595
|
+
function layoutHeader(doc, pageNumber, geometry, options, imageMap) {
|
|
596
|
+
const refs = doc.sectionProperties?.headers;
|
|
597
|
+
if (!refs || refs.length === 0) {
|
|
598
|
+
return [];
|
|
599
|
+
}
|
|
600
|
+
const titlePage = doc.sectionProperties?.titlePage === true;
|
|
601
|
+
const evenAndOdd = doc.settings?.evenAndOddHeaders === true;
|
|
602
|
+
const ref = pickHeaderFooterRef(refs, pageNumber, titlePage, evenAndOdd);
|
|
603
|
+
if (!ref) {
|
|
604
|
+
return [];
|
|
605
|
+
}
|
|
606
|
+
const part = doc.headers?.get(ref.rId);
|
|
607
|
+
if (!part) {
|
|
608
|
+
return [];
|
|
609
|
+
}
|
|
610
|
+
const headerOffsetPt = twipsToPt(doc.sectionProperties?.margins?.header ?? 720);
|
|
611
|
+
return layoutHeaderFooterChildren(part.content.children, headerOffsetPt, geometry, options, imageMap);
|
|
612
|
+
}
|
|
613
|
+
function layoutFooter(doc, pageNumber, geometry, options, imageMap) {
|
|
614
|
+
const refs = doc.sectionProperties?.footers;
|
|
615
|
+
if (!refs || refs.length === 0) {
|
|
616
|
+
return [];
|
|
617
|
+
}
|
|
618
|
+
const titlePage = doc.sectionProperties?.titlePage === true;
|
|
619
|
+
const evenAndOdd = doc.settings?.evenAndOddHeaders === true;
|
|
620
|
+
const ref = pickHeaderFooterRef(refs, pageNumber, titlePage, evenAndOdd);
|
|
621
|
+
if (!ref) {
|
|
622
|
+
return [];
|
|
623
|
+
}
|
|
624
|
+
const part = doc.footers?.get(ref.rId);
|
|
625
|
+
if (!part) {
|
|
626
|
+
return [];
|
|
627
|
+
}
|
|
628
|
+
// Footer band starts at `pageHeight - pgMar.footer` so layout-y is
|
|
629
|
+
// already a page-absolute coordinate (matching the header path,
|
|
630
|
+
// where `pgMar.header` is the absolute offset of the band from the
|
|
631
|
+
// page top). Renderers consume both bands with the same
|
|
632
|
+
// "treat layout-y as page-y" rule.
|
|
633
|
+
const footerOffsetPt = geometry.height - twipsToPt(doc.sectionProperties?.margins?.footer ?? 720);
|
|
634
|
+
return layoutHeaderFooterChildren(part.content.children, footerOffsetPt, geometry, options, imageMap);
|
|
635
|
+
}
|
|
636
|
+
function layoutHeaderFooterChildren(children, initialCursorY, geometry, options, imageMap) {
|
|
637
|
+
const out = [];
|
|
638
|
+
let cursor = initialCursorY;
|
|
639
|
+
for (let idx = 0; idx < children.length; idx++) {
|
|
640
|
+
const child = children[idx];
|
|
641
|
+
if (child.type === "paragraph") {
|
|
642
|
+
const laid = layoutParagraph(child, cursor, geometry.contentWidth, options, undefined, imageMap);
|
|
643
|
+
out.push(laid);
|
|
644
|
+
cursor = laid.rect.y + laid.rect.height;
|
|
645
|
+
}
|
|
646
|
+
else if (child.type === "table") {
|
|
647
|
+
const laid = layoutTable(child, cursor, geometry.contentWidth, idx, options, imageMap);
|
|
648
|
+
out.push(laid);
|
|
649
|
+
cursor = laid.rect.y + laid.rect.height;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
return out;
|
|
653
|
+
}
|
|
654
|
+
function computePageGeometry(sectionProps, override) {
|
|
655
|
+
const widthTwips = sectionProps?.pageSize?.width ?? layout_constants_1.DEFAULT_PAGE_WIDTH_TWIPS;
|
|
656
|
+
const heightTwips = sectionProps?.pageSize?.height ?? layout_constants_1.DEFAULT_PAGE_HEIGHT_TWIPS;
|
|
657
|
+
const sectionWidth = twipsToPt(widthTwips);
|
|
658
|
+
const sectionHeight = twipsToPt(heightTwips);
|
|
659
|
+
const sectionMarginTop = twipsToPt(sectionProps?.margins?.top ?? layout_constants_1.DEFAULT_PAGE_MARGIN_TWIPS);
|
|
660
|
+
const sectionMarginBottom = twipsToPt(sectionProps?.margins?.bottom ?? layout_constants_1.DEFAULT_PAGE_MARGIN_TWIPS);
|
|
661
|
+
const sectionMarginLeft = twipsToPt(sectionProps?.margins?.left ?? layout_constants_1.DEFAULT_PAGE_MARGIN_TWIPS);
|
|
662
|
+
const sectionMarginRight = twipsToPt(sectionProps?.margins?.right ?? layout_constants_1.DEFAULT_PAGE_MARGIN_TWIPS);
|
|
663
|
+
// Per-axis override: callers (PDF bridge, custom hosts) may want to
|
|
664
|
+
// pin the page size or margin on one axis without disturbing the
|
|
665
|
+
// others — `pageWidth` doesn't imply overriding margins, etc.
|
|
666
|
+
const width = override?.pageWidth ?? sectionWidth;
|
|
667
|
+
const height = override?.pageHeight ?? sectionHeight;
|
|
668
|
+
const marginTop = override?.marginTop ?? sectionMarginTop;
|
|
669
|
+
const marginBottom = override?.marginBottom ?? sectionMarginBottom;
|
|
670
|
+
const marginLeft = override?.marginLeft ?? sectionMarginLeft;
|
|
671
|
+
const marginRight = override?.marginRight ?? sectionMarginRight;
|
|
672
|
+
return {
|
|
673
|
+
width,
|
|
674
|
+
height,
|
|
675
|
+
marginTop,
|
|
676
|
+
marginBottom,
|
|
677
|
+
marginLeft,
|
|
678
|
+
marginRight,
|
|
679
|
+
contentWidth: width - marginLeft - marginRight,
|
|
680
|
+
contentHeight: height - marginTop - marginBottom
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
function computeSectionBreaks(layout) {
|
|
684
|
+
const breaks = [0]; // First section starts at page 0
|
|
685
|
+
let prevSection = 0;
|
|
686
|
+
for (let i = 0; i < layout.contentPages.length; i++) {
|
|
687
|
+
const section = layout.contentSections[i];
|
|
688
|
+
if (section > prevSection) {
|
|
689
|
+
breaks.push(layout.contentPages[i] - 1);
|
|
690
|
+
prevSection = section;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return breaks;
|
|
694
|
+
}
|
|
695
|
+
// =============================================================================
|
|
696
|
+
// Internal: Paragraph Layout
|
|
697
|
+
// =============================================================================
|
|
698
|
+
function layoutParagraph(para, startY, contentWidth, options, pageContext, imageMap) {
|
|
699
|
+
const props = para.properties;
|
|
700
|
+
const spacing = props?.spacing;
|
|
701
|
+
const headingScale = getHeadingFontScale(getHeadingLevel(props));
|
|
702
|
+
// Space before
|
|
703
|
+
let spaceBefore = 0;
|
|
704
|
+
if (spacing?.beforeAutoSpacing) {
|
|
705
|
+
spaceBefore = 5;
|
|
706
|
+
}
|
|
707
|
+
else if (spacing?.before != null) {
|
|
708
|
+
spaceBefore = twipsToPt(spacing.before);
|
|
709
|
+
}
|
|
710
|
+
const indent = props?.indent;
|
|
711
|
+
const leftIndentPt = indent?.left ? twipsToPt(indent.left) : 0;
|
|
712
|
+
const firstLineIndentPt = indent?.firstLine ? twipsToPt(indent.firstLine) : 0;
|
|
713
|
+
const alignment = props?.alignment ?? "left";
|
|
714
|
+
// Line height
|
|
715
|
+
let lineHeightPt = DEFAULT_FONT_SIZE_PT * 1.2;
|
|
716
|
+
if (spacing?.line) {
|
|
717
|
+
const rule = spacing.lineRule ?? "auto";
|
|
718
|
+
switch (rule) {
|
|
719
|
+
case "exact":
|
|
720
|
+
lineHeightPt = twipsToPt(spacing.line);
|
|
721
|
+
break;
|
|
722
|
+
case "atLeast":
|
|
723
|
+
lineHeightPt = Math.max(twipsToPt(spacing.line), lineHeightPt);
|
|
724
|
+
break;
|
|
725
|
+
case "auto":
|
|
726
|
+
lineHeightPt = DEFAULT_FONT_SIZE_PT * 1.2 * (spacing.line / 240);
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
lineHeightPt *= headingScale;
|
|
731
|
+
// Collect runs
|
|
732
|
+
const segments = collectParagraphSegments(para);
|
|
733
|
+
const fullAvailableWidth = contentWidth - leftIndentPt;
|
|
734
|
+
// When a page has wrap exclusions (square / tight / through floats)
|
|
735
|
+
// we wrap line-by-line, asking the page context for the widest free
|
|
736
|
+
// slot at the line's actual y-position. Otherwise we use the
|
|
737
|
+
// legacy single-width path which never re-evaluates width across
|
|
738
|
+
// lines — this preserves the existing layout output for documents
|
|
739
|
+
// with no wrap (the overwhelming majority).
|
|
740
|
+
let lines;
|
|
741
|
+
let perLineSlots;
|
|
742
|
+
if (pageContext && pageContext.exclusions.length > 0) {
|
|
743
|
+
const result = wrapSegmentsToLinesWithExclusions(segments, leftIndentPt, firstLineIndentPt, headingScale, lineHeightPt, startY + spaceBefore, pageContext);
|
|
744
|
+
lines = result.lines;
|
|
745
|
+
perLineSlots = result.slots;
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
lines = wrapSegmentsToLines(segments, fullAvailableWidth, firstLineIndentPt, headingScale);
|
|
749
|
+
}
|
|
750
|
+
// Build line boxes
|
|
751
|
+
const lineBoxes = [];
|
|
752
|
+
let yOffset = spaceBefore;
|
|
753
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
754
|
+
const lineSegments = lines[lineIdx];
|
|
755
|
+
const runs = [];
|
|
756
|
+
// Resolve the line's effective slot. With exclusions each line has
|
|
757
|
+
// its own usable [xOffset, width]; otherwise we keep the legacy
|
|
758
|
+
// single-width behaviour and place the first line indent.
|
|
759
|
+
const slot = perLineSlots?.[lineIdx] ?? {
|
|
760
|
+
xOffset: 0,
|
|
761
|
+
width: fullAvailableWidth
|
|
762
|
+
};
|
|
763
|
+
const lineLeftIndent = perLineSlots ? slot.xOffset : leftIndentPt;
|
|
764
|
+
const lineAvailableWidth = perLineSlots ? slot.width : fullAvailableWidth;
|
|
765
|
+
let xPos = lineIdx === 0 ? firstLineIndentPt : 0;
|
|
766
|
+
// Calculate line width for alignment, and find the tallest item
|
|
767
|
+
// so the line's height accommodates inline images.
|
|
768
|
+
let lineWidth = 0;
|
|
769
|
+
let lineMaxHeight = lineHeightPt;
|
|
770
|
+
for (const seg of lineSegments) {
|
|
771
|
+
if ("type" in seg && seg.type === "image") {
|
|
772
|
+
const w = emuToPt(seg.content.width);
|
|
773
|
+
const h = emuToPt(seg.content.height);
|
|
774
|
+
lineWidth += w;
|
|
775
|
+
if (h > lineMaxHeight) {
|
|
776
|
+
lineMaxHeight = h;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
const fontSize = getRunFontSizePt(seg.properties) * headingScale;
|
|
781
|
+
const fontName = (0, font_metrics_1.mapToStandardFont)(resolveRunFontName(seg.properties));
|
|
782
|
+
lineWidth += (0, font_metrics_1.measureTextWidth)(seg.text, fontName, fontSize);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
// Apply alignment
|
|
786
|
+
if (alignment === "center") {
|
|
787
|
+
xPos = (lineAvailableWidth - lineWidth) / 2;
|
|
788
|
+
}
|
|
789
|
+
else if (alignment === "right" || alignment === "end") {
|
|
790
|
+
xPos = lineAvailableWidth - lineWidth;
|
|
791
|
+
}
|
|
792
|
+
xPos += lineLeftIndent;
|
|
793
|
+
for (const seg of lineSegments) {
|
|
794
|
+
if ("type" in seg && seg.type === "image") {
|
|
795
|
+
const widthPt = emuToPt(seg.content.width);
|
|
796
|
+
const heightPt = emuToPt(seg.content.height);
|
|
797
|
+
const img = seg.content.rId ? imageMap?.get(seg.content.rId) : undefined;
|
|
798
|
+
runs.push({
|
|
799
|
+
type: "image",
|
|
800
|
+
x: xPos,
|
|
801
|
+
width: widthPt,
|
|
802
|
+
height: heightPt,
|
|
803
|
+
data: img?.data ?? new Uint8Array(0),
|
|
804
|
+
mimeType: mediaTypeToMime(img?.mediaType),
|
|
805
|
+
altText: seg.content.altText
|
|
806
|
+
});
|
|
807
|
+
xPos += widthPt;
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
const fontSize = getRunFontSizePt(seg.properties) * headingScale;
|
|
811
|
+
const fontName = resolveRunFontName(seg.properties);
|
|
812
|
+
const measuredFont = (0, font_metrics_1.mapToStandardFont)(fontName);
|
|
813
|
+
const segWidth = (0, font_metrics_1.measureTextWidth)(seg.text, measuredFont, fontSize);
|
|
814
|
+
runs.push({
|
|
815
|
+
text: seg.text,
|
|
816
|
+
x: xPos,
|
|
817
|
+
width: segWidth,
|
|
818
|
+
font: fontName,
|
|
819
|
+
fontSize,
|
|
820
|
+
bold: seg.properties?.bold || undefined,
|
|
821
|
+
italic: seg.properties?.italic || undefined,
|
|
822
|
+
color: resolveColorHex(seg.properties?.color),
|
|
823
|
+
underline: seg.properties?.underline !== undefined ? true : undefined,
|
|
824
|
+
strikethrough: seg.properties?.strike || undefined,
|
|
825
|
+
verticalAlign: seg.properties?.vertAlign === "superscript" || seg.properties?.vertAlign === "subscript"
|
|
826
|
+
? seg.properties.vertAlign
|
|
827
|
+
: undefined
|
|
828
|
+
});
|
|
829
|
+
xPos += segWidth;
|
|
830
|
+
}
|
|
831
|
+
const mappedAlignment = alignment === "both"
|
|
832
|
+
? "justify"
|
|
833
|
+
: alignment === "end"
|
|
834
|
+
? "right"
|
|
835
|
+
: alignment === "start"
|
|
836
|
+
? "left"
|
|
837
|
+
: alignment;
|
|
838
|
+
lineBoxes.push({
|
|
839
|
+
y: yOffset,
|
|
840
|
+
height: lineMaxHeight,
|
|
841
|
+
// Baseline for text sits at 80% of line height; for an
|
|
842
|
+
// image-dominant line this puts the image's bottom near the
|
|
843
|
+
// baseline, matching Word's default inline-image alignment.
|
|
844
|
+
baseline: lineMaxHeight * 0.8,
|
|
845
|
+
runs,
|
|
846
|
+
alignment: mappedAlignment
|
|
847
|
+
});
|
|
848
|
+
yOffset += lineMaxHeight;
|
|
849
|
+
}
|
|
850
|
+
// If empty paragraph, still advance by one line
|
|
851
|
+
if (lineBoxes.length === 0) {
|
|
852
|
+
yOffset += lineHeightPt;
|
|
853
|
+
}
|
|
854
|
+
// Space after
|
|
855
|
+
let spaceAfter = 0;
|
|
856
|
+
if (spacing?.afterAutoSpacing) {
|
|
857
|
+
spaceAfter = 5;
|
|
858
|
+
}
|
|
859
|
+
else if (spacing?.after != null) {
|
|
860
|
+
spaceAfter = twipsToPt(spacing.after);
|
|
861
|
+
}
|
|
862
|
+
const totalHeight = yOffset + spaceAfter;
|
|
863
|
+
return {
|
|
864
|
+
type: "paragraph",
|
|
865
|
+
rect: { x: 0, y: startY, width: contentWidth, height: totalHeight },
|
|
866
|
+
lines: lineBoxes,
|
|
867
|
+
sourceIndex: 0 // overwritten by caller
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
// =============================================================================
|
|
871
|
+
// Internal: Table Layout
|
|
872
|
+
// =============================================================================
|
|
873
|
+
function layoutTable(table, startY, contentWidth, sourceIndex, options, imageMap) {
|
|
874
|
+
const numCols = table.rows.length > 0 ? table.rows[0].cells.length : 0;
|
|
875
|
+
const colWidth = numCols > 0 ? contentWidth / numCols : contentWidth;
|
|
876
|
+
const cells = [];
|
|
877
|
+
let cursorY = 0;
|
|
878
|
+
for (let ri = 0; ri < table.rows.length; ri++) {
|
|
879
|
+
const row = table.rows[ri];
|
|
880
|
+
let maxRowHeight = DEFAULT_FONT_SIZE_PT * 1.5; // minimum row height
|
|
881
|
+
for (let ci = 0; ci < row.cells.length; ci++) {
|
|
882
|
+
const cell = row.cells[ci];
|
|
883
|
+
const cellX = ci * colWidth;
|
|
884
|
+
const cellContent = [];
|
|
885
|
+
let cellCursorY = 2; // cell padding top
|
|
886
|
+
for (const block of cell.content) {
|
|
887
|
+
if (block.type === "paragraph") {
|
|
888
|
+
const laid = layoutParagraph(block, cellCursorY, colWidth - 4, options, undefined, imageMap);
|
|
889
|
+
cellContent.push({ ...laid, sourceIndex: -1 });
|
|
890
|
+
cellCursorY = laid.rect.y + laid.rect.height;
|
|
891
|
+
}
|
|
892
|
+
// nested tables skipped for simplicity
|
|
893
|
+
}
|
|
894
|
+
const cellHeight = cellCursorY + 2; // cell padding bottom
|
|
895
|
+
if (cellHeight > maxRowHeight) {
|
|
896
|
+
maxRowHeight = cellHeight;
|
|
897
|
+
}
|
|
898
|
+
cells.push({
|
|
899
|
+
rect: { x: cellX, y: startY + cursorY, width: colWidth, height: cellHeight },
|
|
900
|
+
row: ri,
|
|
901
|
+
col: ci,
|
|
902
|
+
content: cellContent
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
// Normalize cell heights to row max
|
|
906
|
+
for (const c of cells) {
|
|
907
|
+
if (c.row === ri) {
|
|
908
|
+
c.rect.height = maxRowHeight;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
cursorY += maxRowHeight;
|
|
912
|
+
}
|
|
913
|
+
return {
|
|
914
|
+
type: "table",
|
|
915
|
+
rect: { x: 0, y: startY, width: contentWidth, height: cursorY },
|
|
916
|
+
cells,
|
|
917
|
+
sourceIndex
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Walk a paragraph's children and emit a flat sequence of paragraph
|
|
922
|
+
* segments — text runs preserve their formatting; inline images become
|
|
923
|
+
* dedicated `ImageSegment` tokens so the wrap engine treats them as
|
|
924
|
+
* unbreakable atoms positioned in document order. Hyperlinks are
|
|
925
|
+
* descended into; bookmark / comment / track-change wrappers are
|
|
926
|
+
* ignored for layout purposes.
|
|
927
|
+
*/
|
|
928
|
+
function collectParagraphSegments(para) {
|
|
929
|
+
const segments = [];
|
|
930
|
+
for (const child of para.children) {
|
|
931
|
+
if ((0, text_utils_1.isRun)(child)) {
|
|
932
|
+
pushRunSegments(child, segments);
|
|
933
|
+
}
|
|
934
|
+
else if ((0, text_utils_1.isHyperlink)(child)) {
|
|
935
|
+
for (const run of child.children) {
|
|
936
|
+
pushRunSegments(run, segments);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
return segments;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Emit `ParagraphSegment` tokens for a single run, preserving the
|
|
944
|
+
* relative order of text fragments and inline images. Consecutive
|
|
945
|
+
* text-bearing entries are coalesced into one `TextSegment` so the
|
|
946
|
+
* wrap engine sees fewer atoms.
|
|
947
|
+
*/
|
|
948
|
+
function pushRunSegments(run, out) {
|
|
949
|
+
let pending = "";
|
|
950
|
+
for (const item of run.content) {
|
|
951
|
+
if (item.type === "text") {
|
|
952
|
+
pending += item.text;
|
|
953
|
+
}
|
|
954
|
+
else if (item.type === "tab") {
|
|
955
|
+
pending += " ";
|
|
956
|
+
}
|
|
957
|
+
else if (item.type === "break") {
|
|
958
|
+
pending += "\n";
|
|
959
|
+
}
|
|
960
|
+
else if (item.type === "image") {
|
|
961
|
+
if (pending.length > 0) {
|
|
962
|
+
out.push({ text: pending, properties: run.properties });
|
|
963
|
+
pending = "";
|
|
964
|
+
}
|
|
965
|
+
out.push({ type: "image", content: item, properties: run.properties });
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (pending.length > 0) {
|
|
969
|
+
out.push({ text: pending, properties: run.properties });
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Wrap a paragraph's text segments into lines whose available widths
|
|
974
|
+
* vary based on per-line wrap exclusions (square / tight / through
|
|
975
|
+
* floats). Word-level break points only — character-level shaping is
|
|
976
|
+
* out of scope for the layout engine.
|
|
977
|
+
*
|
|
978
|
+
* Returns both the per-line `TextSegment[]` and a parallel array of
|
|
979
|
+
* `{ xOffset, width }` describing where each line is placed within
|
|
980
|
+
* the content area. Callers use the slot to set per-line indent /
|
|
981
|
+
* available width for alignment.
|
|
982
|
+
*/
|
|
983
|
+
function wrapSegmentsToLinesWithExclusions(segments, leftIndentPt, firstLineIndentPt, headingScale, lineHeightPt, paragraphTopPageY, pageContext) {
|
|
984
|
+
const atoms = [];
|
|
985
|
+
for (const seg of segments) {
|
|
986
|
+
if ("type" in seg && seg.type === "image") {
|
|
987
|
+
atoms.push({
|
|
988
|
+
width: emuToPt(seg.content.width),
|
|
989
|
+
isSpace: false,
|
|
990
|
+
isImage: true,
|
|
991
|
+
properties: seg.properties,
|
|
992
|
+
imageContent: seg.content
|
|
993
|
+
});
|
|
994
|
+
continue;
|
|
995
|
+
}
|
|
996
|
+
const fontSize = getRunFontSizePt(seg.properties) * headingScale;
|
|
997
|
+
const fontName = (0, font_metrics_1.mapToStandardFont)(resolveRunFontName(seg.properties));
|
|
998
|
+
// Split on runs of whitespace, keeping the whitespace tokens so
|
|
999
|
+
// wrapping can decide whether to drop trailing space at line end.
|
|
1000
|
+
const tokens = seg.text.split(/(\s+)/);
|
|
1001
|
+
for (const tok of tokens) {
|
|
1002
|
+
if (tok.length === 0) {
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
atoms.push({
|
|
1006
|
+
text: tok,
|
|
1007
|
+
width: (0, font_metrics_1.measureTextWidth)(tok, fontName, fontSize),
|
|
1008
|
+
properties: seg.properties,
|
|
1009
|
+
isSpace: /^\s+$/.test(tok),
|
|
1010
|
+
isImage: false
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
const lines = [];
|
|
1015
|
+
const slots = [];
|
|
1016
|
+
if (atoms.length === 0) {
|
|
1017
|
+
return { lines, slots };
|
|
1018
|
+
}
|
|
1019
|
+
let cursorAtom = 0;
|
|
1020
|
+
let lineIdx = 0;
|
|
1021
|
+
while (cursorAtom < atoms.length) {
|
|
1022
|
+
const lineY = paragraphTopPageY + lineIdx * lineHeightPt;
|
|
1023
|
+
const slot = availableSlotForLine(pageContext, lineY, lineHeightPt);
|
|
1024
|
+
// The first line of a paragraph may carry an extra `firstLineIndent`
|
|
1025
|
+
// (from `<w:ind firstLine="…"/>`) which subtracts from the usable
|
|
1026
|
+
// width on that line only. Subsequent lines use the full slot width
|
|
1027
|
+
// (offset by the paragraph's `leftIndentPt`, which is applied by
|
|
1028
|
+
// the caller's run x-positioning logic, not here).
|
|
1029
|
+
const indentForThisLine = lineIdx === 0 ? firstLineIndentPt : 0;
|
|
1030
|
+
let usable = slot.width - indentForThisLine;
|
|
1031
|
+
let lineXOffset = slot.xOffset + indentForThisLine;
|
|
1032
|
+
// Also subtract the paragraph's own leftIndentPt (which the legacy
|
|
1033
|
+
// path applies through `availableWidth = contentWidth -
|
|
1034
|
+
// leftIndentPt`). We mirror that here so wrap behaviour matches
|
|
1035
|
+
// when no exclusion is in play.
|
|
1036
|
+
if (slot.xOffset === 0 && leftIndentPt > 0) {
|
|
1037
|
+
usable -= leftIndentPt;
|
|
1038
|
+
lineXOffset += leftIndentPt;
|
|
1039
|
+
}
|
|
1040
|
+
if (usable <= 0) {
|
|
1041
|
+
// Pathological — the line is fully blocked or narrower than the
|
|
1042
|
+
// first-line indent. Skip the y position by advancing one line
|
|
1043
|
+
// height; placing zero-content lines indefinitely is worse than
|
|
1044
|
+
// leaving a small visual gap.
|
|
1045
|
+
lines.push([]);
|
|
1046
|
+
slots.push({ xOffset: lineXOffset, width: Math.max(0, usable) });
|
|
1047
|
+
lineIdx++;
|
|
1048
|
+
// Re-evaluate without retrying same atoms (no progress -> bail
|
|
1049
|
+
// after a sane number of retries to avoid infinite loops on a
|
|
1050
|
+
// degenerate page).
|
|
1051
|
+
if (lineIdx > 1000) {
|
|
1052
|
+
break;
|
|
1053
|
+
}
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
// Greedily pack atoms into the line until the next atom would
|
|
1057
|
+
// overflow `usable`. A leading whitespace atom on a fresh line is
|
|
1058
|
+
// dropped (matches typical text engines).
|
|
1059
|
+
if (atoms[cursorAtom].isSpace) {
|
|
1060
|
+
cursorAtom++;
|
|
1061
|
+
if (cursorAtom >= atoms.length) {
|
|
1062
|
+
break;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
const lineAtoms = [];
|
|
1066
|
+
let lineWidth = 0;
|
|
1067
|
+
while (cursorAtom < atoms.length) {
|
|
1068
|
+
const atom = atoms[cursorAtom];
|
|
1069
|
+
const next = lineWidth + atom.width;
|
|
1070
|
+
if (next > usable && lineAtoms.length > 0) {
|
|
1071
|
+
// Atom would overflow; commit the line and go to next.
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
lineAtoms.push(atom);
|
|
1075
|
+
lineWidth = next;
|
|
1076
|
+
cursorAtom++;
|
|
1077
|
+
}
|
|
1078
|
+
// Trim trailing whitespace so alignment computation is correct.
|
|
1079
|
+
// Don't trim trailing image atoms (they're not whitespace).
|
|
1080
|
+
while (lineAtoms.length > 0 && lineAtoms[lineAtoms.length - 1].isSpace) {
|
|
1081
|
+
const drop = lineAtoms.pop();
|
|
1082
|
+
lineWidth -= drop.width;
|
|
1083
|
+
}
|
|
1084
|
+
// Reassemble the line into `ParagraphSegment[]`. Adjacent text
|
|
1085
|
+
// atoms with identical properties merge; image atoms remain
|
|
1086
|
+
// standalone.
|
|
1087
|
+
const merged = [];
|
|
1088
|
+
for (const atom of lineAtoms) {
|
|
1089
|
+
if (atom.isImage) {
|
|
1090
|
+
merged.push({
|
|
1091
|
+
type: "image",
|
|
1092
|
+
content: atom.imageContent,
|
|
1093
|
+
properties: atom.properties
|
|
1094
|
+
});
|
|
1095
|
+
continue;
|
|
1096
|
+
}
|
|
1097
|
+
const last = merged[merged.length - 1];
|
|
1098
|
+
const lastIsText = last && !("type" in last);
|
|
1099
|
+
if (lastIsText && last.properties === atom.properties) {
|
|
1100
|
+
merged[merged.length - 1] = {
|
|
1101
|
+
text: last.text + atom.text,
|
|
1102
|
+
properties: atom.properties
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
else {
|
|
1106
|
+
merged.push({ text: atom.text, properties: atom.properties });
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
lines.push(merged);
|
|
1110
|
+
slots.push({ xOffset: lineXOffset, width: usable });
|
|
1111
|
+
lineIdx++;
|
|
1112
|
+
if (lineIdx > 100000) {
|
|
1113
|
+
// Defensive — degenerate inputs shouldn't loop the engine.
|
|
1114
|
+
break;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
return { lines, slots };
|
|
1118
|
+
}
|
|
1119
|
+
function wrapSegmentsToLines(segments, availableWidth, firstLineIndent, headingScale) {
|
|
1120
|
+
const lines = [];
|
|
1121
|
+
let currentLine = [];
|
|
1122
|
+
let currentLineWidth = 0;
|
|
1123
|
+
let isFirstLine = true;
|
|
1124
|
+
let effectiveWidth = availableWidth - firstLineIndent;
|
|
1125
|
+
const flushLine = () => {
|
|
1126
|
+
lines.push(currentLine);
|
|
1127
|
+
currentLine = [];
|
|
1128
|
+
currentLineWidth = 0;
|
|
1129
|
+
if (isFirstLine) {
|
|
1130
|
+
isFirstLine = false;
|
|
1131
|
+
effectiveWidth = availableWidth;
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
for (const segment of segments) {
|
|
1135
|
+
if ("type" in segment && segment.type === "image") {
|
|
1136
|
+
// Inline images are unbreakable atoms. Width comes from the
|
|
1137
|
+
// source EMU; if the image alone exceeds the line we still
|
|
1138
|
+
// place it (avoids losing content) — the renderer will overflow
|
|
1139
|
+
// visually on that line, matching Word's behaviour for
|
|
1140
|
+
// oversized inline images.
|
|
1141
|
+
const imageWidth = emuToPt(segment.content.width);
|
|
1142
|
+
const fitsCurrent = currentLineWidth + imageWidth <= effectiveWidth || currentLine.length === 0;
|
|
1143
|
+
if (!fitsCurrent) {
|
|
1144
|
+
flushLine();
|
|
1145
|
+
}
|
|
1146
|
+
currentLine.push(segment);
|
|
1147
|
+
currentLineWidth += imageWidth;
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
const text = segment.text;
|
|
1151
|
+
const fontSize = getRunFontSizePt(segment.properties) * headingScale;
|
|
1152
|
+
const fontName = (0, font_metrics_1.mapToStandardFont)(resolveRunFontName(segment.properties));
|
|
1153
|
+
const segmentWidth = (0, font_metrics_1.measureTextWidth)(text, fontName, fontSize);
|
|
1154
|
+
if (currentLineWidth + segmentWidth <= effectiveWidth || currentLine.length === 0) {
|
|
1155
|
+
currentLine.push(segment);
|
|
1156
|
+
currentLineWidth += segmentWidth;
|
|
1157
|
+
}
|
|
1158
|
+
else {
|
|
1159
|
+
// Word-level splitting
|
|
1160
|
+
const words = text.split(/(\s+)/);
|
|
1161
|
+
let bufferedText = "";
|
|
1162
|
+
let bufferedWidth = 0;
|
|
1163
|
+
for (const word of words) {
|
|
1164
|
+
const wordWidth = (0, font_metrics_1.measureTextWidth)(word, fontName, fontSize);
|
|
1165
|
+
if (currentLineWidth + bufferedWidth + wordWidth <= effectiveWidth ||
|
|
1166
|
+
(currentLine.length === 0 && bufferedText.length === 0)) {
|
|
1167
|
+
bufferedText += word;
|
|
1168
|
+
bufferedWidth += wordWidth;
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
if (bufferedText.length > 0) {
|
|
1172
|
+
currentLine.push({ text: bufferedText, properties: segment.properties });
|
|
1173
|
+
}
|
|
1174
|
+
flushLine();
|
|
1175
|
+
bufferedText = word;
|
|
1176
|
+
bufferedWidth = wordWidth;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (bufferedText.length > 0) {
|
|
1180
|
+
currentLine.push({ text: bufferedText, properties: segment.properties });
|
|
1181
|
+
currentLineWidth += bufferedWidth;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
if (currentLine.length > 0) {
|
|
1186
|
+
lines.push(currentLine);
|
|
1187
|
+
}
|
|
1188
|
+
if (lines.length === 0 && segments.length > 0) {
|
|
1189
|
+
lines.push(segments);
|
|
1190
|
+
}
|
|
1191
|
+
return lines;
|
|
1192
|
+
}
|
|
1193
|
+
function getHeadingLevel(props) {
|
|
1194
|
+
if (!props) {
|
|
1195
|
+
return 0;
|
|
1196
|
+
}
|
|
1197
|
+
if (props.outlineLevel !== undefined && props.outlineLevel >= 0 && props.outlineLevel <= 5) {
|
|
1198
|
+
return props.outlineLevel + 1;
|
|
1199
|
+
}
|
|
1200
|
+
if (props.style) {
|
|
1201
|
+
const match = /^[Hh]eading\s*(\d)$/i.exec(props.style);
|
|
1202
|
+
if (match) {
|
|
1203
|
+
return parseInt(match[1], 10);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return 0;
|
|
1207
|
+
}
|
|
1208
|
+
function getHeadingFontScale(level) {
|
|
1209
|
+
switch (level) {
|
|
1210
|
+
case 1:
|
|
1211
|
+
return 2.0;
|
|
1212
|
+
case 2:
|
|
1213
|
+
return 1.5;
|
|
1214
|
+
case 3:
|
|
1215
|
+
return 1.17;
|
|
1216
|
+
case 4:
|
|
1217
|
+
return 1.0;
|
|
1218
|
+
case 5:
|
|
1219
|
+
return 0.83;
|
|
1220
|
+
case 6:
|
|
1221
|
+
return 0.67;
|
|
1222
|
+
default:
|
|
1223
|
+
return 1.0;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Resolve the effective font size in points for a run.
|
|
1228
|
+
*
|
|
1229
|
+
* `<w:sz w:val="…"/>` is in half-points; we halve.
|
|
1230
|
+
*
|
|
1231
|
+
* Sub/superscript runs are conventionally rendered at ~65 % of the
|
|
1232
|
+
* surrounding text's size with a vertical baseline shift. The size
|
|
1233
|
+
* scaling lives here so every measurement (line width, line height,
|
|
1234
|
+
* wrap) sees the same value; the y-shift is applied at render time
|
|
1235
|
+
* via `PositionedRun.verticalAlign`.
|
|
1236
|
+
*/
|
|
1237
|
+
function getRunFontSizePt(props) {
|
|
1238
|
+
const base = props?.size ? props.size / 2 : DEFAULT_FONT_SIZE_PT;
|
|
1239
|
+
if (props?.vertAlign === "superscript" || props?.vertAlign === "subscript") {
|
|
1240
|
+
return base * 0.65;
|
|
1241
|
+
}
|
|
1242
|
+
return base;
|
|
1243
|
+
}
|
|
1244
|
+
function resolveRunFontName(props) {
|
|
1245
|
+
if (!props?.font) {
|
|
1246
|
+
return "Calibri";
|
|
1247
|
+
}
|
|
1248
|
+
if (typeof props.font === "string") {
|
|
1249
|
+
return props.font;
|
|
1250
|
+
}
|
|
1251
|
+
return props.font.ascii ?? "Calibri";
|
|
1252
|
+
}
|
|
1253
|
+
function resolveColorHex(color) {
|
|
1254
|
+
if (!color) {
|
|
1255
|
+
return undefined;
|
|
1256
|
+
}
|
|
1257
|
+
if (typeof color === "string") {
|
|
1258
|
+
return color;
|
|
1259
|
+
}
|
|
1260
|
+
if (typeof color === "object" && color !== null && "value" in color) {
|
|
1261
|
+
return color.value;
|
|
1262
|
+
}
|
|
1263
|
+
return undefined;
|
|
1264
|
+
}
|
|
1265
|
+
// =============================================================================
|
|
1266
|
+
// Internal: Image / Geometry Helpers
|
|
1267
|
+
// =============================================================================
|
|
1268
|
+
function emuToPt(emu) {
|
|
1269
|
+
return emu / units_1.EMU_PER_POINT;
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Convert the docx-internal `ImageMediaType` (`"png"`, `"jpeg"`, …)
|
|
1273
|
+
* to the standard MIME string consumers expect on
|
|
1274
|
+
* `LayoutImage.mimeType` / `PositionedInlineImage.mimeType`. Unknown
|
|
1275
|
+
* tags fall back to `application/octet-stream` so renderers can
|
|
1276
|
+
* decide whether to skip or draw a placeholder.
|
|
1277
|
+
*/
|
|
1278
|
+
function mediaTypeToMime(mt) {
|
|
1279
|
+
switch (mt) {
|
|
1280
|
+
case "png":
|
|
1281
|
+
return "image/png";
|
|
1282
|
+
case "jpeg":
|
|
1283
|
+
return "image/jpeg";
|
|
1284
|
+
case "gif":
|
|
1285
|
+
return "image/gif";
|
|
1286
|
+
case "bmp":
|
|
1287
|
+
return "image/bmp";
|
|
1288
|
+
case "tiff":
|
|
1289
|
+
return "image/tiff";
|
|
1290
|
+
case "svg":
|
|
1291
|
+
return "image/svg+xml";
|
|
1292
|
+
case "webp":
|
|
1293
|
+
return "image/webp";
|
|
1294
|
+
case "emf":
|
|
1295
|
+
return "image/x-emf";
|
|
1296
|
+
case "wmf":
|
|
1297
|
+
return "image/x-wmf";
|
|
1298
|
+
default:
|
|
1299
|
+
return "application/octet-stream";
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function buildImageMap(images) {
|
|
1303
|
+
const map = new Map();
|
|
1304
|
+
if (!images) {
|
|
1305
|
+
return map;
|
|
1306
|
+
}
|
|
1307
|
+
for (const img of images) {
|
|
1308
|
+
if (img.rId) {
|
|
1309
|
+
map.set(img.rId, img);
|
|
1310
|
+
}
|
|
1311
|
+
// Some images carry additional rIds (header/footer parts use their own
|
|
1312
|
+
// local id space). Index by every known rId so layout can resolve
|
|
1313
|
+
// either flavour.
|
|
1314
|
+
if (Array.isArray(img.altRIds)) {
|
|
1315
|
+
for (const aux of img.altRIds) {
|
|
1316
|
+
map.set(aux, img);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return map;
|
|
1321
|
+
}
|
|
1322
|
+
// =============================================================================
|
|
1323
|
+
// Internal: FloatingImage / TextBox / Shape / Chart / SDT / Math / CheckBox
|
|
1324
|
+
// =============================================================================
|
|
1325
|
+
/**
|
|
1326
|
+
* Resolve the page-content-area position of a floating image per
|
|
1327
|
+
* ECMA-376 §20.4.2.10. Layout coordinates have origin at the top-left
|
|
1328
|
+
* of the **content area**; floating-image anchors are normally
|
|
1329
|
+
* expressed against the **page** or **margin**, so we translate
|
|
1330
|
+
* accordingly.
|
|
1331
|
+
*
|
|
1332
|
+
* Resolution order:
|
|
1333
|
+
* 1. `simplePos="1"` (we currently see only `simplePos.x`/`simplePos.y`
|
|
1334
|
+
* in the model; we treat its presence as the simplePos override)
|
|
1335
|
+
* — page-absolute EMU.
|
|
1336
|
+
* 2. `horizontalPosition` / `verticalPosition` with `align` keywords
|
|
1337
|
+
* (left/center/right/inside/outside, top/center/bottom).
|
|
1338
|
+
* 3. `horizontalPosition` / `verticalPosition` with `offset` (EMU)
|
|
1339
|
+
* relative to the chosen `relativeTo` reference.
|
|
1340
|
+
* 4. Fall back to the cursor (inline-like behaviour).
|
|
1341
|
+
*
|
|
1342
|
+
* `relativeTo` reference points (subset we resolve):
|
|
1343
|
+
* - `"page"` — page top-left corner
|
|
1344
|
+
* - `"margin"` — margin box top-left corner (same as content area
|
|
1345
|
+
* origin in our coordinate system)
|
|
1346
|
+
* - `"column"` / `"character"` / `"paragraph"` etc. — fall back to the
|
|
1347
|
+
* cursor; reproducing them faithfully would require column/text-flow
|
|
1348
|
+
* info we don't keep at this stage.
|
|
1349
|
+
*/
|
|
1350
|
+
function resolveFloatingImageRect(fi, cursorY, contentWidth, contentHeight, geometry, widthPt, heightPt) {
|
|
1351
|
+
const usingSimplePos = fi.simplePos !== undefined;
|
|
1352
|
+
// 1. simplePos: page-absolute. Translate into content-area coords by
|
|
1353
|
+
// subtracting the page margins.
|
|
1354
|
+
if (usingSimplePos) {
|
|
1355
|
+
const pageX = emuToPt(fi.simplePos.x ?? 0);
|
|
1356
|
+
const pageY = emuToPt(fi.simplePos.y ?? 0);
|
|
1357
|
+
return {
|
|
1358
|
+
x: pageX - geometry.marginLeft,
|
|
1359
|
+
y: pageY - geometry.marginTop
|
|
1360
|
+
};
|
|
1361
|
+
}
|
|
1362
|
+
// 2/3. positionH / positionV
|
|
1363
|
+
const xPt = resolveHorizontal(fi, contentWidth, geometry, widthPt) ?? 0;
|
|
1364
|
+
const yPt = resolveVertical(fi, cursorY, contentHeight, geometry, heightPt) ?? cursorY;
|
|
1365
|
+
return { x: xPt, y: yPt };
|
|
1366
|
+
}
|
|
1367
|
+
function resolveHorizontal(fi, contentWidth, geometry, widthPt) {
|
|
1368
|
+
const h = fi.horizontalPosition;
|
|
1369
|
+
if (!h) {
|
|
1370
|
+
return undefined;
|
|
1371
|
+
}
|
|
1372
|
+
const relTo = h.relativeTo ?? "column";
|
|
1373
|
+
// Reference origin (in content-area coordinates) and width to anchor against.
|
|
1374
|
+
let originX = 0;
|
|
1375
|
+
let refWidth = contentWidth;
|
|
1376
|
+
if (relTo === "page") {
|
|
1377
|
+
originX = -geometry.marginLeft;
|
|
1378
|
+
refWidth = geometry.width;
|
|
1379
|
+
}
|
|
1380
|
+
else if (relTo === "margin" || relTo === "leftMargin" || relTo === "rightMargin") {
|
|
1381
|
+
originX = 0;
|
|
1382
|
+
refWidth = contentWidth;
|
|
1383
|
+
} // else: column/character/insideMargin/outsideMargin — fall back to content area
|
|
1384
|
+
if (h.align) {
|
|
1385
|
+
switch (h.align) {
|
|
1386
|
+
case "left":
|
|
1387
|
+
case "inside":
|
|
1388
|
+
return originX;
|
|
1389
|
+
case "right":
|
|
1390
|
+
case "outside":
|
|
1391
|
+
return originX + refWidth - widthPt;
|
|
1392
|
+
case "center":
|
|
1393
|
+
return originX + (refWidth - widthPt) / 2;
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
if (h.offset != null) {
|
|
1397
|
+
return originX + emuToPt(h.offset);
|
|
1398
|
+
}
|
|
1399
|
+
return undefined;
|
|
1400
|
+
}
|
|
1401
|
+
function resolveVertical(fi, cursorY, contentHeight, geometry, heightPt) {
|
|
1402
|
+
const v = fi.verticalPosition;
|
|
1403
|
+
if (!v) {
|
|
1404
|
+
return undefined;
|
|
1405
|
+
}
|
|
1406
|
+
const relTo = v.relativeTo ?? "paragraph";
|
|
1407
|
+
let originY = cursorY;
|
|
1408
|
+
let refHeight = contentHeight;
|
|
1409
|
+
if (relTo === "page") {
|
|
1410
|
+
originY = -geometry.marginTop;
|
|
1411
|
+
refHeight = geometry.height;
|
|
1412
|
+
}
|
|
1413
|
+
else if (relTo === "margin" || relTo === "topMargin" || relTo === "bottomMargin") {
|
|
1414
|
+
originY = 0;
|
|
1415
|
+
refHeight = contentHeight;
|
|
1416
|
+
} // else paragraph/line/text-anchored — keep cursor as origin
|
|
1417
|
+
if (v.align) {
|
|
1418
|
+
switch (v.align) {
|
|
1419
|
+
case "top":
|
|
1420
|
+
case "inside":
|
|
1421
|
+
return originY;
|
|
1422
|
+
case "bottom":
|
|
1423
|
+
case "outside":
|
|
1424
|
+
return originY + refHeight - heightPt;
|
|
1425
|
+
case "center":
|
|
1426
|
+
return originY + (refHeight - heightPt) / 2;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
if (v.offset != null) {
|
|
1430
|
+
return originY + emuToPt(v.offset);
|
|
1431
|
+
}
|
|
1432
|
+
return undefined;
|
|
1433
|
+
}
|
|
1434
|
+
function layoutFloatingImage(fi, cursorY, contentWidth, contentHeight, geometry, sourceIndex, imageMap) {
|
|
1435
|
+
const widthPt = emuToPt(fi.width);
|
|
1436
|
+
const heightPt = emuToPt(fi.height);
|
|
1437
|
+
const { x: xPt, y: yPt } = resolveFloatingImageRect(fi, cursorY, contentWidth, contentHeight, geometry, widthPt, heightPt);
|
|
1438
|
+
const img = fi.rId ? imageMap.get(fi.rId) : undefined;
|
|
1439
|
+
const imageContent = img
|
|
1440
|
+
? {
|
|
1441
|
+
type: "image",
|
|
1442
|
+
rect: { x: xPt, y: yPt, width: widthPt, height: heightPt },
|
|
1443
|
+
data: img.data,
|
|
1444
|
+
mimeType: mediaTypeToMime(img.mediaType),
|
|
1445
|
+
altText: fi.altText,
|
|
1446
|
+
sourceIndex
|
|
1447
|
+
}
|
|
1448
|
+
: {
|
|
1449
|
+
type: "image",
|
|
1450
|
+
rect: { x: xPt, y: yPt, width: widthPt, height: heightPt },
|
|
1451
|
+
data: new Uint8Array(0),
|
|
1452
|
+
mimeType: "application/octet-stream",
|
|
1453
|
+
altText: fi.altText,
|
|
1454
|
+
sourceIndex
|
|
1455
|
+
};
|
|
1456
|
+
return {
|
|
1457
|
+
type: "float",
|
|
1458
|
+
rect: { x: xPt, y: yPt, width: widthPt, height: heightPt },
|
|
1459
|
+
content: imageContent,
|
|
1460
|
+
behindText: fi.behindDoc === true,
|
|
1461
|
+
...(fi.wrap ? { wrap: convertWrap(fi.wrap) } : {}),
|
|
1462
|
+
sourceIndex
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* Translate the source `FloatingImage.wrap` (with `WrapMargins` in EMU)
|
|
1467
|
+
* into the layout-side `LayoutFloatWrap` (with margins already in
|
|
1468
|
+
* points so renderers don't need to know about EMU).
|
|
1469
|
+
*/
|
|
1470
|
+
function convertWrap(wrap) {
|
|
1471
|
+
const out = {
|
|
1472
|
+
style: wrap.style
|
|
1473
|
+
};
|
|
1474
|
+
if (wrap.side) {
|
|
1475
|
+
out.side = wrap.side;
|
|
1476
|
+
}
|
|
1477
|
+
if (wrap.margins) {
|
|
1478
|
+
const m = {};
|
|
1479
|
+
if (wrap.margins.top != null) {
|
|
1480
|
+
m.top = emuToPt(wrap.margins.top);
|
|
1481
|
+
}
|
|
1482
|
+
if (wrap.margins.bottom != null) {
|
|
1483
|
+
m.bottom = emuToPt(wrap.margins.bottom);
|
|
1484
|
+
}
|
|
1485
|
+
if (wrap.margins.left != null) {
|
|
1486
|
+
m.left = emuToPt(wrap.margins.left);
|
|
1487
|
+
}
|
|
1488
|
+
if (wrap.margins.right != null) {
|
|
1489
|
+
m.right = emuToPt(wrap.margins.right);
|
|
1490
|
+
}
|
|
1491
|
+
if (Object.keys(m).length > 0) {
|
|
1492
|
+
out.margins = m;
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
return out;
|
|
1496
|
+
}
|
|
1497
|
+
function layoutTextBox(tb, startY, contentWidth, sourceIndex, options, imageMap) {
|
|
1498
|
+
const widthPt = tb.width != null ? twipsToPt(tb.width) : contentWidth;
|
|
1499
|
+
// Lay out inner paragraphs against the text-box width; their positions
|
|
1500
|
+
// are returned relative to the box's top-left so renderers translate
|
|
1501
|
+
// by `rect.x`/`rect.y`.
|
|
1502
|
+
const inner = [];
|
|
1503
|
+
let innerCursor = 0;
|
|
1504
|
+
for (const child of tb.content) {
|
|
1505
|
+
const laid = layoutParagraph(child, innerCursor, widthPt, options, undefined, imageMap);
|
|
1506
|
+
inner.push({ ...laid, sourceIndex });
|
|
1507
|
+
innerCursor = laid.rect.y + laid.rect.height;
|
|
1508
|
+
}
|
|
1509
|
+
const heightPt = tb.height != null ? twipsToPt(tb.height) : Math.max(innerCursor, 12);
|
|
1510
|
+
return {
|
|
1511
|
+
type: "textBox",
|
|
1512
|
+
rect: { x: 0, y: startY, width: widthPt, height: heightPt },
|
|
1513
|
+
content: inner,
|
|
1514
|
+
border: tb.stroke && tb.strokeColor
|
|
1515
|
+
? { width: 0.75, color: normaliseHex(tb.strokeColor) }
|
|
1516
|
+
: undefined,
|
|
1517
|
+
background: tb.fill && tb.fillColor ? normaliseHex(tb.fillColor) : undefined,
|
|
1518
|
+
sourceIndex
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
function layoutDrawingShape(shape, startY, contentWidth, sourceIndex, options, imageMap) {
|
|
1522
|
+
const widthPt = emuToPt(shape.width);
|
|
1523
|
+
const heightPt = emuToPt(shape.height);
|
|
1524
|
+
const innerWidth = Math.min(widthPt, contentWidth);
|
|
1525
|
+
const innerContent = [];
|
|
1526
|
+
if (shape.textContent && shape.textContent.length > 0) {
|
|
1527
|
+
let cursor = 0;
|
|
1528
|
+
for (const para of shape.textContent) {
|
|
1529
|
+
const laid = layoutParagraph(para, cursor, innerWidth, options, undefined, imageMap);
|
|
1530
|
+
innerContent.push({ ...laid, sourceIndex });
|
|
1531
|
+
cursor = laid.rect.y + laid.rect.height;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return {
|
|
1535
|
+
type: "shape",
|
|
1536
|
+
rect: { x: 0, y: startY, width: widthPt, height: heightPt },
|
|
1537
|
+
preset: shape.shapeType,
|
|
1538
|
+
fillColor: shape.noFill ? undefined : normaliseHexOrUndefined(shape.fillColor),
|
|
1539
|
+
strokeColor: shape.noOutline ? undefined : normaliseHexOrUndefined(shape.outlineColor),
|
|
1540
|
+
strokeWidth: shape.outlineWidth != null ? emuToPt(shape.outlineWidth) : undefined,
|
|
1541
|
+
textContent: innerContent.length > 0 ? innerContent : undefined,
|
|
1542
|
+
sourceIndex
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1545
|
+
function layoutChart(ch, startY, contentWidth, sourceIndex) {
|
|
1546
|
+
// Source dimensions:
|
|
1547
|
+
// - ChartContent stores width/height inside the inner Chart model
|
|
1548
|
+
// (writer emits `<wp:extent>` from `chart.width/height`; reader
|
|
1549
|
+
// populates them from the original drawing's `<wp:extent>`).
|
|
1550
|
+
// - ChartExContent carries width/height directly on the content.
|
|
1551
|
+
// Both fall back to a 6"×3.5" default that matches Microsoft Word's
|
|
1552
|
+
// default insert size when the source supplied none.
|
|
1553
|
+
const widthEmu = ch.type === "chart" ? (ch.chart?.width ?? 5486400) : (ch.width ?? 5486400);
|
|
1554
|
+
const heightEmu = ch.type === "chart" ? (ch.chart?.height ?? 3200400) : (ch.height ?? 3200400);
|
|
1555
|
+
const widthPt = Math.min(emuToPt(widthEmu), contentWidth);
|
|
1556
|
+
const heightPt = emuToPt(heightEmu);
|
|
1557
|
+
const title = ch.type === "chart" ? (ch.chart?.title ?? ch.name) : ch.name;
|
|
1558
|
+
return {
|
|
1559
|
+
type: "chart",
|
|
1560
|
+
rect: { x: 0, y: startY, width: widthPt, height: heightPt },
|
|
1561
|
+
chartKind: ch.type === "chart" ? "chart" : "chartEx",
|
|
1562
|
+
title,
|
|
1563
|
+
altText: ch.altText,
|
|
1564
|
+
source: ch,
|
|
1565
|
+
sourceIndex
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
function layoutSdt(sdt, startY, contentWidth, sourceIndex, options, imageMap) {
|
|
1569
|
+
// SDT is a transparent flow container in layout terms: lay out its
|
|
1570
|
+
// children inline and report a rect that encloses them. Inline-only
|
|
1571
|
+
// children (bare runs) are skipped — the SDT-as-block contract is
|
|
1572
|
+
// what layout cares about.
|
|
1573
|
+
const inner = [];
|
|
1574
|
+
let cursor = 0;
|
|
1575
|
+
for (const child of sdt.content) {
|
|
1576
|
+
if ("type" in child) {
|
|
1577
|
+
if (child.type === "paragraph") {
|
|
1578
|
+
const laid = layoutParagraph(child, cursor, contentWidth, options, undefined, imageMap);
|
|
1579
|
+
inner.push({ ...laid, sourceIndex });
|
|
1580
|
+
cursor = laid.rect.y + laid.rect.height;
|
|
1581
|
+
}
|
|
1582
|
+
else if (child.type === "table") {
|
|
1583
|
+
const laid = layoutTable(child, cursor, contentWidth, sourceIndex, options, imageMap);
|
|
1584
|
+
inner.push(laid);
|
|
1585
|
+
cursor = laid.rect.y + laid.rect.height;
|
|
1586
|
+
}
|
|
1587
|
+
// Run-only SDT children are not flowed at the block level.
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return {
|
|
1591
|
+
type: "sdt",
|
|
1592
|
+
rect: { x: 0, y: startY, width: contentWidth, height: cursor },
|
|
1593
|
+
content: inner,
|
|
1594
|
+
tag: sdt.properties?.tag,
|
|
1595
|
+
alias: sdt.properties?.alias,
|
|
1596
|
+
sourceIndex
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
function layoutMath(mb, startY, contentWidth, sourceIndex, options) {
|
|
1600
|
+
const text = (0, text_utils_1.extractMathText)(mb.content);
|
|
1601
|
+
let mathML;
|
|
1602
|
+
try {
|
|
1603
|
+
mathML = (0, math_convert_1.ommlToMathML)(mb.content);
|
|
1604
|
+
}
|
|
1605
|
+
catch {
|
|
1606
|
+
mathML = undefined;
|
|
1607
|
+
}
|
|
1608
|
+
const fontSize = DEFAULT_FONT_SIZE_PT;
|
|
1609
|
+
const lineHeight = fontSize * 1.2;
|
|
1610
|
+
// Width is approximated from the plain-text fallback so renderers that
|
|
1611
|
+
// don't handle MathML still see a reasonable bounding box.
|
|
1612
|
+
const fontName = (0, font_metrics_1.mapToStandardFont)(options?.fonts?.get("Cambria Math") ?? "Cambria Math");
|
|
1613
|
+
const widthPt = Math.min((0, font_metrics_1.measureTextWidth)(text, fontName, fontSize), contentWidth);
|
|
1614
|
+
return {
|
|
1615
|
+
type: "math",
|
|
1616
|
+
rect: { x: 0, y: startY, width: widthPt, height: lineHeight },
|
|
1617
|
+
text,
|
|
1618
|
+
mathML,
|
|
1619
|
+
sourceIndex
|
|
1620
|
+
};
|
|
1621
|
+
}
|
|
1622
|
+
function layoutCheckBox(cb, startY, sourceIndex, options) {
|
|
1623
|
+
const fontSize = DEFAULT_FONT_SIZE_PT;
|
|
1624
|
+
const checked = cb.checked === true;
|
|
1625
|
+
const glyph = checked
|
|
1626
|
+
? (cb.checkedState?.value ?? "\u2611") // ☑
|
|
1627
|
+
: (cb.uncheckedState?.value ?? "\u2610"); // ☐
|
|
1628
|
+
const fontName = (0, font_metrics_1.mapToStandardFont)(cb.checkedState?.font ?? options?.fonts?.get("MS Gothic") ?? "MS Gothic");
|
|
1629
|
+
const widthPt = (0, font_metrics_1.measureTextWidth)(glyph, fontName, fontSize);
|
|
1630
|
+
return {
|
|
1631
|
+
type: "checkBox",
|
|
1632
|
+
rect: { x: 0, y: startY, width: widthPt, height: fontSize * 1.2 },
|
|
1633
|
+
checked,
|
|
1634
|
+
glyph,
|
|
1635
|
+
fontSize,
|
|
1636
|
+
sourceIndex
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
function layoutTableOfContents(toc, startY, contentWidth, sourceIndex, options, imageMap) {
|
|
1640
|
+
const entries = [];
|
|
1641
|
+
let cursor = 0;
|
|
1642
|
+
if (toc.cachedParagraphs && toc.cachedParagraphs.length > 0) {
|
|
1643
|
+
for (const para of toc.cachedParagraphs) {
|
|
1644
|
+
const laid = layoutParagraph(para, cursor, contentWidth, options, undefined, imageMap);
|
|
1645
|
+
entries.push({ ...laid, sourceIndex });
|
|
1646
|
+
cursor = laid.rect.y + laid.rect.height;
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
else {
|
|
1650
|
+
// Stub: emit a single placeholder paragraph so renderers always have
|
|
1651
|
+
// something to render. Consumers wanting a real TOC should run
|
|
1652
|
+
// `updateTableOfContents()` before layout.
|
|
1653
|
+
const stub = {
|
|
1654
|
+
type: "paragraph",
|
|
1655
|
+
children: [{ content: [{ type: "text", text: "[Table of Contents]" }] }]
|
|
1656
|
+
};
|
|
1657
|
+
const laid = layoutParagraph(stub, 0, contentWidth, options, undefined, imageMap);
|
|
1658
|
+
entries.push({ ...laid, sourceIndex });
|
|
1659
|
+
cursor = laid.rect.height;
|
|
1660
|
+
}
|
|
1661
|
+
return {
|
|
1662
|
+
type: "tableOfContents",
|
|
1663
|
+
rect: { x: 0, y: startY, width: contentWidth, height: cursor },
|
|
1664
|
+
entries,
|
|
1665
|
+
sourceIndex
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1668
|
+
function layoutAltChunk(ac, startY, contentWidth, sourceIndex) {
|
|
1669
|
+
// Layout cannot interpret HTML / RTF / MHT payloads; reserve a
|
|
1670
|
+
// placeholder rect proportional to a small fixed height so renderers
|
|
1671
|
+
// can show a substitution glyph or run their own foreign-content
|
|
1672
|
+
// pipeline.
|
|
1673
|
+
const heightPt = DEFAULT_FONT_SIZE_PT * 3;
|
|
1674
|
+
return {
|
|
1675
|
+
type: "altChunk",
|
|
1676
|
+
rect: { x: 0, y: startY, width: contentWidth, height: heightPt },
|
|
1677
|
+
contentType: ac.contentType ?? "application/octet-stream",
|
|
1678
|
+
fileName: ac.fileName,
|
|
1679
|
+
sourceIndex
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
function layoutOpaqueDrawing(od, startY, contentWidth, sourceIndex) {
|
|
1683
|
+
// We have no idea how big the drawing is from XML alone; reserve a
|
|
1684
|
+
// square-ish placeholder roughly matching a typical chart slot. High-
|
|
1685
|
+
// fidelity renderers can re-parse `rawXml` if they need exact size.
|
|
1686
|
+
const heightPt = DEFAULT_FONT_SIZE_PT * 12;
|
|
1687
|
+
return {
|
|
1688
|
+
type: "opaqueDrawing",
|
|
1689
|
+
rect: { x: 0, y: startY, width: contentWidth, height: heightPt },
|
|
1690
|
+
rawXml: od.rawXml,
|
|
1691
|
+
sourceIndex
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
function normaliseHex(hex) {
|
|
1695
|
+
return hex.startsWith("#") ? hex.slice(1) : hex;
|
|
1696
|
+
}
|
|
1697
|
+
function normaliseHexOrUndefined(hex) {
|
|
1698
|
+
return hex ? normaliseHex(hex) : undefined;
|
|
1699
|
+
}
|