@stll/folio-core 0.7.0 → 0.9.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/blockRange.d.ts +13 -2
- package/dist/ai-edits/blockRange.js +23 -2
- package/dist/ai-edits/headless.d.ts +31 -4
- package/dist/ai-edits/headless.js +148 -35
- package/dist/ai-edits/index.d.ts +6 -4
- package/dist/ai-edits/index.js +4 -1
- package/dist/ai-edits/scoped-reading.d.ts +9 -0
- package/dist/ai-edits/scoped-reading.js +60 -0
- package/dist/ai-edits/snapshot.js +53 -7
- package/dist/ai-edits/types.d.ts +46 -3
- package/dist/compat/eigenpal.d.ts +8 -3
- package/dist/compat/eigenpal.js +7 -2
- package/dist/controller/fontReadiness.d.ts +29 -0
- package/dist/controller/fontReadiness.js +139 -0
- package/dist/controller/latestRequestGate.d.ts +13 -0
- package/dist/controller/latestRequestGate.js +16 -0
- package/dist/controller/layoutPipeline.js +88 -10
- package/dist/document-operations.d.ts +10 -3
- package/dist/document-operations.js +29 -14
- package/dist/docx/blockContentParser.js +53 -10
- package/dist/docx/commentParser.js +1 -1
- package/dist/docx/compatibility.d.ts +30 -2
- package/dist/docx/compatibility.js +118 -39
- package/dist/docx/conformance.d.ts +6 -0
- package/dist/docx/conformance.js +18 -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/ensureParaIds.d.ts +29 -0
- package/dist/docx/ensureParaIds.js +423 -0
- 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/normalizeBaseDirection.js +1 -1
- package/dist/docx/numberingParser.js +2 -0
- package/dist/docx/paragraphParser.js +21 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +141 -2
- package/dist/docx/parser.d.ts +1 -1
- package/dist/docx/parser.js +14 -9
- package/dist/docx/rezip.js +70 -5
- package/dist/docx/runConsolidator.js +4 -0
- package/dist/docx/runParser.js +19 -1
- package/dist/docx/selectiveSave.js +3 -3
- package/dist/docx/selectiveXmlPatch.d.ts +10 -1
- package/dist/docx/selectiveXmlPatch.js +1 -1
- 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 +8 -0
- package/dist/docx/serializer/runSerializer.js +14 -2
- 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 +29 -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 +19 -1
- package/dist/docx/textBoxParser.js +6 -1
- package/dist/docx/vmlImageParser.js +146 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +5916 -5916
- package/dist/i18n/messages/catalogs.gen.js +5910 -5910
- package/dist/index.d.ts +8 -3
- package/dist/index.js +7 -2
- 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 +22 -3
- package/dist/layout-bridge/convert/paragraphFrames.d.ts +7 -0
- package/dist/layout-bridge/convert/paragraphFrames.js +136 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +14 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +93 -17
- package/dist/layout-bridge/engine/hitTest.js +2 -1
- package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
- package/dist/layout-bridge/engine/measuring/index.js +2 -1
- package/dist/layout-bridge/engine/selectionRects.js +2 -1
- package/dist/layout-engine/headerFooterRefs.d.ts +7 -0
- package/dist/layout-engine/headerFooterRefs.js +40 -0
- package/dist/layout-engine/index.d.ts +3 -2
- package/dist/layout-engine/index.js +68 -106
- package/dist/layout-engine/measure/cache.js +11 -3
- 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 +4 -1
- package/dist/layout-engine/measure/listMarkerWidth.js +33 -8
- package/dist/layout-engine/measure/measureBlocks.d.ts +4 -2
- package/dist/layout-engine/measure/measureBlocks.js +138 -86
- 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 +346 -74
- 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 +37 -29
- 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.d.ts +15 -0
- package/dist/layout-engine/measure/tableCellGrid.js +62 -0
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +18 -0
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +32 -0
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +18 -0
- package/dist/layout-engine/measure/textMeasurementPolicy.js +24 -0
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +7 -6
- package/dist/layout-engine/paragraphFrame.d.ts +22 -0
- package/dist/layout-engine/paragraphFrame.js +17 -0
- package/dist/layout-engine/paragraphSequence.d.ts +7 -0
- package/dist/layout-engine/paragraphSequence.js +25 -0
- package/dist/layout-engine/paragraphSpacing.d.ts +17 -0
- package/dist/layout-engine/paragraphSpacing.js +30 -0
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +63 -0
- package/dist/layout-engine/renderedBreakReconciliation.js +86 -0
- package/dist/layout-engine/tableRowBreak.d.ts +5 -2
- package/dist/layout-engine/tableRowBreak.js +62 -29
- package/dist/layout-engine/types.d.ts +54 -12
- package/dist/layout-engine/types.js +15 -2
- 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 +15 -101
- package/dist/layout-painter/renderParagraph.js +45 -26
- package/dist/layout-painter/renderTable.d.ts +2 -0
- package/dist/layout-painter/renderTable.js +257 -47
- package/dist/layout-painter/renderTextBox.js +17 -7
- package/dist/managers/DocumentLoaderManager.d.ts +1 -1
- package/dist/managers/DocumentLoaderManager.js +2 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
- package/dist/paged-layout/sectionBlockWidths.js +9 -0
- package/dist/paged-layout/sectionGeometry.js +1 -1
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +32 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +35 -18
- package/dist/prosemirror/conversion/toProseDoc.js +73 -37
- package/dist/prosemirror/extensions/StarterKit.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +8 -2
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ListExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +68 -16
- 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 +2 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +4 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
- 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 +16 -12
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +2 -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.js +13 -3
- package/dist/server.d.ts +9 -4
- package/dist/server.js +7 -2
- 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/types/index.d.ts +2 -1
- package/dist/utils/createDocument.d.ts +12 -2
- package/dist/utils/createDocument.js +55 -36
- package/dist/utils/fontResolver.js +6 -6
- package/dist/utils/formatToStyle.js +1 -1
- package/dist/utils/hexId.d.ts +8 -1
- package/dist/utils/hexId.js +11 -3
- package/dist/utils/paragraphFormattingMerge.d.ts +14 -3
- package/dist/utils/paragraphFormattingMerge.js +14 -4
- package/package.json +5 -1
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import czechHyphenation from "hyphen/cs/index.js";
|
|
2
|
+
import britishEnglishHyphenation from "hyphen/en-gb/index.js";
|
|
3
|
+
import americanEnglishHyphenation from "hyphen/en-us/index.js";
|
|
4
|
+
import slovakHyphenation from "hyphen/sk/index.js";
|
|
5
|
+
//#region src/layout-engine/measure/lineBreakProvider.ts
|
|
6
|
+
/**
|
|
7
|
+
* Replaceable line-break policy for the layout engine.
|
|
8
|
+
*
|
|
9
|
+
* Providers return UTF-16 offsets so their output composes directly with the
|
|
10
|
+
* run and ProseMirror positions used by the rest of the layout pipeline. The
|
|
11
|
+
* default provider uses the platform's Unicode segmenter, then applies the
|
|
12
|
+
* OOXML line-edge restrictions that are available in the flow model.
|
|
13
|
+
*/
|
|
14
|
+
const { hyphenateSync: hyphenateCzech } = czechHyphenation;
|
|
15
|
+
const { hyphenateSync: hyphenateBritishEnglish } = britishEnglishHyphenation;
|
|
16
|
+
const { hyphenateSync: hyphenateAmericanEnglish } = americanEnglishHyphenation;
|
|
17
|
+
const { hyphenateSync: hyphenateSlovak } = slovakHyphenation;
|
|
18
|
+
const SEGMENTER_CACHE_LIMIT = 16;
|
|
19
|
+
const DEFAULT_SEGMENTER_KEY = "";
|
|
20
|
+
const SOFT_HYPHEN = "";
|
|
21
|
+
const MAX_HYPHENATION_WORD_LENGTH = 256;
|
|
22
|
+
const wordSegmenters = /* @__PURE__ */ new Map();
|
|
23
|
+
const graphemeSegmenters = /* @__PURE__ */ new Map();
|
|
24
|
+
const segmenterLocale = (locale) => {
|
|
25
|
+
const language = locale?.trim().replaceAll("_", "-").split("-").at(0);
|
|
26
|
+
return language && /^[a-z]{2,3}$/iu.test(language) ? language.toLowerCase() : void 0;
|
|
27
|
+
};
|
|
28
|
+
const DICTIONARY_BREAK_SCRIPT = /[\p{Script=Thai}\p{Script=Lao}\p{Script=Khmer}\p{Script=Myanmar}]/u;
|
|
29
|
+
const CJK_SCRIPT = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
30
|
+
const BREAK_AFTER_CHARACTER = /* @__PURE__ */ new Set([
|
|
31
|
+
"-",
|
|
32
|
+
"֊",
|
|
33
|
+
"־",
|
|
34
|
+
"᐀",
|
|
35
|
+
"᠆",
|
|
36
|
+
"‐",
|
|
37
|
+
"⸗",
|
|
38
|
+
"⹀",
|
|
39
|
+
"゠",
|
|
40
|
+
"﹣",
|
|
41
|
+
"-",
|
|
42
|
+
"",
|
|
43
|
+
""
|
|
44
|
+
]);
|
|
45
|
+
const CZECH_ONE_LETTER_PREPOSITIONS = /* @__PURE__ */ new Set([
|
|
46
|
+
"k",
|
|
47
|
+
"o",
|
|
48
|
+
"s",
|
|
49
|
+
"u",
|
|
50
|
+
"v",
|
|
51
|
+
"z"
|
|
52
|
+
]);
|
|
53
|
+
const DEFAULT_PROHIBITED_LINE_START = /* @__PURE__ */ new Set([
|
|
54
|
+
"!",
|
|
55
|
+
"%",
|
|
56
|
+
")",
|
|
57
|
+
",",
|
|
58
|
+
".",
|
|
59
|
+
":",
|
|
60
|
+
";",
|
|
61
|
+
"?",
|
|
62
|
+
"]",
|
|
63
|
+
"}",
|
|
64
|
+
"、",
|
|
65
|
+
"。",
|
|
66
|
+
"〉",
|
|
67
|
+
"》",
|
|
68
|
+
"」",
|
|
69
|
+
"』",
|
|
70
|
+
"】",
|
|
71
|
+
"〕",
|
|
72
|
+
")",
|
|
73
|
+
"]",
|
|
74
|
+
"}",
|
|
75
|
+
",",
|
|
76
|
+
".",
|
|
77
|
+
":",
|
|
78
|
+
";",
|
|
79
|
+
"!",
|
|
80
|
+
"?",
|
|
81
|
+
"…",
|
|
82
|
+
"’",
|
|
83
|
+
"”"
|
|
84
|
+
]);
|
|
85
|
+
const DEFAULT_PROHIBITED_LINE_END = /* @__PURE__ */ new Set([
|
|
86
|
+
"$",
|
|
87
|
+
"(",
|
|
88
|
+
"[",
|
|
89
|
+
"{",
|
|
90
|
+
"£",
|
|
91
|
+
"¥",
|
|
92
|
+
"〈",
|
|
93
|
+
"《",
|
|
94
|
+
"「",
|
|
95
|
+
"『",
|
|
96
|
+
"【",
|
|
97
|
+
"〔",
|
|
98
|
+
"(",
|
|
99
|
+
"[",
|
|
100
|
+
"{",
|
|
101
|
+
"‘",
|
|
102
|
+
"“"
|
|
103
|
+
]);
|
|
104
|
+
const getSegmenter = (cache, granularity, locale) => {
|
|
105
|
+
const normalizedLocale = segmenterLocale(locale);
|
|
106
|
+
const key = normalizedLocale ?? DEFAULT_SEGMENTER_KEY;
|
|
107
|
+
const cached = cache.get(key);
|
|
108
|
+
if (cached) return cached;
|
|
109
|
+
const segmenter = new Intl.Segmenter(normalizedLocale, { granularity });
|
|
110
|
+
if (cache.size >= SEGMENTER_CACHE_LIMIT) {
|
|
111
|
+
const oldestKey = cache.keys().next().value;
|
|
112
|
+
if (typeof oldestKey === "string") cache.delete(oldestKey);
|
|
113
|
+
}
|
|
114
|
+
cache.set(key, segmenter);
|
|
115
|
+
return segmenter;
|
|
116
|
+
};
|
|
117
|
+
const firstCodePoint = (text, index) => {
|
|
118
|
+
if (index >= text.length) return;
|
|
119
|
+
return String.fromCodePoint(text.codePointAt(index) ?? 0);
|
|
120
|
+
};
|
|
121
|
+
const previousCodePoint = (text, index) => {
|
|
122
|
+
if (index <= 0) return;
|
|
123
|
+
const trailing = text.charCodeAt(index - 1);
|
|
124
|
+
if (trailing >= 56320 && trailing <= 57343 && index >= 2) return text.slice(index - 2, index);
|
|
125
|
+
return text[index - 1];
|
|
126
|
+
};
|
|
127
|
+
const isProhibitedLineStart = (character, policy) => character !== void 0 && policy?.kinsoku !== false && (policy?.noLineBreaksBefore !== void 0 ? policy.noLineBreaksBefore.includes(character) : DEFAULT_PROHIBITED_LINE_START.has(character));
|
|
128
|
+
const isProhibitedLineEnd = (character, policy) => character !== void 0 && policy?.kinsoku !== false && (policy?.noLineBreaksAfter !== void 0 ? policy.noLineBreaksAfter.includes(character) : DEFAULT_PROHIBITED_LINE_END.has(character));
|
|
129
|
+
const isCjkLineBreakParticipant = (character, policy) => character !== void 0 && (CJK_SCRIPT.test(character) || DEFAULT_PROHIBITED_LINE_START.has(character) || DEFAULT_PROHIBITED_LINE_END.has(character) || policy?.noLineBreaksBefore?.includes(character) === true || policy?.noLineBreaksAfter?.includes(character) === true);
|
|
130
|
+
const isLegacyEthiopicBreakCharacter = (character, policy) => {
|
|
131
|
+
if (!policy?.useLegacyEthiopicAmharicRules || character === void 0) return false;
|
|
132
|
+
const codePoint = character.codePointAt(0);
|
|
133
|
+
return codePoint !== void 0 && codePoint >= 4961 && codePoint <= 4968;
|
|
134
|
+
};
|
|
135
|
+
const czechProtectedBreaks = (text, policy) => {
|
|
136
|
+
const breaks = /* @__PURE__ */ new Set();
|
|
137
|
+
if (segmenterLocale(policy?.locale) !== "cs") return breaks;
|
|
138
|
+
let tokenStart = 0;
|
|
139
|
+
let index = 0;
|
|
140
|
+
while (index < text.length) {
|
|
141
|
+
const character = firstCodePoint(text, index);
|
|
142
|
+
if (character === void 0) break;
|
|
143
|
+
if (!/\s/u.test(character)) {
|
|
144
|
+
index += character.length;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const token = text.slice(tokenStart, index);
|
|
148
|
+
const protectsNextWord = token.length === 1 && CZECH_ONE_LETTER_PREPOSITIONS.has(token.toLocaleLowerCase("cs"));
|
|
149
|
+
while (index < text.length) {
|
|
150
|
+
const whitespace = firstCodePoint(text, index);
|
|
151
|
+
if (whitespace === void 0 || !/\s/u.test(whitespace)) break;
|
|
152
|
+
index += whitespace.length;
|
|
153
|
+
if (protectsNextWord) breaks.add(index);
|
|
154
|
+
}
|
|
155
|
+
tokenStart = index;
|
|
156
|
+
}
|
|
157
|
+
return breaks;
|
|
158
|
+
};
|
|
159
|
+
const allowsBreak = (text, index, policy) => {
|
|
160
|
+
const previous = previousCodePoint(text, index);
|
|
161
|
+
const next = firstCodePoint(text, index);
|
|
162
|
+
return !isProhibitedLineEnd(previous, policy) && !isProhibitedLineStart(next, policy);
|
|
163
|
+
};
|
|
164
|
+
const pushBreak = (breaks, text, index, policy) => {
|
|
165
|
+
if (index <= 0 || index > text.length || breaks.at(-1) === index) return;
|
|
166
|
+
if (allowsBreak(text, index, policy)) breaks.push(index);
|
|
167
|
+
};
|
|
168
|
+
const findUnicodeGraphemeBreaks = (text, policy) => {
|
|
169
|
+
const breaks = [];
|
|
170
|
+
for (const segment of getSegmenter(graphemeSegmenters, "grapheme", policy?.locale).segment(text)) {
|
|
171
|
+
const end = segment.index + segment.segment.length;
|
|
172
|
+
breaks.push(end);
|
|
173
|
+
}
|
|
174
|
+
return breaks;
|
|
175
|
+
};
|
|
176
|
+
const findUnicodeBreaks = (text, policy) => {
|
|
177
|
+
if (text.length === 0) return [];
|
|
178
|
+
const breaks = [];
|
|
179
|
+
const graphemeBreaks = findUnicodeGraphemeBreaks(text, policy);
|
|
180
|
+
for (const index of graphemeBreaks) {
|
|
181
|
+
const previous = previousCodePoint(text, index);
|
|
182
|
+
if (previous !== void 0 && (/\s/u.test(previous) || BREAK_AFTER_CHARACTER.has(previous) || isLegacyEthiopicBreakCharacter(previous, policy))) pushBreak(breaks, text, index, policy);
|
|
183
|
+
}
|
|
184
|
+
const wordSegments = [...getSegmenter(wordSegmenters, "word", policy?.locale).segment(text)];
|
|
185
|
+
for (const [segmentIndex, segment] of wordSegments.entries()) {
|
|
186
|
+
const end = segment.index + segment.segment.length;
|
|
187
|
+
const nextSegment = wordSegments[segmentIndex + 1];
|
|
188
|
+
if (segment.isWordLike && nextSegment?.isWordLike === true && DICTIONARY_BREAK_SCRIPT.test(segment.segment + nextSegment.segment)) pushBreak(breaks, text, end, policy);
|
|
189
|
+
}
|
|
190
|
+
if (CJK_SCRIPT.test(text)) for (const index of graphemeBreaks) {
|
|
191
|
+
const previous = previousCodePoint(text, index);
|
|
192
|
+
if (isCjkLineBreakParticipant(previous, policy)) pushBreak(breaks, text, index, policy);
|
|
193
|
+
}
|
|
194
|
+
const protectedBreaks = czechProtectedBreaks(text, policy);
|
|
195
|
+
return [...new Set(breaks)].filter((index) => !protectedBreaks.has(index)).sort((left, right) => left - right);
|
|
196
|
+
};
|
|
197
|
+
const hyphenatorFor = (locale) => {
|
|
198
|
+
const normalized = locale?.trim().replaceAll("_", "-").toLowerCase();
|
|
199
|
+
if (!normalized) return;
|
|
200
|
+
if (normalized === "en-gb" || normalized.startsWith("en-gb-")) return hyphenateBritishEnglish;
|
|
201
|
+
if (normalized === "en-us" || normalized.startsWith("en-us-")) return hyphenateAmericanEnglish;
|
|
202
|
+
if (normalized === "cs" || normalized.startsWith("cs-")) return hyphenateCzech;
|
|
203
|
+
if (normalized === "sk" || normalized.startsWith("sk-")) return hyphenateSlovak;
|
|
204
|
+
};
|
|
205
|
+
const isAllCapsWord = (text, locale) => {
|
|
206
|
+
const letters = [...text].filter((character) => /\p{Letter}/u.test(character)).join("");
|
|
207
|
+
if (letters.length === 0) return false;
|
|
208
|
+
const casingLocale = segmenterLocale(locale);
|
|
209
|
+
return letters === letters.toLocaleUpperCase(casingLocale) && letters !== letters.toLocaleLowerCase(casingLocale);
|
|
210
|
+
};
|
|
211
|
+
const findPatternHyphenationBreaks = (text, policy) => {
|
|
212
|
+
if (text.length > 256 || text.includes(SOFT_HYPHEN)) return [];
|
|
213
|
+
const hyphenate = hyphenatorFor(policy?.locale);
|
|
214
|
+
if (!hyphenate) return [];
|
|
215
|
+
if (policy?.doNotHyphenateCaps && (policy.renderedAllCaps === true || isAllCapsWord(text, policy.locale))) return [];
|
|
216
|
+
const hyphenated = hyphenate(text);
|
|
217
|
+
const breaks = [];
|
|
218
|
+
let sourceOffset = 0;
|
|
219
|
+
for (const character of hyphenated) {
|
|
220
|
+
if (character === SOFT_HYPHEN) {
|
|
221
|
+
breaks.push(sourceOffset);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
sourceOffset += character.length;
|
|
225
|
+
}
|
|
226
|
+
return sourceOffset === text.length ? breaks : [];
|
|
227
|
+
};
|
|
228
|
+
const isDefaultHangingPunctuation = (text, policy) => {
|
|
229
|
+
const characters = [...text];
|
|
230
|
+
return characters.length > 0 && characters.every((character) => isProhibitedLineStart(character, policy));
|
|
231
|
+
};
|
|
232
|
+
const defaultLineBreakProvider = {
|
|
233
|
+
findBreaks: findUnicodeBreaks,
|
|
234
|
+
findGraphemeBreaks: findUnicodeGraphemeBreaks,
|
|
235
|
+
findHyphenationBreaks: findPatternHyphenationBreaks,
|
|
236
|
+
isHangingPunctuation: isDefaultHangingPunctuation
|
|
237
|
+
};
|
|
238
|
+
let activeLineBreakProvider = defaultLineBreakProvider;
|
|
239
|
+
let lineBreakProviderGeneration = 0;
|
|
240
|
+
const getLineBreakProvider = () => activeLineBreakProvider;
|
|
241
|
+
/** Changes whenever the active provider changes, so layout caches cannot go stale. */
|
|
242
|
+
const getLineBreakProviderGeneration = () => lineBreakProviderGeneration;
|
|
243
|
+
const setLineBreakProvider = (provider) => {
|
|
244
|
+
activeLineBreakProvider = provider;
|
|
245
|
+
lineBreakProviderGeneration += 1;
|
|
246
|
+
};
|
|
247
|
+
const resetLineBreakProvider = () => {
|
|
248
|
+
activeLineBreakProvider = defaultLineBreakProvider;
|
|
249
|
+
lineBreakProviderGeneration += 1;
|
|
250
|
+
};
|
|
251
|
+
//#endregion
|
|
252
|
+
export { MAX_HYPHENATION_WORD_LENGTH, defaultLineBreakProvider, getLineBreakProvider, getLineBreakProviderGeneration, resetLineBreakProvider, setLineBreakProvider };
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { LineBreakPolicy } from "./lineBreakProvider.js";
|
|
2
|
+
|
|
1
3
|
//#region src/layout-engine/measure/lineBreaks.d.ts
|
|
2
4
|
/**
|
|
3
5
|
* Indices in `text` where a line may end. Latin text breaks after
|
|
4
6
|
* whitespace or hyphen; CJK text can break after every ideograph so a
|
|
5
7
|
* partial line is filled instead of pushing the whole run to the next line.
|
|
6
8
|
*/
|
|
7
|
-
declare
|
|
9
|
+
declare const findWordBreaks: (text: string, policy?: LineBreakPolicy) => number[];
|
|
10
|
+
declare const findGraphemeBreaks: (text: string, policy?: LineBreakPolicy) => number[];
|
|
11
|
+
declare const findHyphenationBreaks: (text: string, policy?: LineBreakPolicy) => number[];
|
|
12
|
+
declare const isHangingPunctuation: (text: string, policy?: LineBreakPolicy) => boolean;
|
|
8
13
|
declare function isBreakChar(char: string | undefined): boolean;
|
|
9
14
|
//#endregion
|
|
10
|
-
export { findWordBreaks, isBreakChar };
|
|
15
|
+
export { findGraphemeBreaks, findHyphenationBreaks, findWordBreaks, isBreakChar, isHangingPunctuation };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defaultLineBreakProvider, getLineBreakProvider } from "./lineBreakProvider.js";
|
|
1
2
|
import { isCjkCodePoint } from "../../utils/scriptSegments.js";
|
|
2
3
|
//#region src/layout-engine/measure/lineBreaks.ts
|
|
3
4
|
/**
|
|
@@ -5,26 +6,18 @@ import { isCjkCodePoint } from "../../utils/scriptSegments.js";
|
|
|
5
6
|
* whitespace or hyphen; CJK text can break after every ideograph so a
|
|
6
7
|
* partial line is filled instead of pushing the whole run to the next line.
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const char = text[index];
|
|
15
|
-
if (char === " " || char === "-" || char === " ") breaks.push(index + charLength);
|
|
16
|
-
else if (isCjkCodePoint(codePoint)) breaks.push(index + charLength);
|
|
17
|
-
index += charLength;
|
|
18
|
-
}
|
|
19
|
-
return breaks;
|
|
20
|
-
}
|
|
9
|
+
const findWordBreaks = (text, policy) => getLineBreakProvider().findBreaks(text, policy);
|
|
10
|
+
const findGraphemeBreaks = (text, policy) => getLineBreakProvider().findGraphemeBreaks(text, policy);
|
|
11
|
+
const findHyphenationBreaks = (text, policy) => getLineBreakProvider().findHyphenationBreaks?.(text, policy) ?? [];
|
|
12
|
+
const isHangingPunctuation = (text, policy) => {
|
|
13
|
+
return (getLineBreakProvider().isHangingPunctuation ?? defaultLineBreakProvider.isHangingPunctuation)?.(text, policy) ?? false;
|
|
14
|
+
};
|
|
21
15
|
function isBreakChar(char) {
|
|
22
16
|
if (char === void 0) return false;
|
|
23
|
-
if (char === "
|
|
24
|
-
const codePoint = char.codePointAt(0);
|
|
25
|
-
if (codePoint === void 0) return false;
|
|
17
|
+
if (/\s/u.test(char) || char === "-" || char === "" || char === "") return true;
|
|
26
18
|
if (char >= "\udc00" && char <= "\udfff") return true;
|
|
27
|
-
|
|
19
|
+
const codePoint = char.codePointAt(0);
|
|
20
|
+
return codePoint !== void 0 && isCjkCodePoint(codePoint);
|
|
28
21
|
}
|
|
29
22
|
//#endregion
|
|
30
|
-
export { findWordBreaks, isBreakChar };
|
|
23
|
+
export { findGraphemeBreaks, findHyphenationBreaks, findWordBreaks, isBreakChar, isHangingPunctuation };
|
|
@@ -16,6 +16,7 @@ declare const DEFAULT_TAB_STOP_TWIPS = 720;
|
|
|
16
16
|
declare function resolveListMarkerFont(block: ParagraphBlock): {
|
|
17
17
|
fontFamily: string;
|
|
18
18
|
fontSize: number;
|
|
19
|
+
bold?: boolean;
|
|
19
20
|
};
|
|
20
21
|
/**
|
|
21
22
|
* Compute the marker's inline-block width in pixels, or 0 if the paragraph
|
|
@@ -36,5 +37,7 @@ declare function resolveListMarkerFont(block: ParagraphBlock): {
|
|
|
36
37
|
* grid is not erased by custom tabs, just augmented).
|
|
37
38
|
*/
|
|
38
39
|
declare function getListMarkerInlineWidth(block: ParagraphBlock): number;
|
|
40
|
+
/** Paint-only offset that places the marker around its authored list anchor. */
|
|
41
|
+
declare function getListMarkerVisualOffset(block: ParagraphBlock): number;
|
|
39
42
|
//#endregion
|
|
40
|
-
export { DEFAULT_TAB_STOP_TWIPS, getListMarkerInlineWidth, resolveListMarkerFont };
|
|
43
|
+
export { DEFAULT_TAB_STOP_TWIPS, getListMarkerInlineWidth, getListMarkerVisualOffset, resolveListMarkerFont };
|
|
@@ -19,9 +19,13 @@ const TWIPS_TO_PX = 96 / 1440;
|
|
|
19
19
|
function resolveListMarkerFont(block) {
|
|
20
20
|
const attrs = block.attrs;
|
|
21
21
|
const firstTextRun = block.runs.find((r) => r.kind === "text");
|
|
22
|
+
const fontFamily = attrs?.listMarkerFontFamily ?? firstTextRun?.fontFamily ?? attrs?.defaultFontFamily ?? DEFAULT_FONT_FAMILY;
|
|
23
|
+
const fontSize = attrs?.listMarkerFontSize ?? firstTextRun?.fontSize ?? attrs?.defaultFontSize ?? DEFAULT_FONT_SIZE;
|
|
24
|
+
const bold = attrs?.listMarkerBold ?? firstTextRun?.bold;
|
|
22
25
|
return {
|
|
23
|
-
fontFamily
|
|
24
|
-
fontSize
|
|
26
|
+
fontFamily,
|
|
27
|
+
fontSize,
|
|
28
|
+
...bold !== void 0 ? { bold } : {}
|
|
25
29
|
};
|
|
26
30
|
}
|
|
27
31
|
/**
|
|
@@ -45,21 +49,23 @@ function resolveListMarkerFont(block) {
|
|
|
45
49
|
function getListMarkerInlineWidth(block) {
|
|
46
50
|
const attrs = block.attrs;
|
|
47
51
|
if (!attrs?.listMarker || attrs.listMarkerHidden) return 0;
|
|
48
|
-
const { fontFamily, fontSize } = resolveListMarkerFont(block);
|
|
52
|
+
const { fontFamily, fontSize, bold } = resolveListMarkerFont(block);
|
|
49
53
|
const style = {
|
|
50
54
|
fontFamily,
|
|
51
|
-
fontSize
|
|
55
|
+
fontSize,
|
|
56
|
+
...bold !== void 0 ? { bold } : {}
|
|
52
57
|
};
|
|
53
58
|
const naturalWidth = measureTextWidth(attrs.listMarker, style);
|
|
59
|
+
const markerEndOffset = getMarkerEndOffset(naturalWidth, attrs.listMarkerAlignment);
|
|
54
60
|
const suffix = attrs.listMarkerSuffix ?? "tab";
|
|
55
|
-
if (suffix === "nothing") return
|
|
56
|
-
if (suffix === "space") return
|
|
61
|
+
if (suffix === "nothing") return markerEndOffset;
|
|
62
|
+
if (suffix === "space") return markerEndOffset + measureTextWidth(" ", style);
|
|
57
63
|
const indent = attrs.indent;
|
|
58
64
|
const indentLeft = indent?.left ?? 0;
|
|
59
65
|
const firstLine = indent?.firstLine ?? 0;
|
|
60
66
|
const hanging = indent?.hanging ?? 0;
|
|
61
67
|
const markerStartPx = hanging > 0 ? indentLeft - hanging : indentLeft + firstLine;
|
|
62
|
-
const minBodyStart = markerStartPx +
|
|
68
|
+
const minBodyStart = markerStartPx + markerEndOffset;
|
|
63
69
|
const customTabs = (attrs.tabs ?? []).filter((t) => t.val !== "clear" && t.val !== "bar").map((t) => t.pos * TWIPS_TO_PX);
|
|
64
70
|
if (hanging > 0) customTabs.push(indentLeft);
|
|
65
71
|
const searchStart = hanging > 0 ? Math.max(minBodyStart, indentLeft) : minBodyStart;
|
|
@@ -72,5 +78,24 @@ function getListMarkerInlineWidth(block) {
|
|
|
72
78
|
if (bodyStart === void 0) return naturalWidth + ptToPx(fontSize) * .5;
|
|
73
79
|
return bodyStart - markerStartPx;
|
|
74
80
|
}
|
|
81
|
+
/** Paint-only offset that places the marker around its authored list anchor. */
|
|
82
|
+
function getListMarkerVisualOffset(block) {
|
|
83
|
+
const attrs = block.attrs;
|
|
84
|
+
if (!attrs?.listMarker || attrs.listMarkerHidden) return 0;
|
|
85
|
+
const { fontFamily, fontSize, bold } = resolveListMarkerFont(block);
|
|
86
|
+
const naturalWidth = measureTextWidth(attrs.listMarker, {
|
|
87
|
+
fontFamily,
|
|
88
|
+
fontSize,
|
|
89
|
+
...bold !== void 0 ? { bold } : {}
|
|
90
|
+
});
|
|
91
|
+
if (attrs.listMarkerAlignment === "right") return -naturalWidth;
|
|
92
|
+
if (attrs.listMarkerAlignment === "center") return -naturalWidth / 2;
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
const getMarkerEndOffset = (naturalWidth, alignment) => {
|
|
96
|
+
if (alignment === "right") return 0;
|
|
97
|
+
if (alignment === "center") return naturalWidth / 2;
|
|
98
|
+
return naturalWidth;
|
|
99
|
+
};
|
|
75
100
|
//#endregion
|
|
76
|
-
export { DEFAULT_TAB_STOP_TWIPS, getListMarkerInlineWidth, resolveListMarkerFont };
|
|
101
|
+
export { DEFAULT_TAB_STOP_TWIPS, getListMarkerInlineWidth, getListMarkerVisualOffset, resolveListMarkerFont };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { FlowBlock, Measure, TableBlock, TableMeasure, TextBoxBlock, TextBoxMeasure } from "../types.js";
|
|
2
2
|
import { FloatingImageZone } from "./floatingZones.js";
|
|
3
3
|
//#region src/layout-engine/measure/measureBlocks.d.ts
|
|
4
|
-
declare function measureTableCellBlockVisualHeight(block: FlowBlock, blockMeasure: Measure): number;
|
|
5
4
|
declare function measureTableBlock(tableBlock: TableBlock, contentWidth: number, fieldValues?: ReadonlyMap<number, string>): TableMeasure;
|
|
6
5
|
type BandPageGeometry = {
|
|
6
|
+
pageWidth?: number | number[];
|
|
7
7
|
pageHeight: number | number[];
|
|
8
|
+
marginLeft?: number | number[];
|
|
9
|
+
marginRight?: number | number[];
|
|
8
10
|
marginBottom: number | number[];
|
|
9
11
|
};
|
|
10
12
|
/**
|
|
@@ -22,4 +24,4 @@ declare function measureTextBoxBlock(tb: TextBoxBlock, fieldValues?: ReadonlyMap
|
|
|
22
24
|
declare function measureBlocks(blocks: FlowBlock[], contentWidth: number | number[], marginTop?: number | number[], pageGeometry?: BandPageGeometry, fieldValues?: ReadonlyMap<number, string>): Measure[];
|
|
23
25
|
declare function measureSingleBlockWithoutFloatingZones(block: FlowBlock, blockWidth: number, blockIndex: number): Measure;
|
|
24
26
|
//#endregion
|
|
25
|
-
export { measureBlock, measureBlocks, measureSingleBlockWithoutFloatingZones, measureTableBlock,
|
|
27
|
+
export { measureBlock, measureBlocks, measureSingleBlockWithoutFloatingZones, measureTableBlock, measureTextBoxBlock };
|