Merge branch 'master' into webgl2

This commit is contained in:
Daniel Imms
2019-06-12 18:20:39 -07:00
181 changed files with 5333 additions and 6467 deletions
+5 -5
View File
@@ -3,15 +3,15 @@
* @license MIT
*/
import { IRenderLayer, IRenderDimensions } from './Types';
import { IRenderLayer } from './Types';
import { IRenderDimensions } from 'browser/renderer/Types';
import { ITerminal } from '../Types';
import { ICellData } from 'core/Types';
import { DEFAULT_COLOR } from 'common/Types';
import { ICellData, DEFAULT_COLOR } from 'common/Types';
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier } from './atlas/Types';
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 'common/buffer/BufferLine';
import { IColorSet } from 'browser/Types';
export abstract class BaseRenderLayer implements IRenderLayer {
private _canvas: HTMLCanvasElement;
+2 -2
View File
@@ -10,8 +10,8 @@ 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 'common/buffer/BufferLine';
import { IBufferLine } from 'common/Types';
describe('CharacterJoinerRegistry', () => {
let registry: ICharacterJoinerRegistry;
+2 -2
View File
@@ -4,9 +4,9 @@
*/
import { ITerminal } from '../Types';
import { IBufferLine, ICellData, CharData } from 'core/Types';
import { IBufferLine, ICellData, CharData } from 'common/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 'common/buffer/BufferLine';
export class JoinedCellData extends AttributeData implements ICellData {
private _width: number;
+4 -4
View File
@@ -3,12 +3,12 @@
* @license MIT
*/
import { IRenderDimensions } from './Types';
import { IRenderDimensions } from 'browser/renderer/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 'common/Types';
import { CellData } from 'common/buffer/BufferLine';
import { IColorSet } from 'browser/Types';
interface ICursorState {
x: number;
+2 -2
View File
@@ -4,11 +4,11 @@
*/
import { ILinkifierEvent, ITerminal, ILinkifierAccessor } from '../Types';
import { IRenderDimensions } from './Types';
import { IRenderDimensions } from 'browser/renderer/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 'browser/Types';
export class LinkRenderLayer extends BaseRenderLayer {
private _state: ILinkifierEvent = null;
-162
View File
@@ -1,162 +0,0 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
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 { CharacterJoinerHandler } from '../Types';
import { IOptionsService } from 'common/options/Types';
export class RenderCoordinator extends Disposable {
private _renderDebouncer: RenderDebouncer;
private _screenDprMonitor: ScreenDprMonitor;
private _isPaused: boolean = false;
private _needsFullRefresh: boolean = false;
private _canvasWidth: number = 0;
private _canvasHeight: number = 0;
private _onDimensionsChange = new EventEmitter2<IRenderDimensions>();
public get onDimensionsChange(): IEvent<IRenderDimensions> { return this._onDimensionsChange.event; }
private _onRender = new EventEmitter2<{ start: number, end: number }>();
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }
private _onRefreshRequest = new EventEmitter2<{ start: number, end: number }>();
public get onRefreshRequest(): IEvent<{ start: number, end: number }> { return this._onRefreshRequest.event; }
public get dimensions(): IRenderDimensions { return this._renderer.dimensions; }
constructor(
private _renderer: IRenderer,
private _rowCount: number,
screenElement: HTMLElement,
optionsService: IOptionsService
) {
super();
this._renderDebouncer = new RenderDebouncer((start, end) => this._renderRows(start, end));
this.register(this._renderDebouncer);
this._screenDprMonitor = new ScreenDprMonitor();
this._screenDprMonitor.setListener(() => this._renderer.onDevicePixelRatioChange());
this.register(this._screenDprMonitor);
this.register(optionsService.onOptionChange(() => this._renderer.onOptionsChanged()));
// dprchange should handle this case, we need this as well for browsers that don't support the
// matchMedia query.
this.register(addDisposableDomListener(window, 'resize', () => this._renderer.onDevicePixelRatioChange()));
// Detect whether IntersectionObserver is detected and enable renderer pause
// and resume based on terminal visibility if so
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(e => this._onIntersectionChange(e[e.length - 1]), { threshold: 0 });
observer.observe(screenElement);
this.register({ dispose: () => observer.disconnect() });
}
}
private _onIntersectionChange(entry: IntersectionObserverEntry): void {
this._isPaused = entry.intersectionRatio === 0;
if (!this._isPaused && this._needsFullRefresh) {
this.refreshRows(0, this._rowCount - 1);
this._needsFullRefresh = false;
}
}
public refreshRows(start: number, end: number): void {
if (this._isPaused) {
this._needsFullRefresh = true;
return;
}
this._renderDebouncer.refresh(start, end, this._rowCount);
}
private _renderRows(start: number, end: number): void {
this._renderer.renderRows(start, end);
this._onRender.fire({ start, end });
}
public resize(cols: number, rows: number): void {
this._rowCount = rows;
this._fireOnCanvasResize();
}
public changeOptions(): void {
this._renderer.onOptionsChanged();
this._fireOnCanvasResize();
}
private _fireOnCanvasResize(): void {
// Don't fire the event if the dimensions haven't changed
if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) {
return;
}
this._onDimensionsChange.fire(this._renderer.dimensions);
}
public setRenderer(renderer: IRenderer): void {
// TODO: RenderCoordinator should be the only one to dispose the renderer
this._renderer.dispose();
this._renderer = renderer;
}
private _fullRefresh(): void {
if (this._isPaused) {
this._needsFullRefresh = true;
} else {
this.refreshRows(0, this._rowCount);
}
}
public setColors(colors: IColorSet): void {
this._renderer.setColors(colors);
this._fullRefresh();
}
public onDevicePixelRatioChange(): void {
this._renderer.onDevicePixelRatioChange();
}
public onResize(cols: number, rows: number): void {
this._renderer.onResize(cols, rows);
this._fullRefresh();
}
// TODO: Is this useful when we have onResize?
public onCharSizeChanged(): void {
this._renderer.onCharSizeChanged();
}
public onBlur(): void {
this._renderer.onBlur();
}
public onFocus(): void {
this._renderer.onFocus();
}
public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void {
this._renderer.onSelectionChanged(start, end, columnSelectMode);
}
public onCursorMove(): void {
this._renderer.onCursorMove();
}
public clear(): void {
this._renderer.clear();
}
public registerCharacterJoiner(handler: CharacterJoinerHandler): number {
return this._renderer.registerCharacterJoiner(handler);
}
public deregisterCharacterJoiner(joinerId: number): boolean {
return this._renderer.deregisterCharacterJoiner(joinerId);
}
}
+13 -12
View File
@@ -6,12 +6,14 @@
import { TextRenderLayer } from './TextRenderLayer';
import { SelectionRenderLayer } from './SelectionRenderLayer';
import { CursorRenderLayer } from './CursorRenderLayer';
import { IRenderLayer, IRenderer, IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { ITerminal, CharacterJoinerHandler } from '../Types';
import { IRenderLayer, ICharacterJoinerRegistry } from './Types';
import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types';
import { ITerminal } from '../Types';
import { LinkRenderLayer } from './LinkRenderLayer';
import { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry';
import { Disposable } from 'common/Lifecycle';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
import { ICharSizeService } from 'browser/services/Services';
export class Renderer extends Disposable implements IRenderer {
private _renderLayers: IRenderLayer[];
@@ -22,7 +24,8 @@ export class Renderer extends Disposable implements IRenderer {
constructor(
private _terminal: ITerminal,
private _colors: IColorSet
private _colors: IColorSet,
private _charSizeService: ICharSizeService
) {
super();
const allowTransparency = this._terminal.options.allowTransparency;
@@ -133,8 +136,7 @@ export class Renderer extends Disposable implements IRenderer {
* Recalculates the character and canvas dimensions.
*/
private _updateDimensions(): void {
// Perform a new measure if the CharMeasure dimensions are not yet available
if (!this._terminal.charMeasure.width || !this._terminal.charMeasure.height) {
if (!this._charSizeService.hasValidSize) {
return;
}
@@ -142,12 +144,12 @@ export class Renderer extends Disposable implements IRenderer {
// drawn to an integer grid in order for the CharAtlas "stamps" to not be
// blurry. When text is drawn to the grid not using the CharAtlas, it is
// clipped to ensure there is no overlap with the next cell.
this.dimensions.scaledCharWidth = Math.floor(this._terminal.charMeasure.width * window.devicePixelRatio);
this.dimensions.scaledCharWidth = Math.floor(this._charSizeService.width * window.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 * window.devicePixelRatio);
this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * window.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
@@ -181,10 +183,9 @@ export class Renderer extends Disposable implements IRenderer {
// Get the _actual_ dimensions of an individual cell. This needs to be
// derived from the canvasWidth/Height calculated above which takes into
// account window.devicePixelRatio. CharMeasure.width/height by itself is
// insufficient when the page is not at 100% zoom level as CharMeasure is
// measured in CSS pixels, but the actual char size on the canvas can
// differ.
// account window.devicePixelRatio. ICharSizeService.width/height by itself
// is insufficient when the page is not at 100% zoom level as it's measured
// in CSS pixels, but the actual char size on the canvas can differ.
this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._terminal.rows;
this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._terminal.cols;
}
+2 -2
View File
@@ -4,9 +4,9 @@
*/
import { ITerminal } from '../Types';
import { IRenderDimensions } from './Types';
import { IRenderDimensions } from 'browser/renderer/Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
interface ISelectionState {
start: [number, number];
+5 -4
View File
@@ -3,14 +3,15 @@
* @license MIT
*/
import { IRenderDimensions, ICharacterJoinerRegistry } from './Types';
import { ICharacterJoinerRegistry } from './Types';
import { IRenderDimensions } from 'browser/renderer/Types';
import { ITerminal } from '../Types';
import { CharData, ICellData } from 'core/Types';
import { CharData, ICellData } from 'common/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 'common/buffer/BufferLine';
import { JoinedCellData } from './CharacterJoinerRegistry';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
/**
* This CharData looks like a null character, which will forc a clear and render
+3 -40
View File
@@ -3,9 +3,10 @@
* @license MIT
*/
import { ITerminal, CharacterJoinerHandler } from '../Types';
import { ITerminal } from '../Types';
import { IDisposable } from 'xterm';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
import { IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types';
/**
* Flags used to render terminal text properly.
@@ -20,44 +21,6 @@ export const enum FLAGS {
ITALIC = 64
}
/**
* Note that IRenderer implementations should emit the refresh event after
* rendering rows to the screen.
*/
export interface IRenderer extends IDisposable {
readonly dimensions: IRenderDimensions;
dispose(): void;
setColors(colors: IColorSet): void;
onDevicePixelRatioChange(): void;
onResize(cols: number, rows: number): void;
onCharSizeChanged(): void;
onBlur(): void;
onFocus(): void;
onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void;
onCursorMove(): void;
onOptionsChanged(): void;
clear(): void;
renderRows(start: number, end: number): void;
registerCharacterJoiner(handler: CharacterJoinerHandler): number;
deregisterCharacterJoiner(joinerId: number): boolean;
}
export interface IRenderDimensions {
scaledCharWidth: number;
scaledCharHeight: number;
scaledCellWidth: number;
scaledCellHeight: number;
scaledCharLeft: number;
scaledCharTop: number;
scaledCanvasWidth: number;
scaledCanvasHeight: number;
canvasWidth: number;
canvasHeight: number;
actualCellWidth: number;
actualCellHeight: number;
}
export interface IRenderLayer extends IDisposable {
/**
* Called when the terminal loses focus.
+1 -1
View File
@@ -8,7 +8,7 @@ import { generateConfig, configEquals } from './CharAtlasUtils';
import { BaseCharAtlas } from './BaseCharAtlas';
import { DynamicCharAtlas } from './DynamicCharAtlas';
import { ICharAtlasConfig } from './Types';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
interface ICharAtlasCacheEntry {
atlas: BaseCharAtlas;
+1 -1
View File
@@ -6,7 +6,7 @@
import { ITerminal } from '../../Types';
import { ICharAtlasConfig } from './Types';
import { DEFAULT_COLOR } from 'common/Types';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {
// null out some fields that don't matter
+2 -2
View File
@@ -5,10 +5,10 @@
import { DIM_OPACITY, IGlyphIdentifier, INVERTED_DEFAULT_COLOR, ICharAtlasConfig } from './Types';
import { BaseCharAtlas } from './BaseCharAtlas';
import { DEFAULT_ANSI_COLORS } from 'ui/ColorManager';
import { DEFAULT_ANSI_COLORS } from 'browser/ColorManager';
import { LRUMap } from './LRUMap';
import { isFirefox, isSafari } from 'common/Platform';
import { IColor } from 'ui/Types';
import { IColor } from 'browser/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.
+1 -1
View File
@@ -4,7 +4,7 @@
*/
import { FontWeight } from 'xterm';
import { IColorSet } from 'ui/Types';
import { IColorSet } from 'browser/Types';
export const INVERTED_DEFAULT_COLOR = 257;
export const DIM_OPACITY = 0.5;
+8 -6
View File
@@ -3,12 +3,13 @@
* @license MIT
*/
import { IRenderer, IRenderDimensions } from '../Types';
import { ILinkifierEvent, ITerminal, CharacterJoinerHandler } from '../../Types';
import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types';
import { ILinkifierEvent, ITerminal } 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 { IColorSet } from 'browser/Types';
import { ICharSizeService } from 'browser/services/Services';
const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
const ROW_CONTAINER_CLASS = 'xterm-rows';
@@ -41,7 +42,8 @@ export class DomRenderer extends Disposable implements IRenderer {
constructor(
private _terminal: ITerminal,
private _colors: IColorSet
private _colors: IColorSet,
private _charSizeService: ICharSizeService
) {
super();
@@ -91,8 +93,8 @@ export class DomRenderer extends Disposable implements IRenderer {
}
private _updateDimensions(): void {
this.dimensions.scaledCharWidth = this._terminal.charMeasure.width * window.devicePixelRatio;
this.dimensions.scaledCharHeight = Math.ceil(this._terminal.charMeasure.height * window.devicePixelRatio);
this.dimensions.scaledCharWidth = this._charSizeService.width * window.devicePixelRatio;
this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * window.devicePixelRatio);
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing);
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight);
this.dimensions.scaledCharLeft = 0;
@@ -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 'common/buffer/BufferLine';
import { ITerminalOptions } from '../../Types';
import { IBufferLine } from 'core/Types';
import { IBufferLine } from 'common/Types';
describe('DomRendererRowFactory', () => {
let dom: jsdom.JSDOM;
+2 -2
View File
@@ -4,9 +4,9 @@
*/
import { ITerminalOptions } from '../../Types';
import { IBufferLine } from '../../core/Types';
import { IBufferLine } from 'common/Types';
import { INVERTED_DEFAULT_COLOR } from '../atlas/Types';
import { CellData, AttributeData, NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from '../../core/buffer/BufferLine';
import { CellData, AttributeData, NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from 'common/buffer/BufferLine';
export const BOLD_CLASS = 'xterm-bold';
export const DIM_CLASS = 'xterm-dim';