@xterm/addon-webgl 0.20.0-beta.26 → 0.20.0-beta.261
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 +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 +35 -25
- package/src/RectangleRenderer.ts +15 -11
- package/src/RenderModel.ts +7 -5
- package/src/TextureAtlas.ts +90 -62
- package/src/Types.ts +4 -3
- package/src/WebglAddon.ts +8 -12
- package/src/WebglRenderer.ts +103 -31
- 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 +3 -0
package/src/WebglRenderer.ts
CHANGED
|
@@ -10,26 +10,32 @@ import { CursorBlinkStateManager } from './CursorBlinkStateManager';
|
|
|
10
10
|
import { observeDevicePixelDimensions } from './DevicePixelObserver';
|
|
11
11
|
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types';
|
|
12
12
|
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
|
13
|
-
import { CharData, IBufferLine, ICellData } from 'common/Types';
|
|
13
|
+
import { CharData, IBufferLine, ICellData } from 'common/buffer/Types';
|
|
14
14
|
import { AttributeData } from 'common/buffer/AttributeData';
|
|
15
15
|
import { CellData } from 'common/buffer/CellData';
|
|
16
|
-
import { Attributes, Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
|
|
17
|
-
import {
|
|
16
|
+
import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
|
|
17
|
+
import { TextBlinkStateManager } from 'browser/renderer/shared/TextBlinkStateManager';
|
|
18
|
+
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
|
18
19
|
import { Terminal } from '@xterm/xterm';
|
|
19
20
|
import { GlyphRenderer } from './GlyphRenderer';
|
|
20
21
|
import { RectangleRenderer } from './RectangleRenderer';
|
|
21
|
-
import { COMBINED_CHAR_BIT_MASK,
|
|
22
|
+
import { COMBINED_CHAR_BIT_MASK, RenderModel, RenderModelConstants } from './RenderModel';
|
|
22
23
|
import { IWebGL2RenderingContext, type ITextureAtlas } from './Types';
|
|
23
24
|
import { LinkRenderLayer } from './renderLayer/LinkRenderLayer';
|
|
24
25
|
import { IRenderLayer } from './renderLayer/Types';
|
|
25
|
-
import { Emitter,
|
|
26
|
-
import { addDisposableListener } from '
|
|
27
|
-
import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from '
|
|
26
|
+
import { Emitter, EventUtils } from 'common/Event';
|
|
27
|
+
import { addDisposableListener } from 'browser/Dom';
|
|
28
|
+
import { combinedDisposable, Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
|
|
28
29
|
import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
|
|
29
30
|
|
|
31
|
+
const enum Constants {
|
|
32
|
+
MERGE_RETRY_LIMIT = 32
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
export class WebglRenderer extends Disposable implements IRenderer {
|
|
31
36
|
private _renderLayers: IRenderLayer[];
|
|
32
|
-
private _cursorBlinkStateManager: MutableDisposable<CursorBlinkStateManager> = new MutableDisposable();
|
|
37
|
+
private _cursorBlinkStateManager: MutableDisposable<CursorBlinkStateManager> = this._register(new MutableDisposable());
|
|
38
|
+
private _textBlinkStateManager: TextBlinkStateManager;
|
|
33
39
|
private _charAtlasDisposable = this._register(new MutableDisposable());
|
|
34
40
|
private _charAtlas: ITextureAtlas | undefined;
|
|
35
41
|
private _devicePixelRatio: number;
|
|
@@ -37,8 +43,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
37
43
|
private _observerDisposable = this._register(new MutableDisposable());
|
|
38
44
|
|
|
39
45
|
private _model: RenderModel = new RenderModel();
|
|
46
|
+
private _rowHasBlinkingCells: boolean[] = [];
|
|
47
|
+
private _rowHasBlinkingCellsCount: number = 0;
|
|
40
48
|
private _workCell: ICellData = new CellData();
|
|
41
|
-
private _workCell2: ICellData = new CellData();
|
|
42
49
|
private _cellColorResolver: CellColorResolver;
|
|
43
50
|
|
|
44
51
|
private _canvas: HTMLCanvasElement;
|
|
@@ -70,6 +77,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
70
77
|
private readonly _coreBrowserService: ICoreBrowserService,
|
|
71
78
|
private readonly _coreService: ICoreService,
|
|
72
79
|
private readonly _decorationService: IDecorationService,
|
|
80
|
+
private readonly _logService: ILogService,
|
|
73
81
|
private readonly _optionsService: IOptionsService,
|
|
74
82
|
private readonly _themeService: IThemeService,
|
|
75
83
|
private readonly _customGlyphs: boolean = true,
|
|
@@ -105,23 +113,29 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
105
113
|
this._updateDimensions();
|
|
106
114
|
this._updateCursorBlink();
|
|
107
115
|
this._register(_optionsService.onOptionChange(() => this._handleOptionsChanged()));
|
|
116
|
+
this._textBlinkStateManager = this._register(new TextBlinkStateManager(
|
|
117
|
+
() => this._requestRedrawViewport(),
|
|
118
|
+
this._coreBrowserService,
|
|
119
|
+
this._optionsService
|
|
120
|
+
));
|
|
121
|
+
this._resetBlinkingRowState();
|
|
108
122
|
|
|
109
123
|
this._deviceMaxTextureSize = this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE);
|
|
110
124
|
|
|
111
125
|
this._register(addDisposableListener(this._canvas, 'webglcontextlost', (e) => {
|
|
112
|
-
|
|
126
|
+
this._logService.debug('webglcontextlost event received');
|
|
113
127
|
// Prevent the default behavior in order to enable WebGL context restoration.
|
|
114
128
|
e.preventDefault();
|
|
115
129
|
// Wait a few seconds to see if the 'webglcontextrestored' event is fired.
|
|
116
130
|
// If not, dispatch the onContextLoss notification to observers.
|
|
117
131
|
this._contextRestorationTimeout = setTimeout(() => {
|
|
118
132
|
this._contextRestorationTimeout = undefined;
|
|
119
|
-
|
|
133
|
+
this._logService.warn('webgl context not restored; firing onContextLoss');
|
|
120
134
|
this._onContextLoss.fire(e);
|
|
121
135
|
}, 3000 /* ms */);
|
|
122
136
|
}));
|
|
123
137
|
this._register(addDisposableListener(this._canvas, 'webglcontextrestored', (e) => {
|
|
124
|
-
|
|
138
|
+
this._logService.warn('webglcontextrestored event received');
|
|
125
139
|
clearTimeout(this._contextRestorationTimeout);
|
|
126
140
|
this._contextRestorationTimeout = undefined;
|
|
127
141
|
// The texture atlas and glyph renderer must be fully reinitialized
|
|
@@ -136,6 +150,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
136
150
|
this._observerDisposable.value = observeDevicePixelDimensions(this._canvas, w, (w, h) => this._setCanvasDevicePixelDimensions(w, h));
|
|
137
151
|
}));
|
|
138
152
|
|
|
153
|
+
this._register(addDisposableListener(this._coreBrowserService.mainDocument, 'mousedown', () => this._cursorBlinkStateManager.value?.restartBlinkAnimation()));
|
|
154
|
+
|
|
139
155
|
this._core.screenElement!.appendChild(this._canvas);
|
|
140
156
|
|
|
141
157
|
[this._rectangleRenderer.value, this._glyphRenderer.value] = this._initializeWebGLState();
|
|
@@ -143,6 +159,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
143
159
|
this._isAttached = this._core.screenElement!.isConnected;
|
|
144
160
|
|
|
145
161
|
this._register(toDisposable(() => {
|
|
162
|
+
clearTimeout(this._contextRestorationTimeout);
|
|
163
|
+
this._contextRestorationTimeout = undefined;
|
|
146
164
|
for (const l of this._renderLayers) {
|
|
147
165
|
l.dispose();
|
|
148
166
|
}
|
|
@@ -176,6 +194,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
176
194
|
this._updateDimensions();
|
|
177
195
|
|
|
178
196
|
this._model.resize(this._terminal.cols, this._terminal.rows);
|
|
197
|
+
this._resetBlinkingRowState();
|
|
179
198
|
|
|
180
199
|
// Resize all render layers
|
|
181
200
|
for (const l of this._renderLayers) {
|
|
@@ -202,6 +221,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
202
221
|
// Force a full refresh. Resizing `_glyphRenderer` should clear it already,
|
|
203
222
|
// so there is no need to clear it again here.
|
|
204
223
|
this._clearModel(false);
|
|
224
|
+
|
|
225
|
+
// Render synchronously to avoid flicker when the canvas is cleared
|
|
226
|
+
this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1, sync: true });
|
|
205
227
|
}
|
|
206
228
|
|
|
207
229
|
public handleCharSizeChanged(): void {
|
|
@@ -226,6 +248,10 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
226
248
|
this._requestRedrawViewport();
|
|
227
249
|
}
|
|
228
250
|
|
|
251
|
+
public handleViewportVisibilityChange(isVisible: boolean): void {
|
|
252
|
+
this._textBlinkStateManager.setViewportVisible(isVisible);
|
|
253
|
+
}
|
|
254
|
+
|
|
229
255
|
public handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
|
|
230
256
|
for (const l of this._renderLayers) {
|
|
231
257
|
l.handleSelectionChanged(this._terminal, start, end, columnSelectMode);
|
|
@@ -251,8 +277,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
251
277
|
* Initializes members dependent on WebGL context state.
|
|
252
278
|
*/
|
|
253
279
|
private _initializeWebGLState(): [RectangleRenderer, GlyphRenderer] {
|
|
254
|
-
this._rectangleRenderer.value = new RectangleRenderer(this._terminal, this._gl, this.dimensions, this._themeService);
|
|
255
|
-
this._glyphRenderer.value = new GlyphRenderer(this._terminal, this._gl, this.dimensions, this._optionsService);
|
|
280
|
+
this._rectangleRenderer.value = new RectangleRenderer(this._terminal, this._gl, this.dimensions, this._themeService, this._logService);
|
|
281
|
+
this._glyphRenderer.value = new GlyphRenderer(this._terminal, this._gl, this.dimensions, this._optionsService, this._logService);
|
|
256
282
|
|
|
257
283
|
// Update dimensions and acquire char atlas
|
|
258
284
|
this.handleCharSizeChanged();
|
|
@@ -285,8 +311,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
285
311
|
if (this._charAtlas !== atlas) {
|
|
286
312
|
this._onChangeTextureAtlas.fire(atlas.pages[0].canvas);
|
|
287
313
|
this._charAtlasDisposable.value = combinedDisposable(
|
|
288
|
-
|
|
289
|
-
|
|
314
|
+
EventUtils.forward(atlas.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas),
|
|
315
|
+
EventUtils.forward(atlas.onRemoveTextureAtlasCanvas, this._onRemoveTextureAtlasCanvas)
|
|
290
316
|
);
|
|
291
317
|
}
|
|
292
318
|
this._charAtlas = atlas;
|
|
@@ -318,6 +344,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
318
344
|
l.reset(this._terminal);
|
|
319
345
|
}
|
|
320
346
|
|
|
347
|
+
this._resetBlinkingRowState();
|
|
348
|
+
this._textBlinkStateManager.setNeedsBlinkInViewport(false);
|
|
349
|
+
|
|
321
350
|
this._cursorBlinkStateManager.value?.restartBlinkAnimation();
|
|
322
351
|
this._updateCursorBlink();
|
|
323
352
|
}
|
|
@@ -353,6 +382,19 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
353
382
|
this._updateModel(start, end);
|
|
354
383
|
}
|
|
355
384
|
|
|
385
|
+
// A mid-update atlas page merge invalidates vertex data and may not bump the host
|
|
386
|
+
// page's version, so re-run the update and force a full texture rebind.
|
|
387
|
+
let merged = false;
|
|
388
|
+
let mergeRetries = 0;
|
|
389
|
+
while (this._charAtlas && this._glyphRenderer.value.beginFrame() && mergeRetries++ < Constants.MERGE_RETRY_LIMIT) {
|
|
390
|
+
merged = true;
|
|
391
|
+
this._clearModel(true);
|
|
392
|
+
this._updateModel(0, this._terminal.rows - 1);
|
|
393
|
+
}
|
|
394
|
+
if (merged) {
|
|
395
|
+
this._glyphRenderer.value.invalidateAtlasTextures();
|
|
396
|
+
}
|
|
397
|
+
|
|
356
398
|
// Render
|
|
357
399
|
this._rectangleRenderer.value.renderBackgrounds();
|
|
358
400
|
this._glyphRenderer.value.render(this._model);
|
|
@@ -385,8 +427,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
385
427
|
let line: IBufferLine;
|
|
386
428
|
let joinedRanges: [number, number][];
|
|
387
429
|
let isJoined: boolean;
|
|
388
|
-
let skipJoinedCheckUntilX: number
|
|
389
|
-
let isValidJoinRange: boolean
|
|
430
|
+
let skipJoinedCheckUntilX: number;
|
|
431
|
+
let isValidJoinRange: boolean;
|
|
390
432
|
let lastCharX: number;
|
|
391
433
|
let range: [number, number];
|
|
392
434
|
let isCursorRow: boolean;
|
|
@@ -415,6 +457,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
415
457
|
for (y = start; y <= end; y++) {
|
|
416
458
|
row = y + terminal.buffer.ydisp;
|
|
417
459
|
line = terminal.buffer.lines.get(row)!;
|
|
460
|
+
let rowHasBlinkingCells = false;
|
|
418
461
|
this._model.lineLengths[y] = 0;
|
|
419
462
|
isCursorRow = cursorY === row;
|
|
420
463
|
skipJoinedCheckUntilX = 0;
|
|
@@ -470,10 +513,14 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
470
513
|
|
|
471
514
|
chars = cell.getChars();
|
|
472
515
|
code = cell.getCode();
|
|
473
|
-
i = ((y * terminal.cols) + x) *
|
|
516
|
+
i = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL;
|
|
517
|
+
|
|
518
|
+
if (!rowHasBlinkingCells && cell.isBlink()) {
|
|
519
|
+
rowHasBlinkingCells = true;
|
|
520
|
+
}
|
|
474
521
|
|
|
475
522
|
// Load colors/resolve overrides into work colors
|
|
476
|
-
this._cellColorResolver.resolve(cell, x, row, this.dimensions.device.cell.width);
|
|
523
|
+
this._cellColorResolver.resolve(cell, x, row, this.dimensions.device.cell.width, this.dimensions.device.cell.height);
|
|
477
524
|
|
|
478
525
|
// Override colors for cursor cell
|
|
479
526
|
if (isCursorVisible && row === cursorY) {
|
|
@@ -501,15 +548,19 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
501
548
|
}
|
|
502
549
|
}
|
|
503
550
|
|
|
551
|
+
if (this._textBlinkStateManager.isEnabled && !this._textBlinkStateManager.isBlinkOn && cell.isBlink()) {
|
|
552
|
+
this._cellColorResolver.result.fg |= FgFlags.INVISIBLE;
|
|
553
|
+
}
|
|
554
|
+
|
|
504
555
|
if (code !== NULL_CELL_CODE) {
|
|
505
556
|
this._model.lineLengths[y] = x + 1;
|
|
506
557
|
}
|
|
507
558
|
|
|
508
559
|
// Nothing has changed, no updates needed
|
|
509
560
|
if (this._model.cells[i] === code &&
|
|
510
|
-
this._model.cells[i +
|
|
511
|
-
this._model.cells[i +
|
|
512
|
-
this._model.cells[i +
|
|
561
|
+
this._model.cells[i + RenderModelConstants.BG_OFFSET] === this._cellColorResolver.result.bg &&
|
|
562
|
+
this._model.cells[i + RenderModelConstants.FG_OFFSET] === this._cellColorResolver.result.fg &&
|
|
563
|
+
this._model.cells[i + RenderModelConstants.EXT_OFFSET] === this._cellColorResolver.result.ext) {
|
|
513
564
|
continue;
|
|
514
565
|
}
|
|
515
566
|
|
|
@@ -522,9 +573,9 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
522
573
|
|
|
523
574
|
// Cache the results in the model
|
|
524
575
|
this._model.cells[i] = code;
|
|
525
|
-
this._model.cells[i +
|
|
526
|
-
this._model.cells[i +
|
|
527
|
-
this._model.cells[i +
|
|
576
|
+
this._model.cells[i + RenderModelConstants.BG_OFFSET] = this._cellColorResolver.result.bg;
|
|
577
|
+
this._model.cells[i + RenderModelConstants.FG_OFFSET] = this._cellColorResolver.result.fg;
|
|
578
|
+
this._model.cells[i + RenderModelConstants.EXT_OFFSET] = this._cellColorResolver.result.ext;
|
|
528
579
|
|
|
529
580
|
width = cell.getWidth();
|
|
530
581
|
this._glyphRenderer.value!.updateCell(x, y, code, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, chars, width, lastBg);
|
|
@@ -535,23 +586,43 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
535
586
|
|
|
536
587
|
// Null out non-first cells
|
|
537
588
|
for (x++; x <= lastCharX; x++) {
|
|
538
|
-
j = ((y * terminal.cols) + x) *
|
|
589
|
+
j = ((y * terminal.cols) + x) * RenderModelConstants.INDICIES_PER_CELL;
|
|
539
590
|
this._glyphRenderer.value!.updateCell(x, y, NULL_CELL_CODE, 0, 0, 0, NULL_CELL_CHAR, 0, 0);
|
|
540
591
|
this._model.cells[j] = NULL_CELL_CODE;
|
|
541
592
|
// Don't re-resolve the cell color since multi-colored ligature backgrounds are not
|
|
542
593
|
// supported
|
|
543
|
-
this._model.cells[j +
|
|
544
|
-
this._model.cells[j +
|
|
545
|
-
this._model.cells[j +
|
|
594
|
+
this._model.cells[j + RenderModelConstants.BG_OFFSET] = this._cellColorResolver.result.bg;
|
|
595
|
+
this._model.cells[j + RenderModelConstants.FG_OFFSET] = this._cellColorResolver.result.fg;
|
|
596
|
+
this._model.cells[j + RenderModelConstants.EXT_OFFSET] = this._cellColorResolver.result.ext;
|
|
546
597
|
}
|
|
547
598
|
x--; // Go back to the previous update cell for next iteration
|
|
548
599
|
}
|
|
549
600
|
}
|
|
601
|
+
this._setRowBlinkState(y, rowHasBlinkingCells);
|
|
550
602
|
}
|
|
551
603
|
if (modelUpdated) {
|
|
552
604
|
this._rectangleRenderer.value!.updateBackgrounds(this._model);
|
|
553
605
|
}
|
|
554
606
|
this._rectangleRenderer.value!.updateCursor(this._model);
|
|
607
|
+
this._updateTextBlinkState();
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private _resetBlinkingRowState(): void {
|
|
611
|
+
this._rowHasBlinkingCells = new Array(this._terminal.rows).fill(false);
|
|
612
|
+
this._rowHasBlinkingCellsCount = 0;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private _setRowBlinkState(row: number, hasBlinkingCells: boolean): void {
|
|
616
|
+
const previous = this._rowHasBlinkingCells[row];
|
|
617
|
+
if (previous === hasBlinkingCells) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
this._rowHasBlinkingCells[row] = hasBlinkingCells;
|
|
621
|
+
this._rowHasBlinkingCellsCount += hasBlinkingCells ? 1 : -1;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private _updateTextBlinkState(): void {
|
|
625
|
+
this._textBlinkStateManager.setNeedsBlinkInViewport(this._rowHasBlinkingCellsCount > 0);
|
|
555
626
|
}
|
|
556
627
|
|
|
557
628
|
/**
|
|
@@ -617,7 +688,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|
|
617
688
|
// the change as it's an exact multiple of the cell sizes.
|
|
618
689
|
this._canvas.width = width;
|
|
619
690
|
this._canvas.height = height;
|
|
620
|
-
|
|
691
|
+
// Render synchronously to avoid flicker when the canvas is cleared
|
|
692
|
+
this._onRequestRedraw.fire({ start: 0, end: this._terminal.rows - 1, sync: true });
|
|
621
693
|
}
|
|
622
694
|
|
|
623
695
|
private _requestRedrawViewport(): void {
|
package/src/WebglUtils.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
|
7
|
+
import type { ILogService } from 'common/services/Services';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* A matrix that when multiplies will translate 0-1 coordinates (left to right,
|
|
@@ -16,21 +17,21 @@ export const PROJECTION_MATRIX = new Float32Array([
|
|
|
16
17
|
-1, 1, 0, 1
|
|
17
18
|
]);
|
|
18
19
|
|
|
19
|
-
export function createProgram(gl: WebGLRenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram | undefined {
|
|
20
|
+
export function createProgram(gl: WebGLRenderingContext, vertexSource: string, fragmentSource: string, logService: ILogService): WebGLProgram | undefined {
|
|
20
21
|
const program = throwIfFalsy(gl.createProgram());
|
|
21
|
-
gl.attachShader(program, throwIfFalsy(createShader(gl, gl.VERTEX_SHADER, vertexSource)));
|
|
22
|
-
gl.attachShader(program, throwIfFalsy(createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)));
|
|
22
|
+
gl.attachShader(program, throwIfFalsy(createShader(gl, gl.VERTEX_SHADER, vertexSource, logService)));
|
|
23
|
+
gl.attachShader(program, throwIfFalsy(createShader(gl, gl.FRAGMENT_SHADER, fragmentSource, logService)));
|
|
23
24
|
gl.linkProgram(program);
|
|
24
25
|
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
|
|
25
26
|
if (success) {
|
|
26
27
|
return program;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
logService.error(gl.getProgramInfoLog(program));
|
|
30
31
|
gl.deleteProgram(program);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
export function createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | undefined {
|
|
34
|
+
export function createShader(gl: WebGLRenderingContext, type: number, source: string, logService: ILogService): WebGLShader | undefined {
|
|
34
35
|
const shader = throwIfFalsy(gl.createShader(type));
|
|
35
36
|
gl.shaderSource(shader, source);
|
|
36
37
|
gl.compileShader(shader);
|
|
@@ -39,7 +40,7 @@ export function createShader(gl: WebGLRenderingContext, type: number, source: st
|
|
|
39
40
|
return shader;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
logService.error(gl.getShaderInfoLog(shader));
|
|
43
44
|
gl.deleteShader(shader);
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -5,7 +5,36 @@
|
|
|
5
5
|
|
|
6
6
|
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphCharacterDefinition, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition } from './Types';
|
|
7
7
|
|
|
8
|
-
/*
|
|
8
|
+
/* oxlint-disable @stylistic/max-len -- generated glyph path data */
|
|
9
|
+
|
|
10
|
+
const enum Shapes {
|
|
11
|
+
/** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1',
|
|
12
|
+
/** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5',
|
|
13
|
+
|
|
14
|
+
/** └ */ TOP_TO_RIGHT = 'M.5,0 L.5,.5 L1,.5',
|
|
15
|
+
/** ┘ */ TOP_TO_LEFT = 'M.5,0 L.5,.5 L0,.5',
|
|
16
|
+
/** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1',
|
|
17
|
+
/** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5',
|
|
18
|
+
|
|
19
|
+
/** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L.5,0',
|
|
20
|
+
/** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L0,.5',
|
|
21
|
+
/** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5',
|
|
22
|
+
/** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1',
|
|
23
|
+
|
|
24
|
+
/** ┴ */ T_TOP = 'M0,.5 L1,.5 M.5,.5 L.5,0',
|
|
25
|
+
/** ┤ */ T_LEFT = 'M.5,0 L.5,1 M.5,.5 L0,.5',
|
|
26
|
+
/** ├ */ T_RIGHT = 'M.5,0 L.5,1 M.5,.5 L1,.5',
|
|
27
|
+
/** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1',
|
|
28
|
+
|
|
29
|
+
/** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1',
|
|
30
|
+
|
|
31
|
+
/** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', // .2 empty, .3 filled
|
|
32
|
+
/** ┄ */ THREE_DASHES_HORIZONTAL = 'M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5', // .1333 empty, .2 filled
|
|
33
|
+
/** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5', // .1 empty, .15 filled
|
|
34
|
+
/** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 L.5,.4 M.5,.6 L.5,.9',
|
|
35
|
+
/** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333',
|
|
36
|
+
/** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95',
|
|
37
|
+
}
|
|
9
38
|
|
|
10
39
|
namespace GitBranchSymbolsParts {
|
|
11
40
|
// Lines
|
|
@@ -324,6 +353,29 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi
|
|
|
324
353
|
|
|
325
354
|
// #endregion
|
|
326
355
|
|
|
356
|
+
// #region Progress Indicators (EE00-EE0B)
|
|
357
|
+
|
|
358
|
+
// initially added in Fira Code and later Nerd Fonts
|
|
359
|
+
// https://github.com/ryanoasis/nerd-fonts/pull/1733
|
|
360
|
+
|
|
361
|
+
// Progress bars (EE00-EE05)
|
|
362
|
+
'\u{EE00}': { type: CustomGlyphDefinitionType.PATH, data: 'M0,0 L1,0 L1,.05 L.1,.05 L.1,.95 L1,.95 L1,1 L0,1 Z' }, // PROGRESS BAR EMPTY START
|
|
363
|
+
'\u{EE01}': { type: CustomGlyphDefinitionType.PATH, data: 'M0,0 L1,0 L1,.05 L0,.05 Z M0,.95 L1,.95 L1,1 L0,1 Z' }, // PROGRESS BAR EMPTY MIDDLE
|
|
364
|
+
'\u{EE02}': { type: CustomGlyphDefinitionType.PATH, data: 'M1,0 L0,0 L0,.05 L.9,.05 L.9,.95 L0,.95 L0,1 L1,1 Z' }, // PROGRESS BAR EMPTY END
|
|
365
|
+
'\u{EE03}': { type: CustomGlyphDefinitionType.PATH, data: 'M0,0 L1,0 L1,.05 L.1,.05 L.1,.95 L1,.95 L1,1 L0,1 Z M.25,.15 L1,.15 L1,.85 L.25,.85 Z' }, // PROGRESS BAR FILLED START
|
|
366
|
+
'\u{EE04}': { type: CustomGlyphDefinitionType.PATH, data: 'M0,0 L1,0 L1,.05 L0,.05 Z M0,.95 L1,.95 L1,1 L0,1 Z M0,.15 L1,.15 L1,.85 L0,.85 Z' }, // PROGRESS BAR FILLED MIDDLE
|
|
367
|
+
'\u{EE05}': { type: CustomGlyphDefinitionType.PATH, data: 'M1,0 L0,0 L0,.05 L.9,.05 L.9,.95 L0,.95 L0,1 L1,1 Z M0,.15 L.75,.15 L.75,.85 L0,.85 Z' }, // PROGRESS BAR FILLED END
|
|
368
|
+
|
|
369
|
+
// Progress spinners (EE06-EE0B) - 6-frame spinner animation using stroked arcs
|
|
370
|
+
'\u{EE06}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0.6574,0.303 Q0.623,0.291,0.5852,0.285 T0.5082,0.279 T0.4311,0.285 T0.359,0.303 L0.3082,0.248 Q0.3525,0.232,0.4041,0.2235 T0.5082,0.215 T0.6123,0.2235 T0.7082,0.248 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // SPINNER FRAME 1 (12 o'clock)
|
|
371
|
+
'\u{EE07}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0.8557,0.582 L0.7656,0.551 Q0.7852,0.53,0.7951,0.507 T0.8049,0.46 Q0.8049,0.424,0.782,0.3905 T0.718,0.332 T0.6221,0.293 T0.5082,0.279 L0.5082,0.215 Q0.5607,0.215,0.6123,0.2235 T0.709,0.248 T0.7918,0.287 T0.8557,0.3375 T0.8959,0.3965 T0.9098,0.46 T0.8959,0.5235 T0.8557,0.582 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // SPINNER FRAME 2 (2 o'clock)
|
|
372
|
+
'\u{EE08}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0.5082,0.705 Q0.482,0.705,0.4557,0.703 T0.4049,0.697 L0.4311,0.635 Q0.4508,0.638,0.4697,0.6395 T0.5082,0.641 Q0.5672,0.641,0.6221,0.627 T0.718,0.588 T0.782,0.5295 T0.8049,0.46 Q0.8049,0.436,0.7951,0.413 T0.7656,0.369 L0.8557,0.338 Q0.882,0.365,0.8959,0.3965 T0.9098,0.46 T0.8959,0.5235 T0.8557,0.5825 T0.7918,0.633 T0.709,0.672 T0.6123,0.6965 T0.5082,0.705 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // SPINNER FRAME 3 (4 o'clock)
|
|
373
|
+
'\u{EE09}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0.5082,0.705 Q0.4557,0.705,0.4041,0.6965 T0.3074,0.672 T0.2246,0.633 T0.1607,0.5825 T0.1205,0.5235 T0.1066,0.46 L0.2115,0.46 Q0.2115,0.496,0.2344,0.5295 T0.2984,0.588 T0.3943,0.627 T0.5082,0.641 T0.6221,0.627 T0.718,0.588 T0.782,0.5295 T0.8049,0.46 L0.9098,0.46 Q0.9098,0.492,0.8959,0.5235 T0.8557,0.5825 T0.7918,0.633 T0.709,0.672 T0.6123,0.6965 T0.5082,0.705 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // SPINNER FRAME 4 (6 o'clock)
|
|
374
|
+
'\u{EE0A}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0.5082,0.705 Q0.4557,0.705,0.4041,0.6965 T0.3074,0.672 T0.2246,0.633 T0.1607,0.5825 T0.1205,0.5235 T0.1066,0.46 T0.1205,0.3965 T0.1607,0.338 L0.2508,0.369 Q0.2311,0.39,0.2213,0.413 T0.2115,0.46 Q0.2115,0.496,0.2344,0.5295 T0.2984,0.588 T0.3943,0.627 T0.5082,0.641 Q0.5279,0.641,0.5467,0.6395 T0.5852,0.635 L0.6115,0.697 Q0.5869,0.701,0.5607,0.703 T0.5082,0.705 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // SPINNER FRAME 5 (8 o'clock)
|
|
375
|
+
'\u{EE0B}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0.1607,0.582 Q0.1344,0.555,0.1205,0.5235 T0.1066,0.46 T0.1205,0.3965 T0.1607,0.3375 T0.2246,0.287 T0.3074,0.248 T0.4041,0.2235 T0.5082,0.215 L0.5082,0.279 Q0.4492,0.279,0.3943,0.293 T0.2984,0.332 T0.2344,0.3905 T0.2115,0.46 Q0.2115,0.484,0.2213,0.507 T0.2508,0.551 Z', type: CustomGlyphVectorType.FILL }, scaleType: CustomGlyphScaleType.CHAR }, // SPINNER FRAME 6 (10 o'clock)
|
|
376
|
+
|
|
377
|
+
// #endregion
|
|
378
|
+
|
|
327
379
|
// #region Git Branch Symbols (F5D0-F60D)
|
|
328
380
|
|
|
329
381
|
// Initially added in Kitty (https://github.com/kovidgoyal/kitty/pull/7681)
|
|
@@ -621,8 +673,8 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi
|
|
|
621
673
|
] },
|
|
622
674
|
|
|
623
675
|
// Diagonal fill characters (1FB98-1FB99)
|
|
624
|
-
'\u{1FB98}': { type: CustomGlyphDefinitionType.PATH_FUNCTION, data: '
|
|
625
|
-
'\u{1FB99}': { type: CustomGlyphDefinitionType.PATH_FUNCTION, data: '
|
|
676
|
+
'\u{1FB98}': { type: CustomGlyphDefinitionType.PATH_FUNCTION, data: 'M-0.25,-0.25 L1.25,1.25 M-0.25,0 L1,1.25 M-0.25,0.25 L0.75,1.25 M-0.25,0.5 L0.5,1.25 M0,-0.25 L1.25,1 M0.25,-0.25 L1.25,0.75 M0.5,-0.25 L1.25,0.5 M-0.25,0.75 L0.25,1.25 M0.75,-0.25 L1.25,0.25', strokeWidth: 1 }, // UPPER LEFT TO LOWER RIGHT FILL
|
|
677
|
+
'\u{1FB99}': { type: CustomGlyphDefinitionType.PATH_FUNCTION, data: 'M-0.25,0.5 L0.5,-0.25 M-0.25,0.75 L0.75,-0.25 M-0.25,1 L1,-0.25 M-0.25,1.25 L1.25,-0.25 M0,1.25 L1.25,0 M0.25,1.25 L1.25,0.25 M0.5,1.25 L1.25,0.5 M-0.25,0.25 L0.25,-0.25 M0.75,1.25 L1.25,0.75', strokeWidth: 1 }, // UPPER RIGHT TO LOWER LEFT FILL
|
|
626
678
|
|
|
627
679
|
// Smooth mosaic terminal graphic characters (1FB9A-1FB9B)
|
|
628
680
|
'\u{1FB9A}': { type: CustomGlyphDefinitionType.VECTOR_SHAPE, data: { d: 'M0,0 L.5,.5 L0,1 L1,1 L.5,.5 L1,0', type: CustomGlyphVectorType.FILL } }, // UPPER AND LOWER TRIANGULAR HALF BLOCK
|
|
@@ -797,6 +849,27 @@ export const customGlyphDefinitions: { [index: string]: CustomGlyphCharacterDefi
|
|
|
797
849
|
// #endregion
|
|
798
850
|
};
|
|
799
851
|
|
|
852
|
+
export const blockPatternCodepoints = new Set<number>([
|
|
853
|
+
// Shade characters (2591-2593)
|
|
854
|
+
0x2591,
|
|
855
|
+
0x2592,
|
|
856
|
+
0x2593,
|
|
857
|
+
// Rectangular shade characters (1FB8C-1FB94)
|
|
858
|
+
0x1FB8C,
|
|
859
|
+
0x1FB8D,
|
|
860
|
+
0x1FB8E,
|
|
861
|
+
0x1FB8F,
|
|
862
|
+
0x1FB90,
|
|
863
|
+
0x1FB91,
|
|
864
|
+
0x1FB92,
|
|
865
|
+
0x1FB94,
|
|
866
|
+
// Triangular shade characters (1FB9C-1FB9F)
|
|
867
|
+
0x1FB9C,
|
|
868
|
+
0x1FB9D,
|
|
869
|
+
0x1FB9E,
|
|
870
|
+
0x1FB9F
|
|
871
|
+
]);
|
|
872
|
+
|
|
800
873
|
/**
|
|
801
874
|
* Generates a drawing function for sextant characters. Sextants are a 2x3 grid where each cell
|
|
802
875
|
* can be on or off.
|
|
@@ -944,31 +1017,3 @@ function segmentedDigit(pattern: number): string {
|
|
|
944
1017
|
return paths.join(' ');
|
|
945
1018
|
}
|
|
946
1019
|
|
|
947
|
-
const enum Shapes {
|
|
948
|
-
/** │ */ TOP_TO_BOTTOM = 'M.5,0 L.5,1',
|
|
949
|
-
/** ─ */ LEFT_TO_RIGHT = 'M0,.5 L1,.5',
|
|
950
|
-
|
|
951
|
-
/** └ */ TOP_TO_RIGHT = 'M.5,0 L.5,.5 L1,.5',
|
|
952
|
-
/** ┘ */ TOP_TO_LEFT = 'M.5,0 L.5,.5 L0,.5',
|
|
953
|
-
/** ┐ */ LEFT_TO_BOTTOM = 'M0,.5 L.5,.5 L.5,1',
|
|
954
|
-
/** ┌ */ RIGHT_TO_BOTTOM = 'M0.5,1 L.5,.5 L1,.5',
|
|
955
|
-
|
|
956
|
-
/** ╵ */ MIDDLE_TO_TOP = 'M.5,.5 L.5,0',
|
|
957
|
-
/** ╴ */ MIDDLE_TO_LEFT = 'M.5,.5 L0,.5',
|
|
958
|
-
/** ╶ */ MIDDLE_TO_RIGHT = 'M.5,.5 L1,.5',
|
|
959
|
-
/** ╷ */ MIDDLE_TO_BOTTOM = 'M.5,.5 L.5,1',
|
|
960
|
-
|
|
961
|
-
/** ┴ */ T_TOP = 'M0,.5 L1,.5 M.5,.5 L.5,0',
|
|
962
|
-
/** ┤ */ T_LEFT = 'M.5,0 L.5,1 M.5,.5 L0,.5',
|
|
963
|
-
/** ├ */ T_RIGHT = 'M.5,0 L.5,1 M.5,.5 L1,.5',
|
|
964
|
-
/** ┬ */ T_BOTTOM = 'M0,.5 L1,.5 M.5,.5 L.5,1',
|
|
965
|
-
|
|
966
|
-
/** ┼ */ CROSS = 'M0,.5 L1,.5 M.5,0 L.5,1',
|
|
967
|
-
|
|
968
|
-
/** ╌ */ TWO_DASHES_HORIZONTAL = 'M.1,.5 L.4,.5 M.6,.5 L.9,.5', // .2 empty, .3 filled
|
|
969
|
-
/** ┄ */ THREE_DASHES_HORIZONTAL = 'M.0667,.5 L.2667,.5 M.4,.5 L.6,.5 M.7333,.5 L.9333,.5', // .1333 empty, .2 filled
|
|
970
|
-
/** ┉ */ FOUR_DASHES_HORIZONTAL = 'M.05,.5 L.2,.5 M.3,.5 L.45,.5 M.55,.5 L.7,.5 M.8,.5 L.95,.5', // .1 empty, .15 filled
|
|
971
|
-
/** ╎ */ TWO_DASHES_VERTICAL = 'M.5,.1 L.5,.4 M.5,.6 L.5,.9',
|
|
972
|
-
/** ┆ */ THREE_DASHES_VERTICAL = 'M.5,.0667 L.5,.2667 M.5,.4 L.5,.6 M.5,.7333 L.5,.9333',
|
|
973
|
-
/** ┊ */ FOUR_DASHES_VERTICAL = 'M.5,.05 L.5,.2 M.5,.3 L.5,.45 L.5,.55 M.5,.7 L.5,.95',
|
|
974
|
-
}
|