@xterm/xterm 5.6.0-beta.9 → 5.6.0-beta.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/css/xterm.css +71 -4
- package/lib/xterm.js +1 -1
- package/lib/xterm.js.map +1 -1
- package/lib/xterm.mjs +53 -0
- package/lib/xterm.mjs.map +7 -0
- package/package.json +43 -33
- package/src/browser/AccessibilityManager.ts +53 -25
- package/src/browser/{Terminal.ts → CoreBrowserTerminal.ts} +139 -148
- package/src/browser/Linkifier.ts +26 -14
- package/src/browser/LocalizableStrings.ts +15 -4
- package/src/browser/{Types.d.ts → Types.ts} +67 -15
- package/src/browser/Viewport.ts +143 -370
- package/src/browser/decorations/BufferDecorationRenderer.ts +14 -9
- package/src/browser/decorations/OverviewRulerRenderer.ts +40 -44
- package/src/browser/input/CompositionHelper.ts +2 -1
- package/src/browser/public/Terminal.ts +25 -19
- package/src/browser/renderer/dom/DomRenderer.ts +19 -14
- package/src/browser/renderer/dom/DomRendererRowFactory.ts +35 -15
- package/src/browser/renderer/shared/CharAtlasCache.ts +3 -2
- package/src/browser/renderer/shared/CharAtlasUtils.ts +6 -1
- package/src/browser/renderer/shared/CustomGlyphs.ts +6 -0
- package/src/browser/renderer/shared/DevicePixelObserver.ts +1 -2
- package/src/browser/renderer/shared/TextureAtlas.ts +45 -12
- package/src/browser/renderer/shared/{Types.d.ts → Types.ts} +7 -6
- package/src/browser/services/CharSizeService.ts +6 -6
- package/src/browser/services/CoreBrowserService.ts +15 -15
- package/src/browser/services/LinkProviderService.ts +2 -2
- package/src/browser/services/RenderService.ts +20 -20
- package/src/browser/services/SelectionService.ts +8 -8
- package/src/browser/services/Services.ts +13 -13
- package/src/browser/services/ThemeService.ts +19 -58
- package/src/browser/shared/Constants.ts +8 -0
- package/src/common/CircularList.ts +5 -5
- package/src/common/CoreTerminal.ts +35 -41
- package/src/common/InputHandler.ts +63 -51
- package/src/common/{Types.d.ts → Types.ts} +13 -17
- package/src/common/buffer/Buffer.ts +15 -7
- package/src/common/buffer/BufferReflow.ts +9 -6
- package/src/common/buffer/BufferSet.ts +5 -5
- package/src/common/buffer/Marker.ts +4 -4
- package/src/common/buffer/{Types.d.ts → Types.ts} +2 -2
- package/src/common/input/WriteBuffer.ts +3 -3
- package/src/common/parser/EscapeSequenceParser.ts +4 -4
- package/src/common/public/BufferNamespaceApi.ts +3 -3
- package/src/common/services/BufferService.ts +7 -7
- package/src/common/services/CoreMouseService.ts +5 -3
- package/src/common/services/CoreService.ts +8 -6
- package/src/common/services/DecorationService.ts +8 -9
- package/src/common/services/InstantiationService.ts +1 -1
- package/src/common/services/LogService.ts +2 -2
- package/src/common/services/OptionsService.ts +7 -6
- package/src/common/services/ServiceRegistry.ts +1 -1
- package/src/common/services/Services.ts +26 -17
- package/src/common/services/UnicodeService.ts +2 -2
- package/src/vs/base/browser/browser.ts +141 -0
- package/src/vs/base/browser/canIUse.ts +49 -0
- package/src/vs/base/browser/dom.ts +2369 -0
- package/src/vs/base/browser/fastDomNode.ts +316 -0
- package/src/vs/base/browser/globalPointerMoveMonitor.ts +112 -0
- package/src/vs/base/browser/iframe.ts +135 -0
- package/src/vs/base/browser/keyboardEvent.ts +213 -0
- package/src/vs/base/browser/mouseEvent.ts +229 -0
- package/src/vs/base/browser/touch.ts +372 -0
- package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +303 -0
- package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +114 -0
- package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +720 -0
- package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +165 -0
- package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +114 -0
- package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +243 -0
- package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +118 -0
- package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +116 -0
- package/src/vs/base/browser/ui/widget.ts +57 -0
- package/src/vs/base/browser/window.ts +14 -0
- package/src/vs/base/common/arrays.ts +887 -0
- package/src/vs/base/common/arraysFind.ts +202 -0
- package/src/vs/base/common/assert.ts +71 -0
- package/src/vs/base/common/async.ts +1992 -0
- package/src/vs/base/common/cancellation.ts +148 -0
- package/src/vs/base/common/charCode.ts +450 -0
- package/src/vs/base/common/collections.ts +140 -0
- package/src/vs/base/common/decorators.ts +130 -0
- package/src/vs/base/common/equals.ts +146 -0
- package/src/vs/base/common/errors.ts +303 -0
- package/src/vs/base/common/event.ts +1778 -0
- package/src/vs/base/common/functional.ts +32 -0
- package/src/vs/base/common/hash.ts +316 -0
- package/src/vs/base/common/iterator.ts +159 -0
- package/src/vs/base/common/keyCodes.ts +526 -0
- package/src/vs/base/common/keybindings.ts +284 -0
- package/src/vs/base/common/lazy.ts +47 -0
- package/src/vs/base/common/lifecycle.ts +801 -0
- package/src/vs/base/common/linkedList.ts +142 -0
- package/src/vs/base/common/map.ts +202 -0
- package/src/vs/base/common/numbers.ts +98 -0
- package/src/vs/base/common/observable.ts +76 -0
- package/src/vs/base/common/observableInternal/api.ts +31 -0
- package/src/vs/base/common/observableInternal/autorun.ts +281 -0
- package/src/vs/base/common/observableInternal/base.ts +489 -0
- package/src/vs/base/common/observableInternal/debugName.ts +145 -0
- package/src/vs/base/common/observableInternal/derived.ts +428 -0
- package/src/vs/base/common/observableInternal/lazyObservableValue.ts +146 -0
- package/src/vs/base/common/observableInternal/logging.ts +328 -0
- package/src/vs/base/common/observableInternal/promise.ts +209 -0
- package/src/vs/base/common/observableInternal/utils.ts +610 -0
- package/src/vs/base/common/platform.ts +281 -0
- package/src/vs/base/common/scrollable.ts +522 -0
- package/src/vs/base/common/sequence.ts +34 -0
- package/src/vs/base/common/stopwatch.ts +43 -0
- package/src/vs/base/common/strings.ts +557 -0
- package/src/vs/base/common/symbols.ts +9 -0
- package/src/vs/base/common/uint.ts +59 -0
- package/src/vs/patches/nls.ts +90 -0
- package/src/vs/typings/base-common.d.ts +20 -0
- package/src/vs/typings/require.d.ts +42 -0
- package/src/vs/typings/thenable.d.ts +12 -0
- package/src/vs/typings/vscode-globals-nls.d.ts +36 -0
- package/src/vs/typings/vscode-globals-product.d.ts +33 -0
- package/typings/xterm.d.ts +66 -15
- package/src/browser/Lifecycle.ts +0 -33
- package/src/common/EventEmitter.ts +0 -78
- package/src/common/Lifecycle.ts +0 -108
- /package/src/browser/selection/{Types.d.ts → Types.ts} +0 -0
- /package/src/common/parser/{Types.d.ts → Types.ts} +0 -0
|
@@ -4,10 +4,14 @@
|
|
|
4
4
|
*--------------------------------------------------------------------------------------------*/
|
|
5
5
|
|
|
6
6
|
import { ColorZoneStore, IColorZone, IColorZoneStore } from 'browser/decorations/ColorZoneStore';
|
|
7
|
-
import { ICoreBrowserService, IRenderService } from 'browser/services/Services';
|
|
8
|
-
import { Disposable, toDisposable } from 'common/
|
|
7
|
+
import { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
|
8
|
+
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
|
9
9
|
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
|
10
10
|
|
|
11
|
+
const enum Constants {
|
|
12
|
+
OVERVIEW_RULER_BORDER_WIDTH = 1
|
|
13
|
+
}
|
|
14
|
+
|
|
11
15
|
// Helper objects to avoid excessive calculation and garbage collection during rendering. These are
|
|
12
16
|
// static values for each render and can be accessed using the decoration position as the key.
|
|
13
17
|
const drawHeight = {
|
|
@@ -34,7 +38,7 @@ export class OverviewRulerRenderer extends Disposable {
|
|
|
34
38
|
private readonly _ctx: CanvasRenderingContext2D;
|
|
35
39
|
private readonly _colorZoneStore: IColorZoneStore = new ColorZoneStore();
|
|
36
40
|
private get _width(): number {
|
|
37
|
-
return this._optionsService.options.
|
|
41
|
+
return this._optionsService.options.overviewRuler?.width || 0;
|
|
38
42
|
}
|
|
39
43
|
private _animationFrame: number | undefined;
|
|
40
44
|
|
|
@@ -51,6 +55,7 @@ export class OverviewRulerRenderer extends Disposable {
|
|
|
51
55
|
@IDecorationService private readonly _decorationService: IDecorationService,
|
|
52
56
|
@IRenderService private readonly _renderService: IRenderService,
|
|
53
57
|
@IOptionsService private readonly _optionsService: IOptionsService,
|
|
58
|
+
@IThemeService private readonly _themeService: IThemeService,
|
|
54
59
|
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService
|
|
55
60
|
) {
|
|
56
61
|
super();
|
|
@@ -58,68 +63,47 @@ export class OverviewRulerRenderer extends Disposable {
|
|
|
58
63
|
this._canvas.classList.add('xterm-decoration-overview-ruler');
|
|
59
64
|
this._refreshCanvasDimensions();
|
|
60
65
|
this._viewportElement.parentElement?.insertBefore(this._canvas, this._viewportElement);
|
|
66
|
+
this._register(toDisposable(() => this._canvas?.remove()));
|
|
67
|
+
|
|
61
68
|
const ctx = this._canvas.getContext('2d');
|
|
62
69
|
if (!ctx) {
|
|
63
70
|
throw new Error('Ctx cannot be null');
|
|
64
71
|
} else {
|
|
65
72
|
this._ctx = ctx;
|
|
66
73
|
}
|
|
67
|
-
this._registerDecorationListeners();
|
|
68
|
-
this._registerBufferChangeListeners();
|
|
69
|
-
this._registerDimensionChangeListeners();
|
|
70
|
-
this.register(toDisposable(() => {
|
|
71
|
-
this._canvas?.remove();
|
|
72
|
-
}));
|
|
73
|
-
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
*/
|
|
78
|
-
private _registerDecorationListeners(): void {
|
|
79
|
-
this.register(this._decorationService.onDecorationRegistered(() => this._queueRefresh(undefined, true)));
|
|
80
|
-
this.register(this._decorationService.onDecorationRemoved(() => this._queueRefresh(undefined, true)));
|
|
81
|
-
}
|
|
75
|
+
this._register(this._decorationService.onDecorationRegistered(() => this._queueRefresh(undefined, true)));
|
|
76
|
+
this._register(this._decorationService.onDecorationRemoved(() => this._queueRefresh(undefined, true)));
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
* and hide the canvas if the alt buffer is active
|
|
86
|
-
*/
|
|
87
|
-
private _registerBufferChangeListeners(): void {
|
|
88
|
-
this.register(this._renderService.onRenderedViewportChange(() => this._queueRefresh()));
|
|
89
|
-
this.register(this._bufferService.buffers.onBufferActivate(() => {
|
|
78
|
+
this._register(this._renderService.onRenderedViewportChange(() => this._queueRefresh()));
|
|
79
|
+
this._register(this._bufferService.buffers.onBufferActivate(() => {
|
|
90
80
|
this._canvas!.style.display = this._bufferService.buffer === this._bufferService.buffers.alt ? 'none' : 'block';
|
|
91
81
|
}));
|
|
92
|
-
this.
|
|
82
|
+
this._register(this._bufferService.onScroll(() => {
|
|
93
83
|
if (this._lastKnownBufferLength !== this._bufferService.buffers.normal.lines.length) {
|
|
94
84
|
this._refreshDrawHeightConstants();
|
|
95
85
|
this._refreshColorZonePadding();
|
|
96
86
|
}
|
|
97
87
|
}));
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
* and then redraw
|
|
102
|
-
*/
|
|
103
|
-
private _registerDimensionChangeListeners(): void {
|
|
104
|
-
// container height changed
|
|
105
|
-
this.register(this._renderService.onRender((): void => {
|
|
88
|
+
|
|
89
|
+
// Container height changed
|
|
90
|
+
this._register(this._renderService.onRender((): void => {
|
|
106
91
|
if (!this._containerHeight || this._containerHeight !== this._screenElement.clientHeight) {
|
|
107
92
|
this._queueRefresh(true);
|
|
108
93
|
this._containerHeight = this._screenElement.clientHeight;
|
|
109
94
|
}
|
|
110
95
|
}));
|
|
111
|
-
|
|
112
|
-
this.
|
|
113
|
-
|
|
114
|
-
this.
|
|
115
|
-
// set the canvas dimensions
|
|
96
|
+
|
|
97
|
+
this._register(this._coreBrowserService.onDprChange(() => this._queueRefresh(true)));
|
|
98
|
+
this._register(this._optionsService.onSpecificOptionChange('overviewRuler', () => this._queueRefresh(true)));
|
|
99
|
+
this._register(this._themeService.onChangeColors(() => this._queueRefresh()));
|
|
116
100
|
this._queueRefresh(true);
|
|
117
101
|
}
|
|
118
102
|
|
|
119
103
|
private _refreshDrawConstants(): void {
|
|
120
104
|
// width
|
|
121
|
-
const outerWidth = Math.floor(this._canvas.width / 3);
|
|
122
|
-
const innerWidth = Math.ceil(this._canvas.width / 3);
|
|
105
|
+
const outerWidth = Math.floor((this._canvas.width - Constants.OVERVIEW_RULER_BORDER_WIDTH) / 3);
|
|
106
|
+
const innerWidth = Math.ceil((this._canvas.width - Constants.OVERVIEW_RULER_BORDER_WIDTH) / 3);
|
|
123
107
|
drawWidth.full = this._canvas.width;
|
|
124
108
|
drawWidth.left = outerWidth;
|
|
125
109
|
drawWidth.center = innerWidth;
|
|
@@ -127,10 +111,10 @@ export class OverviewRulerRenderer extends Disposable {
|
|
|
127
111
|
// height
|
|
128
112
|
this._refreshDrawHeightConstants();
|
|
129
113
|
// x
|
|
130
|
-
drawX.full =
|
|
131
|
-
drawX.left =
|
|
132
|
-
drawX.center = drawWidth.left;
|
|
133
|
-
drawX.right = drawWidth.left + drawWidth.center;
|
|
114
|
+
drawX.full = Constants.OVERVIEW_RULER_BORDER_WIDTH;
|
|
115
|
+
drawX.left = Constants.OVERVIEW_RULER_BORDER_WIDTH;
|
|
116
|
+
drawX.center = Constants.OVERVIEW_RULER_BORDER_WIDTH + drawWidth.left;
|
|
117
|
+
drawX.right = Constants.OVERVIEW_RULER_BORDER_WIDTH + drawWidth.left + drawWidth.center;
|
|
134
118
|
}
|
|
135
119
|
|
|
136
120
|
private _refreshDrawHeightConstants(): void {
|
|
@@ -173,6 +157,7 @@ export class OverviewRulerRenderer extends Disposable {
|
|
|
173
157
|
this._colorZoneStore.addDecoration(decoration);
|
|
174
158
|
}
|
|
175
159
|
this._ctx.lineWidth = 1;
|
|
160
|
+
this._renderRulerOutline();
|
|
176
161
|
const zones = this._colorZoneStore.zones;
|
|
177
162
|
for (const zone of zones) {
|
|
178
163
|
if (zone.position !== 'full') {
|
|
@@ -188,6 +173,17 @@ export class OverviewRulerRenderer extends Disposable {
|
|
|
188
173
|
this._shouldUpdateAnchor = false;
|
|
189
174
|
}
|
|
190
175
|
|
|
176
|
+
private _renderRulerOutline(): void {
|
|
177
|
+
this._ctx.fillStyle = this._themeService.colors.overviewRulerBorder.css;
|
|
178
|
+
this._ctx.fillRect(0, 0, Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.height);
|
|
179
|
+
if (this._optionsService.rawOptions.overviewRuler.showTopBorder) {
|
|
180
|
+
this._ctx.fillRect(Constants.OVERVIEW_RULER_BORDER_WIDTH, 0, this._canvas.width - Constants.OVERVIEW_RULER_BORDER_WIDTH, Constants.OVERVIEW_RULER_BORDER_WIDTH);
|
|
181
|
+
}
|
|
182
|
+
if (this._optionsService.rawOptions.overviewRuler.showBottomBorder) {
|
|
183
|
+
this._ctx.fillRect(Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.height - Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.width - Constants.OVERVIEW_RULER_BORDER_WIDTH, this._canvas.height);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
191
187
|
private _renderColorZone(zone: IColorZone): void {
|
|
192
188
|
this._ctx.fillStyle = zone.color;
|
|
193
189
|
this._ctx.fillRect(
|
|
@@ -93,7 +93,8 @@ export class CompositionHelper {
|
|
|
93
93
|
*/
|
|
94
94
|
public keydown(ev: KeyboardEvent): boolean {
|
|
95
95
|
if (this._isComposing || this._isSendingComposition) {
|
|
96
|
-
if (ev.keyCode === 229) {
|
|
96
|
+
if (ev.keyCode === 20 || ev.keyCode === 229) {
|
|
97
|
+
// 20 is CapsLock, 229 is Enter
|
|
97
98
|
// Continue composing if the keyCode is the "composition character"
|
|
98
99
|
return false;
|
|
99
100
|
}
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import * as Strings from 'browser/LocalizableStrings';
|
|
7
|
-
import {
|
|
7
|
+
import { CoreBrowserTerminal as TerminalCore } from 'browser/CoreBrowserTerminal';
|
|
8
8
|
import { IBufferRange, ITerminal } from 'browser/Types';
|
|
9
|
-
import {
|
|
10
|
-
import { Disposable } from 'common/Lifecycle';
|
|
9
|
+
import { Disposable } from 'vs/base/common/lifecycle';
|
|
11
10
|
import { ITerminalOptions } from 'common/Types';
|
|
12
11
|
import { AddonManager } from 'common/public/AddonManager';
|
|
13
12
|
import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi';
|
|
14
13
|
import { ParserApi } from 'common/public/ParserApi';
|
|
15
14
|
import { UnicodeApi } from 'common/public/UnicodeApi';
|
|
16
15
|
import { IBufferNamespace as IBufferNamespaceApi, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, ILocalizableStrings, IMarker, IModes, IParser, ITerminalAddon, Terminal as ITerminalApi, ITerminalInitOnlyOptions, IUnicodeHandling } from '@xterm/xterm';
|
|
16
|
+
import type { Event } from 'vs/base/common/event';
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* The set of options that only have an effect when set in the Terminal constructor.
|
|
@@ -32,8 +32,8 @@ export class Terminal extends Disposable implements ITerminalApi {
|
|
|
32
32
|
constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions) {
|
|
33
33
|
super();
|
|
34
34
|
|
|
35
|
-
this._core = this.
|
|
36
|
-
this._addonManager = this.
|
|
35
|
+
this._core = this._register(new TerminalCore(options));
|
|
36
|
+
this._addonManager = this._register(new AddonManager());
|
|
37
37
|
|
|
38
38
|
this._publicOptions = { ... this._core.options };
|
|
39
39
|
const getter = (propName: string): any => {
|
|
@@ -68,18 +68,18 @@ export class Terminal extends Disposable implements ITerminalApi {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
public get onBell():
|
|
72
|
-
public get onBinary():
|
|
73
|
-
public get onCursorMove():
|
|
74
|
-
public get onData():
|
|
75
|
-
public get onKey():
|
|
76
|
-
public get onLineFeed():
|
|
77
|
-
public get onRender():
|
|
78
|
-
public get onResize():
|
|
79
|
-
public get onScroll():
|
|
80
|
-
public get onSelectionChange():
|
|
81
|
-
public get onTitleChange():
|
|
82
|
-
public get onWriteParsed():
|
|
71
|
+
public get onBell(): Event<void> { return this._core.onBell; }
|
|
72
|
+
public get onBinary(): Event<string> { return this._core.onBinary; }
|
|
73
|
+
public get onCursorMove(): Event<void> { return this._core.onCursorMove; }
|
|
74
|
+
public get onData(): Event<string> { return this._core.onData; }
|
|
75
|
+
public get onKey(): Event<{ key: string, domEvent: KeyboardEvent }> { return this._core.onKey; }
|
|
76
|
+
public get onLineFeed(): Event<void> { return this._core.onLineFeed; }
|
|
77
|
+
public get onRender(): Event<{ start: number, end: number }> { return this._core.onRender; }
|
|
78
|
+
public get onResize(): Event<{ cols: number, rows: number }> { return this._core.onResize; }
|
|
79
|
+
public get onScroll(): Event<number> { return this._core.onScroll; }
|
|
80
|
+
public get onSelectionChange(): Event<void> { return this._core.onSelectionChange; }
|
|
81
|
+
public get onTitleChange(): Event<string> { return this._core.onTitleChange; }
|
|
82
|
+
public get onWriteParsed(): Event<void> { return this._core.onWriteParsed; }
|
|
83
83
|
|
|
84
84
|
public get element(): HTMLElement | undefined { return this._core.element; }
|
|
85
85
|
public get parser(): IParser {
|
|
@@ -97,7 +97,7 @@ export class Terminal extends Disposable implements ITerminalApi {
|
|
|
97
97
|
public get cols(): number { return this._core.cols; }
|
|
98
98
|
public get buffer(): IBufferNamespaceApi {
|
|
99
99
|
if (!this._buffer) {
|
|
100
|
-
this._buffer = this.
|
|
100
|
+
this._buffer = this._register(new BufferNamespaceApi(this._core));
|
|
101
101
|
}
|
|
102
102
|
return this._buffer;
|
|
103
103
|
}
|
|
@@ -247,7 +247,13 @@ export class Terminal extends Disposable implements ITerminalApi {
|
|
|
247
247
|
this._addonManager.loadAddon(this, addon);
|
|
248
248
|
}
|
|
249
249
|
public static get strings(): ILocalizableStrings {
|
|
250
|
-
|
|
250
|
+
// A wrapper is required here because esbuild prevents setting an `export let`
|
|
251
|
+
return {
|
|
252
|
+
get promptLabel(): string { return Strings.promptLabel.get(); },
|
|
253
|
+
set promptLabel(value: string) { Strings.promptLabel.set(value); },
|
|
254
|
+
get tooMuchOutput(): string { return Strings.tooMuchOutput.get(); },
|
|
255
|
+
set tooMuchOutput(value: string) { Strings.tooMuchOutput.set(value); }
|
|
256
|
+
};
|
|
251
257
|
}
|
|
252
258
|
|
|
253
259
|
private _verifyIntegers(...values: number[]): void {
|
|
@@ -12,9 +12,9 @@ import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ISelectionRenderMode
|
|
|
12
12
|
import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
|
13
13
|
import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from 'browser/Types';
|
|
14
14
|
import { color } from 'common/Color';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
|
16
|
+
import { IBufferService, ICoreService, IInstantiationService, IOptionsService } from 'common/services/Services';
|
|
17
|
+
import { Emitter } from 'vs/base/common/event';
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
|
|
@@ -27,9 +27,9 @@ const SELECTION_CLASS = 'xterm-selection';
|
|
|
27
27
|
let nextTerminalId = 1;
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
*
|
|
31
|
-
* particularly fast
|
|
32
|
-
*
|
|
30
|
+
* The standard renderer and fallback for when the webgl addon is slow. This is not meant to be
|
|
31
|
+
* particularly fast and will even lack some features such as custom glyphs, hoever this is more
|
|
32
|
+
* reliable as webgl may not work on some machines.
|
|
33
33
|
*/
|
|
34
34
|
export class DomRenderer extends Disposable implements IRenderer {
|
|
35
35
|
private _rowFactory: DomRendererRowFactory;
|
|
@@ -45,7 +45,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
45
45
|
|
|
46
46
|
public dimensions: IRenderDimensions;
|
|
47
47
|
|
|
48
|
-
public readonly onRequestRedraw = this.
|
|
48
|
+
public readonly onRequestRedraw = this._register(new Emitter<IRequestRedrawEvent>()).event;
|
|
49
49
|
|
|
50
50
|
constructor(
|
|
51
51
|
private readonly _terminal: ITerminal,
|
|
@@ -59,6 +59,7 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
59
59
|
@ICharSizeService private readonly _charSizeService: ICharSizeService,
|
|
60
60
|
@IOptionsService private readonly _optionsService: IOptionsService,
|
|
61
61
|
@IBufferService private readonly _bufferService: IBufferService,
|
|
62
|
+
@ICoreService private readonly _coreService: ICoreService,
|
|
62
63
|
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService,
|
|
63
64
|
@IThemeService private readonly _themeService: IThemeService
|
|
64
65
|
) {
|
|
@@ -74,9 +75,9 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
74
75
|
|
|
75
76
|
this.dimensions = createRenderDimensions();
|
|
76
77
|
this._updateDimensions();
|
|
77
|
-
this.
|
|
78
|
+
this._register(this._optionsService.onOptionChange(() => this._handleOptionsChanged()));
|
|
78
79
|
|
|
79
|
-
this.
|
|
80
|
+
this._register(this._themeService.onChangeColors(e => this._injectCss(e)));
|
|
80
81
|
this._injectCss(this._themeService.colors);
|
|
81
82
|
|
|
82
83
|
this._rowFactory = instantiationService.createInstance(DomRendererRowFactory, document);
|
|
@@ -85,10 +86,10 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
85
86
|
this._screenElement.appendChild(this._rowContainer);
|
|
86
87
|
this._screenElement.appendChild(this._selectionContainer);
|
|
87
88
|
|
|
88
|
-
this.
|
|
89
|
-
this.
|
|
89
|
+
this._register(this._linkifier2.onShowLinkUnderline(e => this._handleLinkHover(e)));
|
|
90
|
+
this._register(this._linkifier2.onHideLinkUnderline(e => this._handleLinkLeave(e)));
|
|
90
91
|
|
|
91
|
-
this.
|
|
92
|
+
this._register(toDisposable(() => {
|
|
92
93
|
this._element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass);
|
|
93
94
|
|
|
94
95
|
// Outside influences such as React unmounts may manipulate the DOM before our disposal.
|
|
@@ -161,6 +162,10 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
161
162
|
// Base CSS
|
|
162
163
|
let styles =
|
|
163
164
|
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +
|
|
165
|
+
// Disabling pointer events circumvents a browser behavior that prevents `click` events from
|
|
166
|
+
// being delivered if the target element is replaced during the click. This happened due to
|
|
167
|
+
// refresh() being called during the mousedown handler to start a selection.
|
|
168
|
+
` pointer-events: none;` +
|
|
164
169
|
` color: ${colors.foreground.css};` +
|
|
165
170
|
` font-family: ${this._optionsService.rawOptions.fontFamily};` +
|
|
166
171
|
` font-size: ${this._optionsService.rawOptions.fontSize}px;` +
|
|
@@ -437,8 +442,8 @@ export class DomRenderer extends Disposable implements IRenderer {
|
|
|
437
442
|
const buffer = this._bufferService.buffer;
|
|
438
443
|
const cursorAbsoluteY = buffer.ybase + buffer.y;
|
|
439
444
|
const cursorX = Math.min(buffer.x, this._bufferService.cols - 1);
|
|
440
|
-
const cursorBlink = this._optionsService.rawOptions.cursorBlink;
|
|
441
|
-
const cursorStyle = this._optionsService.rawOptions.cursorStyle;
|
|
445
|
+
const cursorBlink = this._coreService.decPrivateModes.cursorBlink ?? this._optionsService.rawOptions.cursorBlink;
|
|
446
|
+
const cursorStyle = this._coreService.decPrivateModes.cursorStyle ?? this._optionsService.rawOptions.cursorStyle;
|
|
442
447
|
const cursorInactiveStyle = this._optionsService.rawOptions.cursorInactiveStyle;
|
|
443
448
|
|
|
444
449
|
for (let y = start; y <= end; y++) {
|
|
@@ -84,6 +84,7 @@ export class DomRendererRowFactory {
|
|
|
84
84
|
let charElement: HTMLSpanElement | undefined;
|
|
85
85
|
let cellAmount = 0;
|
|
86
86
|
let text = '';
|
|
87
|
+
let i = 0;
|
|
87
88
|
let oldBg = 0;
|
|
88
89
|
let oldFg = 0;
|
|
89
90
|
let oldExt = 0;
|
|
@@ -91,6 +92,7 @@ export class DomRendererRowFactory {
|
|
|
91
92
|
let oldSpacing = 0;
|
|
92
93
|
let oldIsInSelection: boolean = false;
|
|
93
94
|
let spacing = 0;
|
|
95
|
+
let skipJoinedCheckUntilX = 0;
|
|
94
96
|
const classes: string[] = [];
|
|
95
97
|
|
|
96
98
|
const hasHover = linkStart !== -1 && linkEnd !== -1;
|
|
@@ -106,29 +108,46 @@ export class DomRendererRowFactory {
|
|
|
106
108
|
|
|
107
109
|
// If true, indicates that the current character(s) to draw were joined.
|
|
108
110
|
let isJoined = false;
|
|
111
|
+
|
|
112
|
+
// Indicates whether this cell is part of a joined range that should be ignored as it cannot
|
|
113
|
+
// be rendered entirely, like the selection state differs across the range.
|
|
114
|
+
let isValidJoinRange = (x >= skipJoinedCheckUntilX);
|
|
115
|
+
|
|
109
116
|
let lastCharX = x;
|
|
110
117
|
|
|
111
118
|
// Process any joined character ranges as needed. Because of how the
|
|
112
119
|
// ranges are produced, we know that they are valid for the characters
|
|
113
120
|
// and attributes of our input.
|
|
114
121
|
let cell = this._workCell;
|
|
115
|
-
if (joinedRanges.length > 0 && x === joinedRanges[0][0]) {
|
|
116
|
-
isJoined = true;
|
|
122
|
+
if (joinedRanges.length > 0 && x === joinedRanges[0][0] && isValidJoinRange) {
|
|
117
123
|
const range = joinedRanges.shift()!;
|
|
124
|
+
// If the ligature's selection state is not consistent, don't join it. This helps the
|
|
125
|
+
// selection render correctly regardless whether they should be joined.
|
|
126
|
+
const firstSelectionState = this._isCellInSelection(range[0], row);
|
|
127
|
+
for (i = range[0] + 1; i < range[1]; i++) {
|
|
128
|
+
isValidJoinRange &&= (firstSelectionState === this._isCellInSelection(i, row));
|
|
129
|
+
}
|
|
130
|
+
// Similarly, if the cursor is in the ligature, don't join it.
|
|
131
|
+
isValidJoinRange &&= !isCursorRow || cursorX < range[0] || cursorX >= range[1];
|
|
132
|
+
if (!isValidJoinRange) {
|
|
133
|
+
skipJoinedCheckUntilX = range[1];
|
|
134
|
+
} else {
|
|
135
|
+
isJoined = true;
|
|
136
|
+
|
|
137
|
+
// We already know the exact start and end column of the joined range,
|
|
138
|
+
// so we get the string and width representing it directly
|
|
139
|
+
cell = new JoinedCellData(
|
|
140
|
+
this._workCell,
|
|
141
|
+
lineData.translateToString(true, range[0], range[1]),
|
|
142
|
+
range[1] - range[0]
|
|
143
|
+
);
|
|
118
144
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
cell = new JoinedCellData(
|
|
122
|
-
this._workCell,
|
|
123
|
-
lineData.translateToString(true, range[0], range[1]),
|
|
124
|
-
range[1] - range[0]
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
// Skip over the cells occupied by this range in the loop
|
|
128
|
-
lastCharX = range[1] - 1;
|
|
145
|
+
// Skip over the cells occupied by this range in the loop
|
|
146
|
+
lastCharX = range[1] - 1;
|
|
129
147
|
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
// Recalculate width
|
|
149
|
+
width = cell.getWidth();
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
const isInSelection = this._isCellInSelection(x, row);
|
|
@@ -178,6 +197,7 @@ export class DomRendererRowFactory {
|
|
|
178
197
|
&& !isCursorCell
|
|
179
198
|
&& !isJoined
|
|
180
199
|
&& !isDecorated
|
|
200
|
+
&& isValidJoinRange
|
|
181
201
|
) {
|
|
182
202
|
// no span alterations, thus only account chars skipping all code below
|
|
183
203
|
if (cell.isInvisible()) {
|
|
@@ -435,7 +455,7 @@ export class DomRendererRowFactory {
|
|
|
435
455
|
}
|
|
436
456
|
|
|
437
457
|
// exclude conditions for cell merging - never merge these
|
|
438
|
-
if (!isCursorCell && !isJoined && !isDecorated) {
|
|
458
|
+
if (!isCursorCell && !isJoined && !isDecorated && isValidJoinRange) {
|
|
439
459
|
cellAmount++;
|
|
440
460
|
} else {
|
|
441
461
|
charElement.textContent = text;
|
|
@@ -31,9 +31,10 @@ export function acquireTextureAtlas(
|
|
|
31
31
|
deviceCellHeight: number,
|
|
32
32
|
deviceCharWidth: number,
|
|
33
33
|
deviceCharHeight: number,
|
|
34
|
-
devicePixelRatio: number
|
|
34
|
+
devicePixelRatio: number,
|
|
35
|
+
deviceMaxTextureSize: number
|
|
35
36
|
): ITextureAtlas {
|
|
36
|
-
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio);
|
|
37
|
+
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio, deviceMaxTextureSize);
|
|
37
38
|
|
|
38
39
|
// Check to see if the terminal already owns this config
|
|
39
40
|
for (let i = 0; i < charAtlasCache.length; i++) {
|
|
@@ -9,7 +9,7 @@ import { ITerminalOptions } from '@xterm/xterm';
|
|
|
9
9
|
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
|
|
10
10
|
import { NULL_COLOR } from 'common/Color';
|
|
11
11
|
|
|
12
|
-
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig {
|
|
12
|
+
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number): ICharAtlasConfig {
|
|
13
13
|
// null out some fields that don't matter
|
|
14
14
|
const clonedColors: IColorSet = {
|
|
15
15
|
foreground: colors.foreground,
|
|
@@ -21,6 +21,10 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number
|
|
|
21
21
|
selectionBackgroundOpaque: NULL_COLOR,
|
|
22
22
|
selectionInactiveBackgroundTransparent: NULL_COLOR,
|
|
23
23
|
selectionInactiveBackgroundOpaque: NULL_COLOR,
|
|
24
|
+
overviewRulerBorder: NULL_COLOR,
|
|
25
|
+
scrollbarSliderBackground: NULL_COLOR,
|
|
26
|
+
scrollbarSliderHoverBackground: NULL_COLOR,
|
|
27
|
+
scrollbarSliderActiveBackground: NULL_COLOR,
|
|
24
28
|
// For the static char atlas, we only use the first 16 colors, but we need all 256 for the
|
|
25
29
|
// dynamic character atlas.
|
|
26
30
|
ansi: colors.ansi.slice(),
|
|
@@ -30,6 +34,7 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number
|
|
|
30
34
|
return {
|
|
31
35
|
customGlyphs: options.customGlyphs,
|
|
32
36
|
devicePixelRatio,
|
|
37
|
+
deviceMaxTextureSize,
|
|
33
38
|
letterSpacing: options.letterSpacing,
|
|
34
39
|
lineHeight: options.lineHeight,
|
|
35
40
|
deviceCellWidth: deviceCellWidth,
|
|
@@ -355,6 +355,12 @@ const enum VectorType {
|
|
|
355
355
|
* Original symbols defined in https://github.com/powerline/fontpatcher
|
|
356
356
|
*/
|
|
357
357
|
export const powerlineDefinitions: { [index: string]: IVectorShape } = {
|
|
358
|
+
// Git branch
|
|
359
|
+
'\u{E0A0}': { d: 'M.3,1 L.03,1 L.03,.88 C.03,.82,.06,.78,.11,.73 C.15,.7,.2,.68,.28,.65 L.43,.6 C.49,.58,.53,.56,.56,.53 C.59,.5,.6,.47,.6,.43 L.6,.27 L.4,.27 L.69,.1 L.98,.27 L.78,.27 L.78,.46 C.78,.52,.76,.56,.72,.61 C.68,.66,.63,.67,.56,.7 L.48,.72 C.42,.74,.38,.76,.35,.78 C.32,.8,.31,.84,.31,.88 L.31,1 M.3,.5 L.03,.59 L.03,.09 L.3,.09 L.3,.655', type: VectorType.FILL },
|
|
360
|
+
// L N
|
|
361
|
+
'\u{E0A1}': { d: 'M.7,.4 L.7,.47 L.2,.47 L.2,.03 L.355,.03 L.355,.4 L.705,.4 M.7,.5 L.86,.5 L.86,.95 L.69,.95 L.44,.66 L.46,.86 L.46,.95 L.3,.95 L.3,.49 L.46,.49 L.71,.78 L.69,.565 L.69,.5', type: VectorType.FILL },
|
|
362
|
+
// Lock
|
|
363
|
+
'\u{E0A2}': { d: 'M.25,.94 C.16,.94,.11,.92,.11,.87 L.11,.53 C.11,.48,.15,.455,.23,.45 L.23,.3 C.23,.25,.26,.22,.31,.19 C.36,.16,.43,.15,.51,.15 C.59,.15,.66,.16,.71,.19 C.77,.22,.79,.26,.79,.3 L.79,.45 C.87,.45,.91,.48,.91,.53 L.91,.87 C.91,.92,.86,.94,.77,.94 L.24,.94 M.53,.2 C.49,.2,.45,.21,.42,.23 C.39,.25,.38,.27,.38,.3 L.38,.45 L.68,.45 L.68,.3 C.68,.27,.67,.25,.64,.23 C.61,.21,.58,.2,.53,.2 M.58,.82 L.58,.66 C.63,.65,.65,.63,.65,.6 C.65,.58,.64,.57,.61,.56 C.58,.55,.56,.54,.52,.54 C.48,.54,.46,.55,.43,.56 C.4,.57,.39,.59,.39,.6 C.39,.63,.41,.64,.46,.66 L.46,.82 L.57,.82', type: VectorType.FILL },
|
|
358
364
|
// Right triangle solid
|
|
359
365
|
'\u{E0B0}': { d: 'M0,0 L1,.5 L0,1', type: VectorType.FILL, rightPadding: 2 },
|
|
360
366
|
// Right triangle line
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { toDisposable } from 'common/
|
|
7
|
-
import { IDisposable } from 'common/Types';
|
|
6
|
+
import { toDisposable, IDisposable } from 'vs/base/common/lifecycle';
|
|
8
7
|
|
|
9
8
|
export function observeDevicePixelDimensions(element: HTMLElement, parentWindow: Window & typeof globalThis, callback: (deviceWidth: number, deviceHeight: number) => void): IDisposable {
|
|
10
9
|
// Observe any resizes to the element and extract the actual pixel size of the element if the
|
|
@@ -9,13 +9,13 @@ import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs';
|
|
|
9
9
|
import { computeNextVariantOffset, treatGlyphAsBackgroundColor, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
|
10
10
|
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from 'browser/renderer/shared/Types';
|
|
11
11
|
import { NULL_COLOR, channels, color, rgba } from 'common/Color';
|
|
12
|
-
import { EventEmitter } from 'common/EventEmitter';
|
|
13
12
|
import { FourKeyMap } from 'common/MultiKeyMap';
|
|
14
13
|
import { IdleTaskQueue } from 'common/TaskQueue';
|
|
15
14
|
import { IColor } from 'common/Types';
|
|
16
15
|
import { AttributeData } from 'common/buffer/AttributeData';
|
|
17
16
|
import { Attributes, DEFAULT_COLOR, DEFAULT_EXT, UnderlineStyle } from 'common/buffer/Constants';
|
|
18
17
|
import { IUnicodeService } from 'common/services/Services';
|
|
18
|
+
import { Emitter } from 'vs/base/common/event';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* A shared object which is used to draw nothing for a particular cell.
|
|
@@ -66,6 +66,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
66
66
|
|
|
67
67
|
// The set of atlas pages that can be written to
|
|
68
68
|
private _activePages: AtlasPage[] = [];
|
|
69
|
+
private _overflowSizePage: AtlasPage | undefined;
|
|
69
70
|
|
|
70
71
|
private _tmpCanvas: HTMLCanvasElement;
|
|
71
72
|
// A temporary context that glyphs are drawn to before being transfered to the atlas.
|
|
@@ -79,9 +80,9 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
79
80
|
public static maxAtlasPages: number | undefined;
|
|
80
81
|
public static maxTextureSize: number | undefined;
|
|
81
82
|
|
|
82
|
-
private readonly _onAddTextureAtlasCanvas = new
|
|
83
|
+
private readonly _onAddTextureAtlasCanvas = new Emitter<HTMLCanvasElement>();
|
|
83
84
|
public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event;
|
|
84
|
-
private readonly _onRemoveTextureAtlasCanvas = new
|
|
85
|
+
private readonly _onRemoveTextureAtlasCanvas = new Emitter<HTMLCanvasElement>();
|
|
85
86
|
public readonly onRemoveTextureAtlasCanvas = this._onRemoveTextureAtlasCanvas.event;
|
|
86
87
|
|
|
87
88
|
constructor(
|
|
@@ -102,6 +103,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
public dispose(): void {
|
|
106
|
+
this._tmpCanvas.remove();
|
|
105
107
|
for (const page of this.pages) {
|
|
106
108
|
page.canvas.remove();
|
|
107
109
|
}
|
|
@@ -121,7 +123,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
121
123
|
for (let i = 33; i < 126; i++) {
|
|
122
124
|
queue.enqueue(() => {
|
|
123
125
|
if (!this._cacheMap.get(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT)) {
|
|
124
|
-
const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT);
|
|
126
|
+
const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT, false, undefined);
|
|
125
127
|
this._cacheMap.set(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT, rasterizedGlyph);
|
|
126
128
|
}
|
|
127
129
|
});
|
|
@@ -241,12 +243,12 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
241
243
|
}
|
|
242
244
|
}
|
|
243
245
|
|
|
244
|
-
public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean): IRasterizedGlyph {
|
|
245
|
-
return this._getFromCacheMap(this._cacheMapCombined, chars, bg, fg, ext, restrictToCellHeight);
|
|
246
|
+
public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph {
|
|
247
|
+
return this._getFromCacheMap(this._cacheMapCombined, chars, bg, fg, ext, restrictToCellHeight, domContainer);
|
|
246
248
|
}
|
|
247
249
|
|
|
248
|
-
public getRasterizedGlyph(code: number, bg: number, fg: number, ext: number, restrictToCellHeight: boolean): IRasterizedGlyph {
|
|
249
|
-
return this._getFromCacheMap(this._cacheMap, code, bg, fg, ext, restrictToCellHeight);
|
|
250
|
+
public getRasterizedGlyph(code: number, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph {
|
|
251
|
+
return this._getFromCacheMap(this._cacheMap, code, bg, fg, ext, restrictToCellHeight, domContainer);
|
|
250
252
|
}
|
|
251
253
|
|
|
252
254
|
/**
|
|
@@ -258,11 +260,12 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
258
260
|
bg: number,
|
|
259
261
|
fg: number,
|
|
260
262
|
ext: number,
|
|
261
|
-
restrictToCellHeight: boolean
|
|
263
|
+
restrictToCellHeight: boolean,
|
|
264
|
+
domContainer: HTMLElement | undefined
|
|
262
265
|
): IRasterizedGlyph {
|
|
263
266
|
$glyph = cacheMap.get(key, bg, fg, ext);
|
|
264
267
|
if (!$glyph) {
|
|
265
|
-
$glyph = this._drawToCache(key, bg, fg, ext, restrictToCellHeight);
|
|
268
|
+
$glyph = this._drawToCache(key, bg, fg, ext, restrictToCellHeight, domContainer);
|
|
266
269
|
cacheMap.set(key, bg, fg, ext, $glyph);
|
|
267
270
|
}
|
|
268
271
|
return $glyph;
|
|
@@ -422,16 +425,24 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
422
425
|
return this._config.colors.contrastCache;
|
|
423
426
|
}
|
|
424
427
|
|
|
425
|
-
private _drawToCache(codeOrChars: number | string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean
|
|
428
|
+
private _drawToCache(codeOrChars: number | string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean, domContainer: HTMLElement | undefined): IRasterizedGlyph {
|
|
426
429
|
const chars = typeof codeOrChars === 'number' ? String.fromCharCode(codeOrChars) : codeOrChars;
|
|
427
430
|
|
|
428
431
|
// Uncomment for debugging
|
|
429
432
|
// console.log(`draw to cache "${chars}"`, bg, fg, ext);
|
|
430
433
|
|
|
434
|
+
// Attach the canvas to the DOM in order to inherit font-feature-settings
|
|
435
|
+
// from the parent elements. This is necessary for ligatures and variants to
|
|
436
|
+
// work.
|
|
437
|
+
if (domContainer && this._tmpCanvas.parentElement !== domContainer) {
|
|
438
|
+
this._tmpCanvas.style.display = 'none';
|
|
439
|
+
domContainer.append(this._tmpCanvas);
|
|
440
|
+
}
|
|
441
|
+
|
|
431
442
|
// Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used
|
|
432
443
|
// to draw the glyph to the canvas as well as to restrict the bounding box search to ensure
|
|
433
444
|
// giant ligatures (eg. =====>) don't impact overall performance.
|
|
434
|
-
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this.
|
|
445
|
+
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._config.deviceMaxTextureSize);
|
|
435
446
|
if (this._tmpCanvas.width < allowedWidth) {
|
|
436
447
|
this._tmpCanvas.width = allowedWidth;
|
|
437
448
|
}
|
|
@@ -772,6 +783,27 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
772
783
|
}
|
|
773
784
|
}
|
|
774
785
|
|
|
786
|
+
// Create a new page for oversized glyphs as they come up
|
|
787
|
+
if (rasterizedGlyph.size.x > this._textureSize) {
|
|
788
|
+
if (!this._overflowSizePage) {
|
|
789
|
+
this._overflowSizePage = new AtlasPage(this._document, this._config.deviceMaxTextureSize);
|
|
790
|
+
this.pages.push(this._overflowSizePage);
|
|
791
|
+
|
|
792
|
+
// Request the model to be cleared to refresh all texture pages.
|
|
793
|
+
this._requestClearModel = true;
|
|
794
|
+
this._onAddTextureAtlasCanvas.fire(this._overflowSizePage.canvas);
|
|
795
|
+
}
|
|
796
|
+
activePage = this._overflowSizePage;
|
|
797
|
+
activeRow = this._overflowSizePage.currentRow;
|
|
798
|
+
// Move to next row if necessary
|
|
799
|
+
if (activeRow.x + rasterizedGlyph.size.x >= activePage.canvas.width) {
|
|
800
|
+
activeRow.x = 0;
|
|
801
|
+
activeRow.y += activeRow.height;
|
|
802
|
+
activeRow.height = 0;
|
|
803
|
+
}
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
|
|
775
807
|
// Create a new page if too much vertical space would be wasted or there is not enough room
|
|
776
808
|
// left in the page. The previous active row will become fixed in the process as it now has a
|
|
777
809
|
// fixed height
|
|
@@ -782,6 +814,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
782
814
|
if (activePage.currentRow.y + activePage.currentRow.height + rasterizedGlyph.size.y >= activePage.canvas.height) {
|
|
783
815
|
// Find the first page with room to create the new row on
|
|
784
816
|
let candidatePage: AtlasPage | undefined;
|
|
817
|
+
|
|
785
818
|
for (const p of this._activePages) {
|
|
786
819
|
if (p.currentRow.y + p.currentRow.height + rasterizedGlyph.size.y < p.canvas.height) {
|
|
787
820
|
candidatePage = p;
|