@itwin/core-backend 5.2.0-dev.8 → 5.3.0-dev.1
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/CHANGELOG.md +31 -1
- package/lib/cjs/BackendHubAccess.d.ts +2 -0
- package/lib/cjs/BackendHubAccess.d.ts.map +1 -1
- package/lib/cjs/BackendHubAccess.js.map +1 -1
- package/lib/cjs/BackendLoggerCategory.d.ts +6 -0
- package/lib/cjs/BackendLoggerCategory.d.ts.map +1 -1
- package/lib/cjs/BackendLoggerCategory.js +6 -0
- package/lib/cjs/BackendLoggerCategory.js.map +1 -1
- package/lib/cjs/BriefcaseManager.d.ts +57 -3
- package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
- package/lib/cjs/BriefcaseManager.js +151 -42
- package/lib/cjs/BriefcaseManager.js.map +1 -1
- package/lib/cjs/CloudSqlite.d.ts +4 -0
- package/lib/cjs/CloudSqlite.d.ts.map +1 -1
- package/lib/cjs/CloudSqlite.js.map +1 -1
- package/lib/cjs/ECDb.d.ts +8 -0
- package/lib/cjs/ECDb.d.ts.map +1 -1
- package/lib/cjs/ECDb.js +22 -0
- package/lib/cjs/ECDb.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +54 -3
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +87 -9
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/IModelHost.d.ts +11 -1
- package/lib/cjs/IModelHost.d.ts.map +1 -1
- package/lib/cjs/IModelHost.js +5 -0
- package/lib/cjs/IModelHost.js.map +1 -1
- package/lib/cjs/IModelIncrementalSchemaLocater.d.ts +1 -5
- package/lib/cjs/IModelIncrementalSchemaLocater.d.ts.map +1 -1
- package/lib/cjs/IModelIncrementalSchemaLocater.js +0 -6
- package/lib/cjs/IModelIncrementalSchemaLocater.js.map +1 -1
- package/lib/cjs/SqliteChangesetReader.d.ts +8 -0
- package/lib/cjs/SqliteChangesetReader.d.ts.map +1 -1
- package/lib/cjs/SqliteChangesetReader.js +11 -0
- package/lib/cjs/SqliteChangesetReader.js.map +1 -1
- package/lib/cjs/StashManager.d.ts +175 -0
- package/lib/cjs/StashManager.d.ts.map +1 -0
- package/lib/cjs/StashManager.js +306 -0
- package/lib/cjs/StashManager.js.map +1 -0
- package/lib/cjs/TxnManager.d.ts +226 -15
- package/lib/cjs/TxnManager.d.ts.map +1 -1
- package/lib/cjs/TxnManager.js +249 -23
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.js +15 -6
- package/lib/cjs/annotations/ElementDrivesTextAnnotation.js.map +1 -1
- package/lib/cjs/annotations/LeaderGeometry.d.ts +3 -2
- package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/LeaderGeometry.js +5 -4
- package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.d.ts +52 -24
- package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
- package/lib/cjs/annotations/TextAnnotationElement.js +49 -59
- package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
- package/lib/cjs/annotations/TextAnnotationGeometry.d.ts +2 -0
- package/lib/cjs/annotations/TextAnnotationGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/TextAnnotationGeometry.js +26 -19
- package/lib/cjs/annotations/TextAnnotationGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextBlockGeometry.d.ts.map +1 -1
- package/lib/cjs/annotations/TextBlockGeometry.js +8 -0
- package/lib/cjs/annotations/TextBlockGeometry.js.map +1 -1
- package/lib/cjs/annotations/TextBlockLayout.d.ts +49 -36
- package/lib/cjs/annotations/TextBlockLayout.d.ts.map +1 -1
- package/lib/cjs/annotations/TextBlockLayout.js +204 -135
- package/lib/cjs/annotations/TextBlockLayout.js.map +1 -1
- package/lib/cjs/internal/ChannelAdmin.js +1 -1
- package/lib/cjs/internal/ChannelAdmin.js.map +1 -1
- package/lib/cjs/internal/Symbols.d.ts +1 -0
- package/lib/cjs/internal/Symbols.d.ts.map +1 -1
- package/lib/cjs/internal/Symbols.js +2 -1
- package/lib/cjs/internal/Symbols.js.map +1 -1
- package/lib/cjs/internal/annotations/fields.d.ts +2 -12
- package/lib/cjs/internal/annotations/fields.d.ts.map +1 -1
- package/lib/cjs/internal/annotations/fields.js +49 -45
- package/lib/cjs/internal/annotations/fields.js.map +1 -1
- package/lib/cjs/workspace/Workspace.d.ts +1 -1
- package/lib/cjs/workspace/Workspace.js.map +1 -1
- package/lib/esm/BackendHubAccess.d.ts +2 -0
- package/lib/esm/BackendHubAccess.d.ts.map +1 -1
- package/lib/esm/BackendHubAccess.js.map +1 -1
- package/lib/esm/BackendLoggerCategory.d.ts +6 -0
- package/lib/esm/BackendLoggerCategory.d.ts.map +1 -1
- package/lib/esm/BackendLoggerCategory.js +6 -0
- package/lib/esm/BackendLoggerCategory.js.map +1 -1
- package/lib/esm/BriefcaseManager.d.ts +57 -3
- package/lib/esm/BriefcaseManager.d.ts.map +1 -1
- package/lib/esm/BriefcaseManager.js +152 -43
- package/lib/esm/BriefcaseManager.js.map +1 -1
- package/lib/esm/CloudSqlite.d.ts +4 -0
- package/lib/esm/CloudSqlite.d.ts.map +1 -1
- package/lib/esm/CloudSqlite.js.map +1 -1
- package/lib/esm/ECDb.d.ts +8 -0
- package/lib/esm/ECDb.d.ts.map +1 -1
- package/lib/esm/ECDb.js +22 -0
- package/lib/esm/ECDb.js.map +1 -1
- package/lib/esm/IModelDb.d.ts +54 -3
- package/lib/esm/IModelDb.d.ts.map +1 -1
- package/lib/esm/IModelDb.js +88 -10
- package/lib/esm/IModelDb.js.map +1 -1
- package/lib/esm/IModelHost.d.ts +11 -1
- package/lib/esm/IModelHost.d.ts.map +1 -1
- package/lib/esm/IModelHost.js +5 -0
- package/lib/esm/IModelHost.js.map +1 -1
- package/lib/esm/IModelIncrementalSchemaLocater.d.ts +1 -5
- package/lib/esm/IModelIncrementalSchemaLocater.d.ts.map +1 -1
- package/lib/esm/IModelIncrementalSchemaLocater.js +0 -6
- package/lib/esm/IModelIncrementalSchemaLocater.js.map +1 -1
- package/lib/esm/SqliteChangesetReader.d.ts +8 -0
- package/lib/esm/SqliteChangesetReader.d.ts.map +1 -1
- package/lib/esm/SqliteChangesetReader.js +11 -0
- package/lib/esm/SqliteChangesetReader.js.map +1 -1
- package/lib/esm/StashManager.d.ts +175 -0
- package/lib/esm/StashManager.d.ts.map +1 -0
- package/lib/esm/StashManager.js +301 -0
- package/lib/esm/StashManager.js.map +1 -0
- package/lib/esm/TxnManager.d.ts +226 -15
- package/lib/esm/TxnManager.d.ts.map +1 -1
- package/lib/esm/TxnManager.js +247 -21
- package/lib/esm/TxnManager.js.map +1 -1
- package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
- package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
- package/lib/esm/annotations/ElementDrivesTextAnnotation.js +13 -5
- package/lib/esm/annotations/ElementDrivesTextAnnotation.js.map +1 -1
- package/lib/esm/annotations/LeaderGeometry.d.ts +3 -2
- package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/LeaderGeometry.js +5 -4
- package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
- package/lib/esm/annotations/TextAnnotationElement.d.ts +52 -24
- package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
- package/lib/esm/annotations/TextAnnotationElement.js +51 -61
- package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
- package/lib/esm/annotations/TextAnnotationGeometry.d.ts +2 -0
- package/lib/esm/annotations/TextAnnotationGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/TextAnnotationGeometry.js +26 -19
- package/lib/esm/annotations/TextAnnotationGeometry.js.map +1 -1
- package/lib/esm/annotations/TextBlockGeometry.d.ts.map +1 -1
- package/lib/esm/annotations/TextBlockGeometry.js +8 -0
- package/lib/esm/annotations/TextBlockGeometry.js.map +1 -1
- package/lib/esm/annotations/TextBlockLayout.d.ts +49 -36
- package/lib/esm/annotations/TextBlockLayout.d.ts.map +1 -1
- package/lib/esm/annotations/TextBlockLayout.js +205 -136
- package/lib/esm/annotations/TextBlockLayout.js.map +1 -1
- package/lib/esm/internal/ChannelAdmin.js +1 -1
- package/lib/esm/internal/ChannelAdmin.js.map +1 -1
- package/lib/esm/internal/Symbols.d.ts +1 -0
- package/lib/esm/internal/Symbols.d.ts.map +1 -1
- package/lib/esm/internal/Symbols.js +1 -0
- package/lib/esm/internal/Symbols.js.map +1 -1
- package/lib/esm/internal/annotations/fields.d.ts +2 -12
- package/lib/esm/internal/annotations/fields.d.ts.map +1 -1
- package/lib/esm/internal/annotations/fields.js +51 -47
- package/lib/esm/internal/annotations/fields.js.map +1 -1
- package/lib/esm/test/AnnotationTestUtils.d.ts +5 -1
- package/lib/esm/test/AnnotationTestUtils.d.ts.map +1 -1
- package/lib/esm/test/AnnotationTestUtils.js +6 -1
- package/lib/esm/test/AnnotationTestUtils.js.map +1 -1
- package/lib/esm/test/annotations/Fields.test.js +163 -46
- package/lib/esm/test/annotations/Fields.test.js.map +1 -1
- package/lib/esm/test/annotations/LeaderGeometry.test.js +12 -10
- package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
- package/lib/esm/test/annotations/TextAnnotation.test.js +299 -43
- package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
- package/lib/esm/test/annotations/TextBlock.test.js +453 -86
- package/lib/esm/test/annotations/TextBlock.test.js.map +1 -1
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts +46 -0
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts.map +1 -1
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js +20 -2
- package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js.map +1 -1
- package/lib/esm/test/ecdb/ECDb.test.js +71 -1
- package/lib/esm/test/ecdb/ECDb.test.js.map +1 -1
- package/lib/esm/test/hubaccess/Rebase.test.d.ts +2 -0
- package/lib/esm/test/hubaccess/Rebase.test.d.ts.map +1 -0
- package/lib/esm/test/hubaccess/Rebase.test.js +640 -0
- package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -0
- package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js +20 -20
- package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js +3 -3
- package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts +16 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts.map +1 -1
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js +47 -0
- package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js.map +1 -1
- package/lib/esm/test/standalone/ChangeMerge.test.js +15 -19
- package/lib/esm/test/standalone/ChangeMerge.test.js.map +1 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js +131 -1
- package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
- package/lib/esm/test/standalone/MergeConflict.test.js +3 -3
- package/lib/esm/test/standalone/MergeConflict.test.js.map +1 -1
- package/lib/esm/workspace/Workspace.d.ts +1 -1
- package/lib/esm/workspace/Workspace.js.map +1 -1
- package/package.json +13 -13
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
/** @packageDocumentation
|
|
6
6
|
* @module ElementGeometry
|
|
7
7
|
*/
|
|
8
|
-
import { TextStyleSettings } from "@itwin/core-common";
|
|
8
|
+
import { getMarkerText, TextRun, TextStyleSettings } from "@itwin/core-common";
|
|
9
9
|
import { Geometry, Range2d } from "@itwin/core-geometry";
|
|
10
10
|
import { assert } from "@itwin/core-bentley";
|
|
11
11
|
import * as LineBreaker from "linebreak";
|
|
12
12
|
import { AnnotationTextStyle } from "./TextAnnotationElement";
|
|
13
|
-
import { Drawing } from "../Element";
|
|
14
13
|
/** @internal */
|
|
15
14
|
function createFindTextStyleImpl(iModel) {
|
|
16
15
|
return function findTextStyleImpl(id) {
|
|
@@ -54,11 +53,10 @@ export function computeLayoutTextBlockResult(args) {
|
|
|
54
53
|
* @beta
|
|
55
54
|
*/
|
|
56
55
|
export function computeGraphemeOffsets(args) {
|
|
57
|
-
const {
|
|
56
|
+
const { source, runLayoutResult, graphemeCharIndexes, iModel } = args;
|
|
58
57
|
const findFontId = args.findFontId ?? ((name, type) => iModel.fonts.findId({ name, type }) ?? 0);
|
|
59
58
|
const computeTextRange = args.computeTextRange ?? ((x) => iModel.computeRangesForText(x));
|
|
60
|
-
|
|
61
|
-
if (source.type !== "text" || runLayoutResult.characterCount === 0) {
|
|
59
|
+
if (!(source instanceof TextRun) || runLayoutResult.characterCount === 0) {
|
|
62
60
|
return [];
|
|
63
61
|
}
|
|
64
62
|
const style = TextStyleSettings.fromJSON(runLayoutResult.textStyle);
|
|
@@ -110,59 +108,39 @@ function applyBlockSettings(target, source, isLeader = false) {
|
|
|
110
108
|
return target;
|
|
111
109
|
}
|
|
112
110
|
/**
|
|
113
|
-
* Resolves the effective style of TextBlockComponents and Leaders, taking into account overrides
|
|
111
|
+
* Resolves the effective style of TextBlockComponents and Leaders, taking into account overrides of the instance and its parent(s).
|
|
114
112
|
* @beta
|
|
115
113
|
*/
|
|
116
114
|
export class TextStyleResolver {
|
|
117
|
-
_textStyles = new Map();
|
|
118
|
-
_findTextStyle;
|
|
119
115
|
/** The resolved style of the TextBlock. */
|
|
120
116
|
blockSettings;
|
|
121
|
-
/** The scale factor of the model containing the TextBlock. */
|
|
122
|
-
scaleFactor;
|
|
123
117
|
constructor(args) {
|
|
124
|
-
|
|
125
|
-
this.
|
|
126
|
-
if (args.modelId) {
|
|
127
|
-
const element = args.iModel.elements.getElement(args.modelId);
|
|
128
|
-
if (element instanceof Drawing)
|
|
129
|
-
this.scaleFactor = element.scaleFactor;
|
|
130
|
-
}
|
|
131
|
-
this.blockSettings = this.findTextStyle(args.textBlock.styleId);
|
|
118
|
+
const findTextStyle = args.findTextStyle ?? createFindTextStyleImpl(args.iModel);
|
|
119
|
+
this.blockSettings = findTextStyle(args.textStyleId);
|
|
132
120
|
if (args.textBlock.styleOverrides)
|
|
133
121
|
this.blockSettings = this.blockSettings.clone(args.textBlock.styleOverrides);
|
|
134
122
|
}
|
|
135
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Resolves the effective text style settings for a given TextBlockComponent, applying block-level overrides.
|
|
125
|
+
*/
|
|
126
|
+
resolveSettings(overrides, isLeader = false) {
|
|
136
127
|
let settings = this.blockSettings;
|
|
137
|
-
if (
|
|
138
|
-
settings = settings.clone(
|
|
139
|
-
return settings;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
settings = settings.clone(leader.styleOverrides);
|
|
154
|
-
return applyBlockSettings(settings, this.blockSettings, true);
|
|
155
|
-
}
|
|
156
|
-
/** Resolves the effective style for a [Paragraph]($common). Paragraph should be child of provided TextBlock. */
|
|
157
|
-
resolveParagraphSettings(paragraph) {
|
|
158
|
-
return applyBlockSettings(this.resolveParagraphSettingsImpl(paragraph), this.blockSettings);
|
|
159
|
-
}
|
|
160
|
-
/** Resolves the effective style for a [Run]($common). Run should be child of provided Paragraph and TextBlock. */
|
|
161
|
-
resolveRunSettings(paragraph, run) {
|
|
162
|
-
let settings = this.resolveParagraphSettingsImpl(paragraph);
|
|
163
|
-
if (run.overridesStyle)
|
|
164
|
-
settings = settings.clone(run.styleOverrides);
|
|
165
|
-
return applyBlockSettings(settings, this.blockSettings);
|
|
128
|
+
if (overrides)
|
|
129
|
+
settings = settings.clone(overrides);
|
|
130
|
+
return applyBlockSettings(settings, this.blockSettings, isLeader);
|
|
131
|
+
}
|
|
132
|
+
resolveMarkerText(overrides, index) {
|
|
133
|
+
const markerSettings = overrides.listMarker ?? this.blockSettings.listMarker;
|
|
134
|
+
return getMarkerText(markerSettings, index);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Computes the indentation based on its style and nesting depth.
|
|
138
|
+
*/
|
|
139
|
+
resolveIndentation(styleOverrides, depth) {
|
|
140
|
+
const overrides = this.resolveSettings(styleOverrides);
|
|
141
|
+
const indentation = overrides.indentation;
|
|
142
|
+
const tabInterval = overrides.tabInterval;
|
|
143
|
+
return indentation + tabInterval * depth;
|
|
166
144
|
}
|
|
167
145
|
}
|
|
168
146
|
class LayoutContext {
|
|
@@ -252,9 +230,9 @@ class LayoutContext {
|
|
|
252
230
|
layout.extendRange(denominator);
|
|
253
231
|
return { layout, numerator, denominator };
|
|
254
232
|
}
|
|
255
|
-
computeRangeForTabRun(style, source,
|
|
233
|
+
computeRangeForTabRun(style, source, lengthFromLastTab) {
|
|
256
234
|
const interval = source.styleOverrides.tabInterval ?? style.tabInterval;
|
|
257
|
-
const tabEndX = interval -
|
|
235
|
+
const tabEndX = interval - lengthFromLastTab % interval;
|
|
258
236
|
const range = new Range2d(0, 0, 0, style.lineHeight);
|
|
259
237
|
range.extendXY(tabEndX, range.low.y);
|
|
260
238
|
return range;
|
|
@@ -310,8 +288,8 @@ export class RunLayout {
|
|
|
310
288
|
this.style = props.style;
|
|
311
289
|
this.fontId = props.fontId;
|
|
312
290
|
}
|
|
313
|
-
static create(source,
|
|
314
|
-
const style = context.textStyleResolver.
|
|
291
|
+
static create(source, context, cumulativeOverrides) {
|
|
292
|
+
const style = context.textStyleResolver.resolveSettings(cumulativeOverrides);
|
|
315
293
|
const fontId = context.findFontId(style.fontName);
|
|
316
294
|
const charOffset = 0;
|
|
317
295
|
const offsetFromLine = { x: 0, y: 0 };
|
|
@@ -380,9 +358,8 @@ export class RunLayout {
|
|
|
380
358
|
});
|
|
381
359
|
});
|
|
382
360
|
}
|
|
383
|
-
toResult(
|
|
361
|
+
toResult() {
|
|
384
362
|
const result = {
|
|
385
|
-
sourceRunIndex: paragraph.runs.indexOf(this.source),
|
|
386
363
|
fontId: this.fontId,
|
|
387
364
|
characterOffset: this.charOffset,
|
|
388
365
|
characterCount: this.numChars,
|
|
@@ -411,32 +388,47 @@ export class RunLayout {
|
|
|
411
388
|
export class LineLayout {
|
|
412
389
|
source;
|
|
413
390
|
range = new Range2d(0, 0, 0, 0);
|
|
391
|
+
runRange = new Range2d(0, 0, 0, 0); // Range of all runs excluding marker.
|
|
414
392
|
justificationRange = new Range2d(0, 0, 0, 0);
|
|
415
|
-
offsetFromDocument
|
|
393
|
+
offsetFromDocument;
|
|
394
|
+
depth;
|
|
416
395
|
lengthFromLastTab = 0; // Used to track the length from the last tab for tab runs.
|
|
417
396
|
_runs = [];
|
|
418
|
-
|
|
397
|
+
_marker;
|
|
398
|
+
constructor(source, style, context, depth = 0) {
|
|
419
399
|
this.source = source;
|
|
400
|
+
this.depth = depth;
|
|
401
|
+
this.offsetFromDocument = { x: context?.textStyleResolver.resolveIndentation(style, depth) ?? 0, y: 0 };
|
|
420
402
|
}
|
|
421
403
|
/** Compute a string representation, primarily for debugging purposes. */
|
|
422
404
|
stringify() {
|
|
423
405
|
const runs = this._runs.map((run) => run.stringify());
|
|
424
406
|
return `${runs.join("")}`;
|
|
425
407
|
}
|
|
408
|
+
/** Gets the array of RunLayout objects contained in this line. */
|
|
426
409
|
get runs() { return this._runs; }
|
|
410
|
+
/** Indicates whether this line contains any runs. */
|
|
427
411
|
get isEmpty() { return this._runs.length === 0; }
|
|
412
|
+
/** Gets the last RunLayout in this line. */
|
|
428
413
|
get back() {
|
|
429
414
|
assert(!this.isEmpty);
|
|
430
415
|
return this._runs[this._runs.length - 1];
|
|
431
416
|
}
|
|
417
|
+
/**
|
|
418
|
+
* Gets or sets the marker RunLayout for this line, used for lists.
|
|
419
|
+
* A marker is the symbol or character that appears before each list item in a list, bullets, numbers, etc.
|
|
420
|
+
* */
|
|
421
|
+
get marker() { return this._marker; }
|
|
422
|
+
set marker(value) { this._marker = value; }
|
|
432
423
|
append(run) {
|
|
433
424
|
this._runs.push(run);
|
|
434
425
|
this.computeRanges();
|
|
435
426
|
}
|
|
436
427
|
/** Invoked every time a run is appended,. */
|
|
437
428
|
computeRanges() {
|
|
438
|
-
this.
|
|
439
|
-
this.
|
|
429
|
+
this.runRange.low.setZero();
|
|
430
|
+
this.runRange.high.setZero();
|
|
431
|
+
this.lengthFromLastTab = 0;
|
|
440
432
|
// Some runs (fractions) are taller than others.
|
|
441
433
|
// We want to center each run vertically inside the line.
|
|
442
434
|
let lineHeight = 0;
|
|
@@ -445,26 +437,39 @@ export class LineLayout {
|
|
|
445
437
|
}
|
|
446
438
|
for (const run of this._runs) {
|
|
447
439
|
const runHeight = run.range.yLength();
|
|
448
|
-
const runOffset = { x: this.
|
|
440
|
+
const runOffset = { x: this.runRange.high.x, y: (lineHeight - runHeight) / 2 };
|
|
449
441
|
run.offsetFromLine = runOffset;
|
|
450
442
|
const runLayoutRange = run.range.cloneTranslated(runOffset);
|
|
451
|
-
this.
|
|
443
|
+
this.runRange.extendRange(runLayoutRange);
|
|
452
444
|
if ("linebreak" !== run.source.type) {
|
|
453
445
|
const runJustificationRange = run.justificationRange?.cloneTranslated(runOffset);
|
|
454
446
|
this.justificationRange.extendRange(runJustificationRange ?? runLayoutRange);
|
|
455
447
|
}
|
|
456
|
-
if (run.source.type
|
|
448
|
+
if ("tab" === run.source.type) {
|
|
457
449
|
this.lengthFromLastTab = 0;
|
|
458
450
|
}
|
|
459
451
|
else {
|
|
460
452
|
this.lengthFromLastTab += run.range.xLength();
|
|
461
453
|
}
|
|
462
454
|
}
|
|
455
|
+
this.range.setFrom(this.runRange);
|
|
456
|
+
if (this._marker) {
|
|
457
|
+
const indentation = this.range.low.x;
|
|
458
|
+
const x = indentation - (this._marker.style.tabInterval / 2) - this._marker.range.xLength();
|
|
459
|
+
const runHeight = this._marker.range.yLength();
|
|
460
|
+
const runOffset = {
|
|
461
|
+
x,
|
|
462
|
+
y: (lineHeight - runHeight) / 2 // Center the marker vertically in the line.
|
|
463
|
+
};
|
|
464
|
+
this._marker.offsetFromLine = runOffset;
|
|
465
|
+
const markerRange = this._marker.range.cloneTranslated(this._marker.offsetFromLine);
|
|
466
|
+
this.range.extendRange(markerRange);
|
|
467
|
+
}
|
|
463
468
|
}
|
|
464
|
-
toResult(
|
|
469
|
+
toResult() {
|
|
465
470
|
return {
|
|
466
|
-
|
|
467
|
-
|
|
471
|
+
runs: this.runs.map((x) => x.toResult()),
|
|
472
|
+
marker: this.marker?.toResult(),
|
|
468
473
|
range: this.range.toJSON(),
|
|
469
474
|
justificationRange: this.justificationRange.toJSON(),
|
|
470
475
|
offsetFromDocument: this.offsetFromDocument,
|
|
@@ -498,7 +503,7 @@ export class TextBlockLayout {
|
|
|
498
503
|
}
|
|
499
504
|
toResult() {
|
|
500
505
|
return {
|
|
501
|
-
lines: this.lines.map((x) => x.toResult(
|
|
506
|
+
lines: this.lines.map((x) => x.toResult()),
|
|
502
507
|
range: this.range.toJSON(),
|
|
503
508
|
};
|
|
504
509
|
}
|
|
@@ -512,59 +517,151 @@ export class TextBlockLayout {
|
|
|
512
517
|
}
|
|
513
518
|
populateLines(context) {
|
|
514
519
|
const doc = this.source;
|
|
515
|
-
if (doc.
|
|
520
|
+
if (!doc.children || doc.children.length === 0) {
|
|
516
521
|
return;
|
|
517
522
|
}
|
|
518
|
-
|
|
519
|
-
let
|
|
520
|
-
for (
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
523
|
+
let curLine = new LineLayout(doc.children[0], doc.children[0].styleOverrides, context);
|
|
524
|
+
let childIndex = 0;
|
|
525
|
+
for (const child of doc.children) {
|
|
526
|
+
curLine = this.populateComponent(child, childIndex++, context, doc.width, curLine, doc, doc.styleOverrides);
|
|
527
|
+
}
|
|
528
|
+
if (curLine.runs.length > 0) {
|
|
529
|
+
this.flushLine(context, curLine, doc.styleOverrides);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
populateComponent(component, componentIndex, context, docWidth, curLine, parent, cumulativeOverrides, depth = 0) {
|
|
533
|
+
cumulativeOverrides = { ...cumulativeOverrides, ...component.styleOverrides };
|
|
534
|
+
switch (component.type) {
|
|
535
|
+
case "list": {
|
|
536
|
+
// If we have any runs in the current line, flush it before starting the list.
|
|
537
|
+
if (curLine.runs.length > 0) {
|
|
538
|
+
curLine = this.flushLine(context, curLine, cumulativeOverrides, component.children[0], true, depth + 1);
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
// If not, we need to apply the indentation for the list to the first line.
|
|
542
|
+
curLine.offsetFromDocument.x = context.textStyleResolver.resolveIndentation(cumulativeOverrides, depth + 1);
|
|
543
|
+
curLine.depth = depth + 1;
|
|
534
544
|
}
|
|
535
|
-
//
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
curLine.
|
|
540
|
-
|
|
545
|
+
// Iterate through each list item, setting the marker and populating its contents.
|
|
546
|
+
component.children.forEach((child, index) => {
|
|
547
|
+
const markerContent = context.textStyleResolver.resolveMarkerText(cumulativeOverrides, index + 1);
|
|
548
|
+
const markerRun = TextRun.create({ content: markerContent });
|
|
549
|
+
curLine.marker = RunLayout.create(markerRun, context, cumulativeOverrides);
|
|
550
|
+
curLine = this.populateComponent(child, index, context, docWidth, curLine, component, cumulativeOverrides, depth + 1);
|
|
551
|
+
});
|
|
552
|
+
// Lastly flush the line.
|
|
553
|
+
const nextSibling = parent?.children[componentIndex + 1];
|
|
554
|
+
if (curLine && nextSibling) {
|
|
555
|
+
curLine = this.flushLine(context, curLine, cumulativeOverrides, nextSibling, true, depth);
|
|
541
556
|
}
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
curLine.
|
|
548
|
-
|
|
557
|
+
break;
|
|
558
|
+
}
|
|
559
|
+
case "paragraph": {
|
|
560
|
+
// Iterate through each paragraph child (either a list or a run), populating its contents.
|
|
561
|
+
component.children.forEach((child, index) => {
|
|
562
|
+
curLine = this.populateComponent(child, index, context, docWidth, curLine, component, cumulativeOverrides, depth);
|
|
563
|
+
});
|
|
564
|
+
// Lastly flush the line.
|
|
565
|
+
const nextSibling = parent?.children[componentIndex + 1];
|
|
566
|
+
if (curLine && nextSibling) {
|
|
567
|
+
curLine = this.flushLine(context, curLine, cumulativeOverrides, nextSibling, true, depth);
|
|
549
568
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
571
|
+
case "text": {
|
|
572
|
+
const layout = RunLayout.create(component, context, cumulativeOverrides);
|
|
573
|
+
// Text can be word-wrapped, so we need to split it into multiple runs if necessary.
|
|
574
|
+
if (docWidth > 0) {
|
|
575
|
+
layout.split(context).forEach(r => { curLine = this.populateRun(curLine, r, context, cumulativeOverrides, docWidth); });
|
|
555
576
|
}
|
|
556
577
|
else {
|
|
557
|
-
|
|
558
|
-
curLine = this.flushLine(context, curLine);
|
|
559
|
-
// Recompute tab shift if applicable
|
|
560
|
-
applyTabShift(run, curLine, context);
|
|
561
|
-
curLine.append(run);
|
|
578
|
+
curLine = this.populateRun(curLine, layout, context, cumulativeOverrides, docWidth);
|
|
562
579
|
}
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
case "fraction":
|
|
583
|
+
case "tab": {
|
|
584
|
+
const layout = RunLayout.create(component, context, cumulativeOverrides);
|
|
585
|
+
curLine = this.populateRun(curLine, layout, context, cumulativeOverrides, docWidth);
|
|
586
|
+
break;
|
|
563
587
|
}
|
|
588
|
+
case "linebreak": {
|
|
589
|
+
const layout = RunLayout.create(component, context, cumulativeOverrides);
|
|
590
|
+
curLine.append(layout);
|
|
591
|
+
curLine = this.flushLine(context, curLine, cumulativeOverrides, undefined, undefined, depth);
|
|
592
|
+
break;
|
|
593
|
+
}
|
|
594
|
+
default: break;
|
|
564
595
|
}
|
|
565
|
-
|
|
566
|
-
|
|
596
|
+
return curLine;
|
|
597
|
+
}
|
|
598
|
+
;
|
|
599
|
+
populateRun(curLine, run, context, cumulativeOverrides, docWidth) {
|
|
600
|
+
// If this is a tab, we need to apply the tab shift first, and then we can treat it like a text run.
|
|
601
|
+
applyTabShift(run, curLine, context);
|
|
602
|
+
// If our width is not set, then we don't have to compute word wrapping, so just append the run, and continue.
|
|
603
|
+
if (docWidth <= 0) {
|
|
604
|
+
curLine.append(run);
|
|
605
|
+
return curLine;
|
|
606
|
+
}
|
|
607
|
+
// If not, we need to determine if we can append this run to the current line without exceeding the document width or if we need to word wrap.
|
|
608
|
+
const runWidth = run.justificationRange?.xLength() ?? run.range.xLength();
|
|
609
|
+
const lineWidth = curLine.runRange.xLength();
|
|
610
|
+
const newWidth = runWidth + lineWidth + curLine.offsetFromDocument.x;
|
|
611
|
+
// If true, then no word wrapping is required, so we can append to the current line.
|
|
612
|
+
if (newWidth < docWidth || Geometry.isAlmostEqualNumber(newWidth, docWidth, Geometry.smallMetricDistance)) {
|
|
613
|
+
curLine.append(run);
|
|
614
|
+
return curLine;
|
|
567
615
|
}
|
|
616
|
+
// If not, do word wrapping
|
|
617
|
+
if (curLine.runs.length === 0) {
|
|
618
|
+
curLine.append(run);
|
|
619
|
+
// Lastly, flush line
|
|
620
|
+
curLine = this.flushLine(context, curLine, cumulativeOverrides, undefined, undefined, curLine.depth);
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
// First, flush line
|
|
624
|
+
curLine = this.flushLine(context, curLine, cumulativeOverrides, undefined, undefined, curLine.depth);
|
|
625
|
+
// Recompute tab shift if applicable
|
|
626
|
+
applyTabShift(run, curLine, context);
|
|
627
|
+
curLine.append(run);
|
|
628
|
+
}
|
|
629
|
+
return curLine;
|
|
630
|
+
}
|
|
631
|
+
;
|
|
632
|
+
flushLine(context, curLine, cumulativeOverrides, next, newParagraph = false, depth = 0) {
|
|
633
|
+
next = next ?? curLine.source;
|
|
634
|
+
// We want to guarantee that each layout line has at least one run.
|
|
635
|
+
if (curLine.runs.length === 0) {
|
|
636
|
+
if (this.lines.length === 0 || this._back.runs.length === 0) {
|
|
637
|
+
return new LineLayout(next, cumulativeOverrides, context, depth);
|
|
638
|
+
}
|
|
639
|
+
if (curLine.source.type !== "linebreak") {
|
|
640
|
+
const newLine = new LineLayout(next, cumulativeOverrides, context, depth);
|
|
641
|
+
newLine.offsetFromDocument.y -= context.textStyleResolver.blockSettings.paragraphSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
|
|
642
|
+
return newLine;
|
|
643
|
+
}
|
|
644
|
+
const run = curLine.source.clone();
|
|
645
|
+
curLine.append(RunLayout.create(run, context, cumulativeOverrides));
|
|
646
|
+
}
|
|
647
|
+
// Line origin is its baseline.
|
|
648
|
+
const lineOffset = { ...curLine.offsetFromDocument }; // Start with the line's original offset, which includes indentation.
|
|
649
|
+
lineOffset.y -= curLine.range.yLength(); // Shift down the baseline
|
|
650
|
+
// Place it below any existing lines
|
|
651
|
+
if (this.lines.length > 0) {
|
|
652
|
+
lineOffset.y += this._back.offsetFromDocument.y;
|
|
653
|
+
lineOffset.y -= context.textStyleResolver.blockSettings.lineSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
|
|
654
|
+
}
|
|
655
|
+
curLine.offsetFromDocument = lineOffset;
|
|
656
|
+
// Update document range from computed line range and position
|
|
657
|
+
this.textRange.extendRange(curLine.range.cloneTranslated(lineOffset));
|
|
658
|
+
this.lines.push(curLine);
|
|
659
|
+
if (newParagraph) {
|
|
660
|
+
const newLine = new LineLayout(next, cumulativeOverrides, context, depth);
|
|
661
|
+
newLine.offsetFromDocument.y -= context.textStyleResolver.blockSettings.paragraphSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
|
|
662
|
+
return newLine;
|
|
663
|
+
}
|
|
664
|
+
return new LineLayout(next, cumulativeOverrides, context, depth);
|
|
568
665
|
}
|
|
569
666
|
justifyLines() {
|
|
570
667
|
// We don't want to justify empty text, or a single line of text whose width is 0. By default text is already left justified.
|
|
@@ -575,7 +672,7 @@ export class TextBlockLayout {
|
|
|
575
672
|
const docWidth = this.source.width;
|
|
576
673
|
let minOffset = Number.MAX_VALUE;
|
|
577
674
|
for (const line of this.lines) {
|
|
578
|
-
const lineWidth = line.justificationRange.xLength();
|
|
675
|
+
const lineWidth = line.justificationRange.xLength() + line.offsetFromDocument.x;
|
|
579
676
|
let offset = docWidth - lineWidth;
|
|
580
677
|
if ("center" === this.source.justification) {
|
|
581
678
|
offset = offset / 2;
|
|
@@ -589,34 +686,6 @@ export class TextBlockLayout {
|
|
|
589
686
|
this.textRange.high.x += minOffset;
|
|
590
687
|
}
|
|
591
688
|
}
|
|
592
|
-
flushLine(context, line, nextParagraph) {
|
|
593
|
-
nextParagraph = nextParagraph ?? line.source;
|
|
594
|
-
// We want to guarantee that each layout line has at least one run.
|
|
595
|
-
if (line.runs.length === 0) {
|
|
596
|
-
// If we're empty, there should always be a preceding run, and it should be a line break.
|
|
597
|
-
if (this.lines.length === 0 || this._back.runs.length === 0) {
|
|
598
|
-
return new LineLayout(nextParagraph);
|
|
599
|
-
}
|
|
600
|
-
const prevRun = this._back.back.source;
|
|
601
|
-
assert(prevRun.type === "linebreak");
|
|
602
|
-
if (prevRun.type !== "linebreak") {
|
|
603
|
-
return new LineLayout(nextParagraph);
|
|
604
|
-
}
|
|
605
|
-
line.append(RunLayout.create(prevRun.clone(), line.source, context));
|
|
606
|
-
}
|
|
607
|
-
// Line origin is its baseline.
|
|
608
|
-
const lineOffset = { x: 0, y: -line.range.yLength() };
|
|
609
|
-
// Place it below any existing lines
|
|
610
|
-
if (this.lines.length > 0) {
|
|
611
|
-
lineOffset.y += this._back.offsetFromDocument.y;
|
|
612
|
-
lineOffset.y -= context.textStyleResolver.blockSettings.lineSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
|
|
613
|
-
}
|
|
614
|
-
line.offsetFromDocument = lineOffset;
|
|
615
|
-
// Update document range from computed line range and position
|
|
616
|
-
this.textRange.extendRange(line.range.cloneTranslated(lineOffset));
|
|
617
|
-
this.lines.push(line);
|
|
618
|
-
return new LineLayout(nextParagraph);
|
|
619
|
-
}
|
|
620
689
|
applyMargins(margins) {
|
|
621
690
|
this.range = this.textRange.clone();
|
|
622
691
|
if (this.range.isNull)
|