@xterm/addon-webgl 0.20.0-beta.28 → 0.20.0-beta.280
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 +1 -1
- package/lib/addon-webgl.js +1 -1
- package/lib/addon-webgl.js.map +1 -1
- package/lib/addon-webgl.mjs +5 -31
- package/lib/addon-webgl.mjs.map +4 -4
- package/package.json +4 -4
- package/src/CellColorResolver.ts +6 -3
- package/src/CharAtlasCache.ts +3 -1
- package/src/CharAtlasUtils.ts +3 -0
- package/src/CursorBlinkStateManager.ts +67 -8
- package/src/DevicePixelObserver.ts +1 -1
- package/src/GlyphRenderer.ts +38 -27
- package/src/RectangleRenderer.ts +15 -11
- package/src/RenderModel.ts +7 -5
- package/src/TextureAtlas.ts +116 -72
- package/src/Types.ts +4 -3
- package/src/WebglAddon.ts +9 -13
- package/src/WebglRenderer.ts +123 -36
- package/src/WebglUtils.ts +7 -6
- package/src/customGlyphs/CustomGlyphDefinitions.ts +76 -31
- package/src/customGlyphs/CustomGlyphRasterizer.ts +45 -20
- package/src/renderLayer/BaseRenderLayer.ts +1 -1
- package/typings/addon-webgl.d.ts +5 -2
package/src/TextureAtlas.ts
CHANGED
|
@@ -14,8 +14,8 @@ import { IdleTaskQueue } from 'common/TaskQueue';
|
|
|
14
14
|
import { IColor } from 'common/Types';
|
|
15
15
|
import { AttributeData } from 'common/buffer/AttributeData';
|
|
16
16
|
import { Attributes, DEFAULT_COLOR, DEFAULT_EXT, UnderlineStyle } from 'common/buffer/Constants';
|
|
17
|
-
import { IUnicodeService } from 'common/services/Services';
|
|
18
|
-
import { Emitter } from '
|
|
17
|
+
import { ILogService, IUnicodeService } from 'common/services/Services';
|
|
18
|
+
import { Emitter } from 'common/Event';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* A shared object which is used to draw nothing for a particular cell.
|
|
@@ -69,7 +69,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
69
69
|
private _overflowSizePage: AtlasPage | undefined;
|
|
70
70
|
|
|
71
71
|
private _tmpCanvas: HTMLCanvasElement;
|
|
72
|
-
// A temporary context that glyphs are drawn to before being
|
|
72
|
+
// A temporary context that glyphs are drawn to before being transferred to the atlas.
|
|
73
73
|
private _tmpCtx: CanvasRenderingContext2D;
|
|
74
74
|
|
|
75
75
|
private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 };
|
|
@@ -88,7 +88,8 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
88
88
|
constructor(
|
|
89
89
|
private readonly _document: Document,
|
|
90
90
|
private readonly _config: ICharAtlasConfig,
|
|
91
|
-
private readonly _unicodeService: IUnicodeService
|
|
91
|
+
private readonly _unicodeService: IUnicodeService,
|
|
92
|
+
private readonly _logService: ILogService
|
|
92
93
|
) {
|
|
93
94
|
this._createNewPage();
|
|
94
95
|
this._tmpCanvas = createCanvas(
|
|
@@ -108,6 +109,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
108
109
|
page.canvas.remove();
|
|
109
110
|
}
|
|
110
111
|
this._onAddTextureAtlasCanvas.dispose();
|
|
112
|
+
this._onRemoveTextureAtlasCanvas.dispose();
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
public warmUp(): void {
|
|
@@ -119,7 +121,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
119
121
|
|
|
120
122
|
private _doWarmUp(): void {
|
|
121
123
|
// Pre-fill with ASCII 33-126, this is not urgent and done in idle callbacks
|
|
122
|
-
const queue = new IdleTaskQueue();
|
|
124
|
+
const queue = new IdleTaskQueue(this._logService);
|
|
123
125
|
for (let i = 33; i < 126; i++) {
|
|
124
126
|
queue.enqueue(() => {
|
|
125
127
|
if (!this._cacheMap.get(i, DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_EXT)) {
|
|
@@ -132,7 +134,9 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
132
134
|
|
|
133
135
|
private _requestClearModel = false;
|
|
134
136
|
public beginFrame(): boolean {
|
|
135
|
-
|
|
137
|
+
const result = this._requestClearModel;
|
|
138
|
+
this._requestClearModel = false;
|
|
139
|
+
return result;
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
public clearTexture(): void {
|
|
@@ -148,7 +152,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
148
152
|
}
|
|
149
153
|
|
|
150
154
|
private _createNewPage(): AtlasPage {
|
|
151
|
-
// Try merge the set of the 4 most used pages of the largest size. This is
|
|
155
|
+
// Try merge the set of the 4 most used pages of the largest size. This is deferred to a
|
|
152
156
|
// microtask to ensure it does not interrupt textures that will be rendered in the current
|
|
153
157
|
// animation frame which would result in blank rendered areas. This is actually not that
|
|
154
158
|
// expensive relative to drawing the glyphs, so there is no need to wait for an idle callback.
|
|
@@ -176,12 +180,23 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
176
180
|
|
|
177
181
|
// Gather details of the merge
|
|
178
182
|
const mergingPages = pagesBySize.slice(sameSizeI, sameSizeI + 4);
|
|
179
|
-
|
|
183
|
+
|
|
184
|
+
// Only proceed with merge if we have exactly 4 same-sized pages. If not, we cannot
|
|
185
|
+
// effectively reduce page count and merging would cause issues.
|
|
186
|
+
if (mergingPages.length < 4 || mergingPages.some(p => p.canvas.width !== mergingPages[0].canvas.width)) {
|
|
187
|
+
const newPage = new AtlasPage(this._document, this._textureSize);
|
|
188
|
+
this._pages.push(newPage);
|
|
189
|
+
this._activePages.push(newPage);
|
|
190
|
+
this._onAddTextureAtlasCanvas.fire(newPage.canvas);
|
|
191
|
+
return newPage;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const sortedMergingPagesIndexes = mergingPages.map(e => e.glyphs[0].texturePage).sort((a, b) => a - b);
|
|
180
195
|
const mergedPageIndex = this.pages.length - mergingPages.length;
|
|
181
196
|
|
|
182
197
|
// Merge into the new page
|
|
183
198
|
const mergedPage = this._mergePages(mergingPages, mergedPageIndex);
|
|
184
|
-
mergedPage.version
|
|
199
|
+
mergedPage.version = ++AtlasPage.nextVersion;
|
|
185
200
|
|
|
186
201
|
// Delete the pages, shifting glyph texture pages as needed
|
|
187
202
|
for (let i = sortedMergingPagesIndexes.length - 1; i >= 0; i--) {
|
|
@@ -239,7 +254,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
239
254
|
for (const g of adjustingPage.glyphs) {
|
|
240
255
|
g.texturePage--;
|
|
241
256
|
}
|
|
242
|
-
adjustingPage.version
|
|
257
|
+
adjustingPage.version = ++AtlasPage.nextVersion;
|
|
243
258
|
}
|
|
244
259
|
}
|
|
245
260
|
|
|
@@ -399,7 +414,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
399
414
|
const cache = this._getContrastCache(dim);
|
|
400
415
|
const adjustedColor = cache.getColor(bg, fg);
|
|
401
416
|
if (adjustedColor !== undefined) {
|
|
402
|
-
return adjustedColor
|
|
417
|
+
return adjustedColor ?? undefined;
|
|
403
418
|
}
|
|
404
419
|
|
|
405
420
|
const bgRgba = this._resolveBackgroundRgba(bgColorMode, bgColor, inverse);
|
|
@@ -514,7 +529,8 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
514
529
|
// Draw custom characters if applicable
|
|
515
530
|
let customGlyph = false;
|
|
516
531
|
if (this._config.customGlyphs !== false) {
|
|
517
|
-
|
|
532
|
+
const variantOffset = this._workAttributeData.getUnderlineVariantOffset();
|
|
533
|
+
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, this._logService, backgroundColor.css, variantOffset);
|
|
518
534
|
}
|
|
519
535
|
|
|
520
536
|
// Whether to clear pixels based on a threshold difference between the glyph color and the
|
|
@@ -551,61 +567,67 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
551
567
|
}
|
|
552
568
|
this._tmpCtx.strokeStyle = this._getColorFromAnsiIndex(fg).css;
|
|
553
569
|
}
|
|
570
|
+
this._tmpCtx.fillStyle = this._tmpCtx.strokeStyle;
|
|
554
571
|
|
|
555
572
|
// Underline style/stroke
|
|
556
573
|
this._tmpCtx.beginPath();
|
|
557
574
|
const xLeft = padding;
|
|
558
|
-
const
|
|
559
|
-
const
|
|
560
|
-
const yBot = yTop + lineWidth * 2;
|
|
575
|
+
const yTopDefault = Math.ceil(padding + this._config.deviceCharHeight) - yOffset - (restrictToCellHeight ? lineWidth * 2 : 0);
|
|
576
|
+
const yBotDefault = yTopDefault + lineWidth * 2;
|
|
561
577
|
let nextOffset = this._workAttributeData.getUnderlineVariantOffset();
|
|
578
|
+
let yTop = 0;
|
|
579
|
+
let yBot = 0;
|
|
562
580
|
|
|
563
581
|
for (let i = 0; i < chWidth; i++) {
|
|
582
|
+
let wasFilled = false;
|
|
564
583
|
this._tmpCtx.save();
|
|
584
|
+
yTop = yTopDefault;
|
|
585
|
+
yBot = yBotDefault;
|
|
565
586
|
const xChLeft = xLeft + i * this._config.deviceCellWidth;
|
|
566
587
|
const xChRight = xLeft + (i + 1) * this._config.deviceCellWidth;
|
|
567
|
-
const xChMid = xChLeft + this._config.deviceCellWidth / 2;
|
|
568
588
|
switch (this._workAttributeData.extended.underlineStyle) {
|
|
569
589
|
case UnderlineStyle.DOUBLE:
|
|
570
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
571
|
-
this._tmpCtx.lineTo(xChRight,
|
|
572
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
573
|
-
this._tmpCtx.lineTo(xChRight,
|
|
590
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
591
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
592
|
+
this._tmpCtx.moveTo(xChLeft, yBotDefault);
|
|
593
|
+
this._tmpCtx.lineTo(xChRight, yBotDefault);
|
|
574
594
|
break;
|
|
575
595
|
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.
|
|
596
|
+
yTop = this._config.deviceCharHeight + 1;
|
|
597
|
+
yBot = yTop + 3 * this._config.devicePixelRatio;
|
|
598
|
+
|
|
583
599
|
const clipRegion = new Path2D();
|
|
584
600
|
clipRegion.rect(xChLeft, yTop, this._config.deviceCellWidth, yBot - yTop);
|
|
585
601
|
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
|
-
|
|
602
|
+
|
|
603
|
+
// Draw a zigzag pattern, this is derived from the SVG used in monaco for the same
|
|
604
|
+
// style. The viewbox is 6x3 so scale it using that.
|
|
605
|
+
const cellW = this._config.deviceCellWidth;
|
|
606
|
+
const curlyH = (yBot - yTop);
|
|
607
|
+
const scaleX = cellW / 6;
|
|
608
|
+
const scaleY = curlyH / 3;
|
|
609
|
+
|
|
610
|
+
const polygons: number[][] = [
|
|
611
|
+
[0, 2, 1, 3, 2.4, 3, 0, 0.6],
|
|
612
|
+
[5.5, 0, 2.5, 3, 1.1, 3, 4.1, 0],
|
|
613
|
+
[4, 0, 6, 2, 6, 0.6, 5.4, 0],
|
|
614
|
+
];
|
|
615
|
+
|
|
616
|
+
for (const polygon of polygons) {
|
|
617
|
+
this._tmpCtx.beginPath();
|
|
618
|
+
for (let i = 0; i < polygon.length; i += 2) {
|
|
619
|
+
const x = xChLeft + polygon[i] * scaleX;
|
|
620
|
+
const y = yBot - polygon[i + 1] * scaleY;
|
|
621
|
+
if (i === 0) {
|
|
622
|
+
this._tmpCtx.moveTo(x, y);
|
|
623
|
+
} else {
|
|
624
|
+
this._tmpCtx.lineTo(x, y);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
this._tmpCtx.closePath();
|
|
628
|
+
this._tmpCtx.fill();
|
|
629
|
+
}
|
|
630
|
+
wasFilled = true;
|
|
609
631
|
break;
|
|
610
632
|
case UnderlineStyle.DOTTED:
|
|
611
633
|
const offsetWidth = nextOffset === 0 ? 0 :
|
|
@@ -614,14 +636,14 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
614
636
|
const isLineStart = nextOffset >= lineWidth ? false : true;
|
|
615
637
|
if (isLineStart === false || offsetWidth === 0) {
|
|
616
638
|
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
|
|
617
|
-
this._tmpCtx.moveTo(xChLeft + offsetWidth,
|
|
618
|
-
this._tmpCtx.lineTo(xChRight,
|
|
639
|
+
this._tmpCtx.moveTo(xChLeft + offsetWidth, yTopDefault);
|
|
640
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
619
641
|
} else {
|
|
620
642
|
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,
|
|
643
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
644
|
+
this._tmpCtx.lineTo(xChLeft + offsetWidth, yTopDefault);
|
|
645
|
+
this._tmpCtx.moveTo(xChLeft + offsetWidth + lineWidth, yTopDefault);
|
|
646
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
625
647
|
}
|
|
626
648
|
nextOffset = computeNextVariantOffset(xChRight - xChLeft, lineWidth, nextOffset);
|
|
627
649
|
break;
|
|
@@ -634,16 +656,18 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
634
656
|
const gap = Math.floor(gapRatio * xChWidth);
|
|
635
657
|
const end = xChWidth - line - gap;
|
|
636
658
|
this._tmpCtx.setLineDash([line, gap, end]);
|
|
637
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
638
|
-
this._tmpCtx.lineTo(xChRight,
|
|
659
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
660
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
639
661
|
break;
|
|
640
662
|
case UnderlineStyle.SINGLE:
|
|
641
663
|
default:
|
|
642
|
-
this._tmpCtx.moveTo(xChLeft,
|
|
643
|
-
this._tmpCtx.lineTo(xChRight,
|
|
664
|
+
this._tmpCtx.moveTo(xChLeft, yTopDefault);
|
|
665
|
+
this._tmpCtx.lineTo(xChRight, yTopDefault);
|
|
644
666
|
break;
|
|
645
667
|
}
|
|
646
|
-
|
|
668
|
+
if (!wasFilled) {
|
|
669
|
+
this._tmpCtx.stroke();
|
|
670
|
+
}
|
|
647
671
|
this._tmpCtx.restore();
|
|
648
672
|
}
|
|
649
673
|
this._tmpCtx.restore();
|
|
@@ -916,7 +940,7 @@ export class TextureAtlas implements ITextureAtlas {
|
|
|
916
940
|
rasterizedGlyph.size.y
|
|
917
941
|
);
|
|
918
942
|
activePage.addGlyph(rasterizedGlyph);
|
|
919
|
-
activePage.version
|
|
943
|
+
activePage.version = ++AtlasPage.nextVersion;
|
|
920
944
|
|
|
921
945
|
return rasterizedGlyph;
|
|
922
946
|
}
|
|
@@ -1026,9 +1050,13 @@ class AtlasPage {
|
|
|
1026
1050
|
}
|
|
1027
1051
|
|
|
1028
1052
|
/**
|
|
1029
|
-
*
|
|
1053
|
+
* Monotonically increasing across all atlas pages globally. Used to detect when the texture
|
|
1054
|
+
* unit at a given index needs to be re-uploaded — both for content changes within the same
|
|
1055
|
+
* page and for a page object swap at the same index (which happens after a page merge,
|
|
1056
|
+
* where a per-page counter could coincide with the previously-bound page's value).
|
|
1030
1057
|
*/
|
|
1031
|
-
public
|
|
1058
|
+
public static nextVersion: number = 0;
|
|
1059
|
+
public version = ++AtlasPage.nextVersion;
|
|
1032
1060
|
|
|
1033
1061
|
// Texture atlas current positioning data. The texture packing strategy used is to fill from
|
|
1034
1062
|
// left-to-right and top-to-bottom. When the glyph being written is less than half of the current
|
|
@@ -1052,17 +1080,33 @@ class AtlasPage {
|
|
|
1052
1080
|
size: number,
|
|
1053
1081
|
sourcePages?: AtlasPage[]
|
|
1054
1082
|
) {
|
|
1055
|
-
if (sourcePages) {
|
|
1056
|
-
for (const p of sourcePages) {
|
|
1057
|
-
this._glyphs.push(...p.glyphs);
|
|
1058
|
-
this._usedPixels += p._usedPixels;
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1061
1083
|
this.canvas = createCanvas(document, size, size);
|
|
1062
1084
|
// The canvas needs alpha because we use clearColor to convert the background color to alpha.
|
|
1063
1085
|
// It might also contain some characters with transparent backgrounds if allowTransparency is
|
|
1064
1086
|
// set.
|
|
1065
1087
|
this.ctx = throwIfFalsy(this.canvas.getContext('2d', { alpha: true }));
|
|
1088
|
+
if (sourcePages) {
|
|
1089
|
+
if (sourcePages.length === 4) {
|
|
1090
|
+
// optimized for quadmerge
|
|
1091
|
+
this._glyphs = this._glyphs.concat(
|
|
1092
|
+
sourcePages[0].glyphs,
|
|
1093
|
+
sourcePages[1].glyphs,
|
|
1094
|
+
sourcePages[2].glyphs,
|
|
1095
|
+
sourcePages[3].glyphs
|
|
1096
|
+
);
|
|
1097
|
+
this._usedPixels = sourcePages[0]._usedPixels +
|
|
1098
|
+
sourcePages[1]._usedPixels +
|
|
1099
|
+
sourcePages[2]._usedPixels +
|
|
1100
|
+
sourcePages[3]._usedPixels;
|
|
1101
|
+
} else {
|
|
1102
|
+
// fallback for non quadmerges (should never be used)
|
|
1103
|
+
for (let i = 0; i < sourcePages.length; ++i) {
|
|
1104
|
+
this._glyphs = this._glyphs.concat(sourcePages[i].glyphs);
|
|
1105
|
+
this._usedPixels += sourcePages[i]._usedPixels;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1066
1110
|
}
|
|
1067
1111
|
|
|
1068
1112
|
public clear(): void {
|
|
@@ -1071,7 +1115,7 @@ class AtlasPage {
|
|
|
1071
1115
|
this.currentRow.y = 0;
|
|
1072
1116
|
this.currentRow.height = 0;
|
|
1073
1117
|
this.fixedRows.length = 0;
|
|
1074
|
-
this.version
|
|
1118
|
+
this.version = ++AtlasPage.nextVersion;
|
|
1075
1119
|
}
|
|
1076
1120
|
}
|
|
1077
1121
|
|
|
@@ -1097,7 +1141,7 @@ function clearColor(imageData: ImageData, bg: IColor, fg: IColor, enableThreshol
|
|
|
1097
1141
|
// were covered (fg=#8ae234, bg=#c4a000).
|
|
1098
1142
|
const threshold = Math.floor((Math.abs(r - fgR) + Math.abs(g - fgG) + Math.abs(b - fgB)) / 12);
|
|
1099
1143
|
|
|
1100
|
-
// Set alpha channel of
|
|
1144
|
+
// Set alpha channel of relevant pixels to 0
|
|
1101
1145
|
let isEmpty = true;
|
|
1102
1146
|
for (let offset = 0; offset < imageData.data.length; offset += 4) {
|
|
1103
1147
|
// Check exact match
|
package/src/Types.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { FontWeight } from '@xterm/xterm';
|
|
|
7
7
|
import { IColorSet } from 'browser/Types';
|
|
8
8
|
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
|
|
9
9
|
import { CursorInactiveStyle, CursorStyle, type IDisposable } from 'common/Types';
|
|
10
|
-
import type {
|
|
10
|
+
import type { IEvent } from 'common/Event';
|
|
11
11
|
|
|
12
12
|
export interface IRenderModel {
|
|
13
13
|
cells: Uint32Array;
|
|
@@ -28,6 +28,7 @@ export interface ICursorRenderModel {
|
|
|
28
28
|
export interface IWebGL2RenderingContext extends WebGLRenderingContext {
|
|
29
29
|
vertexAttribDivisor(index: number, divisor: number): void;
|
|
30
30
|
createVertexArray(): IWebGLVertexArrayObject;
|
|
31
|
+
deleteVertexArray(vao: IWebGLVertexArrayObject): void;
|
|
31
32
|
bindVertexArray(vao: IWebGLVertexArrayObject): void;
|
|
32
33
|
drawElementsInstanced(mode: number, count: number, type: number, offset: number, instanceCount: number): void;
|
|
33
34
|
}
|
|
@@ -58,8 +59,8 @@ export interface ICharAtlasConfig {
|
|
|
58
59
|
export interface ITextureAtlas extends IDisposable {
|
|
59
60
|
readonly pages: { canvas: HTMLCanvasElement, version: number }[];
|
|
60
61
|
|
|
61
|
-
onAddTextureAtlasCanvas:
|
|
62
|
-
onRemoveTextureAtlasCanvas:
|
|
62
|
+
onAddTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
|
63
|
+
onRemoveTextureAtlasCanvas: IEvent<HTMLCanvasElement>;
|
|
63
64
|
|
|
64
65
|
/**
|
|
65
66
|
* Warm up the texture atlas, adding common glyphs to avoid slowing early frame.
|
package/src/WebglAddon.ts
CHANGED
|
@@ -7,15 +7,14 @@ import type { ITerminalAddon, Terminal } from '@xterm/xterm';
|
|
|
7
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
|
-
import { Disposable, toDisposable } from '
|
|
10
|
+
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
11
11
|
import { getSafariVersion, isSafari } from 'common/Platform';
|
|
12
12
|
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
|
13
13
|
import { IWebGL2RenderingContext } from './Types';
|
|
14
14
|
import { WebglRenderer } from './WebglRenderer';
|
|
15
|
-
import {
|
|
16
|
-
import { Emitter, Event } from 'vs/base/common/event';
|
|
15
|
+
import { Emitter, EventUtils } from 'common/Event';
|
|
17
16
|
|
|
18
|
-
export class WebglAddon extends Disposable implements ITerminalAddon
|
|
17
|
+
export class WebglAddon extends Disposable implements ITerminalAddon, IWebglApi {
|
|
19
18
|
private _terminal?: Terminal;
|
|
20
19
|
private _renderer?: WebglRenderer;
|
|
21
20
|
|
|
@@ -41,7 +40,7 @@ export class WebglAddon extends Disposable implements ITerminalAddon , IWebglApi
|
|
|
41
40
|
};
|
|
42
41
|
const gl = document.createElement('canvas').getContext('webgl2', contextAttributes) as IWebGL2RenderingContext;
|
|
43
42
|
if (!gl) {
|
|
44
|
-
throw new Error('
|
|
43
|
+
throw new Error('WebGL2 is only supported on Safari 16 and above');
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
super();
|
|
@@ -69,10 +68,6 @@ export class WebglAddon extends Disposable implements ITerminalAddon , IWebglApi
|
|
|
69
68
|
const logService: ILogService = unsafeCore._logService;
|
|
70
69
|
const themeService: IThemeService = unsafeCore._themeService;
|
|
71
70
|
|
|
72
|
-
// Set trace logger just in case it hasn't been yet which could happen when the addon is
|
|
73
|
-
// bundled separately to the core module
|
|
74
|
-
setTraceLogger(logService);
|
|
75
|
-
|
|
76
71
|
this._renderer = this._register(new WebglRenderer(
|
|
77
72
|
terminal,
|
|
78
73
|
characterJoinerService,
|
|
@@ -80,15 +75,16 @@ export class WebglAddon extends Disposable implements ITerminalAddon , IWebglApi
|
|
|
80
75
|
coreBrowserService,
|
|
81
76
|
coreService,
|
|
82
77
|
decorationService,
|
|
78
|
+
logService,
|
|
83
79
|
optionsService,
|
|
84
80
|
themeService,
|
|
85
81
|
this._customGlyphs,
|
|
86
82
|
this._preserveDrawingBuffer
|
|
87
83
|
));
|
|
88
|
-
this._register(
|
|
89
|
-
this._register(
|
|
90
|
-
this._register(
|
|
91
|
-
this._register(
|
|
84
|
+
this._register(EventUtils.forward(this._renderer.onContextLoss, this._onContextLoss));
|
|
85
|
+
this._register(EventUtils.forward(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas));
|
|
86
|
+
this._register(EventUtils.forward(this._renderer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas));
|
|
87
|
+
this._register(EventUtils.forward(this._renderer.onRemoveTextureAtlasCanvas, this._onRemoveTextureAtlasCanvas));
|
|
92
88
|
renderService.setRenderer(this._renderer);
|
|
93
89
|
|
|
94
90
|
this._register(toDisposable(() => {
|