diff --git a/src/renderer/webgl/ColorUtils.ts b/src/renderer/webgl/ColorUtils.ts new file mode 100644 index 000000000..9efdeb9c6 --- /dev/null +++ b/src/renderer/webgl/ColorUtils.ts @@ -0,0 +1,14 @@ +/** + * @license MIT + * Copyright (c) 2018 The xterm.js authors. All rights reserved. + */ + +import { IColor } from '../../ui/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/src/renderer/webgl/GlyphRenderer.ts b/src/renderer/webgl/GlyphRenderer.ts index 6a6a873d0..9bd4573d0 100644 --- a/src/renderer/webgl/GlyphRenderer.ts +++ b/src/renderer/webgl/GlyphRenderer.ts @@ -4,7 +4,7 @@ */ import { createProgram, PROJECTION_MATRIX } from './WebglUtils'; -import { IColorManager, IRenderDimensions } from '../Types'; +import { IRenderDimensions } from '../Types'; import { ITerminal } from '../../Types'; import WebglCharAtlas from './WebglCharAtlas'; import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types'; @@ -13,6 +13,8 @@ import { COMBINED_CHAR_BIT_MASK } from './RenderModel'; import { fill, slice } from '../../common/TypedArrayUtils'; import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, CHAR_DATA_CHAR_INDEX } from '../../core/buffer/BufferLine'; import { IBufferLine } from '../../core/Types'; +import { IColorSet } from '../../ui/Types'; +import { getLuminance } from './ColorUtils'; interface IVertices { attributes: Float32Array; @@ -96,7 +98,7 @@ export class GlyphRenderer { constructor( private _terminal: ITerminal, - private _colorManager: IColorManager, + private _colors: IColorSet, private _gl: IWebGL2RenderingContext, private _dimensions: IRenderDimensions ) { @@ -216,7 +218,7 @@ 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 = this._colorManager.getLuminance(this._colorManager.colors.background); + const lumi = getLuminance(this._colors.background); const fg = lumi > 0.5 ? 7 : 0; const bg = lumi > 0.5 ? 0 : 7; @@ -297,7 +299,7 @@ export class GlyphRenderer { } } - public onThemeChanged(): void { + public onThemeChange(): void { } public render(renderModel: IRenderModel, isSelectionVisible: boolean): void { diff --git a/src/renderer/webgl/RectangleRenderer.ts b/src/renderer/webgl/RectangleRenderer.ts index 7399cc837..e047d7acf 100644 --- a/src/renderer/webgl/RectangleRenderer.ts +++ b/src/renderer/webgl/RectangleRenderer.ts @@ -4,13 +4,14 @@ */ import { ITerminal } from '../../Types'; -import { IColorManager, IRenderDimensions, IColor } from '../Types'; +import { IRenderDimensions } from '../Types'; import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils'; import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelectionRenderModel } from './Types'; import { fill } from '../../common/TypedArrayUtils'; import { INVERTED_DEFAULT_COLOR } from '../atlas/Types'; import { is256Color } from '../atlas/CharAtlasUtils'; import { DEFAULT_COLOR } from '../../common/Types'; +import { IColorSet, IColor } from '../../ui/Types'; const enum VertexAttribLocations { POSITION = 0, @@ -76,7 +77,7 @@ export class RectangleRenderer { constructor( private _terminal: ITerminal, - private _colorManager: IColorManager, + private _colors: IColorSet, private _gl: IWebGL2RenderingContext, private _dimensions: IRenderDimensions ) { @@ -148,14 +149,14 @@ export class RectangleRenderer { this._updateViewportRectangle(); } - public onThemeChanged(): void { + public onThemeChange(): void { this._updateCachedColors(); this._updateViewportRectangle(); } private _updateCachedColors(): void { - this._bgFloat = this._colorToFloat32Array(this._colorManager.colors.background); - this._selectionFloat = this._colorToFloat32Array(this._colorManager.colors.selection); + this._bgFloat = this._colorToFloat32Array(this._colors.background); + this._selectionFloat = this._colorToFloat32Array(this._colors.selection); } private _updateViewportRectangle(): void { @@ -272,9 +273,9 @@ export class RectangleRenderer { private _updateRectangle(vertices: IVertices, offset: number, bg: number, startX: number, endX: number, y: number): void { let color: IColor | null = null; if (bg === INVERTED_DEFAULT_COLOR) { - color = this._colorManager.colors.foreground; + color = this._colors.foreground; } else if (is256Color(bg)) { - color = this._colorManager.colors.ansi[bg]; + color = this._colors.ansi[bg]; } if (vertices.attributes.length < offset + 4) { vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE); diff --git a/src/renderer/webgl/WebglCharAtlas.ts b/src/renderer/webgl/WebglCharAtlas.ts index 6963e714f..a6bd40130 100644 --- a/src/renderer/webgl/WebglCharAtlas.ts +++ b/src/renderer/webgl/WebglCharAtlas.ts @@ -5,13 +5,14 @@ import { DIM_OPACITY, IGlyphIdentifier, INVERTED_DEFAULT_COLOR, ICharAtlasConfig } from '../atlas/Types'; import BaseCharAtlas from '../atlas/BaseCharAtlas'; -import { DEFAULT_ANSI_COLORS } from '../ColorManager'; import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from './Types'; -import { FLAGS, IColor } from '../Types'; +import { FLAGS } from '../Types'; import { is256Color } from '../atlas/CharAtlasUtils'; import { clearColor } from '../atlas/CharAtlasGenerator'; import { DEFAULT_ATTR } from '../../core/buffer/BufferLine'; import { DEFAULT_COLOR } from '../../common/Types'; +import { IColor } from '../../ui/Types'; +import { DEFAULT_ANSI_COLORS } from '../../ui/ColorManager'; // 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. diff --git a/src/renderer/webgl/WebglRenderer.ts b/src/renderer/webgl/WebglRenderer.ts index 15fe77d98..f7ad0e586 100644 --- a/src/renderer/webgl/WebglRenderer.ts +++ b/src/renderer/webgl/WebglRenderer.ts @@ -3,10 +3,8 @@ * @license MIT */ -import { IRenderer, IRenderDimensions, IColorSet, IRenderLayer, FLAGS } from '../Types'; -import { ITheme } from 'xterm'; +import { IRenderer, IRenderDimensions, IRenderLayer, FLAGS } from '../Types'; import { CharacterJoinerHandler, ITerminal } from '../../Types'; -import { ColorManager } from '../ColorManager'; import { RenderDebouncer } from '../../ui/RenderDebouncer'; import { GlyphRenderer } from './GlyphRenderer'; import { LinkRenderLayer } from '../LinkRenderLayer'; @@ -22,6 +20,8 @@ import { EventEmitter2, IEvent } from '../../common/EventEmitter2'; import { Disposable } from '../../common/Lifecycle'; import { CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, CHAR_DATA_ATTR_INDEX, NULL_CELL_CODE } from '../../core/buffer/BufferLine'; import { DEFAULT_COLOR } from '../../common/Types'; +import { IColorSet } from '../../ui/Types'; +import { getLuminance } from './ColorUtils'; export const INDICIES_PER_CELL = 4; @@ -43,7 +43,6 @@ export class WebglRenderer extends Disposable implements IRenderer { private _needsFullRefresh: boolean = false; public dimensions: IRenderDimensions; - public colorManager: ColorManager; private _onCanvasResize = new EventEmitter2<{ width: number, height: number }>(); public get onCanvasResize(): IEvent<{ width: number, height: number }> { return this._onCanvasResize.event; } @@ -52,20 +51,15 @@ export class WebglRenderer extends Disposable implements IRenderer { constructor( private _terminal: ITerminal, - theme: ITheme + private _colors: IColorSet ) { super(); - const allowTransparency = this._terminal.options.allowTransparency; - this.colorManager = new ColorManager(document, allowTransparency); - if (theme) { - this.colorManager.setTheme(theme); - this._applyBgLuminanceBasedSelection(); - } + this._applyBgLuminanceBasedSelection(); this._renderLayers = [ - new LinkRenderLayer(this._terminal.screenElement, 2, this.colorManager.colors, this._terminal), - new CursorRenderLayer(this._terminal.screenElement, 3, this.colorManager.colors) + new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._terminal), + new CursorRenderLayer(this._terminal.screenElement, 3, this._colors) ]; this.dimensions = { scaledCharWidth: null, @@ -98,8 +92,8 @@ export class WebglRenderer extends Disposable implements IRenderer { } this._terminal.screenElement.appendChild(this._canvas); - this._rectangleRenderer = new RectangleRenderer(this._terminal, this.colorManager, this._gl, this.dimensions); - this._glyphRenderer = new GlyphRenderer(this._terminal, this.colorManager, this._gl, this.dimensions); + this._rectangleRenderer = new RectangleRenderer(this._terminal, this._colors, this._gl, this.dimensions); + this._glyphRenderer = new GlyphRenderer(this._terminal, this._colors, this._gl, this.dimensions); // Detect whether IntersectionObserver is detected and enable renderer pause // and resume based on terminal visibility if so @@ -118,10 +112,10 @@ export class WebglRenderer extends Disposable implements IRenderer { private _applyBgLuminanceBasedSelection(): void { // HACK: This is needed until webgl renderer adds support for selection colors - if (this.colorManager.getLuminance(this.colorManager.colors.background) > 0.5) { - this.colorManager.colors.selection = { css: '#000', rgba: 255 }; + if (getLuminance(this._colors.background) > 0.5) { + this._colors.selection = { css: '#000', rgba: 255 }; } else { - this.colorManager.colors.selection = { css: '#fff', rgba: 4294967295 }; + this._colors.selection = { css: '#fff', rgba: 4294967295 }; } } @@ -142,25 +136,20 @@ export class WebglRenderer extends Disposable implements IRenderer { } } - public setTheme(theme: ITheme | undefined): IColorSet { - if (theme) { - this.colorManager.setTheme(theme); - this._applyBgLuminanceBasedSelection(); - } + public onThemeChange(colors: IColorSet): void { + this._applyBgLuminanceBasedSelection(); // Clear layers and force a full render this._renderLayers.forEach(l => { - l.onThemeChanged(this._terminal, this.colorManager.colors); + l.onThemeChange(this._terminal, this._colors); l.reset(this._terminal); }); - this._rectangleRenderer.onThemeChanged(); - this._glyphRenderer.onThemeChanged(); + this._rectangleRenderer.onThemeChange(); + this._glyphRenderer.onThemeChange(); this._refreshCharAtlas(); this._refreshViewport(); - - return this.colorManager.colors; } public onWindowResize(devicePixelRatio: number): void { @@ -245,7 +234,7 @@ export class WebglRenderer extends Disposable implements IRenderer { return; } - const atlas = acquireCharAtlas(this._terminal, this.colorManager.colors, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight); + const atlas = acquireCharAtlas(this._terminal, this._colors, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight); if (!('getRasterizedGlyph' in atlas)) { throw new Error('The webgl renderer only works with the webgl char atlas'); } diff --git a/src/ui/ColorManager.ts b/src/ui/ColorManager.ts index c751c4424..6d68c58d1 100644 --- a/src/ui/ColorManager.ts +++ b/src/ui/ColorManager.ts @@ -103,14 +103,6 @@ export class ColorManager implements IColorManager { }; } - // Coefficients taken from: https://www.w3.org/TR/AERT/#color-contrast - public getLuminance(color: IColor): number { - 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; - } - /** * Sets the terminal's theme. * @param theme The theme to use. If a partial theme is provided then default diff --git a/src/ui/Types.ts b/src/ui/Types.ts index cc3606848..ef725ba6e 100644 --- a/src/ui/Types.ts +++ b/src/ui/Types.ts @@ -5,7 +5,6 @@ export interface IColorManager { colors: IColorSet; - getLuminance(color: IColor): number; } export interface IColor {