@stll/folio-core 0.29.0 → 0.31.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 (103) hide show
  1. package/dist/controller/folioEditor.d.ts +28 -1
  2. package/dist/controller/folioEditor.js +37 -26
  3. package/dist/controller/fontReadiness.js +28 -24
  4. package/dist/controller/hiddenEditorManager.d.ts +2 -7
  5. package/dist/controller/layoutPipeline.js +33 -3
  6. package/dist/controller/noteEditorManager.d.ts +3 -6
  7. package/dist/docx/metafileSvg.d.ts +12 -0
  8. package/dist/docx/metafileSvg.js +462 -0
  9. package/dist/docx/paragraphTextBoxEnrichment.js +55 -4
  10. package/dist/docx/parser.d.ts +2 -2
  11. package/dist/docx/parser.js +26 -0
  12. package/dist/docx/runParser.js +2 -1
  13. package/dist/docx/serializer/runSerializer.js +14 -2
  14. package/dist/docx/server/createBilingualDocument.d.ts +20 -3
  15. package/dist/docx/server/createBilingualDocument.js +153 -22
  16. package/dist/docx/styleParser.js +2 -1
  17. package/dist/docx/textBoxParser.js +14 -0
  18. package/dist/docx/vmlImageParser.js +72 -152
  19. package/dist/docx/vmlPreview.d.ts +31 -0
  20. package/dist/docx/vmlPreview.js +535 -0
  21. package/dist/docx/wrapTypes.d.ts +2 -36
  22. package/dist/docx/wrapTypes.js +1 -39
  23. package/dist/fonts/fontAlternates.d.ts +8 -0
  24. package/dist/fonts/fontAlternates.js +16 -0
  25. package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
  26. package/dist/layout-bridge/convert/footnoteLayout.js +34 -3
  27. package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
  28. package/dist/layout-bridge/convert/headerFooterLayout.js +5 -0
  29. package/dist/layout-bridge/convert/toFlowBlocks.d.ts +3 -0
  30. package/dist/layout-bridge/convert/toFlowBlocks.js +78 -28
  31. package/dist/layout-bridge/dom/noteStoryDom.d.ts +1 -1
  32. package/dist/layout-bridge/engine/selectionRects.js +3 -1
  33. package/dist/layout-engine/index.js +65 -32
  34. package/dist/layout-engine/justifiedLineFit.d.ts +7 -0
  35. package/dist/layout-engine/justifiedLineFit.js +6 -0
  36. package/dist/layout-engine/keep-together.js +15 -10
  37. package/dist/layout-engine/measure/complexScriptFormatting.d.ts +6 -1
  38. package/dist/layout-engine/measure/complexScriptFormatting.js +11 -2
  39. package/dist/layout-engine/measure/floatingTablePosition.d.ts +16 -1
  40. package/dist/layout-engine/measure/floatingTablePosition.js +29 -6
  41. package/dist/layout-engine/measure/lineBreakProvider.js +67 -8
  42. package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
  43. package/dist/layout-engine/measure/listMarkerWidth.js +23 -10
  44. package/dist/layout-engine/measure/measureBlocks.d.ts +15 -0
  45. package/dist/layout-engine/measure/measureBlocks.js +197 -30
  46. package/dist/layout-engine/measure/measureContainer.js +20 -24
  47. package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
  48. package/dist/layout-engine/measure/measureHelpers.js +14 -8
  49. package/dist/layout-engine/measure/measureParagraph.js +111 -37
  50. package/dist/layout-engine/measure/measureTypes.d.ts +3 -0
  51. package/dist/layout-engine/measure/tabCalculator.d.ts +123 -0
  52. package/dist/layout-engine/measure/tabCalculator.js +144 -0
  53. package/dist/layout-engine/measure/tableCellFlow.d.ts +21 -1
  54. package/dist/layout-engine/measure/tableCellFlow.js +45 -8
  55. package/dist/layout-engine/measure/tableInlinePlacement.d.ts +10 -2
  56. package/dist/layout-engine/measure/tableInlinePlacement.js +17 -15
  57. package/dist/layout-engine/paginator.d.ts +26 -2
  58. package/dist/layout-engine/paginator.js +76 -14
  59. package/dist/layout-engine/paragraphSpacing.d.ts +3 -1
  60. package/dist/layout-engine/paragraphSpacing.js +4 -3
  61. package/dist/layout-engine/renderedBreakReconciliation.d.ts +14 -3
  62. package/dist/layout-engine/renderedBreakReconciliation.js +45 -14
  63. package/dist/layout-engine/section-breaks.d.ts +3 -1
  64. package/dist/layout-engine/section-breaks.js +6 -2
  65. package/dist/layout-engine/types.d.ts +18 -1
  66. package/dist/layout-engine/types.js +1 -1
  67. package/dist/layout-painter/imageLayout.d.ts +1 -1
  68. package/dist/layout-painter/renderPage.js +6 -1
  69. package/dist/layout-painter/renderParagraph.js +169 -82
  70. package/dist/layout-painter/renderTable.d.ts +1 -1
  71. package/dist/layout-painter/renderTable.js +18 -7
  72. package/dist/layout-painter/renderTextBox.d.ts +1 -1
  73. package/dist/layout-painter/renderTextBox.js +6 -1
  74. package/dist/model.d.ts +3 -3
  75. package/dist/model.js +2 -2
  76. package/dist/paged-layout/sectionBlockWidths.d.ts +14 -0
  77. package/dist/paged-layout/sectionBlockWidths.js +103 -14
  78. package/dist/prosemirror/attrs/index.js +12 -1
  79. package/dist/prosemirror/conversion/fromProseDoc.js +6 -2
  80. package/dist/prosemirror/conversion/toProseDoc.js +10 -3
  81. package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +9 -5
  82. package/dist/prosemirror/extensions/nodes/TableExtension.js +2 -0
  83. package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +6 -2
  84. package/dist/prosemirror/schema/nodes.d.ts +4 -0
  85. package/dist/prosemirror/utils/tabCalculator.d.ts +2 -123
  86. package/dist/prosemirror/utils/tabCalculator.js +1 -140
  87. package/dist/render-dom/RemoteSelectionOverlay.d.ts +4 -4
  88. package/dist/server.d.ts +2 -2
  89. package/dist/server.js +2 -2
  90. package/dist/types/documentEnumValues.d.ts +4 -1
  91. package/dist/types/documentEnumValues.js +12 -1
  92. package/dist/types/editor-story.d.ts +8 -0
  93. package/dist/types/editor-story.js +0 -0
  94. package/dist/types/remote-selection.d.ts +11 -0
  95. package/dist/types/remote-selection.js +0 -0
  96. package/dist/types/wrap.d.ts +36 -0
  97. package/dist/types/wrap.js +40 -0
  98. package/dist/utils/fontResolver.d.ts +1 -1
  99. package/dist/utils/fontResolver.js +42 -2
  100. package/dist/utils/formatToStyle.js +4 -2
  101. package/dist/utils/horizontalScale.d.ts +28 -0
  102. package/dist/utils/horizontalScale.js +42 -0
  103. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { measureParagraph } from "../../layout-engine/measure/measureParagraph.js";
