@stll/folio-core 0.59.0 → 0.61.0

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 (226) hide show
  1. package/README.md +23 -1
  2. package/dist/ai-edits/apply.js +139 -32
  3. package/dist/ai-edits/headless.d.ts +3 -0
  4. package/dist/ai-edits/headless.js +57 -63
  5. package/dist/ai-edits/note-story-inventory.d.ts +7 -0
  6. package/dist/ai-edits/note-story-inventory.js +11 -0
  7. package/dist/ai-edits/read.js +16 -9
  8. package/dist/ai-edits/revisionStretches.js +52 -1
  9. package/dist/ai-edits/table-row-column-mutations.js +6 -1
  10. package/dist/compare/reproducible-package.js +2 -1
  11. package/dist/compare/verification.js +1 -0
  12. package/dist/compat/eigenpal.d.ts +4 -2
  13. package/dist/compat/eigenpal.js +2 -2
  14. package/dist/controller/canonicalClipboard.js +2 -1
  15. package/dist/controller/canonicalListRendering.d.ts +4 -6
  16. package/dist/controller/canonicalListRendering.js +3 -157
  17. package/dist/controller/canonicalSession.js +3 -2
  18. package/dist/controller/canonicalStructure.js +10 -7
  19. package/dist/controller/fontReadiness.js +1 -1
  20. package/dist/controller/headerFooterEditorManager.d.ts +1 -0
  21. package/dist/controller/headerFooterEditorManager.js +11 -0
  22. package/dist/controller/hiddenEditorManager.d.ts +1 -1
  23. package/dist/controller/hiddenEditorManager.js +3 -1
  24. package/dist/controller/layoutPipeline.d.ts +3 -1
  25. package/dist/controller/layoutPipeline.js +19 -4
  26. package/dist/controller/layoutSession.d.ts +4 -1
  27. package/dist/display-list/build/fontTable.js +7 -5
  28. package/dist/display-list/build/furniture.d.ts +1 -0
  29. package/dist/display-list/build/furniture.js +1 -0
  30. package/dist/display-list/build/imagePrimitives.js +3 -6
  31. package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
  32. package/dist/display-list/build/watermarkPrimitives.js +9 -3
  33. package/dist/display-list/editor/pageRenderer.js +1 -0
  34. package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
  35. package/dist/docx/bookmarkIdNormalization.js +100 -0
  36. package/dist/docx/bookmarkParser.js +4 -2
  37. package/dist/docx/canonicalStoryRepack.js +3 -2
  38. package/dist/docx/commentTextParagraph.d.ts +6 -0
  39. package/dist/docx/commentTextParagraph.js +15 -0
  40. package/dist/docx/conformance.js +6 -1
  41. package/dist/docx/diagramPreview.js +2 -1
  42. package/dist/docx/documentParser.d.ts +13 -1
  43. package/dist/docx/documentParser.js +1 -1
  44. package/dist/docx/encryption/compoundFile.d.ts +0 -8
  45. package/dist/docx/encryption/compoundFile.js +2 -1
  46. package/dist/docx/encryption/cryptoBytes.d.ts +2 -2
  47. package/dist/docx/encryption/cryptoBytes.js +3 -18
  48. package/dist/docx/encryption/encryptionInfo.d.ts +0 -5
  49. package/dist/docx/encryption/encryptionInfo.js +2 -1
  50. package/dist/docx/ensureParaIds.js +2 -1
  51. package/dist/docx/groupDrawingParser.js +6 -1
  52. package/dist/docx/importedIdCollisions.d.ts +136 -0
  53. package/dist/docx/importedIdCollisions.js +215 -0
  54. package/dist/docx/listModelNormalization.d.ts +10 -0
  55. package/dist/docx/listModelNormalization.js +166 -0
  56. package/dist/docx/metadataPrivacy.js +3 -2
  57. package/dist/docx/metafileRaster.js +2 -1
  58. package/dist/docx/numberingParser.js +2 -2
  59. package/dist/docx/packageParts.js +6 -5
  60. package/dist/docx/paragraphParser.js +6 -4
  61. package/dist/docx/paragraphPropertySource.js +1 -2
  62. package/dist/docx/parseContext.d.ts +2 -1
  63. package/dist/docx/parseContext.js +1 -0
  64. package/dist/docx/parseWarningMessage.js +1 -0
  65. package/dist/docx/parser.js +10 -5
  66. package/dist/docx/preservedRunContent.js +11 -2
  67. package/dist/docx/relsParser.js +1 -1
  68. package/dist/docx/removeHeaderFooterParts.js +8 -7
  69. package/dist/docx/replyToComment.js +3 -13
  70. package/dist/docx/rezip.js +90 -90
  71. package/dist/docx/runParser.js +12 -6
  72. package/dist/docx/runPropertyPresence.d.ts +11 -0
  73. package/dist/docx/runPropertyPresence.js +14 -0
  74. package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
  75. package/dist/docx/selectedXmlIdentityScan.js +36 -0
  76. package/dist/docx/selectiveSave.js +19 -17
  77. package/dist/docx/selectiveXmlPatch.js +44 -52
  78. package/dist/docx/serializer/commentSerializer.d.ts +3 -1
  79. package/dist/docx/serializer/commentSerializer.js +11 -2
  80. package/dist/docx/serializer/runSerializer.js +5 -4
  81. package/dist/docx/serializer/tableSerializer.js +2 -1
  82. package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
  83. package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
  84. package/dist/docx/server/applyDocxXmlPatchProposal.js +2 -2
  85. package/dist/docx/server/boundedArchive.js +2 -1
  86. package/dist/docx/server/evaluateDocxXmlPatchProposal.js +2 -1
  87. package/dist/docx/server/inspectDocxPackage.js +5 -1
  88. package/dist/docx/server/validateDocxConformance.js +2 -1
  89. package/dist/docx/tableParser.js +7 -4
  90. package/dist/docx/tableRowPropertyPresence.d.ts +9 -0
  91. package/dist/docx/tableRowPropertyPresence.js +15 -0
  92. package/dist/docx/unzip.js +2 -1
  93. package/dist/docx/xmlEncoding.js +6 -5
  94. package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
  95. package/dist/fonts/embeddedFontFingerprint.js +18 -0
  96. package/dist/fonts/embeddedFonts.d.ts +1 -1
  97. package/dist/fonts/embeddedFonts.js +1 -1
  98. package/dist/fonts/fontsourceFaces.js +2 -1
  99. package/dist/fonts/headlessMeasure.js +0 -0
  100. package/dist/fonts/sfnt/parse.js +6 -9
  101. package/dist/fonts/sfnt/subset.js +2 -1
  102. package/dist/fonts/sfnt/tables.js +2 -3
  103. package/dist/fonts/sfnt/woff.js +2 -1
  104. package/dist/headless-layout.js +1 -0
  105. package/dist/index.d.ts +4 -2
  106. package/dist/index.js +2 -2
  107. package/dist/internal/revisionResolutionInline.d.ts +2 -1
  108. package/dist/internal/revisionResolutionInline.js +22 -1
  109. package/dist/internal/wholeStoryRevisionResolution.js +24 -7
  110. package/dist/layout-bridge/convert/flowConversionShared.d.ts +4 -0
  111. package/dist/layout-bridge/convert/footnoteLayout.d.ts +5 -1
  112. package/dist/layout-bridge/convert/footnoteLayout.js +16 -3
  113. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +6 -0
  114. package/dist/layout-bridge/convert/headerFooterLayout.js +13 -14
  115. package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
  116. package/dist/layout-bridge/convert/paragraphRuns.js +2 -1
  117. package/dist/layout-bridge/convert/toFlowBlocks.js +25 -1
  118. package/dist/layout-engine/measure/cache.js +39 -7
  119. package/dist/layout-engine/measure/crossRunWords.js +12 -2
  120. package/dist/layout-engine/measure/lineTypography.js +1 -0
  121. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  122. package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
  123. package/dist/layout-engine/measure/measureContainer.js +3 -4
  124. package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
  125. package/dist/layout-engine/measure/measureHelpers.js +21 -18
  126. package/dist/layout-engine/measure/measureParagraph.js +2 -0
  127. package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
  128. package/dist/layout-engine/types.d.ts +4 -1
  129. package/dist/layout-painter/renderPage.d.ts +1 -0
  130. package/dist/layout-painter/renderPage.js +11 -3
  131. package/dist/layout-painter/renderParagraph.js +13 -3
  132. package/dist/layout-painter/renderWatermark.d.ts +1 -0
  133. package/dist/layout-painter/renderWatermark.js +7 -3
  134. package/dist/managers/AutoSaveManager.js +2 -1
  135. package/dist/managers/EditorModeManager.d.ts +10 -1
  136. package/dist/managers/EditorModeManager.js +15 -1
  137. package/dist/managers/TableSelectionManager.d.ts +1 -1
  138. package/dist/managers/autoSaveCodec.js +2 -6
  139. package/dist/managers/editorShortcuts.d.ts +2 -1
  140. package/dist/managers/editorShortcuts.js +2 -1
  141. package/dist/managers/reviewDisplayMode.d.ts +8 -0
  142. package/dist/managers/reviewDisplayMode.js +15 -0
  143. package/dist/paged-layout/pageText.d.ts +11 -2
  144. package/dist/paged-layout/pageText.js +8 -3
  145. package/dist/pdf/fonts.js +5 -14
  146. package/dist/pdf/images.js +3 -2
  147. package/dist/pdf/objects.d.ts +0 -11
  148. package/dist/pdf/objects.js +7 -9
  149. package/dist/pdf/writePdf.js +2 -1
  150. package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
  151. package/dist/prosemirror/canonicalSelectionRange.js +9 -3
  152. package/dist/prosemirror/commands/comments.js +51 -13
  153. package/dist/prosemirror/containerFinalParagraph.d.ts +8 -8
  154. package/dist/prosemirror/containerFinalParagraph.js +8 -8
  155. package/dist/prosemirror/conversion/fromProseDoc.js +9 -4
  156. package/dist/prosemirror/conversion/toProseDoc.js +4 -4
  157. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
  158. package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
  159. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
  160. package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
  161. package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
  162. package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
  163. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
  164. package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
  165. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
  166. package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
  167. package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
  168. package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
  169. package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +16 -2
  170. package/dist/prosemirror/findReplaceSelection.d.ts +11 -1
  171. package/dist/prosemirror/findReplaceSelection.js +15 -1
  172. package/dist/prosemirror/markupViewProjection.d.ts +10 -1
  173. package/dist/prosemirror/markupViewProjection.js +21 -3
  174. package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
  175. package/dist/prosemirror/pluginKeyOwner.js +35 -0
  176. package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
  177. package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
  178. package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
  179. package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
  180. package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
  181. package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
  182. package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
  183. package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
  184. package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
  185. package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
  186. package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
  187. package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
  188. package/dist/prosemirror/plugins/documentNumbering.js +5 -3
  189. package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
  190. package/dist/prosemirror/plugins/documentStyleState.js +2 -2
  191. package/dist/prosemirror/plugins/documentStyles.js +1 -1
  192. package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
  193. package/dist/prosemirror/plugins/selectionTracker.js +4 -3
  194. package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
  195. package/dist/prosemirror/plugins/suggestionMode.js +4 -3
  196. package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
  197. package/dist/prosemirror/plugins/templateDirectives.js +19 -4
  198. package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
  199. package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
  200. package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
  201. package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
  202. package/dist/prosemirror/plugins/transactionInvariants.js +29 -4
  203. package/dist/prosemirror/replacedAnnotations.d.ts +15 -1
  204. package/dist/prosemirror/replacedAnnotations.js +71 -12
  205. package/dist/prosemirror/runFormattingReconciliation.d.ts +3 -1
  206. package/dist/prosemirror/runFormattingReconciliation.js +10 -2
  207. package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +5 -7
  208. package/dist/prosemirror/runIdentityAcrossRevisions.js +66 -38
  209. package/dist/prosemirror/runPropertyChangeResolution.js +13 -1
  210. package/dist/utils/base64.d.ts +1 -31
  211. package/dist/utils/base64.js +19 -33
  212. package/dist/utils/clipboard.js +5 -4
  213. package/dist/utils/colorResolver.js +11 -2
  214. package/dist/utils/findReplace.d.ts +5 -0
  215. package/dist/utils/fontLoader.d.ts +2 -2
  216. package/dist/utils/fontLoader.js +2 -7
  217. package/dist/utils/fontResolver.d.ts +7 -3
  218. package/dist/utils/fontResolver.js +6 -8
  219. package/dist/utils/replaceText.js +21 -4
  220. package/dist/utils/sliceText.d.ts +2 -0
  221. package/dist/utils/sliceText.js +2 -0
  222. package/dist/utils/textEncoding.d.ts +2 -0
  223. package/dist/utils/textEncoding.js +2 -0
  224. package/dist/utils/tiffConverter.d.ts +0 -9
  225. package/dist/utils/tiffConverter.js +2 -4
  226. package/package.json +73 -31
