diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index dc375348..186cb2c1 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { createProgram, PROJECTION_MATRIX } from './WebglUtils'; +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'; @@ -75,7 +75,7 @@ const BYTES_PER_CELL = INDICES_PER_CELL * Float32Array.BYTES_PER_ELEMENT; const CELL_POSITION_INDICES = 2; export class GlyphRenderer { - private _atlas: WebglCharAtlas; + private _atlas: WebglCharAtlas | undefined; private _program: WebGLProgram; private _vertexArrayObject: IWebGLVertexArrayObject; @@ -104,12 +104,16 @@ export class GlyphRenderer { ) { const gl = this._gl; - this._program = createProgram(gl, vertexShaderSource, fragmentShaderSource); + const program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource)); + if (program === undefined) { + throw new Error('Could not create WebGL program'); + } + this._program = program; // Uniform locations - this._projectionLocation = gl.getUniformLocation(this._program, 'u_projection'); - this._resolutionLocation = gl.getUniformLocation(this._program, 'u_resolution'); - this._textureLocation = gl.getUniformLocation(this._program, 'u_texture'); + this._projectionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection')); + this._resolutionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_resolution')); + this._textureLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_texture')); // Create and set the vertex array object this._vertexArrayObject = gl.createVertexArray(); @@ -131,7 +135,7 @@ export class GlyphRenderer { gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW); // Setup attributes - this._attributesBuffer = gl.createBuffer(); + this._attributesBuffer = throwIfFalsy(gl.createBuffer()); gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer); gl.enableVertexAttribArray(VertexAttribLocations.OFFSET); gl.vertexAttribPointer(VertexAttribLocations.OFFSET, 2, gl.FLOAT, false, BYTES_PER_CELL, 0); @@ -150,7 +154,7 @@ export class GlyphRenderer { gl.vertexAttribDivisor(VertexAttribLocations.CELL_POSITION, 1); // Setup empty texture atlas - this._atlasTexture = gl.createTexture(); + this._atlasTexture = throwIfFalsy(gl.createTexture()); gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255])); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); @@ -165,7 +169,7 @@ export class GlyphRenderer { } public beginFrame(): boolean { - return this._atlas.beginFrame(); + return this._atlas ? this._atlas.beginFrame() : true; } public updateCell(x: number, y: number, code: number, attr: number, bg: number, fg: number, chars: string): void { @@ -184,6 +188,9 @@ export class GlyphRenderer { } let rasterizedGlyph: IRasterizedGlyph; + if (!this._atlas) { + throw new Error('atlas must be set before updating cell'); + } if (chars && chars.length > 1) { rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg); } else { @@ -264,7 +271,7 @@ export class GlyphRenderer { if (!line) { line = terminal.buffer.getLine(row); } - const chars = line.getCell(x).char; + const chars = line!.getCell(x)!.char; this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg, chars); } else { this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg); diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index d4ce3b4c..2c464d2a 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils'; +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'; @@ -66,8 +66,8 @@ export class RectangleRenderer { private _resolutionLocation: WebGLUniformLocation; private _attributesBuffer: WebGLBuffer; private _projectionLocation: WebGLUniformLocation; - private _bgFloat: Float32Array; - private _selectionFloat: Float32Array; + private _bgFloat!: Float32Array; + private _selectionFloat!: Float32Array; private _vertices: IVertices = { count: 0, @@ -83,11 +83,11 @@ export class RectangleRenderer { ) { const gl = this._gl; - this._program = createProgram(gl, vertexShaderSource, fragmentShaderSource); + this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource)); // Uniform locations - this._resolutionLocation = gl.getUniformLocation(this._program, 'u_resolution'); - this._projectionLocation = gl.getUniformLocation(this._program, 'u_projection'); + this._resolutionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_resolution')); + this._projectionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection')); // Create and set the vertex array object this._vertexArrayObject = gl.createVertexArray(); @@ -109,7 +109,7 @@ export class RectangleRenderer { gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW); // Setup attributes - this._attributesBuffer = gl.createBuffer(); + this._attributesBuffer = throwIfFalsy(gl.createBuffer()); gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer); gl.enableVertexAttribArray(VertexAttribLocations.POSITION); gl.vertexAttribPointer(VertexAttribLocations.POSITION, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 0); diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index defed962..3d41e1b5 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -27,7 +27,7 @@ export const INDICIES_PER_CELL = 4; export class WebglRenderer extends Disposable implements IRenderer { private _renderLayers: IRenderLayer[]; - private _charAtlas: WebglCharAtlas; + private _charAtlas: WebglCharAtlas | undefined; private _devicePixelRatio: number; private _model: RenderModel = new RenderModel(); @@ -57,18 +57,18 @@ export class WebglRenderer extends Disposable implements IRenderer { new CursorRenderLayer(this._core.screenElement, 3, this._colors) ]; this.dimensions = { - scaledCharWidth: null, - scaledCharHeight: null, - scaledCellWidth: null, - scaledCellHeight: null, - scaledCharLeft: null, - scaledCharTop: null, - scaledCanvasWidth: null, - scaledCanvasHeight: null, - canvasWidth: null, - canvasHeight: null, - actualCellWidth: null, - actualCellHeight: null + scaledCharWidth: 0, + scaledCharHeight: 0, + scaledCellWidth: 0, + scaledCellHeight: 0, + scaledCharLeft: 0, + scaledCharTop: 0, + scaledCanvasWidth: 0, + scaledCanvasHeight: 0, + canvasWidth: 0, + canvasHeight: 0, + actualCellWidth: 0, + actualCellHeight: 0 }; this._devicePixelRatio = window.devicePixelRatio; this._updateDimensions(); @@ -252,7 +252,7 @@ export class WebglRenderer extends Disposable implements IRenderer { for (let y = start; y <= end; y++) { const row = y + terminal.buffer.ydisp; - const line = terminal.buffer.lines.get(row); + 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); diff --git a/addons/xterm-addon-webgl/src/WebglUtils.ts b/addons/xterm-addon-webgl/src/WebglUtils.ts index 8f166a23..ff62388e 100644 --- a/addons/xterm-addon-webgl/src/WebglUtils.ts +++ b/addons/xterm-addon-webgl/src/WebglUtils.ts @@ -15,9 +15,9 @@ export const PROJECTION_MATRIX = new Float32Array([ ]); export function createProgram(gl: WebGLRenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram | undefined { - const program = gl.createProgram(); - gl.attachShader(program, createShader(gl, gl.VERTEX_SHADER, vertexSource)); - gl.attachShader(program, createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)); + const program = throwIfFalsy(gl.createProgram()); + gl.attachShader(program, throwIfFalsy(createShader(gl, gl.VERTEX_SHADER, vertexSource))); + gl.attachShader(program, throwIfFalsy(createShader(gl, gl.FRAGMENT_SHADER, fragmentSource))); gl.linkProgram(program); const success = gl.getProgramParameter(program, gl.LINK_STATUS); if (success) { @@ -29,7 +29,7 @@ export function createProgram(gl: WebGLRenderingContext, vertexSource: string, f } export function createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | undefined { - const shader = gl.createShader(type); + const shader = throwIfFalsy(gl.createShader(type)); gl.shaderSource(shader, source); gl.compileShader(shader); const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); @@ -49,3 +49,10 @@ export function expandFloat32Array(source: Float32Array, max: number): Float32Ar } return newArray; } + +export function throwIfFalsy(value: T | undefined | null): T { + if (!value) { + throw new Error('value must not be falsy'); + } + return value; +} diff --git a/addons/xterm-addon-webgl/src/atlas/BaseCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/BaseCharAtlas.ts deleted file mode 100644 index 470736f1..00000000 --- a/addons/xterm-addon-webgl/src/atlas/BaseCharAtlas.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -import { IGlyphIdentifier } from './Types'; -import { IDisposable } from 'xterm'; - -export abstract class BaseCharAtlas implements IDisposable { - private _didWarmUp: boolean = false; - - public dispose(): void { } - - /** - * Perform any work needed to warm the cache before it can be used. May be called multiple times. - * Implement _doWarmUp instead if you only want to get called once. - */ - public warmUp(): void { - if (!this._didWarmUp) { - this._doWarmUp(); - this._didWarmUp = true; - } - } - - /** - * Perform any work needed to warm the cache before it can be used. Used by the default - * implementation of warmUp(), and will only be called once. - */ - protected _doWarmUp(): void { } - - /** - * Called when we start drawing a new frame. - * - * TODO: We rely on this getting called by TextRenderLayer. This should really be called by - * Renderer instead, but we need to make Renderer the source-of-truth for the char atlas, instead - * of BaseRenderLayer. - */ - public beginFrame(): void { } - - /** - * May be called before warmUp finishes, however it is okay for the implementation to - * do nothing and return false in that case. - * - * @param ctx Where to draw the character onto. - * @param glyph Information about what to draw - * @param x The position on the context to start drawing at - * @param y The position on the context to start drawing at - * @returns The success state. True if we drew the character. - */ - public abstract draw( - ctx: CanvasRenderingContext2D, - glyph: IGlyphIdentifier, - x: number, - y: number - ): boolean; -} diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts index 647b96b4..5046006f 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasCache.ts @@ -4,14 +4,13 @@ */ import { generateConfig, configEquals } from './CharAtlasUtils'; -import { BaseCharAtlas } from './BaseCharAtlas'; import { WebglCharAtlas } from './WebglCharAtlas'; import { ICharAtlasConfig } from './Types'; import { Terminal } from 'xterm'; import { IColorSet } from 'browser/Types'; interface ICharAtlasCacheEntry { - atlas: BaseCharAtlas; + atlas: WebglCharAtlas; config: ICharAtlasConfig; // N.B. This implementation potentially holds onto copies of the terminal forever, so // this may cause memory leaks. @@ -31,7 +30,7 @@ export function acquireCharAtlas( colors: IColorSet, scaledCharWidth: number, scaledCharHeight: number -): BaseCharAtlas { +): WebglCharAtlas { const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors); // Check to see if the terminal already owns this config diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index 1c43dd70..857fa628 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -6,16 +6,21 @@ import { ICharAtlasConfig } from './Types'; import { DEFAULT_COLOR } from 'common/buffer/Constants'; import { Terminal, FontWeight } from 'xterm'; -import { IColorSet } from 'browser/Types'; +import { IColorSet, IColor } from 'browser/Types'; + +const NULL_COLOR: IColor = { + css: '', + rgba: 0 +}; export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig { // null out some fields that don't matter const clonedColors: IColorSet = { foreground: colors.foreground, background: colors.background, - cursor: null, - cursorAccent: null, - selection: null, + cursor: NULL_COLOR, + cursorAccent: NULL_COLOR, + selection: 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/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 6a941d55..8d8e995b 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -3,14 +3,15 @@ * @license MIT */ -import { IGlyphIdentifier, ICharAtlasConfig } from './Types'; +import { ICharAtlasConfig } from './Types'; import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { BaseCharAtlas } from './BaseCharAtlas'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types'; import { DEFAULT_COLOR, DEFAULT_ATTR } 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, // however, it can be useful to set this to a really tiny value, to verify that LRU eviction works. @@ -42,7 +43,9 @@ const NULL_RASTERIZED_GLYPH: IRasterizedGlyph = { const TMP_CANVAS_GLYPH_PADDING = 2; -export class WebglCharAtlas extends BaseCharAtlas { +export class WebglCharAtlas implements IDisposable { + private _didWarmUp: boolean = false; + private _cacheMap: { [code: number]: IRasterizedGlyphSet } = {}; private _cacheMapCombined: { [chars: string]: IRasterizedGlyphSet } = {}; @@ -67,20 +70,18 @@ export class WebglCharAtlas extends BaseCharAtlas { private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 }; constructor(document: Document, private _config: ICharAtlasConfig) { - super(); - this.cacheCanvas = document.createElement('canvas'); this.cacheCanvas.width = TEXTURE_WIDTH; this.cacheCanvas.height = TEXTURE_HEIGHT; // The canvas needs alpha because we use clearColor to convert the background color to alpha. // It might also contain some characters with transparent backgrounds if allowTransparency is // set. - this._cacheCtx = this.cacheCanvas.getContext('2d', {alpha: true}); + this._cacheCtx = throwIfFalsy(this.cacheCanvas.getContext('2d', {alpha: true})); this._tmpCanvas = document.createElement('canvas'); this._tmpCanvas.width = this._config.scaledCharWidth * 2 + TMP_CANVAS_GLYPH_PADDING * 2; this._tmpCanvas.height = this._config.scaledCharHeight + TMP_CANVAS_GLYPH_PADDING * 2; - this._tmpCtx = this._tmpCanvas.getContext('2d', {alpha: this._config.allowTransparency}); + this._tmpCtx = throwIfFalsy(this._tmpCanvas.getContext('2d', {alpha: this._config.allowTransparency})); // This is useful for debugging document.body.appendChild(this.cacheCanvas); @@ -92,6 +93,13 @@ export class WebglCharAtlas extends BaseCharAtlas { } } + public warmUp(): void { + if (!this._didWarmUp) { + this._doWarmUp(); + this._didWarmUp = true; + } + } + protected _doWarmUp(): void { // Pre-fill with ASCII 33-126 for (let i = 33; i < 126; i++) { @@ -146,15 +154,6 @@ export class WebglCharAtlas extends BaseCharAtlas { return rasterizedGlyph; } - public draw( - ctx: CanvasRenderingContext2D, - glyph: IGlyphIdentifier, - x: number, - y: number - ): boolean { - throw new Error('WebglCharAtlas is only compatible with the webgl renderer'); - } - private _getColorFromAnsiIndex(idx: number): IColor { if (idx >= this._config.colors.ansi.length) { throw new Error('No color found for idx ' + idx); diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index 0422440e..df0cdbab 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -8,17 +8,18 @@ import { ICellData } from 'common/Types'; import { DEFAULT_COLOR, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from 'common/buffer/Constants'; import { IGlyphIdentifier } from '../atlas/Types'; import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants'; -import { BaseCharAtlas } from '../atlas/BaseCharAtlas'; import { acquireCharAtlas } from '../atlas/CharAtlasCache'; import { Terminal } from 'xterm'; import { IColorSet } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; import { CellData } from 'common/buffer/CellData'; import { AttributeData } from 'common/buffer/AttributeData'; +import { WebglCharAtlas } from 'atlas/WebglCharAtlas'; +import { throwIfFalsy } from '../WebglUtils'; export abstract class BaseRenderLayer implements IRenderLayer { private _canvas: HTMLCanvasElement; - protected _ctx: CanvasRenderingContext2D; + protected _ctx!: CanvasRenderingContext2D; private _scaledCharWidth: number = 0; private _scaledCharHeight: number = 0; private _scaledCellWidth: number = 0; @@ -26,7 +27,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { private _scaledCharLeft: number = 0; private _scaledCharTop: number = 0; - protected _charAtlas: BaseCharAtlas; + protected _charAtlas: WebglCharAtlas | undefined; /** * An object that's reused when drawing glyphs in order to reduce GC. @@ -63,7 +64,7 @@ export abstract class BaseRenderLayer implements IRenderLayer { } private _initCanvas(): void { - this._ctx = this._canvas.getContext('2d', {alpha: this._alpha}); + this._ctx = throwIfFalsy(this._canvas.getContext('2d', {alpha: this._alpha})); // Draw the background if this is an opaque layer if (!this._alpha) { this._clearAll(); @@ -249,115 +250,6 @@ export abstract class BaseRenderLayer implements IRenderLayer { y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2); } - /** - * Draws one or more characters at a cell. If possible this will draw using - * the character atlas to reduce draw time. - * @param terminal The terminal. - * @param chars The character or characters. - * @param code The character code. - * @param width The width of the characters. - * @param x The column to draw at. - * @param y The row to draw at. - * @param fg The foreground color, in the format stored within the attributes. - * @param bg The background color, in the format stored within the attributes. - * This is used to validate whether a cached image can be used. - * @param bold Whether the text is bold. - */ - protected _drawChars(terminal: Terminal, cell: ICellData, x: number, y: number): void { - - // skip cache right away if we draw in RGB - // Note: to avoid bad runtime JoinedCellData will be skipped - // in the cache handler itself (atlasDidDraw == false) and - // fall through to uncached later down below - if (cell.isFgRGB() || cell.isBgRGB()) { - this._drawUncachedChars(terminal, cell, x, y); - return; - } - - let fg; - let bg; - if (cell.isInverse()) { - fg = (cell.isBgDefault()) ? INVERTED_DEFAULT_COLOR : cell.getBgColor(); - bg = (cell.isFgDefault()) ? INVERTED_DEFAULT_COLOR : cell.getFgColor(); - } else { - bg = (cell.isBgDefault()) ? DEFAULT_COLOR : cell.getBgColor(); - fg = (cell.isFgDefault()) ? DEFAULT_COLOR : cell.getFgColor(); - } - - const drawInBrightColor = terminal.getOption('drawBoldTextInBrightColors') && cell.isBold() && fg < 8 && fg !== INVERTED_DEFAULT_COLOR; - - fg += drawInBrightColor ? 8 : 0; - this._currentGlyphIdentifier.chars = cell.getChars() || WHITESPACE_CELL_CHAR; - this._currentGlyphIdentifier.code = cell.getCode() || WHITESPACE_CELL_CODE; - this._currentGlyphIdentifier.bg = bg; - this._currentGlyphIdentifier.fg = fg; - this._currentGlyphIdentifier.bold = !!cell.isBold(); - this._currentGlyphIdentifier.dim = !!cell.isDim(); - this._currentGlyphIdentifier.italic = !!cell.isItalic(); - const atlasDidDraw = this._charAtlas && this._charAtlas.draw( - this._ctx, - this._currentGlyphIdentifier, - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop - ); - - if (!atlasDidDraw) { - this._drawUncachedChars(terminal, cell, x, y); - } - } - - /** - * Draws one or more characters at one or more cells. The character(s) will be - * clipped to ensure that they fit with the cell(s), including the cell to the - * right if the last character is a wide character. - * @param terminal The terminal. - * @param chars The character. - * @param width The width of the character. - * @param fg The foreground color, in the format stored within the attributes. - * @param x The column to draw at. - * @param y The row to draw at. - */ - private _drawUncachedChars(terminal: Terminal, cell: ICellData, x: number, y: number): void { - this._ctx.save(); - this._ctx.font = this._getFont(terminal, !!cell.isBold(), !!cell.isItalic()); - this._ctx.textBaseline = 'middle'; - - if (cell.isInverse()) { - if (cell.isBgDefault()) { - this._ctx.fillStyle = this._colors.background.css; - } else if (cell.isBgRGB()) { - this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getBgColor()).join(',')})`; - } else { - this._ctx.fillStyle = this._colors.ansi[cell.getBgColor()].css; - } - } else { - if (cell.isFgDefault()) { - this._ctx.fillStyle = this._colors.foreground.css; - } else if (cell.isFgRGB()) { - this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`; - } else { - let fg = cell.getFgColor(); - if (terminal.getOption('drawBoldTextInBrightColors') && cell.isBold() && fg < 8) { - fg += 8; - } - this._ctx.fillStyle = this._colors.ansi[fg].css; - } - } - - this._clipRow(terminal, y); - - // Apply alpha to dim the character - if (cell.isDim()) { - this._ctx.globalAlpha = DIM_OPACITY; - } - // Draw the character - this._ctx.fillText( - cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2); - this._ctx.restore(); - } - /** * Clips a row to ensure no pixels will be drawn outside the cells in the row. * @param terminal The terminal. diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index 09abe82a..6aed5f53 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -26,17 +26,17 @@ const BLINK_INTERVAL = 600; export class CursorRenderLayer extends BaseRenderLayer { private _state: ICursorState; private _cursorRenderers: {[key: string]: (terminal: Terminal, x: number, y: number, cell: ICellData) => void}; - private _cursorBlinkStateManager: CursorBlinkStateManager; + private _cursorBlinkStateManager: CursorBlinkStateManager | undefined; private _cell: ICellData = new CellData(); constructor(container: HTMLElement, zIndex: number, colors: IColorSet) { super(container, 'cursor', zIndex, true, colors); this._state = { - x: null, - y: null, - isFocused: null, - style: null, - width: null + x: 0, + y: 0, + isFocused: false, + style: '', + width: 0 }; this._cursorRenderers = { 'bar': this._renderBarCursor.bind(this), @@ -50,11 +50,11 @@ export class CursorRenderLayer extends BaseRenderLayer { super.resize(terminal, dim); // Resizing the canvas discards the contents of the canvas so clear state this._state = { - x: null, - y: null, - isFocused: null, - style: null, - width: null + x: 0, + y: 0, + isFocused: false, + style: '', + width: 0 }; } @@ -62,7 +62,6 @@ export class CursorRenderLayer extends BaseRenderLayer { this._clearCursor(); if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.dispose(); - this._cursorBlinkStateManager = null; this.onOptionsChanged(terminal); } } @@ -92,7 +91,6 @@ export class CursorRenderLayer extends BaseRenderLayer { } else { if (this._cursorBlinkStateManager) { this._cursorBlinkStateManager.dispose(); - this._cursorBlinkStateManager = null; } // Request a refresh from the terminal as management of rendering is being // moved back to the terminal @@ -184,11 +182,11 @@ export class CursorRenderLayer extends BaseRenderLayer { if (this._state) { this._clearCells(this._state.x, this._state.y, this._state.width, 1); this._state = { - x: null, - y: null, - isFocused: null, - style: null, - width: null + x: 0, + y: 0, + isFocused: false, + style: '', + width: 0 }; } } @@ -227,16 +225,16 @@ export class CursorRenderLayer extends BaseRenderLayer { class CursorBlinkStateManager { public isCursorVisible: boolean; - private _animationFrame: number; - private _blinkStartTimeout: number; - private _blinkInterval: number; + private _animationFrame: number | undefined; + private _blinkStartTimeout: number | undefined; + private _blinkInterval: number | undefined; /** * The time at which the animation frame was restarted, this is used on the * next render to restart the timers so they don't need to restart the timers * multiple times over a short period. */ - private _animationTimeRestarted: number; + private _animationTimeRestarted: number | undefined; constructor( terminal: Terminal, @@ -253,15 +251,15 @@ class CursorBlinkStateManager { public dispose(): void { if (this._blinkInterval) { window.clearInterval(this._blinkInterval); - this._blinkInterval = null; + this._blinkInterval = undefined; } if (this._blinkStartTimeout) { window.clearTimeout(this._blinkStartTimeout); - this._blinkStartTimeout = null; + this._blinkStartTimeout = undefined; } if (this._animationFrame) { window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = null; + this._animationFrame = undefined; } } @@ -276,7 +274,7 @@ class CursorBlinkStateManager { if (!this._animationFrame) { this._animationFrame = window.requestAnimationFrame(() => { this._renderCallback(); - this._animationFrame = null; + this._animationFrame = undefined; }); } } @@ -296,7 +294,7 @@ class CursorBlinkStateManager { // started if (this._animationTimeRestarted) { const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); - this._animationTimeRestarted = null; + this._animationTimeRestarted = undefined; if (time > 0) { this._restartInterval(time); return; @@ -307,7 +305,7 @@ class CursorBlinkStateManager { this.isCursorVisible = false; this._animationFrame = window.requestAnimationFrame(() => { this._renderCallback(); - this._animationFrame = null; + this._animationFrame = undefined; }); // Setup the blink interval @@ -317,7 +315,7 @@ class CursorBlinkStateManager { // calc time diff // Make restart interval do a setTimeout initially? const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted); - this._animationTimeRestarted = null; + this._animationTimeRestarted = undefined; this._restartInterval(time); return; } @@ -326,7 +324,7 @@ class CursorBlinkStateManager { this.isCursorVisible = !this.isCursorVisible; this._animationFrame = window.requestAnimationFrame(() => { this._renderCallback(); - this._animationFrame = null; + this._animationFrame = undefined; }); }, BLINK_INTERVAL); }, timeToStart); @@ -336,20 +334,20 @@ class CursorBlinkStateManager { this.isCursorVisible = true; if (this._blinkInterval) { window.clearInterval(this._blinkInterval); - this._blinkInterval = null; + this._blinkInterval = undefined; } if (this._blinkStartTimeout) { window.clearTimeout(this._blinkStartTimeout); - this._blinkStartTimeout = null; + this._blinkStartTimeout = undefined; } if (this._animationFrame) { window.cancelAnimationFrame(this._animationFrame); - this._animationFrame = null; + this._animationFrame = undefined; } } public resume(terminal: Terminal): void { - this._animationTimeRestarted = null; + this._animationTimeRestarted = undefined; this._restartInterval(); this.restartBlinkAnimation(terminal); } diff --git a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts index 7c79ddcc..a29d2cfd 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/LinkRenderLayer.ts @@ -12,7 +12,7 @@ import { IColorSet } from 'browser/Types'; import { IRenderDimensions } from 'browser/renderer/Types'; export class LinkRenderLayer extends BaseRenderLayer { - private _state: ILinkifierEvent = null; + private _state: ILinkifierEvent | undefined; constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) { super(container, 'link', zIndex, true, colors); @@ -23,7 +23,7 @@ export class LinkRenderLayer extends BaseRenderLayer { public resize(terminal: Terminal, dim: IRenderDimensions): void { super.resize(terminal, dim); // Resizing the canvas discards the contents of the canvas so clear state - this._state = null; + this._state = undefined; } public reset(terminal: Terminal): void { @@ -38,7 +38,7 @@ export class LinkRenderLayer extends BaseRenderLayer { this._clearCells(0, this._state.y1 + 1, this._state.cols, middleRowCount); } this._clearCells(0, this._state.y2, this._state.x2, 1); - this._state = null; + this._state = undefined; } } diff --git a/addons/xterm-addon-webgl/src/tsconfig.json b/addons/xterm-addon-webgl/src/tsconfig.json index 34149159..00134015 100644 --- a/addons/xterm-addon-webgl/src/tsconfig.json +++ b/addons/xterm-addon-webgl/src/tsconfig.json @@ -14,7 +14,8 @@ "paths": { "common/*": [ "../../../src/common/*" ], "browser/*": [ "../../../src/browser/*" ] - } + }, + "strict": true }, "include": [ "./**/*",