mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
first try to optimize read access
This commit is contained in:
+42
-2
@@ -7,7 +7,6 @@ import { NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, CHAR_DATA_CHAR_INDEX,
|
||||
import { stringFromCodePoint } from './core/input/TextDecoder';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* buffer memory layout:
|
||||
*
|
||||
@@ -37,7 +36,7 @@ const enum Cell {
|
||||
/**
|
||||
* Bitmasks and helper for accessing data in `content`.
|
||||
*/
|
||||
const enum Content {
|
||||
export const enum Content {
|
||||
/**
|
||||
* bit 1..21 codepoint, max allowed in UTF32 is 0x10FFFF (21 bits taken)
|
||||
* read: `codepoint = content & Content.codepointMask;`
|
||||
@@ -77,6 +76,25 @@ const enum Content {
|
||||
WIDTH_SHIFT = 22
|
||||
}
|
||||
|
||||
export class CellData {
|
||||
public content: number = 0;
|
||||
public fg: number = 0;
|
||||
public bg: number = 0;
|
||||
public combinedData: string = '';
|
||||
public get combined(): number {
|
||||
return this.content & Content.IS_COMBINED;
|
||||
}
|
||||
public get width(): number {
|
||||
return this.content >> Content.WIDTH_SHIFT;
|
||||
}
|
||||
public get chars(): string {
|
||||
return (this.content & Content.IS_COMBINED) ? this.combinedData : stringFromCodePoint(this.content & Content.CODEPOINT_MASK);
|
||||
}
|
||||
public get code(): number {
|
||||
return ((this.combined) ? this.combinedData.charCodeAt(this.combinedData.length - 1) : this.content & Content.CODEPOINT_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Typed array based bufferline implementation.
|
||||
*/
|
||||
@@ -123,6 +141,28 @@ export class BufferLine implements IBufferLine {
|
||||
}
|
||||
}
|
||||
|
||||
public loadCell(index: number, cell: CellData): CellData {
|
||||
cell.content = this._data[index * CELL_SIZE + Cell.CONTENT];
|
||||
cell.fg = this._data[index * CELL_SIZE + Cell.FG];
|
||||
cell.bg = this._data[index * CELL_SIZE + Cell.BG];
|
||||
if (cell.content & Content.IS_COMBINED) {
|
||||
cell.combinedData = this._combined[index];
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
public setCell(index: number, cell: CellData): void {
|
||||
if (cell.content & Content.IS_COMBINED) {
|
||||
this._combined[index] = cell.combinedData;
|
||||
// we also need to clear and set codepoint to index
|
||||
cell.content &= ~Content.CODEPOINT_MASK;
|
||||
cell.content |= index;
|
||||
}
|
||||
this._data[index * CELL_SIZE + Cell.CONTENT] = cell.content;
|
||||
this._data[index * CELL_SIZE + Cell.FG] = cell.fg;
|
||||
this._data[index * CELL_SIZE + Cell.BG] = cell.bg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cell data from input handler.
|
||||
* Since the input handler see the incoming chars as UTF32 codepoints,
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { CHAR_DATA_ATTR_INDEX, CHAR_DATA_CODE_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../Buffer';
|
||||
import { CHAR_DATA_CODE_INDEX, NULL_CELL_CODE, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../Buffer';
|
||||
import { FLAGS, IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
|
||||
import { CharData, ITerminal } from '../Types';
|
||||
import { INVERTED_DEFAULT_COLOR, DEFAULT_COLOR } from './atlas/Types';
|
||||
import { GridCache } from './GridCache';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { is256Color } from './atlas/CharAtlasUtils';
|
||||
import { CellData } from '../BufferLine';
|
||||
|
||||
/**
|
||||
* This CharData looks like a null character, which will forc a clear and render
|
||||
@@ -24,6 +25,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
private _characterFont: string;
|
||||
private _characterOverlapCache: { [key: string]: boolean } = {};
|
||||
private _characterJoinerRegistry: ICharacterJoinerRegistry;
|
||||
private _cell = new CellData();
|
||||
|
||||
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, characterJoinerRegistry: ICharacterJoinerRegistry, alpha: boolean) {
|
||||
super(container, 'text', zIndex, alpha, colors);
|
||||
@@ -72,14 +74,14 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
const line = terminal.buffer.lines.get(row);
|
||||
const joinedRanges = joinerRegistry ? joinerRegistry.getJoinedCharacters(row) : [];
|
||||
for (let x = 0; x < terminal.cols; x++) {
|
||||
const charData = line.get(x);
|
||||
let code: number = <number>charData[CHAR_DATA_CODE_INDEX] || WHITESPACE_CELL_CODE;
|
||||
(line as any).loadCell(x, this._cell);
|
||||
let code: number = this._cell.code || WHITESPACE_CELL_CODE;
|
||||
|
||||
// Can either represent character(s) for a single cell or multiple cells
|
||||
// if indicated by a character joiner.
|
||||
let chars: string = charData[CHAR_DATA_CHAR_INDEX] || WHITESPACE_CELL_CHAR;
|
||||
const attr: number = charData[CHAR_DATA_ATTR_INDEX];
|
||||
let width: number = charData[CHAR_DATA_WIDTH_INDEX];
|
||||
let chars = this._cell.chars || WHITESPACE_CELL_CHAR;
|
||||
const attr = this._cell.fg;
|
||||
let width = this._cell.width;
|
||||
|
||||
// If true, indicates that the current character(s) to draw were joined.
|
||||
let isJoined = false;
|
||||
@@ -117,7 +119,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
// right is a space, take ownership of the cell to the right. We skip
|
||||
// this check for joined characters because their rendering likely won't
|
||||
// yield the same result as rendering the last character individually.
|
||||
if (!isJoined && this._isOverlapping(charData)) {
|
||||
if (!isJoined && this._isOverlapping(chars, width, code)) {
|
||||
// If the character is overlapping, we want to force a re-render on every
|
||||
// frame. This is specifically to work around the case where two
|
||||
// overlaping chars `a` and `b` are adjacent, the cursor is moved to b and a
|
||||
@@ -271,21 +273,19 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
/**
|
||||
* Whether a character is overlapping to the next cell.
|
||||
*/
|
||||
private _isOverlapping(charData: CharData): boolean {
|
||||
private _isOverlapping(char: string, width: number, code: number): boolean {
|
||||
// Only single cell characters can be overlapping, rendering issues can
|
||||
// occur without this check
|
||||
if (charData[CHAR_DATA_WIDTH_INDEX] !== 1) {
|
||||
if (width !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We assume that any ascii character will not overlap
|
||||
const code = charData[CHAR_DATA_CODE_INDEX];
|
||||
if (code < 256) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deliver from cache if available
|
||||
const char = charData[CHAR_DATA_CHAR_INDEX];
|
||||
if (this._characterOverlapCache.hasOwnProperty(char)) {
|
||||
return this._characterOverlapCache[char];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user