From 8a6e0fca07fa28ef51df1d1af296c73ab53f402b Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 21:15:07 -0800 Subject: [PATCH 01/24] Move parts over to CellData --- addons/xterm-addon-webgl/src/WebglRenderer.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index ab2cb354..785f6e69 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -23,6 +23,7 @@ import { IColorSet } from 'browser/Types'; import { FLAGS } from './Constants'; import { getCompatAttr } from './CharDataCompat'; import { EventEmitter } from 'common/EventEmitter'; +import { CellData } from 'common/buffer/CellData'; export const INDICIES_PER_CELL = 4; @@ -32,6 +33,7 @@ export class WebglRenderer extends Disposable implements IRenderer { private _devicePixelRatio: number; private _model: RenderModel = new RenderModel(); + private _workCell: CellData = new CellData(); private _canvas: HTMLCanvasElement; private _gl: IWebGL2RenderingContext; @@ -258,12 +260,19 @@ export class WebglRenderer extends Disposable implements IRenderer { const line = terminal.buffer.lines.get(row)!; this._model.lineLengths[y] = 0; for (let x = 0; x < terminal.cols; x++) { - const charData = line.get(x); - const chars = charData[CHAR_DATA_CHAR_INDEX]; - let code = charData[CHAR_DATA_CODE_INDEX]; + line.loadCell(x, this._workCell); + + // const charData = line.get(x); + // const chars = charData[CHAR_DATA_CHAR_INDEX]; + const chars = this._workCell.getChars(); + // let code = charData[CHAR_DATA_CODE_INDEX]; + let code = this._workCell.getCode(); const attr = getCompatAttr(line, x); // charData[CHAR_DATA_ATTR_INDEX]; const i = ((y * terminal.cols) + x) * INDICIES_PER_CELL; + // console.log('workcell', this._workCell); + // console.log('attr: ' + attr); + if (code !== NULL_CELL_CODE) { this._model.lineLengths[y] = x + 1; } From e72ee3c58dc87ccfaffd103eff24439e1554ce96 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 22:28:59 -0800 Subject: [PATCH 02/24] Move webgl drawing over from compat Still need to tackle glyph key --- .../src/RectangleRenderer.ts | 25 ++++++++++++------- addons/xterm-addon-webgl/src/WebglRenderer.ts | 22 +++++++--------- .../src/atlas/CharAtlasUtils.ts | 4 +-- .../src/atlas/WebglCharAtlas.ts | 14 +++++------ 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index 2c464d2a..70b5ee3c 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -8,7 +8,7 @@ import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelect import { fill } from 'common/TypedArrayUtils'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { is256Color } from './atlas/CharAtlasUtils'; -import { DEFAULT_COLOR } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, Attributes, FgFlags } from 'common/buffer/Constants'; import { Terminal } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; @@ -248,37 +248,44 @@ export class RectangleRenderer { for (let y = 0; y < terminal.rows; y++) { let currentStartX = -1; let currentBg = DEFAULT_COLOR; + let currentFg = DEFAULT_COLOR; for (let x = 0; x < terminal.cols; x++) { const modelIndex = ((y * terminal.cols) + x) * 4; const bg = model.cells[modelIndex + 2]; + const fg = model.cells[modelIndex + 1]; if (bg !== currentBg) { // A rectangle needs to be drawn if going from non-default to another color + // TODO: DEFAULT_COLOR probably isn't right anymore? if (currentBg !== DEFAULT_COLOR) { const offset = rectangleCount++ * INDICES_PER_RECTANGLE; - this._updateRectangle(vertices, offset, currentBg, currentStartX, x, y); + this._updateRectangle(vertices, offset, currentFg, currentBg, currentStartX, x, y); } currentStartX = x; currentBg = bg; + currentFg = fg; } } // Finish rectangle if it's still going if (currentBg !== DEFAULT_COLOR) { const offset = rectangleCount++ * INDICES_PER_RECTANGLE; - this._updateRectangle(vertices, offset, currentBg, currentStartX, terminal.cols, y); + this._updateRectangle(vertices, offset, currentFg, currentBg, currentStartX, terminal.cols, y); } } vertices.count = rectangleCount; } - private _updateRectangle(vertices: IVertices, offset: number, bg: number, startX: number, endX: number, y: number): void { + private _updateRectangle(vertices: IVertices, offset: number, fg: number, bg: number, startX: number, endX: number, y: number): void { let color: IColor | null = null; - if (bg === INVERTED_DEFAULT_COLOR) { + if (fg & FgFlags.INVERSE) { + // Inverted color color = this._colors.foreground; - } else if (is256Color(bg)) { - color = this._colors.ansi[bg]; + } else if ((bg & Attributes.CM_MASK) === Attributes.CM_P16 || (bg & Attributes.CM_MASK) === Attributes.CM_P256) { + // 256 palette + color = this._colors.ansi[bg & Attributes.PCOLOR_MASK]; } else { - // TODO: Add support for true color - color = this._colors.foreground; + // TODO: Support true color + // Default color + color = this._colors.background; } if (vertices.attributes.length < offset + 4) { vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE); diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 785f6e69..ef20f614 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -14,7 +14,7 @@ import { IWebGL2RenderingContext } from './Types'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { Disposable } from 'common/Lifecycle'; -import { DEFAULT_COLOR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, FgFlags } from 'common/buffer/Constants'; import { Terminal, IEvent } from 'xterm'; import { getLuminance } from './ColorUtils'; import { IRenderLayer } from './renderLayer/Types'; @@ -262,17 +262,11 @@ export class WebglRenderer extends Disposable implements IRenderer { for (let x = 0; x < terminal.cols; x++) { line.loadCell(x, this._workCell); - // const charData = line.get(x); - // const chars = charData[CHAR_DATA_CHAR_INDEX]; const chars = this._workCell.getChars(); - // let code = charData[CHAR_DATA_CODE_INDEX]; let code = this._workCell.getCode(); const attr = getCompatAttr(line, x); // charData[CHAR_DATA_ATTR_INDEX]; const i = ((y * terminal.cols) + x) * INDICIES_PER_CELL; - // console.log('workcell', this._workCell); - // console.log('attr: ' + attr); - if (code !== NULL_CELL_CODE) { this._model.lineLengths[y] = x + 1; } @@ -283,12 +277,11 @@ export class WebglRenderer extends Disposable implements IRenderer { } // Resolve bg and fg and cache in the model - const flags = attr >> 18; - let bg = attr & 0x1ff; - let fg = (attr >> 9) & 0x1ff; + let bg = this._workCell.bg; + let fg = this._workCell.fg; // If inverse flag is on, the foreground should become the background. - if (flags & FLAGS.INVERSE) { + if (this._workCell.isInverse()) { const temp = bg; bg = fg; fg = temp; @@ -299,8 +292,11 @@ export class WebglRenderer extends Disposable implements IRenderer { bg = INVERTED_DEFAULT_COLOR; } } - const drawInBrightColor = terminal.options.drawBoldTextInBrightColors && !!(flags & FLAGS.BOLD) && fg < 8 && fg !== INVERTED_DEFAULT_COLOR; - fg += drawInBrightColor ? 8 : 0; + + // Apply drawBoldTextInBrightColors + if (terminal.options.drawBoldTextInBrightColors && this._workCell.isBold() && fg & FgFlags.BOLD && this._workCell.getFgColor() < 8) { + fg += 8; + } // Flag combined chars with a bit mask so they're easily identifiable if (chars.length > 1) { diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 857fa628..821b53a4 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -4,7 +4,7 @@ */ import { ICharAtlasConfig } from './Types'; -import { DEFAULT_COLOR } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, Attributes } from 'common/buffer/Constants'; import { Terminal, FontWeight } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; @@ -57,5 +57,5 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean } export function is256Color(colorCode: number): boolean { - return colorCode < DEFAULT_COLOR; + return (colorCode & Attributes.CM_MASK) === Attributes.CM_P16 || (colorCode & Attributes.CM_MASK) === Attributes.CM_P256; } diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 8d8e995b..14cd017d 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -6,7 +6,7 @@ import { ICharAtlasConfig } from './Types'; import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; -import { DEFAULT_COLOR, DEFAULT_ATTR } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, DEFAULT_ATTR, FgFlags, Attributes } from 'common/buffer/Constants'; import { is256Color } from './CharAtlasUtils'; import { throwIfFalsy } from '../WebglUtils'; import { IColor } from 'browser/Types'; @@ -161,26 +161,26 @@ export class WebglCharAtlas implements IDisposable { return this._config.colors.ansi[idx]; } - private _getBackgroundColor(bg: number): IColor { + private _getBackgroundColor(bg: number, fg: number): IColor { if (this._config.allowTransparency) { // The background color might have some transparency, so we need to render it as fully // transparent in the atlas. Otherwise we'd end up drawing the transparent background twice // around the anti-aliased edges of the glyph, and it would look too dark. return TRANSPARENT_COLOR; - } else if (bg === INVERTED_DEFAULT_COLOR) { + } else if (fg & FgFlags.INVERSE) { return this._config.colors.foreground; } else if (is256Color(bg)) { - return this._getColorFromAnsiIndex(bg); + return this._getColorFromAnsiIndex(bg & Attributes.PCOLOR_MASK); } // TODO: Support true color return this._config.colors.background; } private _getForegroundColor(fg: number): IColor { - if (fg === INVERTED_DEFAULT_COLOR) { + if (fg & FgFlags.INVERSE) { return this._config.colors.background; } else if (is256Color(fg)) { - return this._getColorFromAnsiIndex(fg); + return this._getColorFromAnsiIndex(fg & Attributes.PCOLOR_MASK); } // TODO: Support true color return this._config.colors.foreground; @@ -202,7 +202,7 @@ export class WebglCharAtlas implements IDisposable { this._tmpCtx.save(); // draw the background - const backgroundColor = this._getBackgroundColor(bg); + const backgroundColor = this._getBackgroundColor(bg, fg); // Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, regardless of // transparency in backgroundColor this._tmpCtx.globalCompositeOperation = 'copy'; From 8f0f8bf827435d9268ef59d88b4a54fd3b99fdeb Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 22:31:10 -0800 Subject: [PATCH 03/24] Remove cache reliance on flags --- .../src/atlas/WebglCharAtlas.ts | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 14cd017d..f3858c69 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -6,7 +6,7 @@ import { ICharAtlasConfig } from './Types'; import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; -import { DEFAULT_COLOR, DEFAULT_ATTR, FgFlags, Attributes } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, DEFAULT_ATTR, FgFlags, Attributes, BgFlags } from 'common/buffer/Constants'; import { is256Color } from './CharAtlasUtils'; import { throwIfFalsy } from '../WebglUtils'; import { IColor } from 'browser/Types'; @@ -103,7 +103,7 @@ export class WebglCharAtlas implements IDisposable { protected _doWarmUp(): void { // Pre-fill with ASCII 33-126 for (let i = 33; i < 126; i++) { - const rasterizedGlyph = this._drawToCache(i, DEFAULT_ATTR, DEFAULT_COLOR, DEFAULT_COLOR); + const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR); this._cacheMap[i] = { [DEFAULT_ATTR]: rasterizedGlyph }; @@ -131,7 +131,7 @@ export class WebglCharAtlas implements IDisposable { } let rasterizedGlyph = rasterizedGlyphSet[attr]; if (!rasterizedGlyph) { - rasterizedGlyph = this._drawToCache(chars, attr, bg, fg); + rasterizedGlyph = this._drawToCache(chars, bg, fg); rasterizedGlyphSet[attr] = rasterizedGlyph; } return rasterizedGlyph; @@ -148,7 +148,7 @@ export class WebglCharAtlas implements IDisposable { } let rasterizedGlyph = rasterizedGlyphSet[attr]; if (!rasterizedGlyph) { - rasterizedGlyph = this._drawToCache(code, attr, bg, fg); + rasterizedGlyph = this._drawToCache(code, bg, fg); rasterizedGlyphSet[attr] = rasterizedGlyph; } return rasterizedGlyph; @@ -186,18 +186,16 @@ export class WebglCharAtlas implements IDisposable { return this._config.colors.foreground; } - private _drawToCache(code: number, attr: number, bg: number, fg: number): IRasterizedGlyph; - private _drawToCache(chars: string, attr: number, bg: number, fg: number): IRasterizedGlyph; - private _drawToCache(codeOrChars: number | string, attr: number, bg: number, fg: number): IRasterizedGlyph { + private _drawToCache(code: number, bg: number, fg: number): IRasterizedGlyph; + private _drawToCache(chars: string, bg: number, fg: number): IRasterizedGlyph; + private _drawToCache(codeOrChars: number | string, bg: number, fg: number): IRasterizedGlyph { const chars = typeof codeOrChars === 'number' ? String.fromCharCode(codeOrChars) : codeOrChars; this.hasCanvasChanged = true; - const flags = attr >> 18; - - const bold = !!(flags & FLAGS.BOLD); - const dim = !!(flags & FLAGS.DIM); - const italic = !!(flags & FLAGS.ITALIC); + const bold = !!(fg & FgFlags.BOLD); + const dim = !!(bg & BgFlags.DIM); + const italic = !!(bg & BgFlags.ITALIC); this._tmpCtx.save(); From e15476704ca9fecbf93e607ce7253eedd040840e Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 22:43:25 -0800 Subject: [PATCH 04/24] Adopt new [bg][fg] map in char cache --- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 14 ++++---- addons/xterm-addon-webgl/src/Types.d.ts | 2 +- addons/xterm-addon-webgl/src/WebglRenderer.ts | 3 +- .../src/atlas/WebglCharAtlas.ts | 32 ++++++++++++++----- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index bd4488dc..dd83131e 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -169,11 +169,11 @@ export class GlyphRenderer { return this._atlas ? this._atlas.beginFrame() : true; } - public updateCell(x: number, y: number, code: number, attr: number, bg: number, fg: number, chars: string): void { - this._updateCell(this._vertices.attributes, x, y, code, attr, bg, fg, chars); + public updateCell(x: number, y: number, code: number, bg: number, fg: number, chars: string): void { + this._updateCell(this._vertices.attributes, x, y, code, bg, fg, chars); } - private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, attr: number, bg: number, fg: number, chars?: string): void { + private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, bg: number, fg: number, chars?: string): void { const terminal = this._terminal; const i = (y * terminal.cols + x) * INDICES_PER_CELL; @@ -189,9 +189,9 @@ export class GlyphRenderer { throw new Error('atlas must be set before updating cell'); } if (chars && chars.length > 1) { - rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg); + rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, bg, fg); } else { - rasterizedGlyph = this._atlas.getRasterizedGlyph(code, attr, bg, fg); + rasterizedGlyph = this._atlas.getRasterizedGlyph(code, bg, fg); } // Fill empty if no glyph was found @@ -269,9 +269,9 @@ export class GlyphRenderer { line = terminal.buffer.getLine(row); } const chars = line!.getCell(x)!.char; - this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg, chars); + this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg, chars); } else { - this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg); + this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg); } } } diff --git a/addons/xterm-addon-webgl/src/Types.d.ts b/addons/xterm-addon-webgl/src/Types.d.ts index 6ebc8d64..f01092ee 100644 --- a/addons/xterm-addon-webgl/src/Types.d.ts +++ b/addons/xterm-addon-webgl/src/Types.d.ts @@ -4,7 +4,7 @@ */ export interface IRasterizedGlyphSet { - [flags: number]: IRasterizedGlyph; + [bg: number]: { [fg: number]: IRasterizedGlyph } | undefined; } /** diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index ef20f614..afdb7fa4 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -304,11 +304,12 @@ export class WebglRenderer extends Disposable implements IRenderer { } this._model.cells[i ] = code; + // TODO: Remove attr from model this._model.cells[i + 1] = attr; this._model.cells[i + 2] = bg; this._model.cells[i + 3] = fg; - this._glyphRenderer.updateCell(x, y, code, attr, bg, fg, chars); + this._glyphRenderer.updateCell(x, y, code, bg, fg, chars); } } this._rectangleRenderer.updateBackgrounds(this._model); diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index f3858c69..9d8eb286 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -4,7 +4,7 @@ */ import { ICharAtlasConfig } from './Types'; -import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; +import { DIM_OPACITY } from 'browser/renderer/atlas/Constants'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; import { DEFAULT_COLOR, DEFAULT_ATTR, FgFlags, Attributes, BgFlags } from 'common/buffer/Constants'; import { is256Color } from './CharAtlasUtils'; @@ -105,7 +105,9 @@ export class WebglCharAtlas implements IDisposable { for (let i = 33; i < 126; i++) { const rasterizedGlyph = this._drawToCache(i, DEFAULT_COLOR, DEFAULT_COLOR); this._cacheMap[i] = { - [DEFAULT_ATTR]: rasterizedGlyph + [DEFAULT_COLOR]: { + [DEFAULT_COLOR]: rasterizedGlyph + } }; } } @@ -123,16 +125,23 @@ export class WebglCharAtlas implements IDisposable { return false; } - public getRasterizedGlyphCombinedChar(chars: string, attr: number, bg: number, fg: number): IRasterizedGlyph { + public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number): IRasterizedGlyph { let rasterizedGlyphSet = this._cacheMapCombined[chars]; if (!rasterizedGlyphSet) { rasterizedGlyphSet = {}; this._cacheMapCombined[chars] = rasterizedGlyphSet; } - let rasterizedGlyph = rasterizedGlyphSet[attr]; + let rasterizedGlyph: IRasterizedGlyph | undefined; + const rasterizedGlyphSetBg = rasterizedGlyphSet[bg]; + if (rasterizedGlyphSetBg) { + rasterizedGlyph = rasterizedGlyphSetBg[fg]; + } if (!rasterizedGlyph) { rasterizedGlyph = this._drawToCache(chars, bg, fg); - rasterizedGlyphSet[attr] = rasterizedGlyph; + if (!rasterizedGlyphSet[bg]) { + rasterizedGlyphSet[bg] = {}; + } + rasterizedGlyphSet[bg]![fg] = rasterizedGlyph; } return rasterizedGlyph; } @@ -140,16 +149,23 @@ export class WebglCharAtlas implements IDisposable { /** * Gets the glyphs texture coords, drawing the texture if it's not already */ - public getRasterizedGlyph(code: number, attr: number, bg: number, fg: number): IRasterizedGlyph { + public getRasterizedGlyph(code: number, bg: number, fg: number): IRasterizedGlyph { let rasterizedGlyphSet = this._cacheMap[code]; if (!rasterizedGlyphSet) { rasterizedGlyphSet = {}; this._cacheMap[code] = rasterizedGlyphSet; } - let rasterizedGlyph = rasterizedGlyphSet[attr]; + let rasterizedGlyph: IRasterizedGlyph | undefined; + const rasterizedGlyphSetBg = rasterizedGlyphSet[bg]; + if (rasterizedGlyphSetBg) { + rasterizedGlyph = rasterizedGlyphSetBg[fg]; + } if (!rasterizedGlyph) { rasterizedGlyph = this._drawToCache(code, bg, fg); - rasterizedGlyphSet[attr] = rasterizedGlyph; + if (!rasterizedGlyphSet[bg]) { + rasterizedGlyphSet[bg] = {}; + } + rasterizedGlyphSet[bg]![fg] = rasterizedGlyph; } return rasterizedGlyph; } From 9dd2ccb1ad87e8af70d970eb481316097cf8b9dc Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 22:48:28 -0800 Subject: [PATCH 05/24] Fix selection color to set correct mode --- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 6 +++--- addons/xterm-addon-webgl/src/WebglRenderer.ts | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index dd83131e..00b21629 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -10,7 +10,7 @@ import { INDICIES_PER_CELL } from './WebglRenderer'; import { COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { fill } from 'common/TypedArrayUtils'; import { slice } from './TypedArray'; -import { NULL_CELL_CODE, WHITESPACE_CELL_CODE } from 'common/buffer/Constants'; +import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants'; import { getLuminance } from './ColorUtils'; import { Terminal, IBufferLine } from 'xterm'; import { IColorSet } from 'browser/Types'; @@ -223,8 +223,8 @@ export class GlyphRenderer { // TODO: Make fg and bg configurable, currently since the buffer doesn't // support truecolor the char atlas cannot store it. const lumi = getLuminance(this._colors.background); - const fg = lumi > 0.5 ? 7 : 0; - const bg = lumi > 0.5 ? 0 : 7; + const fg = (lumi > 0.5 ? 7 : 0) | Attributes.CM_P16; + const bg = (lumi > 0.5 ? 0 : 7) | Attributes.CM_P16; if (columnSelectMode) { const startCol = model.selection.startCol; diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index afdb7fa4..a9a2f860 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -271,15 +271,15 @@ export class WebglRenderer extends Disposable implements IRenderer { this._model.lineLengths[y] = x + 1; } - // Nothing has changed, no updates needed - if (this._model.cells[i] === code && this._model.cells[i + 1] === attr) { - continue; - } - - // Resolve bg and fg and cache in the model + // Resolve bg and fg let bg = this._workCell.bg; let fg = this._workCell.fg; + // Nothing has changed, no updates needed + if (this._model.cells[i] === code && this._model.cells[i + 2] === bg && this._model.cells[i + 3] === fg) { + continue; + } + // If inverse flag is on, the foreground should become the background. if (this._workCell.isInverse()) { const temp = bg; @@ -303,6 +303,7 @@ export class WebglRenderer extends Disposable implements IRenderer { code = code | COMBINED_CHAR_BIT_MASK; } + // Cache the results in the model this._model.cells[i ] = code; // TODO: Remove attr from model this._model.cells[i + 1] = attr; From a2bd0e8eaac09bfcf6eea556685f821a048f5e7d Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 22:50:22 -0800 Subject: [PATCH 06/24] Remove attr compat from webgl --- .../xterm-addon-webgl/src/CharDataCompat.ts | 28 ------------------- addons/xterm-addon-webgl/src/WebglRenderer.ts | 7 ++--- 2 files changed, 2 insertions(+), 33 deletions(-) delete mode 100644 addons/xterm-addon-webgl/src/CharDataCompat.ts diff --git a/addons/xterm-addon-webgl/src/CharDataCompat.ts b/addons/xterm-addon-webgl/src/CharDataCompat.ts deleted file mode 100644 index 13613c88..00000000 --- a/addons/xterm-addon-webgl/src/CharDataCompat.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { CellData } from 'common/buffer/CellData'; -import { FLAGS } from './Constants'; -import { IBufferLine } from 'common/Types'; - -export function getCompatAttr(bufferLine: IBufferLine, index: number): number { - // TODO: Need to move WebGL over to the new system and remove this block - const cell = new CellData(); - bufferLine.loadCell(index, cell); - const oldBg = cell.getBgColor() === -1 ? 256 : cell.getBgColor(); - const oldFg = cell.getFgColor() === -1 ? 256 : cell.getFgColor(); - const oldAttr = - (cell.isBold() ? FLAGS.BOLD : 0) | - (cell.isUnderline() ? FLAGS.UNDERLINE : 0) | - (cell.isBlink() ? FLAGS.BLINK : 0) | - (cell.isInverse() ? FLAGS.INVERSE : 0) | - (cell.isDim() ? FLAGS.DIM : 0) | - (cell.isItalic() ? FLAGS.ITALIC : 0); - const attrCompat = - oldBg | - (oldFg << 9) | - (oldAttr << 18); - return attrCompat; -} diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index a9a2f860..9acbc8df 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -14,14 +14,12 @@ import { IWebGL2RenderingContext } from './Types'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { Disposable } from 'common/Lifecycle'; -import { DEFAULT_COLOR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, FgFlags } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, NULL_CELL_CODE, FgFlags } from 'common/buffer/Constants'; import { Terminal, IEvent } from 'xterm'; import { getLuminance } from './ColorUtils'; import { IRenderLayer } from './renderLayer/Types'; import { IRenderDimensions, IRenderer, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { IColorSet } from 'browser/Types'; -import { FLAGS } from './Constants'; -import { getCompatAttr } from './CharDataCompat'; import { EventEmitter } from 'common/EventEmitter'; import { CellData } from 'common/buffer/CellData'; @@ -264,7 +262,6 @@ export class WebglRenderer extends Disposable implements IRenderer { const chars = this._workCell.getChars(); let code = this._workCell.getCode(); - const attr = getCompatAttr(line, x); // charData[CHAR_DATA_ATTR_INDEX]; const i = ((y * terminal.cols) + x) * INDICIES_PER_CELL; if (code !== NULL_CELL_CODE) { @@ -306,7 +303,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // Cache the results in the model this._model.cells[i ] = code; // TODO: Remove attr from model - this._model.cells[i + 1] = attr; + this._model.cells[i + 1] = 0; this._model.cells[i + 2] = bg; this._model.cells[i + 3] = fg; From 2b5d229aabfa63e4d6e4d28b9fd66c754ee686c1 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 22:56:42 -0800 Subject: [PATCH 07/24] Reduce size of model to 3 by removing attr --- addons/xterm-addon-webgl/src/Constants.ts | 12 ++---------- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 3 --- addons/xterm-addon-webgl/src/RectangleRenderer.ts | 7 +++---- addons/xterm-addon-webgl/src/RenderModel.ts | 2 +- addons/xterm-addon-webgl/src/WebglRenderer.ts | 13 +++++++------ .../xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 3 +-- 6 files changed, 14 insertions(+), 26 deletions(-) diff --git a/addons/xterm-addon-webgl/src/Constants.ts b/addons/xterm-addon-webgl/src/Constants.ts index ab18b97a..bf39ec98 100644 --- a/addons/xterm-addon-webgl/src/Constants.ts +++ b/addons/xterm-addon-webgl/src/Constants.ts @@ -3,13 +3,5 @@ * @license MIT */ -// TODO: Should be removed after chardata workaround is fixed -export const enum FLAGS { - BOLD = 1, - UNDERLINE = 2, - BLINK = 4, - INVERSE = 8, - INVISIBLE = 16, - DIM = 32, - ITALIC = 64 -} +export const MODEL_BG_OFFSET = 2; +export const MODEL_FG_OFFSET = 3; diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 00b21629..a28d5c10 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -260,9 +260,6 @@ export class GlyphRenderer { let line: IBufferLine | undefined; for (let x = startCol; x < endCol; x++) { const offset = (y * this._terminal.cols + x) * INDICIES_PER_CELL; - // Because the cache uses attr as a lookup key it needs to contain the selection colors as well - let attr = model.cells[offset + 1]; - attr = attr & ~0x3ffff | bg << 9 | fg; const code = model.cells[offset]; if (code & COMBINED_CHAR_BIT_MASK) { if (!line) { diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index 70b5ee3c..3a5f6417 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -6,12 +6,11 @@ import { createProgram, expandFloat32Array, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils'; import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelectionRenderModel } from './Types'; import { fill } from 'common/TypedArrayUtils'; -import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { is256Color } from './atlas/CharAtlasUtils'; import { DEFAULT_COLOR, Attributes, FgFlags } from 'common/buffer/Constants'; import { Terminal } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; +import { MODEL_FG_OFFSET, MODEL_BG_OFFSET } from './Constants'; const enum VertexAttribLocations { POSITION = 0, @@ -251,8 +250,8 @@ export class RectangleRenderer { let currentFg = DEFAULT_COLOR; for (let x = 0; x < terminal.cols; x++) { const modelIndex = ((y * terminal.cols) + x) * 4; - const bg = model.cells[modelIndex + 2]; - const fg = model.cells[modelIndex + 1]; + const bg = model.cells[modelIndex + MODEL_BG_OFFSET]; + const fg = model.cells[modelIndex + MODEL_FG_OFFSET]; if (bg !== currentBg) { // A rectangle needs to be drawn if going from non-default to another color // TODO: DEFAULT_COLOR probably isn't right anymore? diff --git a/addons/xterm-addon-webgl/src/RenderModel.ts b/addons/xterm-addon-webgl/src/RenderModel.ts index a9ee24e9..f55111d4 100644 --- a/addons/xterm-addon-webgl/src/RenderModel.ts +++ b/addons/xterm-addon-webgl/src/RenderModel.ts @@ -6,7 +6,7 @@ import { IRenderModel, ISelectionRenderModel } from './Types'; import { fill } from 'common/TypedArrayUtils'; -export const RENDER_MODEL_INDICIES_PER_CELL = 4; +export const RENDER_MODEL_INDICIES_PER_CELL = 3; export const COMBINED_CHAR_BIT_MASK = 0x80000000; diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 9acbc8df..8bbd1b64 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -22,6 +22,7 @@ import { IRenderDimensions, IRenderer, IRequestRefreshRowsEvent } from 'browser/ import { IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { CellData } from 'common/buffer/CellData'; +import { MODEL_BG_OFFSET, MODEL_FG_OFFSET } from './Constants'; export const INDICIES_PER_CELL = 4; @@ -273,7 +274,9 @@ export class WebglRenderer extends Disposable implements IRenderer { let fg = this._workCell.fg; // Nothing has changed, no updates needed - if (this._model.cells[i] === code && this._model.cells[i + 2] === bg && this._model.cells[i + 3] === fg) { + if (this._model.cells[i] === code && + this._model.cells[i + MODEL_BG_OFFSET] === bg && + this._model.cells[i + MODEL_FG_OFFSET] === fg) { continue; } @@ -301,11 +304,9 @@ export class WebglRenderer extends Disposable implements IRenderer { } // Cache the results in the model - this._model.cells[i ] = code; - // TODO: Remove attr from model - this._model.cells[i + 1] = 0; - this._model.cells[i + 2] = bg; - this._model.cells[i + 3] = fg; + this._model.cells[i] = code; + this._model.cells[i + MODEL_BG_OFFSET] = bg; + this._model.cells[i + MODEL_FG_OFFSET] = fg; this._glyphRenderer.updateCell(x, y, code, bg, fg, chars); } diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 9d8eb286..b9c4a827 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -6,11 +6,10 @@ import { ICharAtlasConfig } from './Types'; import { DIM_OPACITY } from 'browser/renderer/atlas/Constants'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; -import { DEFAULT_COLOR, DEFAULT_ATTR, FgFlags, Attributes, BgFlags } from 'common/buffer/Constants'; +import { DEFAULT_COLOR, FgFlags, Attributes, BgFlags } from 'common/buffer/Constants'; import { is256Color } from './CharAtlasUtils'; import { throwIfFalsy } from '../WebglUtils'; import { IColor } from 'browser/Types'; -import { FLAGS } from '../Constants'; import { IDisposable } from 'xterm'; // In practice we're probably never going to exhaust a texture this large. For debugging purposes, From 39f0e17edf4ff0a64d51eea31f7e4c3a01db09a6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 23:05:39 -0800 Subject: [PATCH 08/24] Consolidate constants, fix rectangle rendering --- addons/xterm-addon-webgl/src/Constants.ts | 7 ------- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 5 ++--- addons/xterm-addon-webgl/src/RectangleRenderer.ts | 8 ++++---- addons/xterm-addon-webgl/src/RenderModel.ts | 2 ++ addons/xterm-addon-webgl/src/WebglRenderer.ts | 15 ++++++--------- 5 files changed, 14 insertions(+), 23 deletions(-) delete mode 100644 addons/xterm-addon-webgl/src/Constants.ts diff --git a/addons/xterm-addon-webgl/src/Constants.ts b/addons/xterm-addon-webgl/src/Constants.ts deleted file mode 100644 index bf39ec98..00000000 --- a/addons/xterm-addon-webgl/src/Constants.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2019 The xterm.js authors. All rights reserved. - * @license MIT - */ - -export const MODEL_BG_OFFSET = 2; -export const MODEL_FG_OFFSET = 3; diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index a28d5c10..7ec80907 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -6,8 +6,7 @@ import { createProgram, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils'; import { WebglCharAtlas } from './atlas/WebglCharAtlas'; import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types'; -import { INDICIES_PER_CELL } from './WebglRenderer'; -import { COMBINED_CHAR_BIT_MASK } from './RenderModel'; +import { COMBINED_CHAR_BIT_MASK, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; import { fill } from 'common/TypedArrayUtils'; import { slice } from './TypedArray'; import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants'; @@ -259,7 +258,7 @@ export class GlyphRenderer { const row = y + terminal.buffer.viewportY; let line: IBufferLine | undefined; for (let x = startCol; x < endCol; x++) { - const offset = (y * this._terminal.cols + x) * INDICIES_PER_CELL; + const offset = (y * this._terminal.cols + x) * RENDER_MODEL_INDICIES_PER_CELL; const code = model.cells[offset]; if (code & COMBINED_CHAR_BIT_MASK) { if (!line) { diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index 3a5f6417..0a088034 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -10,7 +10,7 @@ import { DEFAULT_COLOR, Attributes, FgFlags } from 'common/buffer/Constants'; import { Terminal } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; -import { MODEL_FG_OFFSET, MODEL_BG_OFFSET } from './Constants'; +import { RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; const enum VertexAttribLocations { POSITION = 0, @@ -249,9 +249,9 @@ export class RectangleRenderer { let currentBg = DEFAULT_COLOR; let currentFg = DEFAULT_COLOR; for (let x = 0; x < terminal.cols; x++) { - const modelIndex = ((y * terminal.cols) + x) * 4; - const bg = model.cells[modelIndex + MODEL_BG_OFFSET]; - const fg = model.cells[modelIndex + MODEL_FG_OFFSET]; + const modelIndex = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL; + const bg = model.cells[modelIndex + RENDER_MODEL_BG_OFFSET]; + const fg = model.cells[modelIndex + RENDER_MODEL_FG_OFFSET]; if (bg !== currentBg) { // A rectangle needs to be drawn if going from non-default to another color // TODO: DEFAULT_COLOR probably isn't right anymore? diff --git a/addons/xterm-addon-webgl/src/RenderModel.ts b/addons/xterm-addon-webgl/src/RenderModel.ts index f55111d4..2b48047f 100644 --- a/addons/xterm-addon-webgl/src/RenderModel.ts +++ b/addons/xterm-addon-webgl/src/RenderModel.ts @@ -7,6 +7,8 @@ import { IRenderModel, ISelectionRenderModel } from './Types'; import { fill } from 'common/TypedArrayUtils'; export const RENDER_MODEL_INDICIES_PER_CELL = 3; +export const RENDER_MODEL_BG_OFFSET = 1; +export const RENDER_MODEL_FG_OFFSET = 2; export const COMBINED_CHAR_BIT_MASK = 0x80000000; diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 8bbd1b64..4d6428f5 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -12,7 +12,7 @@ import { WebglCharAtlas } from './atlas/WebglCharAtlas'; import { RectangleRenderer } from './RectangleRenderer'; import { IWebGL2RenderingContext } from './Types'; import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel'; +import { RenderModel, COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; import { Disposable } from 'common/Lifecycle'; import { DEFAULT_COLOR, NULL_CELL_CODE, FgFlags } from 'common/buffer/Constants'; import { Terminal, IEvent } from 'xterm'; @@ -22,9 +22,6 @@ import { IRenderDimensions, IRenderer, IRequestRefreshRowsEvent } from 'browser/ import { IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { CellData } from 'common/buffer/CellData'; -import { MODEL_BG_OFFSET, MODEL_FG_OFFSET } from './Constants'; - -export const INDICIES_PER_CELL = 4; export class WebglRenderer extends Disposable implements IRenderer { private _renderLayers: IRenderLayer[]; @@ -263,7 +260,7 @@ export class WebglRenderer extends Disposable implements IRenderer { const chars = this._workCell.getChars(); let code = this._workCell.getCode(); - const i = ((y * terminal.cols) + x) * INDICIES_PER_CELL; + const i = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL; if (code !== NULL_CELL_CODE) { this._model.lineLengths[y] = x + 1; @@ -275,8 +272,8 @@ export class WebglRenderer extends Disposable implements IRenderer { // Nothing has changed, no updates needed if (this._model.cells[i] === code && - this._model.cells[i + MODEL_BG_OFFSET] === bg && - this._model.cells[i + MODEL_FG_OFFSET] === fg) { + this._model.cells[i + RENDER_MODEL_BG_OFFSET] === bg && + this._model.cells[i + RENDER_MODEL_FG_OFFSET] === fg) { continue; } @@ -305,8 +302,8 @@ export class WebglRenderer extends Disposable implements IRenderer { // Cache the results in the model this._model.cells[i] = code; - this._model.cells[i + MODEL_BG_OFFSET] = bg; - this._model.cells[i + MODEL_FG_OFFSET] = fg; + this._model.cells[i + RENDER_MODEL_BG_OFFSET] = bg; + this._model.cells[i + RENDER_MODEL_FG_OFFSET] = fg; this._glyphRenderer.updateCell(x, y, code, bg, fg, chars); } From 3773b22439b6630aac5c838a225e93cae91b7694 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 9 Nov 2019 23:41:00 -0800 Subject: [PATCH 09/24] Support true color... mostly --- .../src/RectangleRenderer.ts | 22 +++++++++------ .../src/atlas/WebglCharAtlas.ts | 27 ++++++++++++++++--- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index 0a088034..4e711846 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -11,6 +11,7 @@ import { Terminal } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; import { RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; +import { AttributeData } from 'common/buffer/AttributeData'; const enum VertexAttribLocations { POSITION = 0, @@ -274,26 +275,31 @@ export class RectangleRenderer { } private _updateRectangle(vertices: IVertices, offset: number, fg: number, bg: number, startX: number, endX: number, y: number): void { - let color: IColor | null = null; + let rgba: number | undefined; + const colorMode = bg & Attributes.CM_MASK; if (fg & FgFlags.INVERSE) { // Inverted color - color = this._colors.foreground; + rgba = this._colors.foreground.rgba; } else if ((bg & Attributes.CM_MASK) === Attributes.CM_P16 || (bg & Attributes.CM_MASK) === Attributes.CM_P256) { // 256 palette - color = this._colors.ansi[bg & Attributes.PCOLOR_MASK]; + rgba = this._colors.ansi[bg & Attributes.PCOLOR_MASK].rgba; + } else if (colorMode === Attributes.CM_RGB) { + // True color + // TODO: Use a switch instead? + rgba = (bg & Attributes.RGB_MASK) << 8; } else { - // TODO: Support true color // Default color - color = this._colors.background; + rgba = this._colors.background.rgba; } if (vertices.attributes.length < offset + 4) { vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE); } const x1 = startX * this._dimensions.scaledCellWidth; const y1 = y * this._dimensions.scaledCellHeight; - const r = ((color.rgba >> 24) & 0xFF) / 255; - const g = ((color.rgba >> 16) & 0xFF) / 255; - const b = ((color.rgba >> 8 ) & 0xFF) / 255; + const r = ((rgba >> 24) & 0xFF) / 255; + const g = ((rgba >> 16) & 0xFF) / 255; + const b = ((rgba >> 8 ) & 0xFF) / 255; + console.log(r, g, b); this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, 1); } diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index b9c4a827..00b24988 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -11,6 +11,7 @@ import { is256Color } from './CharAtlasUtils'; import { throwIfFalsy } from '../WebglUtils'; import { IColor } from 'browser/Types'; import { IDisposable } from 'xterm'; +import { AttributeData } from 'common/buffer/AttributeData'; // 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. @@ -186,18 +187,33 @@ export class WebglCharAtlas implements IDisposable { return this._config.colors.foreground; } else if (is256Color(bg)) { return this._getColorFromAnsiIndex(bg & Attributes.PCOLOR_MASK); + } else if ((bg & Attributes.CM_MASK) === Attributes.CM_RGB) { + // TODO: Use a switch for the color mode? + // True color + const rgb = bg & Attributes.RGB_MASK; + const arr = AttributeData.toColorRGB(rgb); + // TODO: This object creation is slow + return { + rgba: rgb << 255, + css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` + }; } - // TODO: Support true color return this._config.colors.background; } - private _getForegroundColor(fg: number): IColor { + private _getForegroundColor(fg: number): { css: string } { + // TODO: Just return the string value if (fg & FgFlags.INVERSE) { return this._config.colors.background; } else if (is256Color(fg)) { return this._getColorFromAnsiIndex(fg & Attributes.PCOLOR_MASK); + } else if ((fg & Attributes.CM_MASK) === Attributes.CM_RGB) { + // TODO: Use a switch for the color mode? + // TODO: True color + const rgb = fg & Attributes.RGB_MASK; + const arr = AttributeData.toColorRGB(rgb); + return { css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` }; } - // TODO: Support true color return this._config.colors.foreground; } @@ -411,3 +427,8 @@ function clearColor(imageData: ImageData, color: IColor): boolean { } return isEmpty; } + +function toPaddedHex(c: number): string { + const s = c.toString(16); + return s.length < 2 ? '0' + s : s; +} From a2da8f9fbb3dd5a66bcf63f81222c15848168f42 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 10 Nov 2019 00:23:08 -0800 Subject: [PATCH 10/24] Fix true color glyphs not having background cleared --- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 00b24988..0dc3b974 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -194,7 +194,7 @@ export class WebglCharAtlas implements IDisposable { const arr = AttributeData.toColorRGB(rgb); // TODO: This object creation is slow return { - rgba: rgb << 255, + rgba: rgb << 8, css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` }; } From b13e9066bdc028045457fed73851d408dd0b06aa Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 10 Nov 2019 00:29:50 -0800 Subject: [PATCH 11/24] Use a switch for color mode conditions --- .../src/RectangleRenderer.ts | 23 ++++---- .../src/atlas/WebglCharAtlas.ts | 54 +++++++++++-------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index 4e711846..ed7e8f0c 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -280,17 +280,21 @@ export class RectangleRenderer { if (fg & FgFlags.INVERSE) { // Inverted color rgba = this._colors.foreground.rgba; - } else if ((bg & Attributes.CM_MASK) === Attributes.CM_P16 || (bg & Attributes.CM_MASK) === Attributes.CM_P256) { - // 256 palette - rgba = this._colors.ansi[bg & Attributes.PCOLOR_MASK].rgba; - } else if (colorMode === Attributes.CM_RGB) { - // True color - // TODO: Use a switch instead? - rgba = (bg & Attributes.RGB_MASK) << 8; } else { - // Default color - rgba = this._colors.background.rgba; + switch (colorMode) { + case Attributes.CM_P16: + case Attributes.CM_P256: + rgba = this._colors.ansi[bg & Attributes.PCOLOR_MASK].rgba; + break; + case Attributes.CM_RGB: + rgba = (bg & Attributes.RGB_MASK) << 8; + break; + case Attributes.CM_DEFAULT: + default: + rgba = this._colors.background.rgba; + } } + if (vertices.attributes.length < offset + 4) { vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE); } @@ -299,7 +303,6 @@ export class RectangleRenderer { const r = ((rgba >> 24) & 0xFF) / 255; const g = ((rgba >> 16) & 0xFF) / 255; const b = ((rgba >> 8 ) & 0xFF) / 255; - console.log(r, g, b); this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, 1); } diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 0dc3b974..9a923863 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -185,36 +185,46 @@ export class WebglCharAtlas implements IDisposable { return TRANSPARENT_COLOR; } else if (fg & FgFlags.INVERSE) { return this._config.colors.foreground; - } else if (is256Color(bg)) { - return this._getColorFromAnsiIndex(bg & Attributes.PCOLOR_MASK); - } else if ((bg & Attributes.CM_MASK) === Attributes.CM_RGB) { - // TODO: Use a switch for the color mode? - // True color - const rgb = bg & Attributes.RGB_MASK; - const arr = AttributeData.toColorRGB(rgb); - // TODO: This object creation is slow - return { - rgba: rgb << 8, - css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` - }; } - return this._config.colors.background; + + const colorMode = bg & Attributes.CM_MASK; + switch (colorMode) { + case Attributes.CM_P16: + case Attributes.CM_P256: + return this._getColorFromAnsiIndex(bg & Attributes.PCOLOR_MASK); + case Attributes.CM_RGB: + const rgb = bg & Attributes.RGB_MASK; + const arr = AttributeData.toColorRGB(rgb); + // TODO: This object creation is slow + return { + rgba: rgb << 8, + css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` + }; + case Attributes.CM_DEFAULT: + default: + return this._config.colors.background; + } } private _getForegroundColor(fg: number): { css: string } { // TODO: Just return the string value if (fg & FgFlags.INVERSE) { return this._config.colors.background; - } else if (is256Color(fg)) { - return this._getColorFromAnsiIndex(fg & Attributes.PCOLOR_MASK); - } else if ((fg & Attributes.CM_MASK) === Attributes.CM_RGB) { - // TODO: Use a switch for the color mode? - // TODO: True color - const rgb = fg & Attributes.RGB_MASK; - const arr = AttributeData.toColorRGB(rgb); - return { css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` }; } - return this._config.colors.foreground; + + const colorMode = fg & Attributes.CM_MASK; + switch (colorMode) { + case Attributes.CM_P16: + case Attributes.CM_P256: + return this._getColorFromAnsiIndex(fg & Attributes.PCOLOR_MASK); + case Attributes.CM_RGB: + const rgb = fg & Attributes.RGB_MASK; + const arr = AttributeData.toColorRGB(rgb); + return { css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` }; + case Attributes.CM_DEFAULT: + default: + return this._config.colors.foreground; + } } private _drawToCache(code: number, bg: number, fg: number): IRasterizedGlyph; From 149cc76803c79d525a69bea4862d872eae67e91c Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 10 Nov 2019 00:30:58 -0800 Subject: [PATCH 12/24] Avoid extra object creation for foreground fill --- .../xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 9a923863..69acfdbf 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -206,24 +206,23 @@ export class WebglCharAtlas implements IDisposable { } } - private _getForegroundColor(fg: number): { css: string } { - // TODO: Just return the string value + private _getForegroundCss(fg: number): string { if (fg & FgFlags.INVERSE) { - return this._config.colors.background; + return this._config.colors.background.css; } const colorMode = fg & Attributes.CM_MASK; switch (colorMode) { case Attributes.CM_P16: case Attributes.CM_P256: - return this._getColorFromAnsiIndex(fg & Attributes.PCOLOR_MASK); + return this._getColorFromAnsiIndex(fg & Attributes.PCOLOR_MASK).css; case Attributes.CM_RGB: const rgb = fg & Attributes.RGB_MASK; const arr = AttributeData.toColorRGB(rgb); - return { css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}` }; + return `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}`; case Attributes.CM_DEFAULT: default: - return this._config.colors.foreground; + return this._config.colors.foreground.css; } } @@ -256,7 +255,7 @@ export class WebglCharAtlas implements IDisposable { `${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`; this._tmpCtx.textBaseline = 'top'; - this._tmpCtx.fillStyle = this._getForegroundColor(fg).css; + this._tmpCtx.fillStyle = this._getForegroundCss(fg); // Apply alpha to dim the character if (dim) { From b56e29a35bfc7ff26c7fd7e702df744fecaa4a6e Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 10 Nov 2019 00:39:46 -0800 Subject: [PATCH 13/24] Import clean up --- addons/xterm-addon-webgl/src/RectangleRenderer.ts | 1 - addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts | 2 +- addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index ed7e8f0c..7746acb1 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -11,7 +11,6 @@ import { Terminal } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; import { RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; -import { AttributeData } from 'common/buffer/AttributeData'; const enum VertexAttribLocations { POSITION = 0, diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 821b53a4..1fd4c4f6 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -4,7 +4,7 @@ */ import { ICharAtlasConfig } from './Types'; -import { DEFAULT_COLOR, Attributes } from 'common/buffer/Constants'; +import { Attributes } from 'common/buffer/Constants'; import { Terminal, FontWeight } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 69acfdbf..c364c3c1 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -7,7 +7,6 @@ import { ICharAtlasConfig } from './Types'; import { DIM_OPACITY } from 'browser/renderer/atlas/Constants'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; import { DEFAULT_COLOR, FgFlags, Attributes, BgFlags } from 'common/buffer/Constants'; -import { is256Color } from './CharAtlasUtils'; import { throwIfFalsy } from '../WebglUtils'; import { IColor } from 'browser/Types'; import { IDisposable } from 'xterm'; From 811307562ba9b4eca27f930f51096d3bbeb7a2fc Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 10 Nov 2019 00:56:43 -0800 Subject: [PATCH 14/24] Use actual default color for rectangle renderer --- addons/xterm-addon-webgl/src/RectangleRenderer.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index 7746acb1..d5e245c0 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -6,7 +6,7 @@ import { createProgram, expandFloat32Array, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils'; import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelectionRenderModel } from './Types'; import { fill } from 'common/TypedArrayUtils'; -import { DEFAULT_COLOR, Attributes, FgFlags } from 'common/buffer/Constants'; +import { Attributes, FgFlags } from 'common/buffer/Constants'; import { Terminal } from 'xterm'; import { IColorSet, IColor } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; @@ -246,16 +246,15 @@ export class RectangleRenderer { for (let y = 0; y < terminal.rows; y++) { let currentStartX = -1; - let currentBg = DEFAULT_COLOR; - let currentFg = DEFAULT_COLOR; + let currentBg = 0; + let currentFg = 0; for (let x = 0; x < terminal.cols; x++) { const modelIndex = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL; const bg = model.cells[modelIndex + RENDER_MODEL_BG_OFFSET]; const fg = model.cells[modelIndex + RENDER_MODEL_FG_OFFSET]; if (bg !== currentBg) { // A rectangle needs to be drawn if going from non-default to another color - // TODO: DEFAULT_COLOR probably isn't right anymore? - if (currentBg !== DEFAULT_COLOR) { + if (currentBg !== 0) { const offset = rectangleCount++ * INDICES_PER_RECTANGLE; this._updateRectangle(vertices, offset, currentFg, currentBg, currentStartX, x, y); } @@ -265,7 +264,7 @@ export class RectangleRenderer { } } // Finish rectangle if it's still going - if (currentBg !== DEFAULT_COLOR) { + if (currentBg !== 0) { const offset = rectangleCount++ * INDICES_PER_RECTANGLE; this._updateRectangle(vertices, offset, currentFg, currentBg, currentStartX, terminal.cols, y); } From 01628362f566524e55aa15f58f3ac1fd5178336c Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 10 Nov 2019 01:19:27 -0800 Subject: [PATCH 15/24] Support selection color --- addons/xterm-addon-webgl/src/ColorUtils.ts | 14 ----------- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 23 ++++++++----------- addons/xterm-addon-webgl/src/WebglRenderer.ts | 14 ----------- 3 files changed, 9 insertions(+), 42 deletions(-) delete mode 100644 addons/xterm-addon-webgl/src/ColorUtils.ts diff --git a/addons/xterm-addon-webgl/src/ColorUtils.ts b/addons/xterm-addon-webgl/src/ColorUtils.ts deleted file mode 100644 index 80372e65..00000000 --- a/addons/xterm-addon-webgl/src/ColorUtils.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license MIT - * Copyright (c) 2018 The xterm.js authors. All rights reserved. - */ - -import { IColor } from 'browser/Types'; - -export function getLuminance(color: IColor): number { - // Coefficients taken from: https://www.w3.org/TR/AERT/#color-contrast - const r = color.rgba >> 24 & 0xff; - const g = color.rgba >> 16 & 0xff; - const b = color.rgba >> 8 & 0xff; - return (0.299 * r + 0.587 * g + 0.114 * b) / 255; -} diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 7ec80907..3ee9cdb5 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -6,11 +6,10 @@ import { createProgram, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils'; import { WebglCharAtlas } from './atlas/WebglCharAtlas'; import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types'; -import { COMBINED_CHAR_BIT_MASK, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel'; +import { COMBINED_CHAR_BIT_MASK, RENDER_MODEL_INDICIES_PER_CELL, RENDER_MODEL_FG_OFFSET } from './RenderModel'; import { fill } from 'common/TypedArrayUtils'; import { slice } from './TypedArray'; import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, Attributes } from 'common/buffer/Constants'; -import { getLuminance } from './ColorUtils'; import { Terminal, IBufferLine } from 'xterm'; import { IColorSet } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; @@ -219,41 +218,37 @@ export class GlyphRenderer { this._vertices.selectionAttributes = slice(this._vertices.attributes, 0); - // TODO: Make fg and bg configurable, currently since the buffer doesn't - // support truecolor the char atlas cannot store it. - const lumi = getLuminance(this._colors.background); - const fg = (lumi > 0.5 ? 7 : 0) | Attributes.CM_P16; - const bg = (lumi > 0.5 ? 0 : 7) | Attributes.CM_P16; + const bg = (this._colors.selection.rgba >>> 8) | Attributes.CM_RGB; if (columnSelectMode) { const startCol = model.selection.startCol; const width = model.selection.endCol - startCol; const height = model.selection.viewportCappedEndRow - model.selection.viewportCappedStartRow + 1; for (let y = model.selection.viewportCappedStartRow; y < model.selection.viewportCappedStartRow + height; y++) { - this._updateSelectionRange(startCol, startCol + width, y, model, bg, fg); + this._updateSelectionRange(startCol, startCol + width, y, model, bg); } } else { // Draw first row const startCol = model.selection.viewportStartRow === model.selection.viewportCappedStartRow ? model.selection.startCol : 0; const startRowEndCol = model.selection.viewportCappedStartRow === model.selection.viewportCappedEndRow ? model.selection.endCol : terminal.cols; - this._updateSelectionRange(startCol, startRowEndCol, model.selection.viewportCappedStartRow, model, bg, fg); + this._updateSelectionRange(startCol, startRowEndCol, model.selection.viewportCappedStartRow, model, bg); // Draw middle rows const middleRowsCount = Math.max(model.selection.viewportCappedEndRow - model.selection.viewportCappedStartRow - 1, 0); for (let y = model.selection.viewportCappedStartRow + 1; y <= model.selection.viewportCappedStartRow + middleRowsCount; y++) { - this._updateSelectionRange(0, startRowEndCol, y, model, bg, fg); + this._updateSelectionRange(0, startRowEndCol, y, model, bg); } // Draw final row if (model.selection.viewportCappedStartRow !== model.selection.viewportCappedEndRow) { // Only draw viewportEndRow if it's not the same as viewportStartRow const endCol = model.selection.viewportEndRow === model.selection.viewportCappedEndRow ? model.selection.endCol : terminal.cols; - this._updateSelectionRange(0, endCol, model.selection.viewportCappedEndRow, model, bg, fg); + this._updateSelectionRange(0, endCol, model.selection.viewportCappedEndRow, model, bg); } } } - private _updateSelectionRange(startCol: number, endCol: number, y: number, model: IRenderModel, bg: number, fg: number): void { + private _updateSelectionRange(startCol: number, endCol: number, y: number, model: IRenderModel, bg: number): void { const terminal = this._terminal; const row = y + terminal.buffer.viewportY; let line: IBufferLine | undefined; @@ -265,9 +260,9 @@ export class GlyphRenderer { line = terminal.buffer.getLine(row); } const chars = line!.getCell(x)!.char; - this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg, chars); + this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, model.cells[offset + RENDER_MODEL_FG_OFFSET], chars); } else { - this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, fg); + this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], bg, model.cells[offset + RENDER_MODEL_FG_OFFSET]); } } } diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 4d6428f5..5eae61db 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -16,7 +16,6 @@ import { RenderModel, COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MOD import { Disposable } from 'common/Lifecycle'; import { DEFAULT_COLOR, NULL_CELL_CODE, FgFlags } from 'common/buffer/Constants'; import { Terminal, IEvent } from 'xterm'; -import { getLuminance } from './ColorUtils'; import { IRenderLayer } from './renderLayer/Types'; import { IRenderDimensions, IRenderer, IRequestRefreshRowsEvent } from 'browser/renderer/Types'; import { IColorSet } from 'browser/Types'; @@ -52,8 +51,6 @@ export class WebglRenderer extends Disposable implements IRenderer { this._core = (this._terminal)._core; - this._applyBgLuminanceBasedSelection(); - this._renderLayers = [ new LinkRenderLayer(this._core.screenElement, 2, this._colors, this._core), new CursorRenderLayer(this._core.screenElement, 3, this._colors, this._onRequestRefreshRows) @@ -101,20 +98,9 @@ export class WebglRenderer extends Disposable implements IRenderer { super.dispose(); } - private _applyBgLuminanceBasedSelection(): void { - // HACK: This is needed until webgl renderer adds support for selection colors - if (getLuminance(this._colors.background) > 0.5) { - this._colors.selection = { css: '#000', rgba: 255 }; - } else { - this._colors.selection = { css: '#fff', rgba: 4294967295 }; - } - } - public setColors(colors: IColorSet): void { this._colors = colors; - this._applyBgLuminanceBasedSelection(); - // Clear layers and force a full render this._renderLayers.forEach(l => { l.setColors(this._terminal, this._colors); From 8bf837795ffff9f70b17e0714f13e173bd77cb7f Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 10:29:50 -0800 Subject: [PATCH 16/24] Add tests for webgl colors 16-255 --- .../src/WebglRenderer.api.ts | 81 +++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts index 51dae37a..3f7dee35 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts @@ -7,6 +7,7 @@ import * as puppeteer from 'puppeteer'; import { ITerminalOptions } from '../../../src/Types'; import { ITheme } from 'xterm'; import { assert } from 'chai'; +import deepEqual = require('deep-equal'); const APP = 'http://127.0.0.1:3000/test'; @@ -15,7 +16,7 @@ let page: puppeteer.Page; const width = 800; const height = 600; -describe('WebGL Renderer Integration Tests', function(): void { +describe.only('WebGL Renderer Integration Tests', function(): void { it('dispose removes renderer canvases', async () => { await setupBrowser(); assert.equal(await page.evaluate(`document.querySelectorAll('.xterm canvas').length`), 3); @@ -29,7 +30,7 @@ describe('WebGL Renderer Integration Tests', function(): void { after(async () => browser.close()); beforeEach(async () => page.evaluate(`window.term.reset()`)); - it('foreground colors normal', async () => { + it('foreground 0-15', async () => { const theme: ITheme = { black: '#010203', red: '#040506', @@ -52,7 +53,7 @@ describe('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); - it('foreground colors bright', async () => { + it('foreground 0-15 bright', async () => { const theme: ITheme = { brightBlack: '#010203', brightRed: '#040506', @@ -75,7 +76,7 @@ describe('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); - it('background colors normal', async () => { + it('background 0-15 normal', async () => { const theme: ITheme = { black: '#010203', red: '#040506', @@ -98,7 +99,7 @@ describe('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); - it('background colors bright', async () => { + it('background 0-15 bright', async () => { const theme: ITheme = { brightBlack: '#010203', brightRed: '#040506', @@ -120,6 +121,46 @@ describe('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(7, 1), [19, 20, 21, 255]); await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); + + it('background 16-255', async function(): Promise { + let data = ''; + for (let x = 0; x < 240 / 16; x++) { + for (let y = 0; y < 16; y++) { + data += `\\x1b[48;5;${16 + x * 16 + y}m \x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 240 / 16; y++) { + for (let x = 0; x < 16; x++) { + const cssColor = COLORS_16_TO_255[y * 16 + x]; + const r = parseInt(cssColor.substr(1, 2), 16); + const g = parseInt(cssColor.substr(3, 2), 16); + const b = parseInt(cssColor.substr(5, 2), 16); + await pollFor(page, () => getCellColor(x + 1, y + 1), [r, g, b, 255]); + } + } + }); + + it('foreground 16-255', async function(): Promise { + let data = ''; + for (let x = 0; x < 240 / 16; x++) { + for (let y = 0; y < 16; y++) { + data += `\\x1b[38;5;${16 + x * 16 + y}m█\x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 240 / 16; y++) { + for (let x = 0; x < 16; x++) { + const cssColor = COLORS_16_TO_255[y * 16 + x]; + const r = parseInt(cssColor.substr(1, 2), 16); + const g = parseInt(cssColor.substr(3, 2), 16); + const b = parseInt(cssColor.substr(5, 2), 16); + await pollFor(page, () => getCellColor(x + 1, y + 1), [r, g, b, 255]); + } + } + }); }); }); @@ -168,20 +209,32 @@ async function setupBrowser(): Promise { `); } -async function pollFor(page: puppeteer.Page, evalOrFn: string | (() => Promise), val: T, preFn?: () => Promise): Promise { +export async function pollFor(page: puppeteer.Page, evalOrFn: string | (() => Promise), val: T, preFn?: () => Promise): Promise { if (preFn) { await preFn(); } const result = typeof evalOrFn === 'string' ? await page.evaluate(evalOrFn) : await evalOrFn(); - let equal = false; - if (typeof result === 'object') { - equal = Object.keys(result).every(e => result[e] === (val as any)[e]); - } else { - equal = result === val; - } - if (!equal) { + if (!deepEqual(result, val)) { return new Promise(r => { - setTimeout(() => r(pollFor(page, evalOrFn, val, preFn)), 10); + setTimeout(() => r(pollFor(page, evalOrFn, val, preFn)), 1); }); } } + +const COLORS_16_TO_255 = [ + '#000000', '#00005f', '#000087', '#0000af', '#0000d7', '#0000ff', '#005f00', '#005f5f', '#005f87', '#005faf', '#005fd7', '#005fff', '#008700', '#00875f', '#008787', '#0087af', + '#0087d7', '#0087ff', '#00af00', '#00af5f', '#00af87', '#00afaf', '#00afd7', '#00afff', '#00d700', '#00d75f', '#00d787', '#00d7af', '#00d7d7', '#00d7ff', '#00ff00', '#00ff5f', + '#00ff87', '#00ffaf', '#00ffd7', '#00ffff', '#5f0000', '#5f005f', '#5f0087', '#5f00af', '#5f00d7', '#5f00ff', '#5f5f00', '#5f5f5f', '#5f5f87', '#5f5faf', '#5f5fd7', '#5f5fff', + '#5f8700', '#5f875f', '#5f8787', '#5f87af', '#5f87d7', '#5f87ff', '#5faf00', '#5faf5f', '#5faf87', '#5fafaf', '#5fafd7', '#5fafff', '#5fd700', '#5fd75f', '#5fd787', '#5fd7af', + '#5fd7d7', '#5fd7ff', '#5fff00', '#5fff5f', '#5fff87', '#5fffaf', '#5fffd7', '#5fffff', '#870000', '#87005f', '#870087', '#8700af', '#8700d7', '#8700ff', '#875f00', '#875f5f', + '#875f87', '#875faf', '#875fd7', '#875fff', '#878700', '#87875f', '#878787', '#8787af', '#8787d7', '#8787ff', '#87af00', '#87af5f', '#87af87', '#87afaf', '#87afd7', '#87afff', + '#87d700', '#87d75f', '#87d787', '#87d7af', '#87d7d7', '#87d7ff', '#87ff00', '#87ff5f', '#87ff87', '#87ffaf', '#87ffd7', '#87ffff', '#af0000', '#af005f', '#af0087', '#af00af', + '#af00d7', '#af00ff', '#af5f00', '#af5f5f', '#af5f87', '#af5faf', '#af5fd7', '#af5fff', '#af8700', '#af875f', '#af8787', '#af87af', '#af87d7', '#af87ff', '#afaf00', '#afaf5f', + '#afaf87', '#afafaf', '#afafd7', '#afafff', '#afd700', '#afd75f', '#afd787', '#afd7af', '#afd7d7', '#afd7ff', '#afff00', '#afff5f', '#afff87', '#afffaf', '#afffd7', '#afffff', + '#d70000', '#d7005f', '#d70087', '#d700af', '#d700d7', '#d700ff', '#d75f00', '#d75f5f', '#d75f87', '#d75faf', '#d75fd7', '#d75fff', '#d78700', '#d7875f', '#d78787', '#d787af', + '#d787d7', '#d787ff', '#d7af00', '#d7af5f', '#d7af87', '#d7afaf', '#d7afd7', '#d7afff', '#d7d700', '#d7d75f', '#d7d787', '#d7d7af', '#d7d7d7', '#d7d7ff', '#d7ff00', '#d7ff5f', + '#d7ff87', '#d7ffaf', '#d7ffd7', '#d7ffff', '#ff0000', '#ff005f', '#ff0087', '#ff00af', '#ff00d7', '#ff00ff', '#ff5f00', '#ff5f5f', '#ff5f87', '#ff5faf', '#ff5fd7', '#ff5fff', + '#ff8700', '#ff875f', '#ff8787', '#ff87af', '#ff87d7', '#ff87ff', '#ffaf00', '#ffaf5f', '#ffaf87', '#ffafaf', '#ffafd7', '#ffafff', '#ffd700', '#ffd75f', '#ffd787', '#ffd7af', + '#ffd7d7', '#ffd7ff', '#ffff00', '#ffff5f', '#ffff87', '#ffffaf', '#ffffd7', '#ffffff', '#080808', '#121212', '#1c1c1c', '#262626', '#303030', '#3a3a3a', '#444444', '#4e4e4e', + '#585858', '#626262', '#6c6c6c', '#767676', '#808080', '#8a8a8a', '#949494', '#9e9e9e', '#a8a8a8', '#b2b2b2', '#bcbcbc', '#c6c6c6', '#d0d0d0', '#dadada', '#e4e4e4', '#eeeeee' +]; From 753ad30dbc0b48b96483d31fbdbf38d18c1f5d3d Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 10:38:19 -0800 Subject: [PATCH 17/24] Add true color fg tests for webgl --- .../src/WebglRenderer.api.ts | 88 +++++++++++++++++-- 1 file changed, 80 insertions(+), 8 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts index 3f7dee35..71add30a 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts @@ -122,11 +122,11 @@ describe.only('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); - it('background 16-255', async function(): Promise { + it('background 16-255', async () => { let data = ''; - for (let x = 0; x < 240 / 16; x++) { - for (let y = 0; y < 16; y++) { - data += `\\x1b[48;5;${16 + x * 16 + y}m \x1b[0m`; + for (let y = 0; y < 240 / 16; y++) { + for (let x = 0; x < 16; x++) { + data += `\\x1b[48;5;${16 + y * 16 + x}m \x1b[0m`; } data += '\\r\\n'; } @@ -142,11 +142,11 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } }); - it('foreground 16-255', async function(): Promise { + it('foreground 16-255', async () => { let data = ''; - for (let x = 0; x < 240 / 16; x++) { - for (let y = 0; y < 16; y++) { - data += `\\x1b[38;5;${16 + x * 16 + y}m█\x1b[0m`; + for (let y = 0; y < 240 / 16; y++) { + for (let x = 0; x < 16; x++) { + data += `\\x1b[38;5;${16 + y * 16 + x}m█\x1b[0m`; } data += '\\r\\n'; } @@ -161,6 +161,78 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } } }); + + it('foreground true color red', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[38;2;${i};0;0m█\x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [i, 0, 0, 255]); + } + } + }); + + it('foreground true color green', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[38;2;0;${i};0m█\x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [0, i, 0, 255]); + } + } + }); + + it('foreground true color blue', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[38;2;0;0;${i}m█\x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [0, 0, i, 255]); + } + } + }); + + it('foreground true color grey', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[38;2;${i};${i};${i}m█\x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [i, i, i, 255]); + } + } + }); }); }); From 350ca8d5fb08000857e6a792f098560d257fac6b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 10:39:56 -0800 Subject: [PATCH 18/24] Organize tests --- .../src/WebglRenderer.api.ts | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts index 71add30a..bb2f5969 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts @@ -53,6 +53,29 @@ describe.only('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); + it('background 0-15', async () => { + const theme: ITheme = { + black: '#010203', + red: '#040506', + green: '#070809', + yellow: '#0a0b0c', + blue: '#0d0e0f', + magenta: '#101112', + cyan: '#131415', + white: '#161718' + }; + await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`); + await writeSync(`\\x1b[40m \\x1b[41m \\x1b[42m \\x1b[43m \\x1b[44m \\x1b[45m \\x1b[46m \\x1b[47m `); + await pollFor(page, () => getCellColor(1, 1), [1, 2, 3, 255]); + await pollFor(page, () => getCellColor(2, 1), [4, 5, 6, 255]); + await pollFor(page, () => getCellColor(3, 1), [7, 8, 9, 255]); + await pollFor(page, () => getCellColor(4, 1), [10, 11, 12, 255]); + await pollFor(page, () => getCellColor(5, 1), [13, 14, 15, 255]); + await pollFor(page, () => getCellColor(6, 1), [16, 17, 18, 255]); + await pollFor(page, () => getCellColor(7, 1), [19, 20, 21, 255]); + await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); + }); + it('foreground 0-15 bright', async () => { const theme: ITheme = { brightBlack: '#010203', @@ -76,29 +99,6 @@ describe.only('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); - it('background 0-15 normal', async () => { - const theme: ITheme = { - black: '#010203', - red: '#040506', - green: '#070809', - yellow: '#0a0b0c', - blue: '#0d0e0f', - magenta: '#101112', - cyan: '#131415', - white: '#161718' - }; - await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`); - await writeSync(`\\x1b[40m \\x1b[41m \\x1b[42m \\x1b[43m \\x1b[44m \\x1b[45m \\x1b[46m \\x1b[47m `); - await pollFor(page, () => getCellColor(1, 1), [1, 2, 3, 255]); - await pollFor(page, () => getCellColor(2, 1), [4, 5, 6, 255]); - await pollFor(page, () => getCellColor(3, 1), [7, 8, 9, 255]); - await pollFor(page, () => getCellColor(4, 1), [10, 11, 12, 255]); - await pollFor(page, () => getCellColor(5, 1), [13, 14, 15, 255]); - await pollFor(page, () => getCellColor(6, 1), [16, 17, 18, 255]); - await pollFor(page, () => getCellColor(7, 1), [19, 20, 21, 255]); - await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); - }); - it('background 0-15 bright', async () => { const theme: ITheme = { brightBlack: '#010203', @@ -122,11 +122,11 @@ describe.only('WebGL Renderer Integration Tests', function(): void { await pollFor(page, () => getCellColor(8, 1), [22, 23, 24, 255]); }); - it('background 16-255', async () => { + it('foreground 16-255', async () => { let data = ''; for (let y = 0; y < 240 / 16; y++) { for (let x = 0; x < 16; x++) { - data += `\\x1b[48;5;${16 + y * 16 + x}m \x1b[0m`; + data += `\\x1b[38;5;${16 + y * 16 + x}m█\x1b[0m`; } data += '\\r\\n'; } @@ -142,11 +142,11 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } }); - it('foreground 16-255', async () => { + it('background 16-255', async () => { let data = ''; for (let y = 0; y < 240 / 16; y++) { for (let x = 0; x < 16; x++) { - data += `\\x1b[38;5;${16 + y * 16 + x}m█\x1b[0m`; + data += `\\x1b[48;5;${16 + y * 16 + x}m \x1b[0m`; } data += '\\r\\n'; } From 2b2bd91e2ef5a8208e569add26b8e91679ea7908 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 10:41:15 -0800 Subject: [PATCH 19/24] Add background true color tests --- .../src/WebglRenderer.api.ts | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts index bb2f5969..304973fe 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.api.ts @@ -16,7 +16,7 @@ let page: puppeteer.Page; const width = 800; const height = 600; -describe.only('WebGL Renderer Integration Tests', function(): void { +describe('WebGL Renderer Integration Tests', function(): void { it('dispose removes renderer canvases', async () => { await setupBrowser(); assert.equal(await page.evaluate(`document.querySelectorAll('.xterm canvas').length`), 3); @@ -180,6 +180,24 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } }); + it('background true color red', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[48;2;${i};0;0m \x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [i, 0, 0, 255]); + } + } + }); + it('foreground true color green', async () => { let data = ''; for (let y = 0; y < 16; y++) { @@ -198,6 +216,24 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } }); + it('background true color green', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[48;2;0;${i};0m \x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [0, i, 0, 255]); + } + } + }); + it('foreground true color blue', async () => { let data = ''; for (let y = 0; y < 16; y++) { @@ -216,6 +252,24 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } }); + it('background true color blue', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[48;2;0;0;${i}m \x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [0, 0, i, 255]); + } + } + }); + it('foreground true color grey', async () => { let data = ''; for (let y = 0; y < 16; y++) { @@ -233,6 +287,24 @@ describe.only('WebGL Renderer Integration Tests', function(): void { } } }); + + it('background true color grey', async () => { + let data = ''; + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + data += `\\x1b[48;2;${i};${i};${i}m \x1b[0m`; + } + data += '\\r\\n'; + } + await writeSync(data); + for (let y = 0; y < 16; y++) { + for (let x = 0; x < 16; x++) { + const i = y * 16 + x; + await pollFor(page, () => getCellColor(x + 1, y + 1), [i, i, i, 255]); + } + } + }); }); }); From 53b0149764a94471c6a3dcb32510505cf837f928 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 11:11:26 -0800 Subject: [PATCH 20/24] Add selectionOpaque and factor out color into new file --- .../src/atlas/CharAtlasUtils.ts | 1 + src/browser/Color.test.ts | 31 ++++++++++ src/browser/Color.ts | 39 +++++++++++++ src/browser/ColorManager.ts | 56 ++++++++----------- src/browser/Types.d.ts | 2 + 5 files changed, 96 insertions(+), 33 deletions(-) create mode 100644 src/browser/Color.test.ts create mode 100644 src/browser/Color.ts diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 1fd4c4f6..03867b41 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -21,6 +21,7 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number cursor: NULL_COLOR, cursorAccent: NULL_COLOR, selection: NULL_COLOR, + selectionOpaque: NULL_COLOR, // For the static char atlas, we only use the first 16 colors, but we need all 256 for the // dynamic character atlas. ansi: colors.ansi.slice() diff --git a/src/browser/Color.test.ts b/src/browser/Color.test.ts new file mode 100644 index 00000000..fc75d4b9 --- /dev/null +++ b/src/browser/Color.test.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { assert } from 'chai'; +import { blend } from 'browser/Color'; + +describe('Color', () => { + describe('blend', () => { + it('should blend colors based on the alpha channel', () => { + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF00', rgba: 0xFFFFFF00 }), { css: '#000000', rgba: 0x000000FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF10', rgba: 0xFFFFFF10 }), { css: '#101010', rgba: 0x101010FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF20', rgba: 0xFFFFFF20 }), { css: '#202020', rgba: 0x202020FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF30', rgba: 0xFFFFFF30 }), { css: '#303030', rgba: 0x303030FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF40', rgba: 0xFFFFFF40 }), { css: '#404040', rgba: 0x404040FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF50', rgba: 0xFFFFFF50 }), { css: '#505050', rgba: 0x505050FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF60', rgba: 0xFFFFFF60 }), { css: '#606060', rgba: 0x606060FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF70', rgba: 0xFFFFFF70 }), { css: '#707070', rgba: 0x707070FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF80', rgba: 0xFFFFFF80 }), { css: '#808080', rgba: 0x808080FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFF90', rgba: 0xFFFFFF90 }), { css: '#909090', rgba: 0x909090FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFA0', rgba: 0xFFFFFFA0 }), { css: '#a0a0a0', rgba: 0xA0A0A0FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFB0', rgba: 0xFFFFFFB0 }), { css: '#b0b0b0', rgba: 0xB0B0B0FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFC0', rgba: 0xFFFFFFC0 }), { css: '#c0c0c0', rgba: 0xC0C0C0FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFD0', rgba: 0xFFFFFFD0 }), { css: '#d0d0d0', rgba: 0xD0D0D0FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFE0', rgba: 0xFFFFFFE0 }), { css: '#e0e0e0', rgba: 0xE0E0E0FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFF0', rgba: 0xFFFFFFF0 }), { css: '#f0f0f0', rgba: 0xF0F0F0FF }); + assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFFF', rgba: 0xFFFFFFFF }), { css: '#FFFFFFFF', rgba: 0xFFFFFFFF }); + }); + }); +}); diff --git a/src/browser/Color.ts b/src/browser/Color.ts new file mode 100644 index 00000000..31087116 --- /dev/null +++ b/src/browser/Color.ts @@ -0,0 +1,39 @@ +import { IColor } from './Types'; + +export function blend(bg: IColor, fg: IColor): IColor { + const a = (fg.rgba & 0xFF) / 255; + if (a === 1) { + return { + css: fg.css, + rgba: fg.rgba + }; + } + const fgR = (fg.rgba >> 24) & 0xFF; + const fgG = (fg.rgba >> 16) & 0xFF; + const fgB = (fg.rgba >> 8) & 0xFF; + const bgR = (bg.rgba >> 24) & 0xFF; + const bgG = (bg.rgba >> 16) & 0xFF; + const bgB = (bg.rgba >> 8) & 0xFF; + const r = bgR + Math.round((fgR - bgR) * a); + const g = bgG + Math.round((fgG - bgG) * a); + const b = bgB + Math.round((fgB - bgB) * a); + const css = toCss(r, g, b); + const rgba = ((r << 24) | (g << 16) | (b << 8) | 0xFF) >>> 0; + return { css, rgba }; +} + +export function fromCss(css: string): IColor { + return { + css, + rgba: parseInt(css.slice(1), 16) << 8 | 0xFF + }; +} + +export function toPaddedHex(c: number): string { + const s = c.toString(16); + return s.length < 2 ? '0' + s : s; +} + +export function toCss(r: number, g: number, b: number): string { + return `#${toPaddedHex(r)}${toPaddedHex(g)}${toPaddedHex(b)}`; +} diff --git a/src/browser/ColorManager.ts b/src/browser/ColorManager.ts index 70d21a7a..a1bfc105 100644 --- a/src/browser/ColorManager.ts +++ b/src/browser/ColorManager.ts @@ -5,11 +5,12 @@ import { IColorManager, IColor, IColorSet } from 'browser/Types'; import { ITheme } from 'common/services/Services'; +import { fromCss, toPaddedHex, toCss, blend } from 'browser/Color'; -const DEFAULT_FOREGROUND = fromHex('#ffffff'); -const DEFAULT_BACKGROUND = fromHex('#000000'); -const DEFAULT_CURSOR = fromHex('#ffffff'); -const DEFAULT_CURSOR_ACCENT = fromHex('#000000'); +const DEFAULT_FOREGROUND = fromCss('#ffffff'); +const DEFAULT_BACKGROUND = fromCss('#000000'); +const DEFAULT_CURSOR = fromCss('#ffffff'); +const DEFAULT_CURSOR_ACCENT = fromCss('#000000'); const DEFAULT_SELECTION = { css: 'rgba(255, 255, 255, 0.3)', rgba: 0xFFFFFF77 @@ -20,23 +21,23 @@ const DEFAULT_SELECTION = { export const DEFAULT_ANSI_COLORS = (() => { const colors = [ // dark: - fromHex('#2e3436'), - fromHex('#cc0000'), - fromHex('#4e9a06'), - fromHex('#c4a000'), - fromHex('#3465a4'), - fromHex('#75507b'), - fromHex('#06989a'), - fromHex('#d3d7cf'), + fromCss('#2e3436'), + fromCss('#cc0000'), + fromCss('#4e9a06'), + fromCss('#c4a000'), + fromCss('#3465a4'), + fromCss('#75507b'), + fromCss('#06989a'), + fromCss('#d3d7cf'), // bright: - fromHex('#555753'), - fromHex('#ef2929'), - fromHex('#8ae234'), - fromHex('#fce94f'), - fromHex('#729fcf'), - fromHex('#ad7fa8'), - fromHex('#34e2e2'), - fromHex('#eeeeec') + fromCss('#555753'), + fromCss('#ef2929'), + fromCss('#8ae234'), + fromCss('#fce94f'), + fromCss('#729fcf'), + fromCss('#ad7fa8'), + fromCss('#34e2e2'), + fromCss('#eeeeec') ]; // Fill in the remaining 240 ANSI colors. @@ -47,7 +48,7 @@ export const DEFAULT_ANSI_COLORS = (() => { const g = v[(i / 6) % 6 | 0]; const b = v[i % 6]; colors.push({ - css: `#${toPaddedHex(r)}${toPaddedHex(g)}${toPaddedHex(b)}`, + css: toCss(r, g, b), // Use >>> 0 to force a conversion to an unsigned int rgba: ((r << 24) | (g << 16) | (b << 8) | 0xFF) >>> 0 }); @@ -66,18 +67,6 @@ export const DEFAULT_ANSI_COLORS = (() => { return colors; })(); -function fromHex(css: string): IColor { - return { - css, - rgba: parseInt(css.slice(1), 16) << 8 | 0xFF - }; -} - -function toPaddedHex(c: number): string { - const s = c.toString(16); - return s.length < 2 ? '0' + s : s; -} - /** * Manages the source of truth for a terminal's colors. */ @@ -103,6 +92,7 @@ export class ColorManager implements IColorManager { cursor: DEFAULT_CURSOR, cursorAccent: DEFAULT_CURSOR_ACCENT, selection: DEFAULT_SELECTION, + selectionOpaque: blend(DEFAULT_BACKGROUND, DEFAULT_SELECTION), ansi: DEFAULT_ANSI_COLORS.slice() }; } diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index aa7a4c86..ca852b6a 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -21,6 +21,8 @@ export interface IColorSet { cursor: IColor; cursorAccent: IColor; selection: IColor; + /** The selection blended on top of background. */ + selectionOpaque: IColor; ansi: IColor[]; } From 51c77568a8ad2dc1db4bb0fdd1f52183a2dab7b3 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 11:17:36 -0800 Subject: [PATCH 21/24] Add tests for Color functions --- src/browser/Color.test.ts | 68 ++++++++++++++++++++++++++++++++++++++- src/browser/Color.ts | 2 +- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/src/browser/Color.test.ts b/src/browser/Color.test.ts index fc75d4b9..5542611f 100644 --- a/src/browser/Color.test.ts +++ b/src/browser/Color.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { blend } from 'browser/Color'; +import { blend, fromCss, toPaddedHex, toCss } from 'browser/Color'; describe('Color', () => { describe('blend', () => { @@ -28,4 +28,70 @@ describe('Color', () => { assert.deepEqual(blend({ css: '#000000', rgba: 0x000000FF }, { css: '#FFFFFFFF', rgba: 0xFFFFFFFF }), { css: '#FFFFFFFF', rgba: 0xFFFFFFFF }); }); }); + + describe('fromCss', () => { + it('should covert a CSS string to an IColor', () => { + assert.deepEqual(fromCss('#000000'), { css: '#000000', rgba: 0x000000FF }); + assert.deepEqual(fromCss('#101010'), { css: '#101010', rgba: 0x101010FF }); + assert.deepEqual(fromCss('#202020'), { css: '#202020', rgba: 0x202020FF }); + assert.deepEqual(fromCss('#303030'), { css: '#303030', rgba: 0x303030FF }); + assert.deepEqual(fromCss('#404040'), { css: '#404040', rgba: 0x404040FF }); + assert.deepEqual(fromCss('#505050'), { css: '#505050', rgba: 0x505050FF }); + assert.deepEqual(fromCss('#606060'), { css: '#606060', rgba: 0x606060FF }); + assert.deepEqual(fromCss('#707070'), { css: '#707070', rgba: 0x707070FF }); + assert.deepEqual(fromCss('#808080'), { css: '#808080', rgba: 0x808080FF }); + assert.deepEqual(fromCss('#909090'), { css: '#909090', rgba: 0x909090FF }); + assert.deepEqual(fromCss('#a0a0a0'), { css: '#a0a0a0', rgba: 0xa0a0a0FF }); + assert.deepEqual(fromCss('#b0b0b0'), { css: '#b0b0b0', rgba: 0xb0b0b0FF }); + assert.deepEqual(fromCss('#c0c0c0'), { css: '#c0c0c0', rgba: 0xc0c0c0FF }); + assert.deepEqual(fromCss('#d0d0d0'), { css: '#d0d0d0', rgba: 0xd0d0d0FF }); + assert.deepEqual(fromCss('#e0e0e0'), { css: '#e0e0e0', rgba: 0xe0e0e0FF }); + assert.deepEqual(fromCss('#f0f0f0'), { css: '#f0f0f0', rgba: 0xf0f0f0FF }); + assert.deepEqual(fromCss('#ffffff'), { css: '#ffffff', rgba: 0xffffffFF }); + }); + }); + + describe('toPaddedHex', () => { + it('should convert numbers to 2-digit hex values', () => { + assert.equal(toPaddedHex(0x00), '00'); + assert.equal(toPaddedHex(0x10), '10'); + assert.equal(toPaddedHex(0x20), '20'); + assert.equal(toPaddedHex(0x30), '30'); + assert.equal(toPaddedHex(0x40), '40'); + assert.equal(toPaddedHex(0x50), '50'); + assert.equal(toPaddedHex(0x60), '60'); + assert.equal(toPaddedHex(0x70), '70'); + assert.equal(toPaddedHex(0x80), '80'); + assert.equal(toPaddedHex(0x90), '90'); + assert.equal(toPaddedHex(0xa0), 'a0'); + assert.equal(toPaddedHex(0xb0), 'b0'); + assert.equal(toPaddedHex(0xc0), 'c0'); + assert.equal(toPaddedHex(0xd0), 'd0'); + assert.equal(toPaddedHex(0xe0), 'e0'); + assert.equal(toPaddedHex(0xf0), 'f0'); + assert.equal(toPaddedHex(0xff), 'ff'); + }); + }); + + describe('toCss', () => { + it('should convert an rgb array to css hex string', () => { + assert.equal(toCss(0x00, 0x00, 0x00), '#000000'); + assert.equal(toCss(0x10, 0x10, 0x10), '#101010'); + assert.equal(toCss(0x20, 0x20, 0x20), '#202020'); + assert.equal(toCss(0x30, 0x30, 0x30), '#303030'); + assert.equal(toCss(0x40, 0x40, 0x40), '#404040'); + assert.equal(toCss(0x50, 0x50, 0x50), '#505050'); + assert.equal(toCss(0x60, 0x60, 0x60), '#606060'); + assert.equal(toCss(0x70, 0x70, 0x70), '#707070'); + assert.equal(toCss(0x80, 0x80, 0x80), '#808080'); + assert.equal(toCss(0x90, 0x90, 0x90), '#909090'); + assert.equal(toCss(0xa0, 0xa0, 0xa0), '#a0a0a0'); + assert.equal(toCss(0xb0, 0xb0, 0xb0), '#b0b0b0'); + assert.equal(toCss(0xc0, 0xc0, 0xc0), '#c0c0c0'); + assert.equal(toCss(0xd0, 0xd0, 0xd0), '#d0d0d0'); + assert.equal(toCss(0xe0, 0xe0, 0xe0), '#e0e0e0'); + assert.equal(toCss(0xf0, 0xf0, 0xf0), '#f0f0f0'); + assert.equal(toCss(0xff, 0xff, 0xff), '#ffffff'); + }); + }); }); diff --git a/src/browser/Color.ts b/src/browser/Color.ts index 31087116..9771f656 100644 --- a/src/browser/Color.ts +++ b/src/browser/Color.ts @@ -25,7 +25,7 @@ export function blend(bg: IColor, fg: IColor): IColor { export function fromCss(css: string): IColor { return { css, - rgba: parseInt(css.slice(1), 16) << 8 | 0xFF + rgba: (parseInt(css.slice(1), 16) << 8 | 0xFF) >>> 0 }; } From 2da77dd5f8dfe729bcfdd8499d5070b559566052 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 11:23:34 -0800 Subject: [PATCH 22/24] Use opaque selection in webgl, fix selection default rgba --- addons/xterm-addon-webgl/src/GlyphRenderer.ts | 2 +- addons/xterm-addon-webgl/src/RectangleRenderer.ts | 2 +- src/browser/Color.ts | 5 +++++ src/browser/ColorManager.ts | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 3ee9cdb5..3d4d43d1 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -218,7 +218,7 @@ export class GlyphRenderer { this._vertices.selectionAttributes = slice(this._vertices.attributes, 0); - const bg = (this._colors.selection.rgba >>> 8) | Attributes.CM_RGB; + const bg = (this._colors.selectionOpaque.rgba >>> 8) | Attributes.CM_RGB; if (columnSelectMode) { const startCol = model.selection.startCol; diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index d5e245c0..8dcc5c08 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -155,7 +155,7 @@ export class RectangleRenderer { private _updateCachedColors(): void { this._bgFloat = this._colorToFloat32Array(this._colors.background); - this._selectionFloat = this._colorToFloat32Array(this._colors.selection); + this._selectionFloat = this._colorToFloat32Array(this._colors.selectionOpaque); } private _updateViewportRectangle(): void { diff --git a/src/browser/Color.ts b/src/browser/Color.ts index 9771f656..5e86d5e9 100644 --- a/src/browser/Color.ts +++ b/src/browser/Color.ts @@ -1,3 +1,8 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + import { IColor } from './Types'; export function blend(bg: IColor, fg: IColor): IColor { diff --git a/src/browser/ColorManager.ts b/src/browser/ColorManager.ts index a1bfc105..170fead6 100644 --- a/src/browser/ColorManager.ts +++ b/src/browser/ColorManager.ts @@ -13,7 +13,7 @@ const DEFAULT_CURSOR = fromCss('#ffffff'); const DEFAULT_CURSOR_ACCENT = fromCss('#000000'); const DEFAULT_SELECTION = { css: 'rgba(255, 255, 255, 0.3)', - rgba: 0xFFFFFF77 + rgba: 0xFFFFFF4D }; // An IIFE to generate DEFAULT_ANSI_COLORS. Do not mutate DEFAULT_ANSI_COLORS, instead make a copy @@ -108,6 +108,7 @@ export class ColorManager implements IColorManager { this.colors.cursor = this._parseColor(theme.cursor, DEFAULT_CURSOR, true); this.colors.cursorAccent = this._parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT, true); this.colors.selection = this._parseColor(theme.selection, DEFAULT_SELECTION, true); + this.colors.selectionOpaque = blend(this.colors.background, this.colors.selection); this.colors.ansi[0] = this._parseColor(theme.black, DEFAULT_ANSI_COLORS[0]); this.colors.ansi[1] = this._parseColor(theme.red, DEFAULT_ANSI_COLORS[1]); this.colors.ansi[2] = this._parseColor(theme.green, DEFAULT_ANSI_COLORS[2]); From 734bd8c96a43f7ed38e1bdf377b014533d4a7928 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 11:30:48 -0800 Subject: [PATCH 23/24] Factor out toRgba function and test --- src/browser/Color.test.ts | 43 ++++++++++++++++++++++++++++++++++++- src/browser/Color.ts | 7 +++++- src/browser/ColorManager.ts | 12 +++++------ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/browser/Color.test.ts b/src/browser/Color.test.ts index 5542611f..44cd52f3 100644 --- a/src/browser/Color.test.ts +++ b/src/browser/Color.test.ts @@ -4,7 +4,7 @@ */ import { assert } from 'chai'; -import { blend, fromCss, toPaddedHex, toCss } from 'browser/Color'; +import { blend, fromCss, toPaddedHex, toCss, toRgba } from 'browser/Color'; describe('Color', () => { describe('blend', () => { @@ -94,4 +94,45 @@ describe('Color', () => { assert.equal(toCss(0xff, 0xff, 0xff), '#ffffff'); }); }); + + describe('toRgba', () => { + it('should convert an rgb array to an rgba number', () => { + assert.equal(toRgba(0x00, 0x00, 0x00), 0x000000FF); + assert.equal(toRgba(0x10, 0x10, 0x10), 0x101010FF); + assert.equal(toRgba(0x20, 0x20, 0x20), 0x202020FF); + assert.equal(toRgba(0x30, 0x30, 0x30), 0x303030FF); + assert.equal(toRgba(0x40, 0x40, 0x40), 0x404040FF); + assert.equal(toRgba(0x50, 0x50, 0x50), 0x505050FF); + assert.equal(toRgba(0x60, 0x60, 0x60), 0x606060FF); + assert.equal(toRgba(0x70, 0x70, 0x70), 0x707070FF); + assert.equal(toRgba(0x80, 0x80, 0x80), 0x808080FF); + assert.equal(toRgba(0x90, 0x90, 0x90), 0x909090FF); + assert.equal(toRgba(0xa0, 0xa0, 0xa0), 0xa0a0a0FF); + assert.equal(toRgba(0xb0, 0xb0, 0xb0), 0xb0b0b0FF); + assert.equal(toRgba(0xc0, 0xc0, 0xc0), 0xc0c0c0FF); + assert.equal(toRgba(0xd0, 0xd0, 0xd0), 0xd0d0d0FF); + assert.equal(toRgba(0xe0, 0xe0, 0xe0), 0xe0e0e0FF); + assert.equal(toRgba(0xf0, 0xf0, 0xf0), 0xf0f0f0FF); + assert.equal(toRgba(0xff, 0xff, 0xff), 0xffffffFF); + }); + it('should convert an rgba array to an rgba number', () => { + assert.equal(toRgba(0x00, 0x00, 0x00, 0x00), 0x00000000); + assert.equal(toRgba(0x10, 0x10, 0x10, 0x10), 0x10101010); + assert.equal(toRgba(0x20, 0x20, 0x20, 0x20), 0x20202020); + assert.equal(toRgba(0x30, 0x30, 0x30, 0x30), 0x30303030); + assert.equal(toRgba(0x40, 0x40, 0x40, 0x40), 0x40404040); + assert.equal(toRgba(0x50, 0x50, 0x50, 0x50), 0x50505050); + assert.equal(toRgba(0x60, 0x60, 0x60, 0x60), 0x60606060); + assert.equal(toRgba(0x70, 0x70, 0x70, 0x70), 0x70707070); + assert.equal(toRgba(0x80, 0x80, 0x80, 0x80), 0x80808080); + assert.equal(toRgba(0x90, 0x90, 0x90, 0x90), 0x90909090); + assert.equal(toRgba(0xa0, 0xa0, 0xa0, 0xa0), 0xa0a0a0a0); + assert.equal(toRgba(0xb0, 0xb0, 0xb0, 0xb0), 0xb0b0b0b0); + assert.equal(toRgba(0xc0, 0xc0, 0xc0, 0xc0), 0xc0c0c0c0); + assert.equal(toRgba(0xd0, 0xd0, 0xd0, 0xd0), 0xd0d0d0d0); + assert.equal(toRgba(0xe0, 0xe0, 0xe0, 0xe0), 0xe0e0e0e0); + assert.equal(toRgba(0xf0, 0xf0, 0xf0, 0xf0), 0xf0f0f0f0); + assert.equal(toRgba(0xff, 0xff, 0xff, 0xff), 0xffffffff); + }); + }); }); diff --git a/src/browser/Color.ts b/src/browser/Color.ts index 5e86d5e9..51c1a446 100644 --- a/src/browser/Color.ts +++ b/src/browser/Color.ts @@ -23,7 +23,7 @@ export function blend(bg: IColor, fg: IColor): IColor { const g = bgG + Math.round((fgG - bgG) * a); const b = bgB + Math.round((fgB - bgB) * a); const css = toCss(r, g, b); - const rgba = ((r << 24) | (g << 16) | (b << 8) | 0xFF) >>> 0; + const rgba = toRgba(r, g, b); return { css, rgba }; } @@ -42,3 +42,8 @@ export function toPaddedHex(c: number): string { export function toCss(r: number, g: number, b: number): string { return `#${toPaddedHex(r)}${toPaddedHex(g)}${toPaddedHex(b)}`; } + +export function toRgba(r: number, g: number, b: number, a: number = 0xFF): number { + // >>> 0 forces an unsigned int + return (r << 24 | g << 16 | b << 8 | a) >>> 0; +} diff --git a/src/browser/ColorManager.ts b/src/browser/ColorManager.ts index 170fead6..c6354f71 100644 --- a/src/browser/ColorManager.ts +++ b/src/browser/ColorManager.ts @@ -5,7 +5,7 @@ import { IColorManager, IColor, IColorSet } from 'browser/Types'; import { ITheme } from 'common/services/Services'; -import { fromCss, toPaddedHex, toCss, blend } from 'browser/Color'; +import { fromCss, toCss, blend, toRgba } from 'browser/Color'; const DEFAULT_FOREGROUND = fromCss('#ffffff'); const DEFAULT_BACKGROUND = fromCss('#000000'); @@ -49,18 +49,16 @@ export const DEFAULT_ANSI_COLORS = (() => { const b = v[i % 6]; colors.push({ css: toCss(r, g, b), - // Use >>> 0 to force a conversion to an unsigned int - rgba: ((r << 24) | (g << 16) | (b << 8) | 0xFF) >>> 0 + rgba: toRgba(r, g, b) }); } // Generate greys (232-255) for (let i = 0; i < 24; i++) { const c = 8 + i * 10; - const ch = toPaddedHex(c); colors.push({ - css: `#${ch}${ch}${ch}`, - rgba: ((c << 24) | (c << 16) | (c << 8) | 0xFF) >>> 0 + css: toCss(c, c, c), + rgba: toRgba(c, c, c) }); } @@ -175,7 +173,7 @@ export class ColorManager implements IColorManager { return { css, - rgba: (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]) >>> 0 + rgba: toRgba(data[0], data[1], data[2], data[3]) }; } } From e89d79b879a4aa8550a7957e78aeafd584effa56 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 10 Nov 2019 11:33:41 -0800 Subject: [PATCH 24/24] Remove unused code --- .../src/renderLayer/BaseRenderLayer.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index 0e2d645e..29487ad0 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -4,7 +4,6 @@ */ import { IRenderLayer } from './Types'; -import { IGlyphIdentifier } from '../atlas/Types'; import { acquireCharAtlas } from '../atlas/CharAtlasCache'; import { Terminal } from 'xterm'; import { IColorSet } from 'browser/Types'; @@ -25,19 +24,6 @@ export abstract class BaseRenderLayer implements IRenderLayer { protected _charAtlas: WebglCharAtlas | undefined; - /** - * An object that's reused when drawing glyphs in order to reduce GC. - */ - private _currentGlyphIdentifier: IGlyphIdentifier = { - chars: '', - code: 0, - bg: 0, - fg: 0, - bold: false, - dim: false, - italic: false - }; - constructor( private _container: HTMLElement, id: string,