http://git-wip-us.apache.org/repos/asf/hadoop/blob/154449fb/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/resources/TERMINAL/xterm/dist/xterm.js.map ---------------------------------------------------------------------- diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/resources/TERMINAL/xterm/dist/xterm.js.map b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/resources/TERMINAL/xterm/dist/xterm.js.map new file mode 100644 index 0000000..9ea86f3 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/resources/TERMINAL/xterm/dist/xterm.js.map @@ -0,0 +1 @@ +{"version":3,"file":"xterm.js","sources":["../src/xterm.ts","../src/utils/MouseHelper.ts","../src/utils/Clone.ts","../src/ui/ScreenDprMonitor.ts","../src/ui/RenderDebouncer.ts","../src/ui/MouseZoneManager.ts","../src/ui/Lifecycle.ts","../src/ui/CharMeasure.ts","../src/shared/utils/Browser.ts","../src/shared/atlas/Types.ts","../src/shared/atlas/CharAtlasGenerator.ts","../src/renderer/dom/DomRendererRowFactory.ts","../src/renderer/dom/DomRenderer.ts","../src/renderer/atlas/Types.ts","../src/renderer/atlas/StaticCharAtlas.ts","../src/renderer/atlas/NoneCharAtlas.ts","../src/renderer/atlas/LRUMap.ts","../src/renderer/atlas/DynamicCharAtlas.ts","../src/renderer/atlas/CharAtlasUtils.ts","../src/renderer/atlas/CharAtlasCache.ts","../src/renderer/atlas/BaseCharAtlas.ts","../src/renderer/TextRenderLayer.ts","../src/renderer/SelectionRenderLayer.ts","../src/renderer/Renderer.ts","../src/renderer/LinkRenderLayer.ts","../src/renderer/GridCache.ts","../src/renderer/CursorRenderLayer.ts","../src/ renderer/ColorManager.ts","../src/renderer/CharacterJoinerRegistry.ts","../src/renderer/BaseRenderLayer.ts","../src/public/Terminal.ts","../src/handlers/Clipboard.ts","../src/handlers/AltClickHandler.ts","../src/core/input/Keyboard.ts","../src/core/data/Charsets.ts","../src/common/data/EscapeSequences.ts","../src/common/Lifecycle.ts","../src/common/EventEmitter.ts","../src/common/CircularList.ts","../src/Viewport.ts","../src/Terminal.ts","../src/Strings.ts","../src/SoundManager.ts","../src/SelectionModel.ts","../src/SelectionManager.ts","../src/Linkifier.ts","../src/InputHandler.ts","../src/EscapeSequenceParser.ts","../src/CompositionHelper.ts","../src/CharWidth.ts","../src/BufferSet.ts","../src/BufferLine.ts","../src/Buffer.ts","../src/AccessibilityManager.ts","../node_modules/browser-pack/_prelude.js"],"sourcesContent":["/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * This file is the entry point for browserify.\n */\n\nimport { Termi nal } from './public/Terminal';\n\nmodule.exports = Terminal;\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ICharMeasure } from '../Types';\nimport { IRenderer } from '../renderer/Types';\n\nexport class MouseHelper {\n constructor(private _renderer: IRenderer) {}\n\n public static getCoordsRelativeToElement(event: {pageX: number, pageY: number}, element: HTMLElement): [number, number] {\n // Ignore browsers that don't support MouseEvent.pageX\n if (event.pageX === null || event.pageX === undefined) {\n return null;\n }\n\n const originalElement = element;\n let x = event.pageX;\n let y = event.pageY;\n\n // Converts the coordinates from being relative to the document to being\n // relative to the terminal.\n while (element) {\n x -= element.offsetLeft;\n y -= element.offsetTop;\n element = <HTMLElement>element.offsetParent;\n }\n element = originalElement;\n while (element && element !== element.ownerDocument.body) {\n x += element.scrollLeft;\n y += element.scrollTop;\n element = <HTMLElement>element.parentElement;\n }\n return [x, y];\n }\n\n /**\n * Gets coordinates within the terminal for a particular mouse event. The result\n * is returned as an array in the form [x, y] instead of an object as it's a\n * little faster and this function is used in some low level code.\n * @param event The mouse event.\n * @param element The terminal's container element.\n * @param charMeasure The char measure object used to determine character sizes.\n * @param colCount The number of columns in the terminal.\n * @param rowCount The number of rows n the terminal.\n * @param isSelection Whether the request is for the selection or not. This will\n * apply an offset to the x value such that the left half of the cell will\n * select that cell and the right half will select the next cell.\n */\n public getCoords( event: {pageX: number, pageY: number}, element: HTMLElement, charMeasure: ICharMeasure, lineHeight: number, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {\n // Coordinates cannot be measured if charMeasure has not been initialized\n if (!charMeasure.width || !charMeasure.height) {\n return null;\n }\n\n const coords = MouseHelper.getCoordsRelativeToElement(event, element);\n if (!coords) {\n return null;\n }\n\n coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderer.dimensions.actualCellWidth / 2 : 0)) / this._renderer.dimensions.actualCellWidth);\n coords[1] = Math.ceil(coords[1] / this._renderer.dimensions.actualCellHeight);\n\n // Ensure coordinates are within the terminal viewport. Note that selections\n // need an addition point of precision to cover the end point (as characters\n // cover half of one char and half of the next).\n coords[0] = Math.min(Math.max(coords[0], 1), colCount + (isSe lection ? 1 : 0));\n coords[1] = Math.min(Math.max(coords[1], 1), rowCount);\n\n return coords;\n }\n\n /**\n * Gets coordinates within the terminal for a particular mouse event, wrapping\n * them to the bounds of the terminal and adding 32 to both the x and y values\n * as expected by xterm.\n * @param event The mouse event.\n * @param element The terminal's container element.\n * @param charMeasure The char measure object used to determine character sizes.\n * @param colCount The number of columns in the terminal.\n * @param rowCount The number of rows in the terminal.\n */\n public getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, lineHeight: number, colCount: number, rowCount: number): { x: number, y: number } {\n const coords = this.getCoords(event, element, charMeasure, lineHeight, colCount, rowCount);\n let x = coords[0];\n let y = coords[1];\n\n // xterm sends raw bytes and starts at 32 (SP) for each.\ n x += 32;\n y += 32;\n\n return { x, y };\n }\n}\n","/**\n * Copyright (c) 2016 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\n/*\n * A simple utility for cloning values\n */\nexport const clone = <T>(val: T, depth: number = 5): T => {\n if (typeof val !== 'object') {\n return val;\n }\n\n // cloning null always returns null\n if (val === null) {\n return null;\n }\n\n // If we're cloning an array, use an array as the base, otherwise use an object\n const clonedObject: any = Array.isArray(val) ? [] : {};\n\n for (const key in val) {\n // Recursively clone eack item unless we're at the maximum depth\n clonedObject[key] = depth <= 1 ? val[key] : clone(val[key], depth - 1);\n }\n\n return clonedObject as T;\n};\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { Disposable } from '../common/Lifecycle';\n\nexport type ScreenDprListener = (newDevicePixelRatio?: number, oldDeviceP ixelRatio?: number) => void;\n\n/**\n * The screen device pixel ratio monitor allows listening for when the\n * window.devicePixelRatio value changes. This is done not with polling but with\n * the use of window.matchMedia to watch media queries. When the event fires,\n * the listener will be reattached using a different media query to ensure that\n * any further changes will register.\n *\n * The listener should fire on both window zoom changes and switching to a\n * monitor with a different DPI.\n */\nexport class ScreenDprMonitor extends Disposable {\n private _currentDevicePixelRatio: number;\n private _outerListener: MediaQueryListListener;\n private _listener: ScreenDprListener;\n private _resolutionMediaMatchList: MediaQueryList;\n\n public setListener(listener: ScreenDprListener): void {\n if (this._listener) {\n this.clearListener();\n }\n this._listener = listener;\n this._outerListener = () => {\n this._listener(window.devicePixelRatio, this._cu rrentDevicePixelRatio);\n this._updateDpr();\n };\n this._updateDpr();\n }\n\n public dispose(): void {\n super.dispose();\n this.clearListener();\n }\n\n private _updateDpr(): void {\n // Clear listeners for old DPR\n if (this._resolutionMediaMatchList) {\n this._resolutionMediaMatchList.removeListener(this._outerListener);\n }\n // Add listeners for new DPR\n this._currentDevicePixelRatio = window.devicePixelRatio;\n this._resolutionMediaMatchList = window.matchMedia(`screen and (resolution: ${window.devicePixelRatio}dppx)`);\n this._resolutionMediaMatchList.addListener(this._outerListener);\n }\n\n public clearListener(): void {\n if (!this._listener) {\n return;\n }\n this._resolutionMediaMatchList.removeListener(this._outerListener);\n this._listener = null;\n this._outerListener = null;\n }\n}\n","import { ITerminal } from '../Types';\nimport { IDisposable } from 'xterm';\n\n/**\n * Debounces calls to render terminal rows using animation frames.\n */\nexport class RenderDebouncer implements IDisposable {\n private _rowStart: number;\n private _rowEnd: number;\n private _animationFrame: number = null;\n\n constructor(\n private _terminal: ITerminal,\n private _callback: (start: number, end: number) => void\n ) {\n }\n\n public dispose(): void {\n if (this._animationFrame) {\n window.cancelAnimationFrame(this._animationFrame);\n this._animationFrame = null;\n }\n }\n\n public refresh(rowStart: number, rowEnd: number): void {\n // Get the min/max row start/end for the arg values\n rowStart = rowStart !== null && rowStart !== undefined ? rowStart : 0;\n rowEnd = rowEnd !== null && rowEnd !== undefined ? rowEnd : this._terminal.rows - 1;\n // Check whether the row start/end values have already been set\n const isRowStartSet = this._rowStart !== undefined && this._rowStart !== null;\n const isRowEndSet = this._rowEnd !== undefined && this._row End !== null;\n // Set the properties to the updated values\n this._rowStart = isRowStartSet ? Math.min(this._rowStart, rowStart) : rowStart;\n this._rowEnd = isRowEndSet ? Math.max(this._rowEnd, rowEnd) : rowEnd;\n\n if (this._animationFrame) {\n return;\n }\n\n this._animationFrame = window.requestAnimationFrame(() => this._innerRefresh());\n }\n\n private _innerRefresh(): void {\n // Clamp values\n this._rowStart = Math.max(this._rowStart, 0);\n this._rowEnd = Math.min(this._rowEnd, this._terminal.rows - 1);\n\n // Run render callback\n this._callback(this._rowStart, this._rowEnd);\n\n // Reset debouncer\n this._rowStart = null;\n this._rowEnd = null;\n this._animationFrame = null;\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ITerminal } from '../Types';\nimport { IMouseZoneManager, IMouseZone } from './Types';\nimport { Disposable } from '../common/Lifecycle ';\nimport { addDisposableDomListener } from './Lifecycle';\n\nconst HOVER_DURATION = 500;\n\n/**\n * The MouseZoneManager allows components to register zones within the terminal\n * that trigger hover and click callbacks.\n *\n * This class was intentionally made not so robust initially as the only case it\n * needed to support was single-line links which never overlap. Improvements can\n * be made in the future.\n */\nexport class MouseZoneManager extends Disposable implements IMouseZoneManager {\n private _zones: IMouseZone[] = [];\n\n private _areZonesActive: boolean = false;\n private _mouseMoveListener: (e: MouseEvent) => any;\n private _clickListener: (e: MouseEvent) => any;\n\n private _tooltipTimeout: number = null;\n private _currentZone: IMouseZone = null;\n private _lastHoverCoords: [number, number] = [null, null];\n\n constructor(\n private _terminal: ITerminal\n ) {\n super();\n\n this.register(addDisposableDomListener(this._terminal.element, 'mousedo wn', e => this._onMouseDown(e)));\n\n // These events are expensive, only listen to it when mouse zones are active\n this._mouseMoveListener = e => this._onMouseMove(e);\n this._clickListener = e => this._onClick(e);\n }\n\n public dispose(): void {\n super.dispose();\n this._deactivate();\n }\n\n public add(zone: IMouseZone): void {\n this._zones.push(zone);\n if (this._zones.length === 1) {\n this._activate();\n }\n }\n\n public clearAll(start?: number, end?: number): void {\n // Exit if there's nothing to clear\n if (this._zones.length === 0) {\n return;\n }\n\n // Clear all if start/end weren't set\n if (!end) {\n start = 0;\n end = this._terminal.rows - 1;\n }\n\n // Iterate through zones and clear them out if they're within the range\n for (let i = 0; i < this._zones.length; i++) {\n const zone = this._zones[i];\n if ((zone.y1 > start && zone.y1 <= end + 1) ||\n (zone.y2 > start && zon e.y2 <= end + 1) ||\n (zone.y1 < start && zone.y2 > end + 1)) {\n if (this._currentZone && this._currentZone === zone) {\n this._currentZone.leaveCallback();\n this._currentZone = null;\n }\n this._zones.splice(i--, 1);\n }\n }\n\n // Deactivate the mouse zone manager if all the zones have been removed\n if (this._zones.length === 0) {\n this._deactivate();\n }\n }\n\n private _activate(): void {\n if (!this._areZonesActive) {\n this._areZonesActive = true;\n this._terminal.element.addEventListener('mousemove', this._mouseMoveListener);\n this._terminal.element.addEventListener('click', this._clickListener);\n }\n }\n\n private _deactivate(): void {\n if (this._areZonesActive) {\n this._areZonesActive = false;\n this._terminal.element.removeEventListener('mousemove', this._mouseMoveListener);\n this._terminal.element.removeEventListener('click', this._clickListener);\n }\n }\n\n private _onMouseMove(e: MouseEvent): void {\n // TODO: Ideally this would only clear the hover state when the mouse moves\n // outside of the mouse zone\n if (this._lastHoverCoords[0] !== e.pageX || this._lastHoverCoords[1] !== e.pageY) {\n this._onHover(e);\n // Record the current coordinates\n this._lastHoverCoords = [e.pageX, e.pageY];\n }\n }\n\n private _onHover(e: MouseEvent): void {\n const zone = this._findZoneEventAt(e);\n\n // Do nothing if the zone is the same\n if (zone === this._currentZone) {\n return;\n }\n\n // Fire the hover end callback and cancel any existing timer if a new zone\n // is being hovered\n if (this._currentZone) {\n this._currentZone.leaveCallback();\n this._currentZone = null;\n if (this._tooltipTimeout) {\n clearTimeout(this._tooltipTimeout);\n }\n }\n\n // Exit if there is not zone\n if (!zone) {\n return;\n }\n this._currentZone = zon e;\n\n // Trigger the hover callback\n if (zone.hoverCallback) {\n zone.hoverCallback(e);\n }\n\n // Restart the tooltip timeout\n this._tooltipTimeout = <number><any>setTimeout(() => this._onTooltip(e), HOVER_DURATION);\n }\n\n private _onTooltip(e: MouseEvent): void {\n this._tooltipTimeout = null;\n const zone = this._findZoneEventAt(e);\n if (zone && zone.tooltipCallback) {\n zone.tooltipCallback(e);\n }\n }\n\n private _onMouseDown(e: MouseEvent): void {\n // Ignore the event if there are no zones active\n if (!this._areZonesActive) {\n return;\n }\n\n // Find the active zone, prevent event propagation if found to prevent other\n // components from handling the mouse event.\n const zone = this._findZoneEventAt(e);\n if (zone) {\n if (zone.willLinkActivate(e)) {\n e.preventDefault();\n e.stopImmediatePropagation();\n }\n }\n }\n\n private _onClick(e: MouseEvent): void {\n // Find t he active zone and click it if found\n const zone = this._findZoneEventAt(e);\n if (zone) {\n zone.clickCallback(e);\n e.preventDefault();\n e.stopImmediatePropagation();\n }\n }\n\n private _findZoneEventAt(e: MouseEvent): IMouseZone {\n const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);\n if (!coords) {\n return null;\n }\n const x = coords[0];\n const y = coords[1];\n for (let i = 0; i < this._zones.length; i++) {\n const zone = this._zones[i];\n if (zone.y1 === zone.y2) {\n // Single line link\n if (y === zone.y1 && x >= zone.x1 && x < zone.x2) {\n return zone;\n }\n } else {\n // Multi-line link\n if ((y === zone.y1 && x >= zone.x1) ||\n (y === zone.y2 && x < zone.x2) ||\n (y > zone.y1 && y < zone.y2)) {\n return zone;\n }\n }\n }\n return null;\n }\n}\n\nexport class MouseZone implements IMouseZone {\n constructor(\n public x1: number,\n public y1: number,\n public x2: number,\n public y2: number,\n public clickCallback: (e: MouseEvent) => any,\n public hoverCallback: (e: MouseEvent) => any,\n public tooltipCallback: (e: MouseEvent) => any,\n public leaveCallback: () => void,\n public willLinkActivate: (e: MouseEvent) => boolean\n ) {\n }\n}\n","/**\n * Copyright (c) 2018 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { IDisposable } from 'xterm';\n\n/**\n * Adds a disposabe listener to a node in the DOM, returning the disposable.\n * @param type The event type.\n * @param handler The handler for the listener.\n */\nexport function addDisposableDomListener(\n node: Element | Window | Document,\n type: string,\n handler: (e: any) => void,\n useCapture?: boolean\n): IDisposable {\n node.addEventListene r(type, handler, useCapture);\n return {\n dispose: () => {\n if (!handler) {\n // Already disposed\n return;\n }\n node.removeEventListener(type, handler, useCapture);\n node = null;\n handler = null;\n }\n };\n}\n","/**\n * Copyright (c) 2016 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ICharMeasure, ITerminalOptions } from '../Types';\nimport { EventEmitter } from '../common/EventEmitter';\n\n/**\n * Utility class that measures the size of a character. Measurements are done in\n * the DOM rather than with a canvas context because support for extracting the\n * height of characters is patchy across browsers.\n */\nexport class CharMeasure extends EventEmitter implements ICharMeasure {\n private _document: Document;\n private _parentElement: HTMLElement;\n private _measureElement: HTMLElement;\n private _width: number;\n private _height: number;\n\n constructor(document: Document, parentElement: HT MLElement) {\n super();\n this._document = document;\n this._parentElement = parentElement;\n this._measureElement = this._document.createElement('span');\n this._measureElement.classList.add('xterm-char-measure-element');\n this._measureElement.textContent = 'W';\n this._measureElement.setAttribute('aria-hidden', 'true');\n this._parentElement.appendChild(this._measureElement);\n }\n\n public get width(): number {\n return this._width;\n }\n\n public get height(): number {\n return this._height;\n }\n\n public measure(options: ITerminalOptions): void {\n this._measureElement.style.fontFamily = options.fontFamily;\n this._measureElement.style.fontSize = `${options.fontSize}px`;\n const geometry = this._measureElement.getBoundingClientRect();\n // The element is likely currently display:none, we should retain the\n // previous value.\n if (geometry.width === 0 || geometry.height === 0) {\n return;\n }\n if (this._width != = geometry.width || this._height !== geometry.height) {\n this._width = geometry.width;\n this._height = Math.ceil(geometry.height);\n this.emit('charsizechanged');\n }\n }\n}\n","/**\n * Copyright (c) 2016 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nconst isNode = (typeof navigator === 'undefined') ? true : false;\nconst userAgent = (isNode) ? 'node' : navigator.userAgent;\nconst platform = (isNode) ? 'node' : navigator.platform;\n\nexport const isFirefox = !!~userAgent.indexOf('Firefox');\nexport const isSafari = /^((?!chrome|android).)*safari/i.test(userAgent);\nexport const isMSIE = !!~userAgent.indexOf('MSIE') || !!~userAgent.indexOf('Trident');\n\n// Find the users platform. We use this to interpret the meta key\n// and ISO third level shifts.\n// http://stackoverflow.com/q/19877924/577598\nexport const isMac = contains(['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], platform);\nexport const isIpad = platform === 'iPad';\nexport const isIphone = platform === 'iPhone';\nexport const isMSWindows = contains(['Windows', 'Win16', 'Win32', 'WinCE'], platform);\nexport const isLinux = platform.indexOf('Linux') >= 0;\n\n/**\n * Return if the given array contains the given element\n * @param arr The array to search for the given element.\n * @param el The element to look for into the array\n */\nfunction contains(arr: any[], el: any): boolean {\n return arr.indexOf(el) >= 0;\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { FontWeight } from 'xterm';\nimport { IColorSet } from '../Types';\n\nexport const CHAR_ATLAS_CELL_SPACING = 1;\n\nexport interface ICharAtlasConfig {\n type: 'none' | 'static' | 'dynamic';\n devicePixelRatio: number;\n fontSize: number;\n fontFamily: string;\n fontWeight: FontWeight;\n fontWeightBold: FontWeight;\n scaledCharWidth: number;\n scaledCharHeight: number;\n allowTransparency: boolean;\n colors: IColorSet;\n}\n","/**\n * Copyright (c) 2018 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { FontWeight } from 'xterm';\nimport { CHAR_ATLAS_CELL_SPACING, ICharAtlasConfig } from './Types';\nimport { IColor } from '../Types';\nimport { isFirefox, isSafari } from '../utils/Browser';\n\ndeclare const Promise: any;\n\nexport interface IOffscreenCanvas {\n width: number;\n height: number;\n getContext(type: '2d', config?: Canvas2DContextAttributes): CanvasRenderingContext2D;\n transferToImageBitmap(): ImageBitmap;\n}\n\n/**\n * Generates a char atlas.\n * @param context The window or worker context.\n * @param canvasFactory A function to generate a canvas with a width or height.\n * @param config The config for the new char atlas.\n */\nexport function generateStaticCharAtlasTexture(context: Window, canvasFactory: (width: number, height: number) => HTMLCanvasElement | IOffscreenCanvas, config: ICharAtlasConfig): HTMLCanvasElement | Promise<ImageBitmap> {\n const cellWidth = con fig.scaledCharWidth + CHAR_ATLAS_CELL_SPACING;\n const cellHeight = config.scaledCharHeight + CHAR_ATLAS_CELL_SPACING;\n const canvas = canvasFactory(\n /*255 ascii chars*/255 * cellWidth,\n (/*default+default bold*/2 + /*0-15*/16 + /*0-15 bold*/16) * cellHeight\n );\n const ctx = canvas.getContext('2d', {alpha: config.allowTransparency});\n\n ctx.fillStyle = config.colors.background.css;\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n ctx.save();\n ctx.fillStyle = config.colors.foreground.css;\n ctx.font = getFont(config.fontWeight, config);\n ctx.textBaseline = 'top';\n\n // Default color\n for (let i = 0; i < 256; i++) {\n ctx.save();\n ctx.beginPath();\n ctx.rect(i * cellWidth, 0, cellWidth, cellHeight);\n ctx.clip();\n ctx.fillText(String.fromCharCode(i), i * cellWidth, 0);\n ctx.restore();\n }\n // Default color bold\n ctx.save();\n ctx.font = getFont(config.fontWeightBold, config);\n for (let i = 0; i < 256; i++) {\n ctx.save ();\n ctx.beginPath();\n ctx.rect(i * cellWidth, cellHeight, cellWidth, cellHeight);\n ctx.clip();\n ctx.fillText(String.fromCharCode(i), i * cellWidth, cellHeight);\n ctx.restore();\n }\n ctx.restore();\n\n // Colors 0-15\n ctx.font = getFont(config.fontWeight, config);\n for (let colorIndex = 0; colorIndex < 16; colorIndex++) {\n const y = (colorIndex + 2) * cellHeight;\n // Draw ascii characters\n for (let i = 0; i < 256; i++) {\n ctx.save();\n ctx.beginPath();\n ctx.rect(i * cellWidth, y, cellWidth, cellHeight);\n ctx.clip();\n ctx.fillStyle = config.colors.ansi[colorIndex].css;\n ctx.fillText(String.fromCharCode(i), i * cellWidth, y);\n ctx.restore();\n }\n }\n\n // Colors 0-15 bold\n ctx.font = getFont(config.fontWeightBold, config);\n for (let colorIndex = 0; colorIndex < 16; colorIndex++) {\n const y = (colorIndex + 2 + 16) * cellHeight;\n // Draw ascii characters\n for (let i = 0; i < 256; i++) {\n ctx.save();\n ctx.beginPath();\n ctx.rect(i * cellWidth, y, cellWidth, cellHeight);\n ctx.clip();\n ctx.fillStyle = config.colors.ansi[colorIndex].css;\n ctx.fillText(String.fromCharCode(i), i * cellWidth, y);\n ctx.restore();\n }\n }\n ctx.restore();\n\n // Support is patchy for createImageBitmap at the moment, pass a canvas back\n // if support is lacking as drawImage works there too. Firefox is also\n // included here as ImageBitmap appears both buggy and has horrible\n // performance (tested on v55).\n if (!('createImageBitmap' in context) || isFirefox || isSafari) {\n // Don't attempt to clear background colors if createImageBitmap is not supported\n if (canvas instanceof HTMLCanvasElement) {\n // Just return the HTMLCanvas if it's a HTMLCanvasElement\n return canvas;\n }\n // Transfer to an ImageBitmap is this is an OffscreenCanvas\n return new Promise((r: (bitmap: ImageBitmap) => void) => r(canvas.trans ferToImageBitmap()));\n }\n\n const charAtlasImageData = ctx.getImageData(0, 0, canvas.width, canvas.height);\n\n // Remove the background color from the image so characters may overlap\n clearColor(charAtlasImageData, config.colors.background);\n\n return context.createImageBitmap(charAtlasImageData);\n}\n\n/**\n * Makes a partiicular rgb color in an ImageData completely transparent.\n * @returns True if the result is \"empty\", meaning all pixels are fully transparent.\n */\nexport function clearColor(imageData: ImageData, color: IColor): boolean {\n let isEmpty = true;\n const r = color.rgba >>> 24;\n const g = color.rgba >>> 16 & 0xFF;\n const b = color.rgba >>> 8 & 0xFF;\n for (let offset = 0; offset < imageData.data.length; offset += 4) {\n if (imageData.data[offset] === r &&\n imageData.data[offset + 1] === g &&\n imageData.data[offset + 2] === b) {\n imageData.data[offset + 3] = 0;\n } else {\n isEmpty = false;\n }\n }\n return is Empty;\n}\n\nfunction getFont(fontWeight: FontWeight, config: ICharAtlasConfig): string {\n return `${fontWeight} ${config.fontSize * config.devicePixelRatio}px ${config.fontFamily}`;\n}\n","/**\n * Copyright (c) 2018 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, CHAR_DATA_WIDTH_INDEX } from '../../Buffer';\nimport { FLAGS } from '../Types';\nimport { IBufferLine } from '../../Types';\n\nexport const BOLD_CLASS = 'xterm-bold';\nexport const ITALIC_CLASS = 'xterm-italic';\nexport const CURSOR_CLASS = 'xterm-cursor';\nexport const CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block';\nexport const CURSOR_STYLE_BAR_CLASS = 'xterm-cursor-bar';\nexport const CURSOR_STYLE_UNDERLINE_CLASS = 'xterm-cursor-underline';\n\nexport class DomRendererRowFactory {\n constructor(\n private _document: Document\n ) {\n }\n\n public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursor X: number, cellWidth: number, cols: number): DocumentFragment {\n const fragment = this._document.createDocumentFragment();\n let colCount = 0;\n\n for (let x = 0; x < lineData.length; x++) {\n // Don't allow any buffer to the right to be displayed\n if (colCount >= cols) {\n continue;\n }\n\n const charData = lineData.get(x);\n const char: string = charData[CHAR_DATA_CHAR_INDEX];\n const attr: number = charData[CHAR_DATA_ATTR_INDEX];\n const width: number = charData[CHAR_DATA_WIDTH_INDEX];\n\n // The character to the left is a wide character, drawing is owned by the char at x-1\n if (width === 0) {\n continue;\n }\n\n const charElement = this._document.createElement('span');\n if (width > 1) {\n charElement.style.width = `${cellWidth * width}px`;\n }\n\n const flags = attr >> 18;\n let bg = attr & 0x1ff;\n let fg = (attr >> 9) & 0x1ff;\n\n if (isCursorRow && x === curs orX) {\n charElement.classList.add(CURSOR_CLASS);\n\n switch (cursorStyle) {\n case 'bar':\n charElement.classList.add(CURSOR_STYLE_BAR_CLASS);\n break;\n case 'underline':\n charElement.classList.add(CURSOR_STYLE_UNDERLINE_CLASS);\n break;\n default:\n charElement.classList.add(CURSOR_STYLE_BLOCK_CLASS);\n break;\n }\n }\n\n // If inverse flag is on, the foreground should become the background.\n if (flags & FLAGS.INVERSE) {\n const temp = bg;\n bg = fg;\n fg = temp;\n if (fg === 256) {\n fg = 0;\n }\n if (bg === 257) {\n bg = 15;\n }\n }\n\n if (flags & FLAGS.BOLD) {\n // Convert the FG color to the bold variant\n if (fg < 8) {\n fg += 8;\n }\n charElement.classList.add(BOLD_CLASS);\n }\n\n if (flags & FLAGS.ITALIC) {\n charE lement.classList.add(ITALIC_CLASS);\n }\n\n charElement.textContent = char;\n if (fg !== 257) {\n charElement.classList.add(`xterm-fg-${fg}`);\n }\n if (bg !== 256) {\n charElement.classList.add(`xterm-bg-${bg}`);\n }\n fragment.appendChild(charElement);\n colCount += width;\n }\n return fragment;\n }\n}\n","/**\n * Copyright (c) 2018 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { IRenderer, IRenderDimensions, IColorSet } from '../Types';\nimport { ILinkHoverEvent, ITerminal, CharacterJoinerHandler, LinkHoverEventTypes } from '../../Types';\nimport { ITheme } from 'xterm';\nimport { EventEmitter } from '../../common/EventEmitter';\nimport { ColorManager } from '../ColorManager';\nimport { RenderDebouncer } from '../../ui/RenderDebouncer';\nimport { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } fro m './DomRendererRowFactory';\n\nconst TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';\nconst ROW_CONTAINER_CLASS = 'xterm-rows';\nconst FG_CLASS_PREFIX = 'xterm-fg-';\nconst BG_CLASS_PREFIX = 'xterm-bg-';\nconst FOCUS_CLASS = 'xterm-focus';\nconst SELECTION_CLASS = 'xterm-selection';\n\nlet nextTerminalId = 1;\n\n// TODO: Pull into an addon when TS composite projects allow easier sharing of code (not just\n// interfaces) between core and addons\n\n/**\n * A fallback renderer for when canvas is slow. This is not meant to be\n * particularly fast or feature complete, more just stable and usable for when\n * canvas is not an option.\n */\nexport class DomRenderer extends EventEmitter implements IRenderer {\n private _renderDebouncer: RenderDebouncer;\n private _rowFactory: DomRendererRowFactory;\n private _terminalClass: number = nextTerminalId++;\n\n private _themeStyleElement: HTMLStyleElement;\n private _dimensionsStyleElement: HTMLStyleElement;\n private _rowContainer: H TMLElement;\n private _rowElements: HTMLElement[] = [];\n private _selectionContainer: HTMLElement;\n\n public dimensions: IRenderDimensions;\n public colorManager: ColorManager;\n\n constructor(private _terminal: ITerminal, theme: ITheme | undefined) {\n super();\n const allowTransparency = this._terminal.options.allowTransparency;\n this.colorManager = new ColorManager(document, allowTransparency);\n this.setTheme(theme);\n\n this._rowContainer = document.createElement('div');\n this._rowContainer.classList.add(ROW_CONTAINER_CLASS);\n this._rowContainer.style.lineHeight = 'normal';\n this._rowContainer.setAttribute('aria-hidden', 'true');\n this._refreshRowElements(this._terminal.cols, this._terminal.rows);\n this._selectionContainer = document.createElement('div');\n this._selectionContainer.classList.add(SELECTION_CLASS);\n this._selectionContainer.setAttribute('aria-hidden', 'true');\n\n this.dimensions = {\n scaledCharWidth: nul l,\n scaledCharHeight: null,\n scaledCellWidth: null,\n scaledCellHeight: null,\n scaledCharLeft: null,\n scaledCharTop: null,\n scaledCanvasWidth: null,\n scaledCanvasHeight: null,\n canvasWidth: null,\n canvasHeight: null,\n actualCellWidth: null,\n actualCellHeight: null\n };\n this._updateDimensions();\n\n this._renderDebouncer = new RenderDebouncer(this._terminal, this._renderRows.bind(this));\n this._rowFactory = new DomRendererRowFactory(document);\n\n this._terminal.element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass);\n this._terminal.screenElement.appendChild(this._rowContainer);\n this._terminal.screenElement.appendChild(this._selectionContainer);\n\n this._terminal.linkifier.on(LinkHoverEventTypes.HOVER, (e: ILinkHoverEvent) => this._onLinkHover(e));\n this._terminal.linkifier.on(LinkHoverEventTypes.LEAVE, (e: ILinkHoverEvent) => this._onLinkLeave(e));\n }\n\n public dispose (): void {\n this._terminal.element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass);\n this._terminal.screenElement.removeChild(this._rowContainer);\n this._terminal.screenElement.removeChild(this._selectionContainer);\n this._terminal.screenElement.removeChild(this._themeStyleElement);\n this._terminal.screenElement.removeChild(this._dimensionsStyleElement);\n super.dispose();\n }\n\n private _updateDimensions(): void {\n this.dimensions.scaledCharWidth = this._terminal.charMeasure.width * window.devicePixelRatio;\n this.dimensions.scaledCharHeight = this._terminal.charMeasure.height * window.devicePixelRatio;\n this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth;\n this.dimensions.scaledCellHeight = this.dimensions.scaledCharHeight;\n this.dimensions.scaledCharLeft = 0;\n this.dimensions.scaledCharTop = 0;\n this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._terminal.cols;\n this.dimen sions.scaledCanvasHeight = this.dimensions.scaledCellHeight * this._terminal.rows;\n this.dimensions.canvasWidth = this._terminal.charMeasure.width * this._terminal.cols;\n this.dimensions.canvasHeight = this._terminal.charMeasure.height * this._terminal.rows;\n this.dimensions.actualCellWidth = this._terminal.charMeasure.width;\n this.dimensions.actualCellHeight = this._terminal.charMeasure.height;\n\n this._rowElements.forEach(element => {\n element.style.width = `${this.dimensions.canvasWidth}px`;\n element.style.height = `${this._terminal.charMeasure.height}px`;\n });\n\n if (!this._dimensionsStyleElement) {\n this._dimensionsStyleElement = document.createElement('style');\n this._terminal.screenElement.appendChild(this._dimensionsStyleElement);\n }\n\n const styles =\n `${this._terminalSelector} .${ROW_CONTAINER_CLASS} span {` +\n ` display: inline-block;` +\n ` height: 100%;` +\n ` vertical-align: top;` +\n ` width: ${this._terminal.charMeasure.width}px` +\n `}`;\n\n this._dimensionsStyleElement.innerHTML = styles;\n\n this._selectionContainer.style.height = (<any>this._terminal)._viewportElement.style.height;\n this._rowContainer.style.width = `${this.dimensions.canvasWidth}px`;\n this._rowContainer.style.height = `${this.dimensions.canvasHeight}px`;\n }\n\n public setTheme(theme: ITheme | undefined): IColorSet {\n if (theme) {\n this.colorManager.setTheme(theme);\n }\n\n if (!this._themeStyleElement) {\n this._themeStyleElement = document.createElement('style');\n this._terminal.screenElement.appendChild(this._themeStyleElement);\n }\n\n // Base CSS\n let styles =\n `${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +\n ` color: ${this.colorManager.colors.foreground.css};` +\n ` background-color: ${this.colorManager.colors.background.css};` +\n ` font-family: ${this._terminal.getOption('f ontFamily')};` +\n ` font-size: ${this._terminal.getOption('fontSize')}px;` +\n `}`;\n // Text styles\n styles +=\n `${this._terminalSelector} span:not(.${BOLD_CLASS}) {` +\n ` font-weight: ${this._terminal.options.fontWeight};` +\n `}` +\n `${this._terminalSelector} span.${BOLD_CLASS} {` +\n ` font-weight: ${this._terminal.options.fontWeightBold};` +\n `}` +\n `${this._terminalSelector} span.${ITALIC_CLASS} {` +\n ` font-style: italic;` +\n `}`;\n // Cursor\n styles +=\n `${this._terminalSelector} .${ROW_CONTAINER_CLASS}:not(.${FOCUS_CLASS}) .${CURSOR_CLASS} {` +\n ` outline: 1px solid ${this.colorManager.colors.cursor.css};` +\n ` outline-offset: -1px;` +\n `}` +\n `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BLOCK_CLASS} {` +\n ` background-color: ${this.colorManager.colors.cursor.css};` +\n ` color: ${this.colorManager.colors.cursorAccent.css};` +\n `}` +\n `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_BAR_CLASS} {` +\n ` box-shadow: 1px 0 0 ${this.colorManager.colors.cursor.css} inset;` +\n `}` +\n `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${CURSOR_CLASS}.${CURSOR_STYLE_UNDERLINE_CLASS} {` +\n ` box-shadow: 0 -1px 0 ${this.colorManager.colors.cursor.css} inset;` +\n `}`;\n // Selection\n styles +=\n `${this._terminalSelector} .${SELECTION_CLASS} {` +\n ` position: absolute;` +\n ` top: 0;` +\n ` left: 0;` +\n ` z-index: 1;` +\n ` pointer-events: none;` +\n `}` +\n `${this._terminalSelector} .${SELECTION_CLASS} div {` +\n ` position: absolute;` +\n ` background-color: ${this.colorManager.colors.selection.css};` +\n `}`;\n // Colors\n this.colorManager.colors .ansi.forEach((c, i) => {\n styles +=\n `${this._terminalSelector} .${FG_CLASS_PREFIX}${i} { color: ${c.css}; }` +\n `${this._terminalSelector} .${BG_CLASS_PREFIX}${i} { background-color: ${c.css}; }`;\n });\n\n this._themeStyleElement.innerHTML = styles;\n return this.colorManager.colors;\n }\n\n public onWindowResize(devicePixelRatio: number): void {\n this._updateDimensions();\n }\n\n private _refreshRowElements(cols: number, rows: number): void {\n // Add missing elements\n for (let i = this._rowElements.length; i <= rows; i++) {\n const row = document.createElement('div');\n this._rowContainer.appendChild(row);\n this._rowElements.push(row);\n }\n // Remove excess elements\n while (this._rowElements.length > rows) {\n this._rowContainer.removeChild(this._rowElements.pop());\n }\n }\n\n public onResize(cols: number, rows: number): void {\n this._refreshRowElements(cols, rows);\n this._updateDime nsions();\n }\n\n public onCharSizeChanged(): void {\n this._updateDimensions();\n }\n\n public onBlur(): void {\n this._rowContainer.classList.remove(FOCUS_CLASS);\n }\n\n public onFocus(): void {\n this._rowContainer.classList.add(FOCUS_CLASS);\n }\n\n public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void {\n // Remove all selections\n while (this._selectionContainer.children.length) {\n this._selectionContainer.removeChild(this._selectionContainer.children[0]);\n }\n\n // Selection does not exist\n if (!start || !end) {\n return;\n }\n\n // Translate from buffer position to viewport position\n const viewportStartRow = start[1] - this._terminal.buffer.ydisp;\n const viewportEndRow = end[1] - this._terminal.buffer.ydisp;\n const viewportCappedStartRow = Math.max(viewportStartRow, 0);\n const viewportCappedEndRow = Math.min(viewportEndRow, this._terminal.rows - 1);\n\n // No need to draw the selection\n if (viewportCappedStartRow >= this._terminal.rows || viewportCappedEndRow < 0) {\n return;\n }\n\n // Create the selections\n const documentFragment = document.createDocumentFragment();\n\n if (columnSelectMode) {\n documentFragment.appendChild(\n this._createSelectionElement(viewportCappedStartRow, start[0], end[0], viewportCappedEndRow - viewportCappedStartRow + 1)\n );\n } else {\n // Draw first row\n const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;\n const endCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : this._terminal.cols;\n documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));\n // Draw middle rows\n const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;\n documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._term inal.cols, middleRowsCount));\n // Draw final row\n if (viewportCappedStartRow !== viewportCappedEndRow) {\n // Only draw viewportEndRow if it's not the same as viewporttartRow\n const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._terminal.cols;\n documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol));\n }\n }\n this._selectionContainer.appendChild(documentFragment);\n }\n\n /**\n * Creates a selection element at the specified position.\n * @param row The row of the selection.\n * @param colStart The start column.\n * @param colEnd The end columns.\n */\n private _createSelectionElement(row: number, colStart: number, colEnd: number, rowCount: number = 1): HTMLElement {\n const element = document.createElement('div');\n element.style.height = `${rowCount * this._terminal.charMeasure.height}px`;\n element.style.top = `${row * this._terminal.charMeasure.height}px`;\n element.style.left = `${colStart * this._terminal.charMeasure.width}px`;\n element.style.width = `${this._terminal.charMeasure.width * (colEnd - colStart)}px`;\n return element;\n }\n\n public onCursorMove(): void {\n // No-op, the cursor is drawn when rows are drawn\n }\n\n public onOptionsChanged(): void {\n // Force a refresh\n this._updateDimensions();\n this.setTheme(undefined);\n this._terminal.refresh(0, this._terminal.rows - 1);\n }\n\n public clear(): void {\n this._rowElements.forEach(e => e.innerHTML = '');\n }\n\n public refreshRows(start: number, end: number): void {\n this._renderDebouncer.refresh(start, end);\n }\n\n private _renderRows(start: number, end: number): void {\n const terminal = this._terminal;\n\n const cursorAbsoluteY = terminal.buffer.ybase + terminal.buffer.y;\n const cursorX = this._terminal.buffer.x;\n\n for (let y = start; y <= end; y++) {\n const rowElement = this._rowElements[y];\n row Element.innerHTML = '';\n\n const row = y + terminal.buffer.ydisp;\n const lineData = terminal.buffer.lines.get(row);\n const cursorStyle = terminal.options.cursorStyle;\n rowElement.appendChild(this._rowFactory.createRow(lineData, row === cursorAbsoluteY, cursorStyle, cursorX, terminal.charMeasure.width, terminal.cols));\n }\n\n this._terminal.emit('refresh', {start, end});\n }\n\n private get _terminalSelector(): string {\n return `.${TERMINAL_CLASS_PREFIX}${this._terminalClass}`;\n }\n\n public registerCharacterJoiner(handler: CharacterJoinerHandler): number { return -1; }\n public deregisterCharacterJoiner(joinerId: number): boolean { return false; }\n\n private _onLinkHover(e: ILinkHoverEvent): void {\n this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, true);\n }\n\n private _onLinkLeave(e: ILinkHoverEvent): void {\n this._setCellUnderline(e.x1, e.x2, e.y1, e.y2, e.cols, false);\n }\n\n private _setCellUnderline(x: number, x2: n umber, y: number, y2: number, cols: number, enabled: boolean): void {\n while (x !== x2 || y !== y2) {\n const span = <HTMLElement>this._rowElements[y].children[x];\n span.style.textDecoration = enabled ? 'underline' : 'none';\n x = (x + 1) % cols;\n if (x === 0) {\n y++;\n }\n }\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nexport const INVERTED_DEFAULT_COLOR = -1;\nexport const DIM_OPACITY = 0.5;\n\nexport interface IGlyphIdentifier {\n chars: string;\n code: number;\n bg: number;\n fg: number;\n bold: boolean;\n dim: boolean;\n italic: boolean;\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { DIM_OPACITY, IGlyphIdentifier } from './Types';\nimport { CHAR_ATLAS_CELL_SPACING, ICharAtlasConfig } from '../../shared/atlas/Types';\nimport { generateStaticCharAtlasTexture } from '../../shared/atlas/CharAtlasGenerator';\ni mport BaseCharAtlas from './BaseCharAtlas';\n\nexport default class StaticCharAtlas extends BaseCharAtlas {\n private _texture: HTMLCanvasElement | ImageBitmap;\n\n constructor(private _document: Document, private _config: ICharAtlasConfig) {\n super();\n }\n\n private _canvasFactory = (width: number, height: number) => {\n const canvas = this._document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n // This is useful for debugging\n // document.body.appendChild(canvas);\n\n return canvas;\n }\n\n protected _doWarmUp(): void {\n const result = generateStaticCharAtlasTexture(window, this._canvasFactory, this._config);\n if (result instanceof HTMLCanvasElement) {\n this._texture = result;\n } else {\n result.then(texture => {\n this._texture = texture;\n });\n }\n }\n\n private _isCached(glyph: IGlyphIdentifier, colorIndex: number): boolean {\n const isAscii = glyph.code < 256;\n // A c olor is basic if it is one of the 4 bit ANSI colors.\n const isBasicColor = glyph.fg < 16;\n const isDefaultColor = glyph.fg >= 256;\n const isDefaultBackground = glyph.bg >= 256;\n return isAscii && (isBasicColor || isDefaultColor) && isDefaultBackground && !glyph.italic;\n }\n\n public draw(\n ctx: CanvasRenderingContext2D,\n glyph: IGlyphIdentifier,\n x: number,\n y: number\n ): boolean {\n // we're not warmed up yet\n if (this._texture === null || this._texture === undefined) {\n return false;\n }\n\n let colorIndex = 0;\n if (glyph.fg < 256) {\n colorIndex = 2 + glyph.fg + (glyph.bold ? 16 : 0);\n } else {\n // If default color and bold\n if (glyph.bold) {\n colorIndex = 1;\n }\n }\n if (!this._isCached(glyph, colorIndex)) {\n return false;\n }\n\n ctx.save();\n\n // ImageBitmap's draw about twice as fast as from a canvas\n const charAtlasCellWidth = this._config.scaledCharWidth + CHAR_ATLAS_CELL_SPACING;\n const charAtlasCellHeight = this._config.scaledCharHeight + CHAR_ATLAS_CELL_SPACING;\n\n // Apply alpha to dim the character\n if (glyph.dim) {\n ctx.globalAlpha = DIM_OPACITY;\n }\n\n ctx.drawImage(\n this._texture,\n glyph.code * charAtlasCellWidth,\n colorIndex * charAtlasCellHeight,\n charAtlasCellWidth,\n this._config.scaledCharHeight,\n x,\n y,\n charAtlasCellWidth,\n this._config.scaledCharHeight\n );\n\n ctx.restore();\n\n return true;\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * A dummy CharAtlas implementation that always fails to draw characters.\n */\n\nimport { IGlyphIdentifier } from './Types';\nimport { ICharAtlasConfig } from '../../shared/atlas/Types';\nimport BaseCharAtlas from './BaseCharAtlas';\n\nexport default class NoneCharAtlas extends BaseCharAtlas {\n constructor(document: Document, config: ICh arAtlasConfig) {\n super();\n }\n\n public draw(\n ctx: CanvasRenderingContext2D,\n glyph: IGlyphIdentifier,\n x: number,\n y: number\n ): boolean {\n return false;\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\ninterface ILinkedListNode<T> {\n prev: ILinkedListNode<T>;\n next: ILinkedListNode<T>;\n key: number;\n value: T;\n}\n\nexport default class LRUMap<T> {\n private _map: { [key: number]: ILinkedListNode<T> } = {};\n private _head: ILinkedListNode<T> = null;\n private _tail: ILinkedListNode<T> = null;\n private _nodePool: ILinkedListNode<T>[] = [];\n public size: number = 0;\n\n constructor(public capacity: number) { }\n\n private _unlinkNode(node: ILinkedListNode<T>): void {\n const prev = node.prev;\n const next = node.next;\n if (node === this._head) {\n this._head = next;\n }\n if (node === this._tail) {\n this._tail = prev;\n }\n if (prev !== null) {\ n prev.next = next;\n }\n if (next !== null) {\n next.prev = prev;\n }\n }\n\n private _appendNode(node: ILinkedListNode<T>): void {\n const tail = this._tail;\n if (tail !== null) {\n tail.next = node;\n }\n node.prev = tail;\n node.next = null;\n this._tail = node;\n if (this._head === null) {\n this._head = node;\n }\n }\n\n /**\n * Preallocate a bunch of linked-list nodes. Allocating these nodes ahead of time means that\n * they're more likely to live next to each other in memory, which seems to improve performance.\n *\n * Each empty object only consumes about 60 bytes of memory, so this is pretty cheap, even for\n * large maps.\n */\n public prealloc(count: number): void {\n const nodePool = this._nodePool;\n for (let i = 0; i < count; i++) {\n nodePool.push({\n prev: null,\n next: null,\n key: null,\n value: null\n });\n }\n }\n\n public get(key: number): T | null {\n // This is unsafe: We're assuming our keyspace doesn't overlap with Object.prototype. However,\n // it's faster than calling hasOwnProperty, and in our case, it would never overlap.\n const node = this._map[key];\n if (node !== undefined) {\n this._unlinkNode(node);\n this._appendNode(node);\n return node.value;\n }\n return null;\n }\n\n /**\n * Gets a value from a key without marking it as the most recently used item.\n */\n public peekValue(key: number): T | null {\n const node = this._map[key];\n if (node !== undefined) {\n return node.value;\n }\n return null;\n }\n\n public peek(): T | null {\n const head = this._head;\n return head === null ? null : head.value;\n }\n\n public set(key: number, value: T): void {\n // This is unsafe: See note above.\n let node = this._map[key];\n if (node !== undefined) {\n // already exists, we just need to mutate it and move it to the end of the list\n node = this._map[key];\n this._unlinkNode(node);\n node.value = value;\n } else if (this.size >= this.capacity) {\n // we're out of space: recycle the head node, move it to the tail\n node = this._head;\n this._unlinkNode(node);\n delete this._map[node.key];\n node.key = key;\n node.value = value;\n this._map[key] = node;\n } else {\n // make a new element\n const nodePool = this._nodePool;\n if (nodePool.length > 0) {\n // use a preallocated node if we can\n node = nodePool.pop();\n node.key = key;\n node.value = value;\n } else {\n node = {\n prev: null,\n next: null,\n key,\n value\n };\n }\n this._map[key] = node;\n this.size++;\n }\n this._appendNode(node);\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { DIM_OPACITY, IGlyphIdentifier, INVER TED_DEFAULT_COLOR } from './Types';\nimport { ICharAtlasConfig } from '../../shared/atlas/Types';\nimport { IColor } from '../../shared/Types';\nimport BaseCharAtlas from './BaseCharAtlas';\nimport { DEFAULT_ANSI_COLORS } from '../ColorManager';\nimport { clearColor } from '../../shared/atlas/CharAtlasGenerator';\nimport LRUMap from './LRUMap';\nimport { isFirefox, isSafari } from '../../shared/utils/Browser';\n\n// In practice we're probably never going to exhaust a texture this large. For debugging purposes,\n// however, it can be useful to set this to a really tiny value, to verify that LRU eviction works.\nconst TEXTURE_WIDTH = 1024;\nconst TEXTURE_HEIGHT = 1024;\n\nconst TRANSPARENT_COLOR = {\n css: 'rgba(0, 0, 0, 0)',\n rgba: 0\n};\n\n// Drawing to the cache is expensive: If we have to draw more than this number of glyphs to the\n// cache in a single frame, give up on trying to cache anything else, and try to finish the current\n// frame ASAP.\n//\n// This helps to limit the amount of damage a program can do when it would otherwise thrash the\n// cache.\nconst FRAME_CACHE_DRAW_LIMIT = 100;\n\n/**\n * The number of milliseconds to wait before generating the ImageBitmap, this is to debounce/batch\n * the operation as window.createImageBitmap is asynchronous.\n */\nconst GLYPH_BITMAP_COMMIT_DELAY = 100;\n\ninterface IGlyphCacheValue {\n index: number;\n isEmpty: boolean;\n inBitmap: boolean;\n}\n\nfunction getGlyphCacheKey(glyph: IGlyphIdentifier): number {\n // Note that this only returns a valid key when code < 256\n // Layout:\n // 0b00000000000000000000000000000001: italic (1)\n // 0b00000000000000000000000000000010: dim (1)\n // 0b00000000000000000000000000000100: bold (1)\n // 0b00000000000000000000111111111000: fg (9)\n // 0b00000000000111111111000000000000: bg (9)\n // 0b00011111111000000000000000000000: code (8)\n // 0b11100000000000000000000000000000: unused (3)\n return glyph.code << 21 | glyph.bg << 12 | glyph.fg << 3 | (glyph.bol d ? 0 : 4) + (glyph.dim ? 0 : 2) + (glyph.italic ? 0 : 1);\n}\n\nexport default class DynamicCharAtlas extends BaseCharAtlas {\n // An ordered map that we're using to keep track of where each glyph is in the atlas texture.\n // It's ordered so that we can determine when to remove the old entries.\n private _cacheMap: LRUMap<IGlyphCacheValue>;\n\n // The texture that the atlas is drawn to\n private _cacheCanvas: HTMLCanvasElement;\n private _cacheCtx: CanvasRenderingContext2D;\n\n // A temporary context that glyphs are drawn to before being transfered to the atlas.\n private _tmpCtx: CanvasRenderingContext2D;\n\n // The number of characters stored in the atlas by width/height\n private _width: number;\n private _height: number;\n\n private _drawToCacheCount: number = 0;\n\n // An array of glyph keys that are waiting on the bitmap to be generated.\n private _glyphsWaitingOnBitmap: IGlyphCacheValue[] = [];\n\n // The timeout that is used to batch bitmap generation so it' s not requested for every new glyph.\n private _bitmapCommitTimeout: number | null = null;\n\n // The bitmap to draw from, this is much faster on other browsers than others.\n private _bitmap: ImageBitmap | null = null;\n\n constructor(document: Document, private _config: ICharAtlasConfig) {\n super();\n this._cacheCanvas = document.createElement('canvas');\n this._cacheCanvas.width = TEXTURE_WIDTH;\n this._cacheCanvas.height = TEXTURE_HEIGHT;\n // The canvas needs alpha because we use clearColor to convert the background color to alpha.\n // It might also contain some characters with transparent backgrounds if allowTransparency is\n // set.\n this._cacheCtx = this._cacheCanvas.getContext('2d', {alpha: true});\n\n const tmpCanvas = document.createElement('canvas');\n tmpCanvas.width = this._config.scaledCharWidth;\n tmpCanvas.height = this._config.scaledCharHeight;\n this._tmpCtx = tmpCanvas.getContext('2d', {alpha: this._config.allowTranspare ncy});\n\n this._width = Math.floor(TEXTURE_WIDTH / this._config.scaledCharWidth);\n this._height = Math.floor(TEXTURE_HEIGHT / this._config.scaledCharHeight);\n const capacity = this._width * this._height;\n this._cacheMap = new LRUMap(capacity);\n this._cacheMap.prealloc(capacity);\n\n // This is useful for debugging\n // document.body.appendChild(this._cacheCanvas);\n }\n\n public dispose(): void {\n if (this._bitmapCommitTimeout !== null) {\n window.clearTimeout(this._bitmapCommitTimeout);\n this._bitmapCommitTimeout = null;\n }\n }\n\n public beginFrame(): void {\n this._drawToCacheCount = 0;\n }\n\n public draw(\n ctx: CanvasRenderingContext2D,\n glyph: IGlyphIdentifier,\n x: number,\n y: number\n ): boolean {\n // Space is always an empty cell, special case this as it's so common\n if (glyph.code === 32) {\n return true;\n }\n\n const glyphKey = getGlyphCacheKey(glyph);\n const cacheValue = this._c acheMap.get(glyphKey);\n if (cacheValue !== null && cacheValue !== undefined) {\n this._drawFromCache(ctx, cacheValue, x, y);\n return true;\n } else if (this._canCache(glyph) && this._drawToCacheCount < FRAME_CACHE_DRAW_LIMIT) {\n let index;\n if (this._cacheMap.size < this._cacheMap.capacity) {\n index = this._cacheMap.size;\n } else {\n // we're out of space, so our call to set will delete this item\n index = this._cacheMap.peek().index;\n }\n const cacheValue = this._drawToCache(glyph, index);\n this._cacheMap.set(glyphKey, cacheValue);\n this._drawFromCache(ctx, cacheValue, x, y);\n return true;\n }\n return false;\n }\n\n private _canCache(glyph: IGlyphIdentifier): boolean {\n // Only cache ascii and extended characters for now, to be safe. In the future, we could do\n // something more complicated to determine the expected width of a character.\n //\n // If we switch the renderer over to webgl at some point, we may be able to use blending modes\n // to draw overlapping glyphs from the atlas:\n // https://github.com/servo/webrender/issues/464#issuecomment-255632875\n // https://webglfundamentals.org/webgl/lessons/webgl-text-texture.html\n return glyph.code < 256;\n }\n\n private _toCoordinateX(index: number): number {\n return (index % this._width) * this._config.scaledCharWidth;\n }\n\n private _toCoordinateY(index: number): number {\n return Math.floor(index / this._width) * this._config.scaledCharHeight;\n }\n\n private _drawFromCache(\n ctx: CanvasRenderingContext2D,\n cacheValue: IGlyphCacheValue,\n x: number,\n y: number\n ): void {\n // We don't actually need to do anything if this is whitespace.\n if (cacheValue.isEmpty) {\n return;\n }\n const cacheX = this._toCoordinateX(cacheValue.index);\n const cacheY = this._toCoordinateY(cacheValue.index);\n ctx.drawImage(\n cacheValue.inBitmap ? this._bitmap : this._cacheCanvas,\n cacheX,\n cacheY,\n this._config.scaledCharWidth,\n this._config.scaledCharHeight,\n x,\n y,\n this._config.scaledCharWidth,\n this._config.scaledCharHeight\n );\n }\n\n private _getColorFromAnsiIndex(idx: number): IColor {\n if (idx < this._config.colors.ansi.length) {\n return this._config.colors.ansi[idx];\n }\n return DEFAULT_ANSI_COLORS[idx];\n }\n\n private _getBackgroundColor(glyph: IGlyphIdentifier): IColor {\n if (this._config.allowTransparency) {\n // The background color might have some transparency, so we need to render it as fully\n // transparent in the atlas. Otherwise we'd end up drawing the transparent background twice\n // around the anti-aliased edges of the glyph, and it would look too dark.\n return TRANSPARENT_COLOR;\n } else if (glyph.bg === INVERTED_DEFAULT_COLOR) {\n return this._config.colors.foreground;\n } else if (glyph.bg < 256) {\n return this._getColorFromAnsiIndex(glyph.bg);\n }\n return this._config.colors.background;\n }\n\n private _getForegroundColor(glyph: IGlyphIdentifier): IColor {\n if (glyph.fg === INVERTED_DEFAULT_COLOR) {\n return this._config.colors.background;\n } else if (glyph.fg < 256) {\n // 256 color support\n return this._getColorFromAnsiIndex(glyph.fg);\n }\n return this._config.colors.foreground;\n }\n\n // TODO: We do this (or something similar) in multiple places. We should split this off\n // into a shared function.\n private _drawToCache(glyph: IGlyphIdentifier, index: number): IGlyphCacheValue {\n this._drawToCacheCount++;\n\n this._tmpCtx.save();\n\n // draw the background\n const backgroundColor = this._getBackgroundColor(glyph);\n // Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, regardless of\n // transparency in backgroundColor\n this._tmpCtx.globalCompositeOperation = 'copy';\n this._tmpCtx.fillStyle = backgroundColor.css;\n this._tmpCtx.fillRect(0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight);\n this._tmpCtx.globalCompositeOperation = 'source-over';\n\n // draw the foreground/glyph\n const fontWeight = glyph.bold ? this._config.fontWeightBold : this._config.fontWeight;\n const fontStyle = glyph.italic ? 'italic' : '';\n this._tmpCtx.font =\n `${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`;\n this._tmpCtx.textBaseline = 'top';\n\n this._tmpCtx.fillStyle = this._getForegroundColor(glyph).css;\n\n // Apply alpha to dim the character\n if (glyph.dim) {\n this._tmpCtx.globalAlpha = DIM_OPACITY;\n }\n // Draw the character\n this._tmpCtx.fillText(glyph.chars, 0, 0);\n this._tmpCtx.restore();\n\n // clear the background from the character to avoid issues with drawing over the previous\n // character if it extends past it's bounds\n const imageData = this._tmpCtx.getImageData(\n 0, 0, this._config.scaledCharWidth, this._config.scaledCharHeight\n );\n let isEmpty = false;\n if (!this._config.allowTransparency) {\n isEmpty = clearColor(imageData, backgroundColor);\n }\n\n // copy the data from imageData to _cacheCanvas\n const x = this._toCoordinateX(index);\n const y = this._toCoordinateY(index);\n // putImageData doesn't do any blending, so it will overwrite any existing cache entry for us\n this._cacheCtx.putImageData(imageData, x, y);\n\n // Add the glyph and queue it to the bitmap (if the browser supports it)\n const cacheValue = {\n index,\n isEmpty,\n inBitmap: false\n };\n this._addGlyphToBitmap(cacheValue);\n\n return cacheValue;\n }\n\n private _addGlyphToBitmap(cacheValue: IGlyphCacheValue): void {\n // Support is patchy for createImageBitmap at the moment, pass a canvas back\n // if support is lac king as drawImage works there too. Firefox is also\n // included here as ImageBitmap appears both buggy and has horrible\n // performance (tested on v55).\n if (!('createImageBitmap' in window) || isFirefox || isSafari) {\n return;\n }\n\n // Add the glyph to the queue\n this._glyphsWaitingOnBitmap.push(cacheValue);\n\n // Check if bitmap generation timeout already exists\n if (this._bitmapCommitTimeout !== null) {\n return;\n }\n\n this._bitmapCommitTimeout = window.setTimeout(() => this._generateBitmap(), GLYPH_BITMAP_COMMIT_DELAY);\n }\n\n private _generateBitmap(): void {\n const glyphsMovingToBitmap = this._glyphsWaitingOnBitmap;\n this._glyphsWaitingOnBitmap = [];\n window.createImageBitmap(this._cacheCanvas).then(bitmap => {\n // Set bitmap\n this._bitmap = bitmap;\n\n // Mark all new glyphs as in bitmap, excluding glyphs that came in after\n // the bitmap was requested\n for (let i = 0; i < glyphsMov ingToBitmap.length; i++) {\n const value = glyphsMovingToBitmap[i];\n // It doesn't matter if the value was already evicted, it will be\n // released from memory after this block if so.\n value.inBitmap = true;\n }\n });\n this._bitmapCommitTimeout = null;\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ITerminal } from '../../Types';\nimport { IColorSet } from '../Types';\nimport { ICharAtlasConfig } from '../../shared/atlas/Types';\n\nexport function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: ITerminal, colors: IColorSet): ICharAtlasConfig {\n // null out some fields that don't matter\n const clonedColors = <IColorSet>{\n foreground: colors.foreground,\n background: colors.background,\n cursor: null,\n cursorAccent: null,\n selection: null,\n // For the static char atlas, we only use the first 16 colors, but we need all 256 for the\n // dynamic character atlas.\n ansi: colors.ansi.slice(0, 16)\n };\n return {\n type: terminal.options.experimentalCharAtlas,\n devicePixelRatio: window.devicePixelRatio,\n scaledCharWidth,\n scaledCharHeight,\n fontFamily: terminal.options.fontFamily,\n fontSize: terminal.options.fontSize,\n fontWeight: terminal.options.fontWeight,\n fontWeightBold: terminal.options.fontWeightBold,\n allowTransparency: terminal.options.allowTransparency,\n colors: clonedColors\n };\n}\n\nexport function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean {\n for (let i = 0; i < a.colors.ansi.length; i++) {\n if (a.colors.ansi[i].rgba !== b.colors.ansi[i].rgba) {\n return false;\n }\n }\n return a.type === b.type &&\n a.devicePixelRatio === b.devicePixelRatio &&\n a.fontFamily === b.fontFamily &&\n a.fontSize === b.fontSize &&\n a.fontWeight === b.fontWeight &&\n a.fontWeightBold === b.fontWeightBold &&\n a.allowTransparency === b.allowTransparency &&\n a.scaledCharWidth === b.scaledCharWidth &&\n a.scaledCharHeight === b.scaledCharHeight &&\n a.colors.foreground === b.colors.foreground &&\n a.colors.background === b.colors.background;\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ITerminal } from '../../Types';\nimport { IColorSet } from '../Types';\nimport { ICharAtlasConfig } from '../../shared/atlas/Types';\nimport { generateConfig, configEquals } from './CharAtlasUtils';\nimport BaseCharAtlas from './BaseCharAtlas';\nimport DynamicCharAtlas from './DynamicCharAtlas';\nimport NoneCharAtlas from './NoneCharAtlas';\nimport StaticCharAtlas from './StaticCharAtlas';\n\nconst charAtlasImplementations = {\n 'none': NoneCharAtlas,\n 'static': StaticCharAtlas,\n 'dynamic': DynamicCharAtlas\n};\n\ninterface ICharAtlasCacheEntry {\n atlas: BaseCharAtlas;\n config: ICharAtlasConfig;\n // N.B . This implementation potentially holds onto copies of the terminal forever, so\n // this may cause memory leaks.\n ownedBy: ITerminal[];\n}\n\nconst charAtlasCache: ICharAtlasCacheEntry[] = [];\n\n/**\n * Acquires a char atlas, either generating a new one or returning an existing\n * one that is in use by another terminal.\n * @param terminal The terminal.\n * @param colors The colors to use.\n */\nexport function acquireCharAtlas(\n terminal: ITerminal,\n colors: IColorSet,\n scaledCharWidth: number,\n scaledCharHeight: number\n): BaseCharAtlas {\n const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors);\n\n // TODO: Currently if a terminal changes configs it will not free the entry reference (until it's disposed)\n\n // Check to see if the terminal already owns this config\n for (let i = 0; i < charAtlasCache.length; i++) {\n const entry = charAtlasCache[i];\n const ownedByIndex = entry.ownedBy.indexOf(terminal);\n if (ownedByIndex >= 0) {\n if (configEquals(entry.config, newConfig)) {\n return entry.atlas;\n }\n // The configs differ, release the terminal from the entry\n if (entry.ownedBy.length === 1) {\n charAtlasCache.splice(i, 1);\n } else {\n entry.ownedBy.splice(ownedByIndex, 1);\n }\n break;\n }\n }\n\n // Try match a char atlas from the cache\n for (let i = 0; i < charAtlasCache.length; i++) {\n const entry = charAtlasCache[i];\n if (configEquals(entry.config, newConfig)) {\n // Add the terminal to the cache entry and return\n entry.ownedBy.push(terminal);\n return entry.atlas;\n }\n }\n\n const newEntry: ICharAtlasCacheEntry = {\n atlas: new charAtlasImplementations[terminal.options.experimentalCharAtlas](\n document,\n newConfig\n ),\n config: newConfig,\n ownedBy: [terminal]\n };\n charAtlasCache.push(newEntry);\n return newEntry.atlas;\n}\n\n/**\n * Removes a terminal reference from t he cache, allowing its memory to be freed.\n * @param terminal The terminal to remove.\n */\nexport function removeTerminalFromCache(terminal: ITerminal): void {\n for (let i = 0; i < charAtlasCache.length; i++) {\n const index = charAtlasCache[i].ownedBy.indexOf(terminal);\n if (index !== -1) {\n if (charAtlasCache[i].ownedBy.length === 1) {\n // Remove the cache entry if it's the only terminal\n charAtlasCache.splice(i, 1);\n } else {\n // Remove the reference from the cache entry\n charAtlasCache[i].ownedBy.splice(index, 1);\n }\n break;\n }\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { IGlyphIdentifier } from './Types';\nimport { IDisposable } from 'xterm';\n\nexport default abstract class BaseCharAtlas implements IDisposable {\n private _didWarmUp: boolean = false;\n\n public dispose(): void { }\n\n /**\n * Perform any work needed to warm the cach e before it can be used. May be called multiple times.\n * Implement _doWarmUp instead if you only want to get called once.\n */\n public warmUp(): void {\n if (!this._didWarmUp) {\n this._doWarmUp();\n this._didWarmUp = true;\n }\n }\n\n /**\n * Perform any work needed to warm the cache before it can be used. Used by the default\n * implementation of warmUp(), and will only be called once.\n */\n protected _doWarmUp(): void { }\n\n /**\n * Called when we start drawing a new frame.\n *\n * TODO: We rely on this getting called by TextRenderLayer. This should really be called by\n * Renderer instead, but we need to make Renderer the source-of-truth for the char atlas, instead\n * of BaseRenderLayer.\n */\n public beginFrame(): void { }\n\n /**\n * May be called before warmUp finishes, however it is okay for the implementation to\n * do nothing and return false in that case.\n *\n * @param ctx Where to draw the character onto.\n * @param glyph Information about what to draw\n * @param x The position on the context to start drawing at\n * @param y The position on the context to start drawing at\n * @returns The success state. True if we drew the character.\n */\n public abstract draw(\n ctx: CanvasRenderingContext2D,\n glyph: IGlyphIdentifier,\n x: number,\n y: number\n ): boolean;\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { CHAR_DATA_ATTR_INDEX, CHAR_DATA_CODE_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_WIDTH_INDEX, NULL_CELL_CODE } from '../Buffer';\nimport { FLAGS, IColorSet, IRenderDimensions, ICharacterJoinerRegistry } from './Types';\nimport { CharData, ITerminal } from '../Types';\nimport { INVERTED_DEFAULT_COLOR } from './atlas/Types';\nimport { GridCache } from './GridCache';\nimport { BaseRenderLayer } from './BaseRenderLayer';\n\n/**\n * This CharData looks like a null character, which will forc a clear and render\n * when the character changes (a regular space ' ' character may not as it's\n * drawn state is a cleared cell).\n */\n// const OVERLAP_OWNED_CHAR_DATA: CharData = [null, '', 0, -1];\n\nexport class TextRenderLayer extends BaseRenderLayer {\n private _state: GridCache<CharData>;\n private _characterWidth: number;\n private _characterFont: string;\n private _characterOverlapCache: { [key: string]: boolean } = {};\n private _characterJoinerRegistry: ICharacterJoinerRegistry;\n\n constructor(container: HTMLElement, zIndex: number, colors: IColorSet, characterJoinerRegistry: ICharacterJoinerRegistry, alpha: boolean) {\n super(container, 'text', zIndex, alpha, colors);\n this._state = new GridCache<CharData>();\n this._characterJoinerRegistry = characterJoinerRegistry;\n }\n\n public resize(terminal: ITerminal, dim: IRenderDimensions): void {\n super.resize(terminal, dim);\n\n // Clear the character width cache if the font or width has changed\n const terminalFon t = this._getFont(terminal, false, false);\n if (this._characterWidth !== dim.scaledCharWidth || this._characterFont !== terminalFont) {\n this._characterWidth = dim.scaledCharWidth;\n this._characterFont = terminalFont;\n this._characterOverlapCache = {};\n }\n // Resizing the canvas discards the contents of the canvas so clear state\n this._state.clear();\n this._state.resize(terminal.cols, terminal.rows);\n }\n\n public reset(terminal: ITerminal): void {\n this._state.clear();\n this.clearAll();\n }\n\n private _forEachCell(\n terminal: ITerminal,\n firstRow: number,\n lastRow: number,\n joinerRegistry: ICharacterJoinerRegistry | null,\n callback: (\n code: number,\n chars: string,\n width: number,\n x: number,\n y: number,\n fg: number,\n bg: number,\n flags: number\n ) => void\n ): void {\n for (let y = firstRow; y <= lastRow; y++) {\n const row = y + terminal.buffer.ydisp ;\n const line = terminal.buffer.lines.get(row);\n const joinedRanges = joinerRegistry ? joinerRegistry.getJoinedCharacters(row) : [];\n for (let x = 0; x < terminal.cols; x++) {\n const charData = line.get(x);\n let code: number = <number>charData[CHAR_DATA_CODE_INDEX];\n\n // Can either represent character(s) for a single cell or multiple cells\n // if indicated by a character joiner.\n let chars: string = charData[CHAR_DATA_CHAR_INDEX];\n const attr: number = charData[CHAR_DATA_ATTR_INDEX];\n let width: number = charData[CHAR_DATA_WIDTH_INDEX];\n\n // If true, indicates that the current character(s) to draw were joined.\n let isJoined = false;\n let lastCharX = x;\n\n // The character to the left is a wide character, drawing is owned by\n // the char at x-1\n if (width === 0) {\n continue;\n }\n\n // Process any joined character ranges as needed. Becaus e of how the\n // ranges are produced, we know that they are valid for the characters\n // and attributes of our input.\n if (joinedRanges.length > 0 && x === joinedRanges[0][0]) {\n isJoined = true;\n const range = joinedRanges.shift();\n\n // We already know the exact start and end column of the joined range,\n // so we get the string and width representing it directly\n chars = terminal.buffer.translateBufferLineToString(\n row,\n true,\n range[0],\n range[1]\n );\n width = range[1] - range[0];\n code = Infinity;\n\n // Skip over the cells occupied by this range in the loop\n lastCharX = range[1] - 1;\n }\n\n // If the character is an overlapping char and the character to the\n // right is a space, take ownership of the cell to the right. We skip\n // this check for joined characters because their re ndering likely won't\n // yield the same result as rendering the last character individually.\n if (!isJoined && this._isOverlapping(charData)) {\n // If the character is overlapping, we want to force a re-render on every\n // frame. This is specifically to work around the case where two\n // overlaping chars `a` and `b` are adjacent, the cursor is moved to b and a\n // space is added. Without this, the first half of `b` would never\n // get removed, and `a` would not re-render because it thinks it's\n // already in the correct state.\n // this._state.cache[x][y] = OVERLAP_OWNED_CHAR_DATA;\n if (lastCharX < line.length - 1 && line.get(lastCharX + 1)[CHAR_DATA_CODE_INDEX] === NULL_CELL_CODE) {\n width = 2;\n // this._clearChar(x + 1, y);\n // The overlapping char's char data will force a clear and render when the\n // overlapping char is no longer to the l eft of the character and also when\n // the space changes to another character.\n // this._state.cache[x + 1][y] = OVERLAP_OWNED_CHAR_DATA;\n }\n }\n\n const flags = attr >> 18;\n let bg = attr & 0x1ff;\n let fg = (attr >> 9) & 0x1ff;\n\n // If inverse flag is on, the foreground should become the background.\n if (flags & FLAGS.INVERSE) {\n const temp = bg;\n bg = fg;\n fg = temp;\n if (fg === 256) {\n fg = INVERTED_DEFAULT_COLOR;\n }\n if (bg === 257) {\n bg = INVERTED_DEFAULT_COLOR;\n }\n }\n\n callback(\n code,\n chars,\n width,\n x,\n y,\n fg,\n bg,\n flags\n );\n\n x = lastCharX;\n }\n }\n }\n\n /**\n * Draws the background for a specified range of columns. Tries to batch adjacent cells of the\n * same color to gether to reduce draw calls.\n */\n private _drawBackground(terminal: ITerminal, firstRow: number, lastRow: number): void {\n const ctx = this._ctx;\n const cols = terminal.cols;\n let startX: number = 0;\n let startY: number = 0;\n let prevFillStyle: string | null = null;\n\n ctx.save();\n\n this._forEachCell(terminal, firstRow, lastRow, null, (code, chars, width, x, y, fg, bg, flags) => {\n // libvte and xterm both draw the background (but not foreground) of invisible characters,\n // so we should too.\n let nextFillStyle = null; // null represents default background color\n if (bg === INVERTED_DEFAULT_COLOR) {\n nextFillStyle = this._colors.foreground.css;\n } else if (bg < 256) {\n nextFillStyle = this._colors.ansi[bg].css;\n }\n\n if (prevFillStyle === null) {\n // This is either the first iteration, or the default background was set. Either way, we\n // don't need to draw anything.\n startX = x;\n startY = y;\n } if (y !== startY) {\n // our row changed, draw the previous row\n ctx.fillStyle = prevFillStyle;\n this.fillCells(startX, startY, cols - startX, 1);\n startX = x;\n startY = y;\n } else if (prevFillStyle !== nextFillStyle) {\n // our color changed, draw the previous characters in this row\n ctx.fillStyle = prevFillStyle;\n this.fillCells(startX, startY, x - startX, 1);\n startX = x;\n startY = y;\n }\n\n prevFillStyle = nextFillStyle;\n });\n\n // flush the last color we encountered\n if (prevFillStyle !== null) {\n ctx.fillStyle = prevFillStyle;\n this.fillCells(startX, startY, cols - startX, 1);\n }\n\n ctx.restore();\n }\n\n private _drawForeground(terminal: ITerminal, firstRow: number, lastRow: number): void {\n this._forEachCell(terminal, firstRow, lastRow, this._characterJoinerRegistry, (code, chars, width, x, y, fg, bg, f lags) => {\n if (flags & FLAGS.INVISIBLE) {\n return;\n }\n if (flags & FLAGS.UNDERLINE) {\n this._ctx.save();\n if (fg === INVERTED_DEFAULT_COLOR) {\n this._ctx.fillStyle = this._colors.background.css;\n } else if (fg < 256) {\n // 256 color support\n this._ctx.fillStyle = this._colors.ansi[fg].css;\n } else {\n this._ctx.fillStyle = this._colors.foreground.css;\n }\n this.fillBottomLineAtCells(x, y, width);\n this._ctx.restore();\n }\n this.drawChars(\n terminal, chars, code,\n width, x, y,\n fg, bg,\n !!(flags & FLAGS.BOLD), !!(flags & FLAGS.DIM), !!(flags & FLAGS.ITALIC)\n );\n });\n }\n\n public onGridChanged(terminal: ITerminal, firstRow: number, lastRow: number): void {\n // Resize has not been called yet\n if (this._state.cache.length === 0) {\n return;\n }\n\n if (this._charAtlas) {\n this._charAtlas .beginFrame();\n }\n\n this.clearCells(0, firstRow, terminal.cols, lastRow - firstRow + 1);\n this._drawBackground(terminal, firstRow, lastRow);\n this._drawForeground(terminal, firstRow, lastRow);\n }\n\n public onOptionsChanged(terminal: ITerminal): void {\n this.setTransparency(terminal, terminal.options.allowTransparency);\n }\n\n /**\n * Whether a character is overlapping to the next cell.\n */\n private _isOverlapping(charData: CharData): boolean {\n // Only single cell characters can be overlapping, rendering issues can\n // occur without this check\n if (charData[CHAR_DATA_WIDTH_INDEX] !== 1) {\n return false;\n }\n\n // We assume that any ascii character will not overlap\n const code = charData[CHAR_DATA_CODE_INDEX];\n if (code < 256) {\n return false;\n }\n\n // Deliver from cache if available\n const char = charData[CHAR_DATA_CHAR_INDEX];\n if (this._characterOverlapCache.hasOwnProperty(char)) {\n ret urn this._characterOverlapCache[char];\n }\n\n // Setup the font\n this._ctx.save();\n this._ctx.font = this._characterFont;\n\n // Measure the width of the character, but Math.floor it\n // because that is what the renderer does when it calculates\n // the character dimensions we are comparing against\n const overlaps = Math.floor(this._ctx.measureText(char).width) > this._characterWidth;\n\n // Restore the original context\n this._ctx.restore();\n\n // Cache and return\n this._characterOverlapCache[char] = overlaps;\n return overlaps;\n }\n\n /**\n * Clear the charcater at the cell specified.\n * @param x The column of the char.\n * @param y The row of the char.\n */\n // private _clearChar(x: number, y: number): void {\n // let colsToClear = 1;\n // // Clear the adjacent character if it was wide\n // const state = this._state.cache[x][y];\n // if (state && state[CHAR_DATA_WIDTH_INDEX] === 2) {\n // colsToClear = 2 ;\n // }\n // this.clearCells(x, y, colsToClear, 1);\n // }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { ITerminal } from '../Types';\nimport { IColorSet, IRenderDimensions } from './Types';\nimport { BaseRenderLayer } from './BaseRenderLayer';\n\ninterface ISelectionState {\n start: [number, number];\n end: [number, number];\n columnSelectMode: boolean;\n ydisp: number;\n}\n\nexport class SelectionRenderLayer extends BaseRenderLayer {\n private _state: ISelectionState;\n\n constructor(container: HTMLElement, zIndex: number, colors: IColorSet) {\n super(container, 'selection', zIndex, true, colors);\n this._clearState();\n }\n\n private _clearState(): void {\n this._state = {\n start: null,\n end: null,\n columnSelectMode: null,\n ydisp: null\n };\n }\n\n public resize(terminal: ITerminal, dim: IRenderDimensions): void {\n super.resize(terminal, dim);\n // Resizin g the canvas discards the contents of the canvas so clear state\n this._clearState();\n }\n\n public reset(terminal: ITerminal): void {\n if (this._state.start && this._state.end) {\n this._clearState();\n this.clearAll();\n }\n }\n\n public onSelectionChanged(terminal: ITerminal, start: [number, number], end: [number, number], columnSelectMode: boolean): void {\n // Selection has not changed\n if (!this._didStateChange(start, end, columnSelectMode, terminal.buffer.ydisp)) {\n return;\n }\n\n // Remove all selections\n this.clearAll();\n\n // Selection does not exist\n if (!start || !end) {\n return;\n }\n\n // Translate from buffer position to viewport position\n const viewportStartRow = start[1] - terminal.buffer.ydisp;\n const viewportEndRow = end[1] - terminal.buffer.ydisp;\n const viewportCappedStartRow = Math.max(viewportStartRow, 0);\n const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1);\n\n // No need to draw the selection\n if (viewportCappedStartRow >= terminal.rows || viewportCappedEndRow < 0) {\n return;\n }\n\n this._ctx.fillStyle = this._colors.selection.css;\n\n if (columnSelectMode) {\n const startCol = start[0];\n const width = end[0] - startCol;\n const height = viewportCappedEndRow - viewportCappedStartRow + 1;\n this.fillCells(startCol, viewportCappedStartRow, width, height);\n } else {\n // Draw first row\n const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;\n const startRowEndCol = viewportCappedStartRow === viewportCappedEndRow ? end[0] : terminal.cols;\n this.fillCells(startCol, viewportCappedStartRow, startRowEndCol - startCol, 1);\n\n // Draw middle rows\n const middleRowsCount = Math.max(viewportCappedEndRow - viewportCappedStartRow - 1, 0);\n this.fillCells(0, viewportCappedStartRow + 1, terminal.cols, middleRowsCount);\n\n // Draw fin al row\n if (viewportCappedStartRow !== viewportCappedEndRow) {\n // Only draw viewportEndRow if it's not the same as viewportStartRow\n const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : terminal.cols;\n this.fillCells(0, viewportCappedEndRow, endCol, 1);\n }\n }\n\n // Save state for next render\n this._state.start = [start[0], start[1]];\n this._state.end = [end[0], end[1]];\n this._state.columnSelectMode = columnSelectMode;\n this._state.ydisp = terminal.buffer.ydisp;\n }\n\n private _didStateChange(start: [number, number], end: [number, number], columnSelectMode: boolean, ydisp: number): boolean {\n return !this._areCoordinatesEqual(start, this._state.start) ||\n !this._areCoordinatesEqual(end, this._state.end) ||\n columnSelectMode !== this._state.columnSelectMode ||\n ydisp !== this._state.ydisp;\n }\n\n private _areCoordinatesEqual(coord1: [number, number], coord2: [number, number]): boolea n {\n if (!coord1 || !coord2) {\n return false;\n }\n\n return coord1[0] === coord2[0] && coord1[1] === coord2[1];\n }\n}\n","/**\n * Copyright (c) 2017 The xterm.js authors. All rights reserved.\n * @license MIT\n */\n\nimport { TextRenderLayer } from './TextRenderLayer';\nimport { SelectionRenderLayer } from './SelectionRenderLayer';\nimport { CursorRenderLayer } from './CursorRenderLayer';\nimport { ColorManager } from './ColorManager';\nimport { IRenderLayer, IColorSet, IRenderer, IRenderDimensions, ICharacterJoinerRegistry } from './Types';\nimport { ITerminal, CharacterJoinerHandler } from '../Types';\nimport { LinkRenderLayer } from './LinkRenderLayer';\nimport { EventEmitter } from '../common/EventEmitter';\nimport { RenderDebouncer } from '../ui/RenderDebouncer';\nimport { ScreenDprMonitor } from '../ui/ScreenDprMonitor';\nimport { ITheme } from 'xterm';\nimport { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry';\n\nexport class Rend
<TRUNCATED> --------------------------------------------------------------------- To unsubscribe, e-mail: common-commits-unsubscr...@hadoop.apache.org For additional commands, e-mail: common-commits-h...@hadoop.apache.org