From 365661704424f9a33b3a2cb4b85ad144948a86a9 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Wed, 13 Sep 2017 15:21:40 -0700 Subject: [PATCH] Start merging fg/bg layers, draw using SP-AA --- src/renderer/BaseRenderLayer.ts | 3 +- src/renderer/CharAtlas.ts | 2 +- src/renderer/CursorRenderLayer.ts | 2 +- src/renderer/LinkRenderLayer.ts | 2 +- src/renderer/Renderer.ts | 10 +++--- src/renderer/SelectionRenderLayer.ts | 2 +- ...roundRenderLayer.ts => TextRenderLayer.ts} | 35 +++++++++++-------- 7 files changed, 30 insertions(+), 26 deletions(-) rename src/renderer/{ForegroundRenderLayer.ts => TextRenderLayer.ts} (86%) diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 3bc0a9175..22d424070 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -25,12 +25,13 @@ export abstract class BaseRenderLayer implements IRenderLayer { container: HTMLElement, id: string, zIndex: number, + alpha: boolean, protected colors: IColorSet ) { this._canvas = document.createElement('canvas'); this._canvas.id = `xterm-${id}-layer`; this._canvas.style.zIndex = zIndex.toString(); - this._ctx = this._canvas.getContext('2d'); + this._ctx = this._canvas.getContext('2d', {alpha}); this._ctx.scale(window.devicePixelRatio, window.devicePixelRatio); container.appendChild(this._canvas); } diff --git a/src/renderer/CharAtlas.ts b/src/renderer/CharAtlas.ts index bf080cce5..45835a27b 100644 --- a/src/renderer/CharAtlas.ts +++ b/src/renderer/CharAtlas.ts @@ -120,7 +120,7 @@ class CharAtlasGenerator { constructor(private _document: Document) { this._canvas = this._document.createElement('canvas'); - this._ctx = this._canvas.getContext('2d'); + this._ctx = this._canvas.getContext('2d', {alpha: false}); this._ctx.scale(window.devicePixelRatio, window.devicePixelRatio); } diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index 8e25d7c16..faed9bfe3 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -31,7 +31,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _isFocused: boolean; constructor(container: HTMLElement, zIndex: number, colors: IColorSet) { - super(container, 'cursor', zIndex, colors); + super(container, 'cursor', zIndex, true, colors); this._state = { x: null, y: null, diff --git a/src/renderer/LinkRenderLayer.ts b/src/renderer/LinkRenderLayer.ts index ad1789334..980840349 100644 --- a/src/renderer/LinkRenderLayer.ts +++ b/src/renderer/LinkRenderLayer.ts @@ -15,7 +15,7 @@ export class LinkRenderLayer extends BaseRenderLayer { private _state: LinkHoverEvent = null; constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) { - super(container, 'link', zIndex, colors); + super(container, 'link', zIndex, true, colors); terminal.linkifier.on(LinkHoverEventTypes.HOVER, (e: LinkHoverEvent) => this._onLinkHover(e)); terminal.linkifier.on(LinkHoverEventTypes.LEAVE, (e: LinkHoverEvent) => this._onLinkLeave(e)); } diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 63782afdf..8e8934d68 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -5,8 +5,7 @@ import { ITerminal, ITheme } from '../Interfaces'; import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from '../Buffer'; -import { BackgroundRenderLayer } from './BackgroundRenderLayer'; -import { ForegroundRenderLayer } from './ForegroundRenderLayer'; +import { TextRenderLayer } from './TextRenderLayer'; import { SelectionRenderLayer } from './SelectionRenderLayer'; import { CursorRenderLayer } from './CursorRenderLayer'; import { ColorManager } from './ColorManager'; @@ -30,11 +29,10 @@ export class Renderer extends EventEmitter implements IRenderer { super(); this._colorManager = new ColorManager(); this._renderLayers = [ - new BackgroundRenderLayer(this._terminal.element, 0, this._colorManager.colors), + new TextRenderLayer(this._terminal.element, 0, this._colorManager.colors), new SelectionRenderLayer(this._terminal.element, 1, this._colorManager.colors), - new ForegroundRenderLayer(this._terminal.element, 2, this._colorManager.colors), - new LinkRenderLayer(this._terminal.element, 3, this._colorManager.colors, this._terminal), - new CursorRenderLayer(this._terminal.element, 4, this._colorManager.colors) + new LinkRenderLayer(this._terminal.element, 2, this._colorManager.colors, this._terminal), + new CursorRenderLayer(this._terminal.element, 3, this._colorManager.colors) ]; this.dimensions = { scaledCharWidth: null, diff --git a/src/renderer/SelectionRenderLayer.ts b/src/renderer/SelectionRenderLayer.ts index 5339c7a40..7a0aff839 100644 --- a/src/renderer/SelectionRenderLayer.ts +++ b/src/renderer/SelectionRenderLayer.ts @@ -14,7 +14,7 @@ export class SelectionRenderLayer extends BaseRenderLayer { private _state: {start: [number, number], end: [number, number]}; constructor(container: HTMLElement, zIndex: number, colors: IColorSet) { - super(container, 'selection', zIndex, colors); + super(container, 'selection', zIndex, true, colors); this._state = { start: null, end: null diff --git a/src/renderer/ForegroundRenderLayer.ts b/src/renderer/TextRenderLayer.ts similarity index 86% rename from src/renderer/ForegroundRenderLayer.ts rename to src/renderer/TextRenderLayer.ts index 19625466e..4b06ef427 100644 --- a/src/renderer/ForegroundRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -18,29 +18,34 @@ import { BaseRenderLayer, INVERTED_DEFAULT_COLOR } from './BaseRenderLayer'; */ const EMOJI_OWNED_CHAR_DATA: CharData = [null, '', 0, -1]; -export class ForegroundRenderLayer extends BaseRenderLayer { - private _state: GridCache; +export class TextRenderLayer extends BaseRenderLayer { + private _fgState: GridCache; + private _bgState: GridCache; constructor(container: HTMLElement, zIndex: number, colors: IColorSet) { - super(container, 'fg', zIndex, colors); - this._state = new GridCache(); + super(container, 'text', zIndex, false, colors); + this._fgState = new GridCache(); + this._bgState = new GridCache(); } public resize(terminal: ITerminal, dim: IRenderDimensions, charSizeChanged: boolean): void { super.resize(terminal, dim, charSizeChanged); // Resizing the canvas discards the contents of the canvas so clear state - this._state.clear(); - this._state.resize(terminal.cols, terminal.rows); + this._fgState.clear(); + this._bgState.clear(); + this._fgState.resize(terminal.cols, terminal.rows); + this._bgState.resize(terminal.cols, terminal.rows); } public reset(terminal: ITerminal): void { - this._state.clear(); + this._fgState.clear(); + this._bgState.clear(); this.clearAll(); } public onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void { // Resize has not been called yet - if (this._state.cache.length === 0) { + if (this._fgState.cache.length === 0) { return; } @@ -58,7 +63,7 @@ export class ForegroundRenderLayer extends BaseRenderLayer { // The character to the left is a wide character, drawing is owned by // the char at x-1 if (width === 0) { - this._state.cache[x][y] = null; + this._fgState.cache[x][y] = null; continue; } @@ -75,10 +80,10 @@ export class ForegroundRenderLayer extends BaseRenderLayer { } // Skip rendering if the character is identical - const state = this._state.cache[x][y]; + const state = this._fgState.cache[x][y]; if (state && state[CHAR_DATA_CHAR_INDEX] === char && state[CHAR_DATA_ATTR_INDEX] === attr) { // Skip render, contents are identical - this._state.cache[x][y] = charData; + this._fgState.cache[x][y] = charData; continue; } @@ -86,7 +91,7 @@ export class ForegroundRenderLayer extends BaseRenderLayer { if (state && state[CHAR_DATA_CODE_INDEX] !== 32 /*' '*/) { this._clearChar(x, y); } - this._state.cache[x][y] = charData; + this._fgState.cache[x][y] = charData; const flags = attr >> 18; @@ -104,14 +109,14 @@ export class ForegroundRenderLayer extends BaseRenderLayer { // space is added. Without this, the first half of `b` would never // get removed, and `a` would not re-render because it thinks it's // already in the correct state. - this._state.cache[x][y] = EMOJI_OWNED_CHAR_DATA; + this._fgState.cache[x][y] = EMOJI_OWNED_CHAR_DATA; if (x < line.length && line[x + 1][CHAR_DATA_CODE_INDEX] === 32 /*' '*/) { width = 2; this._clearChar(x + 1, y); // The emoji owned char data will force a clear and render when the // emoji is no longer to the left of the character and also when the // space changes to another character. - this._state.cache[x + 1][y] = EMOJI_OWNED_CHAR_DATA; + this._fgState.cache[x + 1][y] = EMOJI_OWNED_CHAR_DATA; } } @@ -176,7 +181,7 @@ export class ForegroundRenderLayer extends BaseRenderLayer { private _clearChar(x: number, y: number): void { let colsToClear = 1; // Clear the adjacent character if it was wide - const state = this._state.cache[x][y]; + const state = this._fgState.cache[x][y]; if (state && state[CHAR_DATA_WIDTH_INDEX] === 2) { colsToClear = 2; }