@stll/folio-core 0.47.7 → 0.49.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/dist/ai-edits/apply.js +565 -121
- package/dist/ai-edits/minimal-replacement.d.ts +64 -0
- package/dist/ai-edits/minimal-replacement.js +282 -0
- package/dist/controller/fontReadiness.js +3 -3
- package/dist/controller/hyphenationReadiness.d.ts +19 -0
- package/dist/controller/hyphenationReadiness.js +47 -0
- package/dist/controller/layoutPipeline.d.ts +3 -0
- package/dist/controller/layoutPipeline.js +70 -18
- package/dist/display-list/build/buildDisplayList.js +39 -12
- package/dist/display-list/build/pageFurniture.d.ts +7 -1
- package/dist/display-list/build/pageFurniture.js +21 -8
- package/dist/display-list/build/paragraphPrimitives.js +68 -11
- package/dist/display-list/build/tablePrimitives.js +10 -6
- package/dist/display-list/build/textBoxPrimitives.js +1 -1
- package/dist/display-list/build/unsupported.d.ts +2 -2
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/dom/renderDisplayListToDom.js +0 -1
- package/dist/docx/attributeRemainder.js +10 -2
- package/dist/docx/blockContentParser.d.ts +2 -0
- package/dist/docx/blockContentParser.js +79 -64
- package/dist/docx/bulletMarkers.d.ts +18 -2
- package/dist/docx/bulletMarkers.js +27 -2
- package/dist/docx/commentParser.d.ts +2 -1
- package/dist/docx/commentParser.js +57 -45
- package/dist/docx/containerChildren.d.ts +21 -8
- package/dist/docx/containerChildren.js +39 -9
- package/dist/docx/documentParser.d.ts +5 -1
- package/dist/docx/documentParser.js +8 -5
- package/dist/docx/documentSectionFacts.d.ts +22 -0
- package/dist/docx/documentSectionFacts.js +43 -0
- package/dist/docx/drawingGroupChildren.d.ts +60 -0
- package/dist/docx/drawingGroupChildren.js +176 -0
- package/dist/docx/drawingUtils.js +3 -0
- package/dist/docx/fieldParser.d.ts +8 -1
- package/dist/docx/fieldParser.js +47 -3
- package/dist/docx/fontTableParser.js +34 -27
- package/dist/docx/footnoteParser.d.ts +3 -2
- package/dist/docx/footnoteParser.js +15 -12
- package/dist/docx/groupDrawingParser.d.ts +9 -2
- package/dist/docx/groupDrawingParser.js +125 -37
- package/dist/docx/headerFooterParser.d.ts +7 -2
- package/dist/docx/headerFooterParser.js +15 -5
- package/dist/docx/hyperlinkParser.d.ts +48 -36
- package/dist/docx/hyperlinkParser.js +97 -82
- package/dist/docx/numberingParser.js +108 -84
- package/dist/docx/packageParts.d.ts +45 -1
- package/dist/docx/packageParts.js +93 -2
- package/dist/docx/paraIdAttribute.d.ts +3 -2
- package/dist/docx/paragraphParser.d.ts +5 -1
- package/dist/docx/paragraphParser.js +468 -365
- package/dist/docx/paragraphProperties.js +123 -109
- package/dist/docx/paragraphPropertySource.d.ts +6 -1
- package/dist/docx/paragraphPropertySource.js +9 -1
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +143 -10
- package/dist/docx/parser.d.ts +7 -1
- package/dist/docx/parser.js +33 -16
- package/dist/docx/previewBudget.d.ts +55 -33
- package/dist/docx/previewBudget.js +59 -65
- package/dist/docx/rezip.js +41 -58
- package/dist/docx/runParser.d.ts +4 -1
- package/dist/docx/runParser.js +182 -184
- package/dist/docx/sdtProperties.js +87 -84
- package/dist/docx/sectionParser.js +169 -160
- package/dist/docx/selectiveSaveFlags.d.ts +10 -3
- package/dist/docx/selectiveSaveFlags.js +1 -1
- package/dist/docx/selectiveXmlPatch.d.ts +56 -34
- package/dist/docx/selectiveXmlPatch.js +222 -115
- package/dist/docx/serializer/groupTextBoxWriteBack.d.ts +12 -0
- package/dist/docx/serializer/groupTextBoxWriteBack.js +101 -0
- package/dist/docx/serializer/paragraphSerializer.js +47 -42
- package/dist/docx/serializer/runSerializer.d.ts +5 -1
- package/dist/docx/serializer/runSerializer.js +4 -3
- package/dist/docx/serializer/settingsSerializer.js +19 -1
- package/dist/docx/settingsParser.js +8 -0
- package/dist/docx/shapeAlternateContent.d.ts +25 -0
- package/dist/docx/shapeAlternateContent.js +52 -0
- package/dist/docx/streamingXmlParser.d.ts +6 -2
- package/dist/docx/streamingXmlParser.js +12 -7
- package/dist/docx/styleParser.js +34 -8
- package/dist/docx/tableParser.d.ts +21 -12
- package/dist/docx/tableParser.js +518 -441
- package/dist/docx/textBoxParser.d.ts +18 -5
- package/dist/docx/textBoxParser.js +12 -6
- package/dist/docx/verbatimCapture.d.ts +10 -8
- package/dist/docx/verbatimCapture.js +45 -2
- package/dist/docx/vmlImageParser.d.ts +15 -13
- package/dist/docx/vmlImageParser.js +75 -60
- package/dist/docx/vmlPreview.d.ts +3 -3
- package/dist/docx/vmlPreview.js +3 -4
- package/dist/docx/xmlNamespaceContext.d.ts +9 -0
- package/dist/docx/xmlNamespaceContext.js +54 -0
- package/dist/docx/xmlParser.d.ts +6 -3
- package/dist/docx/xmlParser.js +11 -41
- package/dist/docx/xmlResourceLimits.d.ts +2 -1
- package/dist/docx/xmlResourceLimits.js +4 -1
- package/dist/fonts/headlessMeasure.js +0 -0
- package/dist/headless-layout.d.ts +11 -2
- package/dist/headless-layout.js +153 -107
- package/dist/internal/headlessRevisionResolution.js +50 -13
- package/dist/internal/paragraphFormattingSerialization.js +3 -3
- package/dist/layout-bridge/convert/endnoteLayout.d.ts +65 -0
- package/dist/layout-bridge/convert/endnoteLayout.js +227 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +19 -3
- package/dist/layout-bridge/convert/footnoteLayout.js +40 -31
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -7
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -20
- package/dist/layout-bridge/convert/paragraphMarkFormatting.d.ts +10 -0
- package/dist/layout-bridge/convert/paragraphMarkFormatting.js +59 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +29 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +284 -39
- package/dist/layout-bridge/engine/hitTest.js +5 -3
- package/dist/layout-bridge/engine/selectionRects.js +5 -3
- package/dist/layout-engine/anchorLayoutInCellCompatibility.d.ts +10 -0
- package/dist/layout-engine/anchorLayoutInCellCompatibility.js +22 -0
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +102 -14
- package/dist/layout-engine/justificationCompatibility.d.ts +1 -1
- package/dist/layout-engine/justificationCompatibility.js +9 -5
- package/dist/layout-engine/keep-together.d.ts +15 -6
- package/dist/layout-engine/keep-together.js +43 -16
- package/dist/layout-engine/layoutInstrumentation.d.ts +8 -2
- package/dist/layout-engine/layoutInstrumentation.js +8 -1
- package/dist/layout-engine/measure/advanceComposition.js +50 -7
- package/dist/layout-engine/measure/hyphenationDictionaries.d.ts +74 -0
- package/dist/layout-engine/measure/hyphenationDictionaries.js +138 -0
- package/dist/layout-engine/measure/hyphenationPreload.d.ts +11 -0
- package/dist/layout-engine/measure/hyphenationPreload.js +24 -0
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +12 -2
- package/dist/layout-engine/measure/lineBreakProvider.js +30 -30
- package/dist/layout-engine/measure/lineBreaks.d.ts +6 -1
- package/dist/layout-engine/measure/lineBreaks.js +10 -3
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +9 -6
- package/dist/layout-engine/measure/listMarkerWidth.js +20 -22
- package/dist/layout-engine/measure/measureBlocks.js +46 -10
- package/dist/layout-engine/measure/measureContainer.js +51 -8
- package/dist/layout-engine/measure/measureHelpers.d.ts +15 -3
- package/dist/layout-engine/measure/measureHelpers.js +34 -8
- package/dist/layout-engine/measure/measureParagraph.js +143 -101
- package/dist/layout-engine/measure/measureTypes.d.ts +5 -0
- package/dist/layout-engine/measure/smallCapsCasing.d.ts +56 -0
- package/dist/layout-engine/measure/smallCapsCasing.js +88 -0
- package/dist/layout-engine/measure/tabCalculator.d.ts +2 -0
- package/dist/layout-engine/measure/tabCalculator.js +2 -1
- package/dist/layout-engine/measure/tableCellFloating.d.ts +2 -0
- package/dist/layout-engine/measure/tableCellFloating.js +51 -19
- package/dist/layout-engine/measure/tableCellGrid.d.ts +28 -3
- package/dist/layout-engine/measure/tableCellGrid.js +45 -5
- package/dist/layout-engine/measure/tableFragmentBorderGeometry.js +2 -1
- package/dist/layout-engine/noteAreaFlow.d.ts +19 -0
- package/dist/layout-engine/noteAreaFlow.js +83 -0
- package/dist/layout-engine/paginator.d.ts +12 -1
- package/dist/layout-engine/paginator.js +18 -2
- package/dist/layout-engine/paragraphSpacing.d.ts +4 -2
- package/dist/layout-engine/paragraphSpacing.js +2 -1
- package/dist/layout-engine/tableRowBreak.d.ts +8 -1
- package/dist/layout-engine/tableRowBreak.js +25 -2
- package/dist/layout-engine/types.d.ts +108 -3
- package/dist/layout-engine/types.js +96 -1
- package/dist/layout-painter/index.d.ts +3 -0
- package/dist/layout-painter/renderPage.js +32 -83
- package/dist/layout-painter/renderParagraph.d.ts +6 -1
- package/dist/layout-painter/renderParagraph.js +75 -26
- package/dist/layout-painter/renderTable.js +26 -13
- package/dist/layout-painter/renderTextBox.d.ts +12 -2
- package/dist/layout-painter/renderTextBox.js +26 -2
- package/dist/prosemirror/alternateContentAttrs.d.ts +9 -0
- package/dist/prosemirror/alternateContentAttrs.js +35 -0
- package/dist/prosemirror/attrs/index.d.ts +9 -9
- package/dist/prosemirror/attrs/index.js +133 -11
- package/dist/prosemirror/commands/comments.js +51 -41
- package/dist/prosemirror/contentControlRevisions.d.ts +43 -0
- package/dist/prosemirror/contentControlRevisions.js +84 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +54 -23
- package/dist/prosemirror/conversion/markInterner.d.ts +21 -0
- package/dist/prosemirror/conversion/markInterner.js +90 -0
- package/dist/prosemirror/conversion/toProseDoc.js +117 -58
- package/dist/prosemirror/extensions/core/DocExtension.js +2 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +7 -7
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -7
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +6 -2
- package/dist/prosemirror/extensions/marks/markUtils.js +39 -51
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +6 -3
- package/dist/prosemirror/extensions/nodes/SdtExtension.js +9 -2
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +5 -1
- package/dist/prosemirror/listMarker.d.ts +1 -0
- package/dist/prosemirror/listMarker.js +4 -2
- package/dist/prosemirror/listRenderingAttrs.d.ts +1 -0
- package/dist/prosemirror/listRenderingAttrs.js +3 -0
- package/dist/prosemirror/paragraphDirection.d.ts +29 -2
- package/dist/prosemirror/paragraphDirection.js +21 -2
- package/dist/prosemirror/plugins/suggestionMode.js +37 -8
- package/dist/prosemirror/rejoinRunCarriers.d.ts +27 -0
- package/dist/prosemirror/rejoinRunCarriers.js +66 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +10 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.js +90 -0
- package/dist/prosemirror/schema/nodes.d.ts +50 -6
- package/dist/prosemirror/textBoxHostParagraph.d.ts +13 -0
- package/dist/prosemirror/textBoxHostParagraph.js +21 -0
- package/dist/prosemirror/validation.js +91 -80
- package/dist/types/content.d.ts +2 -2
- package/dist/utils/createDocument.js +10 -1
- package/dist/utils/scriptSegments.d.ts +33 -4
- package/dist/utils/scriptSegments.js +39 -6
- package/dist/utils/textFormattingMerge.d.ts +17 -3
- package/dist/utils/textFormattingMerge.js +18 -12
- package/dist/utils/trailingText.d.ts +22 -0
- package/dist/utils/trailingText.js +32 -0
- package/package.json +2 -2
- package/dist/layout-engine/justifiedLineFit.d.ts +0 -7
- package/dist/layout-engine/justifiedLineFit.js +0 -6
|
@@ -4,7 +4,8 @@ import { evaluateFieldInstruction } from "../fields/evaluateField.js";
|
|
|
4
4
|
import { applyComplexScriptFormatting, hasComplexScriptFormatting, resolveComplexScriptFormatting } from "../layout-engine/measure/complexScriptFormatting.js";
|
|
5
5
|
import { getHyperlinkInstanceIndex } from "../layout-engine/measure/hyperlinkInstance.js";
|
|
6
6
|
import { getListMarkerInlineWidth, getListMarkerVisualOffset, resolveListMarkerFont } from "../layout-engine/measure/listMarkerWidth.js";
|
|
7
|
-
import {
|
|
7
|
+
import { DEFAULT_FONT_FAMILY, docxScriptFontSize } from "../layout-engine/measure/measureHelpers.js";
|
|
8
|
+
import { SMALL_CAPS_SCALE, smallCapsSegments } from "../layout-engine/measure/smallCapsCasing.js";
|
|
8
9
|
import { calculateTabWidth } from "../layout-engine/measure/tabCalculator.js";
|
|
9
10
|
import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode, toPaintedText } from "../layout-engine/measure/textMeasurementPolicy.js";
|
|
10
11
|
import { isFloatingImageRun } from "../layout-engine/types.js";
|
|
@@ -17,7 +18,8 @@ import { getHorizontalScaleFactor } from "../utils/horizontalScale.js";
|
|
|
17
18
|
import { resolvePhysicalParagraphInlineLayout } from "../utils/paragraphInlineLayout.js";
|
|
18
19
|
import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
|
|
19
20
|
import { sanitizeImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
20
|
-
import { SCRIPT_CLASS,
|
|
21
|
+
import { SCRIPT_CLASS, eastAsiaHintApplies, hasComplexScript, hasEastAsiaSlotText, segmentByScript } from "../utils/scriptSegments.js";
|
|
22
|
+
import { trailingSpaceStart } from "../utils/trailingText.js";
|
|
21
23
|
import { anchorTargetAttrs, sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
22
24
|
import { borderStrokeToCss, resolveParagraphBorderHorizontalOutsets } from "./borderStroke.js";
|
|
23
25
|
import { planCursiveJoiners, withCursiveJoiners } from "./cursiveJoiners.js";
|
|
@@ -146,6 +148,14 @@ function getRenderableTextColor(run) {
|
|
|
146
148
|
if (!shouldRenderTextColor(textColor, run.highlight, run.textColorSource)) return;
|
|
147
149
|
return textColor.trim();
|
|
148
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* The colour a list marker paints in, or undefined for the canvas text colour.
|
|
153
|
+
* Black and `auto` fall back to the canvas colour, as they do for runs.
|
|
154
|
+
*/
|
|
155
|
+
function getRenderableListMarkerColor(color) {
|
|
156
|
+
if (!color || isAutomaticTextColor(color) || isDefaultBlackTextColor(color)) return;
|
|
157
|
+
return color.trim();
|
|
158
|
+
}
|
|
149
159
|
function getHyperlinkTextColor(run, inheritedColor) {
|
|
150
160
|
const textColor = run.color?.trim();
|
|
151
161
|
if (textColor && !isAutomaticTextColor(textColor) && run.textColorSource === "direct") return textColor;
|
|
@@ -155,8 +165,7 @@ function fontSizePtToPx(fontSizePt) {
|
|
|
155
165
|
return fontSizePt * 96 / 72;
|
|
156
166
|
}
|
|
157
167
|
function getRaisedRunFontSize(run) {
|
|
158
|
-
|
|
159
|
-
return `${DOCX_SCRIPT_FONT_SCALE}em`;
|
|
168
|
+
return `${fontSizePtToPx(docxScriptFontSize(run.fontSize || 11))}px`;
|
|
160
169
|
}
|
|
161
170
|
function applyHorizontalScaleTransform(element, horizontalScale) {
|
|
162
171
|
const horizontalScaleFactor = getHorizontalScaleFactor(horizontalScale);
|
|
@@ -193,7 +202,6 @@ function applyRunStyles(element, run) {
|
|
|
193
202
|
}
|
|
194
203
|
if (run.letterSpacing) element.style.letterSpacing = `${run.letterSpacing}px`;
|
|
195
204
|
if (run.allCaps) element.style.textTransform = "uppercase";
|
|
196
|
-
if (run.smallCaps) element.style.fontVariant = "small-caps";
|
|
197
205
|
if (run.positionPx) element.style.verticalAlign = `${run.positionPx}px`;
|
|
198
206
|
applyHorizontalScaleTransform(element, run.horizontalScale);
|
|
199
207
|
element.style.fontKerning = getRunFontKerningMode(run, 11);
|
|
@@ -330,7 +338,8 @@ function applyPmPositions(element, pmStart, pmEnd) {
|
|
|
330
338
|
}
|
|
331
339
|
const NON_COMPRESSIBLE_WHITESPACE_PATTERN = /([^\S ]+)/gu;
|
|
332
340
|
const HAS_NON_COMPRESSIBLE_WHITESPACE_PATTERN = /[^\S ]/u;
|
|
333
|
-
|
|
341
|
+
/** Fill `host` with `text`, splitting it into word-spacing segments as needed. */
|
|
342
|
+
function fillPaintedText({ host, text, doc, contractedWordSpacing }) {
|
|
334
343
|
if (!contractedWordSpacing) {
|
|
335
344
|
host.textContent = text;
|
|
336
345
|
return;
|
|
@@ -349,6 +358,39 @@ function appendPaintedText({ host, text, doc, contractedWordSpacing }) {
|
|
|
349
358
|
host.append(segmentEl);
|
|
350
359
|
}
|
|
351
360
|
}
|
|
361
|
+
function appendPaintedText({ host, text, doc, contractedWordSpacing, smallCapsFontSizePx }) {
|
|
362
|
+
const wordSpacing = contractedWordSpacing === void 0 ? {} : { contractedWordSpacing };
|
|
363
|
+
if (smallCapsFontSizePx === void 0) {
|
|
364
|
+
fillPaintedText({
|
|
365
|
+
host,
|
|
366
|
+
text,
|
|
367
|
+
doc,
|
|
368
|
+
...wordSpacing
|
|
369
|
+
});
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const segments = smallCapsSegments(text);
|
|
373
|
+
if (!segments.some((segment) => segment.small)) {
|
|
374
|
+
fillPaintedText({
|
|
375
|
+
host,
|
|
376
|
+
text,
|
|
377
|
+
doc,
|
|
378
|
+
...wordSpacing
|
|
379
|
+
});
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
for (const segment of segments) {
|
|
383
|
+
const segmentEl = doc.createElement("span");
|
|
384
|
+
if (segment.small) segmentEl.style.fontSize = `${smallCapsFontSizePx}px`;
|
|
385
|
+
fillPaintedText({
|
|
386
|
+
host: segmentEl,
|
|
387
|
+
text: segment.text,
|
|
388
|
+
doc,
|
|
389
|
+
...wordSpacing
|
|
390
|
+
});
|
|
391
|
+
host.append(segmentEl);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
352
394
|
function renderTextRun(run, doc, options) {
|
|
353
395
|
const span = doc.createElement("span");
|
|
354
396
|
span.className = `${PARAGRAPH_CLASS_NAMES.run} ${PARAGRAPH_CLASS_NAMES.text}`;
|
|
@@ -366,6 +408,7 @@ function renderTextRun(run, doc, options) {
|
|
|
366
408
|
applyRunStyles(span, run);
|
|
367
409
|
applyPmPositions(span, run.pmStart, run.pmEnd);
|
|
368
410
|
const paintedText = toPaintedText(run.text);
|
|
411
|
+
const smallCapsFontSizePx = run.smallCaps && !run.allCaps ? fontSizePtToPx(run.fontSize || 11) * SMALL_CAPS_SCALE : void 0;
|
|
369
412
|
const visualSpaceContractionPx = options?.visualSpaceContractionPx;
|
|
370
413
|
const effectiveHorizontalScaleFactor = getHorizontalScaleFactor(run.horizontalScale) * (options?.ancestorHorizontalScaleFactor ?? 1);
|
|
371
414
|
const contractedWordSpacing = visualSpaceContractionPx === void 0 || effectiveHorizontalScaleFactor === 0 ? void 0 : `${-visualSpaceContractionPx / effectiveHorizontalScaleFactor}px`;
|
|
@@ -385,7 +428,8 @@ function renderTextRun(run, doc, options) {
|
|
|
385
428
|
host: anchor,
|
|
386
429
|
text: paintedText,
|
|
387
430
|
doc,
|
|
388
|
-
...contractedWordSpacing !== void 0 ? { contractedWordSpacing } : {}
|
|
431
|
+
...contractedWordSpacing !== void 0 ? { contractedWordSpacing } : {},
|
|
432
|
+
...smallCapsFontSizePx !== void 0 ? { smallCapsFontSizePx } : {}
|
|
389
433
|
});
|
|
390
434
|
if (!run.hyperlink.noDefaultStyle) {
|
|
391
435
|
const hyperlinkColor = getHyperlinkTextColor(run, span.style.color);
|
|
@@ -398,7 +442,8 @@ function renderTextRun(run, doc, options) {
|
|
|
398
442
|
host: span,
|
|
399
443
|
text: paintedText,
|
|
400
444
|
doc,
|
|
401
|
-
...contractedWordSpacing !== void 0 ? { contractedWordSpacing } : {}
|
|
445
|
+
...contractedWordSpacing !== void 0 ? { contractedWordSpacing } : {},
|
|
446
|
+
...smallCapsFontSizePx !== void 0 ? { smallCapsFontSizePx } : {}
|
|
402
447
|
});
|
|
403
448
|
applyWhitespaceUnderline(span, run);
|
|
404
449
|
return span;
|
|
@@ -717,7 +762,7 @@ function renderFieldRun(run, doc, { context, visualSpaceContractionPx }) {
|
|
|
717
762
|
const horizontalScaleFactor = getHorizontalScaleFactor(resolvedRun.horizontalScale);
|
|
718
763
|
applyHorizontalScaleTransform(wrapper, resolvedRun.horizontalScale);
|
|
719
764
|
const { pmStart: _pmStart, pmEnd: _pmEnd, horizontalScale: _horizontalScale, ...segmentBase } = resolvedRun;
|
|
720
|
-
for (const segment of segmentByScript(text)) {
|
|
765
|
+
for (const segment of segmentByScript(text, eastAsiaHintApplies(resolvedRun))) {
|
|
721
766
|
const segmentRun = formatTextRunForScript({
|
|
722
767
|
...segmentBase,
|
|
723
768
|
text: segment.text
|
|
@@ -864,7 +909,7 @@ const formatTextRunForScript = (run, script) => {
|
|
|
864
909
|
*/
|
|
865
910
|
const needsPerScriptSpans = (run) => {
|
|
866
911
|
if (run.letterSpacing) return false;
|
|
867
|
-
if (run.eastAsiaFontFamily !== void 0 &&
|
|
912
|
+
if (run.eastAsiaFontFamily !== void 0 && hasEastAsiaSlotText(run.text, eastAsiaHintApplies(run))) return true;
|
|
868
913
|
return hasComplexScriptFormatting(run) && hasComplexScript(run.text);
|
|
869
914
|
};
|
|
870
915
|
/**
|
|
@@ -888,7 +933,7 @@ function splitTextRunsByEastAsia(runs) {
|
|
|
888
933
|
continue;
|
|
889
934
|
}
|
|
890
935
|
let offset = 0;
|
|
891
|
-
for (const segment of segmentByScript(run.text)) {
|
|
936
|
+
for (const segment of segmentByScript(run.text, eastAsiaHintApplies(run))) {
|
|
892
937
|
result.push(formatTextRunForScript({
|
|
893
938
|
...run,
|
|
894
939
|
text: segment.text,
|
|
@@ -933,13 +978,13 @@ const splitCollapsibleLineEdgeSpaces = (sourceRuns, collapseLeading) => {
|
|
|
933
978
|
const run = runs[index];
|
|
934
979
|
if (!run || !isTextRun(run)) break;
|
|
935
980
|
if (run.text.length === 0) continue;
|
|
936
|
-
const
|
|
937
|
-
if (
|
|
938
|
-
if (
|
|
981
|
+
const spacesStart = trailingSpaceStart(run.text);
|
|
982
|
+
if (spacesStart === run.text.length || paintsLineEdgeSpaces(run)) break;
|
|
983
|
+
if (spacesStart === 0) {
|
|
939
984
|
collapsedTrailingRuns.add(run);
|
|
940
985
|
continue;
|
|
941
986
|
}
|
|
942
|
-
const [leading, trailing] = splitTextRunAt(run,
|
|
987
|
+
const [leading, trailing] = splitTextRunAt(run, spacesStart);
|
|
943
988
|
runs.splice(index, 1, leading, trailing);
|
|
944
989
|
collapsedTrailingRuns.add(trailing);
|
|
945
990
|
break;
|
|
@@ -1005,6 +1050,7 @@ function runMeasureStyle(run) {
|
|
|
1005
1050
|
...run.alternateFontFamily !== void 0 ? { alternateFontFamily: run.alternateFontFamily } : {},
|
|
1006
1051
|
...run.eastAsiaFontFamily !== void 0 ? { eastAsiaFontFamily: run.eastAsiaFontFamily } : {},
|
|
1007
1052
|
...run.eastAsiaAlternateFontFamily !== void 0 ? { eastAsiaAlternateFontFamily: run.eastAsiaAlternateFontFamily } : {},
|
|
1053
|
+
...eastAsiaHintApplies(run) ? { eastAsiaHint: true } : {},
|
|
1008
1054
|
...run.complexScriptFontFamily !== void 0 ? { complexScriptFontFamily: run.complexScriptFontFamily } : {},
|
|
1009
1055
|
...run.complexScriptAlternateFontFamily !== void 0 ? { complexScriptAlternateFontFamily: run.complexScriptAlternateFontFamily } : {},
|
|
1010
1056
|
...run.complexScriptFontSize !== void 0 ? { complexScriptFontSize: run.complexScriptFontSize } : {},
|
|
@@ -1028,10 +1074,10 @@ function measureFollowingContentWidth(runs, tabRunIndex, measureText, context) {
|
|
|
1028
1074
|
if (isTabRun(run) || isLineBreakRun(run)) break;
|
|
1029
1075
|
if (isTextRun(run)) {
|
|
1030
1076
|
const text = run.allCaps ? run.text.toLocaleUpperCase() : run.text;
|
|
1031
|
-
width += measureText(text, run.fontSize ?? 11, run.fontFamily ?? "
|
|
1077
|
+
width += measureText(text, run.fontSize ?? 11, run.fontFamily ?? "Times New Roman", runMeasureStyle(run)) * getHorizontalScaleFactor(run.horizontalScale);
|
|
1032
1078
|
} else if (isFieldRun(run)) {
|
|
1033
1079
|
const fieldText = resolveFieldText(run, context);
|
|
1034
|
-
width += measureText(run.allCaps ? fieldText.toLocaleUpperCase() : fieldText, run.fontSize ?? 11, run.fontFamily ?? "
|
|
1080
|
+
width += measureText(run.allCaps ? fieldText.toLocaleUpperCase() : fieldText, run.fontSize ?? 11, run.fontFamily ?? "Times New Roman", runMeasureStyle(run)) * getHorizontalScaleFactor(run.horizontalScale);
|
|
1035
1081
|
} else if (isImageRun(run) && !isFloatingImageRun(run)) width += inlineImageBoundingBox(run).width || 0;
|
|
1036
1082
|
else if (isMathRun(run)) width += measureText(run.plainText, run.fontSize ?? 11, run.fontFamily ?? "Cambria Math", runMeasureStyle(run)) * getHorizontalScaleFactor(run.horizontalScale);
|
|
1037
1083
|
}
|
|
@@ -1061,7 +1107,7 @@ function measureDecimalPrefixWidth(runs, tabRunIndex, decimalIndex, measureText,
|
|
|
1061
1107
|
const take = Math.min(runText.length, decimalIndex - consumed);
|
|
1062
1108
|
if (take > 0) {
|
|
1063
1109
|
const horizontalScaleFactor = getHorizontalScaleFactor(run.horizontalScale);
|
|
1064
|
-
width += measureText(runText.slice(0, take), run.fontSize ?? 11, run.fontFamily ?? "
|
|
1110
|
+
width += measureText(runText.slice(0, take), run.fontSize ?? 11, run.fontFamily ?? "Times New Roman", runMeasureStyle(run)) * horizontalScaleFactor;
|
|
1065
1111
|
}
|
|
1066
1112
|
consumed += runText.length;
|
|
1067
1113
|
}
|
|
@@ -1113,7 +1159,7 @@ function applyLetterSpacingToMeasuredWidth(width, text, letterSpacing) {
|
|
|
1113
1159
|
}
|
|
1114
1160
|
function createTextMeasurer(doc) {
|
|
1115
1161
|
const ctx = doc.createElement("canvas").getContext("2d");
|
|
1116
|
-
return (text, fontSize = 11, fontFamily =
|
|
1162
|
+
return (text, fontSize = 11, fontFamily = DEFAULT_FONT_FAMILY, style = {}) => {
|
|
1117
1163
|
if (!ctx) return applyLetterSpacingToMeasuredWidth(text.length * 7, text, style.letterSpacing);
|
|
1118
1164
|
ctx.fontKerning = getFontKerningMode(style);
|
|
1119
1165
|
const fontString = (family, size, bold, italic, alternateFamily) => {
|
|
@@ -1131,9 +1177,9 @@ function createTextMeasurer(doc) {
|
|
|
1131
1177
|
ctx.font = complexFont;
|
|
1132
1178
|
return applyLetterSpacingToMeasuredWidth(ctx.measureText(text).width, text, style.letterSpacing);
|
|
1133
1179
|
}
|
|
1134
|
-
if (!style.letterSpacing && (style.eastAsiaFontFamily &&
|
|
1180
|
+
if (!style.letterSpacing && (style.eastAsiaFontFamily && hasEastAsiaSlotText(text, style.eastAsiaHint) || hasComplexScriptFormatting(style) && hasComplexScript(text))) {
|
|
1135
1181
|
let segmentedWidth = 0;
|
|
1136
|
-
for (const segment of segmentByScript(text)) {
|
|
1182
|
+
for (const segment of segmentByScript(text, style.eastAsiaHint)) {
|
|
1137
1183
|
if (segment.script === SCRIPT_CLASS.eastAsia && style.eastAsiaFontFamily) ctx.font = fontString(style.eastAsiaFontFamily, fontSize, style.bold, style.italic, style.eastAsiaAlternateFontFamily);
|
|
1138
1184
|
else if (segment.script === SCRIPT_CLASS.complex) ctx.font = complexFont;
|
|
1139
1185
|
else ctx.font = baseFont;
|
|
@@ -1189,7 +1235,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1189
1235
|
if (collapsedLeadingSpaceRuns.has(run)) runEl.dataset["collapsedLeadingSpaces"] = "true";
|
|
1190
1236
|
if (collapsedTrailingSpaceRuns.has(run)) runEl.dataset["collapsedTrailingSpaces"] = "true";
|
|
1191
1237
|
if (isCollapsedLineEdgeSpaceRun(run)) {
|
|
1192
|
-
const spaceAdvance = (collapsedSpaceMeasureText?.(" ", run.fontSize || 11, run.fontFamily || "
|
|
1238
|
+
const spaceAdvance = (collapsedSpaceMeasureText?.(" ", run.fontSize || 11, run.fontFamily || "Times New Roman", runMeasureStyle(run)) ?? 0) * getHorizontalScaleFactor(run.horizontalScale);
|
|
1193
1239
|
runEl.dataset["collapsedSpaceAdvance"] = String(spaceAdvance);
|
|
1194
1240
|
runEl.style.fontSize = "0";
|
|
1195
1241
|
runEl.style.letterSpacing = "0";
|
|
@@ -1340,7 +1386,8 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1340
1386
|
}
|
|
1341
1387
|
let tabWidth = tabResult.width;
|
|
1342
1388
|
const landsOnLeftIndent = tabResult.alignment === "start" && tabLeftIndentPx > 0 && Math.abs(currentX + tabWidth - tabLeftIndentPx) <= RIGHT_EDGE_EPSILON_PX;
|
|
1343
|
-
|
|
1389
|
+
const followingContentEndsOnLine = options?.isLastLine === true || runsForLine.slice(i + 1).some((next) => isTabRun(next) || isLineBreakRun(next));
|
|
1390
|
+
if (!(preservesAuthoredEndStop || activeContentRightEdge !== void 0 && tabResult.explicit === true && followingContentEndsOnLine && authoredEndpoint <= activeContentRightEdge + RIGHT_EDGE_EPSILON_PX) && !landsOnLeftIndent && lineRightEdgeX !== void 0 && canClampTabToRightEdge(tabResult.alignment, i > 0, runsForLine.slice(0, i).some(isTabRun), options?.isLastLine === true) && currentX + tabWidth + followingWidthForCheck > lineRightEdgeX) tabWidth = Math.max(1, lineRightEdgeX - currentX - followingWidthForCheck);
|
|
1344
1391
|
const tabEl = renderTabRun(run, doc, tabWidth, tabResult.leader);
|
|
1345
1392
|
lineEl.append(tabEl);
|
|
1346
1393
|
currentX += tabWidth;
|
|
@@ -1350,7 +1397,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1350
1397
|
if (isCollapsedLineEdgeSpaceRun(run)) continue;
|
|
1351
1398
|
if (!measureText) continue;
|
|
1352
1399
|
const fontSize = run.fontSize || 11;
|
|
1353
|
-
const fontFamily = run.fontFamily || "
|
|
1400
|
+
const fontFamily = run.fontFamily || "Times New Roman";
|
|
1354
1401
|
const measuredWidth = measureText(run.allCaps ? run.text.toLocaleUpperCase() : run.text, fontSize, fontFamily, runMeasureStyle(run));
|
|
1355
1402
|
const runContractionPx = runVisualSpaceContraction({
|
|
1356
1403
|
text: run.text,
|
|
@@ -1383,7 +1430,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1383
1430
|
if (!measureText) continue;
|
|
1384
1431
|
const fieldText = resolveFieldText(run, options.context);
|
|
1385
1432
|
const fontSize = run.fontSize || 11;
|
|
1386
|
-
const fontFamily = run.fontFamily || "
|
|
1433
|
+
const fontFamily = run.fontFamily || "Times New Roman";
|
|
1387
1434
|
const measuredWidth = measureText(run.allCaps ? fieldText.toLocaleUpperCase() : fieldText, fontSize, fontFamily, runMeasureStyle(run));
|
|
1388
1435
|
const runContractionPx = runVisualSpaceContraction({
|
|
1389
1436
|
text: fieldText,
|
|
@@ -1628,6 +1675,8 @@ function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting,
|
|
|
1628
1675
|
if (formatting.bold !== void 0) span.style.fontWeight = formatting.bold ? "700" : "normal";
|
|
1629
1676
|
if (formatting.italic !== void 0) span.style.fontStyle = formatting.italic ? "italic" : "normal";
|
|
1630
1677
|
if (formatting.rtl !== void 0) span.dir = formatting.rtl ? "rtl" : "ltr";
|
|
1678
|
+
const markerColor = revision ? void 0 : getRenderableListMarkerColor(formatting.color);
|
|
1679
|
+
if (markerColor) setAuthoredTextColor(span.style, markerColor);
|
|
1631
1680
|
span.style.textAlign = physicalStart;
|
|
1632
1681
|
span.style.textAlignLast = physicalStart;
|
|
1633
1682
|
span.style.boxSizing = "border-box";
|
|
@@ -1673,4 +1722,4 @@ function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting,
|
|
|
1673
1722
|
return span;
|
|
1674
1723
|
}
|
|
1675
1724
|
//#endregion
|
|
1676
|
-
export { PARAGRAPH_CLASS_NAMES, UNICODE_BIDI_BY_WRAPPER_CONTROL, getLeaderChar, getRenderableTextColor, paragraphHasTrackedChanges, renderLine, renderParagraphFragment, sliceRunsForLine, splitCollapsibleLineEdgeSpaces, splitTextRunsByEastAsia, startsAfterSoftWrap };
|
|
1725
|
+
export { PARAGRAPH_CLASS_NAMES, UNICODE_BIDI_BY_WRAPPER_CONTROL, getLeaderChar, getRenderableListMarkerColor, getRenderableTextColor, paragraphHasTrackedChanges, renderLine, renderParagraphFragment, sliceRunsForLine, splitCollapsibleLineEdgeSpaces, splitTextRunsByEastAsia, startsAfterSoftWrap };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
2
2
|
import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../layout-engine/measure/tableCellFloating.js";
|
|
3
3
|
import { createTableCellFlowState, finishTableCellFlow, placeTableCellBlock } from "../layout-engine/measure/tableCellFlow.js";
|
|
4
|
-
import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt } from "../layout-engine/measure/tableCellGrid.js";
|
|
4
|
+
import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt, getTableCellSpacingInsetsY } from "../layout-engine/measure/tableCellGrid.js";
|
|
5
5
|
import { tableFragmentBottomBorders } from "../layout-engine/measure/tableFragmentBorderGeometry.js";
|
|
6
6
|
import { resolveTableInlineOffset, resolveTableInlinePlacement } from "../layout-engine/measure/tableInlinePlacement.js";
|
|
7
7
|
import { isFloatingImageRun, isFloatingTextBoxBlock, resolveTableCellPadding, tableColumnsArePinned } from "../layout-engine/types.js";
|
|
@@ -293,7 +293,8 @@ function renderNestedTable(block, measure, context, doc, frameWidth = context.co
|
|
|
293
293
|
const cellPlacements = buildTableCellPlacements({
|
|
294
294
|
grid: cellGrid,
|
|
295
295
|
columnWidths: measure.columnWidths,
|
|
296
|
-
bidi: block.bidi === true
|
|
296
|
+
bidi: block.bidi === true,
|
|
297
|
+
cellSpacing: block.cellSpacing
|
|
297
298
|
});
|
|
298
299
|
let y = 0;
|
|
299
300
|
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
|
|
@@ -318,6 +319,7 @@ function renderNestedTable(block, measure, context, doc, frameWidth = context.co
|
|
|
318
319
|
columnsPinned,
|
|
319
320
|
cellGrid,
|
|
320
321
|
cellPlacements,
|
|
322
|
+
cellSpacing: block.cellSpacing,
|
|
321
323
|
inlineOffset: resolveTableInlineOffset({
|
|
322
324
|
table: block,
|
|
323
325
|
rowJustification: row.justification,
|
|
@@ -375,12 +377,12 @@ function renderCellDiagonalBorder({ border, direction, cellWidth, cellHeight, do
|
|
|
375
377
|
}
|
|
376
378
|
return line;
|
|
377
379
|
}
|
|
378
|
-
function renderTableCell({ cell, cellMeasure, x, width, rowHeight, borderFlags, columnsPinned, context, doc, contentClip, pageContentPosition }) {
|
|
380
|
+
function renderTableCell({ cell, cellMeasure, x, y = 0, width, rowHeight, borderFlags, columnsPinned, context, doc, contentClip, pageContentPosition }) {
|
|
379
381
|
const cellEl = doc.createElement("div");
|
|
380
382
|
cellEl.className = TABLE_CLASS_NAMES.cell;
|
|
381
383
|
cellEl.style.position = "absolute";
|
|
382
384
|
cellEl.style.left = `${x}px`;
|
|
383
|
-
cellEl.style.top =
|
|
385
|
+
cellEl.style.top = `${y}px`;
|
|
384
386
|
cellEl.style.width = `${width}px`;
|
|
385
387
|
cellEl.style.height = `${rowHeight}px`;
|
|
386
388
|
cellEl.style.overflow = "hidden";
|
|
@@ -499,7 +501,8 @@ const continuationRowBottomBorderOffsets = (fragment, block, measure, cellGrid)
|
|
|
499
501
|
snapAfterRow
|
|
500
502
|
});
|
|
501
503
|
};
|
|
502
|
-
function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false, cellGrid, cellPlacements, contentClip, pageContentPosition, inlineOffset = 0, bottomBorderOffset = 0 }) {
|
|
504
|
+
function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false, cellGrid, cellPlacements, cellSpacing, contentClip, pageContentPosition, inlineOffset = 0, bottomBorderOffset = 0 }) {
|
|
505
|
+
const bordersSeparated = (cellSpacing ?? 0) > 0;
|
|
503
506
|
const rowEl = doc.createElement("div");
|
|
504
507
|
rowEl.className = TABLE_CLASS_NAMES.row;
|
|
505
508
|
rowEl.style.position = "absolute";
|
|
@@ -530,15 +533,22 @@ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows,
|
|
|
530
533
|
const isLastCol = bidi ? atLogicalStart : atLogicalEnd;
|
|
531
534
|
const aboveCell = getSourceCellAt(cellGrid, rowIndex - 1, columnIndex);
|
|
532
535
|
const leftCell = getSourceCellAt(cellGrid, rowIndex, bidi ? columnIndex + colSpan : columnIndex - 1);
|
|
533
|
-
const drawTop = isFirstRow || !hasVisibleBorder(aboveCell?.borders?.bottom);
|
|
534
|
-
const drawLeft = isFirstCol || !hasVisibleBorder(leftCell?.borders?.right);
|
|
536
|
+
const drawTop = bordersSeparated || isFirstRow || !hasVisibleBorder(aboveCell?.borders?.bottom);
|
|
537
|
+
const drawLeft = bordersSeparated || isFirstCol || !hasVisibleBorder(leftCell?.borders?.right);
|
|
538
|
+
const spacing = getTableCellSpacingInsetsY(cellSpacing, rowIndex, rowSpan, totalRows);
|
|
539
|
+
const boxHeight = Math.max(0, cellHeight - spacing.top - spacing.bottom);
|
|
540
|
+
const boxClip = contentClip ? {
|
|
541
|
+
top: contentClip.top - spacing.top,
|
|
542
|
+
bottom: contentClip.bottom - spacing.top
|
|
543
|
+
} : void 0;
|
|
535
544
|
const paintBottomBorderSeparately = bottomBorderOffset > 0 && hasVisibleBorder(cell.borders?.bottom);
|
|
536
545
|
const cellEl = renderTableCell({
|
|
537
546
|
cell,
|
|
538
547
|
cellMeasure,
|
|
539
548
|
x: cellLeft,
|
|
549
|
+
y: spacing.top,
|
|
540
550
|
width,
|
|
541
|
-
rowHeight:
|
|
551
|
+
rowHeight: boxHeight,
|
|
542
552
|
borderFlags: {
|
|
543
553
|
drawTop,
|
|
544
554
|
drawBottom: !paintBottomBorderSeparately,
|
|
@@ -549,11 +559,11 @@ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows,
|
|
|
549
559
|
columnsPinned,
|
|
550
560
|
context,
|
|
551
561
|
doc,
|
|
552
|
-
...
|
|
562
|
+
...boxClip ? { contentClip: boxClip } : {},
|
|
553
563
|
...pageContentPosition ? { pageContentPosition: {
|
|
554
564
|
geometry: pageContentPosition.geometry,
|
|
555
565
|
x: pageContentPosition.x + inlineOffset + cellLeft,
|
|
556
|
-
y: pageContentPosition.y
|
|
566
|
+
y: pageContentPosition.y + spacing.top
|
|
557
567
|
} } : {}
|
|
558
568
|
});
|
|
559
569
|
cellEl.dataset["cellIndex"] = String(cellIndex);
|
|
@@ -565,9 +575,9 @@ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows,
|
|
|
565
575
|
bottomBorderEl.className = CELL_BOTTOM_BORDER_CLASS;
|
|
566
576
|
bottomBorderEl.style.position = "absolute";
|
|
567
577
|
bottomBorderEl.style.left = `${cellLeft}px`;
|
|
568
|
-
bottomBorderEl.style.top =
|
|
578
|
+
bottomBorderEl.style.top = `${spacing.top}px`;
|
|
569
579
|
bottomBorderEl.style.width = `${width}px`;
|
|
570
|
-
bottomBorderEl.style.height = `${
|
|
580
|
+
bottomBorderEl.style.height = `${boxHeight + bottomBorderOffset}px`;
|
|
571
581
|
bottomBorderEl.style.boxSizing = "border-box";
|
|
572
582
|
bottomBorderEl.style.pointerEvents = "none";
|
|
573
583
|
bottomBorderEl.style.zIndex = "1";
|
|
@@ -637,7 +647,8 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
637
647
|
const cellPlacements = buildTableCellPlacements({
|
|
638
648
|
grid: cellGrid,
|
|
639
649
|
columnWidths: measure.columnWidths,
|
|
640
|
-
bidi: block.bidi === true
|
|
650
|
+
bidi: block.bidi === true,
|
|
651
|
+
cellSpacing: block.cellSpacing
|
|
641
652
|
});
|
|
642
653
|
const contentRowBottomBorderOffsets = continuationRowBottomBorderOffsets(fragment, block, measure, cellGrid);
|
|
643
654
|
const headerRowCount = fragment.headerRowCount ?? 0;
|
|
@@ -665,6 +676,7 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
665
676
|
columnsPinned,
|
|
666
677
|
cellGrid,
|
|
667
678
|
cellPlacements,
|
|
679
|
+
cellSpacing: block.cellSpacing,
|
|
668
680
|
...tablePageContentPosition ? { pageContentPosition: {
|
|
669
681
|
...tablePageContentPosition,
|
|
670
682
|
y: tablePageContentPosition.y + y
|
|
@@ -718,6 +730,7 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
718
730
|
columnsPinned,
|
|
719
731
|
cellGrid,
|
|
720
732
|
cellPlacements,
|
|
733
|
+
cellSpacing: block.cellSpacing,
|
|
721
734
|
bottomBorderOffset: contentRowBottomBorderOffsets[rowIndex - fragment.fromRow] ?? 0,
|
|
722
735
|
...contentClip ? { contentClip } : {},
|
|
723
736
|
...tablePageContentPosition ? { pageContentPosition: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TableBlock, TableMeasure, TextBoxBlock, TextBoxFragment, TextBoxMeasure } from "../layout-engine/types.js";
|
|
1
|
+
import { TableBlock, TableMeasure, TextBoxBlock, TextBoxFragment, TextBoxGradientFill, TextBoxMeasure } from "../layout-engine/types.js";
|
|
2
2
|
import { RenderContext } from "./renderUtils.js";
|
|
3
3
|
//#region src/layout-painter/renderTextBox.d.ts
|
|
4
4
|
/**
|
|
@@ -14,9 +14,19 @@ type RenderTextBoxFragmentOptions = {
|
|
|
14
14
|
document?: Document;
|
|
15
15
|
renderTable?: (block: TableBlock, measure: TableMeasure, context: RenderContext, document: Document, frameWidth?: number) => HTMLElement;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* The CSS angle of a DrawingML linear gradient over a `width` x `height` box.
|
|
19
|
+
*
|
|
20
|
+
* DrawingML measures `a:lin@ang` clockwise from the positive x axis; CSS
|
|
21
|
+
* measures clockwise from "to top", a quarter turn earlier. A `scaled` angle is
|
|
22
|
+
* stated in the unit square: stretching that square to the box keeps each
|
|
23
|
+
* isoline through the same corners, so the gradient runs perpendicular to the
|
|
24
|
+
* stretched isoline rather than along the stated angle.
|
|
25
|
+
*/
|
|
26
|
+
declare function cssLinearGradientAngle(fill: Pick<TextBoxGradientFill, "angle" | "scaled">, width: number, height: number): number;
|
|
17
27
|
/**
|
|
18
28
|
* Render a text box fragment to DOM
|
|
19
29
|
*/
|
|
20
30
|
declare function renderTextBoxFragment(fragment: TextBoxFragment, block: TextBoxBlock, measure: TextBoxMeasure, context: RenderContext, options?: RenderTextBoxFragmentOptions): HTMLElement;
|
|
21
31
|
//#endregion
|
|
22
|
-
export { RenderTextBoxFragmentOptions, TEXTBOX_CLASS_NAMES, renderTextBoxFragment };
|
|
32
|
+
export { RenderTextBoxFragmentOptions, TEXTBOX_CLASS_NAMES, cssLinearGradientAngle, renderTextBoxFragment };
|
|
@@ -10,7 +10,7 @@ import { panic } from "better-result";
|
|
|
10
10
|
* Text Box Renderer
|
|
11
11
|
*
|
|
12
12
|
* Renders text box fragments to DOM. Handles:
|
|
13
|
-
* - Background fill color
|
|
13
|
+
* - Background fill color or linear gradient
|
|
14
14
|
* - Border/outline
|
|
15
15
|
* - Internal padding (margins)
|
|
16
16
|
* - Block content inside the box (using pre-measured data)
|
|
@@ -20,6 +20,29 @@ import { panic } from "better-result";
|
|
|
20
20
|
*/
|
|
21
21
|
const TEXTBOX_CLASS_NAMES = { textBox: "layout-textbox" };
|
|
22
22
|
/**
|
|
23
|
+
* The CSS angle of a DrawingML linear gradient over a `width` x `height` box.
|
|
24
|
+
*
|
|
25
|
+
* DrawingML measures `a:lin@ang` clockwise from the positive x axis; CSS
|
|
26
|
+
* measures clockwise from "to top", a quarter turn earlier. A `scaled` angle is
|
|
27
|
+
* stated in the unit square: stretching that square to the box keeps each
|
|
28
|
+
* isoline through the same corners, so the gradient runs perpendicular to the
|
|
29
|
+
* stretched isoline rather than along the stated angle.
|
|
30
|
+
*/
|
|
31
|
+
function cssLinearGradientAngle(fill, width, height) {
|
|
32
|
+
const radians = fill.angle * Math.PI / 180;
|
|
33
|
+
return ((90 + (fill.scaled && width > 0 && height > 0 ? Math.atan2(width * Math.sin(radians), height * Math.cos(radians)) : radians) * 180 / Math.PI) % 360 + 360) % 360;
|
|
34
|
+
}
|
|
35
|
+
const formatCssNumber = (value) => String(Math.round(value * 1e3) / 1e3);
|
|
36
|
+
function paintGradientFill(style, fill, width, height) {
|
|
37
|
+
const [first] = fill.stops;
|
|
38
|
+
if (first === void 0) return;
|
|
39
|
+
if (fill.stops.length === 1) {
|
|
40
|
+
setAuthoredBackgroundColor(style, first.color);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
style.backgroundImage = `linear-gradient(${formatCssNumber(cssLinearGradientAngle(fill, width, height))}deg, ${fill.stops.map((stop) => `${stop.color} ${formatCssNumber(stop.offset * 100)}%`).join(", ")})`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
23
46
|
* Render a text box fragment to DOM
|
|
24
47
|
*/
|
|
25
48
|
function renderTextBoxFragment(fragment, block, measure, context, options = {}) {
|
|
@@ -32,6 +55,7 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
|
|
|
32
55
|
containerEl.style.overflow = block.textWrap === "none" ? "visible" : "hidden";
|
|
33
56
|
containerEl.style.boxSizing = "border-box";
|
|
34
57
|
if (block.fillColor) setAuthoredBackgroundColor(containerEl.style, block.fillColor);
|
|
58
|
+
else if (block.fillGradient) paintGradientFill(containerEl.style, block.fillGradient, fragment.width, fragment.height);
|
|
35
59
|
const outlineDash = presetDashForOutlineAttr(block.outlineStyle) ?? "solid";
|
|
36
60
|
if (block.outlineWidth && block.outlineWidth > 0 && outlineDash !== "none") {
|
|
37
61
|
const color = block.outlineColor || "#000000";
|
|
@@ -93,4 +117,4 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
|
|
|
93
117
|
return containerEl;
|
|
94
118
|
}
|
|
95
119
|
//#endregion
|
|
96
|
-
export { TEXTBOX_CLASS_NAMES, renderTextBoxFragment };
|
|
120
|
+
export { TEXTBOX_CLASS_NAMES, cssLinearGradientAngle, renderTextBoxFragment };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AlternateContentAttrs } from "./schema/nodes.js";
|
|
2
|
+
import { Node } from "prosemirror-model";
|
|
3
|
+
//#region src/prosemirror/alternateContentAttrs.d.ts
|
|
4
|
+
/** Attach a captured `mc:AlternateContent` to a freshly projected node. */
|
|
5
|
+
declare const withAlternateContent: (node: Node, xml: string | undefined) => Node;
|
|
6
|
+
/** The captured element, while the node is still the one it was attached to. */
|
|
7
|
+
declare const unchangedAlternateContentXml: (node: Node, captured: AlternateContentAttrs | undefined) => string | undefined;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { unchangedAlternateContentXml, withAlternateContent };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { canonicalJson } from "../utils/canonicalJson.js";
|
|
2
|
+
//#region src/prosemirror/alternateContentAttrs.ts
|
|
3
|
+
const ALTERNATE_CONTENT_ATTR = "_docxAlternateContent";
|
|
4
|
+
/**
|
|
5
|
+
* What the node says about the shape: its attributes and, for a text box, its
|
|
6
|
+
* content. Marks are left out; they carry the run's properties, which sit
|
|
7
|
+
* outside `mc:AlternateContent`.
|
|
8
|
+
*
|
|
9
|
+
* The projection from the model is lossy, so the node is compared with itself
|
|
10
|
+
* as it was projected rather than the rebuilt shape with the parsed one: a
|
|
11
|
+
* round trip that changed nothing would otherwise read as an edit.
|
|
12
|
+
*/
|
|
13
|
+
const nodeFingerprint = (node) => {
|
|
14
|
+
const { [ALTERNATE_CONTENT_ATTR]: _captured, ...attrs } = node.attrs;
|
|
15
|
+
return canonicalJson({
|
|
16
|
+
attrs,
|
|
17
|
+
content: node.content.toJSON()
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
/** Attach a captured `mc:AlternateContent` to a freshly projected node. */
|
|
21
|
+
const withAlternateContent = (node, xml) => {
|
|
22
|
+
if (xml === void 0) return node;
|
|
23
|
+
const alternateContent = {
|
|
24
|
+
xml,
|
|
25
|
+
fingerprint: nodeFingerprint(node)
|
|
26
|
+
};
|
|
27
|
+
return node.type.create({
|
|
28
|
+
...node.attrs,
|
|
29
|
+
[ALTERNATE_CONTENT_ATTR]: alternateContent
|
|
30
|
+
}, node.content, node.marks);
|
|
31
|
+
};
|
|
32
|
+
/** The captured element, while the node is still the one it was attached to. */
|
|
33
|
+
const unchangedAlternateContentXml = (node, captured) => captured !== void 0 && captured.fingerprint === nodeFingerprint(node) ? captured.xml : void 0;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { unchangedAlternateContentXml, withAlternateContent };
|
|
@@ -4,18 +4,18 @@ import "../schema/index.js";
|
|
|
4
4
|
import { Mark, Node } from "prosemirror-model";
|
|
5
5
|
//#region src/prosemirror/attrs/index.d.ts
|
|
6
6
|
type ProseMirrorAttrIssue = {
|
|
7
|
-
path: string;
|
|
8
|
-
message: string;
|
|
7
|
+
readonly path: string;
|
|
8
|
+
readonly message: string;
|
|
9
9
|
};
|
|
10
10
|
type ReadProseMirrorAttrsResult<T> = {
|
|
11
11
|
ok: true;
|
|
12
12
|
value: T;
|
|
13
13
|
} | {
|
|
14
14
|
ok: false;
|
|
15
|
-
issues: ProseMirrorAttrIssue[];
|
|
15
|
+
issues: readonly ProseMirrorAttrIssue[];
|
|
16
16
|
};
|
|
17
|
-
declare const readParagraphAttrs: (node: Node) => ReadProseMirrorAttrsResult<ParagraphAttrs
|
|
18
|
-
declare const expectParagraphAttrs: (node: Node) => ParagraphAttrs
|
|
17
|
+
declare const readParagraphAttrs: (node: Node) => ReadProseMirrorAttrsResult<Readonly<ParagraphAttrs>>;
|
|
18
|
+
declare const expectParagraphAttrs: (node: Node) => Readonly<ParagraphAttrs>;
|
|
19
19
|
declare const readHardBreakAttrs: (node: Node) => ReadProseMirrorAttrsResult<HardBreakAttrs>;
|
|
20
20
|
declare const expectHardBreakAttrs: (node: Node) => HardBreakAttrs;
|
|
21
21
|
declare const readPageBreakRunAttrs: (node: Node) => ReadProseMirrorAttrsResult<PageBreakRunAttrs>;
|
|
@@ -28,10 +28,10 @@ declare const readPreservedXmlAttrs: (node: Node) => ReadProseMirrorAttrsResult<
|
|
|
28
28
|
declare const expectPreservedXmlAttrs: (node: Node) => PreservedXmlAttrs;
|
|
29
29
|
declare const readPreservedBlockAttrs: (node: Node) => ReadProseMirrorAttrsResult<PreservedBlockAttrs>;
|
|
30
30
|
declare const expectPreservedBlockAttrs: (node: Node) => PreservedBlockAttrs;
|
|
31
|
-
declare const readTableAttrs: (node: Node) => ReadProseMirrorAttrsResult<TableAttrs
|
|
32
|
-
declare const expectTableAttrs: (node: Node) => TableAttrs
|
|
33
|
-
declare const readTableRowAttrs: (node: Node) => ReadProseMirrorAttrsResult<TableRowAttrs
|
|
34
|
-
declare const expectTableRowAttrs: (node: Node) => TableRowAttrs
|
|
31
|
+
declare const readTableAttrs: (node: Node) => ReadProseMirrorAttrsResult<Readonly<TableAttrs>>;
|
|
32
|
+
declare const expectTableAttrs: (node: Node) => Readonly<TableAttrs>;
|
|
33
|
+
declare const readTableRowAttrs: (node: Node) => ReadProseMirrorAttrsResult<Readonly<TableRowAttrs>>;
|
|
34
|
+
declare const expectTableRowAttrs: (node: Node) => Readonly<TableRowAttrs>;
|
|
35
35
|
declare const readTableCellAttrs: (node: Node) => ReadProseMirrorAttrsResult<TableCellAttrs>;
|
|
36
36
|
declare const expectTableCellAttrs: (node: Node) => TableCellAttrs;
|
|
37
37
|
declare const readImageAttrs: (node: Node) => ReadProseMirrorAttrsResult<ImageAttrs>;
|