@itwin/core-backend 5.2.0-dev.8 → 5.3.0-dev.2

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.
Files changed (198) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/lib/cjs/BackendHubAccess.d.ts +2 -0
  3. package/lib/cjs/BackendHubAccess.d.ts.map +1 -1
  4. package/lib/cjs/BackendHubAccess.js.map +1 -1
  5. package/lib/cjs/BackendLoggerCategory.d.ts +6 -0
  6. package/lib/cjs/BackendLoggerCategory.d.ts.map +1 -1
  7. package/lib/cjs/BackendLoggerCategory.js +6 -0
  8. package/lib/cjs/BackendLoggerCategory.js.map +1 -1
  9. package/lib/cjs/BriefcaseManager.d.ts +57 -3
  10. package/lib/cjs/BriefcaseManager.d.ts.map +1 -1
  11. package/lib/cjs/BriefcaseManager.js +151 -42
  12. package/lib/cjs/BriefcaseManager.js.map +1 -1
  13. package/lib/cjs/CloudSqlite.d.ts +4 -0
  14. package/lib/cjs/CloudSqlite.d.ts.map +1 -1
  15. package/lib/cjs/CloudSqlite.js.map +1 -1
  16. package/lib/cjs/ECDb.d.ts +8 -0
  17. package/lib/cjs/ECDb.d.ts.map +1 -1
  18. package/lib/cjs/ECDb.js +22 -0
  19. package/lib/cjs/ECDb.js.map +1 -1
  20. package/lib/cjs/GeographicCRSServices.d.ts.map +1 -1
  21. package/lib/cjs/GeographicCRSServices.js +2 -0
  22. package/lib/cjs/GeographicCRSServices.js.map +1 -1
  23. package/lib/cjs/IModelDb.d.ts +54 -3
  24. package/lib/cjs/IModelDb.d.ts.map +1 -1
  25. package/lib/cjs/IModelDb.js +87 -9
  26. package/lib/cjs/IModelDb.js.map +1 -1
  27. package/lib/cjs/IModelHost.d.ts +11 -1
  28. package/lib/cjs/IModelHost.d.ts.map +1 -1
  29. package/lib/cjs/IModelHost.js +5 -0
  30. package/lib/cjs/IModelHost.js.map +1 -1
  31. package/lib/cjs/IModelIncrementalSchemaLocater.d.ts +1 -5
  32. package/lib/cjs/IModelIncrementalSchemaLocater.d.ts.map +1 -1
  33. package/lib/cjs/IModelIncrementalSchemaLocater.js +0 -6
  34. package/lib/cjs/IModelIncrementalSchemaLocater.js.map +1 -1
  35. package/lib/cjs/SqliteChangesetReader.d.ts +8 -0
  36. package/lib/cjs/SqliteChangesetReader.d.ts.map +1 -1
  37. package/lib/cjs/SqliteChangesetReader.js +11 -0
  38. package/lib/cjs/SqliteChangesetReader.js.map +1 -1
  39. package/lib/cjs/StashManager.d.ts +175 -0
  40. package/lib/cjs/StashManager.d.ts.map +1 -0
  41. package/lib/cjs/StashManager.js +306 -0
  42. package/lib/cjs/StashManager.js.map +1 -0
  43. package/lib/cjs/TxnManager.d.ts +226 -15
  44. package/lib/cjs/TxnManager.d.ts.map +1 -1
  45. package/lib/cjs/TxnManager.js +249 -23
  46. package/lib/cjs/TxnManager.js.map +1 -1
  47. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
  48. package/lib/cjs/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
  49. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js +15 -6
  50. package/lib/cjs/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  51. package/lib/cjs/annotations/LeaderGeometry.d.ts +3 -2
  52. package/lib/cjs/annotations/LeaderGeometry.d.ts.map +1 -1
  53. package/lib/cjs/annotations/LeaderGeometry.js +5 -4
  54. package/lib/cjs/annotations/LeaderGeometry.js.map +1 -1
  55. package/lib/cjs/annotations/TextAnnotationElement.d.ts +52 -24
  56. package/lib/cjs/annotations/TextAnnotationElement.d.ts.map +1 -1
  57. package/lib/cjs/annotations/TextAnnotationElement.js +49 -59
  58. package/lib/cjs/annotations/TextAnnotationElement.js.map +1 -1
  59. package/lib/cjs/annotations/TextAnnotationGeometry.d.ts +2 -0
  60. package/lib/cjs/annotations/TextAnnotationGeometry.d.ts.map +1 -1
  61. package/lib/cjs/annotations/TextAnnotationGeometry.js +26 -19
  62. package/lib/cjs/annotations/TextAnnotationGeometry.js.map +1 -1
  63. package/lib/cjs/annotations/TextBlockGeometry.d.ts.map +1 -1
  64. package/lib/cjs/annotations/TextBlockGeometry.js +8 -0
  65. package/lib/cjs/annotations/TextBlockGeometry.js.map +1 -1
  66. package/lib/cjs/annotations/TextBlockLayout.d.ts +49 -36
  67. package/lib/cjs/annotations/TextBlockLayout.d.ts.map +1 -1
  68. package/lib/cjs/annotations/TextBlockLayout.js +204 -135
  69. package/lib/cjs/annotations/TextBlockLayout.js.map +1 -1
  70. package/lib/cjs/internal/ChannelAdmin.js +1 -1
  71. package/lib/cjs/internal/ChannelAdmin.js.map +1 -1
  72. package/lib/cjs/internal/Symbols.d.ts +1 -0
  73. package/lib/cjs/internal/Symbols.d.ts.map +1 -1
  74. package/lib/cjs/internal/Symbols.js +2 -1
  75. package/lib/cjs/internal/Symbols.js.map +1 -1
  76. package/lib/cjs/internal/annotations/fields.d.ts +2 -12
  77. package/lib/cjs/internal/annotations/fields.d.ts.map +1 -1
  78. package/lib/cjs/internal/annotations/fields.js +49 -45
  79. package/lib/cjs/internal/annotations/fields.js.map +1 -1
  80. package/lib/cjs/workspace/Workspace.d.ts +1 -1
  81. package/lib/cjs/workspace/Workspace.js.map +1 -1
  82. package/lib/esm/BackendHubAccess.d.ts +2 -0
  83. package/lib/esm/BackendHubAccess.d.ts.map +1 -1
  84. package/lib/esm/BackendHubAccess.js.map +1 -1
  85. package/lib/esm/BackendLoggerCategory.d.ts +6 -0
  86. package/lib/esm/BackendLoggerCategory.d.ts.map +1 -1
  87. package/lib/esm/BackendLoggerCategory.js +6 -0
  88. package/lib/esm/BackendLoggerCategory.js.map +1 -1
  89. package/lib/esm/BriefcaseManager.d.ts +57 -3
  90. package/lib/esm/BriefcaseManager.d.ts.map +1 -1
  91. package/lib/esm/BriefcaseManager.js +152 -43
  92. package/lib/esm/BriefcaseManager.js.map +1 -1
  93. package/lib/esm/CloudSqlite.d.ts +4 -0
  94. package/lib/esm/CloudSqlite.d.ts.map +1 -1
  95. package/lib/esm/CloudSqlite.js.map +1 -1
  96. package/lib/esm/ECDb.d.ts +8 -0
  97. package/lib/esm/ECDb.d.ts.map +1 -1
  98. package/lib/esm/ECDb.js +22 -0
  99. package/lib/esm/ECDb.js.map +1 -1
  100. package/lib/esm/GeographicCRSServices.d.ts.map +1 -1
  101. package/lib/esm/GeographicCRSServices.js +2 -0
  102. package/lib/esm/GeographicCRSServices.js.map +1 -1
  103. package/lib/esm/IModelDb.d.ts +54 -3
  104. package/lib/esm/IModelDb.d.ts.map +1 -1
  105. package/lib/esm/IModelDb.js +88 -10
  106. package/lib/esm/IModelDb.js.map +1 -1
  107. package/lib/esm/IModelHost.d.ts +11 -1
  108. package/lib/esm/IModelHost.d.ts.map +1 -1
  109. package/lib/esm/IModelHost.js +5 -0
  110. package/lib/esm/IModelHost.js.map +1 -1
  111. package/lib/esm/IModelIncrementalSchemaLocater.d.ts +1 -5
  112. package/lib/esm/IModelIncrementalSchemaLocater.d.ts.map +1 -1
  113. package/lib/esm/IModelIncrementalSchemaLocater.js +0 -6
  114. package/lib/esm/IModelIncrementalSchemaLocater.js.map +1 -1
  115. package/lib/esm/SqliteChangesetReader.d.ts +8 -0
  116. package/lib/esm/SqliteChangesetReader.d.ts.map +1 -1
  117. package/lib/esm/SqliteChangesetReader.js +11 -0
  118. package/lib/esm/SqliteChangesetReader.js.map +1 -1
  119. package/lib/esm/StashManager.d.ts +175 -0
  120. package/lib/esm/StashManager.d.ts.map +1 -0
  121. package/lib/esm/StashManager.js +301 -0
  122. package/lib/esm/StashManager.js.map +1 -0
  123. package/lib/esm/TxnManager.d.ts +226 -15
  124. package/lib/esm/TxnManager.d.ts.map +1 -1
  125. package/lib/esm/TxnManager.js +247 -21
  126. package/lib/esm/TxnManager.js.map +1 -1
  127. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts +10 -1
  128. package/lib/esm/annotations/ElementDrivesTextAnnotation.d.ts.map +1 -1
  129. package/lib/esm/annotations/ElementDrivesTextAnnotation.js +13 -5
  130. package/lib/esm/annotations/ElementDrivesTextAnnotation.js.map +1 -1
  131. package/lib/esm/annotations/LeaderGeometry.d.ts +3 -2
  132. package/lib/esm/annotations/LeaderGeometry.d.ts.map +1 -1
  133. package/lib/esm/annotations/LeaderGeometry.js +5 -4
  134. package/lib/esm/annotations/LeaderGeometry.js.map +1 -1
  135. package/lib/esm/annotations/TextAnnotationElement.d.ts +52 -24
  136. package/lib/esm/annotations/TextAnnotationElement.d.ts.map +1 -1
  137. package/lib/esm/annotations/TextAnnotationElement.js +51 -61
  138. package/lib/esm/annotations/TextAnnotationElement.js.map +1 -1
  139. package/lib/esm/annotations/TextAnnotationGeometry.d.ts +2 -0
  140. package/lib/esm/annotations/TextAnnotationGeometry.d.ts.map +1 -1
  141. package/lib/esm/annotations/TextAnnotationGeometry.js +26 -19
  142. package/lib/esm/annotations/TextAnnotationGeometry.js.map +1 -1
  143. package/lib/esm/annotations/TextBlockGeometry.d.ts.map +1 -1
  144. package/lib/esm/annotations/TextBlockGeometry.js +8 -0
  145. package/lib/esm/annotations/TextBlockGeometry.js.map +1 -1
  146. package/lib/esm/annotations/TextBlockLayout.d.ts +49 -36
  147. package/lib/esm/annotations/TextBlockLayout.d.ts.map +1 -1
  148. package/lib/esm/annotations/TextBlockLayout.js +205 -136
  149. package/lib/esm/annotations/TextBlockLayout.js.map +1 -1
  150. package/lib/esm/internal/ChannelAdmin.js +1 -1
  151. package/lib/esm/internal/ChannelAdmin.js.map +1 -1
  152. package/lib/esm/internal/Symbols.d.ts +1 -0
  153. package/lib/esm/internal/Symbols.d.ts.map +1 -1
  154. package/lib/esm/internal/Symbols.js +1 -0
  155. package/lib/esm/internal/Symbols.js.map +1 -1
  156. package/lib/esm/internal/annotations/fields.d.ts +2 -12
  157. package/lib/esm/internal/annotations/fields.d.ts.map +1 -1
  158. package/lib/esm/internal/annotations/fields.js +51 -47
  159. package/lib/esm/internal/annotations/fields.js.map +1 -1
  160. package/lib/esm/test/AnnotationTestUtils.d.ts +5 -1
  161. package/lib/esm/test/AnnotationTestUtils.d.ts.map +1 -1
  162. package/lib/esm/test/AnnotationTestUtils.js +6 -1
  163. package/lib/esm/test/AnnotationTestUtils.js.map +1 -1
  164. package/lib/esm/test/annotations/Fields.test.js +163 -46
  165. package/lib/esm/test/annotations/Fields.test.js.map +1 -1
  166. package/lib/esm/test/annotations/LeaderGeometry.test.js +12 -10
  167. package/lib/esm/test/annotations/LeaderGeometry.test.js.map +1 -1
  168. package/lib/esm/test/annotations/TextAnnotation.test.js +299 -43
  169. package/lib/esm/test/annotations/TextAnnotation.test.js.map +1 -1
  170. package/lib/esm/test/annotations/TextBlock.test.js +453 -86
  171. package/lib/esm/test/annotations/TextBlock.test.js.map +1 -1
  172. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts +46 -0
  173. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.d.ts.map +1 -1
  174. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js +20 -2
  175. package/lib/esm/test/assets/IncrementalSchemaLocater/configs/simple.config.js.map +1 -1
  176. package/lib/esm/test/ecdb/ECDb.test.js +71 -1
  177. package/lib/esm/test/ecdb/ECDb.test.js.map +1 -1
  178. package/lib/esm/test/hubaccess/Rebase.test.d.ts +2 -0
  179. package/lib/esm/test/hubaccess/Rebase.test.d.ts.map +1 -0
  180. package/lib/esm/test/hubaccess/Rebase.test.js +640 -0
  181. package/lib/esm/test/hubaccess/Rebase.test.js.map +1 -0
  182. package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js +20 -20
  183. package/lib/esm/test/incrementalSchemaLocater/ECSqlQueries.test.js.map +1 -1
  184. package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js +3 -3
  185. package/lib/esm/test/incrementalSchemaLocater/IncrementalLoading.test.js.map +1 -1
  186. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts +16 -1
  187. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.d.ts.map +1 -1
  188. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js +47 -0
  189. package/lib/esm/test/incrementalSchemaLocater/utils/TestSqlSchemaLocater.js.map +1 -1
  190. package/lib/esm/test/standalone/ChangeMerge.test.js +15 -19
  191. package/lib/esm/test/standalone/ChangeMerge.test.js.map +1 -1
  192. package/lib/esm/test/standalone/ChangesetReader.test.js +131 -1
  193. package/lib/esm/test/standalone/ChangesetReader.test.js.map +1 -1
  194. package/lib/esm/test/standalone/MergeConflict.test.js +3 -3
  195. package/lib/esm/test/standalone/MergeConflict.test.js.map +1 -1
  196. package/lib/esm/workspace/Workspace.d.ts +1 -1
  197. package/lib/esm/workspace/Workspace.js.map +1 -1
  198. package/package.json +13 -13