@@ -42,7 +42,7 @@ const formatEndnoteTexts = (numbers, formatNumber) => {
42
42
  for (const [id, displayNumber] of numbers) texts.set(id, formatNumber(displayNumber));
43
43
  return texts;
44
44
  };
45
- const sameMeasureInputs = (left, right) => left.styles === right.styles && left.theme === right.theme && left.defaultTabStop === right.defaultTabStop && left.pageContentHeight === right.pageContentHeight && left.fontSet === right.fontSet && left.fontAlternates.size === right.fontAlternates.size && [...left.fontAlternates].every(([name, alternate]) => right.fontAlternates.get(name) === alternate) && left.markupView === right.markupView;
45
+ const sameMeasureInputs = (left, right) => left.embeddedFontFamilyMap === right.embeddedFontFamilyMap && left.styles === right.styles && left.theme === right.theme && left.defaultTabStop === right.defaultTabStop && left.pageContentHeight === right.pageContentHeight && left.fontSet === right.fontSet && left.fontAlternates.size === right.fontAlternates.size && [...left.fontAlternates].every(([name, alternate]) => right.fontAlternates.get(name) === alternate) && left.markupView === right.markupView && left.showCommentHighlights === right.showCommentHighlights;
46
46
  /**
47
47
  * The range an incremental pass re-measures, or `null` for a full measure: the
48
48
  * committed measures must come from the same measure inputs, and the range is
@@ -136,7 +136,7 @@ function runLayoutPipeline(deps, state, options = {}) {
136
136
  return result;
137
137
  }
138
138
  function runLayoutPipelineMeasured(deps, state, options) {
139
- const { contentWidth, columns, pageSize, margins, pageGap, showMarginGuides, marginGuideColor, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, readFontSetSignature, buildFootnoteRenderItems, describeInvalidHighlightMarks, pageRenderer = PAGE_RENDERER.legacy, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES, emptyTemplatePreviewHidden: EMPTY_TEMPLATE_PREVIEW_HIDDEN, markupView } = deps;
139
+ const { contentWidth, columns, pageSize, margins, pageGap, showMarginGuides, marginGuideColor, syncCoordinator, headerContent, footerContent, firstPageHeaderContent, firstPageFooterContent, headerContentRId, footerContentRId, firstPageHeaderContentRId, firstPageFooterContentRId, sectionHeaderFooterRefs, theme: _theme, sectionProperties, document, defaultTabStop, mirrorMargins, styles, layout, hfPMs, painter, pagesContainer, session, renderHfFromContentOrPm, renderHeaderFooterContentByRId, readFontSetSignature, buildFootnoteRenderItems, describeInvalidHighlightMarks, pageRenderer = PAGE_RENDERER.legacy, emptyTemplatePreviewEntries: EMPTY_TEMPLATE_PREVIEW_ENTRIES, emptyTemplatePreviewHidden: EMPTY_TEMPLATE_PREVIEW_HIDDEN, markupView, showCommentHighlights = true } = deps;
140
140
  let outcome = {};
141
141
  let pendingArtifacts;
142
142
  let pendingTemplatePreview;
@@ -154,16 +154,22 @@ function runLayoutPipelineMeasured(deps, state, options) {
154
154
  let phaseStartedAt = performance.now();
155
155
  const pageContentHeight = pageSize.h - margins.top - margins.bottom;
156
156
  const fontAlternates = buildFontAlternates(document?.package.fontTable);
157
+ const displayCommentHighlights = showCommentHighlights && markupView !== "no-markup" && markupView !== "original";
158
+ const embeddedFontFamilies = session.embeddedFontFamilyMap ? { embeddedFontFamilyMap: session.embeddedFontFamilyMap } : {};
157
159
  const measureInputs = {
160
+ ...embeddedFontFamilies,
158
161
  styles,
159
162
  theme: _theme,
160
163
  defaultTabStop,
161
164
  pageContentHeight,
162
165
  fontSet,
163
166
  fontAlternates,
164
- markupView
167
+ markupView,
168
+ showCommentHighlights: displayCommentHighlights
165
169
  };
166
170
  const flowOpts = {
171
+ showCommentHighlights: displayCommentHighlights,
172
+ ...embeddedFontFamilies,
167
173
  pageContentHeight,
168
174
  fontAlternates,
169
175
  ...styles ? { styles } : {},
@@ -243,11 +249,14 @@ function runLayoutPipelineMeasured(deps, state, options) {
243
249
  const buildHfOptions = (pageCount, fieldInputs) => {
244
250
  const hfMeasureBlocks = (hfBlocks, hfWidth) => measureBlocks(hfBlocks, hfWidth, void 0, void 0, buildHeaderFooterFieldValues(hfBlocks, pageCount, hfClock, fieldInputs), { allowEndTabOverflow: true });
245
251
  return {
252
+ markupView,
253
+ showCommentHighlights: displayCommentHighlights,
246
254
  ...flowOpts.styles ? { styles: flowOpts.styles } : {},
247
255
  ...document?.package.numbering === void 0 ? {} : { numbering: document.package.numbering },
248
256
  ...flowOpts.defaultSize === void 0 ? {} : { defaultSize: flowOpts.defaultSize },
249
257
  ..._theme !== void 0 ? { theme: _theme } : {},
250
258
  fontAlternates,
259
+ ...embeddedFontFamilies,
251
260
  measureBlocks: hfMeasureBlocks,
252
261
  ...defaultTabStop !== void 0 ? { defaultTabStopTwips: defaultTabStop } : {},
253
262
  ...flowOpts.lineBreakRules ? { lineBreakRules: flowOpts.lineBreakRules } : {},
@@ -374,12 +383,17 @@ function runLayoutPipelineMeasured(deps, state, options) {
374
383
  outcome.measures = newMeasures;
375
384
  recordPhaseDuration("measure-blocks", phaseStartedAt);
376
385
  const buildNoteOptions = () => {
377
- const noteOptions = { measureBlocks };
386
+ const noteOptions = {
387
+ measureBlocks,
388
+ showCommentHighlights: displayCommentHighlights,
389
+ markupView
390
+ };
378
391
  if (flowOpts.styles) noteOptions.styles = flowOpts.styles;
379
392
  if (flowOpts.defaultSize !== void 0) noteOptions.defaultSize = flowOpts.defaultSize;
380
393
  if (_theme !== void 0) noteOptions.theme = _theme;
381
394
  if (document?.package.numbering !== void 0) noteOptions.numbering = document.package.numbering;
382
395
  noteOptions.fontAlternates = fontAlternates;
396
+ if (session.embeddedFontFamilyMap) noteOptions.embeddedFontFamilyMap = session.embeddedFontFamilyMap;
383
397
  if (defaultTabStop !== void 0) noteOptions.defaultTabStopTwips = defaultTabStop;
384
398
  if (flowOpts.lineBreakRules) noteOptions.lineBreakRules = flowOpts.lineBreakRules;
385
399
  if (flowOpts.justificationCompatibility) noteOptions.justificationCompatibility = flowOpts.justificationCompatibility;
@@ -579,6 +593,7 @@ function runLayoutPipelineMeasured(deps, state, options) {
579
593
  outcome.blockLookup = blockLookup;
580
594
  const footnotesByPage = hasFootnotes ? buildFootnoteRenderItems(pageFootnoteMap, footnoteContentMap, document) : void 0;
581
595
  const renderOpts = {
596
+ ...embeddedFontFamilies,
582
597
  pageGap,
583
598
  showShadow: true,
584
599
  blockLookup,
@@ -1,7 +1,7 @@
1
1
  import { document_d_exports } from "../types/document.js";
2
2
  import { TemplatePreviewEntry, TemplatePreviewHiddenRange, TemplatePreviewValues } from "../prosemirror/plugins/templatePreviewValues.js";
3
- import { FlowBlock, Measure } from "../layout-engine/types.js";
4
3
  import { DisplayMode } from "../managers/EditorModeManager.js";
4
+ import { FlowBlock, Measure } from "../layout-engine/types.js";
5
5
  import { FontAlternates } from "../fonts/fontAlternates.js";
6
6
  import { EditorState } from "prosemirror-state";
7
7
  //#region src/controller/layoutSession.d.ts
@@ -23,6 +23,7 @@ type LayoutTemplatePreview = {
23
23
  * that changes how text measures brings new styles or font alternates.
24
24
  */
