@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.
- package/README.md +23 -1
- package/dist/ai-edits/apply.js +139 -32
- package/dist/ai-edits/headless.d.ts +3 -0
- package/dist/ai-edits/headless.js +57 -63
- package/dist/ai-edits/note-story-inventory.d.ts +7 -0
- package/dist/ai-edits/note-story-inventory.js +11 -0
- package/dist/ai-edits/read.js +16 -9
- package/dist/ai-edits/revisionStretches.js +52 -1
- package/dist/ai-edits/table-row-column-mutations.js +6 -1
- package/dist/compare/reproducible-package.js +2 -1
- package/dist/compare/verification.js +1 -0
- package/dist/compat/eigenpal.d.ts +4 -2
- package/dist/compat/eigenpal.js +2 -2
- package/dist/controller/canonicalClipboard.js +2 -1
- package/dist/controller/canonicalListRendering.d.ts +4 -6
- package/dist/controller/canonicalListRendering.js +3 -157
- package/dist/controller/canonicalSession.js +3 -2
- package/dist/controller/canonicalStructure.js +10 -7
- package/dist/controller/fontReadiness.js +1 -1
- package/dist/controller/headerFooterEditorManager.d.ts +1 -0
- package/dist/controller/headerFooterEditorManager.js +11 -0
- package/dist/controller/hiddenEditorManager.d.ts +1 -1
- package/dist/controller/hiddenEditorManager.js +3 -1
- package/dist/controller/layoutPipeline.d.ts +3 -1
- package/dist/controller/layoutPipeline.js +19 -4
- package/dist/controller/layoutSession.d.ts +4 -1
- package/dist/display-list/build/fontTable.js +7 -5
- package/dist/display-list/build/furniture.d.ts +1 -0
- package/dist/display-list/build/furniture.js +1 -0
- package/dist/display-list/build/imagePrimitives.js +3 -6
- package/dist/display-list/build/watermarkPrimitives.d.ts +2 -1
- package/dist/display-list/build/watermarkPrimitives.js +9 -3
- package/dist/display-list/editor/pageRenderer.js +1 -0
- package/dist/docx/bookmarkIdNormalization.d.ts +10 -0
- package/dist/docx/bookmarkIdNormalization.js +100 -0
- package/dist/docx/bookmarkParser.js +4 -2
- package/dist/docx/canonicalStoryRepack.js +3 -2
- package/dist/docx/commentTextParagraph.d.ts +6 -0
- package/dist/docx/commentTextParagraph.js +15 -0
- package/dist/docx/conformance.js +6 -1
- package/dist/docx/diagramPreview.js +2 -1
- package/dist/docx/documentParser.d.ts +13 -1
- package/dist/docx/documentParser.js +1 -1
- package/dist/docx/encryption/compoundFile.d.ts +0 -8
- package/dist/docx/encryption/compoundFile.js +2 -1
- package/dist/docx/encryption/cryptoBytes.d.ts +2 -2
- package/dist/docx/encryption/cryptoBytes.js +3 -18
- package/dist/docx/encryption/encryptionInfo.d.ts +0 -5
- package/dist/docx/encryption/encryptionInfo.js +2 -1
- package/dist/docx/ensureParaIds.js +2 -1
- package/dist/docx/groupDrawingParser.js +6 -1
- package/dist/docx/importedIdCollisions.d.ts +136 -0
- package/dist/docx/importedIdCollisions.js +215 -0
- package/dist/docx/listModelNormalization.d.ts +10 -0
- package/dist/docx/listModelNormalization.js +166 -0
- package/dist/docx/metadataPrivacy.js +3 -2
- package/dist/docx/metafileRaster.js +2 -1
- package/dist/docx/numberingParser.js +2 -2
- package/dist/docx/packageParts.js +6 -5
- package/dist/docx/paragraphParser.js +6 -4
- package/dist/docx/paragraphPropertySource.js +1 -2
- package/dist/docx/parseContext.d.ts +2 -1
- package/dist/docx/parseContext.js +1 -0
- package/dist/docx/parseWarningMessage.js +1 -0
- package/dist/docx/parser.js +10 -5
- package/dist/docx/preservedRunContent.js +11 -2
- package/dist/docx/relsParser.js +1 -1
- package/dist/docx/removeHeaderFooterParts.js +8 -7
- package/dist/docx/replyToComment.js +3 -13
- package/dist/docx/rezip.js +90 -90
- package/dist/docx/runParser.js +12 -6
- package/dist/docx/runPropertyPresence.d.ts +11 -0
- package/dist/docx/runPropertyPresence.js +14 -0
- package/dist/docx/selectedXmlIdentityScan.d.ts +10 -0
- package/dist/docx/selectedXmlIdentityScan.js +36 -0
- package/dist/docx/selectiveSave.js +19 -17
- package/dist/docx/selectiveXmlPatch.js +44 -52
- package/dist/docx/serializer/commentSerializer.d.ts +3 -1
- package/dist/docx/serializer/commentSerializer.js +11 -2
- package/dist/docx/serializer/runSerializer.js +5 -4
- package/dist/docx/serializer/tableSerializer.js +2 -1
- package/dist/docx/serializer/trackedChangeAttributes.d.ts +1 -3
- package/dist/docx/serializer/trackedChangeAttributes.js +1 -11
- package/dist/docx/server/applyDocxXmlPatchProposal.js +2 -2
- package/dist/docx/server/boundedArchive.js +2 -1
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +2 -1
- package/dist/docx/server/inspectDocxPackage.js +5 -1
- package/dist/docx/server/validateDocxConformance.js +2 -1
- package/dist/docx/tableParser.js +7 -4
- package/dist/docx/tableRowPropertyPresence.d.ts +9 -0
- package/dist/docx/tableRowPropertyPresence.js +15 -0
- package/dist/docx/unzip.js +2 -1
- package/dist/docx/xmlEncoding.js +6 -5
- package/dist/fonts/embeddedFontFingerprint.d.ts +5 -0
- package/dist/fonts/embeddedFontFingerprint.js +18 -0
- package/dist/fonts/embeddedFonts.d.ts +1 -1
- package/dist/fonts/embeddedFonts.js +1 -1
- package/dist/fonts/fontsourceFaces.js +2 -1
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/fonts/sfnt/parse.js +6 -9
- package/dist/fonts/sfnt/subset.js +2 -1
- package/dist/fonts/sfnt/tables.js +2 -3
- package/dist/fonts/sfnt/woff.js +2 -1
- package/dist/headless-layout.js +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -2
- package/dist/internal/revisionResolutionInline.d.ts +2 -1
- package/dist/internal/revisionResolutionInline.js +22 -1
- package/dist/internal/wholeStoryRevisionResolution.js +24 -7
- package/dist/layout-bridge/convert/flowConversionShared.d.ts +4 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +5 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +16 -3
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +6 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +13 -14
- package/dist/layout-bridge/convert/paragraphConversion.js +8 -1
- package/dist/layout-bridge/convert/paragraphRuns.js +2 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +25 -1
- package/dist/layout-engine/measure/cache.js +39 -7
- package/dist/layout-engine/measure/crossRunWords.js +12 -2
- package/dist/layout-engine/measure/lineTypography.js +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +1 -0
- package/dist/layout-engine/measure/measureContainer.js +3 -4
- package/dist/layout-engine/measure/measureHelpers.d.ts +6 -9
- package/dist/layout-engine/measure/measureHelpers.js +21 -18
- package/dist/layout-engine/measure/measureParagraph.js +2 -0
- package/dist/layout-engine/measure/measureTypes.d.ts +2 -0
- package/dist/layout-engine/types.d.ts +4 -1
- package/dist/layout-painter/renderPage.d.ts +1 -0
- package/dist/layout-painter/renderPage.js +11 -3
- package/dist/layout-painter/renderParagraph.js +13 -3
- package/dist/layout-painter/renderWatermark.d.ts +1 -0
- package/dist/layout-painter/renderWatermark.js +7 -3
- package/dist/managers/AutoSaveManager.js +2 -1
- package/dist/managers/EditorModeManager.d.ts +10 -1
- package/dist/managers/EditorModeManager.js +15 -1
- package/dist/managers/TableSelectionManager.d.ts +1 -1
- package/dist/managers/autoSaveCodec.js +2 -6
- package/dist/managers/editorShortcuts.d.ts +2 -1
- package/dist/managers/editorShortcuts.js +2 -1
- package/dist/managers/reviewDisplayMode.d.ts +8 -0
- package/dist/managers/reviewDisplayMode.js +15 -0
- package/dist/paged-layout/pageText.d.ts +11 -2
- package/dist/paged-layout/pageText.js +8 -3
- package/dist/pdf/fonts.js +5 -14
- package/dist/pdf/images.js +3 -2
- package/dist/pdf/objects.d.ts +0 -11
- package/dist/pdf/objects.js +7 -9
- package/dist/pdf/writePdf.js +2 -1
- package/dist/prosemirror/canonicalSelectionRange.d.ts +4 -1
- package/dist/prosemirror/canonicalSelectionRange.js +9 -3
- package/dist/prosemirror/commands/comments.js +51 -13
- package/dist/prosemirror/containerFinalParagraph.d.ts +8 -8
- package/dist/prosemirror/containerFinalParagraph.js +8 -8
- package/dist/prosemirror/conversion/fromProseDoc.js +9 -4
- package/dist/prosemirror/conversion/toProseDoc.js +4 -4
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +8 -2
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +39 -3
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.d.ts +8 -2
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +4 -3
- package/dist/prosemirror/extensions/features/ImageDragExtension.js +4 -3
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +4 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +9 -3
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +6 -5
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +8 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +11 -3
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/markUtils.js +1 -1
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +16 -2
- package/dist/prosemirror/findReplaceSelection.d.ts +11 -1
- package/dist/prosemirror/findReplaceSelection.js +15 -1
- package/dist/prosemirror/markupViewProjection.d.ts +10 -1
- package/dist/prosemirror/markupViewProjection.js +21 -3
- package/dist/prosemirror/pluginKeyOwner.d.ts +13 -0
- package/dist/prosemirror/pluginKeyOwner.js +35 -0
- package/dist/prosemirror/plugins/aiCitationDecorations.d.ts +11 -4
- package/dist/prosemirror/plugins/aiCitationDecorations.js +16 -3
- package/dist/prosemirror/plugins/aiSuggestionDecorations.d.ts +11 -4
- package/dist/prosemirror/plugins/aiSuggestionDecorations.js +18 -3
- package/dist/prosemirror/plugins/anonymizationDecorations.d.ts +11 -11
- package/dist/prosemirror/plugins/anonymizationDecorations.js +23 -13
- package/dist/prosemirror/plugins/autocompleteSuggestion.d.ts +8 -2
- package/dist/prosemirror/plugins/autocompleteSuggestion.js +27 -5
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +8 -2
- package/dist/prosemirror/plugins/contentControlWidgets.js +4 -3
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +6 -5
- package/dist/prosemirror/plugins/createDocScanPlugin.js +1 -1
- package/dist/prosemirror/plugins/documentNumbering.js +5 -3
- package/dist/prosemirror/plugins/documentStyleState.d.ts +8 -2
- package/dist/prosemirror/plugins/documentStyleState.js +2 -2
- package/dist/prosemirror/plugins/documentStyles.js +1 -1
- package/dist/prosemirror/plugins/selectionTracker.d.ts +8 -2
- package/dist/prosemirror/plugins/selectionTracker.js +4 -3
- package/dist/prosemirror/plugins/suggestionMode.d.ts +8 -2
- package/dist/prosemirror/plugins/suggestionMode.js +4 -3
- package/dist/prosemirror/plugins/templateDirectives.d.ts +8 -2
- package/dist/prosemirror/plugins/templateDirectives.js +19 -4
- package/dist/prosemirror/plugins/templatePreviewValues.d.ts +8 -2
- package/dist/prosemirror/plugins/templatePreviewValues.js +27 -5
- package/dist/prosemirror/plugins/templateSlashMenu.d.ts +8 -2
- package/dist/prosemirror/plugins/templateSlashMenu.js +23 -5
- package/dist/prosemirror/plugins/transactionInvariants.js +29 -4
- package/dist/prosemirror/replacedAnnotations.d.ts +15 -1
- package/dist/prosemirror/replacedAnnotations.js +71 -12
- package/dist/prosemirror/runFormattingReconciliation.d.ts +3 -1
- package/dist/prosemirror/runFormattingReconciliation.js +10 -2
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +5 -7
- package/dist/prosemirror/runIdentityAcrossRevisions.js +66 -38
- package/dist/prosemirror/runPropertyChangeResolution.js +13 -1
- package/dist/utils/base64.d.ts +1 -31
- package/dist/utils/base64.js +19 -33
- package/dist/utils/clipboard.js +5 -4
- package/dist/utils/colorResolver.js +11 -2
- package/dist/utils/findReplace.d.ts +5 -0
- package/dist/utils/fontLoader.d.ts +2 -2
- package/dist/utils/fontLoader.js +2 -7
- package/dist/utils/fontResolver.d.ts +7 -3
- package/dist/utils/fontResolver.js +6 -8
- package/dist/utils/replaceText.js +21 -4
- package/dist/utils/sliceText.d.ts +2 -0
- package/dist/utils/sliceText.js +2 -0
- package/dist/utils/textEncoding.d.ts +2 -0
- package/dist/utils/textEncoding.js +2 -0
- package/dist/utils/tiffConverter.d.ts +0 -9
- package/dist/utils/tiffConverter.js +2 -4
- package/package.json +73 -31
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { cloneParagraphWithPropertySource } from "../../docx/paragraphPropertySource.js";
|
|
2
2
|
import { isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun } from "../../layout-engine/types.js";
|
|
3
3
|
import { headerFooterToProseDoc } from "../../prosemirror/conversion/toProseDoc.js";
|
|
4
|
+
import { projectStoryMarkupView } from "../../prosemirror/markupViewProjection.js";
|
|
4
5
|
import { emuToPixels } from "../../utils/units.js";
|
|
6
|
+
import { remapMarkupViewBlocks } from "./markupViewFlow.js";
|
|
5
7
|
import { toFlowBlocks } from "./toFlowBlocks.js";
|
|
6
8
|
//#region src/layout-bridge/convert/headerFooterLayout.ts
|
|
7
9
|
const DETACHED_WATERMARK_HOST = Symbol.for("stll.detachedWatermarkHost");
|
|
@@ -341,18 +343,7 @@ function convertHeaderFooterToContent(headerFooter, contentWidth, metrics, optio
|
|
|
341
343
|
if (options.styles) proseDocOptions.styles = options.styles;
|
|
342
344
|
if (options.theme !== void 0) proseDocOptions.theme = options.theme;
|
|
343
345
|
if (options.numbering !== void 0) proseDocOptions.numbering = options.numbering;
|
|
344
|
-
|
|
345
|
-
const flowOptions = {};
|
|
346
|
-
if (options.defaultSize !== void 0) flowOptions.defaultSize = options.defaultSize;
|
|
347
|
-
if (options.styles) flowOptions.styles = options.styles;
|
|
348
|
-
if (options.theme !== void 0) flowOptions.theme = options.theme;
|
|
349
|
-
if (options.fontAlternates !== void 0) flowOptions.fontAlternates = options.fontAlternates;
|
|
350
|
-
if (options.defaultTabStopTwips !== void 0) flowOptions.defaultTabStopTwips = options.defaultTabStopTwips;
|
|
351
|
-
if (options.lineBreakRules) flowOptions.lineBreakRules = options.lineBreakRules;
|
|
352
|
-
if (options.justificationCompatibility) flowOptions.justificationCompatibility = options.justificationCompatibility;
|
|
353
|
-
if (options.tableIndentCompatibility) flowOptions.tableIndentCompatibility = options.tableIndentCompatibility;
|
|
354
|
-
if (options.automaticHyphenation) flowOptions.automaticHyphenation = options.automaticHyphenation;
|
|
355
|
-
return finalizeHeaderFooterContent(toFlowBlocks(pmDoc, flowOptions), contentWidth, metrics, options);
|
|
346
|
+
return convertHeaderFooterPmDocToContent(headerFooter.watermarkBlockIndex === void 0 ? headerFooterToProseDoc(headerFooter.content, proseDocOptions) : headerFooterToProseDocWithDetachedWatermarkHost(headerFooter, proseDocOptions), contentWidth, metrics, options);
|
|
356
347
|
}
|
|
357
348
|
/**
|
|
358
349
|
* Same as {@link convertHeaderFooterToContent}, but sourced from a live
|
|
@@ -367,17 +358,25 @@ function convertHeaderFooterToContent(headerFooter, contentWidth, metrics, optio
|
|
|
367
358
|
*/
|
|
368
359
|
function convertHeaderFooterPmDocToContent(pmDoc, contentWidth, metrics, options) {
|
|
369
360
|
if (!pmDoc || pmDoc.content.size === 0) return;
|
|
370
|
-
const flowOptions = {};
|
|
361
|
+
const flowOptions = { showCommentHighlights: options.showCommentHighlights !== false && options.markupView !== "no-markup" && options.markupView !== "original" };
|
|
371
362
|
if (options.defaultSize !== void 0) flowOptions.defaultSize = options.defaultSize;
|
|
372
363
|
if (options.styles) flowOptions.styles = options.styles;
|
|
373
364
|
if (options.theme !== void 0) flowOptions.theme = options.theme;
|
|
365
|
+
if (options.embeddedFontFamilyMap !== void 0) flowOptions.embeddedFontFamilyMap = options.embeddedFontFamilyMap;
|
|
374
366
|
if (options.fontAlternates !== void 0) flowOptions.fontAlternates = options.fontAlternates;
|
|
375
367
|
if (options.defaultTabStopTwips !== void 0) flowOptions.defaultTabStopTwips = options.defaultTabStopTwips;
|
|
376
368
|
if (options.lineBreakRules) flowOptions.lineBreakRules = options.lineBreakRules;
|
|
377
369
|
if (options.justificationCompatibility) flowOptions.justificationCompatibility = options.justificationCompatibility;
|
|
378
370
|
if (options.tableIndentCompatibility) flowOptions.tableIndentCompatibility = options.tableIndentCompatibility;
|
|
379
371
|
if (options.automaticHyphenation) flowOptions.automaticHyphenation = options.automaticHyphenation;
|
|
380
|
-
|
|
372
|
+
const projection = projectStoryMarkupView({
|
|
373
|
+
doc: pmDoc,
|
|
374
|
+
markupView: options.markupView ?? "all-markup",
|
|
375
|
+
styles: options.styles,
|
|
376
|
+
numbering: options.numbering
|
|
377
|
+
});
|
|
378
|
+
const flowBlocks = toFlowBlocks(projection.type === "resolved" ? projection.doc : pmDoc, flowOptions);
|
|
379
|
+
return finalizeHeaderFooterContent(projection.type === "resolved" ? remapMarkupViewBlocks(flowBlocks, projection) : flowBlocks, contentWidth, metrics, options);
|
|
381
380
|
}
|
|
382
381
|
function horizontalImageLeft({ run, contentWidth, metrics }) {
|
|
383
382
|
const horizontal = run.position?.horizontal;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getFontAlternate } from "../../fonts/fontAlternates.js";
|
|
2
2
|
import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
|
|
3
3
|
import { expectParagraphAttrs } from "../../prosemirror/attrs/index.js";
|
|
4
|
+
import { expectBookmarkBoundaryAttrs } from "../../prosemirror/bookmarkBoundaryAttrs.js";
|
|
4
5
|
import { expectTextBoxAnchorAttrs } from "../../prosemirror/textBoxAnchorAttrs.js";
|
|
5
6
|
import { nextBlockId, twipsToPixels } from "./flowConversionShared.js";
|
|
6
7
|
import { convertParagraphAttrs } from "./paragraphAttrs.js";
|
|
@@ -76,7 +77,13 @@ function convertParagraph(node, startPos, options, pageBreaks) {
|
|
|
76
77
|
if (isFullyHiddenParagraph) attrs.suppressEmptyParagraphHeight = true;
|
|
77
78
|
if (runs.length === 0 && expectDetachedWatermarkHostAttr(node.attrs)) attrs.suppressEmptyParagraphHeight = false;
|
|
78
79
|
if (runs.length === 0 && pmAttrs._pageBreakCarrier === true && !hasVisibleParagraphPayload(attrs)) attrs.suppressEmptyParagraphHeight = true;
|
|
79
|
-
const bookmarkNames = pmAttrs.bookmarks?.map((b) => b.name);
|
|
80
|
+
const bookmarkNames = pmAttrs.bookmarks?.map((b) => b.name) ?? [];
|
|
81
|
+
node.descendants((child) => {
|
|
82
|
+
if (child.type.name !== "bookmarkBoundary") return true;
|
|
83
|
+
const marker = expectBookmarkBoundaryAttrs(child);
|
|
84
|
+
if (marker.type === "start") bookmarkNames.push(marker.name);
|
|
85
|
+
return false;
|
|
86
|
+
});
|
|
80
87
|
const block = {
|
|
81
88
|
kind: "paragraph",
|
|
82
89
|
id: nextBlockId(),
|
|
@@ -58,7 +58,8 @@ function paragraphToRuns(node, startPos, _options, pageBreaks) {
|
|
|
58
58
|
});
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
const
|
|
61
|
+
const projectedMarks = mergeProjectedInlineMarks(inheritedMarks, child.marks);
|
|
62
|
+
const effectiveMarks = _options.showCommentHighlights === false ? projectedMarks.filter((mark) => mark.type.name !== "comment") : projectedMarks;
|
|
62
63
|
if (child.type.name === "pageBreakRun") {
|
|
63
64
|
const trackedChange = extractRunFormatting(effectiveMarks, theme, fontAlternates);
|
|
64
65
|
if (trackedChange.isDeletion) {
|
|
@@ -412,10 +412,34 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
412
412
|
}
|
|
413
413
|
const mergedBlocks = mergeRunInParagraphs(blocks);
|
|
414
414
|
const tableCellLinePitch = doc.attrs["_adjustLineHeightInTable"] === true ? "sectionGrid" : void 0;
|
|
415
|
-
|
|
415
|
+
const result = groupParagraphFrames(coalesceTrailingPageBreakBeforeContinuousSection(applySectionStartsToBoundaries(applySectionDocumentGrid(mergedBlocks, {
|
|
416
416
|
finalLinePitchTwips: opts.finalSectionDocumentGridLinePitchTwips,
|
|
417
417
|
tableCellLinePitch
|
|
418
418
|
}), readFinalSectionStart(doc)), options.splitPageBreakAndParagraphMark === true, sectionBreaksWithoutMarker), nextBlockId);
|
|
419
|
+
if (options.embeddedFontFamilyMap) attachEmbeddedFontFamilies(result, options.embeddedFontFamilyMap);
|
|
420
|
+
return result;
|
|
419
421
|
}
|
|
422
|
+
/** Attach editor-owned resolution to freshly derived blocks without changing authored data. */
|
|
423
|
+
const attachEmbeddedFontFamilies = (blocks, familyMap) => {
|
|
424
|
+
for (const block of blocks) switch (block.kind) {
|
|
425
|
+
case "paragraph":
|
|
426
|
+
for (const run of block.runs) if (run.kind !== "image" && run.kind !== "lineBreak") run.embeddedFontFamilyMap = familyMap;
|
|
427
|
+
block.attrs ??= {};
|
|
428
|
+
block.attrs.embeddedFontFamilyMap = familyMap;
|
|
429
|
+
if (block.attrs.listMarkerFormatting) block.attrs.listMarkerFormatting.embeddedFontFamilyMap = familyMap;
|
|
430
|
+
break;
|
|
431
|
+
case "table":
|
|
432
|
+
for (const row of block.rows) for (const cell of row.cells) attachEmbeddedFontFamilies(cell.blocks, familyMap);
|
|
433
|
+
break;
|
|
434
|
+
case "textBox":
|
|
435
|
+
attachEmbeddedFontFamilies(block.content, familyMap);
|
|
436
|
+
break;
|
|
437
|
+
case "image":
|
|
438
|
+
case "sectionBreak":
|
|
439
|
+
case "pageBreak":
|
|
440
|
+
case "columnBreak": break;
|
|
441
|
+
default: return block;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
420
444
|
//#endregion
|
|
421
445
|
export { WORD_UNSPECIFIED_FONT_SIZE, collectNoteRefs, convertBorderSpecToLayout, formatCounter, resetBlockIdCounter, resolveListTemplate, toFlowBlocks };
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
import { embeddedFontFingerprint } from "../../fonts/embeddedFontFingerprint.js";
|
|
1
2
|
import { getLineBreakProviderGeneration } from "./lineBreakProvider.js";
|
|
2
3
|
import { clearFontResolvedCache } from "./measureHelpers.js";
|
|
3
4
|
//#region src/layout-engine/measure/cache.ts
|
|
4
5
|
/**
|
|
6
|
+
* Measurement Cache
|
|
7
|
+
*
|
|
8
|
+
* LRU cache for text width measurements and paragraph layout results.
|
|
9
|
+
* Improves performance by avoiding repeated measurements of identical content.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
5
12
|
* Default max entries for text width cache
|
|
6
13
|
* Large documents (30+ pages) can generate 20,000+ unique text measurements.
|
|
7
14
|
* A generous default avoids cache thrashing on big docs.
|
|
@@ -176,21 +183,31 @@ const imageMeasureCacheInput = (run) => ({
|
|
|
176
183
|
exactLineHeight: run.exactLineHeight,
|
|
177
184
|
positioned: run.position !== void 0
|
|
178
185
|
});
|
|
179
|
-
const runMeasureCacheInput = (run) => {
|
|
186
|
+
const runMeasureCacheInput = (run, fontContextRef) => {
|
|
180
187
|
switch (run.kind) {
|
|
181
188
|
case "text":
|
|
182
189
|
case "tab":
|
|
183
|
-
case "lineBreak":
|
|
184
190
|
case "renderedPageBreak":
|
|
185
191
|
case "field":
|
|
186
|
-
case "math":
|
|
192
|
+
case "math": {
|
|
193
|
+
const { embeddedFontFamilyMap, ...formatting } = run;
|
|
194
|
+
return {
|
|
195
|
+
...formatting,
|
|
196
|
+
embeddedFontFamilies: fontContextRef(embeddedFontFamilyMap)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
case "lineBreak": return run;
|
|
187
200
|
case "image": return imageMeasureCacheInput(run);
|
|
188
201
|
default: return run;
|
|
189
202
|
}
|
|
190
203
|
};
|
|
191
|
-
const paragraphAttrsMeasureCacheInput = (attrs) => {
|
|
204
|
+
const paragraphAttrsMeasureCacheInput = (attrs, fontContextRef) => {
|
|
192
205
|
if (attrs === void 0) return void 0;
|
|
193
|
-
const { snapToGrid, ...
|
|
206
|
+
const { snapToGrid, embeddedFontFamilyMap, ...rest } = attrs;
|
|
207
|
+
const measurementAttrs = {
|
|
208
|
+
...rest,
|
|
209
|
+
embeddedFontFamilies: fontContextRef(embeddedFontFamilyMap)
|
|
210
|
+
};
|
|
194
211
|
if (measurementAttrs.documentGridLinePitch === void 0) return measurementAttrs;
|
|
195
212
|
return {
|
|
196
213
|
...measurementAttrs,
|
|
@@ -199,10 +216,25 @@ const paragraphAttrsMeasureCacheInput = (attrs) => {
|
|
|
199
216
|
};
|
|
200
217
|
/** Serialize the complete, semantically normalized paragraph measurement contract into a cache key. */
|
|
201
218
|
function hashParagraphBlock(block) {
|
|
219
|
+
const fontContexts = [];
|
|
220
|
+
const contextRefs = /* @__PURE__ */ new Map();
|
|
221
|
+
const fontContextRef = (families) => {
|
|
222
|
+
if (!families) return void 0;
|
|
223
|
+
const fingerprint = embeddedFontFingerprint(families);
|
|
224
|
+
const existing = contextRefs.get(fingerprint);
|
|
225
|
+
if (existing !== void 0) return existing;
|
|
226
|
+
const index = fontContexts.length;
|
|
227
|
+
contextRefs.set(fingerprint, index);
|
|
228
|
+
fontContexts.push(fingerprint);
|
|
229
|
+
return index;
|
|
230
|
+
};
|
|
231
|
+
const attrs = paragraphAttrsMeasureCacheInput(block.attrs, fontContextRef);
|
|
232
|
+
const runs = block.runs.map((run) => runMeasureCacheInput(run, fontContextRef));
|
|
202
233
|
return JSON.stringify({
|
|
203
234
|
lineBreakProviderGeneration: getLineBreakProviderGeneration(),
|
|
204
|
-
attrs
|
|
205
|
-
runs
|
|
235
|
+
attrs,
|
|
236
|
+
runs,
|
|
237
|
+
fontContexts
|
|
206
238
|
});
|
|
207
239
|
}
|
|
208
240
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sliceText } from "../../utils/sliceText.js";
|
|
1
2
|
import { splitTrailingToken } from "../../utils/trailingText.js";
|
|
2
3
|
import { resolveEffectiveLineBreakPolicy } from "./effectiveLineBreakPolicy.js";
|
|
3
4
|
import "./lineBreakProvider.js";
|
|
@@ -47,7 +48,11 @@ function computeFollowingTextLeads(block) {
|
|
|
47
48
|
leads[index] = lead;
|
|
48
49
|
const run = block.runs[index];
|
|
49
50
|
if (!run || !isTextRun(run)) lead = void 0;
|
|
50
|
-
else if (run.text) lead =
|
|
51
|
+
else if (run.text) lead = sliceText({
|
|
52
|
+
text: run.text,
|
|
53
|
+
units: "codePoints",
|
|
54
|
+
end: 1
|
|
55
|
+
});
|
|
51
56
|
}
|
|
52
57
|
return leads;
|
|
53
58
|
}
|
|
@@ -101,6 +106,7 @@ function computeProtectedCrossRunGlueWidths(block) {
|
|
|
101
106
|
* invoked from, without the per-word text-length budget ever kicking in.
|
|
102
107
|
*/
|
|
103
108
|
const MAX_CROSS_RUN_SEGMENTS = 64;
|
|
109
|
+
const MAX_SCALAR_CODE_UNITS = 2;
|
|
104
110
|
/** Collect one lexical word continued through adjacent formatting runs. */
|
|
105
111
|
function collectCrossRunWord({ block, startRunIndex, startChar }) {
|
|
106
112
|
const segments = [];
|
|
@@ -115,7 +121,11 @@ function collectCrossRunWord({ block, startRunIndex, startChar }) {
|
|
|
115
121
|
if (remainder.length === 0) continue;
|
|
116
122
|
if (runIndex !== startRunIndex && isSpaceOrTab(remainder[0])) break;
|
|
117
123
|
const remainingBudget = 256 - text.length;
|
|
118
|
-
const boundedRemainder =
|
|
124
|
+
const boundedRemainder = sliceText({
|
|
125
|
+
text: remainder,
|
|
126
|
+
units: "codeUnits",
|
|
127
|
+
end: remainingBudget + MAX_SCALAR_CODE_UNITS
|
|
128
|
+
});
|
|
119
129
|
const firstBreak = findWordBreaks(boundedRemainder, resolveEffectiveLineBreakPolicy({
|
|
120
130
|
attrs: block.attrs,
|
|
121
131
|
run
|
|
@@ -96,6 +96,7 @@ const WORD_SINGLE_LINE_FLOOR = 1.15;
|
|
|
96
96
|
*/
|
|
97
97
|
function calculateEmptyParagraphMetrics(fontSize, spacing, fontFamily, attrs) {
|
|
98
98
|
const result = calculateTypographyMetrics(fontSize, spacing, getFontMetrics({
|
|
99
|
+
...attrs?.embeddedFontFamilyMap ? { embeddedFontFamilyMap: attrs.embeddedFontFamilyMap } : {},
|
|
99
100
|
fontSize,
|
|
100
101
|
fontFamily: fontFamily ?? "Times New Roman",
|
|
101
102
|
...attrs?.defaultAlternateFontFamily !== void 0 ? { alternateFontFamily: attrs.defaultAlternateFontFamily } : {}
|
|
@@ -13,6 +13,7 @@ declare const DEFAULT_TAB_STOP_TWIPS = 720;
|
|
|
13
13
|
* of the paragraph do not format its number.
|
|
14
14
|
*/
|
|
15
15
|
declare function resolveListMarkerFont(block: ParagraphBlock): {
|
|
16
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string>;
|
|
16
17
|
fontFamily: string;
|
|
17
18
|
alternateFontFamily?: string;
|
|
18
19
|
fontSize: number;
|
|
@@ -27,6 +27,7 @@ function resolveListMarkerFont(block) {
|
|
|
27
27
|
alternateFontFamily = markerFormatting.alternateFontFamily;
|
|
28
28
|
}
|
|
29
29
|
const base = {
|
|
30
|
+
...attrs?.embeddedFontFamilyMap ? { embeddedFontFamilyMap: attrs.embeddedFontFamilyMap } : {},
|
|
30
31
|
fontFamily,
|
|
31
32
|
...alternateFontFamily !== void 0 ? { alternateFontFamily } : {},
|
|
32
33
|
fontSize: markerFormatting?.fontSize ?? attrs?.defaultFontSize ?? DEFAULT_FONT_SIZE,
|
|
@@ -61,8 +61,7 @@ function canvasGetFontMetrics(style) {
|
|
|
61
61
|
const bold = style.bold ?? false;
|
|
62
62
|
const italic = style.italic ?? false;
|
|
63
63
|
const fontVariant = style.fontVariant;
|
|
64
|
-
const
|
|
65
|
-
const fontCacheFamily = alternateFontFamily ? `${fontFamily}\u0000${alternateFontFamily}` : fontFamily;
|
|
64
|
+
const fontCacheFamily = getResolvedData(fontFamily, style).cssFallback;
|
|
66
65
|
const cached = getCachedFontMetrics(fontCacheFamily, fontSize, bold, italic, fontVariant);
|
|
67
66
|
if (cached !== void 0) return {
|
|
68
67
|
fontSize,
|
|
@@ -98,7 +97,7 @@ function canvasGetFontMetrics(style) {
|
|
|
98
97
|
}
|
|
99
98
|
} catch {}
|
|
100
99
|
lineHeight = Math.max(lineHeight, ascent + descent);
|
|
101
|
-
const singleLineRatio = getResolvedData(fontFamily,
|
|
100
|
+
const singleLineRatio = getResolvedData(fontFamily, style).singleLineRatio;
|
|
102
101
|
const result = {
|
|
103
102
|
fontSize,
|
|
104
103
|
ascent,
|
|
@@ -165,7 +164,7 @@ function canvasMeasureTextWidth(text, sourceStyle) {
|
|
|
165
164
|
* takes the single-font path (no double-counting, no recursion).
|
|
166
165
|
*/
|
|
167
166
|
function glyphAdvanceStyle(style) {
|
|
168
|
-
const result = {};
|
|
167
|
+
const result = { ...style.embeddedFontFamilyMap ? { embeddedFontFamilyMap: style.embeddedFontFamilyMap } : {} };
|
|
169
168
|
if (style.fontFamily !== void 0) result.fontFamily = style.fontFamily;
|
|
170
169
|
if (style.alternateFontFamily !== void 0) result.alternateFontFamily = style.alternateFontFamily;
|
|
171
170
|
if (style.fontSize !== void 0) result.fontSize = style.fontSize;
|
|
@@ -33,20 +33,17 @@ type ResolvedFontCache = {
|
|
|
33
33
|
/**
|
|
34
34
|
* Get the resolved font data for a font family, with caching.
|
|
35
35
|
*/
|
|
36
|
-
|
|
36
|
+
type ResolvedDataOptions = {
|
|
37
|
+
alternateFontFamily?: string | undefined;
|
|
38
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string> | undefined;
|
|
39
|
+
};
|
|
40
|
+
declare function getResolvedData(fontFamily: string, options?: ResolvedDataOptions): ResolvedFontCache;
|
|
37
41
|
/**
|
|
38
42
|
* Whether a face of `family` (a `FontFace.family`, possibly quoted) can change
|
|
39
43
|
* a width this page has measured.
|
|
40
44
|
*/
|
|
41
45
|
declare function isLayoutFontFamily(family: string): boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Clear the resolved-font-family cache. `resolveFontFamily`'s output for a
|
|
44
|
-
* given key can change even when the raw font names don't — e.g. when the
|
|
45
|
-
* active document's embedded-font family map changes (see
|
|
46
|
-
* `utils/fontResolver.ts`'s `setEmbeddedFontFamilyMap`) — so this must be
|
|
47
|
-
* cleared whenever that happens, not just on font-name changes. Folded into
|
|
48
|
-
* `clearAllCaches` (`./cache.ts`) so callers get it for free.
|
|
49
|
-
*/
|
|
46
|
+
/** Clear cached resolution after a browser font-set or font-policy change. */
|
|
50
47
|
declare function clearFontResolvedCache(): void;
|
|
51
48
|
/**
|
|
52
49
|
* Build a CSS font string from styling properties
|
|
@@ -59,6 +59,7 @@ function buildRunFontStyle(run, fallbackFontFamily, fallbackFontSize) {
|
|
|
59
59
|
const horizontalScale = normalizeHorizontalScalePercent(run.horizontalScale);
|
|
60
60
|
return {
|
|
61
61
|
fontFamily: run.fontFamily ?? fallbackFontFamily,
|
|
62
|
+
...run.embeddedFontFamilyMap ? { embeddedFontFamilyMap: run.embeddedFontFamilyMap } : {},
|
|
62
63
|
...run.alternateFontFamily !== void 0 ? { alternateFontFamily: run.alternateFontFamily } : {},
|
|
63
64
|
...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {},
|
|
64
65
|
...run.eastAsiaAlternateFontFamily !== void 0 ? { eastAsiaAlternateFontFamily: run.eastAsiaAlternateFontFamily } : {},
|
|
@@ -80,19 +81,27 @@ function buildRunFontStyle(run, fallbackFontFamily, fallbackFontSize) {
|
|
|
80
81
|
}
|
|
81
82
|
/** Cache for resolved font data */
|
|
82
83
|
const fontResolvedCache = /* @__PURE__ */ new Map();
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
let embeddedFontResolvedCaches = /* @__PURE__ */ new WeakMap();
|
|
85
|
+
function getResolvedData(fontFamily, options = {}) {
|
|
86
|
+
const { alternateFontFamily, embeddedFontFamilyMap } = options;
|
|
87
|
+
let cache = fontResolvedCache;
|
|
88
|
+
if (embeddedFontFamilyMap) {
|
|
89
|
+
const owned = embeddedFontResolvedCaches.get(embeddedFontFamilyMap);
|
|
90
|
+
cache = owned ?? /* @__PURE__ */ new Map();
|
|
91
|
+
if (!owned) embeddedFontResolvedCaches.set(embeddedFontFamilyMap, cache);
|
|
92
|
+
}
|
|
87
93
|
const cacheKey = `${fontFamily}\u0000${alternateFontFamily ?? ""}`;
|
|
88
|
-
let cached =
|
|
94
|
+
let cached = cache.get(cacheKey);
|
|
89
95
|
if (cached === void 0) {
|
|
90
|
-
const resolved = resolveFontFamily(fontFamily,
|
|
96
|
+
const resolved = resolveFontFamily(fontFamily, {
|
|
97
|
+
alternateFontName: alternateFontFamily,
|
|
98
|
+
embeddedFontFamilyMap
|
|
99
|
+
});
|
|
91
100
|
cached = {
|
|
92
101
|
cssFallback: resolved.cssFallback,
|
|
93
102
|
singleLineRatio: resolved.singleLineRatio
|
|
94
103
|
};
|
|
95
|
-
|
|
104
|
+
cache.set(cacheKey, cached);
|
|
96
105
|
for (const family of parseFontFamilyList(resolved.cssFallback)) layoutFontFamilies.add(normalizeFontFamilyName(family));
|
|
97
106
|
}
|
|
98
107
|
return cached;
|
|
@@ -119,19 +128,13 @@ function isLayoutFontFamily(family) {
|
|
|
119
128
|
/**
|
|
120
129
|
* Get the CSS fallback string for a font family, with caching.
|
|
121
130
|
*/
|
|
122
|
-
function getResolvedFallback(fontFamily,
|
|
123
|
-
return getResolvedData(fontFamily,
|
|
131
|
+
function getResolvedFallback(fontFamily, style) {
|
|
132
|
+
return getResolvedData(fontFamily, style).cssFallback;
|
|
124
133
|
}
|
|
125
|
-
/**
|
|
126
|
-
* Clear the resolved-font-family cache. `resolveFontFamily`'s output for a
|
|
127
|
-
* given key can change even when the raw font names don't — e.g. when the
|
|
128
|
-
* active document's embedded-font family map changes (see
|
|
129
|
-
* `utils/fontResolver.ts`'s `setEmbeddedFontFamilyMap`) — so this must be
|
|
130
|
-
* cleared whenever that happens, not just on font-name changes. Folded into
|
|
131
|
-
* `clearAllCaches` (`./cache.ts`) so callers get it for free.
|
|
132
|
-
*/
|
|
134
|
+
/** Clear cached resolution after a browser font-set or font-policy change. */
|
|
133
135
|
function clearFontResolvedCache() {
|
|
134
136
|
fontResolvedCache.clear();
|
|
137
|
+
embeddedFontResolvedCaches = /* @__PURE__ */ new WeakMap();
|
|
135
138
|
}
|
|
136
139
|
/**
|
|
137
140
|
* Build a CSS font string from styling properties
|
|
@@ -154,7 +157,7 @@ function buildFontString(style) {
|
|
|
154
157
|
const fontSizePx = ptToPx(style.fontSize ?? 11);
|
|
155
158
|
parts.push(`${fontSizePx}px`);
|
|
156
159
|
const fontFamily = style.fontFamily ?? "Times New Roman";
|
|
157
|
-
parts.push(getResolvedFallback(fontFamily, style
|
|
160
|
+
parts.push(getResolvedFallback(fontFamily, style));
|
|
158
161
|
return parts.join(" ");
|
|
159
162
|
}
|
|
160
163
|
/**
|
|
@@ -169,6 +169,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
169
169
|
const metrics = lineFontMetrics ?? getFontMetrics({
|
|
170
170
|
fontSize: paragraphFontSize,
|
|
171
171
|
fontFamily: paragraphFontFamily,
|
|
172
|
+
...attrs?.embeddedFontFamilyMap ? { embeddedFontFamilyMap: attrs.embeddedFontFamilyMap } : {},
|
|
172
173
|
...attrs?.defaultAlternateFontFamily !== void 0 ? { alternateFontFamily: attrs.defaultAlternateFontFamily } : {}
|
|
173
174
|
});
|
|
174
175
|
const finalTypography = { ...calculateTypographyMetrics(fontSize, spacing, metrics) };
|
|
@@ -402,6 +403,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
402
403
|
if (isMathRun(run)) {
|
|
403
404
|
const style = {
|
|
404
405
|
fontFamily: run.fontFamily ?? "Cambria Math",
|
|
406
|
+
...run.embeddedFontFamilyMap ? { embeddedFontFamilyMap: run.embeddedFontFamilyMap } : {},
|
|
405
407
|
fontSize: run.fontSize ?? 11,
|
|
406
408
|
...run.bold !== void 0 ? { bold: run.bold } : {},
|
|
407
409
|
...run.italic !== void 0 ? { italic: run.italic } : {}
|
|
@@ -13,6 +13,8 @@ declare namespace measureTypes_d_exports {
|
|
|
13
13
|
* Font styling properties for measurement
|
|
14
14
|
*/
|
|
15
15
|
type FontStyle = {
|
|
16
|
+
/** Embedded families owned by this editor, never ambient process state. */
|
|
17
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string>;
|
|
16
18
|
fontFamily?: string;
|
|
17
19
|
alternateFontFamily?: string;
|
|
18
20
|
/**
|
|
@@ -13,6 +13,8 @@ type BlockId = string | number;
|
|
|
13
13
|
* Common run formatting properties applied to text runs.
|
|
14
14
|
*/
|
|
15
15
|
type RunFormatting = {
|
|
16
|
+
/** Embedded families owned by this editor, never ambient process state. */
|
|
17
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string>;
|
|
16
18
|
bold?: boolean;
|
|
17
19
|
italic?: boolean;
|
|
18
20
|
/**
|
|
@@ -160,7 +162,7 @@ type RunFormatting = {
|
|
|
160
162
|
/** Groups a suggestion's runs for accept/reject and scroll-to. */
|
|
161
163
|
suggestionId?: string;
|
|
162
164
|
};
|
|
163
|
-
type ListMarkerFormatting = Pick<RunFormatting, "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript" | "color">;
|
|
165
|
+
type ListMarkerFormatting = Pick<RunFormatting, "embeddedFontFamilyMap" | "fontFamily" | "alternateFontFamily" | "eastAsiaFontFamily" | "eastAsiaAlternateFontFamily" | "complexScriptFontFamily" | "complexScriptAlternateFontFamily" | "fontSize" | "complexScriptFontSize" | "bold" | "complexScriptBold" | "italic" | "complexScriptItalic" | "rtl" | "forceComplexScript" | "color">;
|
|
164
166
|
/**
|
|
165
167
|
* Hyperlink information for a run.
|
|
166
168
|
*/
|
|
@@ -416,6 +418,7 @@ declare const isListNumPr: (value: ParagraphNumberingOverride | null | undefined
|
|
|
416
418
|
* Paragraph block attributes.
|
|
417
419
|
*/
|
|
418
420
|
type ParagraphAttrs = {
|
|
421
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string>;
|
|
419
422
|
alignment?: "left" | "center" | "right" | "justify";
|
|
420
423
|
/** Document-generation policy for justified line fitting. */
|
|
421
424
|
justificationCompatibility?: {
|
|
@@ -93,6 +93,7 @@ type PaintPageRequest = {
|
|
|
93
93
|
readonly options: RenderPageOptions;
|
|
94
94
|
};
|
|
95
95
|
type RenderPageOptions = {
|
|
96
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string>;
|
|
96
97
|
/** Document to create elements in (default: window.document) */
|
|
97
98
|
document?: Document;
|
|
98
99
|
/** Bookmark name -> 1-indexed page, for resolving PAGEREF fields at paint. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { embeddedFontFingerprint } from "../fonts/embeddedFontFingerprint.js";
|
|
1
2
|
import "../layout-engine/measure/floatingLineClearance.js";
|
|
2
3
|
import { resolveFloatingTableX } from "../layout-engine/measure/floatingTablePosition.js";
|
|
3
4
|
import { rectsToFloatingZones } from "../layout-engine/measure/floatingZones.js";
|
|
@@ -59,7 +60,7 @@ function applyPageStyles(element, width, height, options) {
|
|
|
59
60
|
element.style.border = "none";
|
|
60
61
|
element.style.boxShadow = "none";
|
|
61
62
|
element.style.outline = "none";
|
|
62
|
-
element.style.fontFamily =
|
|
63
|
+
element.style.fontFamily = resolveFontFamily(DEFAULT_FONT_FAMILY, options).cssFallback;
|
|
63
64
|
element.style.fontSize = `${1056 / 72}px`;
|
|
64
65
|
element.style.color = "var(--doc-canvas-text, #000)";
|
|
65
66
|
}
|
|
@@ -179,7 +180,10 @@ function syncPageWatermarkOverlay(pageEl, page, options, doc) {
|
|
|
179
180
|
for (const stale of Array.from(pageEl.querySelectorAll(":scope > .layout-page-watermark"))) stale.remove();
|
|
180
181
|
const watermark = options.watermark;
|
|
181
182
|
if (!watermark) return;
|
|
182
|
-
const overlay = renderWatermarkLayer(watermark, page, doc,
|
|
183
|
+
const overlay = renderWatermarkLayer(watermark, page, doc, {
|
|
184
|
+
...options.watermarkImageSrc !== void 0 ? { imageSrc: options.watermarkImageSrc } : {},
|
|
185
|
+
...options.embeddedFontFamilyMap ? { embeddedFontFamilyMap: options.embeddedFontFamilyMap } : {}
|
|
186
|
+
});
|
|
183
187
|
if (!overlay) return;
|
|
184
188
|
const contentEl = pageEl.querySelector(`:scope > .${PAGE_CLASS_NAMES.content}`);
|
|
185
189
|
if (contentEl) {
|
|
@@ -785,7 +789,10 @@ function renderPage(page, context, options = {}) {
|
|
|
785
789
|
const pageBorderEl = renderPageBorderOverlay(page, options, doc);
|
|
786
790
|
if (pageBorderEl && options.pageBorders?.zOrder === "back") pageEl.append(pageBorderEl);
|
|
787
791
|
if (options.watermark) {
|
|
788
|
-
const watermarkEl = renderWatermarkLayer(options.watermark, page, doc,
|
|
792
|
+
const watermarkEl = renderWatermarkLayer(options.watermark, page, doc, {
|
|
793
|
+
...options.watermarkImageSrc !== void 0 ? { imageSrc: options.watermarkImageSrc } : {},
|
|
794
|
+
...options.embeddedFontFamilyMap ? { embeddedFontFamilyMap: options.embeddedFontFamilyMap } : {}
|
|
795
|
+
});
|
|
789
796
|
if (watermarkEl) pageEl.append(watermarkEl);
|
|
790
797
|
}
|
|
791
798
|
const contentEl = doc.createElement("div");
|
|
@@ -1403,6 +1410,7 @@ function headerFooterContentFingerprint(prefix, entries) {
|
|
|
1403
1410
|
*/
|
|
1404
1411
|
function computeOptionsHash(options) {
|
|
1405
1412
|
const parts = [];
|
|
1413
|
+
if (options.embeddedFontFamilyMap) parts.push(`embedded-fonts:${embeddedFontFingerprint(options.embeddedFontFamilyMap)}`);
|
|
1406
1414
|
if (options.headerContent) parts.push(`hdr:${options.headerContent.blocks.length},${options.headerContent.height},${options.headerContent.visualTop ?? 0},${options.headerContent.visualBottom ?? options.headerContent.height},${options.headerContent.rId ?? ""},${options.headerContent.textSig ?? ""}`);
|
|
1407
1415
|
if (options.footerContent) parts.push(`ftr:${options.footerContent.blocks.length},${options.footerContent.height},${options.footerContent.visualTop ?? 0},${options.footerContent.visualBottom ?? options.footerContent.height},${options.footerContent.rId ?? ""},${options.footerContent.textSig ?? ""}`);
|
|
1408
1416
|
parts.push(...headerFooterContentFingerprint("hdr-map", options.headerContentByRId));
|
|
@@ -190,7 +190,10 @@ const UNICODE_BIDI_BY_WRAPPER_CONTROL = {
|
|
|
190
190
|
* Apply text run styles to an element
|
|
191
191
|
*/
|
|
192
192
|
function applyRunStyles(element, run) {
|
|
193
|
-
if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily,
|
|
193
|
+
if (run.fontFamily) element.style.fontFamily = resolveFontFamily(run.fontFamily, {
|
|
194
|
+
alternateFontName: run.alternateFontFamily,
|
|
195
|
+
embeddedFontFamilyMap: run.embeddedFontFamilyMap
|
|
196
|
+
}).cssFallback;
|
|
194
197
|
if (run.fontSize) element.style.fontSize = `${fontSizePtToPx(run.fontSize)}px`;
|
|
195
198
|
if (run.bold) element.style.fontWeight = "700";
|
|
196
199
|
if (run.italic) element.style.fontStyle = "italic";
|
|
@@ -1043,6 +1046,7 @@ function runVisualSpaceContraction({ text, horizontalScale, visualSpaceContracti
|
|
|
1043
1046
|
*/
|
|
1044
1047
|
function runMeasureStyle(run) {
|
|
1045
1048
|
return {
|
|
1049
|
+
...run.embeddedFontFamilyMap ? { embeddedFontFamilyMap: run.embeddedFontFamilyMap } : {},
|
|
1046
1050
|
...run.bold !== void 0 ? { bold: run.bold } : {},
|
|
1047
1051
|
...run.italic !== void 0 ? { italic: run.italic } : {},
|
|
1048
1052
|
...run.letterSpacing !== void 0 ? { letterSpacing: run.letterSpacing } : {},
|
|
@@ -1168,7 +1172,10 @@ function createTextMeasurer(doc) {
|
|
|
1168
1172
|
if (style.smallCaps) fontPrefixParts.push("small-caps");
|
|
1169
1173
|
if (bold) fontPrefixParts.push("700");
|
|
1170
1174
|
fontPrefixParts.push(`${size * 96 / 72}px`);
|
|
1171
|
-
return `${fontPrefixParts.join(" ")} ${resolveFontFamily(family,
|
|
1175
|
+
return `${fontPrefixParts.join(" ")} ${resolveFontFamily(family, {
|
|
1176
|
+
alternateFontName: alternateFamily,
|
|
1177
|
+
embeddedFontFamilyMap: style.embeddedFontFamilyMap
|
|
1178
|
+
}).cssFallback}`;
|
|
1172
1179
|
};
|
|
1173
1180
|
const baseFont = fontString(fontFamily, fontSize, style.bold, style.italic, style.alternateFontFamily);
|
|
1174
1181
|
const complex = resolveComplexScriptFormatting(style);
|
|
@@ -1670,7 +1677,10 @@ function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting,
|
|
|
1670
1677
|
const span = doc.createElement("span");
|
|
1671
1678
|
span.className = "layout-list-marker";
|
|
1672
1679
|
span.style.display = "inline-block";
|
|
1673
|
-
span.style.fontFamily = resolveFontFamily(formatting.fontFamily,
|
|
1680
|
+
span.style.fontFamily = resolveFontFamily(formatting.fontFamily, {
|
|
1681
|
+
alternateFontName: formatting.alternateFontFamily,
|
|
1682
|
+
embeddedFontFamilyMap: formatting.embeddedFontFamilyMap
|
|
1683
|
+
}).cssFallback;
|
|
1674
1684
|
if (formatting.fontSize) span.style.fontSize = `${formatting.fontSize * 96 / 72}px`;
|
|
1675
1685
|
if (formatting.bold !== void 0) span.style.fontWeight = formatting.bold ? "700" : "normal";
|
|
1676
1686
|
if (formatting.italic !== void 0) span.style.fontStyle = formatting.italic ? "italic" : "normal";
|
|
@@ -2,6 +2,7 @@ import { document_d_exports } from "../types/document.js";
|
|
|
2
2
|
import { Page } from "../layout-engine/types.js";
|
|
3
3
|
//#region src/layout-painter/renderWatermark.d.ts
|
|
4
4
|
type RenderWatermarkOptions = {
|
|
5
|
+
embeddedFontFamilyMap?: ReadonlyMap<string, string>;
|
|
5
6
|
/** Resolved image src for picture watermarks (`data:` / `blob:` only). */
|
|
6
7
|
imageSrc?: string;
|
|
7
8
|
};
|
|
@@ -25,7 +25,11 @@ function renderWatermarkLayer(watermark, page, doc, options = {}) {
|
|
|
25
25
|
layer.style.display = "flex";
|
|
26
26
|
layer.style.alignItems = "center";
|
|
27
27
|
layer.style.justifyContent = "center";
|
|
28
|
-
if (watermark.kind === "text") layer.append(renderTextWatermark(
|
|
28
|
+
if (watermark.kind === "text") layer.append(renderTextWatermark({
|
|
29
|
+
watermark,
|
|
30
|
+
doc,
|
|
31
|
+
options
|
|
32
|
+
}));
|
|
29
33
|
else {
|
|
30
34
|
const imageSrc = options.imageSrc;
|
|
31
35
|
if (!imageSrc) return null;
|
|
@@ -33,10 +37,10 @@ function renderWatermarkLayer(watermark, page, doc, options = {}) {
|
|
|
33
37
|
}
|
|
34
38
|
return layer;
|
|
35
39
|
}
|
|
36
|
-
function renderTextWatermark(watermark, doc) {
|
|
40
|
+
function renderTextWatermark({ watermark, doc, options }) {
|
|
37
41
|
const el = doc.createElement("div");
|
|
38
42
|
el.textContent = watermark.text;
|
|
39
|
-
el.style.fontFamily = resolveFontFamily(watermark.font ?? "Calibri").cssFallback;
|
|
43
|
+
el.style.fontFamily = resolveFontFamily(watermark.font ?? "Calibri", options).cssFallback;
|
|
40
44
|
el.style.fontSize = "144px";
|
|
41
45
|
el.style.fontWeight = "bold";
|
|
42
46
|
el.style.whiteSpace = "nowrap";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeUtf8 } from "../utils/textEncoding.js";
|
|
1
2
|
import { Subscribable } from "./Subscribable.js";
|
|
2
3
|
import { decodeAutoSaveEnvelope, encodeAutoSaveDocument, encodeAutoSaveEnvelopeFromDocument } from "./autoSaveCodec.js";
|
|
3
4
|
//#region src/managers/AutoSaveManager.ts
|
|
@@ -228,7 +229,7 @@ function getAutoSaveStorageSize(storageKey = DEFAULT_STORAGE_KEY) {
|
|
|
228
229
|
try {
|
|
229
230
|
const data = localStorage.getItem(storageKey);
|
|
230
231
|
if (!data) return 0;
|
|
231
|
-
return
|
|
232
|
+
return encodeUtf8(data).byteLength;
|
|
232
233
|
} catch {
|
|
233
234
|
return 0;
|
|
234
235
|
}
|
|
@@ -5,6 +5,15 @@ type EditorMode = "editing" | "suggesting" | "viewing";
|
|
|
5
5
|
/** How tracked changes render. Drives the display mode dropdown. */
|
|
6
6
|
declare const DISPLAY_MODES: readonly ["all-markup", "simple-markup", "no-markup", "original"];
|
|
7
7
|
type DisplayMode = (typeof DISPLAY_MODES)[number];
|
|
8
|
+
/** Why a user action cannot edit the displayed document. */
|
|
9
|
+
type EditorReadOnlyReason = "host-read-only" | "viewing-mode" | "review-display-mode";
|
|
10
|
+
declare const getReviewViewReadOnlyReason: (displayMode: DisplayMode) => EditorReadOnlyReason | null;
|
|
11
|
+
type EditorReadOnlyReasonOptions = {
|
|
12
|
+
editingMode: EditorMode;
|
|
13
|
+
readOnlyProp: boolean;
|
|
14
|
+
displayMode: DisplayMode;
|
|
15
|
+
};
|
|
16
|
+
declare const getEditorReadOnlyReason: ({ editingMode, readOnlyProp, displayMode }: EditorReadOnlyReasonOptions) => EditorReadOnlyReason | null;
|
|
8
17
|
/** EditorModeManager snapshot. */
|
|
9
18
|
type EditorModeSnapshot = {
|
|
10
19
|
/** Uncontrolled internal editing mode (the host's controlled prop wins over this). */
|
|
@@ -26,4 +35,4 @@ declare class EditorModeManager extends Subscribable<EditorModeSnapshot> {
|
|
|
26
35
|
setDisplayMode(mode: DisplayMode): void;
|
|
27
36
|
}
|
|
28
37
|
//#endregion
|
|
29
|
-
export { DISPLAY_MODES, DisplayMode, EditorMode, EditorModeManager, EditorModeSnapshot, isReadOnlyMode, isTrackChangesMode, toggledTrackChangesMode };
|
|
38
|
+
export { DISPLAY_MODES, DisplayMode, EditorMode, EditorModeManager, EditorModeSnapshot, EditorReadOnlyReason, getEditorReadOnlyReason, getReviewViewReadOnlyReason, isReadOnlyMode, isTrackChangesMode, toggledTrackChangesMode };
|