From 4beea9b7048db193cc1d496e515c9b16578b162b Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sun, 19 May 2019 15:44:13 -0700 Subject: [PATCH] Add tests for webgl bg colors --- src/public/Terminal.api.ts | 9 -- src/public/Terminal.ts | 4 +- src/renderer/webgl/WebglRenderer.api.ts | 136 +++++++++++++++++++++++ src/renderer/webgl/WebglRenderer.ts | 10 +- src/renderer/webgl/WebglRendererAddon.ts | 6 +- 5 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 src/renderer/webgl/WebglRenderer.api.ts diff --git a/src/public/Terminal.api.ts b/src/public/Terminal.api.ts index 80ba489d..d8325229 100644 --- a/src/public/Terminal.api.ts +++ b/src/public/Terminal.api.ts @@ -475,15 +475,6 @@ describe('API Integration Tests', () => { }); }); }); - - describe('WebGL Renderer', () => { - it('load doesn\'t throw', async function(): Promise { - this.timeout(10000); - await openTerminal({ rendererType: 'dom' }); - await page.waitForSelector('.xterm style'); - await page.evaluate(`window.term.loadWebgl();`); - }); - }); }); async function openTerminal(options: ITerminalOptions = {}): Promise { diff --git a/src/public/Terminal.ts b/src/public/Terminal.ts index 3af5162c..ace272d8 100644 --- a/src/public/Terminal.ts +++ b/src/public/Terminal.ts @@ -188,8 +188,8 @@ export class Terminal implements ITerminalApi { public setRenderer(renderer: any): void { this._core.setRenderer(renderer); } - public loadWebgl(): void { - this.loadAddon(new WebglRendererAddon()); + public loadWebgl(preserveDrawingBuffer?: boolean): void { + this.loadAddon(new WebglRendererAddon(preserveDrawingBuffer)); } public static get strings(): ILocalizableStrings { return Strings; diff --git a/src/renderer/webgl/WebglRenderer.api.ts b/src/renderer/webgl/WebglRenderer.api.ts new file mode 100644 index 00000000..0eb111e5 --- /dev/null +++ b/src/renderer/webgl/WebglRenderer.api.ts @@ -0,0 +1,136 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import * as puppeteer from 'puppeteer'; +import { assert } from 'chai'; +import { ITerminalOptions } from '../../Types'; + +const APP = 'http://127.0.0.1:3000/test'; + +let browser: puppeteer.Browser; +let page: puppeteer.Page; +const width = 800; +const height = 600; + +describe('WebGL Renderer Integration Tests', () => { + before(async function(): Promise { + this.timeout(10000); + browser = await puppeteer.launch({ + headless: process.argv.indexOf('--headless') !== -1, + slowMo: 80, + args: [`--window-size=${width},${height}`] + }); + page = (await browser.pages())[0]; + await page.setViewport({ width, height }); + }); + + after(() => { + browser.close(); + }); + + beforeEach(async () => { + await page.goto(APP); + }); + + describe('WebGL Renderer', () => { + it.only('background colors normal', async function(): Promise { + this.timeout(10000); + await openTerminal({ + rendererType: 'dom', + theme: { + black: '#010203', + red: '#040506', + green: '#070809', + yellow: '#0a0b0c', + blue: '#0d0e0f', + magenta: '#101112', + cyan: '#131415', + white: '#161718' + } + }); + // await writeSync(`\\x1b[41m${' '.repeat(5 * 5)}`); + await writeSync(`\\x1b[40m \\x1b[41m \\x1b[42m \\x1b[43m \\x1b[44m \\x1b[45m \\x1b[46m \\x1b[47m `); + await page.evaluate(`window.term.loadWebgl(true);`); + assert.deepEqual(await getCellBgColor(1, 1), [1, 2, 3, 255]); + assert.deepEqual(await getCellBgColor(2, 1), [4, 5, 6, 255]); + assert.deepEqual(await getCellBgColor(3, 1), [7, 8, 9, 255]); + assert.deepEqual(await getCellBgColor(4, 1), [10, 11, 12, 255]); + assert.deepEqual(await getCellBgColor(5, 1), [13, 14, 15, 255]); + assert.deepEqual(await getCellBgColor(6, 1), [16, 17, 18, 255]); + assert.deepEqual(await getCellBgColor(7, 1), [19, 20, 21, 255]); + assert.deepEqual(await getCellBgColor(8, 1), [22, 23, 24, 255]); + }); + + it.only('background colors bright', async function(): Promise { + this.timeout(10000); + await openTerminal({ + rendererType: 'dom', + theme: { + brightBlack: '#010203', + brightRed: '#040506', + brightGreen: '#070809', + brightYellow: '#0a0b0c', + brightBlue: '#0d0e0f', + brightMagenta: '#101112', + brightCyan: '#131415', + brightWhite: '#161718' + } + }); + // await writeSync(`\\x1b[41m${' '.repeat(5 * 5)}`); + await writeSync(`\\x1b[100m \\x1b[101m \\x1b[102m \\x1b[103m \\x1b[104m \\x1b[105m \\x1b[106m \\x1b[107m `); + await page.evaluate(`window.term.loadWebgl(true);`); + assert.deepEqual(await getCellBgColor(1, 1), [1, 2, 3, 255]); + assert.deepEqual(await getCellBgColor(2, 1), [4, 5, 6, 255]); + assert.deepEqual(await getCellBgColor(3, 1), [7, 8, 9, 255]); + assert.deepEqual(await getCellBgColor(4, 1), [10, 11, 12, 255]); + assert.deepEqual(await getCellBgColor(5, 1), [13, 14, 15, 255]); + assert.deepEqual(await getCellBgColor(6, 1), [16, 17, 18, 255]); + assert.deepEqual(await getCellBgColor(7, 1), [19, 20, 21, 255]); + assert.deepEqual(await getCellBgColor(8, 1), [22, 23, 24, 255]); + }); + }); +}); + +async function openTerminal(options: ITerminalOptions = {}): Promise { + await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`); + await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`); + if (options.rendererType === 'dom') { + await page.waitForSelector('.xterm-rows'); + } else { + await page.waitForSelector('.xterm-text-layer'); + } +} + +async function writeSync(data: string): Promise { + await page.evaluate(`window.term.write('${data}');`); + while (true) { + if (await page.evaluate(`window.term._core.writeBuffer.length === 0`)) { + break; + } + } +} + +// async function getPixelAt(x: number, y: number): Promise { +// await page.evaluate(` +// window.gl = window.term._core._renderCoordinator._renderer._gl; +// window.result = new Uint8Array(4); +// window.gl.readPixels(${x}, window.gl.drawingBufferHeight - 1 - ${y}, 1, 1, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result); +// `); +// return await page.evaluate(`Array.from(window.result)`); +// } + +async function getCellBgColor(col: number, row: number): Promise { + await page.evaluate(` + window.gl = window.term._core._renderCoordinator._renderer._gl; + window.result = new Uint8Array(4); + window.d = window.term._core._renderCoordinator.dimensions; + window.gl.readPixels( + Math.floor(${col - 1} * window.d.scaledCellWidth), + Math.floor(window.gl.drawingBufferHeight - 1 - ${row - 1} * window.d.scaledCellHeight), + 1, 1, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result + ); + `); + return await page.evaluate(`Array.from(window.result)`); +} diff --git a/src/renderer/webgl/WebglRenderer.ts b/src/renderer/webgl/WebglRenderer.ts index 7cf68464..1ef53cfa 100644 --- a/src/renderer/webgl/WebglRenderer.ts +++ b/src/renderer/webgl/WebglRenderer.ts @@ -41,7 +41,8 @@ export class WebglRenderer extends Disposable implements IRenderer { constructor( private _terminal: Terminal, - private _colors: IColorSet + private _colors: IColorSet, + preserveDrawingBuffer?: boolean ) { super(); @@ -71,7 +72,12 @@ export class WebglRenderer extends Disposable implements IRenderer { this._updateDimensions(); this._canvas = document.createElement('canvas'); - const contextAttributes = { antialias: false, depth: false }; + + const contextAttributes = { + antialias: false, + depth: false, + preserveDrawingBuffer + }; this._gl = this._canvas.getContext('webgl2', contextAttributes) as IWebGL2RenderingContext; if (!this._gl) { throw new Error('WebGL2 not supported'); diff --git a/src/renderer/webgl/WebglRendererAddon.ts b/src/renderer/webgl/WebglRendererAddon.ts index 6c835ba8..6ce27b0a 100644 --- a/src/renderer/webgl/WebglRendererAddon.ts +++ b/src/renderer/webgl/WebglRendererAddon.ts @@ -9,14 +9,16 @@ import { WebglRenderer } from './WebglRenderer'; export class WebglRendererAddon implements ITerminalAddon { private _terminal: Terminal | undefined; - constructor() {} + constructor( + private _preserveDrawingBuffer?: boolean + ) {} public activate(terminal: Terminal): void { if (!terminal.element) { throw new Error('Cannot activate WebglRendererAddon before Terminal.open'); } this._terminal = terminal; - this._terminal.setRenderer(new WebglRenderer(terminal, (terminal as any)._core._colorManager.colors)); + this._terminal.setRenderer(new WebglRenderer(terminal, (terminal as any)._core._colorManager.colors, this._preserveDrawingBuffer)); } public dispose(): void {