@xterm/addon-webgl 0.20.0-beta.17 → 0.20.0-beta.170
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 +5 -2
- package/src/CharAtlasCache.ts +3 -1
- package/src/CursorBlinkStateManager.ts +67 -8
- package/src/DevicePixelObserver.ts +1 -1
- package/src/GlyphRenderer.ts +3 -3
- package/src/RectangleRenderer.ts +1 -1
- package/src/TextureAtlas.ts +76 -55
- package/src/Types.ts +3 -3
- package/src/WebglAddon.ts +8 -14
- package/src/WebglRenderer.ts +61 -9
- package/src/customGlyphs/CustomGlyphDefinitions.ts +230 -64
- package/src/customGlyphs/CustomGlyphRasterizer.ts +68 -23
- package/src/customGlyphs/Types.ts +16 -0
- package/src/renderLayer/BaseRenderLayer.ts +1 -1
- package/typings/addon-webgl.d.ts +12 -7
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
|
7
7
|
import { customGlyphDefinitions } from './CustomGlyphDefinitions';
|
|
8
|
-
import { CustomGlyphDefinitionType, CustomGlyphVectorType, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types';
|
|
8
|
+
import { CustomGlyphDefinitionType, CustomGlyphScaleType, CustomGlyphVectorType, type CustomGlyphDefinitionPart, type CustomGlyphPathDrawFunctionDefinition, type CustomGlyphPatternDefinition, type ICustomGlyphSolidOctantBlockVector, type ICustomGlyphVectorShape } from './Types';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Try drawing a custom block element or box drawing character, returning whether it was
|
|
@@ -18,16 +18,19 @@ export function tryDrawCustomGlyph(
|
|
|
18
18
|
yOffset: number,
|
|
19
19
|
deviceCellWidth: number,
|
|
20
20
|
deviceCellHeight: number,
|
|
21
|
+
deviceCharWidth: number,
|
|
22
|
+
deviceCharHeight: number,
|
|
21
23
|
fontSize: number,
|
|
22
24
|
devicePixelRatio: number,
|
|
23
|
-
backgroundColor?: string
|
|
25
|
+
backgroundColor?: string,
|
|
26
|
+
variantOffset: number = 0
|
|
24
27
|
): boolean {
|
|
25
28
|
const unifiedCharDefinition = customGlyphDefinitions[c];
|
|
26
29
|
if (unifiedCharDefinition) {
|
|
27
30
|
// Normalize to array for uniform handling
|
|
28
31
|
const parts = Array.isArray(unifiedCharDefinition) ? unifiedCharDefinition : [unifiedCharDefinition];
|
|
29
32
|
for (const part of parts) {
|
|
30
|
-
drawDefinitionPart(ctx, part, xOffset, yOffset, deviceCellWidth, deviceCellHeight, fontSize, devicePixelRatio, backgroundColor);
|
|
33
|
+
drawDefinitionPart(ctx, part, xOffset, yOffset, deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, fontSize, devicePixelRatio, backgroundColor, variantOffset);
|
|
31
34
|
}
|
|
32
35
|
return true;
|
|
33
36
|
}
|
|
@@ -42,37 +45,53 @@ function drawDefinitionPart(
|
|
|
42
45
|
yOffset: number,
|
|
43
46
|
deviceCellWidth: number,
|
|
44
47
|
deviceCellHeight: number,
|
|
48
|
+
deviceCharWidth: number,
|
|
49
|
+
deviceCharHeight: number,
|
|
45
50
|
fontSize: number,
|
|
46
51
|
devicePixelRatio: number,
|
|
47
|
-
backgroundColor?: string
|
|
52
|
+
backgroundColor?: string,
|
|
53
|
+
variantOffset: number = 0
|
|
48
54
|
): void {
|
|
55
|
+
// Handle scaleType - adjust dimensions and offset when scaling to character area
|
|
56
|
+
let drawWidth = deviceCellWidth;
|
|
57
|
+
let drawHeight = deviceCellHeight;
|
|
58
|
+
let drawXOffset = xOffset;
|
|
59
|
+
let drawYOffset = yOffset;
|
|
60
|
+
if (part.scaleType === CustomGlyphScaleType.CHAR) {
|
|
61
|
+
drawWidth = deviceCharWidth;
|
|
62
|
+
drawHeight = deviceCharHeight;
|
|
63
|
+
// Center the character within the cell
|
|
64
|
+
drawXOffset = xOffset + (deviceCellWidth - deviceCharWidth) / 2;
|
|
65
|
+
drawYOffset = yOffset + (deviceCellHeight - deviceCharHeight) / 2;
|
|
66
|
+
}
|
|
67
|
+
|
|
49
68
|
// Handle clipPath generically for any definition type
|
|
50
69
|
if (part.clipPath) {
|
|
51
70
|
ctx.save();
|
|
52
|
-
applyClipPath(ctx, part.clipPath,
|
|
71
|
+
applyClipPath(ctx, part.clipPath, drawXOffset, drawYOffset, drawWidth, drawHeight);
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
switch (part.type) {
|
|
56
75
|
case CustomGlyphDefinitionType.SOLID_OCTANT_BLOCK_VECTOR:
|
|
57
|
-
drawBlockVectorChar(ctx, part.data,
|
|
76
|
+
drawBlockVectorChar(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight);
|
|
58
77
|
break;
|
|
59
78
|
case CustomGlyphDefinitionType.BLOCK_PATTERN:
|
|
60
|
-
drawPatternChar(ctx, part.data,
|
|
79
|
+
drawPatternChar(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, variantOffset);
|
|
61
80
|
break;
|
|
62
81
|
case CustomGlyphDefinitionType.PATH_FUNCTION:
|
|
63
|
-
drawPathFunctionCharacter(ctx, part.data,
|
|
82
|
+
drawPathFunctionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, part.strokeWidth);
|
|
64
83
|
break;
|
|
65
84
|
case CustomGlyphDefinitionType.PATH:
|
|
66
|
-
drawPathDefinitionCharacter(ctx, part.data,
|
|
85
|
+
drawPathDefinitionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, part.strokeWidth);
|
|
67
86
|
break;
|
|
68
87
|
case CustomGlyphDefinitionType.PATH_NEGATIVE:
|
|
69
|
-
drawPathNegativeDefinitionCharacter(ctx, part.data,
|
|
88
|
+
drawPathNegativeDefinitionCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, devicePixelRatio, backgroundColor);
|
|
70
89
|
break;
|
|
71
90
|
case CustomGlyphDefinitionType.VECTOR_SHAPE:
|
|
72
|
-
drawVectorShape(ctx, part.data,
|
|
91
|
+
drawVectorShape(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight, fontSize, devicePixelRatio);
|
|
73
92
|
break;
|
|
74
93
|
case CustomGlyphDefinitionType.BRAILLE:
|
|
75
|
-
drawBrailleCharacter(ctx, part.data,
|
|
94
|
+
drawBrailleCharacter(ctx, part.data, drawXOffset, drawYOffset, drawWidth, drawHeight);
|
|
76
95
|
break;
|
|
77
96
|
}
|
|
78
97
|
|
|
@@ -154,7 +173,9 @@ function drawPathDefinitionCharacter(
|
|
|
154
173
|
xOffset: number,
|
|
155
174
|
yOffset: number,
|
|
156
175
|
deviceCellWidth: number,
|
|
157
|
-
deviceCellHeight: number
|
|
176
|
+
deviceCellHeight: number,
|
|
177
|
+
devicePixelRatio: number,
|
|
178
|
+
strokeWidth?: number
|
|
158
179
|
): void {
|
|
159
180
|
const instructions = typeof charDefinition === 'string' ? charDefinition : charDefinition(0, 0);
|
|
160
181
|
ctx.beginPath();
|
|
@@ -255,7 +276,13 @@ function drawPathDefinitionCharacter(
|
|
|
255
276
|
}
|
|
256
277
|
lastCommand = type;
|
|
257
278
|
}
|
|
258
|
-
|
|
279
|
+
if (strokeWidth !== undefined) {
|
|
280
|
+
ctx.strokeStyle = ctx.fillStyle;
|
|
281
|
+
ctx.lineWidth = devicePixelRatio * strokeWidth;
|
|
282
|
+
ctx.stroke();
|
|
283
|
+
} else {
|
|
284
|
+
ctx.fill();
|
|
285
|
+
}
|
|
259
286
|
}
|
|
260
287
|
|
|
261
288
|
/**
|
|
@@ -412,7 +439,8 @@ function drawPatternChar(
|
|
|
412
439
|
xOffset: number,
|
|
413
440
|
yOffset: number,
|
|
414
441
|
deviceCellWidth: number,
|
|
415
|
-
deviceCellHeight: number
|
|
442
|
+
deviceCellHeight: number,
|
|
443
|
+
variantOffset: number = 0
|
|
416
444
|
): void {
|
|
417
445
|
let patternSet = cachedPatterns.get(charDefinition);
|
|
418
446
|
if (!patternSet) {
|
|
@@ -461,6 +489,15 @@ function drawPatternChar(
|
|
|
461
489
|
pattern = throwIfFalsy(ctx.createPattern(tmpCanvas, null));
|
|
462
490
|
patternSet.set(fillStyle, pattern);
|
|
463
491
|
}
|
|
492
|
+
// Apply pattern offset to ensure seamless tiling across cells when cell dimensions are odd.
|
|
493
|
+
// variantOffset encodes: bit 1 = x pixel shift, bit 0 = y pixel shift.
|
|
494
|
+
const dx = (variantOffset >> 1) & 1;
|
|
495
|
+
const dy = variantOffset & 1;
|
|
496
|
+
if (dx !== 0 || dy !== 0) {
|
|
497
|
+
pattern.setTransform(new DOMMatrix().translateSelf(-dx, -dy));
|
|
498
|
+
} else {
|
|
499
|
+
pattern.setTransform(new DOMMatrix());
|
|
500
|
+
}
|
|
464
501
|
ctx.fillStyle = pattern;
|
|
465
502
|
ctx.fillRect(xOffset, yOffset, deviceCellWidth, deviceCellHeight);
|
|
466
503
|
}
|
|
@@ -475,6 +512,11 @@ function drawPathFunctionCharacter(
|
|
|
475
512
|
devicePixelRatio: number,
|
|
476
513
|
strokeWidth?: number
|
|
477
514
|
): void {
|
|
515
|
+
ctx.save();
|
|
516
|
+
ctx.beginPath();
|
|
517
|
+
ctx.rect(xOffset, yOffset, deviceCellWidth, deviceCellHeight);
|
|
518
|
+
ctx.clip();
|
|
519
|
+
|
|
478
520
|
ctx.beginPath();
|
|
479
521
|
let actualInstructions: string;
|
|
480
522
|
if (typeof charDefinition === 'function') {
|
|
@@ -501,7 +543,7 @@ function drawPathFunctionCharacter(
|
|
|
501
543
|
if (!args[0] || !args[1]) {
|
|
502
544
|
continue;
|
|
503
545
|
}
|
|
504
|
-
f(ctx, translateArgs(args, deviceCellWidth, deviceCellHeight, xOffset, yOffset, true, devicePixelRatio), state);
|
|
546
|
+
f(ctx, translateArgs(args, deviceCellWidth, deviceCellHeight, xOffset, yOffset, true, devicePixelRatio, 0, 0, false), state);
|
|
505
547
|
state.lastCommand = type;
|
|
506
548
|
}
|
|
507
549
|
if (strokeWidth !== undefined) {
|
|
@@ -512,6 +554,7 @@ function drawPathFunctionCharacter(
|
|
|
512
554
|
ctx.fill();
|
|
513
555
|
}
|
|
514
556
|
ctx.closePath();
|
|
557
|
+
ctx.restore();
|
|
515
558
|
}
|
|
516
559
|
|
|
517
560
|
/**
|
|
@@ -660,7 +703,7 @@ const svgToCanvasInstructionMap: { [index: string]: (ctx: CanvasRenderingContext
|
|
|
660
703
|
}
|
|
661
704
|
};
|
|
662
705
|
|
|
663
|
-
function translateArgs(args: string[], cellWidth: number, cellHeight: number, xOffset: number, yOffset: number, doClamp: boolean, devicePixelRatio: number, leftPadding: number = 0, rightPadding: number = 0): number[] {
|
|
706
|
+
function translateArgs(args: string[], cellWidth: number, cellHeight: number, xOffset: number, yOffset: number, doClamp: boolean, devicePixelRatio: number, leftPadding: number = 0, rightPadding: number = 0, clampToCell: boolean = true): number[] {
|
|
664
707
|
const result = args.map(e => parseFloat(e) || parseInt(e));
|
|
665
708
|
|
|
666
709
|
if (result.length < 2) {
|
|
@@ -670,10 +713,11 @@ function translateArgs(args: string[], cellWidth: number, cellHeight: number, xO
|
|
|
670
713
|
for (let x = 0; x < result.length; x += 2) {
|
|
671
714
|
// Translate from 0-1 to 0-cellWidth
|
|
672
715
|
result[x] *= cellWidth - (leftPadding * devicePixelRatio) - (rightPadding * devicePixelRatio);
|
|
673
|
-
//
|
|
674
|
-
//
|
|
716
|
+
// Round to the nearest 0.5 to ensure a crisp line at 100% devicePixelRatio, and optionally
|
|
717
|
+
// clamp to the cell bounds.
|
|
675
718
|
if (doClamp && result[x] !== 0) {
|
|
676
|
-
|
|
719
|
+
const rounded = Math.round(result[x] + 0.5) - 0.5;
|
|
720
|
+
result[x] = clampToCell ? clamp(rounded, cellWidth, 0) : rounded;
|
|
677
721
|
}
|
|
678
722
|
// Apply the cell's offset (ie. x*cellWidth)
|
|
679
723
|
result[x] += xOffset + (leftPadding * devicePixelRatio);
|
|
@@ -682,10 +726,11 @@ function translateArgs(args: string[], cellWidth: number, cellHeight: number, xO
|
|
|
682
726
|
for (let y = 1; y < result.length; y += 2) {
|
|
683
727
|
// Translate from 0-1 to 0-cellHeight
|
|
684
728
|
result[y] *= cellHeight;
|
|
685
|
-
//
|
|
686
|
-
//
|
|
729
|
+
// Round to the nearest 0.5 to ensure a crisp line at 100% devicePixelRatio, and optionally
|
|
730
|
+
// clamp to the cell bounds.
|
|
687
731
|
if (doClamp && result[y] !== 0) {
|
|
688
|
-
|
|
732
|
+
const rounded = Math.round(result[y] + 0.5) - 0.5;
|
|
733
|
+
result[y] = clampToCell ? clamp(rounded, cellHeight, 0) : rounded;
|
|
689
734
|
}
|
|
690
735
|
// Apply the cell's offset (ie. x*cellHeight)
|
|
691
736
|
result[y] += yOffset;
|
|
@@ -50,6 +50,17 @@ export type CustomGlyphDefinitionPartRaw = (
|
|
|
50
50
|
{ type: CustomGlyphDefinitionType.BRAILLE, data: number }
|
|
51
51
|
);
|
|
52
52
|
|
|
53
|
+
export const enum CustomGlyphScaleType {
|
|
54
|
+
/**
|
|
55
|
+
* Scale to the entire cell, including letter spacing and line height.
|
|
56
|
+
*/
|
|
57
|
+
CELL,
|
|
58
|
+
/**
|
|
59
|
+
* Scale to only the character area, excluding letter spacing and line height.
|
|
60
|
+
*/
|
|
61
|
+
CHAR,
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
export interface ICustomGlyphDefinitionCommon {
|
|
54
65
|
/**
|
|
55
66
|
* A custom clip path for the draw definition, restricting the area it can draw to.
|
|
@@ -59,6 +70,11 @@ export interface ICustomGlyphDefinitionCommon {
|
|
|
59
70
|
* The stroke width to use when drawing the path. Defaults to 1.
|
|
60
71
|
*/
|
|
61
72
|
strokeWidth?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Defines how to scale the draw. Defaults to scaling to the full cell including letter spacing
|
|
75
|
+
* and line height.
|
|
76
|
+
*/
|
|
77
|
+
scaleType?: CustomGlyphScaleType;
|
|
62
78
|
}
|
|
63
79
|
|
|
64
80
|
export type CustomGlyphDefinitionPart = CustomGlyphDefinitionPartRaw & ICustomGlyphDefinitionCommon;
|
|
@@ -7,7 +7,7 @@ import { ReadonlyColorSet } from 'browser/Types';
|
|
|
7
7
|
import { acquireTextureAtlas } from '../CharAtlasCache';
|
|
8
8
|
import { IRenderDimensions } from 'browser/renderer/shared/Types';
|
|
9
9
|
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
|
|
10
|
-
import { Disposable, toDisposable } from '
|
|
10
|
+
import { Disposable, toDisposable } from 'common/Lifecycle';
|
|
11
11
|
import { CellData } from 'common/buffer/CellData';
|
|
12
12
|
import { IOptionsService } from 'common/services/Services';
|
|
13
13
|
import { Terminal } from '@xterm/xterm';
|
package/typings/addon-webgl.d.ts
CHANGED
|
@@ -57,21 +57,26 @@ declare module '@xterm/addon-webgl' {
|
|
|
57
57
|
* unicode ranges:
|
|
58
58
|
*
|
|
59
59
|
* - Box Drawing (U+2500-U+257F)
|
|
60
|
-
* -
|
|
60
|
+
* - Block Elements (U+2580-U+259F)
|
|
61
61
|
* - Braille Patterns (U+2800-U+28FF)
|
|
62
|
-
* - Powerline Symbols (U+E0A0
|
|
63
|
-
*
|
|
62
|
+
* - Powerline Symbols (U+E0A0-U+E0D4, Private Use Area with widespread
|
|
63
|
+
* adoption)
|
|
64
|
+
* - Progress Indicators (U+EE00-U+EE0B, Private Use Area initially added in
|
|
65
|
+
* [Fira Code](https://github.com/tonsky/FiraCode) and later
|
|
66
|
+
* [Nerd Fonts](https://github.com/ryanoasis/nerd-fonts/pull/1733)).
|
|
67
|
+
* - Git Branch Symbols (U+F5D0-U+F60D, Private Use Area initially adopted
|
|
68
|
+
* in [Kitty in 2024](https://github.com/kovidgoyal/kitty/pull/7681) by
|
|
69
|
+
* author of [vim-flog](https://github.com/rbong/vim-flog))
|
|
70
|
+
* - Symbols for Legacy Computing (U+1FB00-U+1FBFF)
|
|
64
71
|
*
|
|
65
72
|
* This will typically result in better rendering with continuous lines,
|
|
66
|
-
* even when line height and letter spacing is used.
|
|
67
|
-
* work with the DOM renderer which renders all characters using the font.
|
|
68
|
-
* The default is true.
|
|
73
|
+
* even when line height and letter spacing is used. The default is true.
|
|
69
74
|
*/
|
|
70
75
|
customGlyphs?: boolean;
|
|
71
76
|
|
|
72
77
|
/**
|
|
73
78
|
* Whether to enable the preserveDrawingBuffer flag when creating the WebGL
|
|
74
|
-
* context. This may be useful in tests. This
|
|
79
|
+
* context. This may be useful in tests. This default is false.
|
|
75
80
|
*/
|
|
76
81
|
preserveDrawingBuffer?: boolean
|
|
77
82
|
}
|