Merge remote-tracking branch 'origin/master' into webgl2
This commit is contained in:
@@ -5,13 +5,13 @@
|
||||
|
||||
import { IRenderLayer, IRenderDimensions } from './Types';
|
||||
import { ITerminal } from '../Types';
|
||||
import { ICellData } from '../core/Types';
|
||||
import { DEFAULT_COLOR } from '../common/Types';
|
||||
import { ICellData } from 'core/Types';
|
||||
import { DEFAULT_COLOR } from 'common/Types';
|
||||
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier } from './atlas/Types';
|
||||
import BaseCharAtlas from './atlas/BaseCharAtlas';
|
||||
import { BaseCharAtlas } from './atlas/BaseCharAtlas';
|
||||
import { acquireCharAtlas } from './atlas/CharAtlasCache';
|
||||
import { CellData, AttributeData, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from '../core/buffer/BufferLine';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { CellData, AttributeData, WHITESPACE_CELL_CHAR, WHITESPACE_CELL_CODE } from 'core/buffer/BufferLine';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
private _canvas: HTMLCanvasElement;
|
||||
@@ -288,7 +288,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
this._currentGlyphIdentifier.code = cell.getCode() || WHITESPACE_CELL_CODE;
|
||||
this._currentGlyphIdentifier.bg = bg;
|
||||
this._currentGlyphIdentifier.fg = fg;
|
||||
this._currentGlyphIdentifier.bold = cell.isBold() && terminal.options.enableBold;
|
||||
this._currentGlyphIdentifier.bold = !!cell.isBold();
|
||||
this._currentGlyphIdentifier.dim = !!cell.isDim();
|
||||
this._currentGlyphIdentifier.italic = !!cell.isItalic();
|
||||
const atlasDidDraw = this._charAtlas && this._charAtlas.draw(
|
||||
@@ -316,7 +316,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
*/
|
||||
private _drawUncachedChars(terminal: ITerminal, cell: ICellData, x: number, y: number): void {
|
||||
this._ctx.save();
|
||||
this._ctx.font = this._getFont(terminal, cell.isBold() && terminal.options.enableBold, !!cell.isItalic());
|
||||
this._ctx.font = this._getFont(terminal, !!cell.isBold(), !!cell.isItalic());
|
||||
this._ctx.textBaseline = 'middle';
|
||||
|
||||
if (cell.isInverse()) {
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { MockTerminal, MockBuffer } from '../TestUtils.test';
|
||||
import { CircularList } from '../common/CircularList';
|
||||
import { CircularList } from 'common/CircularList';
|
||||
|
||||
import { ICharacterJoinerRegistry } from './Types';
|
||||
import { CharacterJoinerRegistry } from './CharacterJoinerRegistry';
|
||||
import { BufferLine, CellData } from '../core/buffer/BufferLine';
|
||||
import { IBufferLine } from '../core/Types';
|
||||
import { BufferLine, CellData } from 'core/buffer/BufferLine';
|
||||
import { IBufferLine } from 'core/Types';
|
||||
|
||||
describe('CharacterJoinerRegistry', () => {
|
||||
let registry: ICharacterJoinerRegistry;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*/
|
||||
|
||||
import { ITerminal } from '../Types';
|
||||
import { IBufferLine, ICellData, CharData } from '../core/Types';
|
||||
import { IBufferLine, ICellData, CharData } from 'core/Types';
|
||||
import { ICharacterJoinerRegistry, ICharacterJoiner } from './Types';
|
||||
import { CellData, Content, AttributeData, WHITESPACE_CELL_CHAR } from '../core/buffer/BufferLine';
|
||||
import { CellData, Content, AttributeData, WHITESPACE_CELL_CHAR } from 'core/buffer/BufferLine';
|
||||
|
||||
export class JoinedCellData extends AttributeData implements ICellData {
|
||||
private _width: number;
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import { IRenderDimensions } from './Types';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { ITerminal } from '../Types';
|
||||
import { ICellData } from '../core/Types';
|
||||
import { CellData } from '../core/buffer/BufferLine';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { ICellData } from 'core/Types';
|
||||
import { CellData } from 'core/buffer/BufferLine';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
interface ICursorState {
|
||||
x: number;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IRenderDimensions } from './Types';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { INVERTED_DEFAULT_COLOR } from './atlas/Types';
|
||||
import { is256Color } from './atlas/CharAtlasUtils';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
export class LinkRenderLayer extends BaseRenderLayer {
|
||||
private _state: ILinkifierEvent = null;
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
*/
|
||||
|
||||
import { IRenderer, IRenderDimensions } from './Types';
|
||||
import { RenderDebouncer } from '../ui/RenderDebouncer';
|
||||
import { EventEmitter2, IEvent } from '../common/EventEmitter2';
|
||||
import { Disposable } from '../common/Lifecycle';
|
||||
import { ScreenDprMonitor } from '../ui/ScreenDprMonitor';
|
||||
import { addDisposableDomListener } from '../ui/Lifecycle';
|
||||
import { IColorSet } from '..//ui/Types';
|
||||
import { RenderDebouncer } from 'ui/RenderDebouncer';
|
||||
import { EventEmitter2, IEvent } from 'common/EventEmitter2';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { ScreenDprMonitor } from 'ui/ScreenDprMonitor';
|
||||
import { addDisposableDomListener } from 'ui/Lifecycle';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
import { CharacterJoinerHandler } from '../Types';
|
||||
|
||||
export class RenderCoordinator extends Disposable {
|
||||
|
||||
@@ -10,8 +10,8 @@ import { IRenderLayer, IRenderer, IRenderDimensions, ICharacterJoinerRegistry }
|
||||
import { ITerminal, CharacterJoinerHandler } from '../Types';
|
||||
import { LinkRenderLayer } from './LinkRenderLayer';
|
||||
import { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry';
|
||||
import { Disposable } from '../common/Lifecycle';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
export class Renderer extends Disposable implements IRenderer {
|
||||
private _renderLayers: IRenderLayer[];
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { ITerminal } from '../Types';
|
||||
import { IRenderDimensions } from './Types';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
interface ISelectionState {
|
||||
start: [number, number];
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
import { IRenderDimensions, ICharacterJoinerRegistry } from './Types';
|
||||
import { ITerminal } from '../Types';
|
||||
import { CharData, ICellData } from '../core/Types';
|
||||
import { CharData, ICellData } from 'core/Types';
|
||||
import { GridCache } from './GridCache';
|
||||
import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { CellData, AttributeData, Content, NULL_CELL_CODE } from '../core/buffer/BufferLine';
|
||||
import { CellData, AttributeData, Content, NULL_CELL_CODE } from 'core/buffer/BufferLine';
|
||||
import { JoinedCellData } from './CharacterJoinerRegistry';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
/**
|
||||
* This CharData looks like a null character, which will forc a clear and render
|
||||
@@ -205,6 +205,7 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
if (cell.isInvisible()) {
|
||||
return;
|
||||
}
|
||||
this.drawChars(terminal, cell, x, y);
|
||||
if (cell.isUnderline()) {
|
||||
this._ctx.save();
|
||||
|
||||
@@ -233,7 +234,6 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
this.fillBottomLineAtCells(x, y, cell.getWidth());
|
||||
this._ctx.restore();
|
||||
}
|
||||
this.drawChars(terminal, cell, x, y);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { ITerminal, CharacterJoinerHandler } from '../Types';
|
||||
import { IDisposable } from 'xterm';
|
||||
import { IColorSet } from '../ui/Types';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
/**
|
||||
* Flags used to render terminal text properly.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IGlyphIdentifier } from './Types';
|
||||
import { IDisposable } from 'xterm';
|
||||
|
||||
export default abstract class BaseCharAtlas implements IDisposable {
|
||||
export abstract class BaseCharAtlas implements IDisposable {
|
||||
private _didWarmUp: boolean = false;
|
||||
|
||||
public dispose(): void { }
|
||||
|
||||
@@ -5,18 +5,10 @@
|
||||
|
||||
import { ITerminal } from '../../Types';
|
||||
import { generateConfig, configEquals } from './CharAtlasUtils';
|
||||
import BaseCharAtlas from './BaseCharAtlas';
|
||||
import DynamicCharAtlas from './DynamicCharAtlas';
|
||||
import NoneCharAtlas from './NoneCharAtlas';
|
||||
import StaticCharAtlas from './StaticCharAtlas';
|
||||
import { BaseCharAtlas } from './BaseCharAtlas';
|
||||
import { DynamicCharAtlas } from './DynamicCharAtlas';
|
||||
import { ICharAtlasConfig } from './Types';
|
||||
import { IColorSet } from '../../ui/Types';
|
||||
|
||||
const charAtlasImplementations = {
|
||||
'none': NoneCharAtlas,
|
||||
'static': StaticCharAtlas,
|
||||
'dynamic': DynamicCharAtlas
|
||||
};
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
interface ICharAtlasCacheEntry {
|
||||
atlas: BaseCharAtlas;
|
||||
@@ -72,7 +64,7 @@ export function acquireCharAtlas(
|
||||
}
|
||||
|
||||
const newEntry: ICharAtlasCacheEntry = {
|
||||
atlas: new charAtlasImplementations[terminal.options.experimentalCharAtlas](
|
||||
atlas: new DynamicCharAtlas(
|
||||
document,
|
||||
newConfig
|
||||
),
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { FontWeight } from 'xterm';
|
||||
import { isFirefox, isSafari } from '../../common/Platform';
|
||||
import { ICharAtlasConfig, CHAR_ATLAS_CELL_SPACING } from './Types';
|
||||
import { IColor } from '../../ui/Types';
|
||||
|
||||
/**
|
||||
* Generates a char atlas.
|
||||
* @param context The window or worker context.
|
||||
* @param canvasFactory A function to generate a canvas with a width or height.
|
||||
* @param config The config for the new char atlas.
|
||||
*/
|
||||
export function generateStaticCharAtlasTexture(context: Window, canvasFactory: (width: number, height: number) => HTMLCanvasElement, config: ICharAtlasConfig): HTMLCanvasElement | Promise<ImageBitmap> {
|
||||
const cellWidth = config.scaledCharWidth + CHAR_ATLAS_CELL_SPACING;
|
||||
const cellHeight = config.scaledCharHeight + CHAR_ATLAS_CELL_SPACING;
|
||||
const canvas = canvasFactory(
|
||||
/*255 ascii chars*/255 * cellWidth,
|
||||
(/*default+default bold*/2 + /*0-15*/16 + /*0-15 bold*/16) * cellHeight
|
||||
);
|
||||
const ctx = canvas.getContext('2d', {alpha: config.allowTransparency});
|
||||
|
||||
ctx.fillStyle = config.colors.background.css;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = config.colors.foreground.css;
|
||||
ctx.font = getFont(config.fontWeight, config);
|
||||
ctx.textBaseline = 'middle';
|
||||
|
||||
// Default color
|
||||
for (let i = 0; i < 256; i++) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(i * cellWidth, 0, cellWidth, cellHeight);
|
||||
ctx.clip();
|
||||
ctx.fillText(String.fromCharCode(i), i * cellWidth, cellHeight / 2);
|
||||
ctx.restore();
|
||||
}
|
||||
// Default color bold
|
||||
ctx.save();
|
||||
ctx.font = getFont(config.fontWeightBold, config);
|
||||
for (let i = 0; i < 256; i++) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(i * cellWidth, cellHeight, cellWidth, cellHeight);
|
||||
ctx.clip();
|
||||
ctx.fillText(String.fromCharCode(i), i * cellWidth, cellHeight * 1.5);
|
||||
ctx.restore();
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
// Colors 0-15
|
||||
ctx.font = getFont(config.fontWeight, config);
|
||||
for (let colorIndex = 0; colorIndex < 16; colorIndex++) {
|
||||
const y = (colorIndex + 2) * cellHeight;
|
||||
// Draw ascii characters
|
||||
for (let i = 0; i < 256; i++) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(i * cellWidth, y, cellWidth, cellHeight);
|
||||
ctx.clip();
|
||||
ctx.fillStyle = config.colors.ansi[colorIndex].css;
|
||||
ctx.fillText(String.fromCharCode(i), i * cellWidth, y + cellHeight / 2);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
// Colors 0-15 bold
|
||||
ctx.font = getFont(config.fontWeightBold, config);
|
||||
for (let colorIndex = 0; colorIndex < 16; colorIndex++) {
|
||||
const y = (colorIndex + 2 + 16) * cellHeight;
|
||||
// Draw ascii characters
|
||||
for (let i = 0; i < 256; i++) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(i * cellWidth, y, cellWidth, cellHeight);
|
||||
ctx.clip();
|
||||
ctx.fillStyle = config.colors.ansi[colorIndex].css;
|
||||
ctx.fillText(String.fromCharCode(i), i * cellWidth, y + cellHeight / 2);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
// Support is patchy for createImageBitmap at the moment, pass a canvas back
|
||||
// if support is lacking as drawImage works there too. Firefox is also
|
||||
// included here as ImageBitmap appears both buggy and has horrible
|
||||
// performance (tested on v55).
|
||||
if (!('createImageBitmap' in context) || isFirefox || isSafari) {
|
||||
// Don't attempt to clear background colors if createImageBitmap is not supported
|
||||
return canvas;
|
||||
}
|
||||
|
||||
const charAtlasImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// Remove the background color from the image so characters may overlap
|
||||
clearColor(charAtlasImageData, config.colors.background);
|
||||
|
||||
return context.createImageBitmap(charAtlasImageData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a partiicular rgb color in an ImageData completely transparent.
|
||||
* @returns True if the result is "empty", meaning all pixels are fully transparent.
|
||||
*/
|
||||
export function clearColor(imageData: ImageData, color: IColor): boolean {
|
||||
let isEmpty = true;
|
||||
const r = color.rgba >>> 24;
|
||||
const g = color.rgba >>> 16 & 0xFF;
|
||||
const b = color.rgba >>> 8 & 0xFF;
|
||||
for (let offset = 0; offset < imageData.data.length; offset += 4) {
|
||||
if (imageData.data[offset] === r &&
|
||||
imageData.data[offset + 1] === g &&
|
||||
imageData.data[offset + 2] === b) {
|
||||
imageData.data[offset + 3] = 0;
|
||||
} else {
|
||||
isEmpty = false;
|
||||
}
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
function getFont(fontWeight: FontWeight, config: ICharAtlasConfig): string {
|
||||
return `${fontWeight} ${config.fontSize * config.devicePixelRatio}px ${config.fontFamily}`;
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
import { ITerminal } from '../../Types';
|
||||
import { ICharAtlasConfig } from './Types';
|
||||
import { DEFAULT_COLOR } from '../../common/Types';
|
||||
import { IColorSet } from '../../ui/Types';
|
||||
import { DEFAULT_COLOR } from 'common/Types';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {
|
||||
// null out some fields that don't matter
|
||||
@@ -21,7 +21,6 @@ export function generateConfig(scaledCharWidth: number, scaledCharHeight: number
|
||||
ansi: colors.ansi.slice(0, 16)
|
||||
};
|
||||
return {
|
||||
type: terminal.options.experimentalCharAtlas,
|
||||
devicePixelRatio: window.devicePixelRatio,
|
||||
scaledCharWidth,
|
||||
scaledCharHeight,
|
||||
@@ -40,8 +39,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 &&
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
*/
|
||||
|
||||
import { DIM_OPACITY, IGlyphIdentifier, INVERTED_DEFAULT_COLOR, ICharAtlasConfig } from './Types';
|
||||
import BaseCharAtlas from './BaseCharAtlas';
|
||||
import { DEFAULT_ANSI_COLORS } from '../../ui/ColorManager';
|
||||
import { clearColor } from './CharAtlasGenerator';
|
||||
import LRUMap from './LRUMap';
|
||||
import { isFirefox, isSafari } from '../../common/Platform';
|
||||
import { IColor } from '../../ui/Types';
|
||||
import { BaseCharAtlas } from './BaseCharAtlas';
|
||||
import { DEFAULT_ANSI_COLORS } from 'ui/ColorManager';
|
||||
import { LRUMap } from './LRUMap';
|
||||
import { isFirefox, isSafari } from 'common/Platform';
|
||||
import { IColor } from 'ui/Types';
|
||||
|
||||
// In practice we're probably never going to exhaust a texture this large. For debugging purposes,
|
||||
// however, it can be useful to set this to a really tiny value, to verify that LRU eviction works.
|
||||
@@ -54,7 +53,7 @@ export function getGlyphCacheKey(glyph: IGlyphIdentifier): number {
|
||||
return glyph.code << 21 | glyph.bg << 12 | glyph.fg << 3 | (glyph.bold ? 0 : 4) + (glyph.dim ? 0 : 2) + (glyph.italic ? 0 : 1);
|
||||
}
|
||||
|
||||
export default class DynamicCharAtlas extends BaseCharAtlas {
|
||||
export class DynamicCharAtlas extends BaseCharAtlas {
|
||||
// An ordered map that we're using to keep track of where each glyph is in the atlas texture.
|
||||
// It's ordered so that we can determine when to remove the old entries.
|
||||
private _cacheMap: LRUMap<IGlyphCacheValue>;
|
||||
@@ -328,3 +327,41 @@ export default class DynamicCharAtlas extends BaseCharAtlas {
|
||||
this._bitmapCommitTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
// This is used for debugging the renderer, just swap out `new DynamicCharAtlas` with
|
||||
// `new NoneCharAtlas`.
|
||||
export class NoneCharAtlas extends BaseCharAtlas {
|
||||
constructor(document: Document, config: ICharAtlasConfig) {
|
||||
super();
|
||||
}
|
||||
|
||||
public draw(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
glyph: IGlyphIdentifier,
|
||||
x: number,
|
||||
y: number
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a partiicular rgb color in an ImageData completely transparent.
|
||||
* @returns True if the result is "empty", meaning all pixels are fully transparent.
|
||||
*/
|
||||
function clearColor(imageData: ImageData, color: IColor): boolean {
|
||||
let isEmpty = true;
|
||||
const r = color.rgba >>> 24;
|
||||
const g = color.rgba >>> 16 & 0xFF;
|
||||
const b = color.rgba >>> 8 & 0xFF;
|
||||
for (let offset = 0; offset < imageData.data.length; offset += 4) {
|
||||
if (imageData.data[offset] === r &&
|
||||
imageData.data[offset + 1] === g &&
|
||||
imageData.data[offset + 2] === b) {
|
||||
imageData.data[offset + 3] = 0;
|
||||
} else {
|
||||
isEmpty = false;
|
||||
}
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { assert } from 'chai';
|
||||
import LRUMap from './LRUMap';
|
||||
import { LRUMap } from './LRUMap';
|
||||
|
||||
describe('LRUMap', () => {
|
||||
it('can be used to store and retrieve values', () => {
|
||||
|
||||
@@ -10,7 +10,7 @@ interface ILinkedListNode<T> {
|
||||
value: T;
|
||||
}
|
||||
|
||||
export default class LRUMap<T> {
|
||||
export class LRUMap<T> {
|
||||
private _map: { [key: number]: ILinkedListNode<T> } = {};
|
||||
private _head: ILinkedListNode<T> = null;
|
||||
private _tail: ILinkedListNode<T> = null;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*
|
||||
* A dummy CharAtlas implementation that always fails to draw characters.
|
||||
*/
|
||||
|
||||
import { IGlyphIdentifier, ICharAtlasConfig } from './Types';
|
||||
import BaseCharAtlas from './BaseCharAtlas';
|
||||
|
||||
export default class NoneCharAtlas extends BaseCharAtlas {
|
||||
constructor(document: Document, config: ICharAtlasConfig) {
|
||||
super();
|
||||
}
|
||||
|
||||
public draw(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
glyph: IGlyphIdentifier,
|
||||
x: number,
|
||||
y: number
|
||||
): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { DIM_OPACITY, IGlyphIdentifier, ICharAtlasConfig, CHAR_ATLAS_CELL_SPACING } from './Types';
|
||||
import { generateStaticCharAtlasTexture } from './CharAtlasGenerator';
|
||||
import BaseCharAtlas from './BaseCharAtlas';
|
||||
import { is256Color } from './CharAtlasUtils';
|
||||
import { DEFAULT_COLOR } from '../../common/Types';
|
||||
|
||||
export default class StaticCharAtlas extends BaseCharAtlas {
|
||||
private _texture: HTMLCanvasElement | ImageBitmap;
|
||||
|
||||
constructor(private _document: Document, private _config: ICharAtlasConfig) {
|
||||
super();
|
||||
}
|
||||
|
||||
private _canvasFactory = (width: number, height: number) => {
|
||||
const canvas = this._document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
// This is useful for debugging
|
||||
// document.body.appendChild(canvas);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
protected _doWarmUp(): void {
|
||||
const result = generateStaticCharAtlasTexture(window, this._canvasFactory, this._config);
|
||||
if (result instanceof HTMLCanvasElement) {
|
||||
this._texture = result;
|
||||
} else {
|
||||
result.then(texture => {
|
||||
this._texture = texture;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _isCached(glyph: IGlyphIdentifier, colorIndex: number): boolean {
|
||||
const isAscii = glyph.code < 256;
|
||||
// A color is basic if it is one of the 4 bit ANSI colors.
|
||||
const isBasicColor = glyph.fg < 16;
|
||||
const isDefaultColor = glyph.fg === DEFAULT_COLOR;
|
||||
const isDefaultBackground = glyph.bg === DEFAULT_COLOR;
|
||||
return isAscii && (isBasicColor || isDefaultColor) && isDefaultBackground && !glyph.italic;
|
||||
}
|
||||
|
||||
public draw(
|
||||
ctx: CanvasRenderingContext2D,
|
||||
glyph: IGlyphIdentifier,
|
||||
x: number,
|
||||
y: number
|
||||
): boolean {
|
||||
// we're not warmed up yet
|
||||
if (this._texture === null || this._texture === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let colorIndex = 0;
|
||||
if (is256Color(glyph.fg)) {
|
||||
colorIndex = 2 + glyph.fg + (glyph.bold ? 16 : 0);
|
||||
} else if (glyph.fg === DEFAULT_COLOR) {
|
||||
// If default color and bold
|
||||
if (glyph.bold) {
|
||||
colorIndex = 1;
|
||||
}
|
||||
}
|
||||
if (!this._isCached(glyph, colorIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
|
||||
// ImageBitmap's draw about twice as fast as from a canvas
|
||||
const charAtlasCellWidth = this._config.scaledCharWidth + CHAR_ATLAS_CELL_SPACING;
|
||||
const charAtlasCellHeight = this._config.scaledCharHeight + CHAR_ATLAS_CELL_SPACING;
|
||||
|
||||
// Apply alpha to dim the character
|
||||
if (glyph.dim) {
|
||||
ctx.globalAlpha = DIM_OPACITY;
|
||||
}
|
||||
|
||||
ctx.drawImage(
|
||||
this._texture,
|
||||
glyph.code * charAtlasCellWidth,
|
||||
colorIndex * charAtlasCellHeight,
|
||||
charAtlasCellWidth,
|
||||
this._config.scaledCharHeight,
|
||||
x,
|
||||
y,
|
||||
charAtlasCellWidth,
|
||||
this._config.scaledCharHeight
|
||||
);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { FontWeight } from 'xterm';
|
||||
import { IColorSet } from '../../ui/Types';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
export const INVERTED_DEFAULT_COLOR = 257;
|
||||
export const DIM_OPACITY = 0.5;
|
||||
@@ -22,7 +22,6 @@ export interface IGlyphIdentifier {
|
||||
}
|
||||
|
||||
export interface ICharAtlasConfig {
|
||||
type: 'none' | 'static' | 'dynamic' | 'webgl';
|
||||
devicePixelRatio: number;
|
||||
fontSize: number;
|
||||
fontFamily: string;
|
||||
|
||||
@@ -7,8 +7,8 @@ import { IRenderer, IRenderDimensions } from '../Types';
|
||||
import { ILinkifierEvent, ITerminal, CharacterJoinerHandler } from '../../Types';
|
||||
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 { Disposable } from '../../common/Lifecycle';
|
||||
import { IColorSet } from '../../ui/Types';
|
||||
import { Disposable } from 'common/Lifecycle';
|
||||
import { IColorSet } from 'ui/Types';
|
||||
|
||||
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
|
||||
const ROW_CONTAINER_CLASS = 'xterm-rows';
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
import jsdom = require('jsdom');
|
||||
import { assert } from 'chai';
|
||||
import { DomRendererRowFactory } from './DomRendererRowFactory';
|
||||
import { BufferLine, CellData, FgFlags, BgFlags, Attributes, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, DEFAULT_ATTR_DATA } from '../../core/buffer/BufferLine';
|
||||
import { BufferLine, CellData, FgFlags, BgFlags, Attributes, NULL_CELL_CODE, NULL_CELL_WIDTH, NULL_CELL_CHAR, DEFAULT_ATTR, DEFAULT_ATTR_DATA } from 'core/buffer/BufferLine';
|
||||
import { ITerminalOptions } from '../../Types';
|
||||
import { IBufferLine } from '../../core/Types';
|
||||
import { IBufferLine } from 'core/Types';
|
||||
|
||||
describe('DomRendererRowFactory', () => {
|
||||
let dom: jsdom.JSDOM;
|
||||
@@ -19,7 +19,6 @@ describe('DomRendererRowFactory', () => {
|
||||
beforeEach(() => {
|
||||
dom = new jsdom.JSDOM('');
|
||||
|
||||
options.enableBold = true;
|
||||
options.drawBoldTextInBrightColors = true;
|
||||
|
||||
rowFactory = new DomRendererRowFactory(options, dom.window.document);
|
||||
|
||||
@@ -77,7 +77,7 @@ export class DomRendererRowFactory {
|
||||
}
|
||||
}
|
||||
|
||||
if (this._workCell.isBold() && this._terminalOptions.enableBold) {
|
||||
if (this._workCell.isBold()) {
|
||||
charElement.classList.add(BOLD_CLASS);
|
||||
}
|
||||
|
||||
@@ -104,8 +104,7 @@ export class DomRendererRowFactory {
|
||||
charElement.setAttribute('style', style);
|
||||
} else if (this._workCell.isFgPalette()) {
|
||||
let fg = this._workCell.getFgColor();
|
||||
if (this._workCell.isBold() && fg < 8 && !swapColor &&
|
||||
this._terminalOptions.enableBold && this._terminalOptions.drawBoldTextInBrightColors) {
|
||||
if (this._workCell.isBold() && fg < 8 && !swapColor && this._terminalOptions.drawBoldTextInBrightColors) {
|
||||
fg += 8;
|
||||
}
|
||||
charElement.classList.add(`xterm-${swapColor ? 'b' : 'f'}g-${fg}`);
|
||||
|
||||
Reference in New Issue
Block a user