Don't pass terminal around within render layers

Will ease migration to services
This commit is contained in:
Daniel Imms
2019-07-14 10:04:51 -07:00
parent 60194179f8
commit 868125f258
7 changed files with 143 additions and 149 deletions
+34 -39
View File
@@ -46,7 +46,8 @@ export abstract class BaseRenderLayer implements IRenderLayer {
id: string,
zIndex: number,
private _alpha: boolean,
protected _colors: IColorSet
protected _colors: IColorSet,
protected _terminal: ITerminal
) {
this._canvas = document.createElement('canvas');
this._canvas.classList.add(`xterm-${id}-layer`);
@@ -70,18 +71,18 @@ export abstract class BaseRenderLayer implements IRenderLayer {
}
}
public onOptionsChanged(terminal: ITerminal): void {}
public onBlur(terminal: ITerminal): void {}
public onFocus(terminal: ITerminal): void {}
public onCursorMove(terminal: ITerminal): void {}
public onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void {}
public onSelectionChanged(terminal: ITerminal, start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {}
public onOptionsChanged(): void {}
public onBlur(): void {}
public onFocus(): void {}
public onCursorMove(): void {}
public onGridChanged(startRow: number, endRow: number): void {}
public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {}
public setColors(terminal: ITerminal, colorSet: IColorSet): void {
this._refreshCharAtlas(terminal, colorSet);
public setColors(colorSet: IColorSet): void {
this._refreshCharAtlas(colorSet);
}
protected _setTransparency(terminal: ITerminal, alpha: boolean): void {
protected _setTransparency(alpha: boolean): void {
// Do nothing when alpha doesn't change
if (alpha === this._alpha) {
return;
@@ -96,24 +97,23 @@ export abstract class BaseRenderLayer implements IRenderLayer {
this._container.replaceChild(this._canvas, oldCanvas);
// Regenerate char atlas and force a full redraw
this._refreshCharAtlas(terminal, this._colors);
this.onGridChanged(terminal, 0, terminal.rows - 1);
this._refreshCharAtlas(this._colors);
this.onGridChanged(0, this._terminal.rows - 1);
}
/**
* Refreshes the char atlas, aquiring a new one if necessary.
* @param terminal The terminal.
* @param colorSet The color set to use for the char atlas.
*/
private _refreshCharAtlas(terminal: ITerminal, colorSet: IColorSet): void {
private _refreshCharAtlas(colorSet: IColorSet): void {
if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) {
return;
}
this._charAtlas = acquireCharAtlas(terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight);
this._charAtlas = acquireCharAtlas(this._terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight);
this._charAtlas.warmUp();
}
public resize(terminal: ITerminal, dim: IRenderDimensions): void {
public resize(dim: IRenderDimensions): void {
this._scaledCellWidth = dim.scaledCellWidth;
this._scaledCellHeight = dim.scaledCellHeight;
this._scaledCharWidth = dim.scaledCharWidth;
@@ -130,10 +130,10 @@ export abstract class BaseRenderLayer implements IRenderLayer {
this._clearAll();
}
this._refreshCharAtlas(terminal, this._colors);
this._refreshCharAtlas(this._colors);
}
public abstract reset(terminal: ITerminal): void;
public abstract reset(): void;
/**
* Fills 1+ cells completely. This uses the existing fillStyle on the context.
@@ -233,16 +233,15 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* Draws a truecolor character at the cell. The character will be clipped to
* ensure that it fits with the cell, including the cell to the right if it's
* a wide character. This uses the existing fillStyle on the context.
* @param terminal The terminal.
* @param cell The cell data for the character to draw.
* @param x The column to draw at.
* @param y The row to draw at.
* @param color The color of the character.
*/
protected _fillCharTrueColor(terminal: ITerminal, cell: CellData, x: number, y: number): void {
this._ctx.font = this._getFont(terminal, false, false);
protected _fillCharTrueColor(cell: CellData, x: number, y: number): void {
this._ctx.font = this._getFont(false, false);
this._ctx.textBaseline = 'middle';
this._clipRow(terminal, y);
this._clipRow(y);
this._ctx.fillText(
cell.getChars(),
x * this._scaledCellWidth + this._scaledCharLeft,
@@ -252,7 +251,6 @@ export abstract class BaseRenderLayer implements IRenderLayer {
/**
* Draws one or more characters at a cell. If possible this will draw using
* the character atlas to reduce draw time.
* @param terminal The terminal.
* @param chars The character or characters.
* @param code The character code.
* @param width The width of the characters.
@@ -263,14 +261,14 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* This is used to validate whether a cached image can be used.
* @param bold Whether the text is bold.
*/
protected _drawChars(terminal: ITerminal, cell: ICellData, x: number, y: number): void {
protected _drawChars(cell: ICellData, x: number, y: number): void {
// skip cache right away if we draw in RGB
// Note: to avoid bad runtime JoinedCellData will be skipped
// in the cache handler itself (atlasDidDraw == false) and
// fall through to uncached later down below
if (cell.isFgRGB() || cell.isBgRGB()) {
this._drawUncachedChars(terminal, cell, x, y);
this._drawUncachedChars(cell, x, y);
return;
}
@@ -284,7 +282,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
fg = (cell.isFgDefault()) ? DEFAULT_COLOR : cell.getFgColor();
}
const drawInBrightColor = terminal.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8 && fg !== INVERTED_DEFAULT_COLOR;
const drawInBrightColor = this._terminal.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8 && fg !== INVERTED_DEFAULT_COLOR;
fg += drawInBrightColor ? 8 : 0;
this._currentGlyphIdentifier.chars = cell.getChars() || WHITESPACE_CELL_CHAR;
@@ -302,7 +300,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
);
if (!atlasDidDraw) {
this._drawUncachedChars(terminal, cell, x, y);
this._drawUncachedChars(cell, x, y);
}
}
@@ -310,16 +308,15 @@ export abstract class BaseRenderLayer implements IRenderLayer {
* Draws one or more characters at one or more cells. The character(s) will be
* clipped to ensure that they fit with the cell(s), including the cell to the
* right if the last character is a wide character.
* @param terminal The terminal.
* @param chars The character.
* @param width The width of the character.
* @param fg The foreground color, in the format stored within the attributes.
* @param x The column to draw at.
* @param y The row to draw at.
*/
private _drawUncachedChars(terminal: ITerminal, cell: ICellData, x: number, y: number): void {
private _drawUncachedChars(cell: ICellData, x: number, y: number): void {
this._ctx.save();
this._ctx.font = this._getFont(terminal, !!cell.isBold(), !!cell.isItalic());
this._ctx.font = this._getFont(!!cell.isBold(), !!cell.isItalic());
this._ctx.textBaseline = 'middle';
if (cell.isInverse()) {
@@ -337,14 +334,14 @@ export abstract class BaseRenderLayer implements IRenderLayer {
this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`;
} else {
let fg = cell.getFgColor();
if (terminal.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
if (this._terminal.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
fg += 8;
}
this._ctx.fillStyle = this._colors.ansi[fg].css;
}
}
this._clipRow(terminal, y);
this._clipRow(y);
// Apply alpha to dim the character
if (cell.isDim()) {
@@ -360,29 +357,27 @@ export abstract class BaseRenderLayer implements IRenderLayer {
/**
* Clips a row to ensure no pixels will be drawn outside the cells in the row.
* @param terminal The terminal.
* @param y The row to clip.
*/
private _clipRow(terminal: ITerminal, y: number): void {
private _clipRow(y: number): void {
this._ctx.beginPath();
this._ctx.rect(
0,
y * this._scaledCellHeight,
terminal.cols * this._scaledCellWidth,
this._terminal.cols * this._scaledCellWidth,
this._scaledCellHeight);
this._ctx.clip();
}
/**
* Gets the current font.
* @param terminal The terminal.
* @param isBold If we should use the bold fontWeight.
*/
protected _getFont(terminal: ITerminal, isBold: boolean, isItalic: boolean): string {
const fontWeight = isBold ? terminal.options.fontWeightBold : terminal.options.fontWeight;
protected _getFont(isBold: boolean, isItalic: boolean): string {
const fontWeight = isBold ? this._terminal.options.fontWeightBold : this._terminal.options.fontWeight;
const fontStyle = isItalic ? 'italic' : '';
return `${fontStyle} ${fontWeight} ${terminal.options.fontSize * window.devicePixelRatio}px ${terminal.options.fontFamily}`;
return `${fontStyle} ${fontWeight} ${this._terminal.options.fontSize * window.devicePixelRatio}px ${this._terminal.options.fontFamily}`;
}
}
+43 -43
View File
@@ -25,12 +25,12 @@ const BLINK_INTERVAL = 600;
export class CursorRenderLayer extends BaseRenderLayer {
private _state: ICursorState;
private _cursorRenderers: {[key: string]: (terminal: ITerminal, x: number, y: number, cell: ICellData) => void};
private _cursorRenderers: {[key: string]: (x: number, y: number, cell: ICellData) => void};
private _cursorBlinkStateManager: CursorBlinkStateManager;
private _cell: ICellData = new CellData();
constructor(container: HTMLElement, zIndex: number, colors: IColorSet) {
super(container, 'cursor', zIndex, true, colors);
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ITerminal) {
super(container, 'cursor', zIndex, true, colors, terminal);
this._state = {
x: null,
y: null,
@@ -46,8 +46,8 @@ export class CursorRenderLayer extends BaseRenderLayer {
// TODO: Consider initial options? Maybe onOptionsChanged should be called at the end of open?
}
public resize(terminal: ITerminal, dim: IRenderDimensions): void {
super.resize(terminal, dim);
public resize(dim: IRenderDimensions): void {
super.resize(dim);
// Resizing the canvas discards the contents of the canvas so clear state
this._state = {
x: null,
@@ -58,35 +58,35 @@ export class CursorRenderLayer extends BaseRenderLayer {
};
}
public reset(terminal: ITerminal): void {
public reset(): void {
this._clearCursor();
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.dispose();
this._cursorBlinkStateManager = null;
this.onOptionsChanged(terminal);
this.onOptionsChanged();
}
}
public onBlur(terminal: ITerminal): void {
public onBlur(): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.pause();
}
terminal.refresh(terminal.buffer.y, terminal.buffer.y);
this._terminal.refresh(this._terminal.buffer.y, this._terminal.buffer.y);
}
public onFocus(terminal: ITerminal): void {
public onFocus(): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.resume(terminal);
this._cursorBlinkStateManager.resume(this._terminal);
} else {
terminal.refresh(terminal.buffer.y, terminal.buffer.y);
this._terminal.refresh(this._terminal.buffer.y, this._terminal.buffer.y);
}
}
public onOptionsChanged(terminal: ITerminal): void {
if (terminal.options.cursorBlink) {
public onOptionsChanged(): void {
if (this._terminal.options.cursorBlink) {
if (!this._cursorBlinkStateManager) {
this._cursorBlinkStateManager = new CursorBlinkStateManager(terminal, () => {
this._render(terminal, true);
this._cursorBlinkStateManager = new CursorBlinkStateManager(this._terminal, () => {
this._render(true);
});
}
} else {
@@ -96,55 +96,55 @@ export class CursorRenderLayer extends BaseRenderLayer {
}
// Request a refresh from the terminal as management of rendering is being
// moved back to the terminal
terminal.refresh(terminal.buffer.y, terminal.buffer.y);
this._terminal.refresh(this._terminal.buffer.y, this._terminal.buffer.y);
}
}
public onCursorMove(terminal: ITerminal): void {
public onCursorMove(): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.restartBlinkAnimation(terminal);
this._cursorBlinkStateManager.restartBlinkAnimation(this._terminal);
}
}
public onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void {
public onGridChanged(startRow: number, endRow: number): void {
if (!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isPaused) {
this._render(terminal, false);
this._render(false);
} else {
this._cursorBlinkStateManager.restartBlinkAnimation(terminal);
this._cursorBlinkStateManager.restartBlinkAnimation(this._terminal);
}
}
private _render(terminal: ITerminal, triggeredByAnimationFrame: boolean): void {
private _render(triggeredByAnimationFrame: boolean): void {
// Don't draw the cursor if it's hidden
if (!terminal.cursorState || terminal.cursorHidden) {
if (!this._terminal.cursorState || this._terminal.cursorHidden) {
this._clearCursor();
return;
}
const cursorY = terminal.buffer.ybase + terminal.buffer.y;
const viewportRelativeCursorY = cursorY - terminal.buffer.ydisp;
const cursorY = this._terminal.buffer.ybase + this._terminal.buffer.y;
const viewportRelativeCursorY = cursorY - this._terminal.buffer.ydisp;
// Don't draw the cursor if it's off-screen
if (viewportRelativeCursorY < 0 || viewportRelativeCursorY >= terminal.rows) {
if (viewportRelativeCursorY < 0 || viewportRelativeCursorY >= this._terminal.rows) {
this._clearCursor();
return;
}
terminal.buffer.lines.get(cursorY).loadCell(terminal.buffer.x, this._cell);
this._terminal.buffer.lines.get(cursorY).loadCell(this._terminal.buffer.x, this._cell);
if (this._cell.content === undefined) {
return;
}
if (!terminal.isFocused) {
if (!this._terminal.isFocused) {
this._clearCursor();
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._renderBlurCursor(terminal, terminal.buffer.x, viewportRelativeCursorY, this._cell);
this._renderBlurCursor(this._terminal.buffer.x, viewportRelativeCursorY, this._cell);
this._ctx.restore();
this._state.x = terminal.buffer.x;
this._state.x = this._terminal.buffer.x;
this._state.y = viewportRelativeCursorY;
this._state.isFocused = false;
this._state.style = terminal.options.cursorStyle;
this._state.style = this._terminal.options.cursorStyle;
this._state.width = this._cell.getWidth();
return;
}
@@ -157,10 +157,10 @@ export class CursorRenderLayer extends BaseRenderLayer {
if (this._state) {
// The cursor is already in the correct spot, don't redraw
if (this._state.x === terminal.buffer.x &&
if (this._state.x === this._terminal.buffer.x &&
this._state.y === viewportRelativeCursorY &&
this._state.isFocused === terminal.isFocused &&
this._state.style === terminal.options.cursorStyle &&
this._state.isFocused === this._terminal.isFocused &&
this._state.style === this._terminal.options.cursorStyle &&
this._state.width === this._cell.getWidth()) {
return;
}
@@ -168,13 +168,13 @@ export class CursorRenderLayer extends BaseRenderLayer {
}
this._ctx.save();
this._cursorRenderers[terminal.options.cursorStyle || 'block'](terminal, terminal.buffer.x, viewportRelativeCursorY, this._cell);
this._cursorRenderers[this._terminal.options.cursorStyle || 'block'](this._terminal.buffer.x, viewportRelativeCursorY, this._cell);
this._ctx.restore();
this._state.x = terminal.buffer.x;
this._state.x = this._terminal.buffer.x;
this._state.y = viewportRelativeCursorY;
this._state.isFocused = false;
this._state.style = terminal.options.cursorStyle;
this._state.style = this._terminal.options.cursorStyle;
this._state.width = this._cell.getWidth();
}
@@ -191,30 +191,30 @@ export class CursorRenderLayer extends BaseRenderLayer {
}
}
private _renderBarCursor(terminal: ITerminal, x: number, y: number, cell: ICellData): void {
private _renderBarCursor(x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._fillLeftLineAtCell(x, y);
this._ctx.restore();
}
private _renderBlockCursor(terminal: ITerminal, x: number, y: number, cell: ICellData): void {
private _renderBlockCursor(x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._fillCells(x, y, cell.getWidth(), 1);
this._ctx.fillStyle = this._colors.cursorAccent.css;
this._fillCharTrueColor(terminal, cell, x, y);
this._fillCharTrueColor(cell, x, y);
this._ctx.restore();
}
private _renderUnderlineCursor(terminal: ITerminal, x: number, y: number, cell: ICellData): void {
private _renderUnderlineCursor(x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._fillBottomLineAtCells(x, y);
this._ctx.restore();
}
private _renderBlurCursor(terminal: ITerminal, x: number, y: number, cell: ICellData): void {
private _renderBlurCursor(x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.strokeStyle = this._colors.cursor.css;
this._strokeRectAtCell(x, y, cell.getWidth(), 1);
+6 -6
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { ITerminal, ILinkifierAccessor } from '../Types';
import { ITerminal } from '../Types';
import { IRenderDimensions } from 'browser/renderer/Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
@@ -13,19 +13,19 @@ import { IColorSet, ILinkifierEvent } from 'browser/Types';
export class LinkRenderLayer extends BaseRenderLayer {
private _state: ILinkifierEvent = null;
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) {
super(container, 'link', zIndex, true, colors);
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ITerminal) {
super(container, 'link', zIndex, true, colors, terminal);
terminal.linkifier.onLinkHover(e => this._onLinkHover(e));
terminal.linkifier.onLinkLeave(e => this._onLinkLeave(e));
}
public resize(terminal: ITerminal, dim: IRenderDimensions): void {
super.resize(terminal, dim);
public resize(dim: IRenderDimensions): void {
super.resize(dim);
// Resizing the canvas discards the contents of the canvas so clear state
this._state = null;
}
public reset(terminal: ITerminal): void {
public reset(): void {
this._clearCurrentLink();
}
+13 -13
View File
@@ -34,10 +34,10 @@ export class Renderer extends Disposable implements IRenderer {
this._characterJoinerRegistry = new CharacterJoinerRegistry(bufferService);
this._renderLayers = [
new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency),
new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors),
new TextRenderLayer(this._terminal.screenElement, 0, this._colors, this._characterJoinerRegistry, allowTransparency, this._terminal),
new SelectionRenderLayer(this._terminal.screenElement, 1, this._colors, this._terminal),
new LinkRenderLayer(this._terminal.screenElement, 2, this._colors, this._terminal),
new CursorRenderLayer(this._terminal.screenElement, 3, this._colors)
new CursorRenderLayer(this._terminal.screenElement, 3, this._colors, this._terminal)
];
this.dimensions = {
scaledCharWidth: null,
@@ -77,8 +77,8 @@ export class Renderer 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._colors);
l.reset();
});
}
@@ -87,7 +87,7 @@ export class Renderer extends Disposable implements IRenderer {
this._updateDimensions();
// Resize all render layers
this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions));
this._renderLayers.forEach(l => l.resize(this.dimensions));
// Resize the screen
this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth}px`;
@@ -99,27 +99,27 @@ export class Renderer extends Disposable implements IRenderer {
}
public onBlur(): void {
this._runOperation(l => l.onBlur(this._terminal));
this._runOperation(l => l.onBlur());
}
public onFocus(): void {
this._runOperation(l => l.onFocus(this._terminal));
this._runOperation(l => l.onFocus());
}
public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {
this._runOperation(l => l.onSelectionChanged(this._terminal, start, end, columnSelectMode));
this._runOperation(l => l.onSelectionChanged(start, end, columnSelectMode));
}
public onCursorMove(): void {
this._runOperation(l => l.onCursorMove(this._terminal));
this._runOperation(l => l.onCursorMove());
}
public onOptionsChanged(): void {
this._runOperation(l => l.onOptionsChanged(this._terminal));
this._runOperation(l => l.onOptionsChanged());
}
public clear(): void {
this._runOperation(l => l.reset(this._terminal));
this._runOperation(l => l.reset());
}
private _runOperation(operation: (layer: IRenderLayer) => void): void {
@@ -131,7 +131,7 @@ export class Renderer extends Disposable implements IRenderer {
* necessary before queueing up the next one.
*/
public renderRows(start: number, end: number): void {
this._renderLayers.forEach(l => l.onGridChanged(this._terminal, start, end));
this._renderLayers.forEach(l => l.onGridChanged(start, end));
}
/**
+15 -15
View File
@@ -18,8 +18,8 @@ interface ISelectionState {
export class SelectionRenderLayer extends BaseRenderLayer {
private _state: ISelectionState;
constructor(container: HTMLElement, zIndex: number, colors: IColorSet) {
super(container, 'selection', zIndex, true, colors);
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ITerminal) {
super(container, 'selection', zIndex, true, colors, terminal);
this._clearState();
}
@@ -32,22 +32,22 @@ export class SelectionRenderLayer extends BaseRenderLayer {
};
}
public resize(terminal: ITerminal, dim: IRenderDimensions): void {
super.resize(terminal, dim);
public resize(dim: IRenderDimensions): void {
super.resize(dim);
// Resizing the canvas discards the contents of the canvas so clear state
this._clearState();
}
public reset(terminal: ITerminal): void {
public reset(): void {
if (this._state.start && this._state.end) {
this._clearState();
this._clearAll();
}
}
public onSelectionChanged(terminal: ITerminal, start: [number, number], end: [number, number], columnSelectMode: boolean): void {
public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void {
// Selection has not changed
if (!this._didStateChange(start, end, columnSelectMode, terminal.buffer.ydisp)) {
if (!this._didStateChange(start, end, columnSelectMode, this._terminal.buffer.ydisp)) {
return;
}
@@ -61,13 +61,13 @@ export class SelectionRenderLayer extends BaseRenderLayer {
}
// Translate from buffer position to viewport position
const viewportStartRow = start[1] - terminal.buffer.ydisp;
const viewportEndRow = end[1] - terminal.buffer.ydisp;
const viewportStartRow = start[1] - this._terminal.buffer.ydisp;
const viewportEndRow = end[1] - this._terminal.buffer.ydisp;
const viewportCappedStartRow = Math.max(viewportStartRow, 0);
const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1);
const viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1);
// No need to draw the selection
if (viewportCappedStartRow >= terminal.rows || viewportCappedEndRow < 0) {
if (viewportCappedStartRow >= this._terminal.rows || viewportCappedEndRow < 0) {
return;
}
@@ -81,17 +81,17 @@ export class SelectionRenderLayer extends BaseRenderLayer {
} else {
// Draw first row
const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
const startRowEndCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : terminal.cols;
const startRowEndCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
this._fillCells(startCol, viewportCappedStartRow, startRowEndCol - startCol, 1);
// Draw middle rows
const middleRowsCount = Math.max(viewportCappedEndRow - viewportCappedStartRow - 1, 0);
this._fillCells(0, viewportCappedStartRow + 1, terminal.cols, middleRowsCount);
this._fillCells(0, viewportCappedStartRow + 1, this._terminal.cols, middleRowsCount);
// Draw final row
if (viewportCappedStartRow !== viewportCappedEndRow) {
// Only draw viewportEndRow if it's not the same as viewportStartRow
const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : terminal.cols;
const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols;
this._fillCells(0, viewportCappedEndRow, endCol, 1);
}
}
@@ -100,7 +100,7 @@ export class SelectionRenderLayer extends BaseRenderLayer {
this._state.start = [start[0], start[1]];
this._state.end = [end[0], end[1]];
this._state.columnSelectMode = columnSelectMode;
this._state.ydisp = terminal.buffer.ydisp;
this._state.ydisp = this._terminal.buffer.ydisp;
}
private _didStateChange(start: [number, number], end: [number, number], columnSelectMode: boolean, ydisp: number): boolean {
+23 -24
View File
@@ -29,17 +29,17 @@ export class TextRenderLayer extends BaseRenderLayer {
private _characterJoinerRegistry: ICharacterJoinerRegistry;
private _workCell = new CellData();
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, characterJoinerRegistry: ICharacterJoinerRegistry, alpha: boolean) {
super(container, 'text', zIndex, alpha, colors);
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, characterJoinerRegistry: ICharacterJoinerRegistry, alpha: boolean, terminal: ITerminal) {
super(container, 'text', zIndex, alpha, colors, terminal);
this._state = new GridCache<CharData>();
this._characterJoinerRegistry = characterJoinerRegistry;
}
public resize(terminal: ITerminal, dim: IRenderDimensions): void {
super.resize(terminal, dim);
public resize(dim: IRenderDimensions): void {
super.resize(dim);
// Clear the character width cache if the font or width has changed
const terminalFont = this._getFont(terminal, false, false);
const terminalFont = this._getFont(false, false);
if (this._characterWidth !== dim.scaledCharWidth || this._characterFont !== terminalFont) {
this._characterWidth = dim.scaledCharWidth;
this._characterFont = terminalFont;
@@ -47,16 +47,15 @@ export class TextRenderLayer extends BaseRenderLayer {
}
// Resizing the canvas discards the contents of the canvas so clear state
this._state.clear();
this._state.resize(terminal.cols, terminal.rows);
this._state.resize(this._terminal.cols, this._terminal.rows);
}
public reset(terminal: ITerminal): void {
public reset(): void {
this._state.clear();
this._clearAll();
}
private _forEachCell(
terminal: ITerminal,
firstRow: number,
lastRow: number,
joinerRegistry: ICharacterJoinerRegistry | null,
@@ -67,10 +66,10 @@ export class TextRenderLayer extends BaseRenderLayer {
) => void
): void {
for (let y = firstRow; y <= lastRow; y++) {
const row = y + terminal.buffer.ydisp;
const line = terminal.buffer.lines.get(row);
const row = y + this._terminal.buffer.ydisp;
const line = this._terminal.buffer.lines.get(row);
const joinedRanges = joinerRegistry ? joinerRegistry.getJoinedCharacters(row) : [];
for (let x = 0; x < terminal.cols; x++) {
for (let x = 0; x < this._terminal.cols; x++) {
line.loadCell(x, this._workCell);
let cell = this._workCell;
@@ -143,16 +142,16 @@ export class TextRenderLayer extends BaseRenderLayer {
* Draws the background for a specified range of columns. Tries to batch adjacent cells of the
* same color together to reduce draw calls.
*/
private _drawBackground(terminal: ITerminal, firstRow: number, lastRow: number): void {
private _drawBackground(firstRow: number, lastRow: number): void {
const ctx = this._ctx;
const cols = terminal.cols;
const cols = this._terminal.cols;
let startX: number = 0;
let startY: number = 0;
let prevFillStyle: string | null = null;
ctx.save();
this._forEachCell(terminal, firstRow, lastRow, null, (cell, x, y) => {
this._forEachCell(firstRow, lastRow, null, (cell, x, y) => {
// libvte and xterm both draw the background (but not foreground) of invisible characters,
// so we should too.
let nextFillStyle = null; // null represents default background color
@@ -202,12 +201,12 @@ export class TextRenderLayer extends BaseRenderLayer {
ctx.restore();
}
private _drawForeground(terminal: ITerminal, firstRow: number, lastRow: number): void {
this._forEachCell(terminal, firstRow, lastRow, this._characterJoinerRegistry, (cell, x, y) => {
private _drawForeground(firstRow: number, lastRow: number): void {
this._forEachCell(firstRow, lastRow, this._characterJoinerRegistry, (cell, x, y) => {
if (cell.isInvisible()) {
return;
}
this._drawChars(terminal, cell, x, y);
this._drawChars(cell, x, y);
if (cell.isUnderline()) {
this._ctx.save();
@@ -226,7 +225,7 @@ export class TextRenderLayer extends BaseRenderLayer {
this._ctx.fillStyle = `rgb(${AttributeData.toColorRGB(cell.getFgColor()).join(',')})`;
} else {
let fg = cell.getFgColor();
if (terminal.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
if (this._terminal.options.drawBoldTextInBrightColors && cell.isBold() && fg < 8) {
fg += 8;
}
this._ctx.fillStyle = this._colors.ansi[fg].css;
@@ -239,7 +238,7 @@ export class TextRenderLayer extends BaseRenderLayer {
});
}
public onGridChanged(terminal: ITerminal, firstRow: number, lastRow: number): void {
public onGridChanged(firstRow: number, lastRow: number): void {
// Resize has not been called yet
if (this._state.cache.length === 0) {
return;
@@ -249,13 +248,13 @@ export class TextRenderLayer extends BaseRenderLayer {
this._charAtlas.beginFrame();
}
this._clearCells(0, firstRow, terminal.cols, lastRow - firstRow + 1);
this._drawBackground(terminal, firstRow, lastRow);
this._drawForeground(terminal, firstRow, lastRow);
this._clearCells(0, firstRow, this._terminal.cols, lastRow - firstRow + 1);
this._drawBackground(firstRow, lastRow);
this._drawForeground(firstRow, lastRow);
}
public onOptionsChanged(terminal: ITerminal): void {
this._setTransparency(terminal, terminal.options.allowTransparency);
public onOptionsChanged(): void {
this._setTransparency(this._terminal.options.allowTransparency);
}
/**
+9 -9
View File
@@ -12,38 +12,38 @@ export interface IRenderLayer extends IDisposable {
/**
* Called when the terminal loses focus.
*/
onBlur(terminal: ITerminal): void;
onBlur(): void;
/**
* * Called when the terminal gets focus.
*/
onFocus(terminal: ITerminal): void;
onFocus(): void;
/**
* Called when the cursor is moved.
*/
onCursorMove(terminal: ITerminal): void;
onCursorMove(): void;
/**
* Called when options change.
*/
onOptionsChanged(terminal: ITerminal): void;
onOptionsChanged(): void;
/**
* Called when the theme changes.
*/
setColors(terminal: ITerminal, colorSet: IColorSet): void;
setColors(colorSet: IColorSet): void;
/**
* Called when the data in the grid has changed (or needs to be rendered
* again).
*/
onGridChanged(terminal: ITerminal, startRow: number, endRow: number): void;
onGridChanged(startRow: number, endRow: number): void;
/**
* Calls when the selection changes.
*/
onSelectionChanged(terminal: ITerminal, start: [number, number], end: [number, number], columnSelectMode: boolean): void;
onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void;
/**
* Registers a handler to join characters to render as a group
@@ -58,10 +58,10 @@ export interface IRenderLayer extends IDisposable {
/**
* Resize the render layer.
*/
resize(terminal: ITerminal, dim: IRenderDimensions): void;
resize(dim: IRenderDimensions): void;
/**
* Clear the state of the render layer.
*/
reset(terminal: ITerminal): void;
reset(): void;
}