@xterm/addon-webgl 0.20.0-beta.9 → 0.20.0-beta.90
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/lib/addon-webgl.js +1 -1
- package/lib/addon-webgl.js.map +1 -1
- package/lib/addon-webgl.mjs +16 -16
- package/lib/addon-webgl.mjs.map +4 -4
- package/package.json +3 -3
- package/src/CharAtlasCache.ts +3 -2
- package/src/CharAtlasUtils.ts +2 -2
- package/src/CursorBlinkStateManager.ts +67 -8
- package/src/TextureAtlas.ts +58 -50
- package/src/WebglAddon.ts +8 -4
- package/src/WebglRenderer.ts +12 -2
- package/src/customGlyphs/CustomGlyphDefinitions.ts +411 -235
- package/src/customGlyphs/CustomGlyphRasterizer.ts +218 -157
- package/src/customGlyphs/Types.ts +39 -15
- package/typings/addon-webgl.d.ts +31 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xterm/addon-webgl",
|
|
3
|
-
"version": "0.20.0-beta.
|
|
3
|
+
"version": "0.20.0-beta.90",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "The xterm.js authors",
|
|
6
6
|
"url": "https://xtermjs.org/"
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"prepublishOnly": "npm run package",
|
|
24
24
|
"start": "node ../../demo/start"
|
|
25
25
|
},
|
|
26
|
-
"commit": "
|
|
26
|
+
"commit": "94a264679e6bd51b7021ca59e3b2e1e80d02c633",
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@xterm/xterm": "^6.1.0-beta.
|
|
28
|
+
"@xterm/xterm": "^6.1.0-beta.91"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/src/CharAtlasCache.ts
CHANGED
|
@@ -32,9 +32,10 @@ export function acquireTextureAtlas(
|
|
|
32
32
|
deviceCharWidth: number,
|
|
33
33
|
deviceCharHeight: number,
|
|
34
34
|
devicePixelRatio: number,
|
|
35
|
-
deviceMaxTextureSize: number
|
|
35
|
+
deviceMaxTextureSize: number,
|
|
36
|
+
customGlyphs: boolean = true
|
|
36
37
|
): ITextureAtlas {
|
|
37
|
-
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio, deviceMaxTextureSize);
|
|
38
|
+
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio, deviceMaxTextureSize, customGlyphs);
|
|
38
39
|
|
|
39
40
|
// Check to see if the terminal already owns this config
|
|
40
41
|
for (let i = 0; i < charAtlasCache.length; i++) {
|
package/src/CharAtlasUtils.ts
CHANGED
|
@@ -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, deviceMaxTextureSize: number): ICharAtlasConfig {
|
|
12
|
+
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number, customGlyphs: boolean = true): ICharAtlasConfig {
|
|
13
13
|
// null out some fields that don't matter
|
|
14
14
|
const clonedColors: IColorSet = {
|
|
15
15
|
foreground: colors.foreground,
|
|
@@ -32,7 +32,7 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number
|
|
|
32
32
|
halfContrastCache: colors.halfContrastCache
|
|
33
33
|
};
|
|
34
34
|
return {
|
|
35
|
-
customGlyphs
|
|
35
|
+
customGlyphs,
|
|
36
36
|
devicePixelRatio,
|
|
37
37
|
deviceMaxTextureSize,
|
|
38
38
|
letterSpacing: options.letterSpacing,
|
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
* @license MIT
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { RendererConstants } from 'browser/renderer/shared/Constants';
|
|
6
7
|
import { ICoreBrowserService } from 'browser/services/Services';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const enum Constants {
|
|
10
|
+
/**
|
|
11
|
+
* The time between cursor blinks.
|
|
12
|
+
*/
|
|
13
|
+
BLINK_INTERVAL = 600,
|
|
14
|
+
}
|
|
12
15
|
|
|
13
16
|
export class CursorBlinkStateManager {
|
|
14
17
|
public isCursorVisible: boolean;
|
|
@@ -16,6 +19,8 @@ export class CursorBlinkStateManager {
|
|
|
16
19
|
private _animationFrame: number | undefined;
|
|
17
20
|
private _blinkStartTimeout: number | undefined;
|
|
18
21
|
private _blinkInterval: number | undefined;
|
|
22
|
+
private _idleTimeout: number | undefined;
|
|
23
|
+
private _isIdlePaused: boolean = false;
|
|
19
24
|
|
|
20
25
|
/**
|
|
21
26
|
* The time at which the animation frame was restarted, this is used on the
|
|
@@ -31,6 +36,7 @@ export class CursorBlinkStateManager {
|
|
|
31
36
|
this.isCursorVisible = true;
|
|
32
37
|
if (this._coreBrowserService.isFocused) {
|
|
33
38
|
this._restartInterval();
|
|
39
|
+
this._resetIdleTimer();
|
|
34
40
|
}
|
|
35
41
|
}
|
|
36
42
|
|
|
@@ -49,9 +55,16 @@ export class CursorBlinkStateManager {
|
|
|
49
55
|
this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame);
|
|
50
56
|
this._animationFrame = undefined;
|
|
51
57
|
}
|
|
58
|
+
if (this._idleTimeout) {
|
|
59
|
+
this._coreBrowserService.window.clearTimeout(this._idleTimeout);
|
|
60
|
+
this._idleTimeout = undefined;
|
|
61
|
+
}
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
public restartBlinkAnimation(): void {
|
|
65
|
+
if (this._isIdlePaused) {
|
|
66
|
+
this._resetIdleTimer();
|
|
67
|
+
}
|
|
55
68
|
if (this.isPaused) {
|
|
56
69
|
return;
|
|
57
70
|
}
|
|
@@ -67,7 +80,7 @@ export class CursorBlinkStateManager {
|
|
|
67
80
|
}
|
|
68
81
|
}
|
|
69
82
|
|
|
70
|
-
private _restartInterval(timeToStart: number = BLINK_INTERVAL): void {
|
|
83
|
+
private _restartInterval(timeToStart: number = Constants.BLINK_INTERVAL): void {
|
|
71
84
|
// Clear any existing interval
|
|
72
85
|
if (this._blinkInterval) {
|
|
73
86
|
this._coreBrowserService.window.clearInterval(this._blinkInterval);
|
|
@@ -82,7 +95,7 @@ export class CursorBlinkStateManager {
|
|
|
82
95
|
// Check if another animation restart was requested while this was being
|
|
83
96
|
// started
|
|
84
97
|
if (this._animationTimeRestarted) {
|
|
85
|
-
const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted);
|
|
98
|
+
const time = Constants.BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted);
|
|
86
99
|
this._animationTimeRestarted = undefined;
|
|
87
100
|
if (time > 0) {
|
|
88
101
|
this._restartInterval(time);
|
|
@@ -103,7 +116,7 @@ export class CursorBlinkStateManager {
|
|
|
103
116
|
if (this._animationTimeRestarted) {
|
|
104
117
|
// calc time diff
|
|
105
118
|
// Make restart interval do a setTimeout initially?
|
|
106
|
-
const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted);
|
|
119
|
+
const time = Constants.BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted);
|
|
107
120
|
this._animationTimeRestarted = undefined;
|
|
108
121
|
this._restartInterval(time);
|
|
109
122
|
return;
|
|
@@ -115,12 +128,13 @@ export class CursorBlinkStateManager {
|
|
|
115
128
|
this._renderCallback();
|
|
116
129
|
this._animationFrame = undefined;
|
|
117
130
|
});
|
|
118
|
-
}, BLINK_INTERVAL);
|
|
131
|
+
}, Constants.BLINK_INTERVAL);
|
|
119
132
|
}, timeToStart);
|
|
120
133
|
}
|
|
121
134
|
|
|
122
135
|
public pause(): void {
|
|
123
136
|
this.isCursorVisible = true;
|
|
137
|
+
this._isIdlePaused = false;
|
|
124
138
|
if (this._blinkInterval) {
|
|
125
139
|
this._coreBrowserService.window.clearInterval(this._blinkInterval);
|
|
126
140
|
this._blinkInterval = undefined;
|
|
@@ -133,6 +147,10 @@ export class CursorBlinkStateManager {
|
|
|
133
147
|
this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame);
|
|
134
148
|
this._animationFrame = undefined;
|
|
135
149
|
}
|
|
150
|
+
if (this._idleTimeout) {
|
|
151
|
+
this._coreBrowserService.window.clearTimeout(this._idleTimeout);
|
|
152
|
+
this._idleTimeout = undefined;
|
|
153
|
+
}
|
|
136
154
|
}
|
|
137
155
|
|
|
138
156
|
public resume(): void {
|
|
@@ -141,6 +159,47 @@ export class CursorBlinkStateManager {
|
|
|
141
159
|
|
|
142
160
|
this._animationTimeRestarted = undefined;
|
|
143
161
|
this._restartInterval();
|
|
162
|
+
this._resetIdleTimer();
|
|
144
163
|
this.restartBlinkAnimation();
|
|
145
164
|
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Resets the idle timer. If the terminal is idle for the idle timeout period,
|
|
168
|
+
* the cursor blinking will stop.
|
|
169
|
+
*/
|
|
170
|
+
private _resetIdleTimer(): void {
|
|
171
|
+
this._isIdlePaused = false;
|
|
172
|
+
if (this._idleTimeout) {
|
|
173
|
+
this._coreBrowserService.window.clearTimeout(this._idleTimeout);
|
|
174
|
+
}
|
|
175
|
+
this._idleTimeout = this._coreBrowserService.window.setTimeout(() => {
|
|
176
|
+
this._stopBlinkingDueToIdle();
|
|
177
|
+
}, RendererConstants.CURSOR_BLINK_IDLE_TIMEOUT);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Stops cursor blinking due to idle timeout.
|
|
182
|
+
*/
|
|
183
|
+
private _stopBlinkingDueToIdle(): void {
|
|
184
|
+
// Make cursor visible and stop blinking
|
|
185
|
+
this.isCursorVisible = true;
|
|
186
|
+
this._isIdlePaused = true;
|
|
187
|
+
if (this._blinkInterval) {
|
|
188
|
+
this._coreBrowserService.window.clearInterval(this._blinkInterval);
|
|
189
|
+
this._blinkInterval = undefined;
|
|
190
|
+
}
|
|
191
|
+
if (this._blinkStartTimeout) {
|
|
192
|
+
this._coreBrowserService.window.clearTimeout(this._blinkStartTimeout);
|
|
193
|
+
this._blinkStartTimeout = undefined;
|
|
194
|
+
}
|
|
195
|
+
if (this._animationFrame) {
|
|
196
|
+
this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame);
|
|
197
|
+
this._animationFrame = undefined;
|
|
198
|
+
}
|
|
199
|
+
// Clear the idle timeout as we've already acted on it
|
|
200
|
+
this._coreBrowserService.window.clearTimeout(this._idleTimeout);
|
|
201
|
+
this._idleTimeout = undefined;
|
|
202
|
+
// Trigger a render to show the cursor in its final visible state
|
|
203
|
+
this._renderCallback();
|
|
204
|
+
}
|
|
146
205
|
}
|
package/src/TextureAtlas.ts
CHANGED
|
@@ -514,7 +514,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
514
514
|
// Draw custom characters if applicable
|
|
515
515
|
let customGlyph = false;
|
|
516
516
|
if (this._config.customGlyphs !== false) {
|
|
517
|
-
customGlyph = tryDrawCustomGlyph(this._tmpCtx, chars, padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight, this._config.fontSize, this._config.devicePixelRatio, backgroundColor.css);
|
|
517
|
+
customGlyph = tryDrawCustomGlyph(this._tmpCtx, chars, padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight, this._config.deviceCharWidth, this._config.deviceCharHeight, this._config.fontSize, this._config.devicePixelRatio, backgroundColor.css);
|
|
518
518
|
}
|
|
519
519
|
|
|
520
520
|
// Whether to clear pixels based on a threshold difference between the glyph color and the
|
|
@@ -551,61 +551,67 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
551
551
|
}
|
|
552
552
|
this._tmpCtx.strokeStyle = this._getColorFromAnsiIndex(fg).css;
|
|
553
553
|
}
|
|
554
|
+
this._tmpCtx.fillStyle = this._tmpCtx.strokeStyle;
|
|
554
555
|
|
|
555
556
|
// Underline style/stroke
|
|
556
557
|
this._tmpCtx.beginPath();
|
|
557
558
|
const xLeft = padding;
|
|
558
|
-
const
|
|
559
|
-
const
|
|
560
|
-
const yBot = yTop + lineWidth * 2;
|
|
559
|
+
const yTopDefault = Math.ceil(padding + this._config.deviceCharHeight) - yOffset - (restrictToCellHeight ? lineWidth * 2 : 0);
|
|
560
|
+
const yBotDefault = yTopDefault + lineWidth * 2;
|
|
561
561
|
let nextOffset = this._workAttributeData.getUnderlineVariantOffset();
|
|
562
|
+
let yTop = 0;
|
|
563
|
+
let yBot = 0;
|
|
562
564
|
|
|
563
565
|
for (let i = 0; i < chWidth; i++) {
|
|
566
|
+
let wasFilled = false;
|
|
564
567
|
this._tmpCtx.save();
|
|
568
|
+
yTop = yTopDefault;
|
|
569
|
+
yBot = yBotDefault;
|
|
565
570
|
const xChLeft = xLeft + i * this._config.deviceCellWidth;
|
|
566
571
|
const xChRight = xLeft + (i + 1) * this._config.deviceCellWidth;
|
|
567
|
-
const xChMid = xChLeft + this._config.deviceCellWidth / 2;
|
|
568
572
|
switch (this._workAttributeData.extended.underlineStyle) {
|
|
569
573
|
case UnderlineStyle.DOUBLE:
|
|
570
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
571
|
-
this._tmpCtx.lineTo(xChRight,
|
|
572
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
573
|
-
this._tmpCtx.lineTo(xChRight,
|
|
574
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
575
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
576
|
+
this._tmpCtx.moveTo(xChLeft, yBotDefault);
|
|
577
|
+
this._tmpCtx.lineTo(xChRight, yBotDefault);
|
|
574
578
|
break;
|
|
575
579
|
case UnderlineStyle.CURLY:
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const yCurlyTop = lineWidth <= 1 ? yTop : Math.ceil(padding + this._config.deviceCharHeight + lineWidth / 2) - yOffset;
|
|
580
|
-
// Clip the left and right edges of the underline such that it can be drawn just outside
|
|
581
|
-
// the edge of the cell to ensure a continuous stroke when there are multiple underlined
|
|
582
|
-
// glyphs adjacent to one another.
|
|
580
|
+
yTop = this._config.deviceCharHeight + 1;
|
|
581
|
+
yBot = yTop + 3 * this._config.devicePixelRatio;
|
|
582
|
+
|
|
583
583
|
const clipRegion = new Path2D();
|
|
584
584
|
clipRegion.rect(xChLeft, yTop, this._config.deviceCellWidth, yBot - yTop);
|
|
585
585
|
this._tmpCtx.clip(clipRegion);
|
|
586
|
-
|
|
587
|
-
//
|
|
588
|
-
|
|
589
|
-
this.
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
586
|
+
|
|
587
|
+
// Draw a zigzag pattern, this is derived from the SVG used in monaco for the same
|
|
588
|
+
// style. The viewbox is 6x3 so scale it using that.
|
|
589
|
+
const cellW = this._config.deviceCellWidth;
|
|
590
|
+
const curlyH = (yBot - yTop);
|
|
591
|
+
const scaleX = cellW / 6;
|
|
592
|
+
const scaleY = curlyH / 3;
|
|
593
|
+
|
|
594
|
+
const polygons: number[][] = [
|
|
595
|
+
[0, 2, 1, 3, 2.4, 3, 0, 0.6],
|
|
596
|
+
[5.5, 0, 2.5, 3, 1.1, 3, 4.1, 0],
|
|
597
|
+
[4, 0, 6, 2, 6, 0.6, 5.4, 0],
|
|
598
|
+
];
|
|
599
|
+
|
|
600
|
+
for (const polygon of polygons) {
|
|
601
|
+
this._tmpCtx.beginPath();
|
|
602
|
+
for (let i = 0; i < polygon.length; i += 2) {
|
|
603
|
+
const x = xChLeft + polygon[i] * scaleX;
|
|
604
|
+
const y = yBot - polygon[i + 1] * scaleY;
|
|
605
|
+
if (i === 0) {
|
|
606
|
+
this._tmpCtx.moveTo(x, y);
|
|
607
|
+
} else {
|
|
608
|
+
this._tmpCtx.lineTo(x, y);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
this._tmpCtx.closePath();
|
|
612
|
+
this._tmpCtx.fill();
|
|
613
|
+
}
|
|
614
|
+
wasFilled = true;
|
|
609
615
|
break;
|
|
610
616
|
case UnderlineStyle.DOTTED:
|
|
611
617
|
const offsetWidth = nextOffset === 0 ? 0 :
|
|
@@ -614,14 +620,14 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
614
620
|
const isLineStart = nextOffset >= lineWidth ? false : true;
|
|
615
621
|
if (isLineStart === false || offsetWidth === 0) {
|
|
616
622
|
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
|
|
617
|
-
this._tmpCtx.moveTo(xChLeft + offsetWidth,
|
|
618
|
-
this._tmpCtx.lineTo(xChRight,
|
|
623
|
+
this._tmpCtx.moveTo(xChLeft + offsetWidth, yTopDefault);
|
|
624
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
619
625
|
} else {
|
|
620
626
|
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
|
|
621
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
622
|
-
this._tmpCtx.lineTo(xChLeft + offsetWidth,
|
|
623
|
-
this._tmpCtx.moveTo(xChLeft + offsetWidth + lineWidth,
|
|
624
|
-
this._tmpCtx.lineTo(xChRight,
|
|
627
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
628
|
+
this._tmpCtx.lineTo(xChLeft + offsetWidth, yTopDefault);
|
|
629
|
+
this._tmpCtx.moveTo(xChLeft + offsetWidth + lineWidth, yTopDefault);
|
|
630
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
625
631
|
}
|
|
626
632
|
nextOffset = computeNextVariantOffset(xChRight - xChLeft, lineWidth, nextOffset);
|
|
627
633
|
break;
|
|
@@ -634,16 +640,18 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
634
640
|
const gap = Math.floor(gapRatio * xChWidth);
|
|
635
641
|
const end = xChWidth - line - gap;
|
|
636
642
|
this._tmpCtx.setLineDash([line, gap, end]);
|
|
637
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
638
|
-
this._tmpCtx.lineTo(xChRight,
|
|
643
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
644
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
639
645
|
break;
|
|
640
646
|
case UnderlineStyle.SINGLE:
|
|
641
647
|
default:
|
|
642
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
643
|
-
this._tmpCtx.lineTo(xChRight,
|
|
648
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
649
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
644
650
|
break;
|
|
645
651
|
}
|
|
646
|
-
|
|
652
|
+
if (!wasFilled) {
|
|
653
|
+
this._tmpCtx.stroke();
|
|
654
|
+
}
|
|
647
655
|
this._tmpCtx.restore();
|
|
648
656
|
}
|
|
649
657
|
this._tmpCtx.restore();
|
package/src/WebglAddon.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { ITerminalAddon, Terminal } from '@xterm/xterm';
|
|
7
|
-
import type { WebglAddon as IWebglApi } from '@xterm/addon-webgl';
|
|
7
|
+
import type { IWebglAddonOptions, WebglAddon as IWebglApi } from '@xterm/addon-webgl';
|
|
8
8
|
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
|
9
9
|
import { ITerminal } from 'browser/Types';
|
|
10
10
|
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
|
|
@@ -28,9 +28,10 @@ export class WebglAddon extends Disposable implements ITerminalAddon , IWebglApi
|
|
|
28
28
|
private readonly _onContextLoss = this._register(new Emitter<void>());
|
|
29
29
|
public readonly onContextLoss = this._onContextLoss.event;
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
private readonly _customGlyphs: boolean;
|
|
32
|
+
private readonly _preserveDrawingBuffer?: boolean;
|
|
33
|
+
|
|
34
|
+
constructor(options?: IWebglAddonOptions) {
|
|
34
35
|
if (isSafari && getSafariVersion() < 16) {
|
|
35
36
|
// Perform an extra check to determine if Webgl2 is manually enabled in developer settings
|
|
36
37
|
const contextAttributes = {
|
|
@@ -44,6 +45,8 @@ export class WebglAddon extends Disposable implements ITerminalAddon , IWebglApi
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
super();
|
|
48
|
+
this._customGlyphs = options?.customGlyphs ?? true;
|
|
49
|
+
this._preserveDrawingBuffer = options?.preserveDrawingBuffer;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
public activate(terminal: Terminal): void {
|
|
@@ -79,6 +82,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon , IWebglApi
|
|
|
79
82
|
decorationService,
|
|
80
83
|
optionsService,
|
|
81
84
|
themeService,
|
|
85
|
+
this._customGlyphs,
|
|
82
86
|
this._preserveDrawingBuffer
|
|
83
87
|
));
|
|
84
88
|
this._register(Event.forward(this._renderer.onContextLoss, this._onContextLoss));
|
package/src/WebglRenderer.ts
CHANGED
|
@@ -72,6 +72,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
72
72
|
private readonly _decorationService: IDecorationService,
|
|
73
73
|
private readonly _optionsService: IOptionsService,
|
|
74
74
|
private readonly _themeService: IThemeService,
|
|
75
|
+
private readonly _customGlyphs: boolean = true,
|
|
75
76
|
preserveDrawingBuffer?: boolean
|
|
76
77
|
) {
|
|
77
78
|
super();
|
|
@@ -135,6 +136,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
135
136
|
this._observerDisposable.value = observeDevicePixelDimensions(this._canvas, w, (w, h) => this._setCanvasDevicePixelDimensions(w, h));
|
|
136
137
|
}));
|
|
137
138
|
|
|
139
|
+
this._register(addDisposableListener(this._coreBrowserService.mainDocument, 'mousedown', () => this._cursorBlinkStateManager.value?.restartBlinkAnimation()));
|
|
140
|
+
|
|
138
141
|
this._core.screenElement!.appendChild(this._canvas);
|
|
139
142
|
|
|
140
143
|
[this._rectangleRenderer.value, this._glyphRenderer.value] = this._initializeWebGLState();
|
|
@@ -201,6 +204,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
201
204
|
// Force a full refresh. Resizing `_glyphRenderer` should clear it already,
|
|
202
205
|
// so there is no need to clear it again here.
|
|
203
206
|
this._clearModel(false);
|
|
207
|
+
|
|
208
|
+
// Render synchronously to avoid flicker when the canvas is cleared
|
|
209
|
+
this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1, sync: true });
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
public handleCharSizeChanged(): void {
|
|
@@ -278,7 +284,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
278
284
|
this.dimensions.device.char.width,
|
|
279
285
|
this.dimensions.device.char.height,
|
|
280
286
|
this._coreBrowserService.dpr,
|
|
281
|
-
this._deviceMaxTextureSize
|
|
287
|
+
this._deviceMaxTextureSize,
|
|
288
|
+
this._customGlyphs
|
|
282
289
|
);
|
|
283
290
|
if (this._charAtlas !== atlas) {
|
|
284
291
|
this._onChangeTextureAtlas.fire(atlas.pages[0].canvas);
|
|
@@ -615,7 +622,10 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
615
622
|
// the change as it's an exact multiple of the cell sizes.
|
|
616
623
|
this._canvas.width = width;
|
|
617
624
|
this._canvas.height = height;
|
|
618
|
-
|
|
625
|
+
// Update the WebGL viewport to match the new canvas dimensions
|
|
626
|
+
this._gl.viewport(0, 0, width, height);
|
|
627
|
+
// Render synchronously to avoid flicker when the canvas is cleared
|
|
628
|
+
this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1, sync: true });
|
|
619
629
|
}
|
|
620
630
|
|
|
621
631
|
private _requestRedrawViewport(): void {
|