@stll/folio-core 0.52.0 → 0.53.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 -0
- package/dist/ai-edits/apply.d.ts +26 -1
- package/dist/ai-edits/apply.js +1519 -105
- package/dist/ai-edits/batch-claims.d.ts +130 -0
- package/dist/ai-edits/batch-claims.js +244 -0
- package/dist/ai-edits/blockRange.js +9 -3
- package/dist/ai-edits/character-boundaries.d.ts +43 -0
- package/dist/ai-edits/character-boundaries.js +95 -0
- package/dist/ai-edits/clean-text.d.ts +33 -3
- package/dist/ai-edits/clean-text.js +52 -6
- package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
- package/dist/ai-edits/comment-lifecycle.js +52 -0
- package/dist/ai-edits/headless.d.ts +71 -7
- package/dist/ai-edits/headless.js +381 -41
- package/dist/ai-edits/index.d.ts +2 -1
- package/dist/ai-edits/index.js +2 -1
- package/dist/ai-edits/minimal-replacement.d.ts +21 -6
- package/dist/ai-edits/minimal-replacement.js +134 -15
- package/dist/ai-edits/newListNumbering.d.ts +23 -0
- package/dist/ai-edits/newListNumbering.js +94 -0
- package/dist/ai-edits/note-references.d.ts +96 -0
- package/dist/ai-edits/note-references.js +139 -0
- package/dist/ai-edits/pending-suggestions.d.ts +79 -0
- package/dist/ai-edits/pending-suggestions.js +306 -0
- package/dist/ai-edits/read.d.ts +1 -1
- package/dist/ai-edits/read.js +56 -43
- package/dist/ai-edits/result-validation.d.ts +29 -0
- package/dist/ai-edits/result-validation.js +164 -0
- package/dist/ai-edits/snapshot.d.ts +36 -3
- package/dist/ai-edits/snapshot.js +177 -23
- package/dist/ai-edits/table-cell-mutations.d.ts +1 -1
- package/dist/ai-edits/table-cell-mutations.js +4 -1
- package/dist/ai-edits/table-geometry.d.ts +1 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +38 -16
- package/dist/ai-edits/table-row-column-mutations.js +61 -26
- package/dist/ai-edits/types.d.ts +155 -16
- package/dist/compare/compare.d.ts +1 -1
- package/dist/compare/compare.js +65 -16
- package/dist/compare/content-alignment.js +13 -2
- package/dist/compare/content-types.d.ts +7 -0
- package/dist/compare/content.d.ts +4 -1
- package/dist/compare/content.js +6 -1
- package/dist/compare/formatting.js +2 -1
- package/dist/compare/inline-atoms.d.ts +21 -4
- package/dist/compare/inline-atoms.js +138 -16
- package/dist/compare/plan.js +10 -5
- package/dist/compare/scenario.js +14 -3
- package/dist/compare/section-boundary-properties.js +1 -1
- package/dist/compare/types.d.ts +4 -2
- package/dist/compare/types.js +2 -1
- package/dist/compare/verification.d.ts +1 -1
- package/dist/compare/verification.js +15 -3
- package/dist/controller/committedLayoutDiff.d.ts +25 -0
- package/dist/controller/committedLayoutDiff.js +71 -0
- package/dist/controller/contentControlWidgetController.d.ts +1 -1
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/fontReadiness.d.ts +70 -3
- package/dist/controller/fontReadiness.js +100 -10
- package/dist/controller/headerFooterEditorManager.js +6 -1
- package/dist/controller/layoutPipeline.d.ts +12 -10
- package/dist/controller/layoutPipeline.js +62 -9
- package/dist/controller/layoutRunOptions.d.ts +24 -0
- package/dist/controller/layoutRunOptions.js +17 -0
- package/dist/controller/layoutScheduler.d.ts +19 -14
- package/dist/controller/layoutScheduler.js +15 -12
- package/dist/controller/layoutSession.d.ts +26 -2
- package/dist/controller/layoutSession.js +1 -1
- package/dist/controller/noteEditorManager.js +8 -3
- package/dist/document-operations.d.ts +11 -2
- package/dist/document-operations.js +230 -21
- package/dist/docx/altChunk.d.ts +8 -0
- package/dist/docx/altChunk.js +17 -0
- package/dist/docx/attributeRemainder.d.ts +1 -1
- package/dist/docx/blockContentParser.d.ts +64 -1
- package/dist/docx/blockContentParser.js +17 -4
- package/dist/docx/blockCustomXmlShell.d.ts +7 -0
- package/dist/docx/blockCustomXmlShell.js +14 -0
- package/dist/docx/blockPlainText.js +7 -0
- package/dist/docx/commentAnchorIndex.js +1 -1
- package/dist/docx/commentRangeIntegrity.js +8 -3
- package/dist/docx/commentReferenceNormalization.js +1 -1
- package/dist/docx/commentReplyMarkers.js +20 -1
- package/dist/docx/compatibility.d.ts +1 -1
- package/dist/docx/compatibility.js +34 -13
- package/dist/docx/containerChildren.gen.d.ts +1 -1
- package/dist/docx/containerChildren.gen.js +1 -0
- package/dist/docx/documentParser.js +12 -12
- package/dist/docx/drawingIdNormalization.d.ts +3 -1
- package/dist/docx/drawingIdNormalization.js +6 -1
- package/dist/docx/ensureParaIds.js +119 -97
- package/dist/docx/footnoteParser.js +8 -4
- package/dist/docx/headerFooterParser.js +3 -3
- package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
- package/dist/docx/headerFooterReferenceNormalization.js +52 -27
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/index.d.ts +1 -1
- package/dist/docx/listNumberingInstances.d.ts +59 -0
- package/dist/docx/listNumberingInstances.js +249 -0
- package/dist/docx/normalizeBaseDirection.js +2 -1
- package/dist/docx/opaqueCarrier.d.ts +7 -0
- package/dist/docx/opaqueCarrier.js +38 -0
- package/dist/docx/packageParts.js +4 -1
- package/dist/docx/paragraphParser.js +91 -24
- package/dist/docx/paragraphPropertySource.d.ts +4 -2
- package/dist/docx/paragraphPropertySource.js +7 -1
- package/dist/docx/paragraphTraversal.js +1 -0
- package/dist/docx/parseWarningMessage.js +4 -1
- package/dist/docx/parser.js +173 -20
- package/dist/docx/rezip.js +27 -5
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sdtPropertiesPatch.js +3 -0
- package/dist/docx/selectiveSave.js +16 -9
- package/dist/docx/selectiveXmlPatch.js +106 -37
- package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
- package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
- package/dist/docx/serializer/documentSerializer.js +2 -0
- package/dist/docx/serializer/headerFooterSerializer.js +2 -0
- package/dist/docx/serializer/noteSerializer.js +3 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -9
- package/dist/docx/serializer/tableSerializer.js +25 -38
- package/dist/docx/server/createBilingualDocument.js +3 -3
- package/dist/docx/tableParser.d.ts +157 -1
- package/dist/docx/tableParser.js +89 -10
- package/dist/docx/textBoxParser.js +1 -1
- package/dist/docx/unzip.d.ts +2 -1
- package/dist/docx/unzip.js +1 -1
- package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
- package/dist/docx/wordprocessingPrefixes.js +286 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +136 -0
- package/dist/i18n/messages/catalogs.gen.js +153 -17
- package/dist/i18n/messages/messages.gen.d.ts +8 -0
- package/dist/internal/compare/inline-presentation.d.ts +2 -1
- package/dist/internal/compare/inline-presentation.js +11 -10
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
- package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
- package/dist/internal/indexedPositionMap.d.ts +11 -0
- package/dist/internal/indexedPositionMap.js +42 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/revisionResolutionEdits.d.ts +13 -0
- package/dist/internal/revisionResolutionEdits.js +19 -0
- package/dist/internal/revisionResolutionInline.d.ts +24 -0
- package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
- package/dist/internal/revisionResolutionStep.d.ts +34 -0
- package/dist/internal/revisionResolutionStep.js +282 -0
- package/dist/internal/revisionResolutionTracking.d.ts +11 -0
- package/dist/internal/revisionResolutionTracking.js +124 -0
- package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
- package/dist/internal/wholeStoryRevisionResolution.js +530 -0
- package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
- package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
- package/dist/layout-bridge/convert/tableConversion.js +1 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
- package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
- package/dist/layout-engine/layoutInstrumentation.js +4 -1
- package/dist/layout-engine/measure/cache.d.ts +18 -1
- package/dist/layout-engine/measure/cache.js +31 -1
- package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
- package/dist/layout-engine/measure/measureContainer.js +7 -47
- package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
- package/dist/layout-engine/measure/measureHelpers.js +22 -2
- package/dist/layout-engine/measure/measureWorker.js +2 -3
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
- package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
- package/dist/layout-engine/types.d.ts +6 -0
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/managers/ContextMenuManager.js +5 -2
- package/dist/managers/types.d.ts +3 -0
- package/dist/markdown/fromMarkdown.js +2 -1
- package/dist/markdown/internals.d.ts +11 -1
- package/dist/markdown/internals.js +24 -3
- package/dist/markdown/renderBlock.js +39 -9
- package/dist/markdown/renderParagraph.d.ts +13 -1
- package/dist/markdown/renderParagraph.js +85 -38
- package/dist/markdown/renderRuns.js +3 -10
- package/dist/markdown/renderTable.js +24 -12
- package/dist/markdown/trailers.js +2 -2
- package/dist/markdown/types.d.ts +29 -7
- package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
- package/dist/paged-layout/incrementalMeasure.js +1 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
- package/dist/paged-layout/transactionDirtyRange.js +29 -41
- package/dist/panel-layout.d.ts +83 -0
- package/dist/panel-layout.js +96 -0
- package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
- package/dist/prosemirror/anchoredTextBoxes.js +156 -0
- package/dist/prosemirror/attrs/index.d.ts +6 -2
- package/dist/prosemirror/attrs/index.js +172 -1
- package/dist/prosemirror/commands/comments.d.ts +7 -8
- package/dist/prosemirror/commands/comments.js +241 -207
- package/dist/prosemirror/commands/contentControls.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
- package/dist/prosemirror/commands/formatting.d.ts +1 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/paragraph.d.ts +7 -1
- package/dist/prosemirror/commands/paragraph.js +9 -1
- package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
- package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
- package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
- package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
- package/dist/prosemirror/commands/resolveAllTableChanges.js +615 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.js +59 -0
- package/dist/prosemirror/commands/sectionBreak.js +2 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +8 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.js +1 -1
- package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +181 -31
- package/dist/prosemirror/conversion/toProseDoc.js +39 -4
- package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
- package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
- package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
- package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
- package/dist/prosemirror/extensions/StarterKit.js +3 -1
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +12 -0
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +3 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +161 -123
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
- package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +126 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +21 -5
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +7 -2
- package/dist/prosemirror/extensions/marks/markUtils.js +8 -2
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +10 -0
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +35 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +19 -18
- package/dist/prosemirror/extensions/types.d.ts +4 -1
- package/dist/prosemirror/findReplaceSelection.js +1 -1
- package/dist/prosemirror/index.d.ts +3 -2
- package/dist/prosemirror/index.js +3 -2
- package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
- package/dist/prosemirror/indexedNodeLookup.js +103 -0
- package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
- package/dist/prosemirror/listAutoformatMarkers.js +98 -0
- package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
- package/dist/prosemirror/listInstanceReferences.js +72 -0
- package/dist/prosemirror/listLabels.d.ts +24 -0
- package/dist/prosemirror/listLabels.js +111 -0
- package/dist/prosemirror/listNumbering.d.ts +110 -0
- package/dist/prosemirror/listNumbering.js +345 -0
- package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
- package/dist/prosemirror/listRenderingAttrs.js +8 -1
- package/dist/prosemirror/markupViewProjection.d.ts +95 -0
- package/dist/prosemirror/markupViewProjection.js +83 -0
- package/dist/prosemirror/numberingAttr.d.ts +9 -1
- package/dist/prosemirror/numberingAttr.js +9 -1
- package/dist/prosemirror/outlineLevelAttr.js +1 -1
- package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
- package/dist/prosemirror/paragraphIndentation.js +29 -7
- package/dist/prosemirror/paragraphMarkJoin.d.ts +19 -0
- package/dist/prosemirror/paragraphMarkJoin.js +24 -0
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
- package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
- package/dist/prosemirror/plugins/documentNumbering.js +97 -11
- package/dist/prosemirror/plugins/documentStyles.d.ts +10 -1
- package/dist/prosemirror/plugins/documentStyles.js +14 -1
- package/dist/prosemirror/plugins/suggestionMode.d.ts +16 -2
- package/dist/prosemirror/plugins/suggestionMode.js +116 -52
- package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
- package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
- package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
- package/dist/prosemirror/positionSweep.d.ts +24 -0
- package/dist/prosemirror/positionSweep.js +222 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +1 -1
- package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
- package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
- package/dist/prosemirror/replacedAnnotations.js +170 -1
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +3 -0
- package/dist/prosemirror/schema/nodes.d.ts +42 -11
- package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
- package/dist/prosemirror/sectionMarkEdits.js +59 -0
- package/dist/prosemirror/storyListNumbering.d.ts +17 -0
- package/dist/prosemirror/storyListNumbering.js +102 -0
- package/dist/prosemirror/tableGridMutation.d.ts +48 -2
- package/dist/prosemirror/tableGridMutation.js +106 -1
- package/dist/prosemirror/validation.js +5 -1
- package/dist/redline.js +93 -9
- package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
- package/dist/render-dom/BodySelectionOverlay.js +3 -2
- package/dist/utils/findReplace.js +2 -2
- package/dist/utils/mergeDocumentContent.js +1 -1
- package/dist/utils/noteReferenceLabels.d.ts +36 -0
- package/dist/utils/noteReferenceLabels.js +32 -0
- package/dist/utils/replaceText.js +1 -1
- package/dist/version-comparison.d.ts +1 -0
- package/dist/version-comparison.js +1 -0
- package/package.json +3 -2
- package/dist/internal/headlessRevisionResolution.d.ts +0 -23
|
@@ -192,13 +192,22 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
192
192
|
trailingPageBreakSectionPositions.add(childStart);
|
|
193
193
|
consumedPageBreakPositions.add(childStart + child.nodeSize);
|
|
194
194
|
}
|
|
195
|
-
if (child.type.name === "blockSdt") collectTrailingPageBreakSections(child, childStart + 1);
|
|
195
|
+
if (child.type.name === "blockSdt" || child.type.name === "blockCustomXml") collectTrailingPageBreakSections(child, childStart + 1);
|
|
196
196
|
childStart += child.nodeSize;
|
|
197
197
|
}
|
|
198
198
|
};
|
|
199
199
|
collectTrailingPageBreakSections(doc, offset);
|
|
200
200
|
const visit = (node, pos) => {
|
|
201
201
|
switch (node.type.name) {
|
|
202
|
+
case "blockCustomXml": {
|
|
203
|
+
let childOffset = pos + 1;
|
|
204
|
+
for (let i = 0; i < node.childCount; i += 1) {
|
|
205
|
+
const child = node.child(i);
|
|
206
|
+
visit(child, childOffset);
|
|
207
|
+
childOffset += child.nodeSize;
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
202
211
|
case "blockSdt": {
|
|
203
212
|
const attrs = expectBlockSdtAttrs(node);
|
|
204
213
|
sdtSeq += 1;
|
|
@@ -32,6 +32,13 @@ type LayoutInstrumentation = {
|
|
|
32
32
|
onLayoutStart?: (event: {
|
|
33
33
|
reason: LayoutRunReason;
|
|
34
34
|
}) => void;
|
|
35
|
+
/**
|
|
36
|
+
* A review view (the editor's `DisplayMode`) laid out part of the story as
|
|
37
|
+
* authored: a revision there has no resolution.
|
|
38
|
+
*/
|
|
39
|
+
onMarkupViewIncomplete?: (event: {
|
|
40
|
+
view: string;
|
|
41
|
+
}) => void;
|
|
35
42
|
onLayoutPhase?: (event: {
|
|
36
43
|
durationMs: number;
|
|
37
44
|
phase: LayoutPhase;
|
|
@@ -55,6 +62,7 @@ declare function recordMeasureBlockError(blockIndex: number, block: FlowBlock, e
|
|
|
55
62
|
declare function recordLayoutComplete(reason?: LayoutRunReason): void;
|
|
56
63
|
declare function recordLayoutStart(reason: LayoutRunReason): void;
|
|
57
64
|
declare function recordLayoutError(reason: LayoutRunReason, error: unknown): void;
|
|
65
|
+
declare function recordMarkupViewIncomplete(view: string): void;
|
|
58
66
|
/** A dictionary failed to load; layout continues without hyphenating that language. */
|
|
59
67
|
declare function recordHyphenationDictionaryError(dictionary: string, error: Error): void;
|
|
60
68
|
declare function recordLayoutPhase(reason: LayoutRunReason, phase: LayoutPhase, durationMs: number): void;
|
|
@@ -62,4 +70,4 @@ declare function recordHiddenEditorStateCreate(reason: HiddenEditorStateReason):
|
|
|
62
70
|
declare function recordHiddenEditorPhase(reason: HiddenEditorStateReason, phase: HiddenEditorPhase, durationMs: number): void;
|
|
63
71
|
declare function recordDocumentLoadPhase(phase: DocumentLoadPhase, durationMs: number): void;
|
|
64
72
|
//#endregion
|
|
65
|
-
export { DocumentLoadPhase, HiddenEditorPhase, HiddenEditorStateReason, LayoutInstrumentation, LayoutPhase, LayoutRunReason, recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordHyphenationDictionaryError, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
73
|
+
export { DocumentLoadPhase, HiddenEditorPhase, HiddenEditorStateReason, LayoutInstrumentation, LayoutPhase, LayoutRunReason, recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordHyphenationDictionaryError, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMarkupViewIncomplete, recordMeasureBlock, recordMeasureBlockError };
|
|
@@ -25,6 +25,9 @@ function recordLayoutError(reason, error) {
|
|
|
25
25
|
reason
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
|
+
function recordMarkupViewIncomplete(view) {
|
|
29
|
+
globalThis.__folioLayoutInstrumentation?.onMarkupViewIncomplete?.({ view });
|
|
30
|
+
}
|
|
28
31
|
/** A dictionary failed to load; layout continues without hyphenating that language. */
|
|
29
32
|
function recordHyphenationDictionaryError(dictionary, error) {
|
|
30
33
|
globalThis.__folioLayoutInstrumentation?.onHyphenationDictionaryError?.({
|
|
@@ -56,4 +59,4 @@ function recordDocumentLoadPhase(phase, durationMs) {
|
|
|
56
59
|
});
|
|
57
60
|
}
|
|
58
61
|
//#endregion
|
|
59
|
-
export { recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordHyphenationDictionaryError, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
62
|
+
export { recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordHyphenationDictionaryError, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMarkupViewIncomplete, recordMeasureBlock, recordMeasureBlockError };
|
|
@@ -83,9 +83,26 @@ declare function getParagraphCacheSize(): number;
|
|
|
83
83
|
* Call when fonts change, page width changes, or for testing
|
|
84
84
|
*/
|
|
85
85
|
declare function clearAllCaches(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Bind the caches to the font set the next measurements are taken in. When a
|
|
88
|
+
* face has loaded (or been added or removed) since the cached entries were
|
|
89
|
+
* measured, they are dropped: a width measured in a fallback cannot be served
|
|
90
|
+
* once the face it stood in for is available. Entries measured before the
|
|
91
|
+
* caches were first bound are dropped too: nothing records their font set.
|
|
92
|
+
* Returns whether it cleared.
|
|
93
|
+
*/
|
|
94
|
+
declare function syncMeasureCachesToFontSet(fontSet: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Rename the font set the cached entries were measured in, without dropping
|
|
97
|
+
* them: for a layout run that has just measured, whose signature now also
|
|
98
|
+
* names the families it measured first. Only valid within the run that bound
|
|
99
|
+
* the caches with {@link syncMeasureCachesToFontSet}, since no face can load
|
|
100
|
+
* during a synchronous run.
|
|
101
|
+
*/
|
|
102
|
+
declare function labelMeasureCachesFontSet(fontSet: string): void;
|
|
86
103
|
/**
|
|
87
104
|
* Get total size of all caches
|
|
88
105
|
*/
|
|
89
106
|
declare function getTotalCacheSize(): number;
|
|
90
107
|
//#endregion
|
|
91
|
-
export { clearAllCaches, clearFontMetricsCache, clearParagraphMeasureCache, clearTextWidthCache, getCachedFontMetrics, getCachedParagraphMeasure, getCachedTextWidth, getFontCacheSize, getParagraphCacheSize, getTextCacheSize, getTextWidthCacheGeneration, getTotalCacheSize, hashParagraphBlock, setCachedFontMetrics, setCachedParagraphMeasure, setCachedTextWidth, setFontCacheSize, setParagraphCacheSize, setTextCacheSize };
|
|
108
|
+
export { clearAllCaches, clearFontMetricsCache, clearParagraphMeasureCache, clearTextWidthCache, getCachedFontMetrics, getCachedParagraphMeasure, getCachedTextWidth, getFontCacheSize, getParagraphCacheSize, getTextCacheSize, getTextWidthCacheGeneration, getTotalCacheSize, hashParagraphBlock, labelMeasureCachesFontSet, setCachedFontMetrics, setCachedParagraphMeasure, setCachedTextWidth, setFontCacheSize, setParagraphCacheSize, setTextCacheSize, syncMeasureCachesToFontSet };
|
|
@@ -259,6 +259,11 @@ function getParagraphCacheSize() {
|
|
|
259
259
|
return paragraphMeasureCache.size;
|
|
260
260
|
}
|
|
261
261
|
/**
|
|
262
|
+
* The font set (a `readFontSetSignature` value) every cached measurement was
|
|
263
|
+
* taken in; `null` once the caches are cleared and before anything measures.
|
|
264
|
+
*/
|
|
265
|
+
let cachedFontSet = null;
|
|
266
|
+
/**
|
|
262
267
|
* Clear all measurement caches
|
|
263
268
|
* Call when fonts change, page width changes, or for testing
|
|
264
269
|
*/
|
|
@@ -267,6 +272,31 @@ function clearAllCaches() {
|
|
|
267
272
|
clearFontMetricsCache();
|
|
268
273
|
clearParagraphMeasureCache();
|
|
269
274
|
clearFontResolvedCache();
|
|
275
|
+
cachedFontSet = null;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Bind the caches to the font set the next measurements are taken in. When a
|
|
279
|
+
* face has loaded (or been added or removed) since the cached entries were
|
|
280
|
+
* measured, they are dropped: a width measured in a fallback cannot be served
|
|
281
|
+
* once the face it stood in for is available. Entries measured before the
|
|
282
|
+
* caches were first bound are dropped too: nothing records their font set.
|
|
283
|
+
* Returns whether it cleared.
|
|
284
|
+
*/
|
|
285
|
+
function syncMeasureCachesToFontSet(fontSet) {
|
|
286
|
+
if (cachedFontSet === fontSet) return false;
|
|
287
|
+
clearAllCaches();
|
|
288
|
+
cachedFontSet = fontSet;
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Rename the font set the cached entries were measured in, without dropping
|
|
293
|
+
* them: for a layout run that has just measured, whose signature now also
|
|
294
|
+
* names the families it measured first. Only valid within the run that bound
|
|
295
|
+
* the caches with {@link syncMeasureCachesToFontSet}, since no face can load
|
|
296
|
+
* during a synchronous run.
|
|
297
|
+
*/
|
|
298
|
+
function labelMeasureCachesFontSet(fontSet) {
|
|
299
|
+
cachedFontSet = fontSet;
|
|
270
300
|
}
|
|
271
301
|
/**
|
|
272
302
|
* Get total size of all caches
|
|
@@ -275,4 +305,4 @@ function getTotalCacheSize() {
|
|
|
275
305
|
return getTextCacheSize() + getFontCacheSize() + getParagraphCacheSize();
|
|
276
306
|
}
|
|
277
307
|
//#endregion
|
|
278
|
-
export { clearAllCaches, clearFontMetricsCache, clearParagraphMeasureCache, clearTextWidthCache, getCachedFontMetrics, getCachedParagraphMeasure, getCachedTextWidth, getFontCacheSize, getParagraphCacheSize, getTextCacheSize, getTextWidthCacheGeneration, getTotalCacheSize, hashParagraphBlock, setCachedFontMetrics, setCachedParagraphMeasure, setCachedTextWidth, setFontCacheSize, setParagraphCacheSize, setTextCacheSize };
|
|
308
|
+
export { clearAllCaches, clearFontMetricsCache, clearParagraphMeasureCache, clearTextWidthCache, getCachedFontMetrics, getCachedParagraphMeasure, getCachedTextWidth, getFontCacheSize, getParagraphCacheSize, getTextCacheSize, getTextWidthCacheGeneration, getTotalCacheSize, hashParagraphBlock, labelMeasureCachesFontSet, setCachedFontMetrics, setCachedParagraphMeasure, setCachedTextWidth, setFontCacheSize, setParagraphCacheSize, setTextCacheSize, syncMeasureCachesToFontSet };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { countCodePoints } from "./measureWorkerProtocol.js";
|
|
2
2
|
import { TaggedError } from "better-result";
|
|
3
3
|
//#region src/layout-engine/measure/font-metrics.worker.ts
|
|
4
4
|
/**
|
|
@@ -36,16 +36,12 @@ function getCtx() {
|
|
|
36
36
|
ctx = next;
|
|
37
37
|
return ctx;
|
|
38
38
|
}
|
|
39
|
-
function isFontFingerprintMatch(context, expectedWidth) {
|
|
40
|
-
const actualWidth = context.measureText(WORKER_FONT_FINGERPRINT_TEXT).width;
|
|
41
|
-
const tolerance = Math.max(FONT_FINGERPRINT_EPSILON, expectedWidth * 1e-4);
|
|
42
|
-
return Math.abs(actualWidth - expectedWidth) <= tolerance;
|
|
43
|
-
}
|
|
44
39
|
function measureEntry(entry) {
|
|
45
40
|
const context = getCtx();
|
|
46
41
|
context.font = entry.font;
|
|
47
42
|
context.fontKerning = entry.fontKerning;
|
|
48
|
-
|
|
43
|
+
const actualFingerprintWidth = context.measureText(entry.fontFingerprintText).width;
|
|
44
|
+
if (Math.abs(actualFingerprintWidth - entry.fontFingerprintWidth) > FONT_FINGERPRINT_EPSILON) return null;
|
|
49
45
|
let width = context.measureText(entry.text).width;
|
|
50
46
|
const codePoints = countCodePoints(entry.text);
|
|
51
47
|
if (entry.letterSpacing !== 0 && codePoints > 1) width += entry.letterSpacing * (codePoints - 1);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { getHorizontalScaleFactor } from "../../utils/horizontalScale.js";
|
|
2
2
|
import { SCRIPT_CLASS, hasComplexScript, hasEastAsiaSlotText, scriptClassOf, segmentByScript } from "../../utils/scriptSegments.js";
|
|
3
|
-
import { getCachedFontMetrics, getCachedTextWidth,
|
|
3
|
+
import { getCachedFontMetrics, getCachedTextWidth, setCachedFontMetrics, setCachedTextWidth } from "./cache.js";
|
|
4
4
|
import { applyComplexScriptFormatting, hasComplexScriptFormatting } from "./complexScriptFormatting.js";
|
|
5
5
|
import { buildFontString, getResolvedData, ptToPx } from "./measureHelpers.js";
|
|
6
6
|
import { setMeasureProvider } from "./measureProvider.js";
|
|
7
7
|
import { canPrefetchMeasurement, prefetchMeasurement } from "./measureWorker.js";
|
|
8
|
-
import {
|
|
8
|
+
import { countCodePoints } from "./measureWorkerProtocol.js";
|
|
9
9
|
import { SMALL_CAPS_SCALE, smallCapsMask, smallCapsSegments } from "./smallCapsCasing.js";
|
|
10
10
|
import { getFontKerningMode } from "./textMeasurementPolicy.js";
|
|
11
11
|
import { panic } from "better-result";
|
|
@@ -31,7 +31,6 @@ const DEFAULT_LINE_HEIGHT_MULTIPLIER = 1;
|
|
|
31
31
|
const DEFAULT_ASCENT_RATIO = .8;
|
|
32
32
|
const DEFAULT_DESCENT_RATIO = .2;
|
|
33
33
|
let canvasContext = null;
|
|
34
|
-
const workerFontFingerprintCache = /* @__PURE__ */ new Map();
|
|
35
34
|
/**
|
|
36
35
|
* Get or create a canvas 2D context for text measurement
|
|
37
36
|
*/
|
|
@@ -50,19 +49,6 @@ function getCanvasContext() {
|
|
|
50
49
|
function resetCanvasContext() {
|
|
51
50
|
canvasContext = null;
|
|
52
51
|
}
|
|
53
|
-
function getWorkerFontFingerprintWidth(ctx, font, fontCacheKey, fontKerning) {
|
|
54
|
-
const generation = getTextWidthCacheGeneration();
|
|
55
|
-
const cached = workerFontFingerprintCache.get(fontCacheKey);
|
|
56
|
-
if (cached?.generation === generation) return cached.width;
|
|
57
|
-
ctx.font = font;
|
|
58
|
-
ctx.fontKerning = fontKerning;
|
|
59
|
-
const width = ctx.measureText(WORKER_FONT_FINGERPRINT_TEXT).width;
|
|
60
|
-
workerFontFingerprintCache.set(fontCacheKey, {
|
|
61
|
-
generation,
|
|
62
|
-
width
|
|
63
|
-
});
|
|
64
|
-
return width;
|
|
65
|
-
}
|
|
66
52
|
/**
|
|
67
53
|
* Get typography metrics for a given font size and family
|
|
68
54
|
*
|
|
@@ -149,7 +135,8 @@ function canvasMeasureTextWidth(text, sourceStyle) {
|
|
|
149
135
|
if (cached !== void 0) return cached;
|
|
150
136
|
ctx.font = font;
|
|
151
137
|
ctx.fontKerning = fontKerning;
|
|
152
|
-
|
|
138
|
+
const metrics = ctx.measureText(measuredText);
|
|
139
|
+
let width = metrics.width;
|
|
153
140
|
if (letterSpacing) {
|
|
154
141
|
const codePoints = countCodePoints(measuredText);
|
|
155
142
|
if (codePoints > 1) width += letterSpacing * (codePoints - 1);
|
|
@@ -157,17 +144,18 @@ function canvasMeasureTextWidth(text, sourceStyle) {
|
|
|
157
144
|
const scaledWidth = width * horizontalScale;
|
|
158
145
|
setCachedTextWidth(measuredText, fontCacheKey, letterSpacing, scaledWidth);
|
|
159
146
|
if (!canPrefetchMeasurement()) return scaledWidth;
|
|
160
|
-
const
|
|
147
|
+
const fontFingerprintText = measuredText;
|
|
148
|
+
const fontFingerprintWidth = metrics.width;
|
|
161
149
|
prefetchMeasurement({
|
|
162
150
|
text: measuredText,
|
|
163
151
|
font,
|
|
164
152
|
letterSpacing,
|
|
165
153
|
horizontalScale,
|
|
166
154
|
fontCacheKey,
|
|
155
|
+
fontFingerprintText,
|
|
167
156
|
fontFingerprintWidth,
|
|
168
157
|
fontKerning
|
|
169
158
|
});
|
|
170
|
-
prefetchBinarySearchProbes(measuredText, font, fontCacheKey, fontFingerprintWidth, letterSpacing, horizontalScale, fontKerning);
|
|
171
159
|
return scaledWidth;
|
|
172
160
|
}
|
|
173
161
|
/**
|
|
@@ -262,34 +250,6 @@ function measureSmallCapsWidth(measuredText, style) {
|
|
|
262
250
|
return width * horizontalScale;
|
|
263
251
|
}
|
|
264
252
|
/**
|
|
265
|
-
* Speculatively enqueue the slice lengths that a subsequent
|
|
266
|
-
* `findMaxFittingLength` binary search is likely to probe. We pick the
|
|
267
|
-
* geometric series (full, half, quarter, eighth) which covers the
|
|
268
|
-
* majority of probe points the binary search uses, without flooding
|
|
269
|
-
* the worker for runs that will never trigger a line break.
|
|
270
|
-
*
|
|
271
|
-
* The worker is racing the main thread here: if the main thread asks
|
|
272
|
-
* for slice(0, n/2) before the worker has answered, the cache miss
|
|
273
|
-
* pays the main-thread cost as usual. When the worker wins, that probe
|
|
274
|
-
* lands on a hit.
|
|
275
|
-
*/
|
|
276
|
-
function prefetchBinarySearchProbes(text, font, fontCacheKey, fontFingerprintWidth, letterSpacing, horizontalScale, fontKerning) {
|
|
277
|
-
if (text.length < 4) return;
|
|
278
|
-
for (let denom = 2; denom <= 8; denom *= 2) {
|
|
279
|
-
const len = Math.floor(text.length / denom);
|
|
280
|
-
if (len < 2) break;
|
|
281
|
-
prefetchMeasurement({
|
|
282
|
-
text: text.slice(0, len),
|
|
283
|
-
font,
|
|
284
|
-
letterSpacing,
|
|
285
|
-
horizontalScale,
|
|
286
|
-
fontCacheKey,
|
|
287
|
-
fontFingerprintWidth,
|
|
288
|
-
fontKerning
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
253
|
* Measure text and return full metrics
|
|
294
254
|
*/
|
|
295
255
|
function canvasMeasureText(text, style) {
|
|
@@ -34,6 +34,11 @@ type ResolvedFontCache = {
|
|
|
34
34
|
* Get the resolved font data for a font family, with caching.
|
|
35
35
|
*/
|
|
36
36
|
declare function getResolvedData(fontFamily: string, alternateFontFamily?: string): ResolvedFontCache;
|
|
37
|
+
/**
|
|
38
|
+
* Whether a face of `family` (a `FontFace.family`, possibly quoted) can change
|
|
39
|
+
* a width this page has measured.
|
|
40
|
+
*/
|
|
41
|
+
declare function isLayoutFontFamily(family: string): boolean;
|
|
37
42
|
/**
|
|
38
43
|
* Clear the resolved-font-family cache. `resolveFontFamily`'s output for a
|
|
39
44
|
* given key can change even when the raw font names don't — e.g. when the
|
|
@@ -100,4 +105,4 @@ declare function halfPtToPx(halfPt: number): number;
|
|
|
100
105
|
*/
|
|
101
106
|
declare function pxToHalfPt(px: number): number;
|
|
102
107
|
//#endregion
|
|
103
|
-
export { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, buildFontString, buildRunFontStyle, clearFontResolvedCache, docxScriptFontSize, findCharacterAtX, getResolvedData, getXForCharacter, halfPtToPx, ptToPx, pxToHalfPt, pxToPt, pxToTwips, twipsToPx };
|
|
108
|
+
export { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, buildFontString, buildRunFontStyle, clearFontResolvedCache, docxScriptFontSize, findCharacterAtX, getResolvedData, getXForCharacter, halfPtToPx, isLayoutFontFamily, ptToPx, pxToHalfPt, pxToPt, pxToTwips, twipsToPx };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveFontFamily } from "../../utils/fontResolver.js";
|
|
1
|
+
import { parseFontFamilyList, resolveFontFamily } from "../../utils/fontResolver.js";
|
|
2
2
|
import "../../utils/fontWeights.js";
|
|
3
3
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
4
4
|
import { eastAsiaHintApplies } from "../../utils/scriptSegments.js";
|
|
@@ -93,10 +93,30 @@ function getResolvedData(fontFamily, alternateFontFamily) {
|
|
|
93
93
|
singleLineRatio: resolved.singleLineRatio
|
|
94
94
|
};
|
|
95
95
|
fontResolvedCache.set(cacheKey, cached);
|
|
96
|
+
for (const family of parseFontFamilyList(resolved.cssFallback)) layoutFontFamilies.add(normalizeFontFamilyName(family));
|
|
96
97
|
}
|
|
97
98
|
return cached;
|
|
98
99
|
}
|
|
99
100
|
/**
|
|
101
|
+
* Every family a measured font stack has named on this page, normalized.
|
|
102
|
+
*
|
|
103
|
+
* Recorded where measurement resolves its stacks, so it is exactly the set of
|
|
104
|
+
* families whose faces can change a measured width: a face of any other family
|
|
105
|
+
* loading (the host's UI font, say) cannot. Never cleared, because a family
|
|
106
|
+
* stays relevant for as long as a cached or committed measurement may hold it,
|
|
107
|
+
* and the set is bounded by the families the page's documents name.
|
|
108
|
+
*/
|
|
109
|
+
const layoutFontFamilies = /* @__PURE__ */ new Set();
|
|
110
|
+
/** CSS family names match ASCII case-insensitively, quotes aside. */
|
|
111
|
+
const normalizeFontFamilyName = (family) => family.trim().replace(/^(["'])(.*)\1$/u, "$2").toLowerCase();
|
|
112
|
+
/**
|
|
113
|
+
* Whether a face of `family` (a `FontFace.family`, possibly quoted) can change
|
|
114
|
+
* a width this page has measured.
|
|
115
|
+
*/
|
|
116
|
+
function isLayoutFontFamily(family) {
|
|
117
|
+
return layoutFontFamilies.has(normalizeFontFamilyName(family));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
100
120
|
* Get the CSS fallback string for a font family, with caching.
|
|
101
121
|
*/
|
|
102
122
|
function getResolvedFallback(fontFamily, alternateFontFamily) {
|
|
@@ -207,4 +227,4 @@ function pxToHalfPt(px) {
|
|
|
207
227
|
return pxToPt(px) * 2;
|
|
208
228
|
}
|
|
209
229
|
//#endregion
|
|
210
|
-
export { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, buildFontString, buildRunFontStyle, clearFontResolvedCache, docxScriptFontSize, findCharacterAtX, getResolvedData, getXForCharacter, halfPtToPx, ptToPx, pxToHalfPt, pxToPt, pxToTwips, twipsToPx };
|
|
230
|
+
export { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, buildFontString, buildRunFontStyle, clearFontResolvedCache, docxScriptFontSize, findCharacterAtX, getResolvedData, getXForCharacter, halfPtToPx, isLayoutFontFamily, ptToPx, pxToHalfPt, pxToPt, pxToTwips, twipsToPx };
|
|
@@ -118,9 +118,8 @@ function ensureProxy() {
|
|
|
118
118
|
}
|
|
119
119
|
/**
|
|
120
120
|
* How long to wait before flushing the queue, in milliseconds. Short
|
|
121
|
-
* enough to
|
|
122
|
-
*
|
|
123
|
-
* paragraph's worth of probes.
|
|
121
|
+
* enough to process measured entries promptly, long enough to amortise
|
|
122
|
+
* `postMessage` overhead across a typical paragraph's runs.
|
|
124
123
|
*/
|
|
125
124
|
const FLUSH_INTERVAL_MS = 10;
|
|
126
125
|
/**
|
|
@@ -14,22 +14,21 @@ import { FontKerningMode } from "./textMeasurementPolicy.js";
|
|
|
14
14
|
* `fontCacheKey` is the main-thread cache identity. It intentionally
|
|
15
15
|
* differs from `font` when scale metadata is appended.
|
|
16
16
|
*
|
|
17
|
-
* `
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* poisoning the main-thread cache.
|
|
17
|
+
* `fontFingerprintText` is text already measured on the main thread in
|
|
18
|
+
* this font. The worker checks its unscaled width against
|
|
19
|
+
* `fontFingerprintWidth` before caching a result. This covers the actual
|
|
20
|
+
* glyphs and font subsets used by the request, including non-Latin text.
|
|
22
21
|
*/
|
|
23
22
|
type MeasureRequestEntry = {
|
|
24
23
|
text: string;
|
|
25
24
|
font: string;
|
|
26
25
|
fontCacheKey: string;
|
|
26
|
+
fontFingerprintText: string;
|
|
27
27
|
fontFingerprintWidth: number;
|
|
28
28
|
letterSpacing: number;
|
|
29
29
|
horizontalScale: number;
|
|
30
30
|
fontKerning: FontKerningMode;
|
|
31
31
|
};
|
|
32
|
-
declare const WORKER_FONT_FINGERPRINT_TEXT = "HAMBURGEFONTS ivwqy 0123456789";
|
|
33
32
|
/**
|
|
34
33
|
* Count whole code points (not UTF-16 units) so letter spacing is applied once
|
|
35
34
|
* per rendered glyph — an astral character is one glyph spanning two units.
|
|
@@ -73,4 +72,4 @@ type MeasureWorkerResponse = {
|
|
|
73
72
|
error: string;
|
|
74
73
|
};
|
|
75
74
|
//#endregion
|
|
76
|
-
export { MeasureRequestEntry, MeasureResponseEntry, MeasureWorkerRequest, MeasureWorkerResponse,
|
|
75
|
+
export { MeasureRequestEntry, MeasureResponseEntry, MeasureWorkerRequest, MeasureWorkerResponse, countCodePoints };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
//#region src/layout-engine/measure/measureWorkerProtocol.ts
|
|
2
|
-
const WORKER_FONT_FINGERPRINT_TEXT = "HAMBURGEFONTS ivwqy 0123456789";
|
|
3
2
|
/**
|
|
4
3
|
* Count whole code points (not UTF-16 units) so letter spacing is applied once
|
|
5
4
|
* per rendered glyph — an astral character is one glyph spanning two units.
|
|
@@ -17,4 +16,4 @@ function countCodePoints(text) {
|
|
|
17
16
|
return count;
|
|
18
17
|
}
|
|
19
18
|
//#endregion
|
|
20
|
-
export {
|
|
19
|
+
export { countCodePoints };
|
|
@@ -585,6 +585,12 @@ type ParagraphBlock = {
|
|
|
585
585
|
* the innermost group and draws boundary chrome per outer→inner level.
|
|
586
586
|
*/
|
|
587
587
|
sdtGroups?: SdtGroup[];
|
|
588
|
+
/**
|
|
589
|
+
* Set by a review view that lays out resolved text (Simple Markup) on a
|
|
590
|
+
* paragraph whose authored text carries a revision the view resolved: the
|
|
591
|
+
* painter marks it with the change bar its runs no longer show.
|
|
592
|
+
*/
|
|
593
|
+
reviewIndicator?: "change-bar";
|
|
588
594
|
};
|
|
589
595
|
/**
|
|
590
596
|
* Cell border specification for rendering.
|
|
@@ -1326,6 +1326,7 @@ function collectContentFingerprint(block, parts) {
|
|
|
1326
1326
|
if (block.kind === "paragraph") {
|
|
1327
1327
|
if (block.attrs?.styleId) parts.push(`p:st:${block.attrs.styleId}`);
|
|
1328
1328
|
if (block.attrs?.alignment) parts.push(`p:al:${block.attrs.alignment}`);
|
|
1329
|
+
if (block.reviewIndicator) parts.push(`p:ri:${block.reviewIndicator}`);
|
|
1329
1330
|
for (let index = 0; index < block.runs.length; index++) {
|
|
1330
1331
|
const run = block.runs[index];
|
|
1331
1332
|
if (!run) continue;
|
|
@@ -1500,7 +1500,7 @@ function bordersFormGroup(a, b) {
|
|
|
1500
1500
|
if (!a || !b) return false;
|
|
1501
1501
|
return bordersEqual(a.top, b.top) && bordersEqual(a.bottom, b.bottom) && bordersEqual(a.left, b.left) && bordersEqual(a.right, b.right) && bordersEqual(a.between, b.between);
|
|
1502
1502
|
}
|
|
1503
|
-
const paragraphHasTrackedChanges = (block) => block.attrs?.listMarkerRevision !== void 0 || block.runs.some((run) => run.kind !== "lineBreak" && (run.isInsertion === true || run.isDeletion === true));
|
|
1503
|
+
const paragraphHasTrackedChanges = (block) => block.reviewIndicator === "change-bar" || block.attrs?.listMarkerRevision !== void 0 || block.runs.some((run) => run.kind !== "lineBreak" && (run.isInsertion === true || run.isDeletion === true));
|
|
1504
1504
|
/**
|
|
1505
1505
|
* Render a paragraph fragment
|
|
1506
1506
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isInTable as isInTableCell } from "../prosemirror/extensions/nodes/TableExtension.js";
|
|
2
|
+
import { NO_LIST_NUMBERING_MENU, listNumberingMenuState } from "../prosemirror/listNumbering.js";
|
|
2
3
|
import { Subscribable } from "./Subscribable.js";
|
|
3
4
|
//#region src/managers/ContextMenuManager.ts
|
|
4
5
|
const CLOSED_STATE = {
|
|
@@ -13,7 +14,8 @@ const CLOSED_STATE = {
|
|
|
13
14
|
to: 0
|
|
14
15
|
},
|
|
15
16
|
cursorInTable: false,
|
|
16
|
-
cursorInTrackedChange: false
|
|
17
|
+
cursorInTrackedChange: false,
|
|
18
|
+
listNumbering: NO_LIST_NUMBERING_MENU
|
|
17
19
|
};
|
|
18
20
|
var ContextMenuManager = class extends Subscribable {
|
|
19
21
|
constructor() {
|
|
@@ -36,7 +38,8 @@ var ContextMenuManager = class extends Subscribable {
|
|
|
36
38
|
to: selection.to
|
|
37
39
|
},
|
|
38
40
|
cursorInTable,
|
|
39
|
-
cursorInTrackedChange
|
|
41
|
+
cursorInTrackedChange,
|
|
42
|
+
listNumbering: state ? listNumberingMenuState(state) : NO_LIST_NUMBERING_MENU
|
|
40
43
|
});
|
|
41
44
|
}
|
|
42
45
|
/** Close the menu. */
|
package/dist/managers/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ListNumberingMenuState } from "../prosemirror/listNumbering.js";
|
|
1
2
|
//#region src/managers/types.d.ts
|
|
2
3
|
/** Cell coordinates in a table */
|
|
3
4
|
type CellCoordinates = {
|
|
@@ -21,6 +22,8 @@ type ContextMenuSnapshot = {
|
|
|
21
22
|
};
|
|
22
23
|
cursorInTable: boolean;
|
|
23
24
|
cursorInTrackedChange: boolean;
|
|
25
|
+
/** Restart / continue / set-value entries for the list item under the caret. */
|
|
26
|
+
listNumbering: ListNumberingMenuState;
|
|
24
27
|
};
|
|
25
28
|
/** Error severity levels */
|
|
26
29
|
type ErrorSeverity = "error" | "warning" | "info";
|
|
@@ -36,9 +36,10 @@ const applyMarkdownPageGeometry = (document) => {
|
|
|
36
36
|
*/
|
|
37
37
|
function fromMarkdown(markdown) {
|
|
38
38
|
const document = createEmptyDocument();
|
|
39
|
-
const { content, numbering } = compileMarkdownToContent(markdown);
|
|
39
|
+
const { content, numbering, warnings } = compileMarkdownToContent(markdown);
|
|
40
40
|
if (content.length > 0) document.package.document.content = content;
|
|
41
41
|
if (numbering) document.package.numbering = numbering;
|
|
42
|
+
if (warnings && warnings.length > 0) document.warnings = [...document.warnings ?? [], ...warnings];
|
|
42
43
|
applyMarkdownPageGeometry(document);
|
|
43
44
|
return document;
|
|
44
45
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { NoteReferenceKind } from "../utils/noteReferenceLabels.js";
|
|
2
3
|
import { MarkdownOptions, RenderContext } from "./types.js";
|
|
3
4
|
//#region src/markdown/internals.d.ts
|
|
4
5
|
/**
|
|
@@ -15,5 +16,14 @@ declare function newContext(opts?: MarkdownOptions, styles?: document_d_exports.
|
|
|
15
16
|
* recurring messages appear at most once.
|
|
16
17
|
*/
|
|
17
18
|
declare function pushWarning(ctx: RenderContext, message: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Number a footnote or endnote reference in reading order and record its
|
|
21
|
+
* note for the definitions trailer on the note's first reference. Returns the
|
|
22
|
+
* bare token (`1`, `e1`) and the inline marker (`[^1]`, `[^e1]`).
|
|
23
|
+
*/
|
|
24
|
+
declare function numberNoteReference(ctx: RenderContext, kind: NoteReferenceKind, refId: number): {
|
|
25
|
+
token: string;
|
|
26
|
+
marker: string;
|
|
27
|
+
};
|
|
18
28
|
//#endregion
|
|
19
|
-
export { newContext, pushWarning };
|
|
29
|
+
export { newContext, numberNoteReference, pushWarning };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createBuiltInStyleIndex } from "../docx/builtInStyles.js";
|
|
2
|
+
import { createListLabelCounter } from "../prosemirror/listLabels.js";
|
|
3
|
+
import { createNoteReferenceNumbering, noteReferenceMarker, noteReferenceToken } from "../utils/noteReferenceLabels.js";
|
|
2
4
|
//#region src/markdown/internals.ts
|
|
3
5
|
/**
|
|
4
6
|
* Internal helpers shared by the markdown converter: context construction and
|
|
@@ -30,11 +32,12 @@ function newContext(opts = {}, styles) {
|
|
|
30
32
|
imagesByPath: /* @__PURE__ */ new Map(),
|
|
31
33
|
warnings: [],
|
|
32
34
|
footnoteRefs: [],
|
|
35
|
+
noteNumbering: createNoteReferenceNumbering(),
|
|
33
36
|
commentRefs: [],
|
|
34
37
|
hyperlinkRefs: [],
|
|
35
38
|
imageCounter: 0,
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
nextListLabel: createListLabelCounter(),
|
|
40
|
+
listIndentWidths: []
|
|
38
41
|
};
|
|
39
42
|
}
|
|
40
43
|
/**
|
|
@@ -44,5 +47,23 @@ function newContext(opts = {}, styles) {
|
|
|
44
47
|
function pushWarning(ctx, message) {
|
|
45
48
|
if (!ctx.warnings.includes(message)) ctx.warnings.push(message);
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Number a footnote or endnote reference in reading order and record its
|
|
52
|
+
* note for the definitions trailer on the note's first reference. Returns the
|
|
53
|
+
* bare token (`1`, `e1`) and the inline marker (`[^1]`, `[^e1]`).
|
|
54
|
+
*/
|
|
55
|
+
function numberNoteReference(ctx, kind, refId) {
|
|
56
|
+
const { displayNumber, first } = ctx.noteNumbering.next(kind, refId);
|
|
57
|
+
const marker = noteReferenceMarker(kind, displayNumber);
|
|
58
|
+
if (first) ctx.footnoteRefs.push({
|
|
59
|
+
refId,
|
|
60
|
+
marker,
|
|
61
|
+
kind
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
token: noteReferenceToken(kind, displayNumber),
|
|
65
|
+
marker
|
|
66
|
+
};
|
|
67
|
+
}
|
|
47
68
|
//#endregion
|
|
48
|
-
export { newContext, pushWarning };
|
|
69
|
+
export { newContext, numberNoteReference, pushWarning };
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { ALT_CHUNK_READER_DIAGNOSTIC, isAltChunkMarkup } from "../docx/altChunk.js";
|
|
2
|
+
import { OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC, isOpaqueNestedRowMarkup, opaqueRevisionCarrierName } from "../docx/opaqueCarrier.js";
|
|
1
3
|
import { cloneParagraphWithoutPropertySource } from "../docx/paragraphPropertySource.js";
|
|
2
|
-
import {
|
|
4
|
+
import { renderParagraphBlock } from "./renderParagraph.js";
|
|
3
5
|
import { renderTable } from "./renderTable.js";
|
|
4
6
|
import { panic } from "better-result";
|
|
5
7
|
//#region src/markdown/renderBlock.ts
|
|
@@ -14,9 +16,12 @@ import { panic } from "better-result";
|
|
|
14
16
|
* its break on accept and merges with the following paragraph. Word's join
|
|
15
17
|
* keeps the FIRST paragraph's properties (style, list) and drops the resolved
|
|
16
18
|
* mark; the surviving break is the next paragraph's, so a run of consecutive
|
|
17
|
-
* deletions collapses into one paragraph. A
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* deletions collapses into one paragraph. A first paragraph with nothing left
|
|
20
|
+
* once its deletions are accepted (a whole deleted paragraph) contributes only
|
|
21
|
+
* the join, so the NEXT paragraph keeps its own properties, as the editor's
|
|
22
|
+
* accept does. A non-paragraph next block (table, SDT) is structurally
|
|
23
|
+
* incompatible and stays unmerged, matching the editor's accept-change join
|
|
24
|
+
* guard (`commands/comments.ts`).
|
|
20
25
|
*/
|
|
21
26
|
function mergeAcceptedParagraphBreaks(blocks) {
|
|
22
27
|
const merged = [];
|
|
@@ -24,8 +29,9 @@ function mergeAcceptedParagraphBreaks(blocks) {
|
|
|
24
29
|
const prev = merged.at(-1);
|
|
25
30
|
if (prev?.type === "paragraph" && prev.pPrMark?.kind === "del" && block.type === "paragraph") {
|
|
26
31
|
const next = block.pPrMark;
|
|
27
|
-
const
|
|
28
|
-
|
|
32
|
+
const content = [...prev.content, ...block.content];
|
|
33
|
+
const joined = cloneParagraphWithoutPropertySource(holdsNothingOnAccept(prev) ? block : prev, {
|
|
34
|
+
content,
|
|
29
35
|
...next ? { pPrMark: next } : {}
|
|
30
36
|
});
|
|
31
37
|
if (!next) Reflect.deleteProperty(joined, "pPrMark");
|
|
@@ -36,14 +42,33 @@ function mergeAcceptedParagraphBreaks(blocks) {
|
|
|
36
42
|
}
|
|
37
43
|
return merged;
|
|
38
44
|
}
|
|
45
|
+
/** Paragraph content that shows nothing: range boundaries and anchors. */
|
|
46
|
+
const ZERO_WIDTH_CONTENT = /* @__PURE__ */ new Set([
|
|
47
|
+
"bookmarkStart",
|
|
48
|
+
"bookmarkEnd",
|
|
49
|
+
"commentRangeStart",
|
|
50
|
+
"commentRangeEnd",
|
|
51
|
+
"commentReference",
|
|
52
|
+
"moveFromRangeStart",
|
|
53
|
+
"moveFromRangeEnd",
|
|
54
|
+
"moveToRangeStart",
|
|
55
|
+
"moveToRangeEnd"
|
|
56
|
+
]);
|
|
57
|
+
/** Whether an item shows nothing once every change is accepted. */
|
|
58
|
+
const showsNothingOnAccept = (item) => {
|
|
59
|
+
if (item.type === "deletion" || item.type === "moveFrom" || ZERO_WIDTH_CONTENT.has(item.type)) return true;
|
|
60
|
+
if (item.type === "insertion" || item.type === "moveTo") return item.content.every(showsNothingOnAccept);
|
|
61
|
+
return item.type === "run" && item.content.every((content) => content.type === "renderedPageBreak");
|
|
62
|
+
};
|
|
63
|
+
/** Whether a paragraph keeps no visible content once every change is accepted. */
|
|
64
|
+
const holdsNothingOnAccept = (paragraph) => paragraph.content.every(showsNothingOnAccept);
|
|
39
65
|
function renderBlocks(ctx, pkg, blocks) {
|
|
40
66
|
const out = [];
|
|
41
67
|
let prevWasListItem = false;
|
|
42
68
|
const ordered = ctx.opts.trackedChanges === "clean" ? mergeAcceptedParagraphBreaks(blocks) : blocks;
|
|
43
69
|
for (const block of ordered) switch (block.type) {
|
|
44
70
|
case "paragraph": {
|
|
45
|
-
const isListItem =
|
|
46
|
-
const md = renderParagraph(ctx, pkg, block);
|
|
71
|
+
const { markdown: md, isListItem } = renderParagraphBlock(ctx, pkg, block);
|
|
47
72
|
if (!md) {
|
|
48
73
|
prevWasListItem = false;
|
|
49
74
|
continue;
|
|
@@ -63,7 +88,8 @@ function renderBlocks(ctx, pkg, blocks) {
|
|
|
63
88
|
prevWasListItem = false;
|
|
64
89
|
break;
|
|
65
90
|
}
|
|
66
|
-
case "blockSdt":
|
|
91
|
+
case "blockSdt":
|
|
92
|
+
case "blockCustomXml": {
|
|
67
93
|
const nested = renderBlocks(ctx, pkg, block.content);
|
|
68
94
|
if (nested) {
|
|
69
95
|
if (out.length) out.push("");
|
|
@@ -72,6 +98,10 @@ function renderBlocks(ctx, pkg, blocks) {
|
|
|
72
98
|
break;
|
|
73
99
|
}
|
|
74
100
|
case "preservedBlock":
|
|
101
|
+
if (isAltChunkMarkup(block.xml)) out.push(block.readerText === void 0 ? ALT_CHUNK_READER_DIAGNOSTIC : `${ALT_CHUNK_READER_DIAGNOSTIC}\n\n${block.readerText}`);
|
|
102
|
+
else if (opaqueRevisionCarrierName(block.xml) !== void 0) out.push(OPAQUE_REVISION_CARRIER_READER_DIAGNOSTIC);
|
|
103
|
+
else if (isOpaqueNestedRowMarkup(block.xml)) out.push("[Unsupported nested w:tr content]");
|
|
104
|
+
break;
|
|
75
105
|
case "bookmarkStart":
|
|
76
106
|
case "bookmarkEnd": break;
|
|
77
107
|
default: panic(`Unsupported block content in markdown: ${JSON.stringify(block)}`);
|