@xterm/addon-webgl 0.17.0-beta.1

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.
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
7
+ import { IRenderDimensions } from 'browser/renderer/shared/Types';
8
+ import { IThemeService } from 'browser/services/Services';
9
+ import { ReadonlyColorSet } from 'browser/Types';
10
+ import { Attributes, FgFlags } from 'common/buffer/Constants';
11
+ import { Disposable, toDisposable } from 'common/Lifecycle';
12
+ import { IColor } from 'common/Types';
13
+ import { Terminal } from '@xterm/xterm';
14
+ import { RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel';
15
+ import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject } from './Types';
16
+ import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils';
17
+
18
+ const enum VertexAttribLocations {
19
+ POSITION = 0,
20
+ SIZE = 1,
21
+ COLOR = 2,
22
+ UNIT_QUAD = 3
23
+ }
24
+
25
+ const vertexShaderSource = `#version 300 es
26
+ layout (location = ${VertexAttribLocations.POSITION}) in vec2 a_position;
27
+ layout (location = ${VertexAttribLocations.SIZE}) in vec2 a_size;
28
+ layout (location = ${VertexAttribLocations.COLOR}) in vec4 a_color;
29
+ layout (location = ${VertexAttribLocations.UNIT_QUAD}) in vec2 a_unitquad;
30
+
31
+ uniform mat4 u_projection;
32
+
33
+ out vec4 v_color;
34
+
35
+ void main() {
36
+ vec2 zeroToOne = a_position + (a_unitquad * a_size);
37
+ gl_Position = u_projection * vec4(zeroToOne, 0.0, 1.0);
38
+ v_color = a_color;
39
+ }`;
40
+
41
+ const fragmentShaderSource = `#version 300 es
42
+ precision lowp float;
43
+
44
+ in vec4 v_color;
45
+
46
+ out vec4 outColor;
47
+
48
+ void main() {
49
+ outColor = v_color;
50
+ }`;
51
+
52
+ const INDICES_PER_RECTANGLE = 8;
53
+ const BYTES_PER_RECTANGLE = INDICES_PER_RECTANGLE * Float32Array.BYTES_PER_ELEMENT;
54
+
55
+ const INITIAL_BUFFER_RECTANGLE_CAPACITY = 20 * INDICES_PER_RECTANGLE;
56
+
57
+ class Vertices {
58
+ public attributes: Float32Array;
59
+ public count: number;
60
+
61
+ constructor() {
62
+ this.attributes = new Float32Array(INITIAL_BUFFER_RECTANGLE_CAPACITY);
63
+ this.count = 0;
64
+ }
65
+ }
66
+
67
+ // Work variables to avoid garbage collection
68
+ let $rgba = 0;
69
+ let $x1 = 0;
70
+ let $y1 = 0;
71
+ let $r = 0;
72
+ let $g = 0;
73
+ let $b = 0;
74
+ let $a = 0;
75
+
76
+ export class RectangleRenderer extends Disposable {
77
+
78
+ private _program: WebGLProgram;
79
+ private _vertexArrayObject: IWebGLVertexArrayObject;
80
+ private _attributesBuffer: WebGLBuffer;
81
+ private _projectionLocation: WebGLUniformLocation;
82
+ private _bgFloat!: Float32Array;
83
+ private _cursorFloat!: Float32Array;
84
+
85
+ private _vertices: Vertices = new Vertices();
86
+ private _verticesCursor: Vertices = new Vertices();
87
+
88
+ constructor(
89
+ private _terminal: Terminal,
90
+ private _gl: IWebGL2RenderingContext,
91
+ private _dimensions: IRenderDimensions,
92
+ private readonly _themeService: IThemeService
93
+ ) {
94
+ super();
95
+
96
+ const gl = this._gl;
97
+
98
+ this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource));
99
+ this.register(toDisposable(() => gl.deleteProgram(this._program)));
100
+
101
+ // Uniform locations
102
+ this._projectionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection'));
103
+
104
+ // Create and set the vertex array object
105
+ this._vertexArrayObject = gl.createVertexArray();
106
+ gl.bindVertexArray(this._vertexArrayObject);
107
+
108
+ // Setup a_unitquad, this defines the 4 vertices of a rectangle
109
+ const unitQuadVertices = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
110
+ const unitQuadVerticesBuffer = gl.createBuffer();
111
+ this.register(toDisposable(() => gl.deleteBuffer(unitQuadVerticesBuffer)));
112
+ gl.bindBuffer(gl.ARRAY_BUFFER, unitQuadVerticesBuffer);
113
+ gl.bufferData(gl.ARRAY_BUFFER, unitQuadVertices, gl.STATIC_DRAW);
114
+ gl.enableVertexAttribArray(VertexAttribLocations.UNIT_QUAD);
115
+ gl.vertexAttribPointer(VertexAttribLocations.UNIT_QUAD, 2, this._gl.FLOAT, false, 0, 0);
116
+
117
+ // Setup the unit quad element array buffer, this points to indices in
118
+ // unitQuadVertices to allow is to draw 2 triangles from the vertices via a
119
+ // triangle strip
120
+ const unitQuadElementIndices = new Uint8Array([0, 1, 2, 3]);
121
+ const elementIndicesBuffer = gl.createBuffer();
122
+ this.register(toDisposable(() => gl.deleteBuffer(elementIndicesBuffer)));
123
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementIndicesBuffer);
124
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW);
125
+
126
+ // Setup attributes
127
+ this._attributesBuffer = throwIfFalsy(gl.createBuffer());
128
+ this.register(toDisposable(() => gl.deleteBuffer(this._attributesBuffer)));
129
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
130
+ gl.enableVertexAttribArray(VertexAttribLocations.POSITION);
131
+ gl.vertexAttribPointer(VertexAttribLocations.POSITION, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 0);
132
+ gl.vertexAttribDivisor(VertexAttribLocations.POSITION, 1);
133
+ gl.enableVertexAttribArray(VertexAttribLocations.SIZE);
134
+ gl.vertexAttribPointer(VertexAttribLocations.SIZE, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 2 * Float32Array.BYTES_PER_ELEMENT);
135
+ gl.vertexAttribDivisor(VertexAttribLocations.SIZE, 1);
136
+ gl.enableVertexAttribArray(VertexAttribLocations.COLOR);
137
+ gl.vertexAttribPointer(VertexAttribLocations.COLOR, 4, gl.FLOAT, false, BYTES_PER_RECTANGLE, 4 * Float32Array.BYTES_PER_ELEMENT);
138
+ gl.vertexAttribDivisor(VertexAttribLocations.COLOR, 1);
139
+
140
+ this._updateCachedColors(_themeService.colors);
141
+ this.register(this._themeService.onChangeColors(e => {
142
+ this._updateCachedColors(e);
143
+ this._updateViewportRectangle();
144
+ }));
145
+ }
146
+
147
+ public renderBackgrounds(): void {
148
+ this._renderVertices(this._vertices);
149
+ }
150
+
151
+ public renderCursor(): void {
152
+ this._renderVertices(this._verticesCursor);
153
+ }
154
+
155
+ private _renderVertices(vertices: Vertices): void {
156
+ const gl = this._gl;
157
+
158
+ gl.useProgram(this._program);
159
+
160
+ gl.bindVertexArray(this._vertexArrayObject);
161
+
162
+ gl.uniformMatrix4fv(this._projectionLocation, false, PROJECTION_MATRIX);
163
+
164
+ // Bind attributes buffer and draw
165
+ gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
166
+ gl.bufferData(gl.ARRAY_BUFFER, vertices.attributes, gl.DYNAMIC_DRAW);
167
+ gl.drawElementsInstanced(this._gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_BYTE, 0, vertices.count);
168
+ }
169
+
170
+ public handleResize(): void {
171
+ this._updateViewportRectangle();
172
+ }
173
+
174
+ public setDimensions(dimensions: IRenderDimensions): void {
175
+ this._dimensions = dimensions;
176
+ }
177
+
178
+ private _updateCachedColors(colors: ReadonlyColorSet): void {
179
+ this._bgFloat = this._colorToFloat32Array(colors.background);
180
+ this._cursorFloat = this._colorToFloat32Array(colors.cursor);
181
+ }
182
+
183
+ private _updateViewportRectangle(): void {
184
+ // Set first rectangle that clears the screen
185
+ this._addRectangleFloat(
186
+ this._vertices.attributes,
187
+ 0,
188
+ 0,
189
+ 0,
190
+ this._terminal.cols * this._dimensions.device.cell.width,
191
+ this._terminal.rows * this._dimensions.device.cell.height,
192
+ this._bgFloat
193
+ );
194
+ }
195
+
196
+ public updateBackgrounds(model: IRenderModel): void {
197
+ const terminal = this._terminal;
198
+ const vertices = this._vertices;
199
+
200
+ // Declare variable ahead of time to avoid garbage collection
201
+ let rectangleCount = 1;
202
+ let y: number;
203
+ let x: number;
204
+ let currentStartX: number;
205
+ let currentBg: number;
206
+ let currentFg: number;
207
+ let currentInverse: boolean;
208
+ let modelIndex: number;
209
+ let bg: number;
210
+ let fg: number;
211
+ let inverse: boolean;
212
+ let offset: number;
213
+
214
+ for (y = 0; y < terminal.rows; y++) {
215
+ currentStartX = -1;
216
+ currentBg = 0;
217
+ currentFg = 0;
218
+ currentInverse = false;
219
+ for (x = 0; x < terminal.cols; x++) {
220
+ modelIndex = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL;
221
+ bg = model.cells[modelIndex + RENDER_MODEL_BG_OFFSET];
222
+ fg = model.cells[modelIndex + RENDER_MODEL_FG_OFFSET];
223
+ inverse = !!(fg & FgFlags.INVERSE);
224
+ if (bg !== currentBg || (fg !== currentFg && (currentInverse || inverse))) {
225
+ // A rectangle needs to be drawn if going from non-default to another color
226
+ if (currentBg !== 0 || (currentInverse && currentFg !== 0)) {
227
+ offset = rectangleCount++ * INDICES_PER_RECTANGLE;
228
+ this._updateRectangle(vertices, offset, currentFg, currentBg, currentStartX, x, y);
229
+ }
230
+ currentStartX = x;
231
+ currentBg = bg;
232
+ currentFg = fg;
233
+ currentInverse = inverse;
234
+ }
235
+ }
236
+ // Finish rectangle if it's still going
237
+ if (currentBg !== 0 || (currentInverse && currentFg !== 0)) {
238
+ offset = rectangleCount++ * INDICES_PER_RECTANGLE;
239
+ this._updateRectangle(vertices, offset, currentFg, currentBg, currentStartX, terminal.cols, y);
240
+ }
241
+ }
242
+ vertices.count = rectangleCount;
243
+ }
244
+
245
+ public updateCursor(model: IRenderModel): void {
246
+ const vertices = this._verticesCursor;
247
+ const cursor = model.cursor;
248
+ if (!cursor || cursor.style === 'block') {
249
+ vertices.count = 0;
250
+ return;
251
+ }
252
+
253
+ let offset: number;
254
+ let rectangleCount = 0;
255
+
256
+ if (cursor.style === 'bar' || cursor.style === 'outline') {
257
+ // Left edge
258
+ offset = rectangleCount++ * INDICES_PER_RECTANGLE;
259
+ this._addRectangleFloat(
260
+ vertices.attributes,
261
+ offset,
262
+ cursor.x * this._dimensions.device.cell.width,
263
+ cursor.y * this._dimensions.device.cell.height,
264
+ cursor.style === 'bar' ? cursor.dpr * cursor.cursorWidth : cursor.dpr,
265
+ this._dimensions.device.cell.height,
266
+ this._cursorFloat
267
+ );
268
+ }
269
+ if (cursor.style === 'underline' || cursor.style === 'outline') {
270
+ // Bottom edge
271
+ offset = rectangleCount++ * INDICES_PER_RECTANGLE;
272
+ this._addRectangleFloat(
273
+ vertices.attributes,
274
+ offset,
275
+ cursor.x * this._dimensions.device.cell.width,
276
+ (cursor.y + 1) * this._dimensions.device.cell.height - cursor.dpr,
277
+ cursor.width * this._dimensions.device.cell.width,
278
+ cursor.dpr,
279
+ this._cursorFloat
280
+ );
281
+ }
282
+ if (cursor.style === 'outline') {
283
+ // Top edge
284
+ offset = rectangleCount++ * INDICES_PER_RECTANGLE;
285
+ this._addRectangleFloat(
286
+ vertices.attributes,
287
+ offset,
288
+ cursor.x * this._dimensions.device.cell.width,
289
+ cursor.y * this._dimensions.device.cell.height,
290
+ cursor.width * this._dimensions.device.cell.width,
291
+ cursor.dpr,
292
+ this._cursorFloat
293
+ );
294
+ // Right edge
295
+ offset = rectangleCount++ * INDICES_PER_RECTANGLE;
296
+ this._addRectangleFloat(
297
+ vertices.attributes,
298
+ offset,
299
+ (cursor.x + cursor.width) * this._dimensions.device.cell.width - cursor.dpr,
300
+ cursor.y * this._dimensions.device.cell.height,
301
+ cursor.dpr,
302
+ this._dimensions.device.cell.height,
303
+ this._cursorFloat
304
+ );
305
+ }
306
+
307
+ vertices.count = rectangleCount;
308
+ }
309
+
310
+ private _updateRectangle(vertices: Vertices, offset: number, fg: number, bg: number, startX: number, endX: number, y: number): void {
311
+ if (fg & FgFlags.INVERSE) {
312
+ switch (fg & Attributes.CM_MASK) {
313
+ case Attributes.CM_P16:
314
+ case Attributes.CM_P256:
315
+ $rgba = this._themeService.colors.ansi[fg & Attributes.PCOLOR_MASK].rgba;
316
+ break;
317
+ case Attributes.CM_RGB:
318
+ $rgba = (fg & Attributes.RGB_MASK) << 8;
319
+ break;
320
+ case Attributes.CM_DEFAULT:
321
+ default:
322
+ $rgba = this._themeService.colors.foreground.rgba;
323
+ }
324
+ } else {
325
+ switch (bg & Attributes.CM_MASK) {
326
+ case Attributes.CM_P16:
327
+ case Attributes.CM_P256:
328
+ $rgba = this._themeService.colors.ansi[bg & Attributes.PCOLOR_MASK].rgba;
329
+ break;
330
+ case Attributes.CM_RGB:
331
+ $rgba = (bg & Attributes.RGB_MASK) << 8;
332
+ break;
333
+ case Attributes.CM_DEFAULT:
334
+ default:
335
+ $rgba = this._themeService.colors.background.rgba;
336
+ }
337
+ }
338
+
339
+ if (vertices.attributes.length < offset + 4) {
340
+ vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE);
341
+ }
342
+ $x1 = startX * this._dimensions.device.cell.width;
343
+ $y1 = y * this._dimensions.device.cell.height;
344
+ $r = (($rgba >> 24) & 0xFF) / 255;
345
+ $g = (($rgba >> 16) & 0xFF) / 255;
346
+ $b = (($rgba >> 8 ) & 0xFF) / 255;
347
+ $a = 1;
348
+
349
+ this._addRectangle(vertices.attributes, offset, $x1, $y1, (endX - startX) * this._dimensions.device.cell.width, this._dimensions.device.cell.height, $r, $g, $b, $a);
350
+ }
351
+
352
+ private _addRectangle(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, r: number, g: number, b: number, a: number): void {
353
+ array[offset ] = x1 / this._dimensions.device.canvas.width;
354
+ array[offset + 1] = y1 / this._dimensions.device.canvas.height;
355
+ array[offset + 2] = width / this._dimensions.device.canvas.width;
356
+ array[offset + 3] = height / this._dimensions.device.canvas.height;
357
+ array[offset + 4] = r;
358
+ array[offset + 5] = g;
359
+ array[offset + 6] = b;
360
+ array[offset + 7] = a;
361
+ }
362
+
363
+ private _addRectangleFloat(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, color: Float32Array): void {
364
+ array[offset ] = x1 / this._dimensions.device.canvas.width;
365
+ array[offset + 1] = y1 / this._dimensions.device.canvas.height;
366
+ array[offset + 2] = width / this._dimensions.device.canvas.width;
367
+ array[offset + 3] = height / this._dimensions.device.canvas.height;
368
+ array[offset + 4] = color[0];
369
+ array[offset + 5] = color[1];
370
+ array[offset + 6] = color[2];
371
+ array[offset + 7] = color[3];
372
+ }
373
+
374
+ private _colorToFloat32Array(color: IColor): Float32Array {
375
+ return new Float32Array([
376
+ ((color.rgba >> 24) & 0xFF) / 255,
377
+ ((color.rgba >> 16) & 0xFF) / 255,
378
+ ((color.rgba >> 8 ) & 0xFF) / 255,
379
+ ((color.rgba ) & 0xFF) / 255
380
+ ]);
381
+ }
382
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { ICursorRenderModel, IRenderModel } from './Types';
7
+ import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
8
+ import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
9
+
10
+ export const RENDER_MODEL_INDICIES_PER_CELL = 4;
11
+ export const RENDER_MODEL_BG_OFFSET = 1;
12
+ export const RENDER_MODEL_FG_OFFSET = 2;
13
+ export const RENDER_MODEL_EXT_OFFSET = 3;
14
+
15
+ export const COMBINED_CHAR_BIT_MASK = 0x80000000;
16
+
17
+ export class RenderModel implements IRenderModel {
18
+ public cells: Uint32Array;
19
+ public lineLengths: Uint32Array;
20
+ public selection: ISelectionRenderModel;
21
+ public cursor?: ICursorRenderModel;
22
+
23
+ constructor() {
24
+ this.cells = new Uint32Array(0);
25
+ this.lineLengths = new Uint32Array(0);
26
+ this.selection = createSelectionRenderModel();
27
+ }
28
+
29
+ public resize(cols: number, rows: number): void {
30
+ const indexCount = cols * rows * RENDER_MODEL_INDICIES_PER_CELL;
31
+ if (indexCount !== this.cells.length) {
32
+ this.cells = new Uint32Array(indexCount);
33
+ this.lineLengths = new Uint32Array(rows);
34
+ }
35
+ }
36
+
37
+ public clear(): void {
38
+ this.cells.fill(0, 0);
39
+ this.lineLengths.fill(0, 0);
40
+ }
41
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ export type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Int8Array | Int16Array | Int32Array | Float32Array | Float64Array;
7
+
8
+ export function slice<T extends TypedArray>(array: T, start?: number, end?: number): T {
9
+ // all modern engines that support .slice
10
+ if (array.slice) {
11
+ return array.slice(start, end) as T;
12
+ }
13
+ return sliceFallback(array, start, end);
14
+ }
15
+
16
+ export function sliceFallback<T extends TypedArray>(array: T, start: number = 0, end: number = array.length): T {
17
+ if (start < 0) {
18
+ start = (array.length + start) % array.length;
19
+ }
20
+ if (end >= array.length) {
21
+ end = array.length;
22
+ } else {
23
+ end = (array.length + end) % array.length;
24
+ }
25
+ start = Math.min(start, end);
26
+
27
+ const result: T = new (array.constructor as any)(end - start);
28
+ for (let i = 0; i < end - start; ++i) {
29
+ result[i] = array[i + start];
30
+ }
31
+ return result;
32
+ }
package/src/Types.d.ts ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) 2018 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
7
+ import { CursorInactiveStyle, CursorStyle } from 'common/Types';
8
+
9
+ export interface IRenderModel {
10
+ cells: Uint32Array;
11
+ lineLengths: Uint32Array;
12
+ selection: ISelectionRenderModel;
13
+ cursor?: ICursorRenderModel;
14
+ }
15
+
16
+ export interface ICursorRenderModel {
17
+ x: number;
18
+ y: number;
19
+ width: number;
20
+ style: CursorStyle | CursorInactiveStyle;
21
+ cursorWidth: number;
22
+ dpr: number;
23
+ }
24
+
25
+ export interface IWebGL2RenderingContext extends WebGLRenderingContext {
26
+ vertexAttribDivisor(index: number, divisor: number): void;
27
+ createVertexArray(): IWebGLVertexArrayObject;
28
+ bindVertexArray(vao: IWebGLVertexArrayObject): void;
29
+ drawElementsInstanced(mode: number, count: number, type: number, offset: number, instanceCount: number): void;
30
+ }
31
+
32
+ export interface IWebGLVertexArrayObject {
33
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Copyright (c) 2017 The xterm.js authors. All rights reserved.
3
+ * @license MIT
4
+ */
5
+
6
+ import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
7
+ import { ITerminal } from 'browser/Types';
8
+ import { EventEmitter, forwardEvent } from 'common/EventEmitter';
9
+ import { Disposable, toDisposable } from 'common/Lifecycle';
10
+ import { getSafariVersion, isSafari } from 'common/Platform';
11
+ import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
12
+ import { ITerminalAddon, Terminal } from '@xterm/xterm';
13
+ import { WebglRenderer } from './WebglRenderer';
14
+ import { setTraceLogger } from 'common/services/LogService';
15
+
16
+ export class WebglAddon extends Disposable implements ITerminalAddon {
17
+ private _terminal?: Terminal;
18
+ private _renderer?: WebglRenderer;
19
+
20
+ private readonly _onChangeTextureAtlas = this.register(new EventEmitter<HTMLCanvasElement>());
21
+ public readonly onChangeTextureAtlas = this._onChangeTextureAtlas.event;
22
+ private readonly _onAddTextureAtlasCanvas = this.register(new EventEmitter<HTMLCanvasElement>());
23
+ public readonly onAddTextureAtlasCanvas = this._onAddTextureAtlasCanvas.event;
24
+ private readonly _onRemoveTextureAtlasCanvas = this.register(new EventEmitter<HTMLCanvasElement>());
25
+ public readonly onRemoveTextureAtlasCanvas = this._onRemoveTextureAtlasCanvas.event;
26
+ private readonly _onContextLoss = this.register(new EventEmitter<void>());
27
+ public readonly onContextLoss = this._onContextLoss.event;
28
+
29
+ constructor(
30
+ private _preserveDrawingBuffer?: boolean
31
+ ) {
32
+ if (isSafari && getSafariVersion() < 16) {
33
+ throw new Error('Webgl2 is only supported on Safari 16 and above');
34
+ }
35
+ super();
36
+ }
37
+
38
+ public activate(terminal: Terminal): void {
39
+ const core = (terminal as any)._core as ITerminal;
40
+ if (!terminal.element) {
41
+ this.register(core.onWillOpen(() => this.activate(terminal)));
42
+ return;
43
+ }
44
+
45
+ this._terminal = terminal;
46
+ const coreService: ICoreService = core.coreService;
47
+ const optionsService: IOptionsService = core.optionsService;
48
+
49
+ const unsafeCore = core as any;
50
+ const renderService: IRenderService = unsafeCore._renderService;
51
+ const characterJoinerService: ICharacterJoinerService = unsafeCore._characterJoinerService;
52
+ const charSizeService: ICharSizeService = unsafeCore._charSizeService;
53
+ const coreBrowserService: ICoreBrowserService = unsafeCore._coreBrowserService;
54
+ const decorationService: IDecorationService = unsafeCore._decorationService;
55
+ const logService: ILogService = unsafeCore._logService;
56
+ const themeService: IThemeService = unsafeCore._themeService;
57
+
58
+ // Set trace logger just in case it hasn't been yet which could happen when the addon is
59
+ // bundled separately to the core module
60
+ setTraceLogger(logService);
61
+
62
+ this._renderer = this.register(new WebglRenderer(
63
+ terminal,
64
+ characterJoinerService,
65
+ charSizeService,
66
+ coreBrowserService,
67
+ coreService,
68
+ decorationService,
69
+ optionsService,
70
+ themeService,
71
+ this._preserveDrawingBuffer
72
+ ));
73
+ this.register(forwardEvent(this._renderer.onContextLoss, this._onContextLoss));
74
+ this.register(forwardEvent(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas));
75
+ this.register(forwardEvent(this._renderer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas));
76
+ this.register(forwardEvent(this._renderer.onRemoveTextureAtlasCanvas, this._onRemoveTextureAtlasCanvas));
77
+ renderService.setRenderer(this._renderer);
78
+
79
+ this.register(toDisposable(() => {
80
+ const renderService: IRenderService = (this._terminal as any)._core._renderService;
81
+ renderService.setRenderer((this._terminal as any)._core._createRenderer());
82
+ renderService.handleResize(terminal.cols, terminal.rows);
83
+ }));
84
+ }
85
+
86
+ public get textureAtlas(): HTMLCanvasElement | undefined {
87
+ return this._renderer?.textureAtlas;
88
+ }
89
+
90
+ public clearTextureAtlas(): void {
91
+ this._renderer?.clearTextureAtlas();
92
+ }
93
+ }