From 89f5c2e06caba9be8b0aedccc22762ee616a85f1 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Sun, 24 Jul 2022 09:30:13 +0000 Subject: [PATCH 01/24] Allow markers on the alt buffer --- src/browser/Terminal.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index bd82325d..9e41e5a4 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -1017,11 +1017,6 @@ export class Terminal extends CoreTerminal implements ITerminal { } public addMarker(cursorYOffset: number): IMarker | undefined { - // Disallow markers on the alt buffer - if (this.buffer !== this.buffers.normal) { - return; - } - return this.buffer.addMarker(this.buffer.ybase + this.buffer.y + cursorYOffset); } From dc30a51017dccc86b313039def5e3cb926ac36f6 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Sat, 30 Jul 2022 15:46:07 +0000 Subject: [PATCH 02/24] Apply row/col changes from xterm to xtmer-headless --- typings/xterm-headless.d.ts | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index d39a7098..04732cea 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -48,11 +48,6 @@ declare module 'xterm-headless' { */ convertEol?: boolean; - /** - * The number of columns in the terminal. - */ - cols?: number; - /** * Whether the cursor blinks. */ @@ -145,11 +140,6 @@ declare module 'xterm-headless' { */ rightClickSelectsWord?: boolean; - /** - * The number of rows in the terminal. - */ - rows?: number; - /** * Whether screen reader support is enabled. When on this will expose * supporting elements in the DOM to support NVDA on Windows and VoiceOver @@ -210,6 +200,22 @@ declare module 'xterm-headless' { windowOptions?: IWindowOptions; } + /** + * An object containing additional options for the terminal that can only be + * set on start up. + */ + export interface ITerminalInitOnlyOptions { + /** + * The number of columns in the terminal. + */ + cols?: number; + + /** + * The number of rows in the terminal. + */ + rows?: number; + } + /** * Contains colors to theme the terminal with. */ @@ -558,7 +564,7 @@ declare module 'xterm-headless' { * * @param options An object containing a set of options. */ - constructor(options?: ITerminalOptions); + constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions); /** * Adds an event listener for when the bell is triggered. From 027fffbadc2949d866208c973d8f7c19b1894144 Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Sat, 30 Jul 2022 15:48:49 +0000 Subject: [PATCH 03/24] Fix comment --- typings/xterm-headless.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typings/xterm-headless.d.ts b/typings/xterm-headless.d.ts index 04732cea..cda7ad1a 100644 --- a/typings/xterm-headless.d.ts +++ b/typings/xterm-headless.d.ts @@ -14,7 +14,7 @@ declare module 'xterm-headless' { export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off'; /** - * An object containing start up options for the terminal. + * An object containing options for the terminal. */ export interface ITerminalOptions { /** From c7122e8447beea0dac15cd25982f7cf68adc67a2 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 10:29:41 -0700 Subject: [PATCH 04/24] Fix dim flag applying to selection in webgl Fixes #3970 --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index d2d4f478..6616db6e 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -402,6 +402,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // override logic throughout the different sub-renderers let bgOverride: number | undefined; let fgOverride: number | undefined; + let isSelected: boolean = false; // Apply decorations on the bottom layer for (const d of this._decorationService.getDecorationsAtCell(x, y, 'bottom')) { @@ -414,7 +415,8 @@ export class WebglRenderer extends Disposable implements IRenderer { } // Apply the selection color if needed - if (this._isCellSelected(x, y)) { + isSelected = this._isCellSelected(x, y); + if (isSelected) { bgOverride = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF; if (this._colors.selectionForeground) { fgOverride = this._colors.selectionForeground.rgba >> 8 & 0xFFFFFF; @@ -434,8 +436,13 @@ export class WebglRenderer extends Disposable implements IRenderer { // Convert any overrides from rgba to the fg/bg packed format. This resolves the inverse flag // ahead of time in order to use the correct cache key if (bgOverride !== undefined) { - // Non-RGB attributes from model + override + force RGB color mode - bgOverride = (this._workCell.bg & ~Attributes.RGB_MASK) | bgOverride | Attributes.CM_RGB; + if (isSelected) { + // Non-RGB attributes from model + force non-dim + override + force RGB color mode + bgOverride = (this._workCell.bg & ~Attributes.RGB_MASK & ~BgFlags.DIM) | bgOverride | Attributes.CM_RGB; + } else { + // Non-RGB attributes from model + override + force RGB color mode + bgOverride = (this._workCell.bg & ~Attributes.RGB_MASK) | bgOverride | Attributes.CM_RGB; + } } if (fgOverride !== undefined) { // Non-RGB attributes from model + force disable inverse + override + force RGB color mode From 309487a020d6ac1d0cbb30d8bd2ef2648092ed2c Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 11:07:33 -0700 Subject: [PATCH 05/24] Fix character offset to respect texture padding in webgl Fixes #3974 --- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 12 ++++++------ demo/client.ts | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index e5f0fe6c..a7237c48 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -401,12 +401,12 @@ export class WebglCharAtlas implements IDisposable { `${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`; this._tmpCtx.textBaseline = TEXT_BASELINE; - const powerLineGlyph = chars.length === 1 && isPowerlineGlyph(chars.charCodeAt(0)); + const powerlineGlyph = chars.length === 1 && isPowerlineGlyph(chars.charCodeAt(0)); const foregroundColor = this._getForegroundColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, dim, bold, excludeFromContrastRatioDemands(chars.charCodeAt(0))); this._tmpCtx.fillStyle = foregroundColor.css; // For powerline glyphs left/top padding is excluded (https://github.com/microsoft/vscode/issues/120129) - const padding = powerLineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING * 2; + const padding = powerlineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING * 2; // Draw custom characters if applicable let drawSuccess = false; @@ -577,7 +577,7 @@ export class WebglCharAtlas implements IDisposable { return NULL_RASTERIZED_GLYPH; } - const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, powerLineGlyph, drawSuccess); + const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, powerlineGlyph, padding); const clippedImageData = this._clipImageData(imageData, this._workBoundingBox); // Check if there is enough room in the current row and go to next if needed @@ -610,7 +610,7 @@ export class WebglCharAtlas implements IDisposable { * @param imageData The image data to read. * @param boundingBox An IBoundingBox to put the clipped bounding box values. */ - private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, customGlyph: boolean): IRasterizedGlyph { + private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, padding: number): IRasterizedGlyph { boundingBox.top = 0; const height = restrictedGlyph ? this._config.scaledCellHeight : this._tmpCanvas.height; const width = restrictedGlyph ? this._config.scaledCharWidth : allowedWidth; @@ -685,8 +685,8 @@ export class WebglCharAtlas implements IDisposable { y: (boundingBox.bottom - boundingBox.top + 1) / TEXTURE_HEIGHT }, offset: { - x: -boundingBox.left + (restrictedGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING) + (customGlyph ? Math.floor(this._config.letterSpacing / 2) : 0), - y: -boundingBox.top + (restrictedGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING) + (customGlyph ? this._config.lineHeight === 1 ? 0 : Math.round((this._config.scaledCellHeight - this._config.scaledCharHeight) / 2) : 0) + x: -boundingBox.left + padding + (restrictedGlyph ? Math.floor(this._config.letterSpacing / 2) : 0), + y: -boundingBox.top + padding + (restrictedGlyph ? this._config.lineHeight === 1 ? 0 : Math.round((this._config.scaledCellHeight - this._config.scaledCharHeight) / 2) : 0) } }; } diff --git a/demo/client.ts b/demo/client.ts index 1c01a38a..dd3b4325 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -688,7 +688,7 @@ function powerlineSymbolTest() { ` 3 \ue0b1 \x1b[33;44m\ue0b0\x1b[39m` + ` 4 \ue0b1 \x1b[34;45m\ue0b0\x1b[39m` + ` 5 \ue0b1 \x1b[35;46m\ue0b0\x1b[39m` + - ` 6 \ue0b1 \x1b[36;47m\ue0b0\x1b[39m` + + ` 6 \ue0b1 \x1b[36;47m\ue0b0\x1b[30m` + ` 7 \ue0b1 \x1b[37;49m\ue0b0\x1b[0m` ); term.writeln(''); @@ -701,7 +701,7 @@ function powerlineSymbolTest() { ` 3 \ue0b3 \x1b[7;33;44m\ue0b2\x1b[27;39m` + ` 4 \ue0b3 \x1b[7;34;45m\ue0b2\x1b[27;39m` + ` 5 \ue0b3 \x1b[7;35;46m\ue0b2\x1b[27;39m` + - ` 6 \ue0b3 \x1b[7;36;47m\ue0b2\x1b[27;39m` + + ` 6 \ue0b3 \x1b[7;36;47m\ue0b2\x1b[27;30m` + ` 7 \ue0b3 \x1b[7;37;49m\ue0b2\x1b[0m` ); term.writeln(''); @@ -714,7 +714,7 @@ function powerlineSymbolTest() { ` 3 \ue0b5 \x1b[33;44m\ue0b4\x1b[39m` + ` 4 \ue0b5 \x1b[34;45m\ue0b4\x1b[39m` + ` 5 \ue0b5 \x1b[35;46m\ue0b4\x1b[39m` + - ` 6 \ue0b5 \x1b[36;47m\ue0b4\x1b[39m` + + ` 6 \ue0b5 \x1b[36;47m\ue0b4\x1b[30m` + ` 7 \ue0b5 \x1b[37;49m\ue0b4\x1b[0m` ); term.writeln(''); @@ -727,7 +727,7 @@ function powerlineSymbolTest() { ` 3 \ue0b7 \x1b[7;33;44m\ue0b6\x1b[27;39m` + ` 4 \ue0b7 \x1b[7;34;45m\ue0b6\x1b[27;39m` + ` 5 \ue0b7 \x1b[7;35;46m\ue0b6\x1b[27;39m` + - ` 6 \ue0b7 \x1b[7;36;47m\ue0b6\x1b[27;39m` + + ` 6 \ue0b7 \x1b[7;36;47m\ue0b6\x1b[27;30m` + ` 7 \ue0b7 \x1b[7;37;49m\ue0b6\x1b[0m` ); term.writeln(''); From ce4a85d07d23bc5e1d015b32e7c8283e07900280 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 17:52:00 -0700 Subject: [PATCH 06/24] Clip outline drawing near underline Fixes #3975 --- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index e5f0fe6c..bd8aa2ae 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -516,9 +516,17 @@ export class WebglCharAtlas implements IDisposable { // text if (!this._config.allowTransparency && chars !== ' ') { // This translates to 1/2 the line width in either direction + this._tmpCtx.save(); + // Clip the region to only draw in valid pixels near the underline to avoid a slight + // outline around the whole glyph, as well as additional pixels in the glyph at the top + // which would increase GPU memory demands + const clipRegion = new Path2D(); + clipRegion.rect(xLeft, yTop - Math.ceil(lineWidth / 2), this._config.scaledCellWidth, yBot - yTop + Math.ceil(lineWidth / 2)); + this._tmpCtx.clip(clipRegion); this._tmpCtx.lineWidth = window.devicePixelRatio * 3; this._tmpCtx.strokeStyle = backgroundColor.css; this._tmpCtx.strokeText(chars, padding, padding + this._config.scaledCharHeight); + this._tmpCtx.restore(); } } } From ed492f72536f28136ca7afcd883fa487dae044fc Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 19:24:09 -0700 Subject: [PATCH 07/24] Implement improved texture packing strategy Fixes #3977 --- .../src/atlas/WebglCharAtlas.ts | 108 ++++++++++++++---- 1 file changed, 84 insertions(+), 24 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index e5f0fe6c..008e65a8 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -45,6 +45,12 @@ const NULL_RASTERIZED_GLYPH: IRasterizedGlyph = { const TMP_CANVAS_GLYPH_PADDING = 2; +interface ICharAtlasActiveRow { + x: number; + y: number; + height: number; +} + export class WebglCharAtlas implements IDisposable { private _didWarmUp: boolean = false; @@ -59,13 +65,22 @@ export class WebglCharAtlas implements IDisposable { // A temporary context that glyphs are drawn to before being transfered to the atlas. private _tmpCtx: CanvasRenderingContext2D; - // Since glyphs are expected to be around the same height, the packing - // strategy used it to fill a row with glyphs while keeping track of the - // tallest glyph in the row. Once the row is full a new row is started at - // (0,lastRow+lastRowTallestGlyph). - private _currentRowY: number = 0; - private _currentRowX: number = 0; - private _currentRowHeight: number = 0; + // Texture atlas current positioning data. The texture packing strategy used is to fill from + // left-to-right and top-to-bottom. When the glyph being written is less than half of the current + // row's height, the following happens: + // + // - The current row becomes the fixed height row A + // - A new fixed height row B the exact size of the glyph is created below the current row + // - A new dynamic height current row is created below B + // + // This strategy does a good job preventing space being wasted for very short glyphs such as + // underscores, hyphens etc. or those with underlines rendered. + private _currentRow: ICharAtlasActiveRow = { + x: 0, + y: 0, + height: 0 + }; + private readonly _fixedRows: ICharAtlasActiveRow[] = []; public hasCanvasChanged = false; @@ -118,7 +133,7 @@ export class WebglCharAtlas implements IDisposable { } public beginFrame(): boolean { - if (this._currentRowY > TEXTURE_CAPACITY) { + if (this._currentRow.y > TEXTURE_CAPACITY) { this.clearTexture(); this.warmUp(); return true; @@ -127,15 +142,16 @@ export class WebglCharAtlas implements IDisposable { } public clearTexture(): void { - if (this._currentRowX === 0 && this._currentRowY === 0) { + if (this._currentRow.x === 0 && this._currentRow.y === 0) { return; } this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); this._cacheMap = {}; this._cacheMapCombined = {}; - this._currentRowHeight = 0; - this._currentRowX = 0; - this._currentRowY = 0; + this._currentRow.x = 0; + this._currentRow.y = 0; + this._currentRow.height = 0; + this._fixedRows.length = 0; this._didWarmUp = false; } @@ -580,22 +596,66 @@ export class WebglCharAtlas implements IDisposable { const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, powerLineGlyph, drawSuccess); const clippedImageData = this._clipImageData(imageData, this._workBoundingBox); - // Check if there is enough room in the current row and go to next if needed - if (this._currentRowX + rasterizedGlyph.size.x > TEXTURE_WIDTH) { - this._currentRowX = 0; - this._currentRowY += this._currentRowHeight; - this._currentRowHeight = 0; + // Find the best atlas row to use + let activeRow: ICharAtlasActiveRow; + while (true) { + // Select the ideal existing row, preferring fixed rows over the current row + activeRow = this._currentRow; + for (const row of this._fixedRows) { + if ((activeRow === this._currentRow || row.height < activeRow.height) && rasterizedGlyph.size.y <= row.height) { + activeRow = row; + } + } + + // Create a new one if vertical space would be wasted, fixing the previously active row in the + // process as it now has a fixed height + if (activeRow.height > rasterizedGlyph.size.y * 2) { + // Fix the current row as the new row is being added below + if (this._currentRow.height > 0) { + this._fixedRows.push(this._currentRow); + } + + // Create the new fixed height row + activeRow = { + x: 0, + y: this._currentRow.y + this._currentRow.height, + height: rasterizedGlyph.size.y + }; + this._fixedRows.push(activeRow); + + // Create the new current row below the new fixed height row + this._currentRow = { + x: 0, + y: activeRow.y + activeRow.height, + height: 0 + }; + } + + // Exit the loop if there is enough room in the row + if (activeRow.x + rasterizedGlyph.size.x <= TEXTURE_WIDTH) { + break; + } + + // If there is enough room in the current row, finish it and try again + if (activeRow === this._currentRow) { + activeRow.x = 0; + activeRow.y += activeRow.height; + activeRow.height = 0; + } else { + this._fixedRows.splice(this._fixedRows.indexOf(activeRow), 1); + } } // Record texture position - rasterizedGlyph.texturePosition.x = this._currentRowX; - rasterizedGlyph.texturePosition.y = this._currentRowY; - rasterizedGlyph.texturePositionClipSpace.x = this._currentRowX / TEXTURE_WIDTH; - rasterizedGlyph.texturePositionClipSpace.y = this._currentRowY / TEXTURE_HEIGHT; + rasterizedGlyph.texturePosition.x = activeRow.x; + rasterizedGlyph.texturePosition.y = activeRow.y; + rasterizedGlyph.texturePositionClipSpace.x = activeRow.x / TEXTURE_WIDTH; + rasterizedGlyph.texturePositionClipSpace.y = activeRow.y / TEXTURE_HEIGHT; - // Update atlas current row - this._currentRowHeight = Math.max(this._currentRowHeight, rasterizedGlyph.size.y); - this._currentRowX += rasterizedGlyph.size.x; + // Update atlas current row, for fixed rows the glyph height will never be larger than the row + // height + activeRow.height = Math.max(activeRow.height, rasterizedGlyph.size.y); + activeRow.x += rasterizedGlyph.size.x; // putImageData doesn't do any blending, so it will overwrite any existing cache entry for us this._cacheCtx.putImageData(clippedImageData, rasterizedGlyph.texturePosition.x, rasterizedGlyph.texturePosition.y); From 0514b559361f5b79339636ad716f5464da9282b6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:16:47 -0700 Subject: [PATCH 08/24] Fix default underline color Fixes #3971 --- src/common/buffer/AttributeData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/buffer/AttributeData.ts b/src/common/buffer/AttributeData.ts index 6878069a..b51f7ecb 100644 --- a/src/common/buffer/AttributeData.ts +++ b/src/common/buffer/AttributeData.ts @@ -149,7 +149,7 @@ export class ExtendedAttrs implements IExtendedAttrs { constructor( underlineStyle: UnderlineStyle = UnderlineStyle.NONE, - underlineColor: number = -1 + underlineColor: number = Attributes.CM_DEFAULT ) { this.underlineStyle = underlineStyle; this.underlineColor = underlineColor; From 686105942c98c1fcd7fed7c76a9c74b96cd18a25 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:25:18 -0700 Subject: [PATCH 09/24] Reduce line width of webgl underline --- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 008e65a8..6ec81ce6 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -438,8 +438,8 @@ export class WebglCharAtlas implements IDisposable { // Draw underline if (underline) { this._tmpCtx.save(); - const lineWidth = Math.max(1, Math.floor(this._config.fontSize * window.devicePixelRatio / 10)); - const yOffset = this._tmpCtx.lineWidth % 2 === 1 ? 0.5 : 0; // When the width is odd, draw at 0.5 position + const lineWidth = Math.max(1, Math.floor(this._config.fontSize * window.devicePixelRatio / 15)); + const yOffset = lineWidth % 2 === 1 ? 0.5 : 0; // When the width is odd, draw at 0.5 position this._tmpCtx.lineWidth = lineWidth; // Underline color From f4618b229f151d551f63ddbdfa61cfa9e9a48209 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:30:52 -0700 Subject: [PATCH 10/24] Bring underlines closer to characters --- .../src/atlas/WebglCharAtlas.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 6ec81ce6..c5069e64 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -439,7 +439,9 @@ export class WebglCharAtlas implements IDisposable { if (underline) { this._tmpCtx.save(); const lineWidth = Math.max(1, Math.floor(this._config.fontSize * window.devicePixelRatio / 15)); - const yOffset = lineWidth % 2 === 1 ? 0.5 : 0; // When the width is odd, draw at 0.5 position + // When the width is odd, draw at 0.5 position. Offset by an additional 1 dpr to bring the + // underline closer to the character + const yOffset = (lineWidth % 2 === 1 ? 0.5 : 0) + window.devicePixelRatio; this._tmpCtx.lineWidth = lineWidth; // Underline color @@ -508,18 +510,18 @@ export class WebglCharAtlas implements IDisposable { break; case UnderlineStyle.DOTTED: this._tmpCtx.setLineDash([window.devicePixelRatio * 2, window.devicePixelRatio]); - this._tmpCtx.moveTo(xLeft, yMid); - this._tmpCtx.lineTo(xRight, yMid); + this._tmpCtx.moveTo(xLeft, yTop); + this._tmpCtx.lineTo(xRight, yTop); break; case UnderlineStyle.DASHED: this._tmpCtx.setLineDash([window.devicePixelRatio * 4, window.devicePixelRatio * 3]); - this._tmpCtx.moveTo(xLeft, yMid); - this._tmpCtx.lineTo(xRight, yMid); + this._tmpCtx.moveTo(xLeft, yTop); + this._tmpCtx.lineTo(xRight, yTop); break; case UnderlineStyle.SINGLE: default: - this._tmpCtx.moveTo(xLeft, yMid); - this._tmpCtx.lineTo(xRight, yMid); + this._tmpCtx.moveTo(xLeft, yTop); + this._tmpCtx.lineTo(xRight, yTop); break; } this._tmpCtx.stroke(); From bff529e1e2d1840d3f4dfc1d5bc0dcca899a5da6 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:41:08 -0700 Subject: [PATCH 11/24] Simplify dom tests and fix assertion --- src/browser/renderer/dom/DomRendererRowFactory.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/browser/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts index df359dac..776ff701 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -139,7 +139,7 @@ describe('DomRendererRowFactory', () => { lineData.setCell(0, cell); const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20); assert.equal(getFragmentHtml(fragment), - 'a' + 'a' ); }); it('should add class for double underline style', () => { @@ -150,7 +150,7 @@ describe('DomRendererRowFactory', () => { lineData.setCell(0, cell); const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20); assert.equal(getFragmentHtml(fragment), - 'a' + 'a' ); }); it('should add class for curly underline style', () => { @@ -161,7 +161,7 @@ describe('DomRendererRowFactory', () => { lineData.setCell(0, cell); const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20); assert.equal(getFragmentHtml(fragment), - 'a' + 'a' ); }); it('should add class for double dotted style', () => { @@ -172,7 +172,7 @@ describe('DomRendererRowFactory', () => { lineData.setCell(0, cell); const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20); assert.equal(getFragmentHtml(fragment), - 'a' + 'a' ); }); it('should add class for dashed underline style', () => { @@ -183,7 +183,7 @@ describe('DomRendererRowFactory', () => { lineData.setCell(0, cell); const fragment = rowFactory.createRow(lineData, 0, false, undefined, 0, false, 5, 20); assert.equal(getFragmentHtml(fragment), - 'a' + 'a' ); }); }); From 8d57c64d29080de015d051617ad4f41d48edff70 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sat, 30 Jul 2022 23:48:37 -0700 Subject: [PATCH 12/24] Include purpose of canvas addon in readme Fixes #3978 --- addons/xterm-addon-canvas/README.md | 5 +++++ addons/xterm-addon-webgl/README.md | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/addons/xterm-addon-canvas/README.md b/addons/xterm-addon-canvas/README.md index ed65967d..bffac96e 100644 --- a/addons/xterm-addon-canvas/README.md +++ b/addons/xterm-addon-canvas/README.md @@ -2,6 +2,7 @@ An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables a canvas-based renderer using a 2d context to draw. This addon requires xterm.js v5+. +The purpose of this addon is to be used as a fallback for the [webgl addon](https://www.npmjs.com/package/xterm-addon-webgl) when better performance is desired over the default DOM renderer, but WebGL2 isn't supported or performant for some reason. ### Install @@ -21,3 +22,7 @@ terminal.loadAddon(new CanvasAddon()); ``` See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-canvas/typings/xterm-addon-canvas.d.ts) for more advanced usage. + +### See also + +- [xterm-addon-webgl](https://www.npmjs.com/package/xterm-addon-webgl) A renderer for xterm.js that uses WebGL diff --git a/addons/xterm-addon-webgl/README.md b/addons/xterm-addon-webgl/README.md index 2519fb7b..a431170f 100644 --- a/addons/xterm-addon-webgl/README.md +++ b/addons/xterm-addon-webgl/README.md @@ -36,3 +36,7 @@ terminal.loadAddon(addon); ``` Read more about handling WebGL context losses on the [Khronos wiki](https://www.khronos.org/webgl/wiki/HandlingContextLost). + +### See also + +- [xterm-addon-canvas](https://www.npmjs.com/package/xterm-addon-canvas) A renderer for xterm.js that uses a 2d canvas that can be used as a fallback when WebGL is not available From 0a83040ac88fcfc3bd2dc3a108217dd5f9145e4d Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Sun, 31 Jul 2022 07:38:14 +0000 Subject: [PATCH 13/24] clearAllMarkers --- src/common/buffer/BufferSet.test.ts | 13 +++++++++++++ src/common/buffer/BufferSet.ts | 1 + 2 files changed, 14 insertions(+) diff --git a/src/common/buffer/BufferSet.test.ts b/src/common/buffer/BufferSet.test.ts index 894ebb20..a200060f 100644 --- a/src/common/buffer/BufferSet.test.ts +++ b/src/common/buffer/BufferSet.test.ts @@ -71,4 +71,17 @@ describe('BufferSet', () => { assert.equal(bufferSet.active.y, 10); }); }); + + describe('markers', () => { + beforeEach(() => { + }); + + it('should clear the markers when the buffer is switched', () => { + bufferSet.activateAltBuffer(); + bufferSet.alt.addMarker(1); + assert.equal(bufferSet.alt.markers.length, 1); + bufferSet.activateNormalBuffer(); + assert.equal(bufferSet.alt.markers.length, 0); + }); + }); }); diff --git a/src/common/buffer/BufferSet.ts b/src/common/buffer/BufferSet.ts index de220e8f..7d07cec8 100644 --- a/src/common/buffer/BufferSet.ts +++ b/src/common/buffer/BufferSet.ts @@ -83,6 +83,7 @@ export class BufferSet extends Disposable implements IBufferSet { // The alt buffer should always be cleared when we switch to the normal // buffer. This frees up memory since the alt buffer should always be new // when activated. + this._alt.clearAllMarkers(); this._alt.clear(); this._activeBuffer = this._normal; this._onBufferActivate.fire({ From 31686fda614a8c23955306857e365caec4d70a6a Mon Sep 17 00:00:00 2001 From: Simon Lamon Date: Sun, 31 Jul 2022 07:54:29 +0000 Subject: [PATCH 14/24] Fix tests --- src/headless/public/Terminal.test.ts | 7 ++----- src/headless/public/Terminal.ts | 5 ++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/headless/public/Terminal.test.ts b/src/headless/public/Terminal.test.ts index 7f341b91..43aaf628 100644 --- a/src/headless/public/Terminal.test.ts +++ b/src/headless/public/Terminal.test.ts @@ -125,13 +125,10 @@ describe('Headless API Tests', function (): void { }); it('get options', () => { const options: ITerminalOptions = term.options; - strictEqual(options.cols, 80); - strictEqual(options.rows, 24); + strictEqual(options.lineHeight, 1); + strictEqual(options.cursorWidth, 1); }); it('set options', async () => { - const options: ITerminalOptions = term.options; - throws(() => options.cols = 40); - throws(() => options.rows = 20); term.options.scrollback = 1; strictEqual(term.options.scrollback, 1); term.options= { diff --git a/src/headless/public/Terminal.ts b/src/headless/public/Terminal.ts index 451d2372..efc0a8a1 100644 --- a/src/headless/public/Terminal.ts +++ b/src/headless/public/Terminal.ts @@ -7,11 +7,10 @@ import { IEvent } from 'common/EventEmitter'; import { BufferNamespaceApi } from 'common/public/BufferNamespaceApi'; import { ParserApi } from 'common/public/ParserApi'; import { UnicodeApi } from 'common/public/UnicodeApi'; -import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless'; +import { IBufferNamespace as IBufferNamespaceApi, IMarker, IModes, IParser, ITerminalAddon, ITerminalInitOnlyOptions, IUnicodeHandling, Terminal as ITerminalApi } from 'xterm-headless'; import { Terminal as TerminalCore } from 'headless/Terminal'; import { AddonManager } from 'common/public/AddonManager'; import { ITerminalOptions } from 'common/Types'; - /** * The set of options that only have an effect when set in the Terminal constructor. */ @@ -24,7 +23,7 @@ export class Terminal implements ITerminalApi { private _buffer: BufferNamespaceApi | undefined; private _publicOptions: ITerminalOptions; - constructor(options?: ITerminalOptions) { + constructor(options?: ITerminalOptions & ITerminalInitOnlyOptions) { this._core = new TerminalCore(options); this._addonManager = new AddonManager(); From 266d79517945f3460ca4623423d43a42f6cfd9ba Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 31 Jul 2022 10:58:04 -0700 Subject: [PATCH 15/24] Fix line height and letter spacing for custom glyphs --- .../src/atlas/WebglCharAtlas.ts | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index a7237c48..f9ba9d2f 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -409,15 +409,15 @@ export class WebglCharAtlas implements IDisposable { const padding = powerlineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING * 2; // Draw custom characters if applicable - let drawSuccess = false; + let customGlyph = false; if (this._config.customGlyphs !== false) { - drawSuccess = tryDrawCustomChar(this._tmpCtx, chars, padding, padding, this._config.scaledCellWidth, this._config.scaledCellHeight); + customGlyph = tryDrawCustomChar(this._tmpCtx, chars, padding, padding, this._config.scaledCellWidth, this._config.scaledCellHeight); } // Whether to clear pixels based on a threshold difference between the glyph color and the // background color. This should be disabled when the glyph contains multiple colors such as // underline colors to prevent important colors could get cleared. - let enableClearThresholdCheck = true; + let enableClearThresholdCheck = !powerlineGlyph; // Draw underline if (underline) { @@ -511,7 +511,7 @@ export class WebglCharAtlas implements IDisposable { // Draw stroke in the background color for non custom characters in order to give an outline // between the text and the underline - if (!drawSuccess) { + if (!customGlyph) { // This only works when transparency is disabled because it's not clear how to clear stroked // text if (!this._config.allowTransparency && chars !== ' ') { @@ -524,7 +524,7 @@ export class WebglCharAtlas implements IDisposable { } // Draw the character - if (!drawSuccess) { + if (!customGlyph) { this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight); } @@ -577,7 +577,10 @@ export class WebglCharAtlas implements IDisposable { return NULL_RASTERIZED_GLYPH; } - const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, powerlineGlyph, padding); + const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, powerlineGlyph, customGlyph, padding); + if (powerlineGlyph) { + console.log(`powerline glyph ${chars}`, rasterizedGlyph, this._workBoundingBox); + } const clippedImageData = this._clipImageData(imageData, this._workBoundingBox); // Check if there is enough room in the current row and go to next if needed @@ -610,10 +613,10 @@ export class WebglCharAtlas implements IDisposable { * @param imageData The image data to read. * @param boundingBox An IBoundingBox to put the clipped bounding box values. */ - private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, padding: number): IRasterizedGlyph { + private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, customGlyph: boolean, padding: number): IRasterizedGlyph { boundingBox.top = 0; const height = restrictedGlyph ? this._config.scaledCellHeight : this._tmpCanvas.height; - const width = restrictedGlyph ? this._config.scaledCharWidth : allowedWidth; + const width = restrictedGlyph ? this._config.scaledCellWidth : allowedWidth; let found = false; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { @@ -685,8 +688,8 @@ export class WebglCharAtlas implements IDisposable { y: (boundingBox.bottom - boundingBox.top + 1) / TEXTURE_HEIGHT }, offset: { - x: -boundingBox.left + padding + (restrictedGlyph ? Math.floor(this._config.letterSpacing / 2) : 0), - y: -boundingBox.top + padding + (restrictedGlyph ? this._config.lineHeight === 1 ? 0 : Math.round((this._config.scaledCellHeight - this._config.scaledCharHeight) / 2) : 0) + x: -boundingBox.left + padding + ((restrictedGlyph || customGlyph) ? Math.round((this._config.scaledCellWidth - this._config.scaledCharWidth) / 2) : 0), + y: -boundingBox.top + padding + ((restrictedGlyph || customGlyph) ? this._config.lineHeight === 1 ? 0 : Math.round((this._config.scaledCellHeight - this._config.scaledCharHeight) / 2) : 0) } }; } @@ -763,8 +766,3 @@ function checkCompletelyTransparent(imageData: ImageData): boolean { } return true; } - -function toPaddedHex(c: number): string { - const s = c.toString(16); - return s.length < 2 ? '0' + s : s; -} From 75ca5006a27f98409c3a6ae595039cbf3efee64d Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 31 Jul 2022 11:16:12 -0700 Subject: [PATCH 16/24] Expose texture atlas change event and use in demo --- addons/xterm-addon-webgl/src/WebglAddon.ts | 8 ++++++-- addons/xterm-addon-webgl/src/WebglRenderer.ts | 7 ++++++- demo/client.ts | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index 02ab942e..5b98a048 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -7,13 +7,16 @@ import { Terminal, ITerminalAddon, IEvent } from 'xterm'; import { WebglRenderer } from './WebglRenderer'; import { ICharacterJoinerService, ICoreBrowserService, IRenderService } from 'browser/services/Services'; import { IColorSet } from 'browser/Types'; -import { EventEmitter } from 'common/EventEmitter'; +import { EventEmitter, forwardEvent } from 'common/EventEmitter'; import { isSafari } from 'common/Platform'; import { ICoreService, IDecorationService } from 'common/services/Services'; export class WebglAddon implements ITerminalAddon { private _terminal?: Terminal; private _renderer?: WebglRenderer; + + private _onChangeTextureAtlas = new EventEmitter(); + public get onChangeTextureAtlas(): IEvent { return this._onChangeTextureAtlas.event; } private _onContextLoss = new EventEmitter(); public get onContextLoss(): IEvent { return this._onContextLoss.event; } @@ -36,7 +39,8 @@ export class WebglAddon implements ITerminalAddon { const decorationService: IDecorationService = (terminal as any)._core._decorationService; const colors: IColorSet = (terminal as any)._core._colorManager.colors; this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, coreBrowserService, coreService, decorationService, this._preserveDrawingBuffer); - this._renderer.onContextLoss(() => this._onContextLoss.fire()); + forwardEvent(this._renderer.onContextLoss, this._onContextLoss); + forwardEvent(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas); renderService.setRenderer(this._renderer); } diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index d2d4f478..c4d40f0d 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -46,6 +46,8 @@ export class WebglRenderer extends Disposable implements IRenderer { private _core: ITerminal; private _isAttached: boolean; + private _onChangeTextureAtlas = new EventEmitter(); + public get onChangeTextureAtlas(): IEvent { return this._onChangeTextureAtlas.event; } private _onRequestRedraw = new EventEmitter(); public get onRequestRedraw(): IEvent { return this._onRequestRedraw.event; } @@ -240,7 +242,10 @@ export class WebglRenderer extends Disposable implements IRenderer { if (!('getRasterizedGlyph' in atlas)) { throw new Error('The webgl renderer only works with the webgl char atlas'); } - this._charAtlas = atlas as WebglCharAtlas; + if (this._charAtlas !== atlas) { + this._onChangeTextureAtlas.fire(atlas.cacheCanvas); + } + this._charAtlas = atlas; this._charAtlas.warmUp(); this._glyphRenderer.setAtlas(this._charAtlas); } diff --git a/demo/client.ts b/demo/client.ts index dd3b4325..1c414702 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -240,6 +240,7 @@ function createTerminal(): void { typedTerm.loadAddon(addons.webgl.instance); setTimeout(() => { document.body.appendChild(addons.webgl.instance.textureAtlas); + addons.webgl.instance.onChangeTextureAtlas(e => document.body.appendChild(e)); }, 0); term.focus(); @@ -506,6 +507,7 @@ function initAddons(term: TerminalType): void { if (name === 'webgl') { setTimeout(() => { document.body.appendChild((addon.instance as WebglAddon).textureAtlas); + (addon.instance as WebglAddon).onChangeTextureAtlas(e => document.body.appendChild(e)); }, 0); } else if (name === 'unicode11') { term.unicode.activeVersion = '11'; From d6fe5c73849a1bf530fdea476984ebd6368c3e66 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 31 Jul 2022 11:21:27 -0700 Subject: [PATCH 17/24] Update size when letter spacing changes --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 1 - .../typings/xterm-addon-webgl.d.ts | 15 ++++++++++----- demo/client.ts | 13 ++++--------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index c4d40f0d..beed0304 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -25,7 +25,6 @@ import { ICharacterJoinerService, ICoreBrowserService } from 'browser/services/S import { CharData, ICellData } from 'common/Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { ICoreService, IDecorationService } from 'common/services/Services'; -import { color, rgba as rgbaNs } from 'common/Color'; export class WebglRenderer extends Disposable implements IRenderer { private _renderLayers: IRenderLayer[]; diff --git a/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts b/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts index ee390d8a..74aed0cc 100644 --- a/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts +++ b/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts @@ -12,6 +12,16 @@ declare module 'xterm-addon-webgl' { export class WebglAddon implements ITerminalAddon { public textureAtlas?: HTMLCanvasElement; + /** + * An event that is fired when the renderer loses its canvas context. + */ + public get onContextLoss(): IEvent; + + /** + * An event that is fired when the texture atlas of the renderer changes. + */ + public get onChangeTextureAtlas(): IEvent; + constructor(preserveDrawingBuffer?: boolean); /** @@ -29,10 +39,5 @@ declare module 'xterm-addon-webgl' { * Clears the terminal's texture atlas and triggers a redraw. */ public clearTextureAtlas(): void; - - /** - * Fired when the WebglRenderer loses context - */ - public get onContextLoss(): IEvent; } } diff --git a/demo/client.ts b/demo/client.ts index 1c414702..98c60f70 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -400,20 +400,18 @@ function initOptions(term: TerminalType): void { const input = document.getElementById(`opt-${o}`); addDomListener(input, 'change', () => { console.log('change', o, input.value); - if (o === 'cols' || o === 'rows') { - updateTerminalSize(); - } else if (o === 'lineHeight') { + if (o === 'lineHeight') { term.options.lineHeight = parseFloat(input.value); - updateTerminalSize(); } else if (o === 'scrollSensitivity') { term.options.scrollSensitivity = parseFloat(input.value); - updateTerminalSize(); } else if (o === 'scrollback') { term.options.scrollback = parseInt(input.value); setTimeout(() => updateTerminalSize(), 5); } else { term.options[o] = parseInt(input.value); } + if (['cols', 'rows', 'letterSpacing', 'lineHeight'].includes(o)) { + updateTerminalSize(); }); }); Object.keys(stringOptions).forEach(o => { @@ -505,10 +503,7 @@ function initAddons(term: TerminalType): void { addon.instance = new addon.ctor(); term.loadAddon(addon.instance); if (name === 'webgl') { - setTimeout(() => { - document.body.appendChild((addon.instance as WebglAddon).textureAtlas); - (addon.instance as WebglAddon).onChangeTextureAtlas(e => document.body.appendChild(e)); - }, 0); + (addon.instance as WebglAddon).onChangeTextureAtlas(e => document.body.appendChild(e)); } else if (name === 'unicode11') { term.unicode.activeVersion = '11'; } else if (name === 'search') { From 208364147ab31efdad082de46d74da3b305d0ad3 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Sun, 31 Jul 2022 11:35:12 -0700 Subject: [PATCH 18/24] Allow texture atlas to be zoomed on hover --- demo/client.ts | 10 +++++++--- demo/index.html | 1 + demo/style.css | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index 98c60f70..85355dae 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -239,8 +239,8 @@ function createTerminal(): void { addons.fit.instance!.fit(); typedTerm.loadAddon(addons.webgl.instance); setTimeout(() => { - document.body.appendChild(addons.webgl.instance.textureAtlas); - addons.webgl.instance.onChangeTextureAtlas(e => document.body.appendChild(e)); + addTextureAtlas(addons.webgl.instance.textureAtlas); + addons.webgl.instance.onChangeTextureAtlas(e => addTextureAtlas(e)); }, 0); term.focus(); @@ -412,6 +412,7 @@ function initOptions(term: TerminalType): void { } if (['cols', 'rows', 'letterSpacing', 'lineHeight'].includes(o)) { updateTerminalSize(); + } }); }); Object.keys(stringOptions).forEach(o => { @@ -503,7 +504,7 @@ function initAddons(term: TerminalType): void { addon.instance = new addon.ctor(); term.loadAddon(addon.instance); if (name === 'webgl') { - (addon.instance as WebglAddon).onChangeTextureAtlas(e => document.body.appendChild(e)); + (addon.instance as WebglAddon).onChangeTextureAtlas(e => addTextureAtlas(e)); } else if (name === 'unicode11') { term.unicode.activeVersion = '11'; } else if (name === 'search') { @@ -587,6 +588,9 @@ function htmlSerializeButtonHandler(): void { document.getElementById("htmlserialize-output-result").innerText = "Copied to clipboard"; } +function addTextureAtlas(e: HTMLCanvasElement) { + document.querySelector('#texture-atlas').appendChild(e); +} function writeCustomGlyphHandler() { term.write('\n\r'); diff --git a/demo/index.html b/demo/index.html index bff5b4b2..214dd25f 100644 --- a/demo/index.html +++ b/demo/index.html @@ -87,6 +87,7 @@ +