diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 29e97d6d..75b6230c 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -230,7 +230,7 @@ export class WebglRenderer extends Disposable implements IRenderer { return; } - const atlas = acquireCharAtlas(this._terminal, this._colors, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight); + const atlas = acquireCharAtlas(this._terminal, this._colors, this.dimensions.scaledCellWidth, this.dimensions.scaledCellHeight, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight); if (!('getRasterizedGlyph' in atlas)) { throw new Error('The webgl renderer only works with the webgl char atlas'); } diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts index 5046006f..41114de0 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts @@ -28,10 +28,12 @@ const charAtlasCache: ICharAtlasCacheEntry[] = []; export function acquireCharAtlas( terminal: Terminal, colors: IColorSet, + scaledCellWidth: number, + scaledCellHeight: number, scaledCharWidth: number, scaledCharHeight: number ): WebglCharAtlas { - const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors); + const newConfig = generateConfig(scaledCellWidth, scaledCellHeight, scaledCharWidth, scaledCharHeight, terminal, colors); // Check to see if the terminal already owns this config for (let i = 0; i < charAtlasCache.length; i++) { diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 5496a500..e91c5fd1 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -13,7 +13,7 @@ const NULL_COLOR: IColor = { rgba: 0 }; -export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig { +export function generateConfig(scaledCellWidth: number, scaledCellHeight: number, scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig { // null out some fields that don't matter const clonedColors: IColorSet = { foreground: colors.foreground, @@ -28,7 +28,10 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number contrastCache: colors.contrastCache }; return { + customBlockAndBoxCharacters: terminal.getOption('customBlockAndBoxCharacters'), devicePixelRatio: window.devicePixelRatio, + scaledCellWidth, + scaledCellHeight, scaledCharWidth, scaledCharHeight, fontFamily: terminal.getOption('fontFamily'), diff --git a/addons/xterm-addon-webgl/src/atlas/Types.d.ts b/addons/xterm-addon-webgl/src/atlas/Types.d.ts index cd73393c..37384306 100644 --- a/addons/xterm-addon-webgl/src/atlas/Types.d.ts +++ b/addons/xterm-addon-webgl/src/atlas/Types.d.ts @@ -17,11 +17,14 @@ export interface IGlyphIdentifier { } export interface ICharAtlasConfig { + customBlockAndBoxCharacters: boolean; devicePixelRatio: number; fontSize: number; fontFamily: string; fontWeight: FontWeight; fontWeightBold: FontWeight; + scaledCellWidth: number; + scaledCellHeight: number; scaledCharWidth: number; scaledCharHeight: number; allowTransparency: boolean; diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 5f729e28..8fd43e1e 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -12,6 +12,7 @@ import { IColor } from 'browser/Types'; import { IDisposable } from 'xterm'; import { AttributeData } from 'common/buffer/AttributeData'; import { channels, rgba } from 'browser/Color'; +import { tryDrawCustomChar } from 'browser/renderer/BoxAndBlockCharacters'; // In practice we're probably never going to exhaust a texture this large. For debugging purposes, // however, it can be useful to set this to a really tiny value, to verify that LRU eviction works. @@ -390,8 +391,16 @@ export class WebglCharAtlas implements IDisposable { // For powerline glyphs left/top padding is excluded (https://github.com/microsoft/vscode/issues/120129) const padding = isPowerlineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING; + // Draw custom characters if applicable + let drawSuccess = false; + if (this._config.customBlockAndBoxCharacters !== false) { + drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING, this._config.scaledCellWidth, this._config.scaledCellHeight, this._config.scaledCharWidth, this._config.scaledCharHeight); + } + // Draw the character - this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight); + if (!drawSuccess) { + this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight); + } // Draw underline and strikethrough if (underline || strikethrough) { diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index cc210fd3..532836ee 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -92,7 +92,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) { return; } - this._charAtlas = acquireCharAtlas(terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight); + this._charAtlas = acquireCharAtlas(terminal, colorSet, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharWidth, this._scaledCharHeight); this._charAtlas.warmUp(); } diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index e702e61e..3ab343da 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -224,6 +224,7 @@ export class Terminal extends CoreTerminal implements ITerminal { // The DOM renderer needs a row refresh to update the cursor styles this.refresh(this.buffer.y, this.buffer.y); break; + case 'customBlockAndBoxCharacters': case 'drawBoldTextInBrightColors': case 'letterSpacing': case 'lineHeight': diff --git a/src/browser/renderer/BaseRenderLayer.ts b/src/browser/renderer/BaseRenderLayer.ts index e7116ed6..afa12bb2 100644 --- a/src/browser/renderer/BaseRenderLayer.ts +++ b/src/browser/renderer/BaseRenderLayer.ts @@ -264,7 +264,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.options.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x, y, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); } // Draw the character @@ -388,7 +388,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.options.customBlockAndBoxCharacters !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x, y, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharLeft, this._scaledCharTop); } // Draw the character diff --git a/src/browser/renderer/BoxAndBlockCharacters.ts b/src/browser/renderer/BoxAndBlockCharacters.ts index fd897675..b38199ad 100644 --- a/src/browser/renderer/BoxAndBlockCharacters.ts +++ b/src/browser/renderer/BoxAndBlockCharacters.ts @@ -288,8 +288,8 @@ export const boxDrawingDefinitions: { [character: string]: { [fontWeight: number export function tryDrawCustomChar( ctx: CanvasRenderingContext2D, c: string, - x: number, - y: number, + xOffset: number, + yOffset: number, scaledCellWidth: number, scaledCellHeight: number, scaledCharLeft: number, @@ -297,13 +297,13 @@ export function tryDrawCustomChar( ): boolean { const blockElementDefinition = blockElementDefinitions[c]; if (blockElementDefinition) { - drawBlockElementChar(ctx, blockElementDefinition, x, y, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); + drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight, scaledCharLeft, scaledCharTop); return true; } const boxDrawingDefinition = boxDrawingDefinitions[c]; if (boxDrawingDefinition) { - drawBoxDrawingChar(ctx, boxDrawingDefinition, x, y, scaledCellWidth, scaledCellHeight); + drawBoxDrawingChar(ctx, boxDrawingDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); return true; } @@ -313,15 +313,16 @@ export function tryDrawCustomChar( function drawBlockElementChar( ctx: CanvasRenderingContext2D, charDefinition: IBlockVector[], - x: number, - y: number, + xOffset: number, + yOffset: number, scaledCellWidth: number, scaledCellHeight: number, scaledCharLeft: number, scaledCharTop: number ): void { - const xOffset = x * scaledCellWidth + scaledCharLeft; - const yOffset = y * scaledCellHeight + scaledCharTop; + // TODO: Scale to cell not char? + xOffset += scaledCharLeft; + yOffset += scaledCharTop; for (let i = 0; i < charDefinition.length; i++) { const box = charDefinition[i]; const xEighth = scaledCellWidth / 8; @@ -378,13 +379,11 @@ function drawBlockElementChar( function drawBoxDrawingChar( ctx: CanvasRenderingContext2D, charDefinition: { [fontWeight: number]: string | ((xp: number, yp: number) => string) }, - x: number, - y: number, + xOffset: number, + yOffset: number, scaledCellWidth: number, scaledCellHeight: number ): void { - const xOffset = x * scaledCellWidth; - const yOffset = y * scaledCellHeight; ctx.strokeStyle = ctx.fillStyle; for (const [fontWeight, instructions] of Object.entries(charDefinition)) { ctx.beginPath();