Move parts of webgl renderer to public API

This commit is contained in:
Daniel Imms
2019-05-19 00:21:07 -07:00
parent 29d3b8281b
commit 134c2ff859
10 changed files with 62 additions and 61 deletions
+1
View File
@@ -32,6 +32,7 @@ export class Terminal implements ITerminalApi {
public get onResize(): IEvent<{ cols: number, rows: number }> { return this._core.onResize; }
public get element(): HTMLElement { return this._core.element; }
public get screenElement(): HTMLElement { return this._core.screenElement; }
public get textarea(): HTMLTextAreaElement { return this._core.textarea; }
public get rows(): number { return this._core.rows; }
public get cols(): number { return this._core.cols; }
+1
View File
@@ -15,6 +15,7 @@ export class LinkRenderLayer extends BaseRenderLayer {
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) {
super(container, 'link', zIndex, true, colors);
// TODO: Need to expose link-related renderer API
terminal.linkifier.onLinkHover(e => this._onLinkHover(e));
terminal.linkifier.onLinkLeave(e => this._onLinkLeave(e));
}
+9 -12
View File
@@ -5,16 +5,14 @@
import { createProgram, PROJECTION_MATRIX } from './WebglUtils';
import { IRenderDimensions } from '../Types';
import { ITerminal } from '../../Types';
import WebglCharAtlas from './atlas/WebglCharAtlas';
import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types';
import { INDICIES_PER_CELL } from './WebglRenderer';
import { COMBINED_CHAR_BIT_MASK } from './RenderModel';
import { fill, slice } from './TypedArray';
import { NULL_CELL_CODE, WHITESPACE_CELL_CODE, CHAR_DATA_CHAR_INDEX } from '../../core/buffer/BufferLine';
import { IBufferLine } from '../../core/Types';
import { NULL_CELL_CODE, WHITESPACE_CELL_CODE } from '../../core/buffer/BufferLine';
import { getLuminance } from './ColorUtils';
import { IColorSet } from 'xterm';
import { IColorSet, Terminal, IBufferLine } from 'xterm';
interface IVertices {
attributes: Float32Array;
@@ -97,7 +95,7 @@ export class GlyphRenderer {
};
constructor(
private _terminal: ITerminal,
private _terminal: Terminal,
private _colors: IColorSet,
private _gl: IWebGL2RenderingContext,
private _dimensions: IRenderDimensions
@@ -185,9 +183,9 @@ export class GlyphRenderer {
let rasterizedGlyph: IRasterizedGlyph;
if (chars && chars.length > 1) {
rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg, this._terminal.options.enableBold);
rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg, this._terminal.getOption('enableBold'));
} else {
rasterizedGlyph = this._atlas.getRasterizedGlyph(code, attr, bg, fg, this._terminal.options.enableBold);
rasterizedGlyph = this._atlas.getRasterizedGlyph(code, attr, bg, fg, this._terminal.getOption('enableBold'));
}
// Fill empty if no glyph was found
@@ -252,8 +250,8 @@ export class GlyphRenderer {
private _updateSelectionRange(startCol: number, endCol: number, y: number, model: IRenderModel, bg: number, fg: number): void {
const terminal = this._terminal;
const row = y + terminal.buffer.ydisp;
let line: IBufferLine;
const row = y + terminal.buffer.viewportY;
let line: IBufferLine | undefined;
for (let x = startCol; x < endCol; x++) {
const offset = (y * this._terminal.cols + x) * INDICIES_PER_CELL;
// Because the cache uses attr as a lookup key it needs to contain the selection colors as well
@@ -262,10 +260,9 @@ export class GlyphRenderer {
const code = model.cells[offset];
if (code & COMBINED_CHAR_BIT_MASK) {
if (!line) {
line = terminal.buffer.lines.get(row);
line = terminal.buffer.getLine(row);
}
const charData = line.get(x);
const chars = charData[CHAR_DATA_CHAR_INDEX];
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);
+2 -3
View File
@@ -3,7 +3,6 @@
* @license MIT
*/
import { ITerminal } from '../../Types';
import { IRenderDimensions } from '../Types';
import { createProgram, expandFloat32Array, PROJECTION_MATRIX } from './WebglUtils';
import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelectionRenderModel } from './Types';
@@ -11,7 +10,7 @@ import { fill } from './TypedArray';
import { INVERTED_DEFAULT_COLOR } from './atlas/Types';
import { is256Color } from './atlas/CharAtlasUtils';
import { DEFAULT_COLOR } from '../../common/Types';
import { IColorSet, IColor } from 'xterm';
import { IColorSet, IColor, Terminal } from 'xterm';
const enum VertexAttribLocations {
POSITION = 0,
@@ -76,7 +75,7 @@ export class RectangleRenderer {
};
constructor(
private _terminal: ITerminal,
private _terminal: Terminal,
private _colors: IColorSet,
private _gl: IWebGL2RenderingContext,
private _dimensions: IRenderDimensions
+31 -27
View File
@@ -17,7 +17,7 @@ import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel';
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 'xterm';
import { IColorSet, Terminal } from 'xterm';
import { getLuminance } from './ColorUtils';
export const INDICIES_PER_CELL = 4;
@@ -36,16 +36,20 @@ export class WebglRenderer extends Disposable implements IRenderer {
public dimensions: IRenderDimensions;
private _core: ITerminal;
constructor(
private _terminal: ITerminal,
private _terminal: Terminal,
private _colors: IColorSet
) {
super();
this._core = (this._terminal as any)._core;
this._applyBgLuminanceBasedSelection();
this._renderLayers = [
new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._terminal),
new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._core),
new CursorRenderLayer(this._terminal.screenElement, 3, this._colors)
];
this.dimensions = {
@@ -102,8 +106,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
// Clear layers and force a full render
this._renderLayers.forEach(l => {
l.setColors(this._terminal, this._colors);
l.reset(this._terminal);
l.setColors(this._core, this._colors);
l.reset(this._core);
});
this._rectangleRenderer.setColors();
@@ -117,7 +121,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
// and the terminal needs to refreshed
if (this._devicePixelRatio !== window.devicePixelRatio) {
this._devicePixelRatio = window.devicePixelRatio;
this.onResize(this._terminal.cols, this._terminal.rows);
this.onResize(this._core.cols, this._core.rows);
}
}
@@ -125,11 +129,11 @@ export class WebglRenderer extends Disposable implements IRenderer {
// Update character and canvas dimensions
this._updateDimensions(devicePixelRatio);
this._model.resize(this._terminal.cols, this._terminal.rows);
this._model.resize(this._core.cols, this._core.rows);
this._rectangleRenderer.onResize();
// Resize all render layers
this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions));
this._renderLayers.forEach(l => l.resize(this._core, this.dimensions));
// Resize the canvas
this._canvas.width = this.dimensions.scaledCanvasWidth;
@@ -151,15 +155,15 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
public onBlur(): void {
this._renderLayers.forEach(l => l.onBlur(this._terminal));
this._renderLayers.forEach(l => l.onBlur(this._core));
}
public onFocus(): void {
this._renderLayers.forEach(l => l.onFocus(this._terminal));
this._renderLayers.forEach(l => l.onFocus(this._core));
}
public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void {
this._renderLayers.forEach(l => l.onSelectionChanged(this._terminal, start, end, columnSelectMode));
this._renderLayers.forEach(l => l.onSelectionChanged(this._core, start, end, columnSelectMode));
this._updateSelectionModel(start, end);
@@ -167,15 +171,15 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._glyphRenderer.updateSelection(this._model, columnSelectMode);
// TODO: #2102 Should this move to RenderCoordinator?
this._terminal.refresh(0, this._terminal.rows - 1);
this._core.refresh(0, this._core.rows - 1);
}
public onCursorMove(): void {
this._renderLayers.forEach(l => l.onCursorMove(this._terminal));
this._renderLayers.forEach(l => l.onCursorMove(this._core));
}
public onOptionsChanged(): void {
this._renderLayers.forEach(l => l.onOptionsChanged(this._terminal));
this._renderLayers.forEach(l => l.onOptionsChanged(this._core));
this._updateDimensions();
this._refreshCharAtlas();
}
@@ -200,7 +204,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
public clear(): void {
this._renderLayers.forEach(l => l.reset(this._terminal));
this._renderLayers.forEach(l => l.reset(this._core));
}
public registerCharacterJoiner(handler: CharacterJoinerHandler): number {
@@ -213,7 +217,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
public renderRows(start: number, end: number): void {
// Update render layers
this._renderLayers.forEach(l => l.onGridChanged(this._terminal, start, end));
this._renderLayers.forEach(l => l.onGridChanged(this._core, start, end));
// Tell renderer the frame is beginning
if (this._glyphRenderer.beginFrame()) {
@@ -229,7 +233,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
private _updateModel(start: number, end: number): void {
const terminal = this._terminal;
const terminal = this._core;
for (let y = start; y <= end; y++) {
const row = y + terminal.buffer.ydisp;
@@ -288,7 +292,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
}
private _updateSelectionModel(start: [number, number], end: [number, number]): void {
const terminal = this._terminal;
const terminal = this._core;
// Selection does not exist
if (!start || !end || (start[0] === end[0] && start[1] === end[1])) {
@@ -322,7 +326,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
*/
private _updateDimensions(devicePixelRatio: number = window.devicePixelRatio): void {
// Perform a new measure if the CharMeasure dimensions are not yet available
if (!this._terminal.charMeasure.width || !this._terminal.charMeasure.height) {
if (!this._core.charMeasure.width || !this._core.charMeasure.height) {
return;
}
@@ -333,34 +337,34 @@ export class WebglRenderer extends Disposable implements IRenderer {
// NOTE: ceil fixes sometime, floor does others :s
this.dimensions.scaledCharWidth = Math.floor(this._terminal.charMeasure.width * devicePixelRatio);
this.dimensions.scaledCharWidth = Math.floor(this._core.charMeasure.width * devicePixelRatio);
// Calculate the scaled character height. Height is ceiled in case
// devicePixelRatio is a floating point number in order to ensure there is
// enough space to draw the character to the cell.
this.dimensions.scaledCharHeight = Math.ceil(this._terminal.charMeasure.height * devicePixelRatio);
this.dimensions.scaledCharHeight = Math.ceil(this._core.charMeasure.height * devicePixelRatio);
// Calculate the scaled cell height, if lineHeight is not 1 then the value
// will be floored because since lineHeight can never be lower then 1, there
// is a guarentee that the scaled line height will always be larger than
// scaled char height.
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight);
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._core.options.lineHeight);
// Calculate the y coordinate within a cell that text should draw from in
// order to draw in the center of a cell.
this.dimensions.scaledCharTop = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2);
this.dimensions.scaledCharTop = this._core.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2);
// Calculate the scaled cell width, taking the letterSpacing into account.
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing);
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._core.options.letterSpacing);
// Calculate the x coordinate with a cell that text should draw from in
// order to draw in the center of a cell.
this.dimensions.scaledCharLeft = Math.floor(this._terminal.options.letterSpacing / 2);
this.dimensions.scaledCharLeft = Math.floor(this._core.options.letterSpacing / 2);
// Recalculate the canvas dimensions; scaled* define the actual number of
// pixel in the canvas
this.dimensions.scaledCanvasHeight = this._terminal.rows * this.dimensions.scaledCellHeight;
this.dimensions.scaledCanvasWidth = this._terminal.cols * this.dimensions.scaledCellWidth;
this.dimensions.scaledCanvasHeight = this._core.rows * this.dimensions.scaledCellHeight;
this.dimensions.scaledCanvasWidth = this._core.cols * this.dimensions.scaledCellWidth;
// The the size of the canvas on the page. It's very important that this
// rounds to nearest integer and not ceils as browsers often set
+1 -2
View File
@@ -16,8 +16,7 @@ export class WebglRendererAddon implements ITerminalAddon {
throw new Error('Cannot activate WebglRendererAddon before Terminal.open');
}
this._terminal = terminal;
const core = (terminal as any)._core;
this._terminal.setRenderer(new WebglRenderer(core, core._colorManager.colors));
this._terminal.setRenderer(new WebglRenderer(terminal, (terminal as any)._core._colorManager.colors));
}
public dispose(): void {
+4 -5
View File
@@ -3,19 +3,18 @@
* @license MIT
*/
import { ITerminal } from '../../../Types';
import { generateConfig, configEquals } from './CharAtlasUtils';
import BaseCharAtlas from './BaseCharAtlas';
import WebglCharAtlas from './WebglCharAtlas';
import { ICharAtlasConfig } from './Types';
import { IColorSet } from 'xterm';
import { IColorSet, Terminal } from 'xterm';
interface ICharAtlasCacheEntry {
atlas: BaseCharAtlas;
config: ICharAtlasConfig;
// N.B. This implementation potentially holds onto copies of the terminal forever, so
// this may cause memory leaks.
ownedBy: ITerminal[];
ownedBy: Terminal[];
}
const charAtlasCache: ICharAtlasCacheEntry[] = [];
@@ -27,7 +26,7 @@ const charAtlasCache: ICharAtlasCacheEntry[] = [];
* @param colors The colors to use.
*/
export function acquireCharAtlas(
terminal: ITerminal,
terminal: Terminal,
colors: IColorSet,
scaledCharWidth: number,
scaledCharHeight: number
@@ -76,7 +75,7 @@ export function acquireCharAtlas(
* Removes a terminal reference from the cache, allowing its memory to be freed.
* @param terminal The terminal to remove.
*/
export function removeTerminalFromCache(terminal: ITerminal): void {
export function removeTerminalFromCache(terminal: Terminal): void {
for (let i = 0; i < charAtlasCache.length; i++) {
const index = charAtlasCache[i].ownedBy.indexOf(terminal);
if (index !== -1) {
+8 -11
View File
@@ -3,12 +3,11 @@
* @license MIT
*/
import { ITerminal } from '../../../Types';
import { ICharAtlasConfig } from './Types';
import { DEFAULT_COLOR } from '../../../common/Types';
import { IColorSet } from 'xterm';
import { IColorSet, Terminal, FontWeight } from 'xterm';
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {
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,
@@ -21,15 +20,14 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number
ansi: colors.ansi.slice(0, 16)
};
return {
type: terminal.options.experimentalCharAtlas,
devicePixelRatio: window.devicePixelRatio,
scaledCharWidth,
scaledCharHeight,
fontFamily: terminal.options.fontFamily,
fontSize: terminal.options.fontSize,
fontWeight: terminal.options.fontWeight,
fontWeightBold: terminal.options.fontWeightBold,
allowTransparency: terminal.options.allowTransparency,
fontFamily: terminal.getOption('fontFamily'),
fontSize: terminal.getOption('fontSize'),
fontWeight: terminal.getOption('fontWeight') as FontWeight,
fontWeightBold: terminal.getOption('fontWeightBold') as FontWeight,
allowTransparency: terminal.getOption('allowTransparency'),
colors: clonedColors
};
}
@@ -40,8 +38,7 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean
return false;
}
}
return a.type === b.type &&
a.devicePixelRatio === b.devicePixelRatio &&
return a.devicePixelRatio === b.devicePixelRatio &&
a.fontFamily === b.fontFamily &&
a.fontSize === b.fontSize &&
a.fontWeight === b.fontWeight &&
-1
View File
@@ -21,7 +21,6 @@ export interface IGlyphIdentifier {
}
export interface ICharAtlasConfig {
type: 'none' | 'static' | 'dynamic' | 'webgl';
devicePixelRatio: number;
fontSize: number;
fontFamily: string;
+5
View File
@@ -895,6 +895,11 @@ declare module 'xterm' {
* (EXPERIMENTAL)
*/
setRenderer(renderer: any): void;
screenElement: HTMLElement;
}
export namespace Renderer {
const DEFAULT_COLOR: number;
}
/**