25
25
  type LayoutMeasureInputs = {
26
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
26
27
  styles: document_d_exports.StyleDefinitions | null | undefined;
27
28
  theme: document_d_exports.Theme | null | undefined;
28
29
  defaultTabStop: number | undefined;
@@ -35,8 +36,10 @@ type LayoutMeasureInputs = {
35
36
  fontAlternates: FontAlternates;
36
37
  /** The review view: each lays out different text, so a measure is reusable only within one. */
37
38
  markupView: DisplayMode;
39
+ showCommentHighlights?: boolean;
38
40
  };
39
41
  type LayoutSession = {
42
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
40
43
  artifacts: LayoutArtifacts | null;
41
44
  lastEditorState: EditorState | null;
42
45
  lastPmDoc: EditorState["doc"] | null;
@@ -1,6 +1,6 @@
1
1
  import { ptToPx } from "../../layout-engine/measure/measureHelpers.js";
2
2
  import { getFontMetrics } from "../../layout-engine/measure/measureProvider.js";
3
- import { resolveFontFamily } from "../../utils/fontResolver.js";
3
+ import { parseFontFamilyList, resolveFontFamily } from "../../utils/fontResolver.js";
4
4
  //#region src/display-list/build/fontTable.ts
5
5
  const CSS_NORMAL_WEIGHT = 400;
6
6
  const CSS_BOLD_WEIGHT = 700;
@@ -12,7 +12,6 @@ const GENERIC_FAMILIES = {
12
12
  fantasy: "fantasy"
13
13
  };
14
14
  const DEFAULT_GENERIC = "sans-serif";
15
- const splitFallbackStack = (cssFallback) => cssFallback.split(",").map((entry) => entry.trim().replace(/^["']|["']$/gu, ""));
16
15
  /**
17
16
  * The category `resolveFontFamily` chose. It is the last CSS generic in the
18
17
  * stack it built, which is where `detectFontCategory` puts it; reading it back
@@ -30,8 +29,8 @@ const faceKey = (family, weight, italic) => `${family.toLowerCase()} ${weight} $
30
29
  * Package faces keyed by every family name a run can resolve to.
31
30
  *
32
31
  * `resolveFontFamily` substitutes the scoped `folio-embedded-{nonce}-{name}`
33
- * family only while the document's embedded-family map is installed; a build
34
- * that never installed it resolves the same run to the authored name. Both
32
+ * family when the run carries its document-owned embedded-family map; a build
33
+ * without that context resolves the same run to the authored name. Both
35
34
  * names therefore key the same face, and the bytes are interned by id so one
36
35
  * face's binary appears once however many names reach it.
37
36
  */
@@ -64,7 +63,10 @@ var FontTable = class {
64
63
  this.embeddedByKey = indexEmbeddedFonts(embeddedFonts);
65
64
  }
66
65
  intern({ fontFamily, alternateFontFamily, bold, italic, measureStyle }) {
67
- const stack = splitFallbackStack(resolveFontFamily(fontFamily, alternateFontFamily).cssFallback);
66
+ const stack = parseFontFamilyList(resolveFontFamily(fontFamily, {
67
+ alternateFontName: alternateFontFamily,
68
+ embeddedFontFamilyMap: measureStyle.embeddedFontFamilyMap
69
+ }).cssFallback);
68
70
  const family = stack.at(0) ?? fontFamily;
69
71
  const weight = bold ? CSS_BOLD_WEIGHT : CSS_NORMAL_WEIGHT;
70
72
  const isItalic = italic === true;
@@ -12,6 +12,7 @@ import { PageComposer } from "./regions.js";
12
12
  * caller's `documentFeatures` shows the document had one.
13
13
  */
14
14
  type PageFurnitureInputs = {
15
+ embeddedFontFamilyMap?: ReadonlyMap<string, string>;
15
16
  /**
16
17
  * `w:pgBorders` for the section. Absent: no border is painted, and the gap is
17
18
  * reported unless `documentFeatures` says the document has none.
@@ -61,6 +61,7 @@ const paintPageFurniture = ({ page, furniture, context }) => {
61
61
  const watermark = !suppliesWatermark(furniture) || selected.watermark === void 0 ? [] : paintWatermark({
62
62
  page,
63
63
  watermark: selected.watermark,
64
+ ...furniture.embeddedFontFamilyMap ? { embeddedFontFamilyMap: furniture.embeddedFontFamilyMap } : {},
64
65
  ...furniture.watermarkImageSrc === void 0 ? {} : { imageSrc: furniture.watermarkImageSrc },
65
66
  context
66
67
  });
@@ -1,5 +1,6 @@
1
1
  import { parseRotationDegrees } from "../../utils/rotationBoundingBox.js";
2
2
  import { sanitizeImageSrc } from "../../utils/sanitizeImageSrc.js";
3
+ import { base64ToBytes } from "../../utils/textEncoding.js";
3
4
  import { paintPreview } from "./previewPrimitives.js";
4
5
  import { resolveBorderStroke } from "./strokes.js";
5
6
  import { UNSUPPORTED_CONSTRUCT } from "./unsupported.js";
@@ -21,12 +22,8 @@ const DATA_URL_PATTERN = /^data:([^;,]*)(;base64)?,(.*)$/su;
21
22
  * document the builder reports, not an exception that aborts the build.
22
23
  */
23
24
  const decodeBase64 = (encoded) => {
24
- const decoded = Result.try(() => atob(encoded));
25
- if (decoded.isErr()) return;
26
- const binary = decoded.value;
27
- const bytes = new Uint8Array(binary.length);
28
- for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
29
- return bytes;
25
+ const decoded = Result.try(() => base64ToBytes(encoded));
26
+ return decoded.isOk() ? decoded.value : void 0;
30
27
  };
31
28
  const readUint32BE = (bytes, offset) => bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3];
32
29
  const readUint16BE = (bytes, offset) => bytes[offset] << 8 | bytes[offset + 1];
@@ -4,12 +4,13 @@ import { DisplayPrimitive } from "../types.js";
4
4
  import { BuildContext } from "./buildContext.js";
5
5
  //#region src/display-list/build/watermarkPrimitives.d.ts
6
6
  type WatermarkPaintOptions = {
7
+ embeddedFontFamilyMap?: ReadonlyMap<string, string> | undefined;
7
8
  readonly page: Page;
8
9
  readonly watermark: document_d_exports.Watermark;
9
10
  /** Resolved `data:` source for a picture watermark; absent means unresolved. */
10
11
  readonly imageSrc?: string;
11
12
  readonly context: BuildContext;
12
13
  };
13
- declare const paintWatermark: ({ page, watermark, imageSrc, context }: WatermarkPaintOptions) => readonly DisplayPrimitive[];
14
+ declare const paintWatermark: ({ page, watermark, imageSrc, context, embeddedFontFamilyMap }: WatermarkPaintOptions) => readonly DisplayPrimitive[];
14
15
  //#endregion
15
16
  export { WatermarkPaintOptions, paintWatermark };
@@ -29,9 +29,10 @@ const TEXT_DEFAULT_OPACITY = .5;
29
29
  const TEXT_DIAGONAL_DEGREES = -45;
30
30
  const PICTURE_NATIVE_SCALE = 1;
31
31
  const PICTURE_WASHOUT_OPACITY = .18;
32
- const paintTextWatermark = (watermark, page, context) => {
32
+ const paintTextWatermark = ({ watermark, page, context, embeddedFontFamilyMap }) => {
33
33
  if (watermark.text.length === 0) return [];
34
34
  const style = {
35
+ ...embeddedFontFamilyMap ? { embeddedFontFamilyMap } : {},
35
36
  fontFamily: watermark.font ?? TEXT_DEFAULT_FONT,
36
37
  fontSize: pxToPt(TEXT_FONT_SIZE_PX),
37
38
  bold: true
@@ -129,9 +130,14 @@ const paintPictureWatermark = (watermark, page, imageSrc, context) => {
129
130
  opacity: watermark.washout === false ? 1 : PICTURE_WASHOUT_OPACITY
130
131
  }];
131
132
  };
132
- const paintWatermark = ({ page, watermark, imageSrc, context }) => {
133
+ const paintWatermark = ({ page, watermark, imageSrc, context, embeddedFontFamilyMap }) => {
133
134
  switch (watermark.kind) {
134
- case "text": return paintTextWatermark(watermark, page, context);
135
+ case "text": return paintTextWatermark({
136
+ watermark,
137
+ page,
138
+ context,
139
+ embeddedFontFamilyMap
140
+ });
135
141
  case "picture": return paintPictureWatermark(watermark, page, imageSrc, context);
136
142
  default: return [];
137
143
  }
@@ -17,6 +17,7 @@ const isPageRendererName = (value) => value === PAGE_RENDERER.legacy || value ==
17
17
  * which header a page carries.
18
18
  */
19
19
  const displayListFurnitureFrom = (options) => ({
20
+ ...options.embeddedFontFamilyMap ? { embeddedFontFamilyMap: options.embeddedFontFamilyMap } : {},
20
21
  ...options.pageBorders === void 0 ? {} : { pageBorders: options.pageBorders },
21
22
  ...options.theme === void 0 ? {} : { theme: options.theme },
22
23
  ...options.watermark === void 0 ? {} : { watermark: options.watermark },
@@ -0,0 +1,10 @@
1
+ //#region src/docx/bookmarkIdNormalization.d.ts
2
+ /**
3
+ * Give repeated bookmark ranges independent identities before editor pairing.
4
+ * The first range keeps its id. Ends close starts in encounter order, including
5
+ * overlapping ambiguous ranges. Only colliding ids are repaired: those require
6
+ * unique XML ids for a valid save. Every other source byte stays verbatim.
7
+ */
8
+ declare const normalizeBookmarkIdsInXmlParts: (parts: ReadonlyMap<string, string>) => ReadonlyMap<string, string>;
9
+ //#endregion
10
+ export { normalizeBookmarkIdsInXmlParts };
@@ -0,0 +1,100 @@
1
+ import { scanSelectedStreamingXmlElements } from "./selectedXmlIdentityScan.js";
2
+ import { WORDPROCESSINGML_NAMESPACE_URIS, findAttributeByNamespaceUri, getLocalName, getNamespaceUri } from "./xmlParser.js";
3
+ import { panic } from "better-result";
4
+ //#region src/docx/bookmarkIdNormalization.ts
5
+ const bookmarkIdentity = (element) => {
6
+ if (!WORDPROCESSINGML_NAMESPACE_URIS.has(getNamespaceUri(element) ?? "")) return null;
7
+ const name = getLocalName(element.name);
8
+ if (name !== "bookmarkStart" && name !== "bookmarkEnd") return null;
9
+ const attribute = findAttributeByNamespaceUri(element, WORDPROCESSINGML_NAMESPACE_URIS, "id");
10
+ if (!attribute) return null;
11
+ const id = Number(attribute.value);
12
+ if (!Number.isSafeInteger(id) || id < 0) return null;
13
+ return {
14
+ name,
15
+ attribute: attribute.name,
16
+ id
17
+ };
18
+ };
19
+ /**
20
+ * Give repeated bookmark ranges independent identities before editor pairing.
21
+ * The first range keeps its id. Ends close starts in encounter order, including
22
+ * overlapping ambiguous ranges. Only colliding ids are repaired: those require
23
+ * unique XML ids for a valid save. Every other source byte stays verbatim.
24
+ */
25
+ const normalizeBookmarkIdsInXmlParts = (parts) => {
26
+ const candidates = [...parts].filter(([, xml]) => /bookmark(?:Start|End)/u.test(xml));
27
+ const reserved = /* @__PURE__ */ new Set();
28
+ const repeated = /* @__PURE__ */ new Set();
29
+ const markersByPart = /* @__PURE__ */ new Map();
30
+ for (const [path, xml] of candidates) {
31
+ const starts = /* @__PURE__ */ new Set();
32
+ const markers = [];
33
+ if (scanSelectedStreamingXmlElements(xml, ({ element, attributeValueSpans }) => {
34
+ const marker = bookmarkIdentity(element);
35
+ if (!marker) return;
36
+ const span = attributeValueSpans.get(marker.attribute);
37
+ if (!span) panic("Missing bookmark identity source span");
38
+ markers.push({
39
+ marker,
40
+ ...span
41
+ });
42
+ reserved.add(marker.id);
43
+ if (marker.name === "bookmarkStart") {
44
+ if (starts.has(marker.id)) repeated.add(path);
45
+ starts.add(marker.id);
46
+ }
47
+ }).status === "unsupported") {
48
+ repeated.delete(path);
49
+ continue;
50
+ }
51
+ markersByPart.set(path, markers);
52
+ }
53
+ if (repeated.size === 0) return parts;
54
+ let next = 0;
55
+ const allocate = () => {
56
+ while (reserved.has(next)) next += 1;
57
+ const id = next++;
58
+ reserved.add(id);
59
+ return id;
60
+ };
61
+ const normalized = new Map(parts);
62
+ for (const [path, xml] of candidates) {
63
+ if (!repeated.has(path)) continue;
64
+ const seen = /* @__PURE__ */ new Set();
65
+ const open = /* @__PURE__ */ new Map();
66
+ const chunks = [];
67
+ let cursor = 0;
68
+ for (const { marker, start, end } of markersByPart.get(path) ?? []) {
69
+ let id = marker.id;
70
+ if (marker.name === "bookmarkStart") {
71
+ if (seen.has(id)) id = allocate();
72
+ seen.add(marker.id);
73
+ let queue = open.get(marker.id);
74
+ if (!queue) {
75
+ queue = {
76
+ ids: [],
77
+ cursor: 0
78
+ };
79
+ open.set(marker.id, queue);
80
+ }
81
+ queue.ids.push(id);
82
+ } else {
83
+ const queue = open.get(marker.id);
84
+ const paired = queue?.ids.at(queue.cursor);
85
+ if (paired !== void 0 && queue) {
86
+ id = paired;
87
+ queue.cursor += 1;
88
+ }
89
+ }
90
+ if (id === marker.id) continue;
91
+ chunks.push(xml.slice(cursor, start), String(id));
92
+ cursor = end;
93
+ }
94
+ chunks.push(xml.slice(cursor));
95
+ normalized.set(path, chunks.join(""));
96
+ }
97
+ return normalized;
98
+ };
99
+ //#endregion
100
+ export { normalizeBookmarkIdsInXmlParts };
@@ -31,8 +31,10 @@ function createBookmarkMap() {
31
31
  * @param bookmark - The bookmark start to add
32
32
  */
33
33
  function addBookmark(map, bookmark) {
34
- map.byId.set(bookmark.id, bookmark);
35
- if (bookmark.name) map.byName.set(bookmark.name, bookmark);
34
+ if (!map.byId.has(bookmark.id)) map.byId.set(bookmark.id, bookmark);
35
+ if (bookmark.name) {
36
+ if (!map.byName.has(bookmark.name)) map.byName.set(bookmark.name, bookmark);
37
+ }
36
38
  map.bookmarks.push(bookmark);
37
39
  }
38
40
  /**
@@ -1,5 +1,6 @@
1
1
  import { withTrackedSectionEndpointRemoval } from "../internal/sectionEndpointResolution.js";
2
2
  import { withSectionReferenceResolution } from "../internal/sectionReferenceResolution.js";
3
+ import { decodeText, encodeUtf8 } from "../utils/textEncoding.js";
3
4
  import { readDocumentSectionFacts } from "./documentSectionFacts.js";
4
5
  import { parseDocx } from "./parser.js";
5
6
  import { assertSectionCarriersMatchModel } from "./rezip.js";
@@ -9,7 +10,7 @@ import JSZip from "jszip";
9
10
  /** Canonical snapshots own explicit section references; the PM projection does not. */
10
11
  const referenceKey = ({ element, type, rId }) => `${element}:${type}:${rId}`;
11
12
  const xmlFingerprint = async (xml) => {
12
- const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(xml));
13
+ const digest = await crypto.subtle.digest("SHA-256", encodeUtf8(xml));
13
14
  let fingerprint = "";
14
15
  for (const byte of new Uint8Array(digest)) fingerprint += byte.toString(16).padStart(2, "0");
15
16
  return fingerprint;
@@ -18,7 +19,7 @@ const xmlFingerprint = async (xml) => {
18
19
  const repackWithCanonicalStoryRemovals = async ({ document, repack }) => {
19
20
  const originalBuffer = document.originalBuffer;
20
21
  if (!originalBuffer) return repack();
21
- const xml = await (await JSZip.loadAsync(originalBuffer)).file("word/document.xml")?.async("text");
22
+ const xml = await (await JSZip.loadAsync(originalBuffer)).file("word/document.xml")?.async("uint8array").then((bytes) => decodeText(bytes, { ignoreBOM: true }));
22
23
  if (!xml) return repack();
23
24
  const before = readDocumentSectionFacts(xml);
24
25
  const serializedXml = serializeDocument(document);
@@ -0,0 +1,6 @@
1
+ import { document_d_exports } from "../types/document.js";
2
+ //#region src/docx/commentTextParagraph.d.ts
3
+ /** Plain comment text has no authored paragraph formatting. */
4
+ declare const commentTextParagraph: (text: string) => document_d_exports.Paragraph;
5
+ //#endregion
6
+ export { commentTextParagraph };
@@ -0,0 +1,15 @@
1
+ //#region src/docx/commentTextParagraph.ts
2
+ /** Plain comment text has no authored paragraph formatting. */
3
+ const commentTextParagraph = (text) => ({
4
+ type: "paragraph",
5
+ content: [{
6
+ type: "run",
7
+ formatting: {},
8
+ content: [{
9
+ type: "text",
10
+ text
11
+ }]
12
+ }]
13
+ });
14
+ //#endregion
15
+ export { commentTextParagraph };
@@ -1,3 +1,4 @@
1
+ import { sliceText } from "../utils/sliceText.js";
1
2
  import { getLocalName, getNamespacePrefix, parseXmlDocument } from "./xmlParser.js";
2
3
  import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
3
4
  //#region src/docx/conformance.ts
@@ -62,7 +63,11 @@ function scanRootStartTag(scanTarget) {
62
63
  }
63
64
  const detectDocxConformanceClass = (documentXml) => {
64
65
  if (documentXml === null) return DOCX_CONFORMANCE_CLASSES.UNKNOWN;
65
- const rootStartTag = scanRootStartTag(documentXml.length <= ROOT_START_TAG_SCAN_LIMIT ? documentXml : documentXml.slice(0, ROOT_START_TAG_SCAN_LIMIT));
66
+ const rootStartTag = scanRootStartTag(documentXml.length <= ROOT_START_TAG_SCAN_LIMIT ? documentXml : sliceText({
67
+ text: documentXml,
68
+ units: "codeUnits",
69
+ end: ROOT_START_TAG_SCAN_LIMIT
70
+ }));
66
71
  const root = (rootStartTag === void 0 ? null : parseXmlDocument(rootStartTag.endsWith("/>") ? rootStartTag : `${rootStartTag.slice(0, -1)}/>`)) ?? parseXmlDocument(documentXml);
67
72
  return detectDocxConformanceClassFromRoot(root);
68
73
  };
@@ -1,3 +1,4 @@
1
+ import { decodeText } from "../utils/textEncoding.js";
1
2
  import { resolveRelationshipIdOfType, resolveRelativePath } from "./relsParser.js";
2
3
  import { OFFICE_RELATIONSHIP_NAMESPACE_URIS, findChildByNamespaceUri, getAttribute, getAttributeByNamespaceUri, getLocalName, parseNumericAttribute, parseXmlDocument } from "./xmlParser.js";
3
4
  //#region src/docx/diagramPreview.ts
@@ -31,7 +32,7 @@ const partByRelationshipId = ({ rels, media, rId, type, cache }) => {
31
32
  const cached = cache.get(path);
32
33
  if (cached !== void 0) return cached;
33
34
  const file = media.get(path);
34
- const parsed = file?.data ? parseXmlDocument(new TextDecoder().decode(file.data)) : null;
35
+ const parsed = file?.data ? parseXmlDocument(decodeText(new Uint8Array(file.data))) : null;
35
36
  cache.set(path, parsed);
36
37
  return parsed;
37
38
  };
@@ -19,6 +19,18 @@ declare function extractTemplateVariables(text: string): string[];
19
19
  * @returns Array of unique variable names
20
20
  */
21
21
  declare function extractAllTemplateVariables(content: document_d_exports.BlockContent[]): string[];
22
+ /**
23
+ * Build sections from content based on section properties in paragraphs
24
+ *
25
+ * In OOXML, sections are delimited by:
26
+ * 1. w:pPr/w:sectPr within a paragraph (marks end of a section)
27
+ * 2. w:body/w:sectPr (final section properties)
28
+ *
29
+ * @param content - All block content
30
+ * @param finalSectPr - Final section properties from body
31
+ * @returns Array of sections
32
+ */
33
+ declare function buildSections(content: document_d_exports.BlockContent[], finalSectPr: document_d_exports.SectionProperties | undefined): document_d_exports.Section[];
22
34
  /**
23
35
  * Parse document.xml body content
24
36
  *
@@ -67,4 +79,4 @@ declare function getSectionCount(body: document_d_exports.DocumentBody): number;
67
79
  */
68
80
  declare function hasTemplateVariables(body: document_d_exports.DocumentBody): boolean;
69
81
  //#endregion
70
- export { extractAllTemplateVariables, extractTemplateVariables, getAllParagraphs, getAllTables, getParagraphCount, getSectionCount, hasTemplateVariables, parseDocumentBody, parseDocumentBodyTree };
82
+ export { buildSections, extractAllTemplateVariables, extractTemplateVariables, getAllParagraphs, getAllTables, getParagraphCount, getSectionCount, hasTemplateVariables, parseDocumentBody, parseDocumentBodyTree };
@@ -257,4 +257,4 @@ function hasTemplateVariables(body) {
257
257
  return extractAllTemplateVariables(body.content).length > 0;
258
258
  }
259
259
  //#endregion
260
- export { extractAllTemplateVariables, extractTemplateVariables, getAllParagraphs, getAllTables, getParagraphCount, getSectionCount, hasTemplateVariables, parseDocumentBody, parseDocumentBodyTree };
260
+ export { buildSections, extractAllTemplateVariables, extractTemplateVariables, getAllParagraphs, getAllTables, getParagraphCount, getSectionCount, hasTemplateVariables, parseDocumentBody, parseDocumentBodyTree };
@@ -1,12 +1,4 @@
1
1
  //#region src/docx/encryption/compoundFile.d.ts
2
- /**
3
- * Read-only MS-CFB compound file access for encrypted OOXML packages.
4
- *
5
- * Encrypted `.docx` files store `EncryptionInfo` and `EncryptedPackage` streams
6
- * at the compound-file root. This reader implements only what MS-OFFCRYPTO needs.
7
- *
8
- * @see https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/
9
- */
10
2
  type CompoundFileReader = {
11
3
  readStream: (absolutePath: string) => Uint8Array | null;
12
4
  };
@@ -1,3 +1,4 @@
1
+ import { decodeText } from "../../utils/textEncoding.js";
1
2
  import { joinBytes } from "./cryptoBytes.js";
2
3
  //#region src/docx/encryption/compoundFile.ts
3
4
  /**
@@ -39,7 +40,7 @@ const u64 = (view, offset) => {
39
40
  return BigInt(view.getUint32(offset + 4, true)) << 32n | low;
40
41
  };
41
42
  const decodeName = (nameBytes) => {
42
- const decoded = new TextDecoder("utf-16le").decode(nameBytes);
43
+ const decoded = decodeText(nameBytes, { encoding: "utf-16le" });
43
44
  let end = decoded.length;
44
45
  while (end > 0 && decoded.charCodeAt(end - 1) === 0) end--;
45
46
  return decoded.slice(0, end);
@@ -2,10 +2,10 @@
2
2
  /** Byte helpers shared by MS-CFB and MS-OFFCRYPTO agile decryption. */
3
3
  declare const joinBytes: (parts: readonly Uint8Array[]) => Uint8Array;
4
4
  declare const writeUint32Le: (value: number) => Uint8Array;
5
- declare const passwordToUtf16Le: (password: string) => Uint8Array;
5
+ declare const passwordToUtf16Le: (text: string) => Uint8Array<ArrayBuffer>;
6
6
  declare const bytesEqual: (left: Uint8Array, right: Uint8Array) => boolean;
7
7
  declare const toArrayBuffer: (bytes: Uint8Array) => ArrayBuffer;
8
- declare const decodeBase64: (encoded: string) => Uint8Array;
8
+ declare const decodeBase64: (text: string) => Uint8Array<ArrayBuffer>;
9
9
  declare const padToBlock: (bytes: Uint8Array, blockSize: number, padByte?: number) => Uint8Array;
10
10
  //#endregion
11
11
  export { bytesEqual, decodeBase64, joinBytes, padToBlock, passwordToUtf16Le, toArrayBuffer, writeUint32Le };
@@ -1,3 +1,4 @@
1
+ import { base64ToBytes, encodeUtf16LE } from "../../utils/textEncoding.js";
1
2
  //#region src/docx/encryption/cryptoBytes.ts
2
3
  /** Byte helpers shared by MS-CFB and MS-OFFCRYPTO agile decryption. */
3
4
  const joinBytes = (parts) => {
@@ -19,15 +20,7 @@ const writeUint32Le = (value) => {
19
20
  out[3] = value >>> 24 & 255;
20
21
  return out;
21
22
  };
22
- const passwordToUtf16Le = (password) => {
23
- const out = new Uint8Array(password.length * 2);
24
- for (let i = 0; i < password.length; i++) {
25
- const code = password.charCodeAt(i);
26
- out[i * 2] = code & 255;
27
- out[i * 2 + 1] = code >> 8;
28
- }
29
- return out;
30
- };
23
+ const passwordToUtf16Le = encodeUtf16LE;
31
24
  const bytesEqual = (left, right) => {
32
25
  if (left.length !== right.length) return false;
33
26
  let mismatch = 0;
@@ -38,15 +31,7 @@ const toArrayBuffer = (bytes) => {
38
31
  if (bytes.buffer instanceof ArrayBuffer && bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) return bytes.buffer;
39
32
  return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
40
33
  };
41
- const decodeBase64 = (encoded) => {
42
- if (typeof atob === "function") {
43
- const binary = atob(encoded);
44
- const out = new Uint8Array(binary.length);
45
- for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
46
- return out;
47
- }
48
- return new Uint8Array(Buffer.from(encoded, "base64"));
49
- };
34
+ const decodeBase64 = base64ToBytes;
50
35
  const padToBlock = (bytes, blockSize, padByte = 54) => {
51
36
  if (bytes.length >= blockSize) return bytes.subarray(0, blockSize);
52
37
  const out = new Uint8Array(blockSize);
@@ -1,9 +1,4 @@
1
1
  //#region src/docx/encryption/encryptionInfo.d.ts
2
- /**
3
- * Parse the EncryptionInfo stream for Agile Encryption (Office 2010+).
4
- *
5
- * @see https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/87020a34-e73f-4139-99bc-bbdf6cf6fa55
6
- */
7
2
  type AgileKeyMaterial = {
8
3
  packageSalt: Uint8Array;
9
4
  packageKeyBits: number;
@@ -1,3 +1,4 @@
1
+ import { decodeText } from "../../utils/textEncoding.js";
1
2
  import { decodeBase64 } from "./cryptoBytes.js";
2
3
  import { DOCX_ENCRYPTION_ERROR_CODES, DocxEncryptionError } from "./errors.js";
3
4
  //#region src/docx/encryption/encryptionInfo.ts
@@ -85,7 +86,7 @@ const requireSpinCount = (attrs, element) => {
85
86
  return spinCount;
86
87
  };
87
88
  const parseAgileXml = (xmlBytes) => {
88
- const xml = new TextDecoder("utf-8").decode(xmlBytes);
89
+ const xml = decodeText(xmlBytes, { encoding: "utf-8" });
89
90
  const keyDataTag = findElement(xml, "keyData");
90
91
  const integrityTag = findElement(xml, "dataIntegrity");
91
92
  const encryptedKeyTag = findElement(xml, "encryptedKey");
@@ -1,4 +1,5 @@
1
1
  import { deterministicHexId } from "../utils/hexId.js";
2
+ import { encodeUtf8 } from "../utils/textEncoding.js";
2
3
  import { resolvePackageRelationshipTarget } from "./packageParts.js";
3
4
  import { spliceXml } from "./selectiveXmlPatch.js";
4
5
  import { loadDocxArchive } from "./server/boundedArchive.js";
@@ -390,7 +391,7 @@ const ensureParaIdsInternal = async (docx, options) => {
390
391
  writeZipPart({
391
392
  zip,
392
393
  path: partPath,
393
- data: content,
394
+ data: encodeUtf8(content),
394
395
  options: {
395
396
  compression: "DEFLATE",
396
397
  compressionOptions: { level: 6 },
@@ -1,3 +1,4 @@
1
+ import { sliceText } from "../utils/sliceText.js";
1
2
  import { emuToPixels } from "../utils/units.js";
2
3
  import { collectGroupTextBoxes, readTransform } from "./drawingGroupChildren.js";
3
4
  import { parseImage, resolveImageData } from "./imageParser.js";
@@ -142,7 +143,11 @@ const renderTextBox = (wsp, unitScale) => {
142
143
  const color = colorFrom(findAllDeep(wsp, "w", "color").at(0) ?? null, DEFAULT_TEXT_COLOR);
143
144
  const fontSize = halfPoints * HALF_POINT_TO_EMU / unitScale;
144
145
  const maxCharacters = Math.max(1, Math.floor(width / (fontSize * .38)));
145
- const lines = paragraphs.flatMap((paragraph) => wrapLine(getTextContent(paragraph).slice(0, MAX_TEXT_CHARACTERS), maxCharacters)).map(escapeXmlText);
146
+ const lines = paragraphs.flatMap((paragraph) => wrapLine(sliceText({
147
+ text: getTextContent(paragraph),
148
+ units: "codeUnits",
149
+ end: MAX_TEXT_CHARACTERS
150
+ }), maxCharacters)).map(escapeXmlText);
146
151
  if (lines.length === 0) return "";
147
152
  const lineHeight = fontSize * 1.15;
148
153
  const svgFontSize = 1e3;