@itwin/core-backend 4.6.0-dev.9 → 4.7.0-dev.3
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 +11 -1
- package/lib/cjs/BackendHubAccess.js +1 -1
- package/lib/cjs/BackendHubAccess.js.map +1 -1
- package/lib/cjs/BackendLoggerCategory.js +1 -1
- package/lib/cjs/BackendLoggerCategory.js.map +1 -1
- package/lib/cjs/BisCoreSchema.d.ts.map +1 -1
- package/lib/cjs/BisCoreSchema.js +2 -0
- package/lib/cjs/BisCoreSchema.js.map +1 -1
- package/lib/cjs/BlobContainerService.js +1 -1
- package/lib/cjs/BlobContainerService.js.map +1 -1
- package/lib/cjs/BriefcaseManager.js +2 -2
- package/lib/cjs/BriefcaseManager.js.map +1 -1
- package/lib/cjs/Category.d.ts +1 -1
- package/lib/cjs/Category.js +1 -1
- package/lib/cjs/Category.js.map +1 -1
- package/lib/cjs/ChangeSummaryManager.js +1 -1
- package/lib/cjs/ChangeSummaryManager.js.map +1 -1
- package/lib/cjs/ChangedElementsManager.js.map +1 -1
- package/lib/cjs/ChangesetECAdaptor.js +2 -2
- package/lib/cjs/ChangesetECAdaptor.js.map +1 -1
- package/lib/cjs/ChannelControl.js +2 -2
- package/lib/cjs/ChannelControl.js.map +1 -1
- package/lib/cjs/CheckpointManager.js +4 -4
- package/lib/cjs/CheckpointManager.js.map +1 -1
- package/lib/cjs/ClassRegistry.d.ts +3 -0
- package/lib/cjs/ClassRegistry.d.ts.map +1 -1
- package/lib/cjs/ClassRegistry.js +19 -8
- package/lib/cjs/ClassRegistry.js.map +1 -1
- package/lib/cjs/CloudSqlite.js +1 -1
- package/lib/cjs/CloudSqlite.js.map +1 -1
- package/lib/cjs/CodeService.js +1 -1
- package/lib/cjs/CodeService.js.map +1 -1
- package/lib/cjs/CodeSpecs.js +1 -1
- package/lib/cjs/CodeSpecs.js.map +1 -1
- package/lib/cjs/CustomViewState3dCreator.js.map +1 -1
- package/lib/cjs/DevTools.js +2 -2
- package/lib/cjs/DevTools.js.map +1 -1
- package/lib/cjs/DisplayStyle.js.map +1 -1
- package/lib/cjs/ECDb.js +1 -1
- package/lib/cjs/ECDb.js.map +1 -1
- package/lib/cjs/ECSchemaXmlContext.js.map +1 -1
- package/lib/cjs/ECSqlStatement.js.map +1 -1
- package/lib/cjs/Element.d.ts +0 -16
- package/lib/cjs/Element.d.ts.map +1 -1
- package/lib/cjs/Element.js +7 -23
- package/lib/cjs/Element.js.map +1 -1
- package/lib/cjs/ElementAspect.js +1 -1
- package/lib/cjs/ElementAspect.js.map +1 -1
- package/lib/cjs/ElementGraphics.d.ts +0 -3
- package/lib/cjs/ElementGraphics.d.ts.map +1 -1
- package/lib/cjs/ElementGraphics.js +2 -5
- package/lib/cjs/ElementGraphics.js.map +1 -1
- package/lib/cjs/ElementTreeWalker.d.ts.map +1 -1
- package/lib/cjs/ElementTreeWalker.js +5 -0
- package/lib/cjs/ElementTreeWalker.js.map +1 -1
- package/lib/cjs/EntityReferences.js +1 -1
- package/lib/cjs/EntityReferences.js.map +1 -1
- package/lib/cjs/ExportGraphics.d.ts +1 -1
- package/lib/cjs/ExportGraphics.js +2 -2
- package/lib/cjs/ExportGraphics.js.map +1 -1
- package/lib/cjs/ExternalSource.js.map +1 -1
- package/lib/cjs/GeoCoordConfig.js +1 -1
- package/lib/cjs/GeoCoordConfig.js.map +1 -1
- package/lib/cjs/GeometrySummary.js +5 -5
- package/lib/cjs/GeometrySummary.js.map +1 -1
- package/lib/cjs/HubMock.js +1 -1
- package/lib/cjs/HubMock.js.map +1 -1
- package/lib/cjs/IModelDb.d.ts +8 -2
- package/lib/cjs/IModelDb.d.ts.map +1 -1
- package/lib/cjs/IModelDb.js +62 -21
- package/lib/cjs/IModelDb.js.map +1 -1
- package/lib/cjs/IModelElementCloneContext.js.map +1 -1
- package/lib/cjs/IModelHost.js +2 -2
- package/lib/cjs/IModelHost.js.map +1 -1
- package/lib/cjs/IModelJsFs.js.map +1 -1
- package/lib/cjs/IpcHost.js +1 -1
- package/lib/cjs/IpcHost.js.map +1 -1
- package/lib/cjs/LineStyle.d.ts +1 -1
- package/lib/cjs/LineStyle.js +2 -2
- package/lib/cjs/LineStyle.js.map +1 -1
- package/lib/cjs/LocalHub.js.map +1 -1
- package/lib/cjs/LocalhostIpcHost.js +1 -1
- package/lib/cjs/LocalhostIpcHost.js.map +1 -1
- package/lib/cjs/Material.js +1 -1
- package/lib/cjs/Material.js.map +1 -1
- package/lib/cjs/NativeAppStorage.js +1 -1
- package/lib/cjs/NativeAppStorage.js.map +1 -1
- package/lib/cjs/NativeHost.js +1 -1
- package/lib/cjs/NativeHost.js.map +1 -1
- package/lib/cjs/NavigationRelationship.js +21 -21
- package/lib/cjs/NavigationRelationship.js.map +1 -1
- package/lib/cjs/PromiseMemoizer.d.ts +0 -3
- package/lib/cjs/PromiseMemoizer.d.ts.map +1 -1
- package/lib/cjs/PromiseMemoizer.js +2 -5
- package/lib/cjs/PromiseMemoizer.js.map +1 -1
- package/lib/cjs/PropertyStore.js +1 -1
- package/lib/cjs/PropertyStore.js.map +1 -1
- package/lib/cjs/Relationship.js.map +1 -1
- package/lib/cjs/SQLiteDb.js +2 -2
- package/lib/cjs/SQLiteDb.js.map +1 -1
- package/lib/cjs/Schema.js +1 -1
- package/lib/cjs/Schema.js.map +1 -1
- package/lib/cjs/SchemaSync.js +1 -1
- package/lib/cjs/SchemaSync.js.map +1 -1
- package/lib/cjs/ServerBasedLocks.js.map +1 -1
- package/lib/cjs/SqliteChangesetReader.js.map +1 -1
- package/lib/cjs/SqliteStatement.js +2 -2
- package/lib/cjs/SqliteStatement.js.map +1 -1
- package/lib/cjs/TextAnnotationElement.d.ts +54 -0
- package/lib/cjs/TextAnnotationElement.d.ts.map +1 -0
- package/lib/cjs/TextAnnotationElement.js +94 -0
- package/lib/cjs/TextAnnotationElement.js.map +1 -0
- package/lib/cjs/TextAnnotationGeometry.d.ts +28 -0
- package/lib/cjs/TextAnnotationGeometry.d.ts.map +1 -0
- package/lib/cjs/TextAnnotationGeometry.js +155 -0
- package/lib/cjs/TextAnnotationGeometry.js.map +1 -0
- package/lib/cjs/TextAnnotationLayout.d.ts +141 -0
- package/lib/cjs/TextAnnotationLayout.d.ts.map +1 -0
- package/lib/cjs/TextAnnotationLayout.js +414 -0
- package/lib/cjs/TextAnnotationLayout.js.map +1 -0
- package/lib/cjs/TileStorage.js.map +1 -1
- package/lib/cjs/TxnManager.d.ts.map +1 -1
- package/lib/cjs/TxnManager.js +53 -1
- package/lib/cjs/TxnManager.js.map +1 -1
- package/lib/cjs/ViewDefinition.js +4 -4
- package/lib/cjs/ViewDefinition.js.map +1 -1
- package/lib/cjs/ViewStateHydrator.d.ts +1 -0
- package/lib/cjs/ViewStateHydrator.d.ts.map +1 -1
- package/lib/cjs/ViewStateHydrator.js +1 -0
- package/lib/cjs/ViewStateHydrator.js.map +1 -1
- package/lib/cjs/ViewStore.js +1 -1
- package/lib/cjs/ViewStore.js.map +1 -1
- package/lib/cjs/core-backend.d.ts +47 -61
- package/lib/cjs/core-backend.d.ts.map +1 -1
- package/lib/cjs/core-backend.js +49 -62
- package/lib/cjs/core-backend.js.map +1 -1
- package/lib/cjs/domains/FunctionalElements.js +1 -1
- package/lib/cjs/domains/FunctionalElements.js.map +1 -1
- package/lib/cjs/domains/FunctionalSchema.js.map +1 -1
- package/lib/cjs/domains/GenericSchema.js.map +1 -1
- package/lib/cjs/rpc/multipart.js.map +1 -1
- package/lib/cjs/rpc/tracing.js +2 -2
- package/lib/cjs/rpc/tracing.js.map +1 -1
- package/lib/cjs/rpc/web/logging.js +2 -2
- package/lib/cjs/rpc/web/logging.js.map +1 -1
- package/lib/cjs/rpc/web/request.js.map +1 -1
- package/lib/cjs/rpc/web/response.js +1 -1
- package/lib/cjs/rpc/web/response.js.map +1 -1
- package/lib/cjs/rpc-impl/IModelReadRpcImpl.js.map +1 -1
- package/lib/cjs/rpc-impl/IModelTileRpcImpl.js.map +1 -1
- package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js +1 -1
- package/lib/cjs/rpc-impl/RpcBriefcaseUtility.js.map +1 -1
- package/lib/cjs/rpc-impl/SnapshotIModelRpcImpl.js.map +1 -1
- package/lib/cjs/workspace/Settings.js +1 -1
- package/lib/cjs/workspace/Settings.js.map +1 -1
- package/lib/cjs/workspace/SettingsSchemas.d.ts +0 -5
- package/lib/cjs/workspace/SettingsSchemas.d.ts.map +1 -1
- package/lib/cjs/workspace/SettingsSchemas.js +1 -10
- package/lib/cjs/workspace/SettingsSchemas.js.map +1 -1
- package/lib/cjs/workspace/Workspace.js +4 -4
- package/lib/cjs/workspace/Workspace.js.map +1 -1
- package/package.json +14 -14
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/** @packageDocumentation
|
|
2
|
+
* @module ElementGeometry
|
|
3
|
+
*/
|
|
4
|
+
import { BaselineShift, FontId, FractionRun, Paragraph, Run, TextBlock, TextRun, TextStyleSettings } from "@itwin/core-common";
|
|
5
|
+
import { Range2d, XAndY } from "@itwin/core-geometry";
|
|
6
|
+
import { IModelDb } from "./IModelDb";
|
|
7
|
+
/** @internal */
|
|
8
|
+
export interface TextLayoutRanges {
|
|
9
|
+
layout: Range2d;
|
|
10
|
+
justification: Range2d;
|
|
11
|
+
}
|
|
12
|
+
/** Arguments to [[ComputeRangesForTextLayout]].
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export interface ComputeRangesForTextLayoutArgs {
|
|
16
|
+
chars: string;
|
|
17
|
+
bold: boolean;
|
|
18
|
+
italic: boolean;
|
|
19
|
+
baselineShift: BaselineShift;
|
|
20
|
+
fontId: FontId;
|
|
21
|
+
widthFactor: number;
|
|
22
|
+
lineHeight: number;
|
|
23
|
+
}
|
|
24
|
+
/** A function that uses a font to compute the layout and justification ranges of a string of text.
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export type ComputeRangesForTextLayout = (args: ComputeRangesForTextLayoutArgs) => TextLayoutRanges;
|
|
28
|
+
/** @internal */
|
|
29
|
+
export type FindFontId = (name: string) => FontId;
|
|
30
|
+
/** @internal */
|
|
31
|
+
export type FindTextStyle = (name: string) => TextStyleSettings;
|
|
32
|
+
/** Arguments supplied to [[computeTextBlockExtents]].
|
|
33
|
+
* @beta
|
|
34
|
+
*/
|
|
35
|
+
export interface ComputeTextBlockExtentsArgs {
|
|
36
|
+
/** The text block whose extents are to be computed. */
|
|
37
|
+
textBlock: TextBlock;
|
|
38
|
+
/** The iModel from which to obtain fonts and [TextStyle]($common)s when laying out glyphs. */
|
|
39
|
+
iModel: IModelDb;
|
|
40
|
+
}
|
|
41
|
+
/** @internal */
|
|
42
|
+
export interface LayoutTextBlockArgs extends ComputeTextBlockExtentsArgs {
|
|
43
|
+
/** @internal chiefly for tests, by default uses IModelJsNative.DgnDb.computeRangesForText. */
|
|
44
|
+
computeTextRange?: ComputeRangesForTextLayout;
|
|
45
|
+
/** @internal chiefly for tests, by default looks up styles from a workspace. */
|
|
46
|
+
findTextStyle?: FindTextStyle;
|
|
47
|
+
/** @internal chiefly for tests, by default uses IModelDb.fontMap. */
|
|
48
|
+
findFontId?: FindFontId;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Lays out the contents of a TextBlock into a series of lines containing runs.
|
|
52
|
+
* Each paragraph is decomposed into a series of lines.
|
|
53
|
+
* Each series of consecutive non-linebreak runs within a paragraph is concatenated into one line.
|
|
54
|
+
* If the document specifies a width > 0, individual lines are split to try to avoid exceeding that width.
|
|
55
|
+
* Individual TextRuns can be split onto multiple lines at word boundaries if necessary. Individual FractionRuns are never split.
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export declare function layoutTextBlock(args: LayoutTextBlockArgs): TextBlockLayout;
|
|
59
|
+
/** Compute the bounding box containing the contents of a [TextBlock]($common).
|
|
60
|
+
* This process converts each [Paragraph]($common) into a set of lines of text, laying out the glyphs of individual
|
|
61
|
+
* [Run]($common)s based on their [TextStyle]($common)s and fonts, and applying work-wrapping based on [TextBlock.width]($common).
|
|
62
|
+
* The resultant extents can be supplied to [TextAnnotation.computeTransform]($common) and [TextAnnotation.computeAnchorPoint]($common).
|
|
63
|
+
* @beta
|
|
64
|
+
*/
|
|
65
|
+
export declare function computeTextBlockExtents(args: ComputeTextBlockExtentsArgs): XAndY;
|
|
66
|
+
declare class LayoutContext {
|
|
67
|
+
private readonly _computeTextRange;
|
|
68
|
+
private readonly _findTextStyle;
|
|
69
|
+
private readonly _findFontId;
|
|
70
|
+
private readonly _textStyles;
|
|
71
|
+
private readonly _fontIds;
|
|
72
|
+
readonly blockSettings: TextStyleSettings;
|
|
73
|
+
constructor(block: TextBlock, _computeTextRange: ComputeRangesForTextLayout, _findTextStyle: FindTextStyle, _findFontId: FindFontId);
|
|
74
|
+
findFontId(name: string): FontId;
|
|
75
|
+
findTextStyle(name: string): TextStyleSettings;
|
|
76
|
+
createRunSettings(run: Run): TextStyleSettings;
|
|
77
|
+
computeRangeForText(chars: string, style: TextStyleSettings, baselineShift: BaselineShift): TextLayoutRanges;
|
|
78
|
+
computeRangeForTextRun(style: TextStyleSettings, run: TextRun, charOffset: number, numChars: number): TextLayoutRanges;
|
|
79
|
+
computeRangeForFractionRun(style: TextStyleSettings, source: FractionRun): {
|
|
80
|
+
layout: Range2d;
|
|
81
|
+
numerator: Range2d;
|
|
82
|
+
denominator: Range2d;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** @internal */
|
|
86
|
+
export declare class RunLayout {
|
|
87
|
+
source: Run;
|
|
88
|
+
charOffset: number;
|
|
89
|
+
numChars: number;
|
|
90
|
+
range: Range2d;
|
|
91
|
+
justificationRange?: Range2d;
|
|
92
|
+
denominatorRange?: Range2d;
|
|
93
|
+
numeratorRange?: Range2d;
|
|
94
|
+
offsetFromLine: {
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
};
|
|
98
|
+
style: TextStyleSettings;
|
|
99
|
+
fontId: FontId;
|
|
100
|
+
private constructor();
|
|
101
|
+
static create(source: Run, context: LayoutContext): RunLayout;
|
|
102
|
+
canWrap(): this is {
|
|
103
|
+
source: TextRun;
|
|
104
|
+
};
|
|
105
|
+
private cloneForWrap;
|
|
106
|
+
wrap(availableWidth: number, shouldForceLeadingUnit: boolean, context: LayoutContext): RunLayout | undefined;
|
|
107
|
+
}
|
|
108
|
+
/** @internal */
|
|
109
|
+
export declare class LineLayout {
|
|
110
|
+
source: Paragraph;
|
|
111
|
+
range: Range2d;
|
|
112
|
+
justificationRange: Range2d;
|
|
113
|
+
offsetFromDocument: {
|
|
114
|
+
x: number;
|
|
115
|
+
y: number;
|
|
116
|
+
};
|
|
117
|
+
private _runs;
|
|
118
|
+
constructor(source: Paragraph);
|
|
119
|
+
get runs(): ReadonlyArray<RunLayout>;
|
|
120
|
+
get isEmpty(): boolean;
|
|
121
|
+
get back(): RunLayout;
|
|
122
|
+
append(run: RunLayout): void;
|
|
123
|
+
/** Invoked every time a run is appended,. */
|
|
124
|
+
private computeRanges;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Describes the layout of a text block as a collection of lines containing runs.
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
export declare class TextBlockLayout {
|
|
131
|
+
source: TextBlock;
|
|
132
|
+
range: Range2d;
|
|
133
|
+
lines: LineLayout[];
|
|
134
|
+
constructor(source: TextBlock, context: LayoutContext);
|
|
135
|
+
private get _back();
|
|
136
|
+
private populateLines;
|
|
137
|
+
private justifyLines;
|
|
138
|
+
private flushLine;
|
|
139
|
+
}
|
|
140
|
+
export {};
|
|
141
|
+
//# sourceMappingURL=TextAnnotationLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextAnnotationLayout.d.ts","sourceRoot":"","sources":["../../src/TextAnnotationLayout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*---------------------------------------------------------------------------------------------
|
|
3
|
+
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
4
|
+
* See LICENSE.md in the project root for license terms and full copyright notice.
|
|
5
|
+
*--------------------------------------------------------------------------------------------*/
|
|
6
|
+
/** @packageDocumentation
|
|
7
|
+
* @module ElementGeometry
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.TextBlockLayout = exports.LineLayout = exports.RunLayout = exports.computeTextBlockExtents = exports.layoutTextBlock = void 0;
|
|
11
|
+
const core_common_1 = require("@itwin/core-common");
|
|
12
|
+
const core_geometry_1 = require("@itwin/core-geometry");
|
|
13
|
+
const core_bentley_1 = require("@itwin/core-bentley");
|
|
14
|
+
/**
|
|
15
|
+
* Lays out the contents of a TextBlock into a series of lines containing runs.
|
|
16
|
+
* Each paragraph is decomposed into a series of lines.
|
|
17
|
+
* Each series of consecutive non-linebreak runs within a paragraph is concatenated into one line.
|
|
18
|
+
* If the document specifies a width > 0, individual lines are split to try to avoid exceeding that width.
|
|
19
|
+
* Individual TextRuns can be split onto multiple lines at word boundaries if necessary. Individual FractionRuns are never split.
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
function layoutTextBlock(args) {
|
|
23
|
+
const findFontId = args.findFontId ?? ((name) => args.iModel.fontMap.getFont(name)?.id ?? 0);
|
|
24
|
+
const computeTextRange = args.computeTextRange ?? ((x) => args.iModel.computeRangesForText(x));
|
|
25
|
+
// ###TODO finding text styles in workspaces.
|
|
26
|
+
const findTextStyle = args.findTextStyle ?? (() => core_common_1.TextStyleSettings.fromJSON());
|
|
27
|
+
return new TextBlockLayout(args.textBlock, new LayoutContext(args.textBlock, computeTextRange, findTextStyle, findFontId));
|
|
28
|
+
}
|
|
29
|
+
exports.layoutTextBlock = layoutTextBlock;
|
|
30
|
+
/** Compute the bounding box containing the contents of a [TextBlock]($common).
|
|
31
|
+
* This process converts each [Paragraph]($common) into a set of lines of text, laying out the glyphs of individual
|
|
32
|
+
* [Run]($common)s based on their [TextStyle]($common)s and fonts, and applying work-wrapping based on [TextBlock.width]($common).
|
|
33
|
+
* The resultant extents can be supplied to [TextAnnotation.computeTransform]($common) and [TextAnnotation.computeAnchorPoint]($common).
|
|
34
|
+
* @beta
|
|
35
|
+
*/
|
|
36
|
+
function computeTextBlockExtents(args) {
|
|
37
|
+
const range = layoutTextBlock(args).range;
|
|
38
|
+
(0, core_bentley_1.assert)(range.low.isZero);
|
|
39
|
+
return { x: range.high.x, y: range.high.y };
|
|
40
|
+
}
|
|
41
|
+
exports.computeTextBlockExtents = computeTextBlockExtents;
|
|
42
|
+
function scaleRange(range, scale) {
|
|
43
|
+
range.low.scaleInPlace(scale);
|
|
44
|
+
range.high.scaleInPlace(scale);
|
|
45
|
+
}
|
|
46
|
+
function applyBlockSettings(target, source) {
|
|
47
|
+
if (source === target) {
|
|
48
|
+
return target;
|
|
49
|
+
}
|
|
50
|
+
const lineSpacingFactor = source.lineSpacingFactor ?? target.lineSpacingFactor;
|
|
51
|
+
const lineHeight = source.lineHeight ?? target.lineHeight;
|
|
52
|
+
const widthFactor = source.widthFactor ?? target.widthFactor;
|
|
53
|
+
if (lineSpacingFactor !== target.lineSpacingFactor || lineHeight !== target.lineHeight || widthFactor !== target.widthFactor) {
|
|
54
|
+
target = target.clone({ lineSpacingFactor, lineHeight, widthFactor });
|
|
55
|
+
}
|
|
56
|
+
return target;
|
|
57
|
+
}
|
|
58
|
+
class LayoutContext {
|
|
59
|
+
constructor(block, _computeTextRange, _findTextStyle, _findFontId) {
|
|
60
|
+
this._computeTextRange = _computeTextRange;
|
|
61
|
+
this._findTextStyle = _findTextStyle;
|
|
62
|
+
this._findFontId = _findFontId;
|
|
63
|
+
this._textStyles = new Map();
|
|
64
|
+
this._fontIds = new Map();
|
|
65
|
+
const settings = this.findTextStyle(block.styleName);
|
|
66
|
+
this.blockSettings = applyBlockSettings(settings, block.styleOverrides);
|
|
67
|
+
}
|
|
68
|
+
findFontId(name) {
|
|
69
|
+
let fontId = this._fontIds.get(name);
|
|
70
|
+
if (undefined === fontId) {
|
|
71
|
+
this._fontIds.set(name, fontId = this._findFontId(name));
|
|
72
|
+
}
|
|
73
|
+
return fontId;
|
|
74
|
+
}
|
|
75
|
+
findTextStyle(name) {
|
|
76
|
+
let style = this._textStyles.get(name);
|
|
77
|
+
if (undefined === style) {
|
|
78
|
+
this._textStyles.set(name, style = this._findTextStyle(name));
|
|
79
|
+
}
|
|
80
|
+
return style;
|
|
81
|
+
}
|
|
82
|
+
createRunSettings(run) {
|
|
83
|
+
let settings = this.findTextStyle(run.styleName);
|
|
84
|
+
if (run.overridesStyle) {
|
|
85
|
+
settings = settings.clone(run.styleOverrides);
|
|
86
|
+
}
|
|
87
|
+
return applyBlockSettings(settings, this.blockSettings);
|
|
88
|
+
}
|
|
89
|
+
computeRangeForText(chars, style, baselineShift) {
|
|
90
|
+
if (chars.length === 0) {
|
|
91
|
+
return {
|
|
92
|
+
layout: new core_geometry_1.Range2d(0, 0, 0, style.lineHeight),
|
|
93
|
+
justification: new core_geometry_1.Range2d(),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const fontId = this.findFontId(style.fontName);
|
|
97
|
+
const { layout, justification } = this._computeTextRange({
|
|
98
|
+
chars,
|
|
99
|
+
fontId,
|
|
100
|
+
baselineShift,
|
|
101
|
+
bold: style.isBold,
|
|
102
|
+
italic: style.isItalic,
|
|
103
|
+
lineHeight: this.blockSettings.lineHeight,
|
|
104
|
+
widthFactor: this.blockSettings.widthFactor,
|
|
105
|
+
});
|
|
106
|
+
if ("none" !== baselineShift) {
|
|
107
|
+
const isSub = "subscript" === baselineShift;
|
|
108
|
+
const scale = isSub ? style.subScriptScale : style.superScriptScale;
|
|
109
|
+
const offsetFactor = isSub ? style.subScriptOffsetFactor : style.superScriptOffsetFactor;
|
|
110
|
+
const offset = { x: 0, y: style.lineHeight * offsetFactor };
|
|
111
|
+
scaleRange(layout, scale);
|
|
112
|
+
layout.cloneTranslated(offset, layout);
|
|
113
|
+
scaleRange(justification, scale);
|
|
114
|
+
justification.cloneTranslated(offset, justification);
|
|
115
|
+
}
|
|
116
|
+
return { layout, justification };
|
|
117
|
+
}
|
|
118
|
+
computeRangeForTextRun(style, run, charOffset, numChars) {
|
|
119
|
+
return this.computeRangeForText(run.content.substring(charOffset, charOffset + numChars), style, run.baselineShift);
|
|
120
|
+
}
|
|
121
|
+
computeRangeForFractionRun(style, source) {
|
|
122
|
+
const numerator = this.computeRangeForText(source.numerator, style, "none").layout;
|
|
123
|
+
scaleRange(numerator, style.stackedFractionScale);
|
|
124
|
+
const denominator = this.computeRangeForText(source.denominator, style, "none").layout;
|
|
125
|
+
scaleRange(denominator, style.stackedFractionScale);
|
|
126
|
+
const numLen = numerator.xLength();
|
|
127
|
+
const denomLen = denominator.xLength();
|
|
128
|
+
switch (style.stackedFractionType) {
|
|
129
|
+
case "horizontal": {
|
|
130
|
+
if (numLen > denomLen) {
|
|
131
|
+
denominator.cloneTranslated({ x: (numLen - denomLen) / 2, y: 0 }, denominator);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
numerator.cloneTranslated({ x: (denomLen - numLen) / 2, y: 0 }, numerator);
|
|
135
|
+
}
|
|
136
|
+
numerator.cloneTranslated({ x: 0, y: 1.5 * denominator.yLength() }, numerator);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
case "diagonal": {
|
|
140
|
+
numerator.cloneTranslated({ x: 0, y: denominator.yLength() }, numerator);
|
|
141
|
+
denominator.cloneTranslated({ x: numLen, y: 0 }, denominator);
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const layout = numerator.clone();
|
|
146
|
+
layout.extendRange(denominator);
|
|
147
|
+
return { layout, numerator, denominator };
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** @internal */
|
|
151
|
+
class RunLayout {
|
|
152
|
+
constructor(props) {
|
|
153
|
+
this.source = props.source;
|
|
154
|
+
this.charOffset = props.charOffset;
|
|
155
|
+
this.numChars = props.numChars;
|
|
156
|
+
this.range = props.range;
|
|
157
|
+
this.justificationRange = props.justificationRange;
|
|
158
|
+
this.denominatorRange = props.denominatorRange;
|
|
159
|
+
this.numeratorRange = props.numeratorRange;
|
|
160
|
+
this.offsetFromLine = props.offsetFromLine;
|
|
161
|
+
this.style = props.style;
|
|
162
|
+
this.fontId = props.fontId;
|
|
163
|
+
}
|
|
164
|
+
static create(source, context) {
|
|
165
|
+
const style = context.createRunSettings(source);
|
|
166
|
+
const fontId = context.findFontId(style.fontName);
|
|
167
|
+
const charOffset = 0;
|
|
168
|
+
const offsetFromLine = { x: 0, y: 0 };
|
|
169
|
+
let numChars = 0;
|
|
170
|
+
let range, justificationRange, numeratorRange, denominatorRange;
|
|
171
|
+
switch (source.type) {
|
|
172
|
+
case "text": {
|
|
173
|
+
numChars = source.content.length;
|
|
174
|
+
const ranges = context.computeRangeForTextRun(style, source, charOffset, numChars);
|
|
175
|
+
range = ranges.layout;
|
|
176
|
+
justificationRange = ranges.justification;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case "fraction": {
|
|
180
|
+
numChars = 1;
|
|
181
|
+
const ranges = context.computeRangeForFractionRun(style, source);
|
|
182
|
+
range = ranges.layout;
|
|
183
|
+
numeratorRange = ranges.numerator;
|
|
184
|
+
denominatorRange = ranges.denominator;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
default: {
|
|
188
|
+
// We do this so that blank lines space correctly without special casing later.
|
|
189
|
+
range = new core_geometry_1.Range2d(0, 0, 0, style.lineHeight);
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return new RunLayout({ source, charOffset, numChars, range, justificationRange, denominatorRange, numeratorRange, offsetFromLine, style, fontId });
|
|
194
|
+
}
|
|
195
|
+
canWrap() {
|
|
196
|
+
return this.source.type === "text";
|
|
197
|
+
}
|
|
198
|
+
cloneForWrap(args) {
|
|
199
|
+
(0, core_bentley_1.assert)(this.canWrap());
|
|
200
|
+
return new RunLayout({
|
|
201
|
+
...this,
|
|
202
|
+
charOffset: args.charOffset,
|
|
203
|
+
numChars: args.numChars,
|
|
204
|
+
range: args.ranges.layout,
|
|
205
|
+
justificationRange: args.ranges.justification,
|
|
206
|
+
offsetFromLine: { ...this.offsetFromLine },
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
wrap(availableWidth, shouldForceLeadingUnit, context) {
|
|
210
|
+
if (!this.canWrap()) {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
// An optimization that tracks the computed width so far so we don't have to repeatedly recompute preceding character ranges.
|
|
214
|
+
// Assumes (to the best of Jeff's knowledge) that characters before a break point can't affect the shaping of subsequent characters.
|
|
215
|
+
let runningWidth = 0;
|
|
216
|
+
let breakPos = 0;
|
|
217
|
+
// ###TODO TypeScript only provides type declarations for Intl.Segmenter if targeting ES2022+.
|
|
218
|
+
// But doing so causes inexplicable issues with initialization of Model.modeledElement.
|
|
219
|
+
// So until that's resolved, access it via cast to any.
|
|
220
|
+
const segmenter = new global.Intl.Segmenter(undefined, { granularity: "word" });
|
|
221
|
+
const myText = this.source.content.substring(this.charOffset, this.charOffset + this.numChars);
|
|
222
|
+
if (myText.length === 0) {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
for (const segment of segmenter.segment(myText)) {
|
|
226
|
+
const testContent = segment.segment;
|
|
227
|
+
const forceCurrentUnit = shouldForceLeadingUnit && (0 === breakPos);
|
|
228
|
+
// If we don't fit, the previous break position is the split point.
|
|
229
|
+
const ranges = context.computeRangeForText(testContent, this.style, this.source.baselineShift);
|
|
230
|
+
if (!forceCurrentUnit && (runningWidth + ranges.justification.xLength()) > availableWidth) {
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
// Otherwise, we fit; keep trying.
|
|
234
|
+
runningWidth += ranges.layout.xLength();
|
|
235
|
+
breakPos = segment.index + testContent.length;
|
|
236
|
+
}
|
|
237
|
+
// If the whole thing fits, we don't have to wrap (i.e., we just wasted a bunch of time).
|
|
238
|
+
if (breakPos >= myText.length) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
// Trim this run and return the remainder.
|
|
242
|
+
const charOffset = this.charOffset + breakPos;
|
|
243
|
+
const numChars = this.numChars - breakPos;
|
|
244
|
+
this.numChars = breakPos;
|
|
245
|
+
const leftover = this.source.content.substring(charOffset, charOffset + numChars);
|
|
246
|
+
return this.cloneForWrap({
|
|
247
|
+
ranges: context.computeRangeForText(leftover, this.style, this.source.baselineShift),
|
|
248
|
+
charOffset,
|
|
249
|
+
numChars,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.RunLayout = RunLayout;
|
|
254
|
+
/** @internal */
|
|
255
|
+
class LineLayout {
|
|
256
|
+
constructor(source) {
|
|
257
|
+
this.range = new core_geometry_1.Range2d(0, 0, 0, 0);
|
|
258
|
+
this.justificationRange = new core_geometry_1.Range2d(0, 0, 0, 0);
|
|
259
|
+
this.offsetFromDocument = { x: 0, y: 0 };
|
|
260
|
+
this._runs = [];
|
|
261
|
+
this.source = source;
|
|
262
|
+
}
|
|
263
|
+
get runs() { return this._runs; }
|
|
264
|
+
get isEmpty() { return this._runs.length === 0; }
|
|
265
|
+
get back() {
|
|
266
|
+
(0, core_bentley_1.assert)(!this.isEmpty);
|
|
267
|
+
return this._runs[this._runs.length - 1];
|
|
268
|
+
}
|
|
269
|
+
append(run) {
|
|
270
|
+
this._runs.push(run);
|
|
271
|
+
this.computeRanges();
|
|
272
|
+
}
|
|
273
|
+
/** Invoked every time a run is appended,. */
|
|
274
|
+
computeRanges() {
|
|
275
|
+
this.range.low.setZero();
|
|
276
|
+
this.range.high.setZero();
|
|
277
|
+
for (const run of this._runs) {
|
|
278
|
+
const runOffset = { x: this.range.high.x, y: 0 };
|
|
279
|
+
run.offsetFromLine = runOffset;
|
|
280
|
+
const runLayoutRange = run.range.cloneTranslated(runOffset);
|
|
281
|
+
this.range.extendRange(runLayoutRange);
|
|
282
|
+
if ("linebreak" !== run.source.type) {
|
|
283
|
+
const runJustificationRange = run.justificationRange?.cloneTranslated(runOffset);
|
|
284
|
+
this.justificationRange.extendRange(runJustificationRange ?? runLayoutRange);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
exports.LineLayout = LineLayout;
|
|
290
|
+
/**
|
|
291
|
+
* Describes the layout of a text block as a collection of lines containing runs.
|
|
292
|
+
* @internal
|
|
293
|
+
*/
|
|
294
|
+
class TextBlockLayout {
|
|
295
|
+
constructor(source, context) {
|
|
296
|
+
this.range = new core_geometry_1.Range2d();
|
|
297
|
+
this.lines = [];
|
|
298
|
+
this.source = source;
|
|
299
|
+
this.populateLines(context);
|
|
300
|
+
this.justifyLines();
|
|
301
|
+
}
|
|
302
|
+
get _back() {
|
|
303
|
+
(0, core_bentley_1.assert)(this.lines.length > 0);
|
|
304
|
+
return this.lines[this.lines.length - 1];
|
|
305
|
+
}
|
|
306
|
+
populateLines(context) {
|
|
307
|
+
const doc = this.source;
|
|
308
|
+
if (doc.paragraphs.length === 0) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const isWrapped = doc.width > 0;
|
|
312
|
+
let line = new LineLayout(doc.paragraphs[0]);
|
|
313
|
+
for (let i = 0; i < doc.paragraphs.length; i++) {
|
|
314
|
+
const paragraph = doc.paragraphs[i];
|
|
315
|
+
if (i > 0) {
|
|
316
|
+
line = this.flushLine(context, line, paragraph);
|
|
317
|
+
}
|
|
318
|
+
for (const run of paragraph.runs) {
|
|
319
|
+
let layoutRun = RunLayout.create(run, context);
|
|
320
|
+
// Line break? It always "fits" and causes us to flush the line.
|
|
321
|
+
if ("linebreak" === run.type) {
|
|
322
|
+
line.append(layoutRun);
|
|
323
|
+
line = this.flushLine(context, line);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const effectiveRunWidth = isWrapped ? layoutRun.range.xLength() : 0;
|
|
327
|
+
let effectiveRemainingWidth = isWrapped ? doc.width - line.range.xLength() : Number.MAX_VALUE;
|
|
328
|
+
// Do we fit (no wrapping or narrow enough)? Append and go around to the next run.
|
|
329
|
+
if (effectiveRunWidth < effectiveRemainingWidth) {
|
|
330
|
+
line.append(layoutRun);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
// Can't fit, but can't wrap? Force on the line if it's the first thing; otherwise flush and add to the next line.
|
|
334
|
+
let leftOver = layoutRun.wrap(effectiveRemainingWidth, line.runs.length === 0, context);
|
|
335
|
+
if (!leftOver) {
|
|
336
|
+
if (line.runs.length === 0) {
|
|
337
|
+
line.append(layoutRun);
|
|
338
|
+
line = this.flushLine(context, line);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
line = this.flushLine(context, line);
|
|
342
|
+
line.append(layoutRun);
|
|
343
|
+
}
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
// Otherwise, keep splitting the run into lines until the whole thing is appended.
|
|
347
|
+
do {
|
|
348
|
+
line.append(layoutRun);
|
|
349
|
+
line = this.flushLine(context, line);
|
|
350
|
+
effectiveRemainingWidth = doc.width;
|
|
351
|
+
layoutRun = leftOver;
|
|
352
|
+
} while (leftOver = layoutRun.wrap(effectiveRemainingWidth, line.runs.length === 0, context));
|
|
353
|
+
line.append(layoutRun);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (line.runs.length > 0) {
|
|
357
|
+
this.flushLine(context, line);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
justifyLines() {
|
|
361
|
+
if (this.lines.length <= 1 || "left" === this.source.justification) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
let docWidth = this.source.width;
|
|
365
|
+
if (docWidth <= 0) {
|
|
366
|
+
for (const line of this.lines) {
|
|
367
|
+
const lineWidth = line.justificationRange.xLength();
|
|
368
|
+
docWidth = Math.max(docWidth, lineWidth);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
let minOffset = Number.MAX_VALUE;
|
|
372
|
+
for (const line of this.lines) {
|
|
373
|
+
const lineWidth = line.justificationRange.xLength();
|
|
374
|
+
let offset = docWidth - lineWidth;
|
|
375
|
+
if ("center" === this.source.justification) {
|
|
376
|
+
offset = offset / 2;
|
|
377
|
+
}
|
|
378
|
+
line.offsetFromDocument.x += offset;
|
|
379
|
+
minOffset = Math.min(offset, minOffset);
|
|
380
|
+
}
|
|
381
|
+
this.range.low.x += minOffset;
|
|
382
|
+
this.range.high.x += minOffset;
|
|
383
|
+
}
|
|
384
|
+
flushLine(context, line, nextParagraph) {
|
|
385
|
+
nextParagraph = nextParagraph ?? line.source;
|
|
386
|
+
// We want to guarantee that each layout line has at least one run.
|
|
387
|
+
if (line.runs.length === 0) {
|
|
388
|
+
// If we're empty, there should always be a preceding run, and it should be a line break.
|
|
389
|
+
if (this.lines.length === 0 || this._back.runs.length === 0) {
|
|
390
|
+
return new LineLayout(nextParagraph);
|
|
391
|
+
}
|
|
392
|
+
const prevRun = this._back.back.source;
|
|
393
|
+
(0, core_bentley_1.assert)(prevRun.type === "linebreak");
|
|
394
|
+
if (prevRun.type !== "linebreak") {
|
|
395
|
+
return new LineLayout(nextParagraph);
|
|
396
|
+
}
|
|
397
|
+
line.append(RunLayout.create(prevRun.clone(), context));
|
|
398
|
+
}
|
|
399
|
+
// Line origin is its baseline.
|
|
400
|
+
const lineOffset = { x: 0, y: -line.range.yLength() };
|
|
401
|
+
// Place it below any existing lines
|
|
402
|
+
if (this.lines.length > 0) {
|
|
403
|
+
lineOffset.y += this._back.offsetFromDocument.y;
|
|
404
|
+
lineOffset.y -= context.blockSettings.lineSpacingFactor * context.blockSettings.lineHeight;
|
|
405
|
+
}
|
|
406
|
+
line.offsetFromDocument = lineOffset;
|
|
407
|
+
// Update document range from computed line range and position
|
|
408
|
+
this.range.extendRange(line.range.cloneTranslated(lineOffset));
|
|
409
|
+
this.lines.push(line);
|
|
410
|
+
return new LineLayout(nextParagraph);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
exports.TextBlockLayout = TextBlockLayout;
|
|
414
|
+
//# sourceMappingURL=TextAnnotationLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TextAnnotationLayout.js","sourceRoot":"","sources":["../../src/TextAnnotationLayout.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module ElementGeometry\r\n */\r\n\r\nimport { BaselineShift, FontId, FractionRun, Paragraph, Run, TextBlock, TextRun, TextStyleSettings, TextStyleSettingsProps } from \"@itwin/core-common\";\r\nimport { Range2d, XAndY } from \"@itwin/core-geometry\";\r\nimport { IModelDb } from \"./IModelDb\";\r\nimport { assert, NonFunctionPropertiesOf } from \"@itwin/core-bentley\";\r\n\r\n/** @internal */\r\nexport interface TextLayoutRanges {\r\n layout: Range2d;\r\n justification: Range2d;\r\n}\r\n\r\n/** Arguments to [[ComputeRangesForTextLayout]].\r\n * @internal\r\n */\r\nexport interface ComputeRangesForTextLayoutArgs {\r\n chars: string;\r\n bold: boolean;\r\n italic: boolean;\r\n baselineShift: BaselineShift;\r\n fontId: FontId;\r\n widthFactor: number;\r\n lineHeight: number;\r\n}\r\n\r\n/** A function that uses a font to compute the layout and justification ranges of a string of text.\r\n * @internal\r\n */\r\nexport type ComputeRangesForTextLayout = (args: ComputeRangesForTextLayoutArgs) => TextLayoutRanges;\r\n\r\n/** @internal */\r\nexport type FindFontId = (name: string) => FontId;\r\n\r\n/** @internal */\r\nexport type FindTextStyle = (name: string) => TextStyleSettings;\r\n\r\n/** Arguments supplied to [[computeTextBlockExtents]].\r\n * @beta\r\n */\r\nexport interface ComputeTextBlockExtentsArgs {\r\n /** The text block whose extents are to be computed. */\r\n textBlock: TextBlock;\r\n /** The iModel from which to obtain fonts and [TextStyle]($common)s when laying out glyphs. */\r\n iModel: IModelDb;\r\n}\r\n\r\n/** @internal */\r\nexport interface LayoutTextBlockArgs extends ComputeTextBlockExtentsArgs {\r\n /** @internal chiefly for tests, by default uses IModelJsNative.DgnDb.computeRangesForText. */\r\n computeTextRange?: ComputeRangesForTextLayout;\r\n /** @internal chiefly for tests, by default looks up styles from a workspace. */\r\n findTextStyle?: FindTextStyle;\r\n /** @internal chiefly for tests, by default uses IModelDb.fontMap. */\r\n findFontId?: FindFontId;\r\n}\r\n\r\n/**\r\n * Lays out the contents of a TextBlock into a series of lines containing runs.\r\n * Each paragraph is decomposed into a series of lines.\r\n * Each series of consecutive non-linebreak runs within a paragraph is concatenated into one line.\r\n * If the document specifies a width > 0, individual lines are split to try to avoid exceeding that width.\r\n * Individual TextRuns can be split onto multiple lines at word boundaries if necessary. Individual FractionRuns are never split.\r\n * @internal\r\n */\r\nexport function layoutTextBlock(args: LayoutTextBlockArgs): TextBlockLayout {\r\n const findFontId = args.findFontId ?? ((name) => args.iModel.fontMap.getFont(name)?.id ?? 0);\r\n const computeTextRange = args.computeTextRange ?? ((x) => args.iModel.computeRangesForText(x));\r\n\r\n // ###TODO finding text styles in workspaces.\r\n const findTextStyle = args.findTextStyle ?? (() => TextStyleSettings.fromJSON());\r\n\r\n return new TextBlockLayout(args.textBlock, new LayoutContext(args.textBlock, computeTextRange, findTextStyle, findFontId));\r\n}\r\n\r\n/** Compute the bounding box containing the contents of a [TextBlock]($common).\r\n * This process converts each [Paragraph]($common) into a set of lines of text, laying out the glyphs of individual\r\n * [Run]($common)s based on their [TextStyle]($common)s and fonts, and applying work-wrapping based on [TextBlock.width]($common).\r\n * The resultant extents can be supplied to [TextAnnotation.computeTransform]($common) and [TextAnnotation.computeAnchorPoint]($common).\r\n * @beta\r\n */\r\nexport function computeTextBlockExtents(args: ComputeTextBlockExtentsArgs): XAndY {\r\n const range = layoutTextBlock(args).range;\r\n assert(range.low.isZero);\r\n return { x: range.high.x, y: range.high.y };\r\n}\r\n\r\nfunction scaleRange(range: Range2d, scale: number): void {\r\n range.low.scaleInPlace(scale);\r\n range.high.scaleInPlace(scale);\r\n}\r\n\r\nfunction applyBlockSettings(target: TextStyleSettings, source: TextStyleSettings | TextStyleSettingsProps): TextStyleSettings {\r\n if (source === target) {\r\n return target;\r\n }\r\n\r\n const lineSpacingFactor = source.lineSpacingFactor ?? target.lineSpacingFactor;\r\n const lineHeight = source.lineHeight ?? target.lineHeight;\r\n const widthFactor = source.widthFactor ?? target.widthFactor;\r\n\r\n if (lineSpacingFactor !== target.lineSpacingFactor || lineHeight !== target.lineHeight || widthFactor !== target.widthFactor) {\r\n target = target.clone({ lineSpacingFactor, lineHeight, widthFactor });\r\n }\r\n\r\n return target;\r\n}\r\n\r\nclass LayoutContext {\r\n private readonly _textStyles = new Map<string, TextStyleSettings>();\r\n private readonly _fontIds = new Map<string, FontId>();\r\n public readonly blockSettings: TextStyleSettings;\r\n\r\n public constructor(block: TextBlock, private readonly _computeTextRange: ComputeRangesForTextLayout, private readonly _findTextStyle: FindTextStyle, private readonly _findFontId: FindFontId) {\r\n const settings = this.findTextStyle(block.styleName);\r\n this.blockSettings = applyBlockSettings(settings, block.styleOverrides);\r\n }\r\n\r\n public findFontId(name: string): FontId {\r\n let fontId = this._fontIds.get(name);\r\n if (undefined === fontId) {\r\n this._fontIds.set(name, fontId = this._findFontId(name));\r\n }\r\n\r\n return fontId;\r\n }\r\n\r\n public findTextStyle(name: string): TextStyleSettings {\r\n let style = this._textStyles.get(name);\r\n if (undefined === style) {\r\n this._textStyles.set(name, style = this._findTextStyle(name));\r\n }\r\n\r\n return style;\r\n }\r\n\r\n public createRunSettings(run: Run): TextStyleSettings {\r\n let settings = this.findTextStyle(run.styleName);\r\n if (run.overridesStyle) {\r\n settings = settings.clone(run.styleOverrides);\r\n }\r\n\r\n return applyBlockSettings(settings, this.blockSettings);\r\n }\r\n\r\n public computeRangeForText(chars: string, style: TextStyleSettings, baselineShift: BaselineShift): TextLayoutRanges {\r\n if (chars.length === 0) {\r\n return {\r\n layout: new Range2d(0, 0, 0, style.lineHeight),\r\n justification: new Range2d(),\r\n };\r\n }\r\n\r\n const fontId = this.findFontId(style.fontName);\r\n const { layout, justification } = this._computeTextRange({\r\n chars,\r\n fontId,\r\n baselineShift,\r\n bold: style.isBold,\r\n italic: style.isItalic,\r\n lineHeight: this.blockSettings.lineHeight,\r\n widthFactor: this.blockSettings.widthFactor,\r\n });\r\n\r\n if (\"none\" !== baselineShift) {\r\n const isSub = \"subscript\" === baselineShift;\r\n const scale = isSub ? style.subScriptScale : style.superScriptScale;\r\n const offsetFactor = isSub ? style.subScriptOffsetFactor : style.superScriptOffsetFactor;\r\n const offset = { x: 0, y: style.lineHeight * offsetFactor };\r\n\r\n scaleRange(layout, scale);\r\n layout.cloneTranslated(offset, layout);\r\n\r\n scaleRange(justification, scale);\r\n justification.cloneTranslated(offset, justification);\r\n }\r\n\r\n return { layout, justification };\r\n }\r\n\r\n public computeRangeForTextRun(style: TextStyleSettings, run: TextRun, charOffset: number, numChars: number): TextLayoutRanges {\r\n return this.computeRangeForText(run.content.substring(charOffset, charOffset + numChars), style, run.baselineShift);\r\n }\r\n\r\n public computeRangeForFractionRun(style: TextStyleSettings, source: FractionRun): { layout: Range2d, numerator: Range2d, denominator: Range2d } {\r\n const numerator = this.computeRangeForText(source.numerator, style, \"none\").layout;\r\n scaleRange(numerator, style.stackedFractionScale);\r\n\r\n const denominator = this.computeRangeForText(source.denominator, style, \"none\").layout;\r\n scaleRange(denominator, style.stackedFractionScale);\r\n\r\n const numLen = numerator.xLength();\r\n const denomLen = denominator.xLength();\r\n switch (style.stackedFractionType) {\r\n case \"horizontal\": {\r\n if (numLen > denomLen) {\r\n denominator.cloneTranslated({ x: (numLen - denomLen) / 2, y: 0 }, denominator);\r\n } else {\r\n numerator.cloneTranslated({ x: (denomLen - numLen) / 2, y: 0 }, numerator);\r\n }\r\n\r\n numerator.cloneTranslated({ x: 0, y: 1.5 * denominator.yLength() }, numerator);\r\n break;\r\n }\r\n case \"diagonal\": {\r\n numerator.cloneTranslated({ x: 0, y: denominator.yLength() }, numerator);\r\n denominator.cloneTranslated({ x: numLen, y: 0 }, denominator);\r\n break;\r\n }\r\n }\r\n\r\n const layout = numerator.clone();\r\n layout.extendRange(denominator);\r\n return { layout, numerator, denominator };\r\n }\r\n}\r\n\r\n/** @internal */\r\nexport class RunLayout {\r\n public source: Run;\r\n public charOffset: number;\r\n public numChars: number;\r\n public range: Range2d;\r\n public justificationRange?: Range2d;\r\n public denominatorRange?: Range2d;\r\n public numeratorRange?: Range2d;\r\n public offsetFromLine: { x: number, y: number };\r\n public style: TextStyleSettings;\r\n public fontId: FontId;\r\n\r\n private constructor(props: NonFunctionPropertiesOf<RunLayout>) {\r\n this.source = props.source;\r\n this.charOffset = props.charOffset;\r\n this.numChars = props.numChars;\r\n this.range = props.range;\r\n this.justificationRange = props.justificationRange;\r\n this.denominatorRange = props.denominatorRange;\r\n this.numeratorRange = props.numeratorRange;\r\n this.offsetFromLine = props.offsetFromLine;\r\n this.style = props.style;\r\n this.fontId = props.fontId;\r\n }\r\n\r\n public static create(source: Run, context: LayoutContext): RunLayout {\r\n const style = context.createRunSettings(source);\r\n const fontId = context.findFontId(style.fontName);\r\n const charOffset = 0;\r\n const offsetFromLine = { x: 0, y: 0 };\r\n let numChars = 0;\r\n\r\n let range, justificationRange, numeratorRange, denominatorRange;\r\n\r\n switch (source.type) {\r\n case \"text\": {\r\n numChars = source.content.length;\r\n const ranges = context.computeRangeForTextRun(style, source, charOffset, numChars);\r\n range = ranges.layout;\r\n justificationRange = ranges.justification;\r\n break;\r\n }\r\n case \"fraction\": {\r\n numChars = 1;\r\n const ranges = context.computeRangeForFractionRun(style, source);\r\n range = ranges.layout;\r\n numeratorRange = ranges.numerator;\r\n denominatorRange = ranges.denominator;\r\n break;\r\n }\r\n default: {\r\n // We do this so that blank lines space correctly without special casing later.\r\n range = new Range2d(0, 0, 0, style.lineHeight);\r\n break;\r\n }\r\n }\r\n\r\n return new RunLayout({ source, charOffset, numChars, range, justificationRange, denominatorRange, numeratorRange, offsetFromLine, style, fontId });\r\n }\r\n\r\n public canWrap(): this is { source: TextRun } {\r\n return this.source.type === \"text\";\r\n }\r\n\r\n private cloneForWrap(args: { ranges: TextLayoutRanges, charOffset: number, numChars: number}): RunLayout {\r\n assert(this.canWrap());\r\n\r\n return new RunLayout({\r\n ...this,\r\n charOffset: args.charOffset,\r\n numChars: args.numChars,\r\n range: args.ranges.layout,\r\n justificationRange: args.ranges.justification,\r\n offsetFromLine: { ...this.offsetFromLine },\r\n });\r\n }\r\n\r\n public wrap(availableWidth: number, shouldForceLeadingUnit: boolean, context: LayoutContext): RunLayout | undefined {\r\n if (!this.canWrap()) {\r\n return undefined;\r\n }\r\n\r\n // An optimization that tracks the computed width so far so we don't have to repeatedly recompute preceding character ranges.\r\n // Assumes (to the best of Jeff's knowledge) that characters before a break point can't affect the shaping of subsequent characters.\r\n let runningWidth = 0;\r\n let breakPos = 0;\r\n\r\n // ###TODO TypeScript only provides type declarations for Intl.Segmenter if targeting ES2022+.\r\n // But doing so causes inexplicable issues with initialization of Model.modeledElement.\r\n // So until that's resolved, access it via cast to any.\r\n const segmenter = new (global as any).Intl.Segmenter(undefined, { granularity: \"word\" });\r\n const myText = this.source.content.substring(this.charOffset, this.charOffset + this.numChars);\r\n if (myText.length === 0) {\r\n return undefined;\r\n }\r\n\r\n for (const segment of segmenter.segment(myText)) {\r\n const testContent = segment.segment;\r\n const forceCurrentUnit = shouldForceLeadingUnit && (0 === breakPos);\r\n\r\n // If we don't fit, the previous break position is the split point.\r\n const ranges = context.computeRangeForText(testContent, this.style, this.source.baselineShift);\r\n if (!forceCurrentUnit && (runningWidth + ranges.justification.xLength()) > availableWidth) {\r\n break;\r\n }\r\n\r\n // Otherwise, we fit; keep trying.\r\n runningWidth += ranges.layout.xLength();\r\n breakPos = segment.index + testContent.length;\r\n }\r\n\r\n // If the whole thing fits, we don't have to wrap (i.e., we just wasted a bunch of time).\r\n if (breakPos >= myText.length) {\r\n return undefined;\r\n }\r\n\r\n // Trim this run and return the remainder.\r\n const charOffset = this.charOffset + breakPos;\r\n const numChars = this.numChars - breakPos;\r\n this.numChars = breakPos;\r\n\r\n const leftover = this.source.content.substring(charOffset, charOffset + numChars);\r\n return this.cloneForWrap({\r\n ranges: context.computeRangeForText(leftover, this.style, this.source.baselineShift),\r\n charOffset,\r\n numChars,\r\n });\r\n }\r\n}\r\n\r\n/** @internal */\r\nexport class LineLayout {\r\n public source: Paragraph;\r\n public range = new Range2d(0, 0, 0, 0);\r\n public justificationRange = new Range2d(0, 0, 0, 0);\r\n public offsetFromDocument = { x: 0, y: 0 };\r\n private _runs: RunLayout[] = [];\r\n\r\n public constructor(source: Paragraph) {\r\n this.source = source;\r\n }\r\n\r\n public get runs(): ReadonlyArray<RunLayout> { return this._runs; }\r\n public get isEmpty() { return this._runs.length === 0; }\r\n public get back(): RunLayout {\r\n assert(!this.isEmpty);\r\n return this._runs[this._runs.length - 1];\r\n }\r\n\r\n public append(run: RunLayout): void {\r\n this._runs.push(run);\r\n this.computeRanges();\r\n }\r\n\r\n /** Invoked every time a run is appended,. */\r\n private computeRanges(): void {\r\n this.range.low.setZero();\r\n this.range.high.setZero();\r\n\r\n for (const run of this._runs) {\r\n const runOffset = { x: this.range.high.x, y: 0 };\r\n run.offsetFromLine = runOffset;\r\n\r\n const runLayoutRange = run.range.cloneTranslated(runOffset);\r\n this.range.extendRange(runLayoutRange);\r\n\r\n if (\"linebreak\" !== run.source.type) {\r\n const runJustificationRange = run.justificationRange?.cloneTranslated(runOffset);\r\n this.justificationRange.extendRange(runJustificationRange ?? runLayoutRange);\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Describes the layout of a text block as a collection of lines containing runs.\r\n * @internal\r\n */\r\nexport class TextBlockLayout {\r\n public source: TextBlock;\r\n public range = new Range2d();\r\n public lines: LineLayout[] = [];\r\n\r\n public constructor(source: TextBlock, context: LayoutContext) {\r\n this.source = source;\r\n\r\n this.populateLines(context);\r\n this.justifyLines();\r\n }\r\n\r\n private get _back(): LineLayout {\r\n assert(this.lines.length > 0);\r\n return this.lines[this.lines.length - 1];\r\n }\r\n\r\n private populateLines(context: LayoutContext): void {\r\n const doc = this.source;\r\n if (doc.paragraphs.length === 0) {\r\n return;\r\n }\r\n\r\n const isWrapped = doc.width > 0;\r\n\r\n let line = new LineLayout(doc.paragraphs[0]);\r\n for (let i = 0; i < doc.paragraphs.length; i++) {\r\n const paragraph = doc.paragraphs[i];\r\n if (i > 0) {\r\n line = this.flushLine(context, line, paragraph);\r\n }\r\n\r\n for (const run of paragraph.runs) {\r\n let layoutRun = RunLayout.create(run, context);\r\n\r\n // Line break? It always \"fits\" and causes us to flush the line.\r\n if (\"linebreak\" === run.type) {\r\n line.append(layoutRun);\r\n line = this.flushLine(context, line);\r\n continue;\r\n }\r\n\r\n const effectiveRunWidth = isWrapped ? layoutRun.range.xLength() : 0;\r\n let effectiveRemainingWidth = isWrapped ? doc.width - line.range.xLength() : Number.MAX_VALUE;\r\n\r\n // Do we fit (no wrapping or narrow enough)? Append and go around to the next run.\r\n if (effectiveRunWidth < effectiveRemainingWidth) {\r\n line.append(layoutRun);\r\n continue;\r\n }\r\n\r\n // Can't fit, but can't wrap? Force on the line if it's the first thing; otherwise flush and add to the next line.\r\n let leftOver = layoutRun.wrap(effectiveRemainingWidth, line.runs.length === 0, context);\r\n if (!leftOver) {\r\n if (line.runs.length === 0) {\r\n line.append(layoutRun);\r\n line = this.flushLine(context, line);\r\n } else {\r\n line = this.flushLine(context, line);\r\n line.append(layoutRun);\r\n }\r\n\r\n continue;\r\n }\r\n\r\n // Otherwise, keep splitting the run into lines until the whole thing is appended.\r\n do {\r\n line.append(layoutRun);\r\n line = this.flushLine(context, line);\r\n effectiveRemainingWidth = doc.width;\r\n layoutRun = leftOver;\r\n } while (leftOver = layoutRun.wrap(effectiveRemainingWidth, line.runs.length === 0, context));\r\n\r\n line.append(layoutRun);\r\n }\r\n }\r\n\r\n if (line.runs.length > 0) {\r\n this.flushLine(context, line);\r\n }\r\n }\r\n\r\n private justifyLines(): void {\r\n if (this.lines.length <= 1 || \"left\" === this.source.justification) {\r\n return;\r\n }\r\n\r\n let docWidth = this.source.width;\r\n if (docWidth <= 0) {\r\n for (const line of this.lines) {\r\n const lineWidth = line.justificationRange.xLength();\r\n docWidth = Math.max(docWidth, lineWidth);\r\n }\r\n }\r\n\r\n let minOffset = Number.MAX_VALUE;\r\n for (const line of this.lines) {\r\n const lineWidth = line.justificationRange.xLength();\r\n\r\n let offset = docWidth - lineWidth;\r\n if (\"center\" === this.source.justification) {\r\n offset = offset / 2;\r\n }\r\n\r\n line.offsetFromDocument.x += offset;\r\n minOffset = Math.min(offset, minOffset);\r\n }\r\n\r\n this.range.low.x += minOffset;\r\n this.range.high.x += minOffset;\r\n }\r\n\r\n private flushLine(context: LayoutContext, line: LineLayout, nextParagraph?: Paragraph): LineLayout {\r\n nextParagraph = nextParagraph ?? line.source;\r\n\r\n // We want to guarantee that each layout line has at least one run.\r\n if (line.runs.length === 0) {\r\n // If we're empty, there should always be a preceding run, and it should be a line break.\r\n if (this.lines.length === 0 || this._back.runs.length === 0) {\r\n return new LineLayout(nextParagraph);\r\n }\r\n\r\n const prevRun = this._back.back.source;\r\n assert(prevRun.type === \"linebreak\");\r\n if (prevRun.type !== \"linebreak\") {\r\n return new LineLayout(nextParagraph);\r\n }\r\n\r\n line.append(RunLayout.create(prevRun.clone(), context));\r\n }\r\n\r\n // Line origin is its baseline.\r\n const lineOffset = { x: 0, y: -line.range.yLength() };\r\n\r\n // Place it below any existing lines\r\n if (this.lines.length > 0) {\r\n lineOffset.y += this._back.offsetFromDocument.y;\r\n lineOffset.y -= context.blockSettings.lineSpacingFactor * context.blockSettings.lineHeight;\r\n }\r\n\r\n line.offsetFromDocument = lineOffset;\r\n\r\n // Update document range from computed line range and position\r\n this.range.extendRange(line.range.cloneTranslated(lineOffset));\r\n\r\n this.lines.push(line);\r\n return new LineLayout(nextParagraph);\r\n }\r\n}\r\n"]}
|