From 8792bb5f363033c612c732b0bd34db7dee9e9390 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 18 May 2019 18:47:44 -0700 Subject: [PATCH] Introduce a RenderCoordinator that owns common Renderer logic Part of #2005 --- src/Terminal.ts | 13 +++++++++++-- src/TestUtils.test.ts | 2 +- src/renderer/RenderCoordinator.ts | 30 ++++++++++++++++++++++++++++++ src/renderer/Renderer.ts | 20 ++------------------ src/renderer/Types.ts | 2 +- src/renderer/dom/DomRenderer.ts | 10 ++-------- 6 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 src/renderer/RenderCoordinator.ts diff --git a/src/Terminal.ts b/src/Terminal.ts index 60409859..b241cc23 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -54,6 +54,7 @@ import { EventEmitter2, IEvent } from './common/EventEmitter2'; import { Attributes, DEFAULT_ATTR_DATA } from './core/buffer/BufferLine'; import { applyWindowsMode } from './WindowsMode'; import { ColorManager } from './ui/ColorManager'; +import { RenderCoordinator } from './renderer/RenderCoordinator'; // Let it work inside Node.js for automated testing purposes. const document = (typeof window !== 'undefined') ? window.document : null; @@ -203,6 +204,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II private _inputHandler: InputHandler; public soundManager: SoundManager; + private _renderCoordinator: RenderCoordinator; public renderer: IRenderer; public selectionManager: SelectionManager; public linkifier: ILinkifier; @@ -770,6 +772,9 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II this._colorManager.setTheme(this._theme); this._setupRenderer(); + this._renderCoordinator = new RenderCoordinator(this.renderer, this.rows); + this.onResize(e => this._renderCoordinator.resize(e.cols, e.rows)); + this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this.charMeasure); this.viewport.onThemeChange(this._colorManager.colors); this.register(this.viewport); @@ -839,6 +844,10 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II case 'dom': this.renderer = new DomRenderer(this, this._colorManager.colors); break; default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } + // TODO: Setting of renderer should be owned by RenderCoordinator + if (this._renderCoordinator) { + this._renderCoordinator.setRenderer(this.renderer); + } this.renderer.onRender(e => this._onRender.fire(e)); this.register(this.renderer); } @@ -1207,8 +1216,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II * @param end The row to end at (between start and this.rows - 1). */ public refresh(start: number, end: number): void { - if (this.renderer) { - this.renderer.refreshRows(start, end); + if (this._renderCoordinator) { + this._renderCoordinator.refreshRows(start, end); } } diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index d3ed93a3..86745fc7 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -396,7 +396,7 @@ export class MockRenderer implements IRenderer { onOptionsChanged(): void {} onWindowResize(devicePixelRatio: number): void {} clear(): void {} - refreshRows(start: number, end: number): void {} + renderRows(start: number, end: number): void {} registerCharacterJoiner(handler: CharacterJoinerHandler): number { return 0; } deregisterCharacterJoiner(): boolean { return true; } } diff --git a/src/renderer/RenderCoordinator.ts b/src/renderer/RenderCoordinator.ts new file mode 100644 index 00000000..0a4d4b99 --- /dev/null +++ b/src/renderer/RenderCoordinator.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IRenderer } from './Types'; +import { RenderDebouncer } from '../ui/RenderDebouncer'; + +export class RenderCoordinator { + private _renderDebouncer: RenderDebouncer; + + constructor( + private _renderer: IRenderer, + private _rowCount: number + ) { + this._renderDebouncer = new RenderDebouncer((start, end) => this._renderer.renderRows(start, end)); + } + + public refreshRows(start: number, end: number): void { + this._renderDebouncer.refresh(start, end, this._rowCount); + } + + public resize(cols: number, rows: number): void { + this._rowCount = rows; + } + + public setRenderer(renderer: IRenderer): void { + this._renderer = renderer; + } +} diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 527c5966..98fc50fc 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -9,7 +9,6 @@ import { CursorRenderLayer } from './CursorRenderLayer'; 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 { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry'; import { EventEmitter2, IEvent } from '../common/EventEmitter2'; @@ -17,7 +16,6 @@ import { Disposable } from '../common/Lifecycle'; import { IColorSet } from '../ui/Types'; export class Renderer extends Disposable implements IRenderer { - private _renderDebouncer: RenderDebouncer; private _renderLayers: IRenderLayer[]; private _devicePixelRatio: number; @@ -65,7 +63,7 @@ export class Renderer extends Disposable implements IRenderer { this._updateDimensions(); this.onOptionsChanged(); - this._renderDebouncer = new RenderDebouncer(this._renderRows.bind(this)); + // TODO: Move dpr monitor to RenderCoordinator this._screenDprMonitor = new ScreenDprMonitor(); this._screenDprMonitor.setListener(() => this.onWindowResize(window.devicePixelRatio)); this.register(this._screenDprMonitor); @@ -175,25 +173,11 @@ export class Renderer extends Disposable implements IRenderer { } } - /** - * Queues a refresh between two rows (inclusive), to be done on next animation - * frame. - * @param start The start row. - * @param end The end row. - */ - public refreshRows(start: number, end: number): void { - if (this._isPaused) { - this._needsFullRefresh = true; - return; - } - this._renderDebouncer.refresh(start, end, this._terminal.rows); - } - /** * Performs the refresh loop callback, calling refresh only if a refresh is * necessary before queueing up the next one. */ - private _renderRows(start: number, end: number): void { + public renderRows(start: number, end: number): void { this._renderLayers.forEach(l => l.onGridChanged(this._terminal, start, end)); this._onRender.fire({ start, end }); } diff --git a/src/renderer/Types.ts b/src/renderer/Types.ts index 590df0e0..3b00820a 100644 --- a/src/renderer/Types.ts +++ b/src/renderer/Types.ts @@ -42,7 +42,7 @@ export interface IRenderer extends IDisposable { onCursorMove(): void; onOptionsChanged(): void; clear(): void; - refreshRows(start: number, end: number): void; + renderRows(start: number, end: number): void; registerCharacterJoiner(handler: CharacterJoinerHandler): number; deregisterCharacterJoiner(joinerId: number): boolean; } diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 6f46f0ec..d0c4e20c 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -5,7 +5,6 @@ import { IRenderer, IRenderDimensions } from '../Types'; import { ILinkifierEvent, ITerminal, CharacterJoinerHandler } from '../../Types'; -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'; @@ -30,7 +29,6 @@ let nextTerminalId = 1; * canvas is not an option. */ export class DomRenderer extends Disposable implements IRenderer { - private _renderDebouncer: RenderDebouncer; private _rowFactory: DomRendererRowFactory; private _terminalClass: number = nextTerminalId++; @@ -42,6 +40,7 @@ export class DomRenderer extends Disposable implements IRenderer { public dimensions: IRenderDimensions; + // TODO: These events should be owned by RenderCoordinator 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 }>(); @@ -78,7 +77,6 @@ export class DomRenderer extends Disposable implements IRenderer { }; this._updateDimensions(); - this._renderDebouncer = new RenderDebouncer(this._renderRows.bind(this)); this._rowFactory = new DomRendererRowFactory(_terminal.options, document); this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass); @@ -337,11 +335,7 @@ export class DomRenderer extends Disposable implements IRenderer { this._rowElements.forEach(e => e.innerHTML = ''); } - public refreshRows(start: number, end: number): void { - this._renderDebouncer.refresh(start, end, this._terminal.rows); - } - - private _renderRows(start: number, end: number): void { + public renderRows(start: number, end: number): void { const terminal = this._terminal; const cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y;