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