2
2
  import { layoutTextBoxContent } from "../../layout-engine/measure/textBoxParagraphLayout.js";
3
- import { DEFAULT_TEXTBOX_MARGINS, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT } from "../../layout-engine/types.js";
3
+ import { DEFAULT_TEXTBOX_MARGINS, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, isFloatingImageRun } from "../../layout-engine/types.js";
4
4
  import { footnoteToProseDoc } from "../../prosemirror/conversion/toProseDoc.js";
5
5
  import { toFlowBlocks } from "./toFlowBlocks.js";
6
6
  //#region src/layout-bridge/convert/footnoteLayout.ts
@@ -196,6 +196,7 @@ function convertFootnoteToContent(footnote, displayNumber, contentWidth, options
196
196
  const pmDoc = footnoteToProseDoc(footnote.content, proseOptions);
197
197
  const flowOptions = {};
198
198
  if (options.theme !== void 0) flowOptions.theme = options.theme;
199
+ if (options.fontAlternates !== void 0) flowOptions.fontAlternates = options.fontAlternates;
199
200
  if (options.defaultTabStopTwips !== void 0) flowOptions.defaultTabStopTwips = options.defaultTabStopTwips;
200
201
  if (options.lineBreakRules) flowOptions.lineBreakRules = options.lineBreakRules;
201
202
  if (options.justificationCompatibility) flowOptions.justificationCompatibility = options.justificationCompatibility;
@@ -363,18 +364,48 @@ function applyFootnotePresentation(blocks, displayNumber) {
363
364
  return output;
364
365
  }
365
366
  function createFootnoteNumberRun(displayNumber, paragraph) {
366
- const firstTextRun = paragraph.runs.find((run) => run.kind === "text");
367
367
  const firstFormattedRun = paragraph.runs.find((run) => run.kind === "text" || run.kind === "tab" || run.kind === "field");
368
368
  const numberRun = {
369
369
  kind: "text",
370
- text: firstTextRun?.text.match(/^\s/u) ? `${displayNumber}` : `${displayNumber} `,
370
+ text: `${displayNumber}${resolveFootnoteNumberSuffix(paragraph.runs) === FOOTNOTE_NUMBER_SUFFIX.SEPARATED ? " " : ""}`,
371
371
  fontSize: firstFormattedRun?.fontSize ?? paragraph.attrs?.defaultFontSize ?? FOOTNOTE_FONT_SIZE,
372
372
  superscript: true
373
373
  };
374
374
  const fontFamily = firstFormattedRun?.fontFamily ?? paragraph.attrs?.defaultFontFamily;
375
375
  if (fontFamily) numberRun.fontFamily = fontFamily;
376
+ const alternateFontFamily = firstFormattedRun?.fontFamily !== void 0 ? firstFormattedRun.alternateFontFamily : paragraph.attrs?.defaultAlternateFontFamily;
377
+ if (alternateFontFamily) numberRun.alternateFontFamily = alternateFontFamily;
376
378
  return numberRun;
377
379
  }
380
+ const FOOTNOTE_NUMBER_SUFFIX = {
381
+ ATTACHED: "none",
382
+ SEPARATED: "space"
383
+ };
384
+ const ATTACHED_FOOTNOTE_SUFFIX_PATTERN = /^(?:[\p{Pe}\p{Pf}\p{Sentence_Terminal}]|[,;:\u060c\u061b\u3001\uff0c\uff1a\uff1b])/u;
385
+ const LEADING_WHITESPACE_PATTERN = /^\s/u;
386
+ function resolveTextFootnoteNumberSuffix(text) {
387
+ if (LEADING_WHITESPACE_PATTERN.test(text) || ATTACHED_FOOTNOTE_SUFFIX_PATTERN.test(text)) return FOOTNOTE_NUMBER_SUFFIX.ATTACHED;
388
+ return FOOTNOTE_NUMBER_SUFFIX.SEPARATED;
389
+ }
390
+ function resolveRunFootnoteNumberSuffix(run) {
391
+ switch (run.kind) {
392
+ case "text": return run.text.length === 0 ? void 0 : resolveTextFootnoteNumberSuffix(run.text);
393
+ case "tab":
394
+ case "lineBreak": return FOOTNOTE_NUMBER_SUFFIX.ATTACHED;
395
+ case "field": return resolveTextFootnoteNumberSuffix(run.fallback || "1");
396
+ case "image": return isFloatingImageRun(run) ? void 0 : FOOTNOTE_NUMBER_SUFFIX.SEPARATED;
397
+ case "math": return FOOTNOTE_NUMBER_SUFFIX.SEPARATED;
398
+ case "renderedPageBreak": return;
399
+ default: return run;
400
+ }
401
+ }
402
+ function resolveFootnoteNumberSuffix(runs) {
403
+ for (const run of runs) {
404
+ const suffix = resolveRunFootnoteNumberSuffix(run);
405
+ if (suffix !== void 0) return suffix;
406
+ }
407
+ return FOOTNOTE_NUMBER_SUFFIX.SEPARATED;
408
+ }
378
409
  function applyFootnoteBlockPresentation(block) {
379
410
  if (block.kind === "paragraph") return applyFootnoteParagraphPresentation(block);
380
411
  if (block.kind === "table") return applyFootnoteTablePresentation(block);
@@ -41,6 +41,7 @@ declare function calculateHeaderFooterBodyTopClearance(blocks: FlowBlock[], flow
41
41
  type ConvertHeaderFooterOptions = {
42
42
  styles?: document_d_exports.StyleDefinitions | null;
43
43
  theme?: document_d_exports.Theme | null;
44
+ fontAlternates?: ToFlowBlocksOptions["fontAlternates"];
44
45
  measureBlocks: MeasureBlocksFn;
45
46
  /** Document-wide `w:defaultTabStop` in twips — forwarded to toFlowBlocks. */
46
47
  defaultTabStopTwips?: number;
@@ -333,6 +333,7 @@ function convertHeaderFooterToContent(headerFooter, contentWidth, metrics, optio
333
333
  const pmDoc = headerFooterToProseDoc(headerFooter.content, proseDocOptions);
334
334
  const flowOptions = {};
335
335
  if (options.theme !== void 0) flowOptions.theme = options.theme;
336
+ if (options.fontAlternates !== void 0) flowOptions.fontAlternates = options.fontAlternates;
336
337
  if (options.defaultTabStopTwips !== void 0) flowOptions.defaultTabStopTwips = options.defaultTabStopTwips;
337
338
  if (options.lineBreakRules) flowOptions.lineBreakRules = options.lineBreakRules;
338
339
  if (options.justificationCompatibility) flowOptions.justificationCompatibility = options.justificationCompatibility;
@@ -354,6 +355,7 @@ function convertHeaderFooterPmDocToContent(pmDoc, contentWidth, metrics, options
354
355
  if (!pmDoc || pmDoc.content.size === 0) return;
355
356
  const flowOptions = {};
356
357
  if (options.theme !== void 0) flowOptions.theme = options.theme;
358
+ if (options.fontAlternates !== void 0) flowOptions.fontAlternates = options.fontAlternates;
357
359
  if (options.defaultTabStopTwips !== void 0) flowOptions.defaultTabStopTwips = options.defaultTabStopTwips;
358
360
  if (options.lineBreakRules) flowOptions.lineBreakRules = options.lineBreakRules;
359
361
  if (options.justificationCompatibility) flowOptions.justificationCompatibility = options.justificationCompatibility;
@@ -495,8 +497,11 @@ function serializeRunFmt(run) {
495
497
  "highlightColor",
496
498
  "fontSize",
497
499
  "fontFamily",
500
+ "alternateFontFamily",
498
501
  "eastAsiaFontFamily",
502
+ "eastAsiaAlternateFontFamily",
499
503
  "complexScriptFontFamily",
504
+ "complexScriptAlternateFontFamily",
500
505
  "complexScriptFontSize",
501
506
  "complexScriptBold",
502
507
  "complexScriptItalic",
@@ -1,5 +1,6 @@
1
1
  import { document_d_exports } from "../../types/document.js";
2
2
  import { BorderStyle, FlowBlock, ParagraphAttrs } from "../../layout-engine/types.js";
3
+ import { FontAlternates } from "../../fonts/fontAlternates.js";
3
4
  import { formatCounter, resolveListTemplate } from "../../prosemirror/listMarker.js";
4
5
  import { Node } from "prosemirror-model";
5
6
  //#region src/layout-bridge/convert/toFlowBlocks.d.ts
@@ -13,6 +14,8 @@ type ToFlowBlocksOptions = {
13
14
  defaultSize?: number;
14
15
  /** Theme for resolving theme colors. */
15
16
  theme?: document_d_exports.Theme | null;
17
+ /** Document-scoped OOXML primary-font to `w:altName` lookup. */
18
+ fontAlternates?: FontAlternates;
16
19
  /** Page content height in pixels (pageHeight - marginTop - marginBottom). Images taller than this are scaled down to fit. */
17
20
  pageContentHeight?: number;
18
21
  /** Shared list counters for nested containers. */
@@ -1,5 +1,6 @@
1
1
  import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
2
2
  import { resolveDocumentGridLinePitch } from "../../docx/documentGrid.js";
3
+ import { getFontAlternate } from "../../fonts/fontAlternates.js";
3
4
  import { setHyperlinkInstanceIndex } from "../../layout-engine/measure/hyperlinkInstance.js";
4
5
  import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
5
6
  import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
@@ -13,9 +14,11 @@ import { resolveNumberedRefFields } from "../../prosemirror/numberedRefFields.js
13
14
  import { directionToBidi } from "../../prosemirror/paragraphDirection.js";
14
15
  import { cascadeStyleTextFormatting } from "../../prosemirror/styles/styleToggleCascade.js";
15
16
  import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
17
+ import { normalizeShapeTextAnchor } from "../../types/documentEnumValues.js";
16
18
  import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.js";
17
19
  import { resolveThemeFont } from "../../utils/fontResolver.js";
18
20
  import { resolveShadingFill } from "../../utils/formatToStyle.js";
21
+ import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
19
22
  import { decodeOoxmlSymbolCharacter } from "../../utils/ooxmlSymbol.js";
20
23
  import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
21
24
  import { AUTO_PARAGRAPH_SPACING_PX, halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
@@ -85,7 +88,7 @@ function resetBlockIdCounter() {
85
88
  /**
86
89
  * Extract run formatting from ProseMirror marks.
87
90
  */
88
- function extractRunFormatting(marks, theme) {
91
+ function extractRunFormatting(marks, theme, fontAlternates) {
89
92
  const formatting = {};
90
93
  let hasNoteRef = false;
91
94
  for (const mark of marks) switch (mark.type.name) {
@@ -137,11 +140,23 @@ function extractRunFormatting(marks, theme) {
137
140
  case "fontFamily": {
138
141
  const attrs = expectFontFamilyMarkAttrs(mark);
139
142
  const font = resolveWesternThemeFont(attrs, theme);
140
- if (font) formatting.fontFamily = font;
143
+ if (font) {
144
+ formatting.fontFamily = font;
145
+ const alternate = getFontAlternate(font, fontAlternates);
146
+ if (alternate) formatting.alternateFontFamily = alternate;
147
+ }
141
148
  const eastAsiaFont = resolveEastAsiaThemeFont(attrs, theme);
142
- if (eastAsiaFont) formatting.eastAsiaFontFamily = eastAsiaFont;
149
+ if (eastAsiaFont) {
150
+ formatting.eastAsiaFontFamily = eastAsiaFont;
151
+ const alternate = getFontAlternate(eastAsiaFont, fontAlternates);
152
+ if (alternate) formatting.eastAsiaAlternateFontFamily = alternate;
153
+ }
143
154
  const complexScriptFont = resolveComplexScriptThemeFont(attrs, theme);
144
- if (complexScriptFont) formatting.complexScriptFontFamily = complexScriptFont;
155
+ if (complexScriptFont) {
156
+ formatting.complexScriptFontFamily = complexScriptFont;
157
+ const alternate = getFontAlternate(complexScriptFont, fontAlternates);
158
+ if (alternate) formatting.complexScriptAlternateFontFamily = alternate;
159
+ }
145
160
  break;
146
161
  }
147
162
  case "language": {
@@ -157,7 +172,8 @@ function extractRunFormatting(marks, theme) {
157
172
  const attrs = expectCharacterSpacingMarkAttrs(mark);
158
173
  if (attrs.spacing !== void 0) formatting.letterSpacing = twipsToPixels(attrs.spacing);
159
174
  if (attrs.position !== void 0 && attrs.position !== 0) formatting.positionPx = halfPointsToPixels(attrs.position);
160
- if (attrs.scale !== void 0 && attrs.scale !== 100) formatting.horizontalScale = attrs.scale;
175
+ const horizontalScale = normalizeHorizontalScalePercent(attrs.scale);
176
+ if (horizontalScale !== void 0) formatting.horizontalScale = horizontalScale;
161
177
  if (attrs.kerning !== void 0 && attrs.kerning > 0) formatting.kerningMinPt = halfPointsToPoints(attrs.kerning);
162
178
  break;
163
179
  }
@@ -280,7 +296,11 @@ function mergeRunFormatting(paraDefaults, formatting) {
280
296
  ...paraDefaults,
281
297
  ...markDefaultBlackTextColorSource(formatting, paraDefaults)
282
298
  };
299
+ if (formatting.fontFamily !== void 0 && formatting.alternateFontFamily === void 0) delete merged.alternateFontFamily;
300
+ if (formatting.eastAsiaFontFamily !== void 0 && formatting.eastAsiaAlternateFontFamily === void 0) delete merged.eastAsiaAlternateFontFamily;
301
+ if (formatting.complexScriptFontFamily !== void 0 && formatting.complexScriptAlternateFontFamily === void 0) delete merged.complexScriptAlternateFontFamily;
283
302
  if (merged.letterSpacing === 0) delete merged.letterSpacing;
303
+ if (formatting.horizontalScale === 100 && paraDefaults.horizontalScale === void 0) delete merged.horizontalScale;
284
304
  return merged;
285
305
  }
286
306
  /** Restore character-style toggle values that plain visual marks cannot represent. */
@@ -332,15 +352,27 @@ function applyRunFormattingOverrides(formatting, attrs) {
332
352
  if (attrs.fontSizeCs !== void 0) formatting.complexScriptFontSize = attrs.fontSizeCs / 2;
333
353
  if (attrs.cs !== void 0) formatting.forceComplexScript = attrs.cs;
334
354
  }
335
- function textFormattingToRunFormatting(defaultTextFormatting, theme) {
355
+ function textFormattingToRunFormatting(defaultTextFormatting, theme, fontAlternates) {
336
356
  if (!defaultTextFormatting) return {};
337
357
  const result = {};
338
358
  const fontFamily = defaultTextFormatting.fontFamily ? resolveWesternThemeFont(defaultTextFormatting.fontFamily, theme) : void 0;
339
- if (fontFamily) result.fontFamily = fontFamily;
359
+ if (fontFamily) {
360
+ result.fontFamily = fontFamily;
361
+ const alternate = getFontAlternate(fontFamily, fontAlternates);
362
+ if (alternate) result.alternateFontFamily = alternate;
363
+ }
340
364
  const eastAsiaFontFamily = defaultTextFormatting.fontFamily ? resolveEastAsiaThemeFont(defaultTextFormatting.fontFamily, theme) : void 0;
341
- if (eastAsiaFontFamily) result.eastAsiaFontFamily = eastAsiaFontFamily;
365
+ if (eastAsiaFontFamily) {
366
+ result.eastAsiaFontFamily = eastAsiaFontFamily;
367
+ const alternate = getFontAlternate(eastAsiaFontFamily, fontAlternates);
368
+ if (alternate) result.eastAsiaAlternateFontFamily = alternate;
369
+ }
342
370
  const complexScriptFontFamily = defaultTextFormatting.fontFamily ? resolveComplexScriptThemeFont(defaultTextFormatting.fontFamily, theme) : void 0;
343
- if (complexScriptFontFamily) result.complexScriptFontFamily = complexScriptFontFamily;
371
+ if (complexScriptFontFamily) {
372
+ result.complexScriptFontFamily = complexScriptFontFamily;
373
+ const alternate = getFontAlternate(complexScriptFontFamily, fontAlternates);
374
+ if (alternate) result.complexScriptAlternateFontFamily = alternate;
375
+ }
344
376
  if (defaultTextFormatting.language) result.language = { ...defaultTextFormatting.language };
345
377
  if (defaultTextFormatting.fontSize !== void 0) result.fontSize = defaultTextFormatting.fontSize / 2;
346
378
  if (defaultTextFormatting.fontSizeCs !== void 0) result.complexScriptFontSize = defaultTextFormatting.fontSizeCs / 2;
@@ -369,7 +401,8 @@ function textFormattingToRunFormatting(defaultTextFormatting, theme) {
369
401
  if (defaultTextFormatting.smallCaps !== void 0) result.smallCaps = defaultTextFormatting.smallCaps;
370
402
  if (defaultTextFormatting.spacing !== void 0 && defaultTextFormatting.spacing !== 0) result.letterSpacing = twipsToPixels(defaultTextFormatting.spacing);
371
403
  if (defaultTextFormatting.position !== void 0 && defaultTextFormatting.position !== 0) result.positionPx = halfPointsToPixels(defaultTextFormatting.position);
372
- if (defaultTextFormatting.scale !== void 0 && defaultTextFormatting.scale !== 100) result.horizontalScale = defaultTextFormatting.scale;
404
+ const horizontalScale = normalizeHorizontalScalePercent(defaultTextFormatting.scale);
405
+ if (horizontalScale !== void 0 && horizontalScale !== 100) result.horizontalScale = horizontalScale;
373
406
  if (defaultTextFormatting.kerning !== void 0 && defaultTextFormatting.kerning > 0) result.kerningMinPt = halfPointsToPoints(defaultTextFormatting.kerning);
374
407
  if (defaultTextFormatting.emboss !== void 0) result.emboss = defaultTextFormatting.emboss;
375
408
  if (defaultTextFormatting.imprint !== void 0) result.imprint = defaultTextFormatting.imprint;
@@ -378,8 +411,8 @@ function textFormattingToRunFormatting(defaultTextFormatting, theme) {
378
411
  if (defaultTextFormatting.emphasisMark && defaultTextFormatting.emphasisMark !== "none") result.emphasisMark = defaultTextFormatting.emphasisMark;
379
412
  return result;
380
413
  }
381
- function paragraphRunDefaults(pmAttrs, theme) {
382
- return textFormattingToRunFormatting(pmAttrs.defaultTextFormatting, theme);
414
+ function paragraphRunDefaults(pmAttrs, theme, fontAlternates) {
415
+ return textFormattingToRunFormatting(pmAttrs.defaultTextFormatting, theme, fontAlternates);
383
416
  }
384
417
  /**
385
418
  * Build an ImageRun from ProseMirror node attrs, applying conditional property assignment
@@ -443,8 +476,9 @@ function paragraphToRuns(node, startPos, _options) {
443
476
  const runs = [];
444
477
  const offset = startPos + 1;
445
478
  const theme = _options.theme;
479
+ const fontAlternates = _options.fontAlternates;
446
480
  const pmAttrs = expectParagraphAttrs(node);
447
- const paraDefaults = paragraphRunDefaults(pmAttrs, theme);
481
+ const paraDefaults = paragraphRunDefaults(pmAttrs, theme, fontAlternates);
448
482
  const paragraphStyleId = pmAttrs.styleId;
449
483
  const inTocParagraph = pmAttrs._tableOfContentsLevel !== void 0 || tableOfContentsStyleLevel({ styleId: paragraphStyleId }) !== void 0;
450
484
  let leadingRenderedPageBreakPending = pmAttrs.renderedPageBreakBefore === true;
@@ -464,7 +498,7 @@ function paragraphToRuns(node, startPos, _options) {
464
498
  }
465
499
  if (child.type.name !== "sdt") leadingRenderedPageBreakPending = false;
466
500
  if (child.isText && child.text) {
467
- const formatting = extractRunFormatting(child.marks, theme);
501
+ const formatting = extractRunFormatting(child.marks, theme, fontAlternates);
468
502
  applyCharacterStyleToggleFormatting({
469
503
  formatting,
470
504
  marks: child.marks,
@@ -485,18 +519,20 @@ function paragraphToRuns(node, startPos, _options) {
485
519
  const attrs = expectSymbolAttrs(child);
486
520
  const text = decodeOoxmlSymbolCharacter(attrs.char);
487
521
  if (text === null) return;
488
- const formatting = extractRunFormatting(child.marks, theme);
522
+ const formatting = extractRunFormatting(child.marks, theme, fontAlternates);
489
523
  applyCharacterStyleToggleFormatting({
490
524
  formatting,
491
525
  marks: child.marks,
492
526
  paraDefaults
493
527
  });
494
528
  if (inTocParagraph) stripTocHyperlinkStyle(formatting);
529
+ const alternateFontFamily = getFontAlternate(attrs.font, fontAlternates);
530
+ formatting.fontFamily = attrs.font;
531
+ if (alternateFontFamily) formatting.alternateFontFamily = alternateFontFamily;
495
532
  runs.push({
496
533
  kind: "text",
497
534
  text,
498
535
  ...mergeRunFormatting(paraDefaults, formatting),
499
- fontFamily: attrs.font,
500
536
  pmStart: childPos,
501
537
  pmEnd: childPos + child.nodeSize
502
538
  });
@@ -511,7 +547,7 @@ function paragraphToRuns(node, startPos, _options) {
511
547
  return;
512
548
  }
513
549
  if (child.type.name === "tab") {
514
- const formatting = extractRunFormatting(child.marks, theme);
550
+ const formatting = extractRunFormatting(child.marks, theme, fontAlternates);
515
551
  applyCharacterStyleToggleFormatting({
516
552
  formatting,
517
553
  marks: child.marks,
@@ -530,7 +566,7 @@ function paragraphToRuns(node, startPos, _options) {
530
566
  const attrs = expectImageAttrs(child);
531
567
  if (!attrs.src) return;
532
568
  const constrained = constrainImageToPage(attrs.width ?? 100, attrs.height ?? 100, _options.pageContentHeight);
533
- const trackedFmt = extractRunFormatting(child.marks, theme);
569
+ const trackedFmt = extractRunFormatting(child.marks, theme, fontAlternates);
534
570
  const run = buildImageRun(attrs, constrained, childPos, childPos + child.nodeSize, trackedFmt);
535
571
  runs.push(run);
536
572
  return;
@@ -543,7 +579,7 @@ function paragraphToRuns(node, startPos, _options) {
543
579
  else if (ft === "NUMPAGES") mappedType = "NUMPAGES";
544
580
  else if (ft === "DATE") mappedType = "DATE";
545
581
  else if (ft === "TIME") mappedType = "TIME";
546
- const extractedFieldFormatting = extractRunFormatting(child.marks, theme);
582
+ const extractedFieldFormatting = extractRunFormatting(child.marks, theme, fontAlternates);
547
583
  applyCharacterStyleToggleFormatting({
548
584
  formatting: extractedFieldFormatting,
549
585
  marks: child.marks,
@@ -655,7 +691,7 @@ function resolveDeletedListMarker(previousListAttrs, listCounterState) {
655
691
  if (previousListAttrs.listIsBullet) return "•";
656
692
  return null;
657
693
  }
658
- function applyDeletedListMarkerAttrs(attrs, change, listCounterState, theme) {
694
+ function applyDeletedListMarkerAttrs(attrs, change, listCounterState, theme, fontAlternates) {
659
695
  const previousListAttrs = toPreviousListAttrs(change.previousFormatting);
660
696
  const marker = resolveDeletedListMarker(previousListAttrs, listCounterState);
661
697
  if (!marker) return;
@@ -663,11 +699,11 @@ function applyDeletedListMarkerAttrs(attrs, change, listCounterState, theme) {
663
699
  attrs.listMarkerRevision = toListMarkerRevision("del", change.info);
664
700
  if (previousListAttrs.listIsBullet !== void 0) attrs.listIsBullet = previousListAttrs.listIsBullet;
665
701
  if (previousListAttrs.listMarkerHidden !== void 0) attrs.listMarkerHidden = previousListAttrs.listMarkerHidden;
666
- if (previousListAttrs.listMarkerFormatting) attrs.listMarkerFormatting = textFormattingToRunFormatting(previousListAttrs.listMarkerFormatting, theme);
702
+ if (previousListAttrs.listMarkerFormatting) attrs.listMarkerFormatting = textFormattingToRunFormatting(previousListAttrs.listMarkerFormatting, theme, fontAlternates);
667
703
  if (previousListAttrs.listMarkerAlignment) attrs.listMarkerAlignment = previousListAttrs.listMarkerAlignment;
668
704
  if (previousListAttrs.listMarkerSuffix) attrs.listMarkerSuffix = previousListAttrs.listMarkerSuffix;
669
705
  }
670
- function convertParagraphAttrs(pmAttrs, { theme, listCounterStreams, defaultTabStopTwips }) {
706
+ function convertParagraphAttrs(pmAttrs, { theme, fontAlternates, listCounterStreams, defaultTabStopTwips }) {
671
707
  const attrs = {};
672
708
  if (pmAttrs.alignment) {
673
709
  const align = pmAttrs.alignment;
@@ -791,14 +827,14 @@ function convertParagraphAttrs(pmAttrs, { theme, listCounterStreams, defaultTabS
791
827
  else if (pmAttrs.listMarker) attrs.listMarker = pmAttrs.listIsBullet ? convertBulletToUnicode(pmAttrs.listMarker) : pmAttrs.listMarker;
792
828
  if (pmAttrs.listIsBullet !== void 0) attrs.listIsBullet = pmAttrs.listIsBullet;
793
829
  if (pmAttrs.listMarkerHidden) attrs.listMarkerHidden = true;
794
- if (pmAttrs.listMarkerFormatting) attrs.listMarkerFormatting = textFormattingToRunFormatting(pmAttrs.listMarkerFormatting, theme);
830
+ if (pmAttrs.listMarkerFormatting) attrs.listMarkerFormatting = textFormattingToRunFormatting(pmAttrs.listMarkerFormatting, theme, fontAlternates);
795
831
  if (pmAttrs.listMarkerAlignment) attrs.listMarkerAlignment = pmAttrs.listMarkerAlignment;
796
832
  if (pmAttrs.listMarkerSuffix) attrs.listMarkerSuffix = pmAttrs.listMarkerSuffix;
797
833
  if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
798
834
  if (!pmAttrs.numPr) {
799
835
  const numberingRemovedChange = propertyChanges.find(isRemovedNumberingChange);
800
836
  if (numberingRemovedChange) {
801
- applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, void 0, theme);
837
+ applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, void 0, theme, fontAlternates);
802
838
  if (resolvedMarker !== null) {
803
839
  attrs.listMarker = resolvedMarker;
804
840
  attrs.listMarkerRevision = toListMarkerRevision("del", numberingRemovedChange.info);
@@ -812,7 +848,11 @@ function convertParagraphAttrs(pmAttrs, { theme, listCounterStreams, defaultTabS
812
848
  if (attrs.listMarker !== void 0 && !attrs.listMarkerHidden && dtf.fontSizeCs !== void 0 && (dtf.fontSize === void 0 || dtf.fontSizeCs > dtf.fontSize)) attrs.listParagraphMarkFontSize = dtf.fontSizeCs / 2;
813
849
  if (dtf.fontFamily) {
814
850
  const resolvedFamily = resolveWesternThemeFont(dtf.fontFamily, theme);
815
- if (resolvedFamily) attrs.defaultFontFamily = resolvedFamily;
851
+ if (resolvedFamily) {
852
+ attrs.defaultFontFamily = resolvedFamily;
853
+ const alternate = getFontAlternate(resolvedFamily, fontAlternates);
854
+ if (alternate) attrs.defaultAlternateFontFamily = alternate;
855
+ }
816
856
  }
817
857
  }
818
858
  return attrs;
@@ -843,6 +883,7 @@ function convertParagraph(node, startPos, options) {
843
883
  const runs = paragraphToRuns(node, startPos, options);
844
884
  const attrs = convertParagraphAttrs(pmAttrs, {
845
885
  theme: options.theme,
886
+ fontAlternates: options.fontAlternates,
846
887
  listCounterStreams: options.listCounterStreams,
847
888
  defaultTabStopTwips: options.defaultTabStopTwips
848
889
  });
@@ -856,7 +897,11 @@ function convertParagraph(node, startPos, options) {
856
897
  if (paragraphMarkFormatting && Object.values(paragraphMarkFormatting).some((value) => value !== void 0 && value !== null)) attrs.hasDirectParagraphMarkFormatting = true;
857
898
  if (paragraphMarkFormatting?.fontSize !== void 0) attrs.defaultFontSize = paragraphMarkFormatting.fontSize / 2;
858
899
  const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily ? resolveWesternThemeFont(paragraphMarkFormatting.fontFamily, options.theme) : void 0;
859
- if (paragraphMarkFontFamily) attrs.defaultFontFamily = paragraphMarkFontFamily;
900
+ if (paragraphMarkFontFamily) {
901
+ attrs.defaultFontFamily = paragraphMarkFontFamily;
902
+ const alternate = getFontAlternate(paragraphMarkFontFamily, options.fontAlternates);
903
+ if (alternate) attrs.defaultAlternateFontFamily = alternate;
904
+ }
860
905
  }
861
906
  if (runs.length === 0 && defaultTextFormatting?.hidden === true) {
862
907
  attrs.suppressEmptyParagraphHeight = true;
@@ -1076,6 +1121,8 @@ function convertTableRow(node, startPos, options, tableCellMargins) {
1076
1121
  if (attrs.isHeader) row.isHeader = attrs.isHeader;
1077
1122
  if (attrs._originalFormatting?.cantSplit) row.cantSplit = true;
1078
1123
  if (attrs.hidden) row.hidden = attrs.hidden;
1124
+ const effectiveJustification = attrs._originalFormatting?.justification ?? attrs._resolvedJustification;
1125
+ if (effectiveJustification) row.justification = effectiveJustification;
1079
1126
  return row;
1080
1127
  }
1081
1128
  /**
@@ -1097,7 +1144,7 @@ function convertTable(node, startPos, options) {
1097
1144
  const cellWidths = rows[0].cells.map((cell) => cell.width);
1098
1145
  if (cellWidths.every((w) => w !== void 0 && w > 0)) columnWidths = cellWidths;
1099
1146
  }
1100
- const justification = attrs.justification;
1147
+ const justification = attrs.justification ?? attrs._resolvedJustification;
1101
1148
  const originalFormatting = attrs._originalFormatting;
1102
1149
  const effectiveIndent = attrs._resolvedIndent ?? originalFormatting?.indent;
1103
1150
  const indentPx = effectiveIndent?.value !== void 0 && effectiveIndent?.type === "dxa" ? twipsToPixels(effectiveIndent.value) : void 0;
@@ -1201,6 +1248,8 @@ function convertTextBoxNode(node, startPos, opts) {
1201
1248
  pmStart: startPos,
1202
1249
  pmEnd: startPos + node.nodeSize
1203
1250
  };
1251
+ const verticalAlign = normalizeShapeTextAnchor(attrs.verticalAlign);
1252
+ if (verticalAlign !== void 0) textBox.verticalAlign = verticalAlign;
1204
1253
  if (attrs.height !== void 0) textBox.height = attrs.height;
1205
1254
  if (attrs.autoFit !== void 0) textBox.autoFit = attrs.autoFit;
1206
1255
  if (attrs.textWrap !== void 0) textBox.textWrap = attrs.textWrap;
@@ -1416,7 +1465,8 @@ function toFlowBlocks(doc, options = {}) {
1416
1465
  ...sourceAttrs?.snapToGrid !== void 0 ? { snapToGrid: sourceAttrs.snapToGrid } : {},
1417
1466
  ...sourceAttrs?.documentGridLinePitch !== void 0 ? { documentGridLinePitch: sourceAttrs.documentGridLinePitch } : {},
1418
1467
  ...sourceAttrs?.defaultFontSize !== void 0 ? { defaultFontSize: sourceAttrs.defaultFontSize } : {},
1419
- ...sourceAttrs?.defaultFontFamily !== void 0 ? { defaultFontFamily: sourceAttrs.defaultFontFamily } : {}
1468
+ ...sourceAttrs?.defaultFontFamily !== void 0 ? { defaultFontFamily: sourceAttrs.defaultFontFamily } : {},
1469
+ ...sourceAttrs?.defaultAlternateFontFamily !== void 0 ? { defaultAlternateFontFamily: sourceAttrs.defaultAlternateFontFamily } : {}
1420
1470
  };
1421
1471
  const carrier = {
1422
1472
  kind: "paragraph",
@@ -1,4 +1,4 @@
1
- import { NoteStoryKey } from "../../controller/noteEditorManager.js";
1
+ import { NoteStoryKey } from "../../types/editor-story.js";
2
2
  //#region src/layout-bridge/dom/noteStoryDom.d.ts
3
3
  declare const findNoteStoryForTarget: (target: unknown) => NoteStoryKey | null;
4
4
  //#endregion
@@ -6,6 +6,7 @@ import { measureRun } from "../../layout-engine/measure/measureProvider.js";
6
6
  import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../../layout-engine/measure/tableCellFloating.js";
7
7
  import { buildTableCellGrid, buildTableCellPlacements } from "../../layout-engine/measure/tableCellGrid.js";
8
8
  import { resolveTableCellPadding } from "../../layout-engine/types.js";
9
+ import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
9
10
  import { resolvePhysicalParagraphInlineLayout } from "../../utils/paragraphInlineLayout.js";
10
11
  import { inlineImageBoundingBox } from "../../utils/rotationBoundingBox.js";
11
12
  import { getPageTop } from "./hitTest.js";
@@ -33,13 +34,14 @@ function runToFontStyle(run) {
33
34
  return buildRunFontStyle(run, "Arial", 12);
34
35
  }
35
36
  function mathRunToFontStyle(run) {
37
+ const horizontalScale = normalizeHorizontalScalePercent(run.horizontalScale);
36
38
  return {
37
39
  fontFamily: run.fontFamily ?? "Cambria Math",
38
40
  fontSize: run.fontSize ?? 11,
39
41
  ...run.bold !== void 0 ? { bold: run.bold } : {},
40
42
  ...run.italic !== void 0 ? { italic: run.italic } : {},
41
43
  ...run.letterSpacing !== void 0 ? { letterSpacing: run.letterSpacing } : {},
42
- ...run.horizontalScale !== void 0 ? { horizontalScale: run.horizontalScale } : {}
44
+ ...horizontalScale !== void 0 ? { horizontalScale } : {}
43
45
  };
44
46
  }
45
47
  /**