Merge remote-tracking branch 'origin/master' into webgl2

This commit is contained in:
Daniel Imms
2019-05-18 18:24:30 -07:00
20 changed files with 108 additions and 100 deletions
+3 -2
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { IRenderLayer, IColorSet, IRenderDimensions } from './Types';
import { IRenderLayer, IRenderDimensions } from './Types';
import { ITerminal } from '../Types';
import { ICellData } from '../core/Types';
import { DEFAULT_COLOR } from '../common/Types';
@@ -11,6 +11,7 @@ import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier } from './atlas/T
import BaseCharAtlas from './atlas/BaseCharAtlas';
import { acquireCharAtlas } from './atlas/CharAtlasCache';
import { CellData, AttributeData, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../core/buffer/BufferLine';
import { IColorSet } from '../ui/Types';
export abstract class BaseRenderLayer implements IRenderLayer {
private _canvas: HTMLCanvasElement;
@@ -73,7 +74,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
public onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void {}
public onSelectionChanged(terminal: ITerminal, start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {}
public onThemeChanged(terminal: ITerminal, colorSet: IColorSet): void {
public onThemeChange(terminal: ITerminal, colorSet: IColorSet): void {
this._refreshCharAtlas(terminal, colorSet);
}
-313
View File
@@ -1,313 +0,0 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import jsdom = require('jsdom');
import { assert } from 'chai';
import { ColorManager } from './ColorManager';
describe('ColorManager', () => {
let cm: ColorManager;
let dom: jsdom.JSDOM;
let document: Document;
let window: Window;
beforeEach(() => {
dom = new jsdom.JSDOM('');
window = dom.window;
document = window.document;
(<any>window).HTMLCanvasElement.prototype.getContext = () => ({
createLinearGradient(): any {
return null;
},
fillRect(): void { },
getImageData(): any {
return {data: [0, 0, 0, 0xFF]};
}
});
cm = new ColorManager(document, false);
});
describe('constructor', () => {
it('should fill all colors with values', () => {
for (const key of Object.keys(cm.colors)) {
if (key !== 'ansi') {
// A #rrggbb or rgba(...)
assert.ok((<any>cm.colors)[key].css.length >= 7);
}
}
assert.equal(cm.colors.ansi.length, 256);
});
it('should fill 240 colors with expected values', () => {
assert.equal(cm.colors.ansi[16].css, '#000000');
assert.equal(cm.colors.ansi[17].css, '#00005f');
assert.equal(cm.colors.ansi[18].css, '#000087');
assert.equal(cm.colors.ansi[19].css, '#0000af');
assert.equal(cm.colors.ansi[20].css, '#0000d7');
assert.equal(cm.colors.ansi[21].css, '#0000ff');
assert.equal(cm.colors.ansi[22].css, '#005f00');
assert.equal(cm.colors.ansi[23].css, '#005f5f');
assert.equal(cm.colors.ansi[24].css, '#005f87');
assert.equal(cm.colors.ansi[25].css, '#005faf');
assert.equal(cm.colors.ansi[26].css, '#005fd7');
assert.equal(cm.colors.ansi[27].css, '#005fff');
assert.equal(cm.colors.ansi[28].css, '#008700');
assert.equal(cm.colors.ansi[29].css, '#00875f');
assert.equal(cm.colors.ansi[30].css, '#008787');
assert.equal(cm.colors.ansi[31].css, '#0087af');
assert.equal(cm.colors.ansi[32].css, '#0087d7');
assert.equal(cm.colors.ansi[33].css, '#0087ff');
assert.equal(cm.colors.ansi[34].css, '#00af00');
assert.equal(cm.colors.ansi[35].css, '#00af5f');
assert.equal(cm.colors.ansi[36].css, '#00af87');
assert.equal(cm.colors.ansi[37].css, '#00afaf');
assert.equal(cm.colors.ansi[38].css, '#00afd7');
assert.equal(cm.colors.ansi[39].css, '#00afff');
assert.equal(cm.colors.ansi[40].css, '#00d700');
assert.equal(cm.colors.ansi[41].css, '#00d75f');
assert.equal(cm.colors.ansi[42].css, '#00d787');
assert.equal(cm.colors.ansi[43].css, '#00d7af');
assert.equal(cm.colors.ansi[44].css, '#00d7d7');
assert.equal(cm.colors.ansi[45].css, '#00d7ff');
assert.equal(cm.colors.ansi[46].css, '#00ff00');
assert.equal(cm.colors.ansi[47].css, '#00ff5f');
assert.equal(cm.colors.ansi[48].css, '#00ff87');
assert.equal(cm.colors.ansi[49].css, '#00ffaf');
assert.equal(cm.colors.ansi[50].css, '#00ffd7');
assert.equal(cm.colors.ansi[51].css, '#00ffff');
assert.equal(cm.colors.ansi[52].css, '#5f0000');
assert.equal(cm.colors.ansi[53].css, '#5f005f');
assert.equal(cm.colors.ansi[54].css, '#5f0087');
assert.equal(cm.colors.ansi[55].css, '#5f00af');
assert.equal(cm.colors.ansi[56].css, '#5f00d7');
assert.equal(cm.colors.ansi[57].css, '#5f00ff');
assert.equal(cm.colors.ansi[58].css, '#5f5f00');
assert.equal(cm.colors.ansi[59].css, '#5f5f5f');
assert.equal(cm.colors.ansi[60].css, '#5f5f87');
assert.equal(cm.colors.ansi[61].css, '#5f5faf');
assert.equal(cm.colors.ansi[62].css, '#5f5fd7');
assert.equal(cm.colors.ansi[63].css, '#5f5fff');
assert.equal(cm.colors.ansi[64].css, '#5f8700');
assert.equal(cm.colors.ansi[65].css, '#5f875f');
assert.equal(cm.colors.ansi[66].css, '#5f8787');
assert.equal(cm.colors.ansi[67].css, '#5f87af');
assert.equal(cm.colors.ansi[68].css, '#5f87d7');
assert.equal(cm.colors.ansi[69].css, '#5f87ff');
assert.equal(cm.colors.ansi[70].css, '#5faf00');
assert.equal(cm.colors.ansi[71].css, '#5faf5f');
assert.equal(cm.colors.ansi[72].css, '#5faf87');
assert.equal(cm.colors.ansi[73].css, '#5fafaf');
assert.equal(cm.colors.ansi[74].css, '#5fafd7');
assert.equal(cm.colors.ansi[75].css, '#5fafff');
assert.equal(cm.colors.ansi[76].css, '#5fd700');
assert.equal(cm.colors.ansi[77].css, '#5fd75f');
assert.equal(cm.colors.ansi[78].css, '#5fd787');
assert.equal(cm.colors.ansi[79].css, '#5fd7af');
assert.equal(cm.colors.ansi[80].css, '#5fd7d7');
assert.equal(cm.colors.ansi[81].css, '#5fd7ff');
assert.equal(cm.colors.ansi[82].css, '#5fff00');
assert.equal(cm.colors.ansi[83].css, '#5fff5f');
assert.equal(cm.colors.ansi[84].css, '#5fff87');
assert.equal(cm.colors.ansi[85].css, '#5fffaf');
assert.equal(cm.colors.ansi[86].css, '#5fffd7');
assert.equal(cm.colors.ansi[87].css, '#5fffff');
assert.equal(cm.colors.ansi[88].css, '#870000');
assert.equal(cm.colors.ansi[89].css, '#87005f');
assert.equal(cm.colors.ansi[90].css, '#870087');
assert.equal(cm.colors.ansi[91].css, '#8700af');
assert.equal(cm.colors.ansi[92].css, '#8700d7');
assert.equal(cm.colors.ansi[93].css, '#8700ff');
assert.equal(cm.colors.ansi[94].css, '#875f00');
assert.equal(cm.colors.ansi[95].css, '#875f5f');
assert.equal(cm.colors.ansi[96].css, '#875f87');
assert.equal(cm.colors.ansi[97].css, '#875faf');
assert.equal(cm.colors.ansi[98].css, '#875fd7');
assert.equal(cm.colors.ansi[99].css, '#875fff');
assert.equal(cm.colors.ansi[100].css, '#878700');
assert.equal(cm.colors.ansi[101].css, '#87875f');
assert.equal(cm.colors.ansi[102].css, '#878787');
assert.equal(cm.colors.ansi[103].css, '#8787af');
assert.equal(cm.colors.ansi[104].css, '#8787d7');
assert.equal(cm.colors.ansi[105].css, '#8787ff');
assert.equal(cm.colors.ansi[106].css, '#87af00');
assert.equal(cm.colors.ansi[107].css, '#87af5f');
assert.equal(cm.colors.ansi[108].css, '#87af87');
assert.equal(cm.colors.ansi[109].css, '#87afaf');
assert.equal(cm.colors.ansi[110].css, '#87afd7');
assert.equal(cm.colors.ansi[111].css, '#87afff');
assert.equal(cm.colors.ansi[112].css, '#87d700');
assert.equal(cm.colors.ansi[113].css, '#87d75f');
assert.equal(cm.colors.ansi[114].css, '#87d787');
assert.equal(cm.colors.ansi[115].css, '#87d7af');
assert.equal(cm.colors.ansi[116].css, '#87d7d7');
assert.equal(cm.colors.ansi[117].css, '#87d7ff');
assert.equal(cm.colors.ansi[118].css, '#87ff00');
assert.equal(cm.colors.ansi[119].css, '#87ff5f');
assert.equal(cm.colors.ansi[120].css, '#87ff87');
assert.equal(cm.colors.ansi[121].css, '#87ffaf');
assert.equal(cm.colors.ansi[122].css, '#87ffd7');
assert.equal(cm.colors.ansi[123].css, '#87ffff');
assert.equal(cm.colors.ansi[124].css, '#af0000');
assert.equal(cm.colors.ansi[125].css, '#af005f');
assert.equal(cm.colors.ansi[126].css, '#af0087');
assert.equal(cm.colors.ansi[127].css, '#af00af');
assert.equal(cm.colors.ansi[128].css, '#af00d7');
assert.equal(cm.colors.ansi[129].css, '#af00ff');
assert.equal(cm.colors.ansi[130].css, '#af5f00');
assert.equal(cm.colors.ansi[131].css, '#af5f5f');
assert.equal(cm.colors.ansi[132].css, '#af5f87');
assert.equal(cm.colors.ansi[133].css, '#af5faf');
assert.equal(cm.colors.ansi[134].css, '#af5fd7');
assert.equal(cm.colors.ansi[135].css, '#af5fff');
assert.equal(cm.colors.ansi[136].css, '#af8700');
assert.equal(cm.colors.ansi[137].css, '#af875f');
assert.equal(cm.colors.ansi[138].css, '#af8787');
assert.equal(cm.colors.ansi[139].css, '#af87af');
assert.equal(cm.colors.ansi[140].css, '#af87d7');
assert.equal(cm.colors.ansi[141].css, '#af87ff');
assert.equal(cm.colors.ansi[142].css, '#afaf00');
assert.equal(cm.colors.ansi[143].css, '#afaf5f');
assert.equal(cm.colors.ansi[144].css, '#afaf87');
assert.equal(cm.colors.ansi[145].css, '#afafaf');
assert.equal(cm.colors.ansi[146].css, '#afafd7');
assert.equal(cm.colors.ansi[147].css, '#afafff');
assert.equal(cm.colors.ansi[148].css, '#afd700');
assert.equal(cm.colors.ansi[149].css, '#afd75f');
assert.equal(cm.colors.ansi[150].css, '#afd787');
assert.equal(cm.colors.ansi[151].css, '#afd7af');
assert.equal(cm.colors.ansi[152].css, '#afd7d7');
assert.equal(cm.colors.ansi[153].css, '#afd7ff');
assert.equal(cm.colors.ansi[154].css, '#afff00');
assert.equal(cm.colors.ansi[155].css, '#afff5f');
assert.equal(cm.colors.ansi[156].css, '#afff87');
assert.equal(cm.colors.ansi[157].css, '#afffaf');
assert.equal(cm.colors.ansi[158].css, '#afffd7');
assert.equal(cm.colors.ansi[159].css, '#afffff');
assert.equal(cm.colors.ansi[160].css, '#d70000');
assert.equal(cm.colors.ansi[161].css, '#d7005f');
assert.equal(cm.colors.ansi[162].css, '#d70087');
assert.equal(cm.colors.ansi[163].css, '#d700af');
assert.equal(cm.colors.ansi[164].css, '#d700d7');
assert.equal(cm.colors.ansi[165].css, '#d700ff');
assert.equal(cm.colors.ansi[166].css, '#d75f00');
assert.equal(cm.colors.ansi[167].css, '#d75f5f');
assert.equal(cm.colors.ansi[168].css, '#d75f87');
assert.equal(cm.colors.ansi[169].css, '#d75faf');
assert.equal(cm.colors.ansi[170].css, '#d75fd7');
assert.equal(cm.colors.ansi[171].css, '#d75fff');
assert.equal(cm.colors.ansi[172].css, '#d78700');
assert.equal(cm.colors.ansi[173].css, '#d7875f');
assert.equal(cm.colors.ansi[174].css, '#d78787');
assert.equal(cm.colors.ansi[175].css, '#d787af');
assert.equal(cm.colors.ansi[176].css, '#d787d7');
assert.equal(cm.colors.ansi[177].css, '#d787ff');
assert.equal(cm.colors.ansi[178].css, '#d7af00');
assert.equal(cm.colors.ansi[179].css, '#d7af5f');
assert.equal(cm.colors.ansi[180].css, '#d7af87');
assert.equal(cm.colors.ansi[181].css, '#d7afaf');
assert.equal(cm.colors.ansi[182].css, '#d7afd7');
assert.equal(cm.colors.ansi[183].css, '#d7afff');
assert.equal(cm.colors.ansi[184].css, '#d7d700');
assert.equal(cm.colors.ansi[185].css, '#d7d75f');
assert.equal(cm.colors.ansi[186].css, '#d7d787');
assert.equal(cm.colors.ansi[187].css, '#d7d7af');
assert.equal(cm.colors.ansi[188].css, '#d7d7d7');
assert.equal(cm.colors.ansi[189].css, '#d7d7ff');
assert.equal(cm.colors.ansi[190].css, '#d7ff00');
assert.equal(cm.colors.ansi[191].css, '#d7ff5f');
assert.equal(cm.colors.ansi[192].css, '#d7ff87');
assert.equal(cm.colors.ansi[193].css, '#d7ffaf');
assert.equal(cm.colors.ansi[194].css, '#d7ffd7');
assert.equal(cm.colors.ansi[195].css, '#d7ffff');
assert.equal(cm.colors.ansi[196].css, '#ff0000');
assert.equal(cm.colors.ansi[197].css, '#ff005f');
assert.equal(cm.colors.ansi[198].css, '#ff0087');
assert.equal(cm.colors.ansi[199].css, '#ff00af');
assert.equal(cm.colors.ansi[200].css, '#ff00d7');
assert.equal(cm.colors.ansi[201].css, '#ff00ff');
assert.equal(cm.colors.ansi[202].css, '#ff5f00');
assert.equal(cm.colors.ansi[203].css, '#ff5f5f');
assert.equal(cm.colors.ansi[204].css, '#ff5f87');
assert.equal(cm.colors.ansi[205].css, '#ff5faf');
assert.equal(cm.colors.ansi[206].css, '#ff5fd7');
assert.equal(cm.colors.ansi[207].css, '#ff5fff');
assert.equal(cm.colors.ansi[208].css, '#ff8700');
assert.equal(cm.colors.ansi[209].css, '#ff875f');
assert.equal(cm.colors.ansi[210].css, '#ff8787');
assert.equal(cm.colors.ansi[211].css, '#ff87af');
assert.equal(cm.colors.ansi[212].css, '#ff87d7');
assert.equal(cm.colors.ansi[213].css, '#ff87ff');
assert.equal(cm.colors.ansi[214].css, '#ffaf00');
assert.equal(cm.colors.ansi[215].css, '#ffaf5f');
assert.equal(cm.colors.ansi[216].css, '#ffaf87');
assert.equal(cm.colors.ansi[217].css, '#ffafaf');
assert.equal(cm.colors.ansi[218].css, '#ffafd7');
assert.equal(cm.colors.ansi[219].css, '#ffafff');
assert.equal(cm.colors.ansi[220].css, '#ffd700');
assert.equal(cm.colors.ansi[221].css, '#ffd75f');
assert.equal(cm.colors.ansi[222].css, '#ffd787');
assert.equal(cm.colors.ansi[223].css, '#ffd7af');
assert.equal(cm.colors.ansi[224].css, '#ffd7d7');
assert.equal(cm.colors.ansi[225].css, '#ffd7ff');
assert.equal(cm.colors.ansi[226].css, '#ffff00');
assert.equal(cm.colors.ansi[227].css, '#ffff5f');
assert.equal(cm.colors.ansi[228].css, '#ffff87');
assert.equal(cm.colors.ansi[229].css, '#ffffaf');
assert.equal(cm.colors.ansi[230].css, '#ffffd7');
assert.equal(cm.colors.ansi[231].css, '#ffffff');
assert.equal(cm.colors.ansi[232].css, '#080808');
assert.equal(cm.colors.ansi[233].css, '#121212');
assert.equal(cm.colors.ansi[234].css, '#1c1c1c');
assert.equal(cm.colors.ansi[235].css, '#262626');
assert.equal(cm.colors.ansi[236].css, '#303030');
assert.equal(cm.colors.ansi[237].css, '#3a3a3a');
assert.equal(cm.colors.ansi[238].css, '#444444');
assert.equal(cm.colors.ansi[239].css, '#4e4e4e');
assert.equal(cm.colors.ansi[240].css, '#585858');
assert.equal(cm.colors.ansi[241].css, '#626262');
assert.equal(cm.colors.ansi[242].css, '#6c6c6c');
assert.equal(cm.colors.ansi[243].css, '#767676');
assert.equal(cm.colors.ansi[244].css, '#808080');
assert.equal(cm.colors.ansi[245].css, '#8a8a8a');
assert.equal(cm.colors.ansi[246].css, '#949494');
assert.equal(cm.colors.ansi[247].css, '#9e9e9e');
assert.equal(cm.colors.ansi[248].css, '#a8a8a8');
assert.equal(cm.colors.ansi[249].css, '#b2b2b2');
assert.equal(cm.colors.ansi[250].css, '#bcbcbc');
assert.equal(cm.colors.ansi[251].css, '#c6c6c6');
assert.equal(cm.colors.ansi[252].css, '#d0d0d0');
assert.equal(cm.colors.ansi[253].css, '#dadada');
assert.equal(cm.colors.ansi[254].css, '#e4e4e4');
assert.equal(cm.colors.ansi[255].css, '#eeeeee');
});
});
describe('setTheme', () => {
it('should not throw when not setting all colors', () => {
assert.doesNotThrow(() => {
cm.setTheme({});
});
});
it('should set a partial set of colors, using the default if not present', () => {
assert.equal(cm.colors.background.css, '#000000');
assert.equal(cm.colors.foreground.css, '#ffffff');
cm.setTheme({
background: '#FF0000',
foreground: '#00FF00'
});
assert.equal(cm.colors.background.css, '#FF0000');
assert.equal(cm.colors.foreground.css, '#00FF00');
cm.setTheme({
background: '#0000FF'
});
assert.equal(cm.colors.background.css, '#0000FF');
// FG reverts back to default
assert.equal(cm.colors.foreground.css, '#ffffff');
});
});
});
-194
View File
@@ -1,194 +0,0 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IColorManager, IColor, IColorSet } from './Types';
import { ITheme } from 'xterm';
const DEFAULT_FOREGROUND = fromHex('#ffffff');
const DEFAULT_BACKGROUND = fromHex('#000000');
const DEFAULT_CURSOR = fromHex('#ffffff');
const DEFAULT_CURSOR_ACCENT = fromHex('#000000');
const DEFAULT_SELECTION = {
css: 'rgba(255, 255, 255, 0.3)',
rgba: 0xFFFFFF77
};
// An IIFE to generate DEFAULT_ANSI_COLORS. Do not mutate DEFAULT_ANSI_COLORS, instead make a copy
// and mutate that.
export const DEFAULT_ANSI_COLORS = (() => {
const colors = [
// dark:
fromHex('#2e3436'),
fromHex('#cc0000'),
fromHex('#4e9a06'),
fromHex('#c4a000'),
fromHex('#3465a4'),
fromHex('#75507b'),
fromHex('#06989a'),
fromHex('#d3d7cf'),
// bright:
fromHex('#555753'),
fromHex('#ef2929'),
fromHex('#8ae234'),
fromHex('#fce94f'),
fromHex('#729fcf'),
fromHex('#ad7fa8'),
fromHex('#34e2e2'),
fromHex('#eeeeec')
];
// Fill in the remaining 240 ANSI colors.
// Generate colors (16-231)
const v = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff];
for (let i = 0; i < 216; i++) {
const r = v[(i / 36) % 6 | 0];
const g = v[(i / 6) % 6 | 0];
const b = v[i % 6];
colors.push({
css: `#${toPaddedHex(r)}${toPaddedHex(g)}${toPaddedHex(b)}`,
// Use >>> 0 to force a conversion to an unsigned int
rgba: ((r << 24) | (g << 16) | (b << 8) | 0xFF) >>> 0
});
}
// 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
});
}
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.
*/
export class ColorManager implements IColorManager {
public colors: IColorSet;
private _ctx: CanvasRenderingContext2D;
private _litmusColor: CanvasGradient;
constructor(document: Document, public allowTransparency: boolean) {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
this._ctx = canvas.getContext('2d');
this._ctx.globalCompositeOperation = 'copy';
this._litmusColor = this._ctx.createLinearGradient(0, 0, 1, 1);
this.colors = {
foreground: DEFAULT_FOREGROUND,
background: DEFAULT_BACKGROUND,
cursor: DEFAULT_CURSOR,
cursorAccent: DEFAULT_CURSOR_ACCENT,
selection: DEFAULT_SELECTION,
ansi: DEFAULT_ANSI_COLORS.slice()
};
}
// 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
* colors will be used where colors are not defined.
*/
public setTheme(theme: ITheme): void {
this.colors.foreground = this._parseColor(theme.foreground, DEFAULT_FOREGROUND);
this.colors.background = this._parseColor(theme.background, DEFAULT_BACKGROUND);
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.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]);
this.colors.ansi[3] = this._parseColor(theme.yellow, DEFAULT_ANSI_COLORS[3]);
this.colors.ansi[4] = this._parseColor(theme.blue, DEFAULT_ANSI_COLORS[4]);
this.colors.ansi[5] = this._parseColor(theme.magenta, DEFAULT_ANSI_COLORS[5]);
this.colors.ansi[6] = this._parseColor(theme.cyan, DEFAULT_ANSI_COLORS[6]);
this.colors.ansi[7] = this._parseColor(theme.white, DEFAULT_ANSI_COLORS[7]);
this.colors.ansi[8] = this._parseColor(theme.brightBlack, DEFAULT_ANSI_COLORS[8]);
this.colors.ansi[9] = this._parseColor(theme.brightRed, DEFAULT_ANSI_COLORS[9]);
this.colors.ansi[10] = this._parseColor(theme.brightGreen, DEFAULT_ANSI_COLORS[10]);
this.colors.ansi[11] = this._parseColor(theme.brightYellow, DEFAULT_ANSI_COLORS[11]);
this.colors.ansi[12] = this._parseColor(theme.brightBlue, DEFAULT_ANSI_COLORS[12]);
this.colors.ansi[13] = this._parseColor(theme.brightMagenta, DEFAULT_ANSI_COLORS[13]);
this.colors.ansi[14] = this._parseColor(theme.brightCyan, DEFAULT_ANSI_COLORS[14]);
this.colors.ansi[15] = this._parseColor(theme.brightWhite, DEFAULT_ANSI_COLORS[15]);
}
private _parseColor(
css: string,
fallback: IColor,
allowTransparency: boolean = this.allowTransparency
): IColor {
if (!css) {
return fallback;
}
// If parsing the value results in failure, then it must be ignored, and the attribute must
// retain its previous value.
// -- https://html.spec.whatwg.org/multipage/canvas.html#fill-and-stroke-styles
this._ctx.fillStyle = this._litmusColor;
this._ctx.fillStyle = css;
if (typeof this._ctx.fillStyle !== 'string') {
console.warn(`Color: ${css} is invalid using fallback ${fallback.css}`);
return fallback;
}
this._ctx.fillRect(0, 0, 1, 1);
const data = this._ctx.getImageData(0, 0, 1, 1).data;
if (!allowTransparency && data[3] !== 0xFF) {
// Ideally we'd just ignore the alpha channel, but...
//
// Browsers may not give back exactly the same RGB values we put in, because most/all
// convert the color to a pre-multiplied representation. getImageData converts that back to
// a un-premultipled representation, but the precision loss may make the RGB channels unuable
// on their own.
//
// E.g. In Chrome #12345610 turns into #10305010, and in the extreme case, 0xFFFFFF00 turns
// into 0x00000000.
//
// "Note: Due to the lossy nature of converting to and from premultiplied alpha color values,
// pixels that have just been set using putImageData() might be returned to an equivalent
// getImageData() as different values."
// -- https://html.spec.whatwg.org/multipage/canvas.html#pixel-manipulation
//
// So let's just use the fallback color in this case instead.
console.warn(
`Color: ${css} is using transparency, but allowTransparency is false. ` +
`Using fallback ${fallback.css}.`
);
return fallback;
}
return {
css,
rgba: (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]) >>> 0
};
}
}
+2 -1
View File
@@ -3,11 +3,12 @@
* @license MIT
*/
import { IColorSet, IRenderDimensions } from './Types';
import { IRenderDimensions } from './Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { ITerminal } from '../Types';
import { ICellData } from '../core/Types';
import { CellData } from '../core/buffer/BufferLine';
import { IColorSet } from '../ui/Types';
interface ICursorState {
x: number;
+2 -1
View File
@@ -4,10 +4,11 @@
*/
import { ILinkifierEvent, ITerminal, ILinkifierAccessor } from '../Types';
import { IColorSet, IRenderDimensions } from './Types';
import { IRenderDimensions } from './Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { INVERTED_DEFAULT_COLOR } from './atlas/Types';
import { is256Color } from './atlas/CharAtlasUtils';
import { IColorSet } from '../ui/Types';
export class LinkRenderLayer extends BaseRenderLayer {
private _state: ILinkifierEvent = null;
+12 -20
View File
@@ -6,16 +6,15 @@
import { TextRenderLayer } from './TextRenderLayer';
import { SelectionRenderLayer } from './SelectionRenderLayer';
import { CursorRenderLayer } from './CursorRenderLayer';
import { ColorManager } from './ColorManager';
import { IRenderLayer, IColorSet, IRenderer, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { IRenderLayer, IRenderer, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { ITerminal, CharacterJoinerHandler } from '../Types';
import { LinkRenderLayer } from './LinkRenderLayer';
import { RenderDebouncer } from '../ui/RenderDebouncer';
import { ScreenDprMonitor } from '../ui/ScreenDprMonitor';
import { ITheme } from 'xterm';
import { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry';
import { EventEmitter2, IEvent } from '../common/EventEmitter2';
import { Disposable } from '../common/Lifecycle';
import { IColorSet } from '../ui/Types';
export class Renderer extends Disposable implements IRenderer {
private _renderDebouncer: RenderDebouncer;
@@ -27,7 +26,6 @@ export class Renderer extends Disposable implements IRenderer {
private _needsFullRefresh: boolean = false;
private _characterJoinerRegistry: ICharacterJoinerRegistry;
public colorManager: ColorManager;
public dimensions: IRenderDimensions;
private _onCanvasResize = new EventEmitter2<{ width: number, height: number }>();
@@ -35,20 +33,19 @@ export class Renderer extends Disposable implements IRenderer {
private _onRender = new EventEmitter2<{ start: number, end: number }>();
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }
constructor(private _terminal: ITerminal, theme: ITheme) {
constructor(
private _terminal: ITerminal,
private _colors: IColorSet
) {
super();
const allowTransparency = this._terminal.options.allowTransparency;
this.colorManager = new ColorManager(document, allowTransparency);
this._characterJoinerRegistry = new CharacterJoinerRegistry(_terminal);
if (theme) {
this.colorManager.setTheme(theme);
}
this._renderLayers = [
new TextRenderLayer(this._terminal.screenElement, 0, this.colorManager.colors, this._characterJoinerRegistry, allowTransparency),
new SelectionRenderLayer(this._terminal.screenElement, 1, this.colorManager.colors),
new LinkRenderLayer(this._terminal.screenElement, 2, this.colorManager.colors, this._terminal),
new CursorRenderLayer(this._terminal.screenElement, 3, this.colorManager.colors)
new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency),
new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors),
new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._terminal),
new CursorRenderLayer(this._terminal.screenElement, 3, this._colors)
];
this.dimensions = {
scaledCharWidth: null,
@@ -104,12 +101,10 @@ export class Renderer extends Disposable implements IRenderer {
}
}
public setTheme(theme: ITheme): IColorSet {
this.colorManager.setTheme(theme);
public onThemeChange(colors: IColorSet): void {
// 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);
});
@@ -118,8 +113,6 @@ export class Renderer extends Disposable implements IRenderer {
} else {
this._terminal.refresh(0, this._terminal.rows - 1);
}
return this.colorManager.colors;
}
public onResize(cols: number, rows: number): void {
@@ -167,7 +160,6 @@ export class Renderer extends Disposable implements IRenderer {
}
public onOptionsChanged(): void {
this.colorManager.allowTransparency = this._terminal.options.allowTransparency;
this._runOperation(l => l.onOptionsChanged(this._terminal));
}
+2 -1
View File
@@ -4,8 +4,9 @@
*/
import { ITerminal } from '../Types';
import { IColorSet, IRenderDimensions } from './Types';
import { IRenderDimensions } from './Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { IColorSet } from '../ui/Types';
interface ISelectionState {
start: [number, number];
+2 -1
View File
@@ -3,13 +3,14 @@
* @license MIT
*/
import { IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { ITerminal } from '../Types';
import { CharData, ICellData } from '../core/Types';
import { GridCache } from './GridCache';
import { BaseRenderLayer } from './BaseRenderLayer';
import { CellData, AttributeData, Content, NULL_CELL_CODE } from '../core/buffer/BufferLine';
import { JoinedCellData } from './CharacterJoinerRegistry';
import { IColorSet } from '../ui/Types';
/**
* This CharData looks like a null character, which will forc a clear and render
+4 -23
View File
@@ -4,8 +4,9 @@
*/
import { ITerminal, CharacterJoinerHandler } from '../Types';
import { ITheme, IDisposable } from 'xterm';
import { IDisposable } from 'xterm';
import { IEvent } from '../common/EventEmitter2';
import { IColorSet } from '../ui/Types';
/**
* Flags used to render terminal text properly.
@@ -26,13 +27,12 @@ export const enum FLAGS {
*/
export interface IRenderer extends IDisposable {
dimensions: IRenderDimensions;
colorManager: IColorManager;
onCanvasResize: IEvent<{ width: number, height: number }>;
onRender: IEvent<{ start: number, end: number }>;
dispose(): void;
setTheme(theme: ITheme): IColorSet;
onThemeChange(colors: IColorSet): void;
onWindowResize(devicePixelRatio: number): void;
onResize(cols: number, rows: number): void;
onCharSizeChanged(): void;
@@ -47,11 +47,6 @@ export interface IRenderer extends IDisposable {
deregisterCharacterJoiner(joinerId: number): boolean;
}
export interface IColorManager {
colors: IColorSet;
getLuminance(color: IColor): number;
}
export interface IRenderDimensions {
scaledCharWidth: number;
scaledCharHeight: number;
@@ -91,7 +86,7 @@ export interface IRenderLayer extends IDisposable {
/**
* Called when the theme changes.
*/
onThemeChanged(terminal: ITerminal, colorSet: IColorSet): void;
onThemeChange(terminal: ITerminal, colorSet: IColorSet): void;
/**
* Called when the data in the grid has changed (or needs to be rendered
@@ -135,17 +130,3 @@ export interface ICharacterJoinerRegistry {
deregisterCharacterJoiner(joinerId: number): boolean;
getJoinedCharacters(row: number): [number, number][];
}
export interface IColor {
css: string;
rgba: number; // 32-bit int with rgba in each byte
}
export interface IColorSet {
foreground: IColor;
background: IColor;
cursor: IColor;
cursorAccent: IColor;
selection: IColor;
ansi: IColor[];
}
+1 -1
View File
@@ -4,7 +4,6 @@
*/
import { ITerminal } from '../../Types';
import { IColorSet } from '../Types';
import { generateConfig, configEquals } from './CharAtlasUtils';
import BaseCharAtlas from './BaseCharAtlas';
import DynamicCharAtlas from './DynamicCharAtlas';
@@ -12,6 +11,7 @@ import NoneCharAtlas from './NoneCharAtlas';
import StaticCharAtlas from './StaticCharAtlas';
import WebglCharAtlas from '../webgl/WebglCharAtlas';
import { ICharAtlasConfig } from './Types';
import { IColorSet } from '../../ui/Types';
const charAtlasImplementations = {
'none': NoneCharAtlas,
+1 -1
View File
@@ -5,8 +5,8 @@
import { FontWeight } from 'xterm';
import { isFirefox, isSafari } from '../../common/Platform';
import { IColor } from '../Types';
import { ICharAtlasConfig, CHAR_ATLAS_CELL_SPACING } from './Types';
import { IColor } from '../../ui/Types';
/**
* Generates a char atlas.
+1 -1
View File
@@ -4,9 +4,9 @@
*/
import { ITerminal } from '../../Types';
import { IColorSet } from '../Types';
import { ICharAtlasConfig } from './Types';
import { DEFAULT_COLOR } from '../../common/Types';
import { IColorSet } from '../../ui/Types';
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {
// null out some fields that don't matter
+2 -2
View File
@@ -5,11 +5,11 @@
import { DIM_OPACITY, IGlyphIdentifier, INVERTED_DEFAULT_COLOR, ICharAtlasConfig } from './Types';
import BaseCharAtlas from './BaseCharAtlas';
import { DEFAULT_ANSI_COLORS } from '../ColorManager';
import { DEFAULT_ANSI_COLORS } from '../../ui/ColorManager';
import { clearColor } from './CharAtlasGenerator';
import LRUMap from './LRUMap';
import { isFirefox, isSafari } from '../../common/Platform';
import { IColor } from '../Types';
import { IColor } from '../../ui/Types';
// 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.
+1 -1
View File
@@ -4,7 +4,7 @@
*/
import { FontWeight } from 'xterm';
import { IColorSet } from '../Types';
import { IColorSet } from '../../ui/Types';
export const INVERTED_DEFAULT_COLOR = 257;
export const DIM_OPACITY = 0.5;
+23 -25
View File
@@ -3,15 +3,14 @@
* @license MIT
*/
import { IRenderer, IRenderDimensions, IColorSet } from '../Types';
import { IRenderer, IRenderDimensions } from '../Types';
import { ILinkifierEvent, ITerminal, CharacterJoinerHandler } from '../../Types';
import { ITheme } from 'xterm';
import { ColorManager } from '../ColorManager';
import { RenderDebouncer } from '../../ui/RenderDebouncer';
import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory';
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
import { EventEmitter2, IEvent } from '../../common/EventEmitter2';
import { Disposable } from '../../common/Lifecycle';
import { IColorSet } from '../../ui/Types';
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
const ROW_CONTAINER_CLASS = 'xterm-rows';
@@ -42,18 +41,17 @@ export class DomRenderer extends Disposable implements IRenderer {
private _selectionContainer: HTMLElement;
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; }
private _onRender = new EventEmitter2<{ start: number, end: number }>();
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }
constructor(private _terminal: ITerminal, theme: ITheme | undefined) {
constructor(
private _terminal: ITerminal,
private _colors: IColorSet
) {
super();
const allowTransparency = this._terminal.options.allowTransparency;
this.colorManager = new ColorManager(document, allowTransparency);
this.setTheme(theme);
this._rowContainer = document.createElement('div');
this._rowContainer.classList.add(ROW_CONTAINER_CLASS);
@@ -142,11 +140,12 @@ export class DomRenderer extends Disposable implements IRenderer {
this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`;
}
public setTheme(theme: ITheme | undefined): IColorSet {
if (theme) {
this.colorManager.setTheme(theme);
}
public onThemeChange(colors: IColorSet): void {
this._colors = colors;
this._injectCss();
}
private _injectCss(): void {
if (!this._themeStyleElement) {
this._themeStyleElement = document.createElement('style');
this._terminal.screenElement.appendChild(this._themeStyleElement);
@@ -155,8 +154,8 @@ export class DomRenderer extends Disposable implements IRenderer {
// Base CSS
let styles =
`${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +
` color: ${this.colorManager.colors.foreground.css};` +
` background-color: ${this.colorManager.colors.background.css};` +
` color: ${this._colors.foreground.css};` +
` background-color: ${this._colors.background.css};` +
` font-family: ${this._terminal.options.fontFamily};` +
` font-size: ${this._terminal.options.fontSize}px;` +
`}`;
@@ -181,21 +180,21 @@ export class DomRenderer extends Disposable implements IRenderer {
// Cursor
styles +=
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS} {` +
` outline: 1px solid ${this.colorManager.colors.cursor.css};` +
` outline: 1px solid ${this._colors.cursor.css};` +
` outline-offset: -1px;` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_BLINK_CLASS} {` +
` animation: blink 1s step-end infinite;` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` +
` background-color: ${this.colorManager.colors.cursor.css};` +
` color: ${this.colorManager.colors.cursorAccent.css};` +
` background-color: ${this._colors.cursor.css};` +
` color: ${this._colors.cursorAccent.css};` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BAR_CLASS} {` +
` box-shadow: 1px 0 0 ${this.colorManager.colors.cursor.css} inset;` +
` box-shadow: 1px 0 0 ${this._colors.cursor.css} inset;` +
`}` +
`${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_UNDERLINE_CLASS} {` +
` box-shadow: 0 -1px 0 ${this.colorManager.colors.cursor.css} inset;` +
` box-shadow: 0 -1px 0 ${this._colors.cursor.css} inset;` +
`}`;
// Selection
styles +=
@@ -208,20 +207,19 @@ export class DomRenderer extends Disposable implements IRenderer {
`}` +
`${this._terminalSelector} .${SELECTION_CLASS} div {` +
` position: absolute;` +
` background-color: ${this.colorManager.colors.selection.css};` +
` background-color: ${this._colors.selection.css};` +
`}`;
// Colors
this.colorManager.colors.ansi.forEach((c, i) => {
this._colors.ansi.forEach((c, i) => {
styles +=
`${this._terminalSelector} .${FG_CLASS_PREFIX}${i} { color: ${c.css}; }` +
`${this._terminalSelector} .${BG_CLASS_PREFIX}${i} { background-color: ${c.css}; }`;
});
styles +=
`${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${this.colorManager.colors.background.css}; }` +
`${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${this.colorManager.colors.foreground.css}; }`;
`${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${this._colors.background.css}; }` +
`${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${this._colors.foreground.css}; }`;
this._themeStyleElement.innerHTML = styles;
return this.colorManager.colors;
}
public onWindowResize(devicePixelRatio: number): void {
@@ -331,7 +329,7 @@ export class DomRenderer extends Disposable implements IRenderer {
public onOptionsChanged(): void {
// Force a refresh
this._updateDimensions();
this.setTheme(undefined);
this._injectCss();
this._terminal.refresh(0, this._terminal.rows - 1);
}