@stll/folio-core 0.8.0 → 0.10.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 +39 -0
- package/dist/ai-edits/apply.js +18 -4
- package/dist/ai-edits/headless.d.ts +73 -6
- package/dist/ai-edits/headless.js +299 -60
- package/dist/ai-edits/index.d.ts +3 -3
- package/dist/ai-edits/index.js +2 -1
- package/dist/ai-edits/snapshot.js +40 -3
- package/dist/ai-edits/types.d.ts +2 -1
- package/dist/compat/eigenpal.d.ts +6 -4
- package/dist/compat/eigenpal.js +5 -3
- package/dist/controller/latestRequestGate.d.ts +13 -0
- package/dist/controller/latestRequestGate.js +16 -0
- package/dist/controller/layoutPipeline.js +13 -1
- package/dist/document-operations.d.ts +20 -4
- package/dist/document-operations.js +36 -15
- package/dist/document-stories.d.ts +10 -0
- package/dist/document-stories.js +27 -0
- package/dist/docx/blockContentParser.js +2 -2
- package/dist/docx/commentParser.js +1 -1
- package/dist/docx/compatibility.d.ts +3 -7
- package/dist/docx/compatibility.js +0 -11
- package/dist/docx/corePropertiesParser.d.ts +8 -0
- package/dist/docx/corePropertiesParser.js +53 -0
- package/dist/docx/encryption/agileDecryption.js +1 -1
- package/dist/docx/encryption/encryptionInfo.js +1 -1
- package/dist/docx/encryption/openEncryptedDocx.js +1 -1
- package/dist/docx/fontTableParser.d.ts +6 -0
- package/dist/docx/fontTableParser.js +72 -0
- package/dist/docx/groupDrawingParser.js +7 -2
- package/dist/docx/headerFooterParser.js +1 -1
- package/dist/docx/index.d.ts +2 -1
- package/dist/docx/index.js +2 -1
- package/dist/docx/metadataPrivacy.d.ts +40 -0
- package/dist/docx/metadataPrivacy.js +131 -0
- package/dist/docx/normalizeBaseDirection.js +1 -1
- package/dist/docx/numberingParser.js +1 -0
- package/dist/docx/paragraphParser.js +12 -1
- package/dist/docx/parser.d.ts +1 -1
- package/dist/docx/parser.js +16 -10
- package/dist/docx/rezip.d.ts +5 -4
- package/dist/docx/rezip.js +76 -13
- package/dist/docx/runConsolidator.js +4 -0
- package/dist/docx/runParser.js +19 -1
- package/dist/docx/selectiveSave.js +3 -3
- package/dist/docx/serializer/fontTableSerializer.d.ts +6 -0
- package/dist/docx/serializer/fontTableSerializer.js +26 -0
- package/dist/docx/serializer/headerFooterSerializer.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +4 -0
- package/dist/docx/serializer/runSerializer.js +7 -0
- package/dist/docx/serializer/settingsSerializer.d.ts +6 -0
- package/dist/docx/serializer/settingsSerializer.js +16 -0
- package/dist/docx/serializer/stylesSerializer.d.ts +6 -0
- package/dist/docx/serializer/stylesSerializer.js +56 -0
- package/dist/docx/serializer/tableSerializer.js +25 -26
- package/dist/docx/serializer/themeSerializer.d.ts +6 -0
- package/dist/docx/serializer/themeSerializer.js +36 -0
- package/dist/docx/settingsParser.js +46 -0
- package/dist/docx/styleParser.js +26 -1
- package/dist/docx/tableParser.js +11 -1
- package/dist/docx/vmlImageParser.js +1 -0
- package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
- package/dist/i18n/messages/catalogs.gen.js +5910 -5910
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +3 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +3 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +3 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +6 -1
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +52 -14
- package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
- package/dist/layout-bridge/engine/measuring/index.js +2 -1
- package/dist/layout-engine/index.js +36 -28
- package/dist/layout-engine/measure/cache.js +6 -3
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.d.ts +29 -0
- package/dist/layout-engine/measure/effectiveLineBreakPolicy.js +60 -0
- package/dist/layout-engine/measure/font-metrics.worker.js +1 -0
- package/dist/layout-engine/measure/index.d.ts +2 -1
- package/dist/layout-engine/measure/index.js +2 -1
- package/dist/layout-engine/measure/lineBreakProvider.d.ts +33 -0
- package/dist/layout-engine/measure/lineBreakProvider.js +252 -0
- package/dist/layout-engine/measure/lineBreaks.d.ts +7 -2
- package/dist/layout-engine/measure/lineBreaks.js +11 -18
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +1 -0
- package/dist/layout-engine/measure/listMarkerWidth.js +12 -6
- package/dist/layout-engine/measure/measureBlocks.d.ts +1 -2
- package/dist/layout-engine/measure/measureBlocks.js +6 -36
- package/dist/layout-engine/measure/measureContainer.js +32 -9
- package/dist/layout-engine/measure/measureHelpers.js +5 -2
- package/dist/layout-engine/measure/measureParagraph.js +332 -73
- package/dist/layout-engine/measure/measureTypes.d.ts +2 -1
- package/dist/layout-engine/measure/measureWorker.d.ts +2 -2
- package/dist/layout-engine/measure/measureWorker.js +8 -19
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +3 -14
- package/dist/layout-engine/measure/tableCellFloating.d.ts +10 -3
- package/dist/layout-engine/measure/tableCellFloating.js +51 -37
- package/dist/layout-engine/measure/tableCellFlow.d.ts +27 -0
- package/dist/layout-engine/measure/tableCellFlow.js +73 -0
- package/dist/layout-engine/measure/tableCellGrid.js +1 -1
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
- package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +6 -1
- package/dist/layout-engine/renderedBreakReconciliation.js +34 -11
- package/dist/layout-engine/tableRowBreak.d.ts +5 -2
- package/dist/layout-engine/tableRowBreak.js +62 -29
- package/dist/layout-engine/types.d.ts +43 -8
- package/dist/layout-painter/anchoredImagePosition.d.ts +23 -0
- package/dist/layout-painter/anchoredImagePosition.js +95 -0
- package/dist/layout-painter/borderStroke.d.ts +23 -0
- package/dist/layout-painter/borderStroke.js +39 -0
- package/dist/layout-painter/renderImage.d.ts +5 -4
- package/dist/layout-painter/renderImage.js +18 -4
- package/dist/layout-painter/renderPage.d.ts +2 -27
- package/dist/layout-painter/renderPage.js +13 -99
- package/dist/layout-painter/renderParagraph.js +41 -23
- package/dist/layout-painter/renderTable.d.ts +2 -0
- package/dist/layout-painter/renderTable.js +223 -43
- package/dist/managers/DocumentLoaderManager.d.ts +1 -1
- package/dist/managers/DocumentLoaderManager.js +2 -2
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +22 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
- package/dist/prosemirror/conversion/effectiveTableCellFormatting.d.ts +62 -0
- package/dist/prosemirror/conversion/effectiveTableCellFormatting.js +131 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +34 -18
- package/dist/prosemirror/conversion/toProseDoc.js +81 -77
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +7 -2
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +1 -0
- package/dist/prosemirror/extensions/marks/HighlightExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/LanguageExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/marks/LanguageExtension.js +30 -0
- package/dist/prosemirror/extensions/marks/RunShadingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +1 -1
- package/dist/prosemirror/extensions/marks/markUtils.js +12 -0
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +3 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +6 -1
- package/dist/prosemirror/schema/nodes.d.ts +15 -12
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.d.ts +3 -1
- package/dist/prosemirror/utils/tabCalculator.js +12 -10
- package/dist/prosemirror/validation.js +4 -1
- package/dist/redline.d.ts +26 -11
- package/dist/redline.js +107 -64
- package/dist/server.d.ts +9 -5
- package/dist/server.js +8 -4
- package/dist/style-sets/extract.d.ts +35 -0
- package/dist/style-sets/extract.js +123 -0
- package/dist/style-sets/stellaStyle.d.ts +13 -0
- package/dist/style-sets/stellaStyle.js +516 -0
- package/dist/style-sets/types.d.ts +31 -0
- package/dist/style-sets/types.js +5 -0
- package/dist/utils/createDocument.d.ts +12 -2
- package/dist/utils/createDocument.js +42 -31
- package/dist/utils/fontResolver.js +6 -6
- package/dist/utils/formatToStyle.js +1 -1
- package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
- package/dist/utils/paragraphFormattingMerge.js +14 -4
- package/dist/version-comparison.d.ts +65 -11
- package/dist/version-comparison.js +187 -29
- package/package.json +5 -1
- package/dist/docx/capabilities.d.ts +0 -41
- package/dist/docx/capabilities.js +0 -322
|
@@ -1,28 +1,24 @@
|
|
|
1
|
-
import { isFloatingTextBoxBlock } from "./types.js";
|
|
2
1
|
import { measureParagraph } from "./measure/measureParagraph.js";
|
|
2
|
+
import { isEmptyParagraph } from "./paragraphSpacing.js";
|
|
3
|
+
import { createTableCellFlowState, placeTableCellBlock } from "./measure/tableCellFlow.js";
|
|
3
4
|
import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "./measure/tableCellFloating.js";
|
|
4
5
|
//#region src/layout-engine/tableRowBreak.ts
|
|
5
6
|
/**
|
|
6
7
|
* Table row-break geometry. Ported from eigenpal/docx-editor#698 (folio subset).
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* was clipped (content lost; upstream #570).
|
|
9
|
+
* Table rows may break across flow regions unless `cantSplit` is set. When a
|
|
10
|
+
* permitted row exceeds the current region, the portion that fits stays and
|
|
11
|
+
* the rest continues in the next region, broken between whole text lines and
|
|
12
|
+
* never through a glyph. This also prevents oversized rows from overflowing
|
|
13
|
+
* one page and clipping content (upstream #570).
|
|
14
14
|
*
|
|
15
15
|
* This computes, per row, the safe break offsets (the y of every line bottom in
|
|
16
16
|
* the row's cells) so the paginator can snap a break to the deepest whole line
|
|
17
17
|
* that still fits. Vertically-merged cells that span into a row are not modeled
|
|
18
18
|
* here yet (a separate follow-up); each row uses its own cells' content.
|
|
19
19
|
*/
|
|
20
|
+
const BREAK_OFFSET_EPSILON = .01;
|
|
20
21
|
const DEFAULT_TABLE_CELL_PADDING_TOP = 1;
|
|
21
|
-
function getAtomicBlockHeight(measure) {
|
|
22
|
-
if ("totalHeight" in measure) return measure.totalHeight;
|
|
23
|
-
if ("height" in measure) return measure.height;
|
|
24
|
-
return 0;
|
|
25
|
-
}
|
|
26
22
|
function isInsideRange(offset, range) {
|
|
27
23
|
return offset > range.top && offset < range.bottom;
|
|
28
24
|
}
|
|
@@ -39,6 +35,10 @@ function shiftCellGeometry(geometry, offset) {
|
|
|
39
35
|
unsafeRanges: geometry.unsafeRanges.map((range) => ({
|
|
40
36
|
top: range.top + offset,
|
|
41
37
|
bottom: range.bottom + offset
|
|
38
|
+
})),
|
|
39
|
+
suppressibleLeadingRanges: geometry.suppressibleLeadingRanges.map((range) => ({
|
|
40
|
+
top: range.top + offset,
|
|
41
|
+
bottom: range.bottom + offset
|
|
42
42
|
}))
|
|
43
43
|
};
|
|
44
44
|
}
|
|
@@ -46,22 +46,28 @@ function shiftCellGeometry(geometry, offset) {
|
|
|
46
46
|
function cellBreakGeometry(cell, measure) {
|
|
47
47
|
const bottoms = [];
|
|
48
48
|
const unsafeRanges = [];
|
|
49
|
+
const suppressibleLeadingRanges = [];
|
|
49
50
|
const cellBlocks = cell?.blocks;
|
|
50
51
|
const blockMeasures = measure.blocks;
|
|
51
52
|
const padTop = cell?.padding?.top ?? DEFAULT_TABLE_CELL_PADDING_TOP;
|
|
52
53
|
const contentWidth = getTableCellContentWidth(cell, measure);
|
|
53
54
|
const floatingZones = buildTableCellFloatingZones(cell !== void 0 ? getTableCellFloatingImages(cell, measure, contentWidth) : [], contentWidth);
|
|
54
|
-
|
|
55
|
-
let paragraphY = 0;
|
|
55
|
+
const flowState = createTableCellFlowState();
|
|
56
56
|
for (let i = 0; i < blockMeasures.length; i++) {
|
|
57
57
|
let blockMeasure = blockMeasures[i];
|
|
58
58
|
if (blockMeasure?.kind === "paragraph") {
|
|
59
59
|
const block = cellBlocks?.[i];
|
|
60
|
-
if (block?.kind
|
|
60
|
+
if (block?.kind !== "paragraph") continue;
|
|
61
|
+
if (floatingZones.length > 0) blockMeasure = measureParagraph(block, contentWidth, {
|
|
61
62
|
floatingZones,
|
|
62
|
-
paragraphYOffset:
|
|
63
|
+
paragraphYOffset: placeTableCellBlock({ ...flowState }, block, blockMeasure).contentTop
|
|
64
|
+
});
|
|
65
|
+
const placement = placeTableCellBlock(flowState, block, blockMeasure);
|
|
66
|
+
if (placement.leadingSpacing > 0 && isEmptyParagraph(block)) suppressibleLeadingRanges.push({
|
|
67
|
+
top: padTop + placement.top,
|
|
68
|
+
bottom: padTop + placement.contentTop
|
|
63
69
|
});
|
|
64
|
-
|
|
70
|
+
let y = padTop + placement.contentTop;
|
|
65
71
|
for (const line of blockMeasure.lines) {
|
|
66
72
|
y += line.floatSkipBefore ?? 0;
|
|
67
73
|
const top = y;
|
|
@@ -72,16 +78,15 @@ function cellBreakGeometry(cell, measure) {
|
|
|
72
78
|
});
|
|
73
79
|
bottoms.push(y);
|
|
74
80
|
}
|
|
75
|
-
|
|
76
|
-
paragraphY += blockMeasure.totalHeight;
|
|
81
|
+
bottoms.push(padTop + flowState.height);
|
|
77
82
|
} else if (blockMeasure) {
|
|
78
83
|
const block = cellBlocks?.[i];
|
|
79
|
-
if (block
|
|
80
|
-
const
|
|
84
|
+
if (!block) continue;
|
|
85
|
+
const placement = placeTableCellBlock(flowState, block, blockMeasure);
|
|
86
|
+
const blockHeight = placement.contentHeight;
|
|
81
87
|
if (blockHeight > 0) {
|
|
82
|
-
const top =
|
|
83
|
-
y
|
|
84
|
-
paragraphY += blockHeight;
|
|
88
|
+
const top = padTop + placement.contentTop;
|
|
89
|
+
const y = top + blockHeight;
|
|
85
90
|
unsafeRanges.push({
|
|
86
91
|
top,
|
|
87
92
|
bottom: y
|
|
@@ -92,9 +97,26 @@ function cellBreakGeometry(cell, measure) {
|
|
|
92
97
|
}
|
|
93
98
|
return {
|
|
94
99
|
bottoms,
|
|
95
|
-
unsafeRanges
|
|
100
|
+
unsafeRanges,
|
|
101
|
+
suppressibleLeadingRanges
|
|
96
102
|
};
|
|
97
103
|
}
|
|
104
|
+
const continuationSkipForCell = (geometry, offset) => {
|
|
105
|
+
if (!geometry.unsafeRanges.some(({ bottom }) => bottom > offset + BREAK_OFFSET_EPSILON)) return;
|
|
106
|
+
const leadingRange = geometry.suppressibleLeadingRanges.find(({ top, bottom }) => top <= offset + BREAK_OFFSET_EPSILON && bottom > offset + BREAK_OFFSET_EPSILON);
|
|
107
|
+
return leadingRange ? leadingRange.bottom - offset : 0;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Leading spacing before an empty paragraph is consumed when a split row
|
|
111
|
+
* resumes at the top of a fresh flow region. Only a whitespace band shared by
|
|
112
|
+
* every cell with remaining content is suppressible; non-empty paragraphs,
|
|
113
|
+
* line boxes, cell padding, and explicit row height retain authored space.
|
|
114
|
+
*/
|
|
115
|
+
const continuationSkipAfter = (geometries, offset) => {
|
|
116
|
+
const skips = geometries.map((geometry) => continuationSkipForCell(geometry, offset)).filter((skip) => skip !== void 0);
|
|
117
|
+
if (skips.length === 0 || skips.some((skip) => skip <= BREAK_OFFSET_EPSILON)) return 0;
|
|
118
|
+
return Math.min(...skips);
|
|
119
|
+
};
|
|
98
120
|
/** Build break geometry for a table from its block + measure. */
|
|
99
121
|
function buildTableRowBreakInfo(block, measure) {
|
|
100
122
|
const rowCount = measure.rows.length;
|
|
@@ -106,6 +128,7 @@ function buildTableRowBreakInfo(block, measure) {
|
|
|
106
128
|
}
|
|
107
129
|
rowTops.push(acc);
|
|
108
130
|
const breakOffsets = [];
|
|
131
|
+
const continuationSkips = [];
|
|
109
132
|
for (let r = 0; r < rowCount; r++) {
|
|
110
133
|
const rowHeight = measure.rows[r]?.height ?? 0;
|
|
111
134
|
const offsets = /* @__PURE__ */ new Set();
|
|
@@ -121,14 +144,24 @@ function buildTableRowBreakInfo(block, measure) {
|
|
|
121
144
|
cellGeometries.push(geometry);
|
|
122
145
|
for (const b of geometry.bottoms) if (b > 0 && b < rowHeight) offsets.add(b);
|
|
123
146
|
}
|
|
124
|
-
const
|
|
125
|
-
breakOffsets.push(
|
|
147
|
+
const sortedOffsets = [...offsets].filter((offset) => offset === rowHeight || cellGeometries.every((geometry) => geometry.unsafeRanges.every((range) => !isInsideRange(offset, range)))).sort((a, b) => a - b);
|
|
148
|
+
breakOffsets.push(sortedOffsets);
|
|
149
|
+
continuationSkips.push(sortedOffsets.map((offset) => continuationSkipAfter(cellGeometries, offset)));
|
|
126
150
|
}
|
|
127
151
|
return {
|
|
128
152
|
rowTops,
|
|
129
|
-
breakOffsets
|
|
153
|
+
breakOffsets,
|
|
154
|
+
continuationSkips
|
|
130
155
|
};
|
|
131
156
|
}
|
|
157
|
+
/** Leading empty-paragraph whitespace to consume when a row resumes after `offset`. */
|
|
158
|
+
function getRowContinuationSkip(info, rowIndex, offset) {
|
|
159
|
+
const offsets = info.breakOffsets[rowIndex];
|
|
160
|
+
const skips = info.continuationSkips[rowIndex];
|
|
161
|
+
const index = offsets?.findIndex((candidate) => Math.abs(candidate - offset) <= BREAK_OFFSET_EPSILON);
|
|
162
|
+
if (index === void 0 || index < 0) return 0;
|
|
163
|
+
return skips?.[index] ?? 0;
|
|
164
|
+
}
|
|
132
165
|
/**
|
|
133
166
|
* Given a row and how much of it has already been placed (`fromOffset`), return
|
|
134
167
|
* how many more px can be placed ending on a whole line, without exceeding
|
|
@@ -147,4 +180,4 @@ function snapRowBreak(info, rowIndex, fromOffset, maxSlice) {
|
|
|
147
180
|
return best;
|
|
148
181
|
}
|
|
149
182
|
//#endregion
|
|
150
|
-
export { buildTableRowBreakInfo, snapRowBreak };
|
|
183
|
+
export { buildTableRowBreakInfo, getRowContinuationSkip, snapRowBreak };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { OutlineStyleAttr } from "../types/documentEnumValues.js";
|
|
2
|
-
import { ImagePosition, ImageWrap, SdtProperties, SdtType, ShapeTextBody, TableWidthType } from "@stll/docx-core/model";
|
|
2
|
+
import { ImagePosition, ImageWrap, SdtProperties, SdtType, ShapeTextBody, TableCellFormatting, TableWidthType } from "@stll/docx-core/model";
|
|
3
3
|
|
|
4
4
|
//#region src/layout-engine/types.d.ts
|
|
5
5
|
declare namespace types_d_exports {
|
|
@@ -38,7 +38,12 @@ type RunFormatting = {
|
|
|
38
38
|
* `segmentByScript`) so wrapping stays correct. Absent means CJK falls back
|
|
39
39
|
* to `fontFamily`.
|
|
40
40
|
*/
|
|
41
|
-
eastAsiaFontFamily?: string;
|
|
41
|
+
eastAsiaFontFamily?: string; /** Run language metadata resolved from `w:lang`. */
|
|
42
|
+
language?: {
|
|
43
|
+
val?: string;
|
|
44
|
+
eastAsia?: string;
|
|
45
|
+
bidi?: string;
|
|
46
|
+
};
|
|
42
47
|
fontSize?: number;
|
|
43
48
|
letterSpacing?: number;
|
|
44
49
|
superscript?: boolean;
|
|
@@ -157,14 +162,16 @@ type ImageRun = {
|
|
|
157
162
|
* eigenpal #424 (opacity render pipeline).
|
|
158
163
|
*/
|
|
159
164
|
opacity?: number; /** Position for floating/anchored images */
|
|
160
|
-
position?: ImageRunPosition; /**
|
|
165
|
+
position?: ImageRunPosition; /** Whether a table-cell anchor uses the cell as its positioning scope. Undefined defaults true. */
|
|
166
|
+
layoutInCell?: boolean; /** Wrap type from DOCX (inline, square, tight, through, topAndBottom, etc.) */
|
|
161
167
|
wrapType?: ImageWrap["type"]; /** Display mode for CSS rendering */
|
|
162
168
|
displayMode?: "inline" | "block" | "float"; /** CSS float direction */
|
|
163
169
|
cssFloat?: "left" | "right" | "none"; /** Wrap distances in pixels */
|
|
164
170
|
distTop?: number;
|
|
165
171
|
distBottom?: number;
|
|
166
172
|
distLeft?: number;
|
|
167
|
-
distRight?: number;
|
|
173
|
+
distRight?: number; /** Use the image box as the exact line height for an embedded-object preview. */
|
|
174
|
+
exactLineHeight?: boolean;
|
|
168
175
|
/**
|
|
169
176
|
* wp:srcRect crop fractions in [0, 1]; emit as CSS `clip-path: inset(...)`
|
|
170
177
|
* to match Word's visible region. eigenpal #424 (image-crop subset).
|
|
@@ -286,7 +293,27 @@ type ListNumPr = {
|
|
|
286
293
|
* Paragraph block attributes.
|
|
287
294
|
*/
|
|
288
295
|
type ParagraphAttrs = {
|
|
289
|
-
alignment?: "left" | "center" | "right" | "justify"; /**
|
|
296
|
+
alignment?: "left" | "center" | "right" | "justify"; /** East Asian first/last-character restrictions (`w:kinsoku`). */
|
|
297
|
+
kinsoku?: boolean; /** Hanging punctuation (`w:overflowPunct`); defaults to enabled when omitted. */
|
|
298
|
+
overflowPunctuation?: boolean; /** Exempt this paragraph from document automatic hyphenation. */
|
|
299
|
+
suppressAutoHyphens?: boolean; /** Document-wide automatic hyphenation controls retained for line layout. */
|
|
300
|
+
automaticHyphenation?: {
|
|
301
|
+
enabled: true;
|
|
302
|
+
doNotHyphenateCaps?: boolean;
|
|
303
|
+
consecutiveLineLimit?: number; /** Maximum tolerated line-end whitespace before hyphenation, in twips. */
|
|
304
|
+
hyphenationZoneTwips?: number;
|
|
305
|
+
}; /** Document-wide custom line-edge characters and compatibility behavior. */
|
|
306
|
+
lineBreakRules?: {
|
|
307
|
+
noLineBreaksBefore?: {
|
|
308
|
+
language?: string;
|
|
309
|
+
characters: string;
|
|
310
|
+
};
|
|
311
|
+
noLineBreaksAfter?: {
|
|
312
|
+
language?: string;
|
|
313
|
+
characters: string;
|
|
314
|
+
};
|
|
315
|
+
useLegacyEthiopicAmharicRules?: boolean;
|
|
316
|
+
}; /** OOXML outline level (`w:outlineLvl`), where zero is the top level. */
|
|
290
317
|
outlineLevel?: number;
|
|
291
318
|
spacing?: ParagraphSpacing; /** Spacing sides resolved from OOXML automatic paragraph spacing. */
|
|
292
319
|
automaticSpacing?: {
|
|
@@ -338,7 +365,8 @@ type ParagraphAttrs = {
|
|
|
338
365
|
listIsBullet?: boolean;
|
|
339
366
|
listMarkerHidden?: boolean;
|
|
340
367
|
listMarkerFontFamily?: string;
|
|
341
|
-
listMarkerFontSize?: number;
|
|
368
|
+
listMarkerFontSize?: number;
|
|
369
|
+
listMarkerBold?: boolean; /** Horizontal alignment of the marker around the paragraph's list anchor. */
|
|
342
370
|
listMarkerAlignment?: "left" | "center" | "right";
|
|
343
371
|
/**
|
|
344
372
|
* `w:suff` (§17.9.25) — what follows the marker before body text.
|
|
@@ -413,6 +441,8 @@ type CellBorders = {
|
|
|
413
441
|
bottom?: CellBorderSpec;
|
|
414
442
|
left?: CellBorderSpec;
|
|
415
443
|
right?: CellBorderSpec;
|
|
444
|
+
topLeftToBottomRight?: CellBorderSpec;
|
|
445
|
+
topRightToBottomLeft?: CellBorderSpec;
|
|
416
446
|
};
|
|
417
447
|
/**
|
|
418
448
|
* A table cell with content.
|
|
@@ -424,6 +454,7 @@ type TableCell = {
|
|
|
424
454
|
rowSpan?: number;
|
|
425
455
|
width?: number;
|
|
426
456
|
verticalAlign?: "top" | "center" | "bottom";
|
|
457
|
+
textDirection?: NonNullable<TableCellFormatting["textDirection"]>;
|
|
427
458
|
background?: string;
|
|
428
459
|
borders?: CellBorders; /** Per-cell padding in pixels (from w:tcMar or table-level w:tblCellMar) */
|
|
429
460
|
padding?: {
|
|
@@ -449,7 +480,8 @@ type TableRow = {
|
|
|
449
480
|
gridAfter?: number;
|
|
450
481
|
height?: number;
|
|
451
482
|
heightRule?: "auto" | "atLeast" | "exact";
|
|
452
|
-
isHeader?: boolean;
|
|
483
|
+
isHeader?: boolean; /** `w:cantSplit`: keep this row in one flow region. */
|
|
484
|
+
cantSplit?: boolean;
|
|
453
485
|
hidden?: boolean;
|
|
454
486
|
};
|
|
455
487
|
/**
|
|
@@ -669,7 +701,10 @@ type MeasuredLine = {
|
|
|
669
701
|
* no usable horizontal room at the natural line Y. Painters render this
|
|
670
702
|
* as marginTop on the line element; measurement adds it to totalHeight.
|
|
671
703
|
*/
|
|
672
|
-
floatSkipBefore?: number;
|
|
704
|
+
floatSkipBefore?: number; /** Decorative hyphen inserted at a dictionary break without changing source text. */
|
|
705
|
+
discretionaryHyphen?: {
|
|
706
|
+
runIndex: number;
|
|
707
|
+
};
|
|
673
708
|
};
|
|
674
709
|
/**
|
|
675
710
|
* Measurement result for a paragraph block.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ImageRun } from "../layout-engine/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/layout-painter/anchoredImagePosition.d.ts
|
|
4
|
+
type PageGeometry = {
|
|
5
|
+
pageWidth: number;
|
|
6
|
+
pageHeight: number;
|
|
7
|
+
marginLeft: number;
|
|
8
|
+
marginTop: number;
|
|
9
|
+
marginRight: number;
|
|
10
|
+
marginBottom: number;
|
|
11
|
+
contentWidth: number;
|
|
12
|
+
contentHeight: number;
|
|
13
|
+
};
|
|
14
|
+
/** Coordinates relative to the page content area's top-left corner. */
|
|
15
|
+
type AnchoredImagePosition = {
|
|
16
|
+
x: number;
|
|
17
|
+
y: number;
|
|
18
|
+
side: "left" | "right";
|
|
19
|
+
};
|
|
20
|
+
/** Resolve an anchored image into page-content-relative coordinates. */
|
|
21
|
+
declare function resolveAnchoredImagePosition(imgRun: ImageRun, fragmentY: number, geometry: PageGeometry): AnchoredImagePosition;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { AnchoredImagePosition, PageGeometry, resolveAnchoredImagePosition };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { emuToPixels } from "./renderUtils.js";
|
|
2
|
+
//#region src/layout-painter/anchoredImagePosition.ts
|
|
3
|
+
function resolveHorizontalBand(relativeTo, geometry) {
|
|
4
|
+
switch (relativeTo) {
|
|
5
|
+
case "page": return {
|
|
6
|
+
baseX: -geometry.marginLeft,
|
|
7
|
+
bandWidth: geometry.pageWidth
|
|
8
|
+
};
|
|
9
|
+
case "leftMargin":
|
|
10
|
+
case "insideMargin": return {
|
|
11
|
+
baseX: -geometry.marginLeft,
|
|
12
|
+
bandWidth: geometry.marginLeft
|
|
13
|
+
};
|
|
14
|
+
case "rightMargin":
|
|
15
|
+
case "outsideMargin": return {
|
|
16
|
+
baseX: geometry.contentWidth,
|
|
17
|
+
bandWidth: geometry.marginRight
|
|
18
|
+
};
|
|
19
|
+
case "character": return {
|
|
20
|
+
baseX: 0,
|
|
21
|
+
bandWidth: 0
|
|
22
|
+
};
|
|
23
|
+
default: return {
|
|
24
|
+
baseX: 0,
|
|
25
|
+
bandWidth: geometry.contentWidth
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function resolveVerticalBand(relativeTo, fragmentY, geometry) {
|
|
30
|
+
switch (relativeTo) {
|
|
31
|
+
case "page": return {
|
|
32
|
+
baseY: -geometry.marginTop,
|
|
33
|
+
bandHeight: geometry.pageHeight
|
|
34
|
+
};
|
|
35
|
+
case "topMargin": return {
|
|
36
|
+
baseY: -geometry.marginTop,
|
|
37
|
+
bandHeight: geometry.marginTop
|
|
38
|
+
};
|
|
39
|
+
case "bottomMargin": return {
|
|
40
|
+
baseY: geometry.contentHeight,
|
|
41
|
+
bandHeight: geometry.marginBottom
|
|
42
|
+
};
|
|
43
|
+
case "paragraph":
|
|
44
|
+
case "line": return {
|
|
45
|
+
baseY: fragmentY,
|
|
46
|
+
bandHeight: 0
|
|
47
|
+
};
|
|
48
|
+
default: return {
|
|
49
|
+
baseY: 0,
|
|
50
|
+
bandHeight: geometry.contentHeight
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Resolve an anchored image into page-content-relative coordinates. */
|
|
55
|
+
function resolveAnchoredImagePosition(imgRun, fragmentY, geometry) {
|
|
56
|
+
const position = imgRun.position;
|
|
57
|
+
const contentWidth = geometry.contentWidth;
|
|
58
|
+
let side = "left";
|
|
59
|
+
let x = 0;
|
|
60
|
+
if (position?.horizontal) {
|
|
61
|
+
const h = position.horizontal;
|
|
62
|
+
const { baseX, bandWidth } = resolveHorizontalBand(h.relativeTo, geometry);
|
|
63
|
+
const horizontalHasBand = h.relativeTo !== "character";
|
|
64
|
+
if (h.align === "right" || h.align === "outside") {
|
|
65
|
+
side = "right";
|
|
66
|
+
x = horizontalHasBand ? baseX + bandWidth - imgRun.width : 0;
|
|
67
|
+
} else if (h.align === "left" || h.align === "inside") x = baseX;
|
|
68
|
+
else if (h.align === "center") x = horizontalHasBand ? baseX + (bandWidth - imgRun.width) / 2 : 0;
|
|
69
|
+
else if (h.posOffset !== void 0) {
|
|
70
|
+
x = baseX + emuToPixels(h.posOffset);
|
|
71
|
+
side = x > contentWidth / 2 ? "right" : "left";
|
|
72
|
+
} else x = baseX;
|
|
73
|
+
} else if (imgRun.cssFloat === "right") {
|
|
74
|
+
side = "right";
|
|
75
|
+
x = contentWidth - imgRun.width;
|
|
76
|
+
}
|
|
77
|
+
let y;
|
|
78
|
+
if (position?.vertical) {
|
|
79
|
+
const v = position.vertical;
|
|
80
|
+
const { baseY, bandHeight } = resolveVerticalBand(v.relativeTo, fragmentY, geometry);
|
|
81
|
+
const verticalHasBand = v.relativeTo !== "paragraph" && v.relativeTo !== "line";
|
|
82
|
+
if (v.align === "top" || v.align === "inside") y = baseY;
|
|
83
|
+
else if (v.align === "center") y = verticalHasBand ? baseY + (bandHeight - imgRun.height) / 2 : fragmentY;
|
|
84
|
+
else if (v.align === "bottom" || v.align === "outside") y = verticalHasBand ? baseY + bandHeight - imgRun.height : fragmentY;
|
|
85
|
+
else if (v.posOffset !== void 0) y = baseY + emuToPixels(v.posOffset);
|
|
86
|
+
else y = verticalHasBand ? baseY : fragmentY;
|
|
87
|
+
} else y = fragmentY;
|
|
88
|
+
return {
|
|
89
|
+
x,
|
|
90
|
+
y,
|
|
91
|
+
side
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { resolveAnchoredImagePosition };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BorderStyle, ParagraphBorders } from "../layout-engine/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/layout-painter/borderStroke.d.ts
|
|
4
|
+
type CssBorderStroke = {
|
|
5
|
+
color: string;
|
|
6
|
+
style: string;
|
|
7
|
+
width: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Preserve the optical weight of authored subpixel borders. CSS quantizes a
|
|
11
|
+
* fractional border width to one device pixel, so its color carries the
|
|
12
|
+
* fractional coverage while layout keeps the authored width.
|
|
13
|
+
*/
|
|
14
|
+
declare const resolveCssBorderStroke: (border: Pick<BorderStyle, "color" | "style" | "width">) => CssBorderStroke;
|
|
15
|
+
declare const borderStrokeToCss: (border: Pick<BorderStyle, "color" | "style" | "width">) => string;
|
|
16
|
+
type ParagraphBorderHorizontalOutsets = {
|
|
17
|
+
left: number;
|
|
18
|
+
right: number;
|
|
19
|
+
};
|
|
20
|
+
/** Resolve the outer horizontal edges of a paragraph border box. */
|
|
21
|
+
declare const resolveParagraphBorderHorizontalOutsets: (borders: ParagraphBorders, hasHorizontalRule: boolean) => ParagraphBorderHorizontalOutsets;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { borderStrokeToCss, resolveCssBorderStroke, resolveParagraphBorderHorizontalOutsets };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { pointsToPixels } from "../utils/units.js";
|
|
2
|
+
//#region src/layout-painter/borderStroke.ts
|
|
3
|
+
const DEFAULT_BORDER_COLOR = "#000000";
|
|
4
|
+
const DEFAULT_BORDER_STYLE = "solid";
|
|
5
|
+
const CSS_HAIRLINE_WIDTH = 1;
|
|
6
|
+
const PARAGRAPH_RULE_ENDPOINT_OUTSET = pointsToPixels(1.5);
|
|
7
|
+
/**
|
|
8
|
+
* Preserve the optical weight of authored subpixel borders. CSS quantizes a
|
|
9
|
+
* fractional border width to one device pixel, so its color carries the
|
|
10
|
+
* fractional coverage while layout keeps the authored width.
|
|
11
|
+
*/
|
|
12
|
+
const resolveCssBorderStroke = (border) => {
|
|
13
|
+
const authoredWidth = border.width ?? CSS_HAIRLINE_WIDTH;
|
|
14
|
+
if (authoredWidth <= 0 || authoredWidth >= CSS_HAIRLINE_WIDTH) return {
|
|
15
|
+
color: border.color ?? DEFAULT_BORDER_COLOR,
|
|
16
|
+
style: border.style ?? DEFAULT_BORDER_STYLE,
|
|
17
|
+
width: Math.max(CSS_HAIRLINE_WIDTH, authoredWidth)
|
|
18
|
+
};
|
|
19
|
+
const coveragePercent = Number((authoredWidth * 100).toFixed(4));
|
|
20
|
+
return {
|
|
21
|
+
color: `color-mix(in srgb, ${border.color ?? DEFAULT_BORDER_COLOR} ${coveragePercent}%, transparent)`,
|
|
22
|
+
style: border.style ?? DEFAULT_BORDER_STYLE,
|
|
23
|
+
width: CSS_HAIRLINE_WIDTH
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
const borderStrokeToCss = (border) => {
|
|
27
|
+
const stroke = resolveCssBorderStroke(border);
|
|
28
|
+
return `${stroke.width}px ${stroke.style} ${stroke.color}`;
|
|
29
|
+
};
|
|
30
|
+
/** Resolve the outer horizontal edges of a paragraph border box. */
|
|
31
|
+
const resolveParagraphBorderHorizontalOutsets = (borders, hasHorizontalRule) => {
|
|
32
|
+
const ruleOutset = hasHorizontalRule ? PARAGRAPH_RULE_ENDPOINT_OUTSET : 0;
|
|
33
|
+
return {
|
|
34
|
+
left: borders.left ? (borders.left.space ?? 0) + (borders.left.width ?? 0) : ruleOutset,
|
|
35
|
+
right: borders.right ? (borders.right.space ?? 0) + (borders.right.width ?? 0) : ruleOutset
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { borderStrokeToCss, resolveCssBorderStroke, resolveParagraphBorderHorizontalOutsets };
|
|
@@ -10,7 +10,7 @@ declare const IMAGE_CLASS_NAMES: {
|
|
|
10
10
|
imageAnchored: string;
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
|
-
* Structural shape required to apply
|
|
13
|
+
* Structural shape required to apply OOXML per-image visual attributes:
|
|
14
14
|
* `wp:srcRect` crop fractions and `a:alphaModFix` opacity. `ImageRun` and
|
|
15
15
|
* `ImageBlock` both satisfy this, so callers don't need an adapter.
|
|
16
16
|
*/
|
|
@@ -32,10 +32,11 @@ type ImageVisualAttrs = {
|
|
|
32
32
|
* `0`) — that bug otherwise hides every plain image behind `opacity: 0`.
|
|
33
33
|
*/
|
|
34
34
|
declare function hasImageVisualAttrs(v: ImageVisualAttrs): boolean;
|
|
35
|
+
declare function hasImageCrop(v: ImageVisualAttrs): boolean;
|
|
35
36
|
/**
|
|
36
|
-
* Apply
|
|
37
|
+
* Apply an OOXML `<a:srcRect>` crop to an `<img>` whose parent already has
|
|
37
38
|
* `overflow: hidden` and is sized to the *visible* (cropped) dimensions
|
|
38
|
-
* (this matches `wp:extent` semantics:
|
|
39
|
+
* (this matches `wp:extent` semantics: the extent is the cropped
|
|
39
40
|
* frame, with `<a:stretch><a:fillRect/>` stretching the cropped source to
|
|
40
41
|
* fill it).
|
|
41
42
|
*
|
|
@@ -85,4 +86,4 @@ type RenderImageFragmentOptions = {
|
|
|
85
86
|
*/
|
|
86
87
|
declare function renderImageFragment(fragment: ImageFragment, block: ImageBlock, _measure: ImageMeasure, _context: RenderContext, options?: RenderImageFragmentOptions): HTMLElement;
|
|
87
88
|
//#endregion
|
|
88
|
-
export { IMAGE_CLASS_NAMES, ImageVisualAttrs, RenderImageFragmentOptions, applyImageVisualAttrs, hasImageVisualAttrs, renderImageFragment, wrapImageWithCrop };
|
|
89
|
+
export { IMAGE_CLASS_NAMES, ImageVisualAttrs, RenderImageFragmentOptions, applyImageVisualAttrs, hasImageCrop, hasImageVisualAttrs, renderImageFragment, wrapImageWithCrop };
|
|
@@ -18,12 +18,15 @@ const IMAGE_CLASS_NAMES = {
|
|
|
18
18
|
*/
|
|
19
19
|
function hasImageVisualAttrs(v) {
|
|
20
20
|
if (v.opacity != null && v.opacity < 1) return true;
|
|
21
|
+
return hasImageCrop(v);
|
|
22
|
+
}
|
|
23
|
+
function hasImageCrop(v) {
|
|
21
24
|
return Boolean(v.cropTop || v.cropRight || v.cropBottom || v.cropLeft);
|
|
22
25
|
}
|
|
23
26
|
/**
|
|
24
|
-
* Apply
|
|
27
|
+
* Apply an OOXML `<a:srcRect>` crop to an `<img>` whose parent already has
|
|
25
28
|
* `overflow: hidden` and is sized to the *visible* (cropped) dimensions
|
|
26
|
-
* (this matches `wp:extent` semantics:
|
|
29
|
+
* (this matches `wp:extent` semantics: the extent is the cropped
|
|
27
30
|
* frame, with `<a:stretch><a:fillRect/>` stretching the cropped source to
|
|
28
31
|
* fill it).
|
|
29
32
|
*
|
|
@@ -54,8 +57,19 @@ function applyImageVisualAttrs(img, v) {
|
|
|
54
57
|
const fh = 1 / remainingH;
|
|
55
58
|
img.style.width = `${fw * 100}%`;
|
|
56
59
|
img.style.height = `${fh * 100}%`;
|
|
60
|
+
img.style.maxWidth = "none";
|
|
61
|
+
img.style.maxHeight = "none";
|
|
57
62
|
img.style.marginLeft = `${-left * fw * 100}%`;
|
|
58
|
-
img.style.
|
|
63
|
+
const existingTransform = img.style.transform;
|
|
64
|
+
if (existingTransform) {
|
|
65
|
+
const visibleCenterX = (left + 1 - right) * 50;
|
|
66
|
+
const visibleCenterY = (top + 1 - bottom) * 50;
|
|
67
|
+
img.style.transformOrigin = `${visibleCenterX}% ${visibleCenterY}%`;
|
|
68
|
+
}
|
|
69
|
+
if (top !== 0) {
|
|
70
|
+
const cropTransform = `translateY(${-top * 100}%)`;
|
|
71
|
+
img.style.transform = existingTransform ? `${existingTransform} ${cropTransform}` : cropTransform;
|
|
72
|
+
}
|
|
59
73
|
img.style.objectFit = "fill";
|
|
60
74
|
}
|
|
61
75
|
/**
|
|
@@ -127,4 +141,4 @@ function renderImageFragment(fragment, block, _measure, _context, options = {})
|
|
|
127
141
|
return containerEl;
|
|
128
142
|
}
|
|
129
143
|
//#endregion
|
|
130
|
-
export { IMAGE_CLASS_NAMES, applyImageVisualAttrs, hasImageVisualAttrs, renderImageFragment, wrapImageWithCrop };
|
|
144
|
+
export { IMAGE_CLASS_NAMES, applyImageVisualAttrs, hasImageCrop, hasImageVisualAttrs, renderImageFragment, wrapImageWithCrop };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { document_d_exports } from "../types/document.js";
|
|
2
2
|
import { FootnoteContent, HeaderFooterContent, ImageRun, Page, isFloatingImageRun } from "../layout-engine/types.js";
|
|
3
3
|
import { RenderContext, emuToPixels } from "./renderUtils.js";
|
|
4
|
+
import { AnchoredImagePosition, PageGeometry } from "./anchoredImagePosition.js";
|
|
4
5
|
import { BlockLookup } from "./index.js";
|
|
5
6
|
|
|
6
7
|
//#region src/layout-painter/renderPage.d.ts
|
|
@@ -157,32 +158,6 @@ declare function resolveHeaderFooterFloatLeft(width: number, h: {
|
|
|
157
158
|
align?: string;
|
|
158
159
|
alignment?: string;
|
|
159
160
|
} | undefined, layout: HeaderFooterLayoutInfo): string;
|
|
160
|
-
/**
|
|
161
|
-
* Page geometry needed to translate OOXML `relativeFrom` anchors into
|
|
162
|
-
* painter coordinates. All values are in CSS pixels. Mirrors the upstream
|
|
163
|
-
* (eigenpal docx-editor) `PageGeometry` shape introduced in #424 so the
|
|
164
|
-
* anchor math stays identical across the two codebases.
|
|
165
|
-
*/
|
|
166
|
-
type PageGeometry = {
|
|
167
|
-
pageWidth: number;
|
|
168
|
-
pageHeight: number;
|
|
169
|
-
marginLeft: number;
|
|
170
|
-
marginTop: number;
|
|
171
|
-
marginRight: number;
|
|
172
|
-
marginBottom: number;
|
|
173
|
-
contentWidth: number;
|
|
174
|
-
contentHeight: number;
|
|
175
|
-
};
|
|
176
|
-
/**
|
|
177
|
-
* Resolved on-page coordinates for an anchored floating image.
|
|
178
|
-
* `x` / `y` are in content-area-relative pixels (content origin = (0, 0)).
|
|
179
|
-
* `side` feeds the text-wrap exclusion zone helper.
|
|
180
|
-
*/
|
|
181
|
-
type AnchoredImagePosition = {
|
|
182
|
-
x: number;
|
|
183
|
-
y: number;
|
|
184
|
-
side: "left" | "right";
|
|
185
|
-
};
|
|
186
161
|
/**
|
|
187
162
|
* Resolve the on-page coordinates of an anchored floating image.
|
|
188
163
|
*
|
|
@@ -290,4 +265,4 @@ declare function findPageShellForPmPos(container: HTMLElement, pmPos: number): {
|
|
|
290
265
|
isExact: boolean;
|
|
291
266
|
} | null;
|
|
292
267
|
//#endregion
|
|
293
|
-
export { AnchoredImagePosition, FootnoteRenderItem, type HeaderFooterContent, HeaderFooterLayoutInfo, PAGE_CLASS_NAMES, PAINTER_PAINTED_EVENT, PageFloatingImage, PageGeometry, PainterPaintedDetail, type RenderContext, RenderPageOptions, applySectionHeaderFooterOptions, calculateFootnoteAreaRenderHeight, computePageFingerprint, emuToPixels, findPageShellForPmPos, floatingTableReservesBand, getDefaultPageFontFamily, isFloatingImageRun, renderAllPagesNow, renderFloatingImagesLayer, renderFootnoteArea, renderPage, renderPages, resolveAnchoredImagePosition, resolveHeaderFooterFloatLeft };
|
|
268
|
+
export { type AnchoredImagePosition, FootnoteRenderItem, type HeaderFooterContent, HeaderFooterLayoutInfo, PAGE_CLASS_NAMES, PAINTER_PAINTED_EVENT, PageFloatingImage, type PageGeometry, PainterPaintedDetail, type RenderContext, RenderPageOptions, applySectionHeaderFooterOptions, calculateFootnoteAreaRenderHeight, computePageFingerprint, emuToPixels, findPageShellForPmPos, floatingTableReservesBand, getDefaultPageFontFamily, isFloatingImageRun, renderAllPagesNow, renderFloatingImagesLayer, renderFootnoteArea, renderPage, renderPages, resolveAnchoredImagePosition, resolveHeaderFooterFloatLeft };
|