@@ -16,7 +16,6 @@ const core_geometry_1 = require("@itwin/core-geometry");
16
16
  const core_bentley_1 = require("@itwin/core-bentley");
17
17
  const LineBreaker = require("linebreak");
18
18
  const TextAnnotationElement_1 = require("./TextAnnotationElement");
19
- const Element_1 = require("../Element");
20
19
  /** @internal */
21
20
  function createFindTextStyleImpl(iModel) {
22
21
  return function findTextStyleImpl(id) {
@@ -60,11 +59,10 @@ function computeLayoutTextBlockResult(args) {
60
59
  * @beta
61
60
  */
62
61
  function computeGraphemeOffsets(args) {
63
- const { textBlock, paragraphIndex, runLayoutResult, graphemeCharIndexes, iModel } = args;
62
+ const { source, runLayoutResult, graphemeCharIndexes, iModel } = args;
64
63
  const findFontId = args.findFontId ?? ((name, type) => iModel.fonts.findId({ name, type }) ?? 0);
65
64
  const computeTextRange = args.computeTextRange ?? ((x) => iModel.computeRangesForText(x));
66
- const source = textBlock.paragraphs[paragraphIndex].runs[runLayoutResult.sourceRunIndex];
67
- if (source.type !== "text" || runLayoutResult.characterCount === 0) {
65
+ if (!(source instanceof core_common_1.TextRun) || runLayoutResult.characterCount === 0) {
68
66
  return [];
69
67
  }
70
68
  const style = core_common_1.TextStyleSettings.fromJSON(runLayoutResult.textStyle);
@@ -116,59 +114,39 @@ function applyBlockSettings(target, source, isLeader = false) {
116
114
  return target;
117
115
  }
118
116
  /**
119
- * Resolves the effective style of TextBlockComponents and Leaders, taking into account overrides/style of the instance and its parent(s).
117
+ * Resolves the effective style of TextBlockComponents and Leaders, taking into account overrides of the instance and its parent(s).
120
118
  * @beta
121
119
  */
122
120
  class TextStyleResolver {
123
- _textStyles = new Map();
124
- _findTextStyle;
125
121
  /** The resolved style of the TextBlock. */
126
122
  blockSettings;
127
- /** The scale factor of the model containing the TextBlock. */
128
- scaleFactor;
129
123
  constructor(args) {
130
- this._findTextStyle = args.findTextStyle ?? createFindTextStyleImpl(args.iModel);
131
- this.scaleFactor = 1;
132
- if (args.modelId) {
133
- const element = args.iModel.elements.getElement(args.modelId);
134
- if (element instanceof Element_1.Drawing)
135
- this.scaleFactor = element.scaleFactor;
136
- }
137
- this.blockSettings = this.findTextStyle(args.textBlock.styleId);
124
+ const findTextStyle = args.findTextStyle ?? createFindTextStyleImpl(args.iModel);
125
+ this.blockSettings = findTextStyle(args.textStyleId);
138
126
  if (args.textBlock.styleOverrides)
139
127
  this.blockSettings = this.blockSettings.clone(args.textBlock.styleOverrides);
140
128
  }
141
- resolveParagraphSettingsImpl(paragraph) {
129
+ /**
130
+ * Resolves the effective text style settings for a given TextBlockComponent, applying block-level overrides.
131
+ */
132
+ resolveSettings(overrides, isLeader = false) {
142
133
  let settings = this.blockSettings;
143
- if (paragraph.overridesStyle)
144
- settings = settings.clone(paragraph.styleOverrides);
145
- return settings;
146
- }
147
- /** Looks up an [[AnnotationTextStyle]] by ID. Uses caching. */
148
- findTextStyle(id) {
149
- let style = this._textStyles.get(id);
150
- if (undefined === style) {
151
- this._textStyles.set(id, style = this._findTextStyle(id));
152
- }
153
- return style;
154
- }
155
- /** Resolves the effective style for a [TextAnnotationLeader]($common). The TextAnnotationLeader should be a sibling of the provided TextBlock. */
156
- resolveTextAnnotationLeaderSettings(leader) {
157
- let settings = this.blockSettings;
158
- if (leader.styleOverrides)
159
- settings = settings.clone(leader.styleOverrides);
160
- return applyBlockSettings(settings, this.blockSettings, true);
161
- }
162
- /** Resolves the effective style for a [Paragraph]($common). Paragraph should be child of provided TextBlock. */
163
- resolveParagraphSettings(paragraph) {
164
- return applyBlockSettings(this.resolveParagraphSettingsImpl(paragraph), this.blockSettings);
165
- }
166
- /** Resolves the effective style for a [Run]($common). Run should be child of provided Paragraph and TextBlock. */
167
- resolveRunSettings(paragraph, run) {
168
- let settings = this.resolveParagraphSettingsImpl(paragraph);
169
- if (run.overridesStyle)
170
- settings = settings.clone(run.styleOverrides);
171
- return applyBlockSettings(settings, this.blockSettings);
134
+ if (overrides)
135
+ settings = settings.clone(overrides);
136
+ return applyBlockSettings(settings, this.blockSettings, isLeader);
137
+ }
138
+ resolveMarkerText(overrides, index) {
139
+ const markerSettings = overrides.listMarker ?? this.blockSettings.listMarker;
140
+ return (0, core_common_1.getMarkerText)(markerSettings, index);
141
+ }
142
+ /**
143
+ * Computes the indentation based on its style and nesting depth.
144
+ */
145
+ resolveIndentation(styleOverrides, depth) {
146
+ const overrides = this.resolveSettings(styleOverrides);
147
+ const indentation = overrides.indentation;
148
+ const tabInterval = overrides.tabInterval;
149
+ return indentation + tabInterval * depth;
172
150
  }
173
151
  }
174
152
  exports.TextStyleResolver = TextStyleResolver;
@@ -259,9 +237,9 @@ class LayoutContext {
259
237
  layout.extendRange(denominator);
260
238
  return { layout, numerator, denominator };
261
239
  }
262
- computeRangeForTabRun(style, source, length) {
240
+ computeRangeForTabRun(style, source, lengthFromLastTab) {
263
241
  const interval = source.styleOverrides.tabInterval ?? style.tabInterval;
264
- const tabEndX = interval - length % interval;
242
+ const tabEndX = interval - lengthFromLastTab % interval;
265
243
  const range = new core_geometry_1.Range2d(0, 0, 0, style.lineHeight);
266
244
  range.extendXY(tabEndX, range.low.y);
267
245
  return range;
@@ -317,8 +295,8 @@ class RunLayout {
317
295
  this.style = props.style;
318
296
  this.fontId = props.fontId;
319
297
  }
320
- static create(source, parentParagraph, context) {
321
- const style = context.textStyleResolver.resolveRunSettings(parentParagraph, source);
298
+ static create(source, context, cumulativeOverrides) {
299
+ const style = context.textStyleResolver.resolveSettings(cumulativeOverrides);
322
300
  const fontId = context.findFontId(style.fontName);
323
301
  const charOffset = 0;
324
302
  const offsetFromLine = { x: 0, y: 0 };
@@ -387,9 +365,8 @@ class RunLayout {
387
365
  });
388
366
  });
389
367
  }
390
- toResult(paragraph) {
368
+ toResult() {
391
369
  const result = {
392
- sourceRunIndex: paragraph.runs.indexOf(this.source),
393
370
  fontId: this.fontId,
394
371
  characterOffset: this.charOffset,
395
372
  characterCount: this.numChars,
@@ -419,32 +396,47 @@ exports.RunLayout = RunLayout;
419
396
  class LineLayout {
420
397
  source;
421
398
  range = new core_geometry_1.Range2d(0, 0, 0, 0);
399
+ runRange = new core_geometry_1.Range2d(0, 0, 0, 0); // Range of all runs excluding marker.
422
400
  justificationRange = new core_geometry_1.Range2d(0, 0, 0, 0);
423
- offsetFromDocument = { x: 0, y: 0 };
401
+ offsetFromDocument;
402
+ depth;
424
403
  lengthFromLastTab = 0; // Used to track the length from the last tab for tab runs.
425
404
  _runs = [];
426
- constructor(source) {
405
+ _marker;
406
+ constructor(source, style, context, depth = 0) {
427
407
  this.source = source;
408
+ this.depth = depth;
409
+ this.offsetFromDocument = { x: context?.textStyleResolver.resolveIndentation(style, depth) ?? 0, y: 0 };
428
410
  }
429
411
  /** Compute a string representation, primarily for debugging purposes. */
430
412
  stringify() {
431
413
  const runs = this._runs.map((run) => run.stringify());
432
414
  return `${runs.join("")}`;
433
415
  }
416
+ /** Gets the array of RunLayout objects contained in this line. */
434
417
  get runs() { return this._runs; }
418
+ /** Indicates whether this line contains any runs. */
435
419
  get isEmpty() { return this._runs.length === 0; }
420
+ /** Gets the last RunLayout in this line. */
436
421
  get back() {
437
422
  (0, core_bentley_1.assert)(!this.isEmpty);
438
423
  return this._runs[this._runs.length - 1];
439
424
  }
425
+ /**
426
+ * Gets or sets the marker RunLayout for this line, used for lists.
427
+ * A marker is the symbol or character that appears before each list item in a list, bullets, numbers, etc.
428
+ * */
429
+ get marker() { return this._marker; }
430
+ set marker(value) { this._marker = value; }
440
431
  append(run) {
441
432
  this._runs.push(run);
442
433
  this.computeRanges();
443
434
  }
444
435
  /** Invoked every time a run is appended,. */
445
436
  computeRanges() {
446
- this.range.low.setZero();
447
- this.range.high.setZero();
437
+ this.runRange.low.setZero();
438
+ this.runRange.high.setZero();
439
+ this.lengthFromLastTab = 0;
448
440
  // Some runs (fractions) are taller than others.
449
441
  // We want to center each run vertically inside the line.
450
442
  let lineHeight = 0;
@@ -453,26 +445,39 @@ class LineLayout {
453
445
  }
454
446
  for (const run of this._runs) {
455
447
  const runHeight = run.range.yLength();
456
- const runOffset = { x: this.range.high.x, y: (lineHeight - runHeight) / 2 };
448
+ const runOffset = { x: this.runRange.high.x, y: (lineHeight - runHeight) / 2 };
457
449
  run.offsetFromLine = runOffset;
458
450
  const runLayoutRange = run.range.cloneTranslated(runOffset);
459
- this.range.extendRange(runLayoutRange);
451
+ this.runRange.extendRange(runLayoutRange);
460
452
  if ("linebreak" !== run.source.type) {
461
453
  const runJustificationRange = run.justificationRange?.cloneTranslated(runOffset);
462
454
  this.justificationRange.extendRange(runJustificationRange ?? runLayoutRange);
463
455
  }
464
- if (run.source.type === "tab") {
456
+ if ("tab" === run.source.type) {
465
457
  this.lengthFromLastTab = 0;
466
458
  }
467
459
  else {
468
460
  this.lengthFromLastTab += run.range.xLength();
469
461
  }
470
462
  }
463
+ this.range.setFrom(this.runRange);
464
+ if (this._marker) {
465
+ const indentation = this.range.low.x;
466
+ const x = indentation - (this._marker.style.tabInterval / 2) - this._marker.range.xLength();
467
+ const runHeight = this._marker.range.yLength();
468
+ const runOffset = {
469
+ x,
470
+ y: (lineHeight - runHeight) / 2 // Center the marker vertically in the line.
471
+ };
472
+ this._marker.offsetFromLine = runOffset;
473
+ const markerRange = this._marker.range.cloneTranslated(this._marker.offsetFromLine);
474
+ this.range.extendRange(markerRange);
475
+ }
471
476
  }
472
- toResult(textBlock) {
477
+ toResult() {
473
478
  return {
474
- sourceParagraphIndex: textBlock.paragraphs.indexOf(this.source),
475
- runs: this.runs.map((x) => x.toResult(this.source)),
479
+ runs: this.runs.map((x) => x.toResult()),
480
+ marker: this.marker?.toResult(),
476
481
  range: this.range.toJSON(),
477
482
  justificationRange: this.justificationRange.toJSON(),
478
483
  offsetFromDocument: this.offsetFromDocument,
@@ -507,7 +512,7 @@ class TextBlockLayout {
507
512
  }
508
513
  toResult() {
509
514
  return {
510
- lines: this.lines.map((x) => x.toResult(this.source)),
515
+ lines: this.lines.map((x) => x.toResult()),
511
516
  range: this.range.toJSON(),
512
517
  };
513
518
  }
@@ -521,59 +526,151 @@ class TextBlockLayout {
521
526
  }
522
527
  populateLines(context) {
523
528
  const doc = this.source;
524
- if (doc.paragraphs.length === 0) {
529
+ if (!doc.children || doc.children.length === 0) {
525
530
  return;
526
531
  }
527
- const doWrap = doc.width > 0;
528
- let curLine = new LineLayout(doc.paragraphs[0]);
529
- for (let i = 0; i < doc.paragraphs.length; i++) {
530
- const paragraph = doc.paragraphs[i];
531
- if (i > 0) {
532
- curLine = this.flushLine(context, curLine, paragraph);
533
- }
534
- let runs = paragraph.runs.map((run) => RunLayout.create(run, paragraph, context));
535
- if (doWrap) {
536
- runs = runs.map((run) => run.split(context)).flat();
537
- }
538
- for (const run of runs) {
539
- if ("linebreak" === run.source.type) {
540
- curLine.append(run);
541
- curLine = this.flushLine(context, curLine);
542
- continue;
532
+ let curLine = new LineLayout(doc.children[0], doc.children[0].styleOverrides, context);
533
+ let childIndex = 0;
534
+ for (const child of doc.children) {
535
+ curLine = this.populateComponent(child, childIndex++, context, doc.width, curLine, doc, doc.styleOverrides);
536
+ }
537
+ if (curLine.runs.length > 0) {
538
+ this.flushLine(context, curLine, doc.styleOverrides);
539
+ }
540
+ }
541
+ populateComponent(component, componentIndex, context, docWidth, curLine, parent, cumulativeOverrides, depth = 0) {
542
+ cumulativeOverrides = { ...cumulativeOverrides, ...component.styleOverrides };
543
+ switch (component.type) {
544
+ case "list": {
545
+ // If we have any runs in the current line, flush it before starting the list.
546
+ if (curLine.runs.length > 0) {
547
+ curLine = this.flushLine(context, curLine, cumulativeOverrides, component.children[0], true, depth + 1);
548
+ }
549
+ else {
550
+ // If not, we need to apply the indentation for the list to the first line.
551
+ curLine.offsetFromDocument.x = context.textStyleResolver.resolveIndentation(cumulativeOverrides, depth + 1);
552
+ curLine.depth = depth + 1;
543
553
  }
544
- // If this is a tab, we need to apply the tab shift first, and then we can treat it like a text run.
545
- applyTabShift(run, curLine, context);
546
- // If our width is not set (doWrap is false), then we don't have to compute word wrapping, so just append the run, and continue.
547
- if (!doWrap) {
548
- curLine.append(run);
549
- continue;
554
+ // Iterate through each list item, setting the marker and populating its contents.
555
+ component.children.forEach((child, index) => {
556
+ const markerContent = context.textStyleResolver.resolveMarkerText(cumulativeOverrides, index + 1);
557
+ const markerRun = core_common_1.TextRun.create({ content: markerContent });
558
+ curLine.marker = RunLayout.create(markerRun, context, cumulativeOverrides);
559
+ curLine = this.populateComponent(child, index, context, docWidth, curLine, component, cumulativeOverrides, depth + 1);
560
+ });
561
+ // Lastly flush the line.
562
+ const nextSibling = parent?.children[componentIndex + 1];
563
+ if (curLine && nextSibling) {
564
+ curLine = this.flushLine(context, curLine, cumulativeOverrides, nextSibling, true, depth);
550
565
  }
551
- // Next, determine if we can append this run to the current line without exceeding the document width
552
- const runWidth = run.range.xLength();
553
- const lineWidth = curLine.range.xLength();
554
- // If true, then no word wrapping is required, so we can append to the current line.
555
- if (runWidth + lineWidth < doc.width || core_geometry_1.Geometry.isAlmostEqualNumber(runWidth + lineWidth, doc.width, core_geometry_1.Geometry.smallMetricDistance)) {
556
- curLine.append(run);
557
- continue;
566
+ break;
567
+ }
568
+ case "paragraph": {
569
+ // Iterate through each paragraph child (either a list or a run), populating its contents.
570
+ component.children.forEach((child, index) => {
571
+ curLine = this.populateComponent(child, index, context, docWidth, curLine, component, cumulativeOverrides, depth);
572
+ });
573
+ // Lastly flush the line.
574
+ const nextSibling = parent?.children[componentIndex + 1];
575
+ if (curLine && nextSibling) {
576
+ curLine = this.flushLine(context, curLine, cumulativeOverrides, nextSibling, true, depth);
558
577
  }
559
- // Do word wrapping
560
- if (curLine.runs.length === 0) {
561
- curLine.append(run);
562
- // Lastly, flush line
563
- curLine = this.flushLine(context, curLine);
578
+ break;
579
+ }
580
+ case "text": {
581
+ const layout = RunLayout.create(component, context, cumulativeOverrides);
582
+ // Text can be word-wrapped, so we need to split it into multiple runs if necessary.
583
+ if (docWidth > 0) {
584
+ layout.split(context).forEach(r => { curLine = this.populateRun(curLine, r, context, cumulativeOverrides, docWidth); });
564
585
  }
565
586
  else {
566
- // First, flush line
567
- curLine = this.flushLine(context, curLine);
568
- // Recompute tab shift if applicable
569
- applyTabShift(run, curLine, context);
570
- curLine.append(run);
587
+ curLine = this.populateRun(curLine, layout, context, cumulativeOverrides, docWidth);
571
588
  }
589
+ break;
590
+ }
591
+ case "fraction":
592
+ case "tab": {
593
+ const layout = RunLayout.create(component, context, cumulativeOverrides);
594
+ curLine = this.populateRun(curLine, layout, context, cumulativeOverrides, docWidth);
595
+ break;
572
596
  }
597
+ case "linebreak": {
598
+ const layout = RunLayout.create(component, context, cumulativeOverrides);
599
+ curLine.append(layout);
600
+ curLine = this.flushLine(context, curLine, cumulativeOverrides, undefined, undefined, depth);
601
+ break;
602
+ }
603
+ default: break;
573
604
  }
574
- if (curLine.runs.length > 0) {
575
- this.flushLine(context, curLine);
605
+ return curLine;
606
+ }
607
+ ;
608
+ populateRun(curLine, run, context, cumulativeOverrides, docWidth) {
609
+ // If this is a tab, we need to apply the tab shift first, and then we can treat it like a text run.
610
+ applyTabShift(run, curLine, context);
611
+ // If our width is not set, then we don't have to compute word wrapping, so just append the run, and continue.
612
+ if (docWidth <= 0) {
613
+ curLine.append(run);
614
+ return curLine;
615
+ }
616
+ // 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.
617
+ const runWidth = run.justificationRange?.xLength() ?? run.range.xLength();
618
+ const lineWidth = curLine.runRange.xLength();
619
+ const newWidth = runWidth + lineWidth + curLine.offsetFromDocument.x;
620
+ // If true, then no word wrapping is required, so we can append to the current line.
621
+ if (newWidth < docWidth || core_geometry_1.Geometry.isAlmostEqualNumber(newWidth, docWidth, core_geometry_1.Geometry.smallMetricDistance)) {
622
+ curLine.append(run);
623
+ return curLine;
576
624
  }
625
+ // If not, do word wrapping
626
+ if (curLine.runs.length === 0) {
627
+ curLine.append(run);
628
+ // Lastly, flush line
629
+ curLine = this.flushLine(context, curLine, cumulativeOverrides, undefined, undefined, curLine.depth);
630
+ }
631
+ else {
632
+ // First, flush line
633
+ curLine = this.flushLine(context, curLine, cumulativeOverrides, undefined, undefined, curLine.depth);
634
+ // Recompute tab shift if applicable
635
+ applyTabShift(run, curLine, context);
636
+ curLine.append(run);
637
+ }
638
+ return curLine;
639
+ }
640
+ ;
641
+ flushLine(context, curLine, cumulativeOverrides, next, newParagraph = false, depth = 0) {
642
+ next = next ?? curLine.source;
643
+ // We want to guarantee that each layout line has at least one run.
644
+ if (curLine.runs.length === 0) {
645
+ if (this.lines.length === 0 || this._back.runs.length === 0) {
646
+ return new LineLayout(next, cumulativeOverrides, context, depth);
647
+ }
648
+ if (curLine.source.type !== "linebreak") {
649
+ const newLine = new LineLayout(next, cumulativeOverrides, context, depth);
650
+ newLine.offsetFromDocument.y -= context.textStyleResolver.blockSettings.paragraphSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
651
+ return newLine;
652
+ }
653
+ const run = curLine.source.clone();
654
+ curLine.append(RunLayout.create(run, context, cumulativeOverrides));
655
+ }
656
+ // Line origin is its baseline.
657
+ const lineOffset = { ...curLine.offsetFromDocument }; // Start with the line's original offset, which includes indentation.
658
+ lineOffset.y -= curLine.range.yLength(); // Shift down the baseline
659
+ // Place it below any existing lines
660
+ if (this.lines.length > 0) {
661
+ lineOffset.y += this._back.offsetFromDocument.y;
662
+ lineOffset.y -= context.textStyleResolver.blockSettings.lineSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
663
+ }
664
+ curLine.offsetFromDocument = lineOffset;
665
+ // Update document range from computed line range and position
666
+ this.textRange.extendRange(curLine.range.cloneTranslated(lineOffset));
667
+ this.lines.push(curLine);
668
+ if (newParagraph) {
669
+ const newLine = new LineLayout(next, cumulativeOverrides, context, depth);
670
+ newLine.offsetFromDocument.y -= context.textStyleResolver.blockSettings.paragraphSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
671
+ return newLine;
672
+ }
673
+ return new LineLayout(next, cumulativeOverrides, context, depth);
577
674
  }
578
675
  justifyLines() {
579
676
  // 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.
@@ -584,7 +681,7 @@ class TextBlockLayout {
584
681
  const docWidth = this.source.width;
585
682
  let minOffset = Number.MAX_VALUE;
586
683
  for (const line of this.lines) {
587
- const lineWidth = line.justificationRange.xLength();
684
+ const lineWidth = line.justificationRange.xLength() + line.offsetFromDocument.x;
588
685
  let offset = docWidth - lineWidth;
589
686
  if ("center" === this.source.justification) {
590
687
  offset = offset / 2;
@@ -598,34 +695,6 @@ class TextBlockLayout {
598
695
  this.textRange.high.x += minOffset;
599
696
  }
600
697
  }
601
- flushLine(context, line, nextParagraph) {
602
- nextParagraph = nextParagraph ?? line.source;
603
- // We want to guarantee that each layout line has at least one run.
604
- if (line.runs.length === 0) {
605
- // If we're empty, there should always be a preceding run, and it should be a line break.
606
- if (this.lines.length === 0 || this._back.runs.length === 0) {
607
- return new LineLayout(nextParagraph);
608
- }
609
- const prevRun = this._back.back.source;
610
- (0, core_bentley_1.assert)(prevRun.type === "linebreak");
611
- if (prevRun.type !== "linebreak") {
612
- return new LineLayout(nextParagraph);
613
- }
614
- line.append(RunLayout.create(prevRun.clone(), line.source, context));
615
- }
616
- // Line origin is its baseline.
617
- const lineOffset = { x: 0, y: -line.range.yLength() };
618
- // Place it below any existing lines
619
- if (this.lines.length > 0) {
620
- lineOffset.y += this._back.offsetFromDocument.y;
621
- lineOffset.y -= context.textStyleResolver.blockSettings.lineSpacingFactor * context.textStyleResolver.blockSettings.lineHeight;
622
- }
623
- line.offsetFromDocument = lineOffset;
624
- // Update document range from computed line range and position
625
- this.textRange.extendRange(line.range.cloneTranslated(lineOffset));
626
- this.lines.push(line);
627
- return new LineLayout(nextParagraph);
628
- }
629
698
  applyMargins(margins) {
630
699
  this.range = this.textRange.clone();
631
700
  if (this.range.isNull)