diff --git a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts index 29c85558..ccd1f56f 100644 --- a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts @@ -24,12 +24,12 @@ import { Disposable, toDisposable } from 'common/Lifecycle'; export abstract class BaseRenderLayer extends Disposable implements IRenderLayer { private _canvas: HTMLCanvasElement; protected _ctx!: CanvasRenderingContext2D; - private _scaledCharWidth: number = 0; - private _scaledCharHeight: number = 0; - private _scaledCellWidth: number = 0; - private _scaledCellHeight: number = 0; - private _scaledCharLeft: number = 0; - private _scaledCharTop: number = 0; + private _deviceCharWidth: number = 0; + private _deviceCharHeight: number = 0; + private _deviceCellWidth: number = 0; + private _deviceCellHeight: number = 0; + private _deviceCharLeft: number = 0; + private _deviceCharTop: number = 0; protected _selectionModel: ISelectionRenderModel = createSelectionRenderModel(); private _cellColorResolver: CellColorResolver; @@ -112,25 +112,25 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer * @param colorSet The color set to use for the char atlas. */ private _refreshCharAtlas(colorSet: ReadonlyColorSet): void { - if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) { + if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) { return; } - this._charAtlas = acquireTextureAtlas(this._terminal, colorSet, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharWidth, this._scaledCharHeight, this._coreBrowserService.dpr); + this._charAtlas = acquireTextureAtlas(this._terminal, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr); this._charAtlas.warmUp(); this._bitmapGenerator = new BitmapGenerator(this._charAtlas.cacheCanvas); } public resize(dim: IRenderDimensions): void { - this._scaledCellWidth = dim.scaledCellWidth; - this._scaledCellHeight = dim.scaledCellHeight; - this._scaledCharWidth = dim.scaledCharWidth; - this._scaledCharHeight = dim.scaledCharHeight; - this._scaledCharLeft = dim.scaledCharLeft; - this._scaledCharTop = dim.scaledCharTop; - this._canvas.width = dim.scaledCanvasWidth; - this._canvas.height = dim.scaledCanvasHeight; - this._canvas.style.width = `${dim.canvasWidth}px`; - this._canvas.style.height = `${dim.canvasHeight}px`; + this._deviceCellWidth = dim.device.cell.width; + this._deviceCellHeight = dim.device.cell.height; + this._deviceCharWidth = dim.device.char.width; + this._deviceCharHeight = dim.device.char.height; + this._deviceCharLeft = dim.device.char.left; + this._deviceCharTop = dim.device.char.top; + this._canvas.width = dim.device.canvas.width; + this._canvas.height = dim.device.canvas.height; + this._canvas.style.width = `${dim.css.canvas.width}px`; + this._canvas.style.height = `${dim.css.canvas.height}px`; // Draw the background if this is an opaque layer if (!this._alpha) { @@ -155,10 +155,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer */ protected _fillCells(x: number, y: number, width: number, height: number): void { this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + height * this._deviceCellHeight); } /** @@ -168,11 +168,11 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer * @param y The row to fill. */ protected _fillMiddleLineAtCells(x: number, y: number, width: number = 1): void { - const cellOffset = Math.ceil(this._scaledCellHeight * 0.5); + const cellOffset = Math.ceil(this._deviceCellHeight * 0.5); this._ctx.fillRect( - x * this._scaledCellWidth, - (y + 1) * this._scaledCellHeight - cellOffset - this._coreBrowserService.dpr, - width * this._scaledCellWidth, + x * this._deviceCellWidth, + (y + 1) * this._deviceCellHeight - cellOffset - this._coreBrowserService.dpr, + width * this._deviceCellWidth, this._coreBrowserService.dpr); } @@ -184,9 +184,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer */ protected _fillBottomLineAtCells(x: number, y: number, width: number = 1, pixelOffset: number = 0): void { this._ctx.fillRect( - x * this._scaledCellWidth, - (y + 1) * this._scaledCellHeight + pixelOffset - this._coreBrowserService.dpr - 1 /* Ensure it's drawn within the cell */, - width * this._scaledCellWidth, + x * this._deviceCellWidth, + (y + 1) * this._deviceCellHeight + pixelOffset - this._coreBrowserService.dpr - 1 /* Ensure it's drawn within the cell */, + width * this._deviceCellWidth, this._coreBrowserService.dpr); } @@ -197,10 +197,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer const lineWidth = this._coreBrowserService.dpr; this._ctx.lineWidth = lineWidth; for (let xOffset = 0; xOffset < width; xOffset++) { - const xLeft = (x + xOffset) * this._scaledCellWidth; - const xMid = (x + xOffset + 0.5) * this._scaledCellWidth; - const xRight = (x + xOffset + 1) * this._scaledCellWidth; - const yMid = (y + 1) * this._scaledCellHeight - lineWidth - 1; + const xLeft = (x + xOffset) * this._deviceCellWidth; + const xMid = (x + xOffset + 0.5) * this._deviceCellWidth; + const xRight = (x + xOffset + 1) * this._deviceCellWidth; + const yMid = (y + 1) * this._deviceCellHeight - lineWidth - 1; const yMidBot = yMid - lineWidth; const yMidTop = yMid + lineWidth; this._ctx.moveTo(xLeft, yMid); @@ -226,12 +226,12 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer const lineWidth = this._coreBrowserService.dpr; this._ctx.lineWidth = lineWidth; this._ctx.setLineDash([lineWidth * 2, lineWidth]); - const xLeft = x * this._scaledCellWidth; - const yMid = (y + 1) * this._scaledCellHeight - lineWidth - 1; + const xLeft = x * this._deviceCellWidth; + const yMid = (y + 1) * this._deviceCellHeight - lineWidth - 1; this._ctx.moveTo(xLeft, yMid); for (let xOffset = 0; xOffset < width; xOffset++) { - // const xLeft = x * this._scaledCellWidth; - const xRight = (x + width + xOffset) * this._scaledCellWidth; + // const xLeft = x * this._deviceCellWidth; + const xRight = (x + width + xOffset) * this._deviceCellWidth; this._ctx.lineTo(xRight, yMid); } this._ctx.stroke(); @@ -246,9 +246,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer const lineWidth = this._coreBrowserService.dpr; this._ctx.lineWidth = lineWidth; this._ctx.setLineDash([lineWidth * 4, lineWidth * 3]); - const xLeft = x * this._scaledCellWidth; - const xRight = (x + width) * this._scaledCellWidth; - const yMid = (y + 1) * this._scaledCellHeight - lineWidth - 1; + const xLeft = x * this._deviceCellWidth; + const xRight = (x + width) * this._deviceCellWidth; + const yMid = (y + 1) * this._deviceCellHeight - lineWidth - 1; this._ctx.moveTo(xLeft, yMid); this._ctx.lineTo(xRight, yMid); this._ctx.stroke(); @@ -264,10 +264,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer */ protected _fillLeftLineAtCell(x: number, y: number, width: number): void { this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, + x * this._deviceCellWidth, + y * this._deviceCellHeight, this._coreBrowserService.dpr * width, - this._scaledCellHeight); + this._deviceCellHeight); } /** @@ -280,10 +280,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer const lineWidth = this._coreBrowserService.dpr; this._ctx.lineWidth = lineWidth; this._ctx.strokeRect( - x * this._scaledCellWidth + lineWidth / 2, - y * this._scaledCellHeight + (lineWidth / 2), - width * this._scaledCellWidth - lineWidth, - (height * this._scaledCellHeight) - lineWidth); + x * this._deviceCellWidth + lineWidth / 2, + y * this._deviceCellHeight + (lineWidth / 2), + width * this._deviceCellWidth - lineWidth, + (height * this._deviceCellHeight) - lineWidth); } /** @@ -308,17 +308,17 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer protected _clearCells(x: number, y: number, width: number, height: number): void { if (this._alpha) { this._ctx.clearRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + height * this._deviceCellHeight); } else { this._ctx.fillStyle = this._themeService.colors.background.css; this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + height * this._deviceCellHeight); } } @@ -338,15 +338,15 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer // Draw custom characters if applicable let drawSuccess = false; if (this._optionsService.rawOptions.customGlyphs !== false) { - drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._scaledCellWidth, y * this._scaledCellHeight, this._scaledCellWidth, this._scaledCellHeight, this._optionsService.rawOptions.fontSize, this._coreBrowserService.dpr); + drawSuccess = tryDrawCustomChar(this._ctx, cell.getChars(), x * this._deviceCellWidth, y * this._deviceCellHeight, this._deviceCellWidth, this._deviceCellHeight, this._optionsService.rawOptions.fontSize, this._coreBrowserService.dpr); } // Draw the character if (!drawSuccess) { this._ctx.fillText( cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); + x * this._deviceCellWidth + this._deviceCharLeft, + y * this._deviceCellHeight + this._deviceCharTop + this._deviceCharHeight); } } @@ -376,8 +376,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer glyph.texturePosition.y, glyph.size.x, glyph.size.y, - x * this._scaledCellWidth - glyph.offset.x, - y * this._scaledCellHeight - glyph.offset.y, + x * this._deviceCellWidth - glyph.offset.x, + y * this._deviceCellHeight - glyph.offset.y, glyph.size.x, glyph.size.y ); @@ -392,9 +392,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer this._ctx.beginPath(); this._ctx.rect( 0, - y * this._scaledCellHeight, - this._bufferService.cols * this._scaledCellWidth, - this._scaledCellHeight); + y * this._deviceCellHeight, + this._bufferService.cols * this._deviceCellWidth, + this._deviceCellHeight); this._ctx.clip(); } diff --git a/addons/xterm-addon-canvas/src/CanvasRenderer.ts b/addons/xterm-addon-canvas/src/CanvasRenderer.ts index b657270f..d4563c5c 100644 --- a/addons/xterm-addon-canvas/src/CanvasRenderer.ts +++ b/addons/xterm-addon-canvas/src/CanvasRenderer.ts @@ -5,9 +5,10 @@ import { removeTerminalFromCache } from 'browser/renderer/shared/CharAtlasCache'; import { observeDevicePixelDimensions } from 'browser/renderer/shared/DevicePixelObserver'; +import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { IColorSet, ILinkifier2, ReadonlyColorSet } from 'browser/Types'; +import { ILinkifier2 } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { Disposable, toDisposable } from 'common/Lifecycle'; import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; @@ -50,20 +51,7 @@ export class CanvasRenderer extends Disposable implements IRenderer { new LinkRenderLayer(this._terminal, this._screenElement, 2, linkifier2, this._bufferService, this._optionsService, decorationService, this._coreBrowserService, _themeService), new CursorRenderLayer(this._terminal, this._screenElement, 3, this._onRequestRedraw, this._bufferService, this._optionsService, coreService, this._coreBrowserService, decorationService, _themeService) ]; - this.dimensions = { - scaledCharWidth: 0, - scaledCharHeight: 0, - scaledCellWidth: 0, - scaledCellHeight: 0, - scaledCharLeft: 0, - scaledCharTop: 0, - scaledCanvasWidth: 0, - scaledCanvasHeight: 0, - canvasWidth: 0, - canvasHeight: 0, - actualCellWidth: 0, - actualCellHeight: 0 - }; + this.dimensions = createRenderDimensions(); this._devicePixelRatio = this._coreBrowserService.dpr; this._updateDimensions(); @@ -99,8 +87,8 @@ export class CanvasRenderer extends Disposable implements IRenderer { } // Resize the screen - this._screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._screenElement.style.height = `${this.dimensions.canvasHeight}px`; + this._screenElement.style.width = `${this.dimensions.css.canvas.width}px`; + this._screenElement.style.height = `${this.dimensions.css.canvas.height}px`; } public handleCharSizeChanged(): void { @@ -163,23 +151,23 @@ export class CanvasRenderer extends Disposable implements IRenderer { // See the WebGL renderer for an explanation of this section. const dpr = this._coreBrowserService.dpr; - this.dimensions.scaledCharWidth = Math.floor(this._charSizeService.width * dpr); - this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * dpr); - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.rawOptions.lineHeight); - this.dimensions.scaledCharTop = this._optionsService.rawOptions.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.rawOptions.letterSpacing); - this.dimensions.scaledCharLeft = Math.floor(this._optionsService.rawOptions.letterSpacing / 2); - this.dimensions.scaledCanvasHeight = this._bufferService.rows * this.dimensions.scaledCellHeight; - this.dimensions.scaledCanvasWidth = this._bufferService.cols * this.dimensions.scaledCellWidth; - this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / dpr); - this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / dpr); - this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._bufferService.rows; - this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._bufferService.cols; + this.dimensions.device.char.width = Math.floor(this._charSizeService.width * dpr); + this.dimensions.device.char.height = Math.ceil(this._charSizeService.height * dpr); + this.dimensions.device.cell.height = Math.floor(this.dimensions.device.char.height * this._optionsService.rawOptions.lineHeight); + this.dimensions.device.char.top = this._optionsService.rawOptions.lineHeight === 1 ? 0 : Math.round((this.dimensions.device.cell.height - this.dimensions.device.char.height) / 2); + this.dimensions.device.cell.width = this.dimensions.device.char.width + Math.round(this._optionsService.rawOptions.letterSpacing); + this.dimensions.device.char.left = Math.floor(this._optionsService.rawOptions.letterSpacing / 2); + this.dimensions.device.canvas.height = this._bufferService.rows * this.dimensions.device.cell.height; + this.dimensions.device.canvas.width = this._bufferService.cols * this.dimensions.device.cell.width; + this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / dpr); + this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / dpr); + this.dimensions.css.cell.height = this.dimensions.css.canvas.height / this._bufferService.rows; + this.dimensions.css.cell.width = this.dimensions.css.canvas.width / this._bufferService.cols; } private _setCanvasDevicePixelDimensions(width: number, height: number): void { - this.dimensions.scaledCanvasHeight = height; - this.dimensions.scaledCanvasWidth = width; + this.dimensions.device.canvas.height = height; + this.dimensions.device.canvas.width = width; // Resize all render layers for (const l of this._renderLayers) { l.resize(this.dimensions); diff --git a/addons/xterm-addon-canvas/src/TextRenderLayer.ts b/addons/xterm-addon-canvas/src/TextRenderLayer.ts index e2a35751..66fc5106 100644 --- a/addons/xterm-addon-canvas/src/TextRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/TextRenderLayer.ts @@ -53,8 +53,8 @@ export class TextRenderLayer extends BaseRenderLayer { // Clear the character width cache if the font or width has changed const terminalFont = this._getFont(false, false); - if (this._characterWidth !== dim.scaledCharWidth || this._characterFont !== terminalFont) { - this._characterWidth = dim.scaledCharWidth; + if (this._characterWidth !== dim.device.char.width || this._characterFont !== terminalFont) { + this._characterWidth = dim.device.char.width; this._characterFont = terminalFont; this._characterOverlapCache = {}; } diff --git a/addons/xterm-addon-canvas/src/Types.d.ts b/addons/xterm-addon-canvas/src/Types.d.ts index edd5c2ea..7e582535 100644 --- a/addons/xterm-addon-canvas/src/Types.d.ts +++ b/addons/xterm-addon-canvas/src/Types.d.ts @@ -4,24 +4,8 @@ */ import { IDisposable } from 'common/Types'; -import { IColorSet, ReadonlyColorSet } from 'browser/Types'; import { IEvent } from 'common/EventEmitter'; - -// TODO: Use core interfaces -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; -} +import { IRenderDimensions } from 'browser/renderer/shared/Types'; export interface IRequestRedrawEvent { start: number; diff --git a/addons/xterm-addon-fit/src/FitAddon.ts b/addons/xterm-addon-fit/src/FitAddon.ts index 7b9c228f..6b3df6f0 100644 --- a/addons/xterm-addon-fit/src/FitAddon.ts +++ b/addons/xterm-addon-fit/src/FitAddon.ts @@ -4,6 +4,7 @@ */ import { Terminal, ITerminalAddon } from 'xterm'; +import { IRenderDimensions } from 'browser/renderer/shared/Types'; interface ITerminalDimensions { /** @@ -58,8 +59,9 @@ export class FitAddon implements ITerminalAddon { // TODO: Remove reliance on private API const core = (this._terminal as any)._core; + const dims: IRenderDimensions = core._renderService.dimensions; - if (core._renderService.dimensions.actualCellWidth === 0 || core._renderService.dimensions.actualCellHeight === 0) { + if (dims.css.cell.width === 0 || dims.css.cell.height === 0) { return undefined; } @@ -81,8 +83,8 @@ export class FitAddon implements ITerminalAddon { const availableHeight = parentElementHeight - elementPaddingVer; const availableWidth = parentElementWidth - elementPaddingHor - scrollbarWidth; const geometry = { - cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / core._renderService.dimensions.actualCellWidth)), - rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / core._renderService.dimensions.actualCellHeight)) + cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / dims.css.cell.width)), + rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / dims.css.cell.height)) }; return geometry; } diff --git a/addons/xterm-addon-fit/src/tsconfig.json b/addons/xterm-addon-fit/src/tsconfig.json index f3e409d1..3bfbea67 100644 --- a/addons/xterm-addon-fit/src/tsconfig.json +++ b/addons/xterm-addon-fit/src/tsconfig.json @@ -13,10 +13,20 @@ "strict": true, "types": [ "../../../node_modules/@types/mocha" - ] + ], + "paths": { + "browser/*": [ + "../../../src/browser/*" + ] + } }, "include": [ "./**/*", "../../../typings/xterm.d.ts" + ], + "references": [ + { + "path": "../../../src/browser" + } ] } diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 88475f18..4bce546a 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -204,15 +204,15 @@ export class GlyphRenderer extends Disposable { $glyph = this._atlas.getRasterizedGlyph(code, bg, fg, ext); } - $leftCellPadding = Math.floor((this._dimensions.scaledCellWidth - this._dimensions.scaledCharWidth) / 2); + $leftCellPadding = Math.floor((this._dimensions.device.cell.width - this._dimensions.device.char.width) / 2); if (bg !== lastBg && $glyph.offset.x > $leftCellPadding) { $clippedPixels = $glyph.offset.x - $leftCellPadding; // a_origin - array[$i ] = -($glyph.offset.x - $clippedPixels) + this._dimensions.scaledCharLeft; - array[$i + 1] = -$glyph.offset.y + this._dimensions.scaledCharTop; + array[$i ] = -($glyph.offset.x - $clippedPixels) + this._dimensions.device.char.left; + array[$i + 1] = -$glyph.offset.y + this._dimensions.device.char.top; // a_size - array[$i + 2] = ($glyph.size.x - $clippedPixels) / this._dimensions.scaledCanvasWidth; - array[$i + 3] = $glyph.size.y / this._dimensions.scaledCanvasHeight; + array[$i + 2] = ($glyph.size.x - $clippedPixels) / this._dimensions.device.canvas.width; + array[$i + 3] = $glyph.size.y / this._dimensions.device.canvas.height; // a_texcoord array[$i + 4] = $glyph.texturePositionClipSpace.x + $clippedPixels / this._atlas.cacheCanvas.width; array[$i + 5] = $glyph.texturePositionClipSpace.y; @@ -221,11 +221,11 @@ export class GlyphRenderer extends Disposable { array[$i + 7] = $glyph.sizeClipSpace.y; } else { // a_origin - array[$i ] = -$glyph.offset.x + this._dimensions.scaledCharLeft; - array[$i + 1] = -$glyph.offset.y + this._dimensions.scaledCharTop; + array[$i ] = -$glyph.offset.x + this._dimensions.device.char.left; + array[$i + 1] = -$glyph.offset.y + this._dimensions.device.char.top; // a_size - array[$i + 2] = $glyph.size.x / this._dimensions.scaledCanvasWidth; - array[$i + 3] = $glyph.size.y / this._dimensions.scaledCanvasHeight; + array[$i + 2] = $glyph.size.x / this._dimensions.device.canvas.width; + array[$i + 3] = $glyph.size.y / this._dimensions.device.canvas.height; // a_texcoord array[$i + 4] = $glyph.texturePositionClipSpace.x; array[$i + 5] = $glyph.texturePositionClipSpace.y; diff --git a/addons/xterm-addon-webgl/src/RectangleRenderer.ts b/addons/xterm-addon-webgl/src/RectangleRenderer.ts index ca5cb9a9..f45ae3df 100644 --- a/addons/xterm-addon-webgl/src/RectangleRenderer.ts +++ b/addons/xterm-addon-webgl/src/RectangleRenderer.ts @@ -176,8 +176,8 @@ export class RectangleRenderer extends Disposable { 0, 0, 0, - this._terminal.cols * this._dimensions.scaledCellWidth, - this._terminal.rows * this._dimensions.scaledCellHeight, + this._terminal.cols * this._dimensions.device.cell.width, + this._terminal.rows * this._dimensions.device.cell.height, this._bgFloat ); } @@ -265,21 +265,21 @@ export class RectangleRenderer extends Disposable { if (vertices.attributes.length < offset + 4) { vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE); } - $x1 = startX * this._dimensions.scaledCellWidth; - $y1 = y * this._dimensions.scaledCellHeight; + $x1 = startX * this._dimensions.device.cell.width; + $y1 = y * this._dimensions.device.cell.height; $r = (($rgba >> 24) & 0xFF) / 255; $g = (($rgba >> 16) & 0xFF) / 255; $b = (($rgba >> 8 ) & 0xFF) / 255; $a = (!$isDefault && bg & BgFlags.DIM) ? DIM_OPACITY : 1; - this._addRectangle(vertices.attributes, offset, $x1, $y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, $r, $g, $b, $a); + this._addRectangle(vertices.attributes, offset, $x1, $y1, (endX - startX) * this._dimensions.device.cell.width, this._dimensions.device.cell.height, $r, $g, $b, $a); } private _addRectangle(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, r: number, g: number, b: number, a: number): void { - array[offset ] = x1 / this._dimensions.scaledCanvasWidth; - array[offset + 1] = y1 / this._dimensions.scaledCanvasHeight; - array[offset + 2] = width / this._dimensions.scaledCanvasWidth; - array[offset + 3] = height / this._dimensions.scaledCanvasHeight; + array[offset ] = x1 / this._dimensions.device.canvas.width; + array[offset + 1] = y1 / this._dimensions.device.canvas.height; + array[offset + 2] = width / this._dimensions.device.canvas.width; + array[offset + 3] = height / this._dimensions.device.canvas.height; array[offset + 4] = r; array[offset + 5] = g; array[offset + 6] = b; @@ -287,10 +287,10 @@ export class RectangleRenderer extends Disposable { } private _addRectangleFloat(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, color: Float32Array): void { - array[offset ] = x1 / this._dimensions.scaledCanvasWidth; - array[offset + 1] = y1 / this._dimensions.scaledCanvasHeight; - array[offset + 2] = width / this._dimensions.scaledCanvasWidth; - array[offset + 3] = height / this._dimensions.scaledCanvasHeight; + array[offset ] = x1 / this._dimensions.device.canvas.width; + array[offset + 1] = y1 / this._dimensions.device.canvas.height; + array[offset + 2] = width / this._dimensions.device.canvas.width; + array[offset + 3] = height / this._dimensions.device.canvas.height; array[offset + 4] = color[0]; array[offset + 5] = color[1]; array[offset + 6] = color[2]; diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index ded9130a..f4eceb00 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -7,9 +7,10 @@ import { addDisposableDomListener } from 'browser/Lifecycle'; import { CellColorResolver } from 'browser/renderer/shared/CellColorResolver'; import { acquireTextureAtlas, removeTerminalFromCache } from 'browser/renderer/shared/CharAtlasCache'; import { observeDevicePixelDimensions } from 'browser/renderer/shared/DevicePixelObserver'; +import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ITextureAtlas } from 'browser/renderer/shared/Types'; import { ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { IColorSet, ITerminal, ReadonlyColorSet } from 'browser/Types'; +import { ITerminal } from 'browser/Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { CellData } from 'common/buffer/CellData'; import { Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants'; @@ -40,7 +41,7 @@ export class WebglRenderer extends Disposable implements IRenderer { private _rectangleRenderer!: RectangleRenderer; private _glyphRenderer!: GlyphRenderer; - public dimensions: IRenderDimensions; + public readonly dimensions: IRenderDimensions; private _core: ITerminal; private _isAttached: boolean; @@ -75,20 +76,7 @@ export class WebglRenderer extends Disposable implements IRenderer { new LinkRenderLayer(this._core.screenElement!, 2, this._terminal, this._core.linkifier2, this._coreBrowserService, this._themeService), new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._onRequestRedraw, this._coreBrowserService, coreService, this._themeService, optionsService) ]; - this.dimensions = { - scaledCharWidth: 0, - scaledCharHeight: 0, - scaledCellWidth: 0, - scaledCellHeight: 0, - scaledCharLeft: 0, - scaledCharTop: 0, - scaledCanvasWidth: 0, - scaledCanvasHeight: 0, - canvasWidth: 0, - canvasHeight: 0, - actualCellWidth: 0, - actualCellHeight: 0 - }; + this.dimensions = createRenderDimensions(); this._devicePixelRatio = this._coreBrowserService.dpr; this._updateDimensions(); this.register(optionsService.onOptionChange(() => this._handleOptionsChanged())); @@ -177,14 +165,14 @@ export class WebglRenderer extends Disposable implements IRenderer { } // Resize the canvas - this._canvas.width = this.dimensions.scaledCanvasWidth; - this._canvas.height = this.dimensions.scaledCanvasHeight; - this._canvas.style.width = `${this.dimensions.canvasWidth}px`; - this._canvas.style.height = `${this.dimensions.canvasHeight}px`; + this._canvas.width = this.dimensions.device.canvas.width; + this._canvas.height = this.dimensions.device.canvas.height; + this._canvas.style.width = `${this.dimensions.css.canvas.width}px`; + this._canvas.style.height = `${this.dimensions.css.canvas.height}px`; // Resize the screen - this._core.screenElement!.style.width = `${this.dimensions.canvasWidth}px`; - this._core.screenElement!.style.height = `${this.dimensions.canvasHeight}px`; + this._core.screenElement!.style.width = `${this.dimensions.css.canvas.width}px`; + this._core.screenElement!.style.height = `${this.dimensions.css.canvas.height}px`; this._rectangleRenderer.setDimensions(this.dimensions); this._rectangleRenderer.handleResize(); @@ -256,13 +244,21 @@ export class WebglRenderer extends Disposable implements IRenderer { * Refreshes the char atlas, aquiring a new one if necessary. */ private _refreshCharAtlas(): void { - if (this.dimensions.scaledCharWidth <= 0 && this.dimensions.scaledCharHeight <= 0) { + if (this.dimensions.device.char.width <= 0 && this.dimensions.device.char.height <= 0) { // Mark as not attached so char atlas gets refreshed on next render this._isAttached = false; return; } - const atlas = acquireTextureAtlas(this._terminal, this._themeService.colors, this.dimensions.scaledCellWidth, this.dimensions.scaledCellHeight, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight, this._coreBrowserService.dpr); + const atlas = acquireTextureAtlas( + this._terminal, + this._themeService.colors, + this.dimensions.device.cell.width, + this.dimensions.device.cell.height, + this.dimensions.device.char.width, + this.dimensions.device.char.height, + this._coreBrowserService.dpr + ); if (this._charAtlas !== atlas) { this._onChangeTextureAtlas.fire(atlas.cacheCanvas); } @@ -451,57 +447,57 @@ export class WebglRenderer extends Disposable implements IRenderer { return; } - // Calculate the scaled character width. Width is floored as it must be drawn to an integer grid + // Calculate the device character width. Width is floored as it must be drawn to an integer grid // in order for the char atlas glyphs to not be blurry. - this.dimensions.scaledCharWidth = Math.floor((this._core as any)._charSizeService.width * this._devicePixelRatio); + this.dimensions.device.char.width = Math.floor((this._core as any)._charSizeService.width * this._devicePixelRatio); - // Calculate the scaled character height. Height is ceiled in case devicePixelRatio is a + // Calculate the device 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._core as any)._charSizeService.height * this._devicePixelRatio); + this.dimensions.device.char.height = Math.ceil((this._core as any)._charSizeService.height * this._devicePixelRatio); - // Calculate the scaled cell height, if lineHeight is _not_ 1, the resulting value will be - // floored since lineHeight can never be lower then 1, this guarentees the scaled cell height - // will always be larger than scaled char height. - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.options.lineHeight); + // Calculate the device cell height, if lineHeight is _not_ 1, the resulting value will be + // floored since lineHeight can never be lower then 1, this guarentees the device cell height + // will always be larger than device char height. + this.dimensions.device.cell.height = Math.floor(this.dimensions.device.char.height * this._terminal.options.lineHeight); // Calculate the y offset within a cell that glyph should draw at in order for it to be centered // correctly within the cell. - this.dimensions.scaledCharTop = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2); + this.dimensions.device.char.top = this._terminal.options.lineHeight === 1 ? 0 : Math.round((this.dimensions.device.cell.height - this.dimensions.device.char.height) / 2); - // Calculate the scaled cell width, taking the letterSpacing into account. - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.options.letterSpacing); + // Calculate the device cell width, taking the letterSpacing into account. + this.dimensions.device.cell.width = this.dimensions.device.char.width + Math.round(this._terminal.options.letterSpacing); // Calculate the x offset with a cell that text should draw from in order for it to be centered // correctly within the cell. - this.dimensions.scaledCharLeft = Math.floor(this._terminal.options.letterSpacing / 2); + this.dimensions.device.char.left = Math.floor(this._terminal.options.letterSpacing / 2); - // Recalculate the canvas dimensions, the scaled dimensions define the actual number of pixel in + // Recalculate the canvas dimensions, the device dimensions define the actual number of pixel in // the canvas - this.dimensions.scaledCanvasHeight = this._terminal.rows * this.dimensions.scaledCellHeight; - this.dimensions.scaledCanvasWidth = this._terminal.cols * this.dimensions.scaledCellWidth; + this.dimensions.device.canvas.height = this._terminal.rows * this.dimensions.device.cell.height; + this.dimensions.device.canvas.width = this._terminal.cols * this.dimensions.device.cell.width; // The the size of the canvas on the page. It's important that this rounds to nearest integer // and not ceils as browsers often have floating point precision issues where // `window.devicePixelRatio` ends up being something like `1.100000023841858` for example, when // it's actually 1.1. Ceiling may causes blurriness as the backing canvas image is 1 pixel too // large for the canvas element size. - this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / this._devicePixelRatio); - this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / this._devicePixelRatio); + this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / this._devicePixelRatio); + this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / this._devicePixelRatio); // Get the CSS dimensions of an individual cell. This needs to be derived from the calculated // device pixel canvas value above. 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. - this.dimensions.actualCellHeight = this.dimensions.scaledCellHeight / this._devicePixelRatio; - this.dimensions.actualCellWidth = this.dimensions.scaledCellWidth / this._devicePixelRatio; + this.dimensions.css.cell.height = this.dimensions.device.cell.height / this._devicePixelRatio; + this.dimensions.css.cell.width = this.dimensions.device.cell.width / this._devicePixelRatio; } private _setCanvasDevicePixelDimensions(width: number, height: number): void { if (this._canvas.width === width && this._canvas.height === height) { return; } - // While the actual canvas size has changed, keep scaledCanvasWidth/Height as the value before + // While the actual canvas size has changed, keep device canvas dimensions as the value before // the change as it's an exact multiple of the cell sizes. this._canvas.width = width; this._canvas.height = height; diff --git a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts index aa08b583..e30ef25b 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/BaseRenderLayer.ts @@ -17,12 +17,12 @@ import { Disposable, toDisposable } from 'common/Lifecycle'; export abstract class BaseRenderLayer extends Disposable implements IRenderLayer { private _canvas: HTMLCanvasElement; protected _ctx!: CanvasRenderingContext2D; - private _scaledCharWidth: number = 0; - private _scaledCharHeight: number = 0; - private _scaledCellWidth: number = 0; - private _scaledCellHeight: number = 0; - private _scaledCharLeft: number = 0; - private _scaledCharTop: number = 0; + private _deviceCharWidth: number = 0; + private _deviceCharHeight: number = 0; + private _deviceCellWidth: number = 0; + private _deviceCellHeight: number = 0; + private _deviceCharLeft: number = 0; + private _deviceCharTop: number = 0; protected _charAtlas: ITextureAtlas | undefined; @@ -90,24 +90,24 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer * @param colorSet The color set to use for the char atlas. */ private _refreshCharAtlas(terminal: Terminal, colorSet: ReadonlyColorSet): void { - if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) { + if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) { return; } - this._charAtlas = acquireTextureAtlas(terminal, colorSet, this._scaledCellWidth, this._scaledCellHeight, this._scaledCharWidth, this._scaledCharHeight, this._coreBrowserService.dpr); + this._charAtlas = acquireTextureAtlas(terminal, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr); this._charAtlas.warmUp(); } public resize(terminal: Terminal, dim: IRenderDimensions): void { - this._scaledCellWidth = dim.scaledCellWidth; - this._scaledCellHeight = dim.scaledCellHeight; - this._scaledCharWidth = dim.scaledCharWidth; - this._scaledCharHeight = dim.scaledCharHeight; - this._scaledCharLeft = dim.scaledCharLeft; - this._scaledCharTop = dim.scaledCharTop; - this._canvas.width = dim.scaledCanvasWidth; - this._canvas.height = dim.scaledCanvasHeight; - this._canvas.style.width = `${dim.canvasWidth}px`; - this._canvas.style.height = `${dim.canvasHeight}px`; + this._deviceCellWidth = dim.device.cell.width; + this._deviceCellHeight = dim.device.cell.height; + this._deviceCharWidth = dim.device.char.width; + this._deviceCharHeight = dim.device.char.height; + this._deviceCharLeft = dim.device.char.left; + this._deviceCharTop = dim.device.char.top; + this._canvas.width = dim.device.canvas.width; + this._canvas.height = dim.device.canvas.height; + this._canvas.style.width = `${dim.css.canvas.width}px`; + this._canvas.style.height = `${dim.css.canvas.height}px`; // Draw the background if this is an opaque layer if (!this._alpha) { @@ -128,10 +128,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer */ protected _fillCells(x: number, y: number, width: number, height: number): void { this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + height * this._deviceCellHeight); } /** @@ -142,9 +142,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer */ protected _fillBottomLineAtCells(x: number, y: number, width: number = 1): void { this._ctx.fillRect( - x * this._scaledCellWidth, - (y + 1) * this._scaledCellHeight - this._coreBrowserService.dpr - 1 /* Ensure it's drawn within the cell */, - width * this._scaledCellWidth, + x * this._deviceCellWidth, + (y + 1) * this._deviceCellHeight - this._coreBrowserService.dpr - 1 /* Ensure it's drawn within the cell */, + width * this._deviceCellWidth, this._coreBrowserService.dpr); } @@ -156,10 +156,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer */ protected _fillLeftLineAtCell(x: number, y: number, width: number): void { this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, + x * this._deviceCellWidth, + y * this._deviceCellHeight, this._coreBrowserService.dpr * width, - this._scaledCellHeight); + this._deviceCellHeight); } /** @@ -171,10 +171,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer protected _strokeRectAtCell(x: number, y: number, width: number, height: number): void { this._ctx.lineWidth = this._coreBrowserService.dpr; this._ctx.strokeRect( - x * this._scaledCellWidth + this._coreBrowserService.dpr / 2, - y * this._scaledCellHeight + (this._coreBrowserService.dpr / 2), - width * this._scaledCellWidth - this._coreBrowserService.dpr, - (height * this._scaledCellHeight) - this._coreBrowserService.dpr); + x * this._deviceCellWidth + this._coreBrowserService.dpr / 2, + y * this._deviceCellHeight + (this._coreBrowserService.dpr / 2), + width * this._deviceCellWidth - this._coreBrowserService.dpr, + (height * this._deviceCellHeight) - this._coreBrowserService.dpr); } /** @@ -199,17 +199,17 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer protected _clearCells(x: number, y: number, width: number, height: number): void { if (this._alpha) { this._ctx.clearRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + height * this._deviceCellHeight); } else { this._ctx.fillStyle = this._themeService.colors.background.css; this._ctx.fillRect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - height * this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + height * this._deviceCellHeight); } } @@ -228,8 +228,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer this._clipCell(x, y, cell.getWidth()); this._ctx.fillText( cell.getChars(), - x * this._scaledCellWidth + this._scaledCharLeft, - y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight); + x * this._deviceCellWidth + this._deviceCharLeft, + y * this._deviceCellHeight + this._deviceCharTop + this._deviceCharHeight); } /** @@ -241,10 +241,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer private _clipCell(x: number, y: number, width: number): void { this._ctx.beginPath(); this._ctx.rect( - x * this._scaledCellWidth, - y * this._scaledCellHeight, - width * this._scaledCellWidth, - this._scaledCellHeight); + x * this._deviceCellWidth, + y * this._deviceCellHeight, + width * this._deviceCellWidth, + this._deviceCellHeight); this._ctx.clip(); } diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index a6325dcb..cb288f24 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -7,7 +7,6 @@ import { Terminal } from 'xterm'; import { BaseRenderLayer } from './BaseRenderLayer'; import { ICellData } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; -import { IColorSet, ReadonlyColorSet } from 'browser/Types'; import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; import { IEventEmitter } from 'common/EventEmitter'; import { ICoreBrowserService, IThemeService } from 'browser/services/Services'; diff --git a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts index 53073092..5e34aede 100644 --- a/addons/xterm-addon-webgl/test/WebglRenderer.api.ts +++ b/addons/xterm-addon-webgl/test/WebglRenderer.api.ts @@ -992,8 +992,8 @@ async function getCellColor(col: number, row: number): Promise { window.result = new Uint8Array(4); window.d = window.term._core._renderService.dimensions; window.gl.readPixels( - Math.floor((${col - 0.5}) * window.d.scaledCellWidth), - Math.floor(window.gl.drawingBufferHeight - 1 - (${row - 0.5}) * window.d.scaledCellHeight), + Math.floor((${col - 0.5}) * window.d.device.cell.width), + Math.floor(window.gl.drawingBufferHeight - 1 - (${row - 0.5}) * window.d.device.cell.height), 1, 1, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result ); `); @@ -1003,12 +1003,12 @@ async function getCellColor(col: number, row: number): Promise { async function getCellPixels(col: number, row: number): Promise { await page.evaluate(` window.gl = window.term._core._renderService._renderer._gl; - window.result = new Uint8Array(window.d.scaledCellWidth * window.d.scaledCellHeight * 4); + window.result = new Uint8Array(window.d.device.cell.width * window.d.device.cell.height * 4); window.d = window.term._core._renderService.dimensions; window.gl.readPixels( - Math.floor(${col - 1} * window.d.scaledCellWidth), - Math.floor(window.gl.drawingBufferHeight - ${row} * window.d.scaledCellHeight), - window.d.scaledCellWidth, window.d.scaledCellHeight, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result + Math.floor(${col - 1} * window.d.device.cell.width), + Math.floor(window.gl.drawingBufferHeight - ${row} * window.d.device.cell.height), + window.d.device.cell.width, window.d.device.cell.height, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result ); `); return await page.evaluate(`Array.from(window.result)`); diff --git a/demo/client.ts b/demo/client.ts index 44a96eb3..921ee155 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -618,8 +618,8 @@ function addDomListener(element: HTMLElement, type: string, handler: (...args: a function updateTerminalSize(): void { const cols = parseInt((document.getElementById(`opt-cols`) as HTMLInputElement).value, 10); const rows = parseInt((document.getElementById(`opt-rows`) as HTMLInputElement).value, 10); - const width = (cols * term._core._renderService.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px'; - const height = (rows * term._core._renderService.dimensions.actualCellHeight).toString() + 'px'; + const width = (cols * term._core._renderService.dimensions.css.cell.width + term._core.viewport.scrollBarWidth).toString() + 'px'; + const height = (rows * term._core._renderService.dimensions.css.cell.height).toString() + 'px'; terminalContainer.style.width = width; terminalContainer.style.height = height; addons.fit.instance.fit(); diff --git a/src/browser/AccessibilityManager.ts b/src/browser/AccessibilityManager.ts index d0c9f601..3998e779 100644 --- a/src/browser/AccessibilityManager.ts +++ b/src/browser/AccessibilityManager.ts @@ -274,7 +274,7 @@ export class AccessibilityManager extends Disposable { } private _refreshRowsDimensions(): void { - if (!this._renderService.dimensions.actualCellHeight) { + if (!this._renderService.dimensions.css.cell.height) { return; } if (this._rowElements.length !== this._terminal.rows) { @@ -286,7 +286,7 @@ export class AccessibilityManager extends Disposable { } private _refreshRowDimensions(element: HTMLElement): void { - element.style.height = `${this._renderService.dimensions.actualCellHeight}px`; + element.style.height = `${this._renderService.dimensions.css.cell.height}px`; } private _announceCharacters(): void { diff --git a/src/browser/Terminal.ts b/src/browser/Terminal.ts index b5262b1e..3c88b948 100644 --- a/src/browser/Terminal.ts +++ b/src/browser/Terminal.ts @@ -321,11 +321,11 @@ export class Terminal extends CoreTerminal implements ITerminal { return; } const cursorX = Math.min(this.buffer.x, this.cols - 1); - const cellHeight = this._renderService.dimensions.actualCellHeight; + const cellHeight = this._renderService.dimensions.css.cell.height; const width = bufferLine.getWidth(cursorX); - const cellWidth = this._renderService.dimensions.actualCellWidth * width; - const cursorTop = this.buffer.y * this._renderService.dimensions.actualCellHeight; - const cursorLeft = cursorX * this._renderService.dimensions.actualCellWidth; + const cellWidth = this._renderService.dimensions.css.cell.width * width; + const cursorTop = this.buffer.y * this._renderService.dimensions.css.cell.height; + const cursorLeft = cursorX * this._renderService.dimensions.css.cell.width; // Sync the textarea to the exact position of the composition view so the IME knows where the // text is. @@ -1273,13 +1273,13 @@ export class Terminal extends CoreTerminal implements ITerminal { switch (type) { case WindowsOptionsReportType.GET_WIN_SIZE_PIXELS: - const canvasWidth = this._renderService.dimensions.canvasWidth.toFixed(0); - const canvasHeight = this._renderService.dimensions.canvasHeight.toFixed(0); + const canvasWidth = this._renderService.dimensions.css.canvas.width.toFixed(0); + const canvasHeight = this._renderService.dimensions.css.canvas.height.toFixed(0); this.coreService.triggerDataEvent(`${C0.ESC}[4;${canvasHeight};${canvasWidth}t`); break; case WindowsOptionsReportType.GET_CELL_SIZE_PIXELS: - const cellWidth = this._renderService.dimensions.actualCellWidth.toFixed(0); - const cellHeight = this._renderService.dimensions.actualCellHeight.toFixed(0); + const cellWidth = this._renderService.dimensions.css.cell.width.toFixed(0); + const cellHeight = this._renderService.dimensions.css.cell.height.toFixed(0); this.coreService.triggerDataEvent(`${C0.ESC}[6;${cellHeight};${cellWidth}t`); break; } diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index 97ad90d8..d55e961f 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -18,6 +18,7 @@ import { IFunctionIdentifier, IParams } from 'common/parser/Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { ISelectionRedrawRequestEvent, ISelectionRequestScrollLinesEvent } from 'browser/selection/Types'; import { css } from 'common/Color'; +import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; export class TestTerminal extends Terminal { public get curAttrData(): IAttributeData { return (this as any)._inputHandler._curAttrData; } @@ -372,20 +373,7 @@ export class MockRenderService implements IRenderService { public onRenderedViewportChange: IEvent<{ start: number, end: number }, void> = new EventEmitter<{ start: number, end: number }>().event; public onRender: IEvent<{ start: number, end: number }, void> = new EventEmitter<{ start: number, end: number }>().event; public onRefreshRequest: IEvent<{ start: number, end: number}, void> = new EventEmitter<{ start: number, end: number }>().event; - public dimensions: IRenderDimensions = { - scaledCharWidth: 0, - scaledCharHeight: 0, - scaledCellWidth: 0, - scaledCellHeight: 0, - scaledCharLeft: 0, - scaledCharTop: 0, - scaledCanvasWidth: 0, - scaledCanvasHeight: 0, - canvasWidth: 0, - canvasHeight: 0, - actualCellWidth: 0, - actualCellHeight: 0 - }; + public dimensions: IRenderDimensions = createRenderDimensions(); public refreshRows(start: number, end: number): void { throw new Error('Method not implemented.'); } diff --git a/src/browser/Viewport.ts b/src/browser/Viewport.ts index 700c9e22..8e01f23c 100644 --- a/src/browser/Viewport.ts +++ b/src/browser/Viewport.ts @@ -26,7 +26,7 @@ interface ISmoothScrollState { export class Viewport extends Disposable implements IViewport { public scrollBarWidth: number = 0; private _currentRowHeight: number = 0; - private _currentScaledCellHeight: number = 0; + private _currentDeviceCellHeight: number = 0; private _lastRecordedBufferLength: number = 0; private _lastRecordedViewportHeight: number = 0; private _lastRecordedBufferHeight: number = 0; @@ -104,10 +104,10 @@ export class Viewport extends Disposable implements IViewport { private _innerRefresh(): void { if (this._charSizeService.height > 0) { - this._currentRowHeight = this._renderService.dimensions.scaledCellHeight / this._coreBrowserService.dpr; - this._currentScaledCellHeight = this._renderService.dimensions.scaledCellHeight; + this._currentRowHeight = this._renderService.dimensions.device.cell.height / this._coreBrowserService.dpr; + this._currentDeviceCellHeight = this._renderService.dimensions.device.cell.height; this._lastRecordedViewportHeight = this._viewportElement.offsetHeight; - const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._renderService.dimensions.canvasHeight); + const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._renderService.dimensions.css.canvas.height); if (this._lastRecordedBufferHeight !== newBufferHeight) { this._lastRecordedBufferHeight = newBufferHeight; this._scrollArea.style.height = this._lastRecordedBufferHeight + 'px'; @@ -138,7 +138,7 @@ export class Viewport extends Disposable implements IViewport { } // If viewport height changed - if (this._lastRecordedViewportHeight !== this._renderService.dimensions.canvasHeight) { + if (this._lastRecordedViewportHeight !== this._renderService.dimensions.css.canvas.height) { this._refresh(immediate); return; } @@ -150,7 +150,7 @@ export class Viewport extends Disposable implements IViewport { } // If row height changed - if (this._renderDimensions.scaledCellHeight !== this._currentScaledCellHeight) { + if (this._renderDimensions.device.cell.height !== this._currentDeviceCellHeight) { this._refresh(immediate); return; } diff --git a/src/browser/decorations/BufferDecorationRenderer.ts b/src/browser/decorations/BufferDecorationRenderer.ts index 5836e266..72ed6428 100644 --- a/src/browser/decorations/BufferDecorationRenderer.ts +++ b/src/browser/decorations/BufferDecorationRenderer.ts @@ -72,10 +72,10 @@ export class BufferDecorationRenderer extends Disposable { private _createElement(decoration: IInternalDecoration): HTMLElement { const element = document.createElement('div'); element.classList.add('xterm-decoration'); - element.style.width = `${Math.round((decoration.options.width || 1) * this._renderService.dimensions.actualCellWidth)}px`; - element.style.height = `${(decoration.options.height || 1) * this._renderService.dimensions.actualCellHeight}px`; - element.style.top = `${(decoration.marker.line - this._bufferService.buffers.active.ydisp) * this._renderService.dimensions.actualCellHeight}px`; - element.style.lineHeight = `${this._renderService.dimensions.actualCellHeight}px`; + element.style.width = `${Math.round((decoration.options.width || 1) * this._renderService.dimensions.css.cell.width)}px`; + element.style.height = `${(decoration.options.height || 1) * this._renderService.dimensions.css.cell.height}px`; + element.style.top = `${(decoration.marker.line - this._bufferService.buffers.active.ydisp) * this._renderService.dimensions.css.cell.height}px`; + element.style.lineHeight = `${this._renderService.dimensions.css.cell.height}px`; const x = decoration.options.x ?? 0; if (x && x > this._bufferService.cols) { @@ -104,7 +104,7 @@ export class BufferDecorationRenderer extends Disposable { this._decorationElements.set(decoration, element); this._container.appendChild(element); } - element.style.top = `${line * this._renderService.dimensions.actualCellHeight}px`; + element.style.top = `${line * this._renderService.dimensions.css.cell.height}px`; element.style.display = this._altBufferIsActive ? 'none' : 'block'; decoration.onRenderEmitter.fire(element); } @@ -116,9 +116,9 @@ export class BufferDecorationRenderer extends Disposable { } const x = decoration.options.x ?? 0; if ((decoration.options.anchor || 'left') === 'right') { - element.style.right = x ? `${x * this._renderService.dimensions.actualCellWidth}px` : ''; + element.style.right = x ? `${x * this._renderService.dimensions.css.cell.width}px` : ''; } else { - element.style.left = x ? `${x * this._renderService.dimensions.actualCellWidth}px` : ''; + element.style.left = x ? `${x * this._renderService.dimensions.css.cell.width}px` : ''; } } diff --git a/src/browser/input/CompositionHelper.ts b/src/browser/input/CompositionHelper.ts index ba7d4b6a..7542969a 100644 --- a/src/browser/input/CompositionHelper.ts +++ b/src/browser/input/CompositionHelper.ts @@ -218,9 +218,9 @@ export class CompositionHelper { if (this._bufferService.buffer.isCursorInViewport) { const cursorX = Math.min(this._bufferService.buffer.x, this._bufferService.cols - 1); - const cellHeight = this._renderService.dimensions.actualCellHeight; - const cursorTop = this._bufferService.buffer.y * this._renderService.dimensions.actualCellHeight; - const cursorLeft = cursorX * this._renderService.dimensions.actualCellWidth; + const cellHeight = this._renderService.dimensions.css.cell.height; + const cursorTop = this._bufferService.buffer.y * this._renderService.dimensions.css.cell.height; + const cursorLeft = cursorX * this._renderService.dimensions.css.cell.width; this._compositionView.style.left = cursorLeft + 'px'; this._compositionView.style.top = cursorTop + 'px'; diff --git a/src/browser/input/Mouse.ts b/src/browser/input/Mouse.ts index 309d9265..c40a7cc7 100644 --- a/src/browser/input/Mouse.ts +++ b/src/browser/input/Mouse.ts @@ -24,13 +24,13 @@ export function getCoordsRelativeToElement(window: Pick, event: Pick, element: HTMLElement, colCount: number, rowCount: number, hasValidCharSize: boolean, actualCellWidth: number, actualCellHeight: number, isSelection?: boolean): [number, number] | undefined { +export function getCoords(window: Pick, event: Pick, element: HTMLElement, colCount: number, rowCount: number, hasValidCharSize: boolean, cssCellWidth: number, cssCellHeight: number, isSelection?: boolean): [number, number] | undefined { // Coordinates cannot be measured if there are no valid if (!hasValidCharSize) { return undefined; @@ -41,8 +41,8 @@ export function getCoords(window: Pick, event: Pick< return undefined; } - coords[0] = Math.ceil((coords[0] + (isSelection ? actualCellWidth / 2 : 0)) / actualCellWidth); - coords[1] = Math.ceil(coords[1] / actualCellHeight); + coords[0] = Math.ceil((coords[0] + (isSelection ? cssCellWidth / 2 : 0)) / cssCellWidth); + coords[1] = Math.ceil(coords[1] / cssCellHeight); // Ensure coordinates are within the terminal viewport. Note that selections // need an addition point of precision to cover the end point (as characters diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index 02738b5b..399682ac 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -3,16 +3,17 @@ * @license MIT */ -import { IRenderer, IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/shared/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 'browser/renderer/dom/DomRendererRowFactory'; -import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants'; -import { Disposable, toDisposable } from 'common/Lifecycle'; -import { IColorSet, ILinkifierEvent, ILinkifier2, ReadonlyColorSet } from 'browser/Types'; -import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; -import { IOptionsService, IBufferService, IInstantiationService } from 'common/services/Services'; -import { EventEmitter, IEvent } from 'common/EventEmitter'; -import { color } from 'common/Color'; import { removeElementFromParent } from 'browser/Dom'; +import { BOLD_CLASS, CURSOR_BLINK_CLASS, CURSOR_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory, ITALIC_CLASS } from 'browser/renderer/dom/DomRendererRowFactory'; +import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants'; +import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils'; +import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/shared/Types'; +import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services'; +import { ILinkifier2, ILinkifierEvent, ReadonlyColorSet } from 'browser/Types'; +import { color } from 'common/Color'; +import { EventEmitter } from 'common/EventEmitter'; +import { Disposable, toDisposable } from 'common/Lifecycle'; +import { IBufferService, IInstantiationService, IOptionsService } from 'common/services/Services'; const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-'; const ROW_CONTAINER_CLASS = 'xterm-rows'; @@ -64,20 +65,7 @@ export class DomRenderer extends Disposable implements IRenderer { this._selectionContainer.classList.add(SELECTION_CLASS); this._selectionContainer.setAttribute('aria-hidden', 'true'); - this.dimensions = { - scaledCharWidth: 0, - scaledCharHeight: 0, - scaledCellWidth: 0, - scaledCellHeight: 0, - scaledCharLeft: 0, - scaledCharTop: 0, - scaledCanvasWidth: 0, - scaledCanvasHeight: 0, - canvasWidth: 0, - canvasHeight: 0, - actualCellWidth: 0, - actualCellHeight: 0 - }; + this.dimensions = createRenderDimensions(); this._updateDimensions(); this.register(this._optionsService.onOptionChange(() => this._handleOptionsChanged())); @@ -104,23 +92,23 @@ export class DomRenderer extends Disposable implements IRenderer { private _updateDimensions(): void { const dpr = this._coreBrowserService.dpr; - this.dimensions.scaledCharWidth = this._charSizeService.width * dpr; - this.dimensions.scaledCharHeight = Math.ceil(this._charSizeService.height * dpr); - this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._optionsService.rawOptions.letterSpacing); - this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._optionsService.rawOptions.lineHeight); - this.dimensions.scaledCharLeft = 0; - this.dimensions.scaledCharTop = 0; - this.dimensions.scaledCanvasWidth = this.dimensions.scaledCellWidth * this._bufferService.cols; - this.dimensions.scaledCanvasHeight = this.dimensions.scaledCellHeight * this._bufferService.rows; - this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / dpr); - this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / dpr); - this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._bufferService.cols; - this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._bufferService.rows; + this.dimensions.device.char.width = this._charSizeService.width * dpr; + this.dimensions.device.char.height = Math.ceil(this._charSizeService.height * dpr); + this.dimensions.device.cell.width = this.dimensions.device.char.width + Math.round(this._optionsService.rawOptions.letterSpacing); + this.dimensions.device.cell.height = Math.floor(this.dimensions.device.char.height * this._optionsService.rawOptions.lineHeight); + this.dimensions.device.char.left = 0; + this.dimensions.device.char.top = 0; + this.dimensions.device.canvas.width = this.dimensions.device.cell.width * this._bufferService.cols; + this.dimensions.device.canvas.height = this.dimensions.device.cell.height * this._bufferService.rows; + this.dimensions.css.canvas.width = Math.round(this.dimensions.device.canvas.width / dpr); + this.dimensions.css.canvas.height = Math.round(this.dimensions.device.canvas.height / dpr); + this.dimensions.css.cell.width = this.dimensions.css.canvas.width / this._bufferService.cols; + this.dimensions.css.cell.height = this.dimensions.css.canvas.height / this._bufferService.rows; for (const element of this._rowElements) { - element.style.width = `${this.dimensions.canvasWidth}px`; - element.style.height = `${this.dimensions.actualCellHeight}px`; - element.style.lineHeight = `${this.dimensions.actualCellHeight}px`; + element.style.width = `${this.dimensions.css.canvas.width}px`; + element.style.height = `${this.dimensions.css.cell.height}px`; + element.style.lineHeight = `${this.dimensions.css.cell.height}px`; // Make sure rows don't overflow onto following row element.style.overflow = 'hidden'; } @@ -135,14 +123,14 @@ export class DomRenderer extends Disposable implements IRenderer { ` display: inline-block;` + ` height: 100%;` + ` vertical-align: top;` + - ` width: ${this.dimensions.actualCellWidth}px` + + ` width: ${this.dimensions.css.cell.width}px` + `}`; this._dimensionsStyleElement.textContent = styles; this._selectionContainer.style.height = this._viewportElement.style.height; - this._screenElement.style.width = `${this.dimensions.canvasWidth}px`; - this._screenElement.style.height = `${this.dimensions.canvasHeight}px`; + this._screenElement.style.width = `${this.dimensions.css.canvas.width}px`; + this._screenElement.style.height = `${this.dimensions.css.canvas.height}px`; } private _injectCss(colors: ReadonlyColorSet): void { @@ -332,10 +320,10 @@ export class DomRenderer extends Disposable implements IRenderer { */ private _createSelectionElement(row: number, colStart: number, colEnd: number, rowCount: number = 1): HTMLElement { const element = document.createElement('div'); - element.style.height = `${rowCount * this.dimensions.actualCellHeight}px`; - element.style.top = `${row * this.dimensions.actualCellHeight}px`; - element.style.left = `${colStart * this.dimensions.actualCellWidth}px`; - element.style.width = `${this.dimensions.actualCellWidth * (colEnd - colStart)}px`; + element.style.height = `${rowCount * this.dimensions.css.cell.height}px`; + element.style.top = `${row * this.dimensions.css.cell.height}px`; + element.style.left = `${colStart * this.dimensions.css.cell.width}px`; + element.style.width = `${this.dimensions.css.cell.width * (colEnd - colStart)}px`; return element; } @@ -365,7 +353,7 @@ export class DomRenderer extends Disposable implements IRenderer { const row = y + this._bufferService.buffer.ydisp; const lineData = this._bufferService.buffer.lines.get(row); const cursorStyle = this._optionsService.rawOptions.cursorStyle; - rowElement.appendChild(this._rowFactory.createRow(lineData!, row, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.actualCellWidth, this._bufferService.cols)); + rowElement.appendChild(this._rowFactory.createRow(lineData!, row, row === cursorAbsoluteY, cursorStyle, cursorX, cursorBlink, this.dimensions.css.cell.width, this._bufferService.cols)); } } diff --git a/src/browser/renderer/shared/CharAtlasCache.ts b/src/browser/renderer/shared/CharAtlasCache.ts index e953dc46..48368a16 100644 --- a/src/browser/renderer/shared/CharAtlasCache.ts +++ b/src/browser/renderer/shared/CharAtlasCache.ts @@ -28,13 +28,13 @@ const charAtlasCache: ITextureAtlasCacheEntry[] = []; export function acquireTextureAtlas( terminal: Terminal, colors: ReadonlyColorSet, - scaledCellWidth: number, - scaledCellHeight: number, - scaledCharWidth: number, - scaledCharHeight: number, + deviceCellWidth: number, + deviceCellHeight: number, + deviceCharWidth: number, + deviceCharHeight: number, devicePixelRatio: number ): ITextureAtlas { - const newConfig = generateConfig(scaledCellWidth, scaledCellHeight, scaledCharWidth, scaledCharHeight, terminal, colors, devicePixelRatio); + const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, terminal, colors, devicePixelRatio); // Check to see if the terminal already owns this config for (let i = 0; i < charAtlasCache.length; i++) { diff --git a/src/browser/renderer/shared/CharAtlasUtils.ts b/src/browser/renderer/shared/CharAtlasUtils.ts index e443168e..e69b476a 100644 --- a/src/browser/renderer/shared/CharAtlasUtils.ts +++ b/src/browser/renderer/shared/CharAtlasUtils.ts @@ -9,7 +9,7 @@ import { Terminal } from 'xterm'; import { IColorSet, ReadonlyColorSet } from 'browser/Types'; import { NULL_COLOR } from 'common/Color'; -export function generateConfig(scaledCellWidth: number, scaledCellHeight: number, scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig { +export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, terminal: Terminal, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig { // null out some fields that don't matter const clonedColors: IColorSet = { foreground: colors.foreground, @@ -31,10 +31,10 @@ export function generateConfig(scaledCellWidth: number, scaledCellHeight: number devicePixelRatio, letterSpacing: terminal.options.letterSpacing, lineHeight: terminal.options.lineHeight, - scaledCellWidth, - scaledCellHeight, - scaledCharWidth, - scaledCharHeight, + deviceCellWidth: deviceCellWidth, + deviceCellHeight: deviceCellHeight, + deviceCharWidth: deviceCharWidth, + deviceCharHeight: deviceCharHeight, fontFamily: terminal.options.fontFamily, fontSize: terminal.options.fontSize, fontWeight: terminal.options.fontWeight, @@ -61,8 +61,8 @@ export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean a.fontWeight === b.fontWeight && a.fontWeightBold === b.fontWeightBold && a.allowTransparency === b.allowTransparency && - a.scaledCharWidth === b.scaledCharWidth && - a.scaledCharHeight === b.scaledCharHeight && + a.deviceCharWidth === b.deviceCharWidth && + a.deviceCharHeight === b.deviceCharHeight && a.drawBoldTextInBrightColors === b.drawBoldTextInBrightColors && a.minimumContrastRatio === b.minimumContrastRatio && a.colors.foreground.rgba === b.colors.foreground.rgba && diff --git a/src/browser/renderer/shared/CustomGlyphs.ts b/src/browser/renderer/shared/CustomGlyphs.ts index b8725685..fd56376b 100644 --- a/src/browser/renderer/shared/CustomGlyphs.ts +++ b/src/browser/renderer/shared/CustomGlyphs.ts @@ -381,32 +381,32 @@ export function tryDrawCustomChar( c: string, xOffset: number, yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number, + deviceCellWidth: number, + deviceCellHeight: number, fontSize: number, devicePixelRatio: number ): boolean { const blockElementDefinition = blockElementDefinitions[c]; if (blockElementDefinition) { - drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); + drawBlockElementChar(ctx, blockElementDefinition, xOffset, yOffset, deviceCellWidth, deviceCellHeight); return true; } const patternDefinition = patternCharacterDefinitions[c]; if (patternDefinition) { - drawPatternChar(ctx, patternDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight); + drawPatternChar(ctx, patternDefinition, xOffset, yOffset, deviceCellWidth, deviceCellHeight); return true; } const boxDrawingDefinition = boxDrawingDefinitions[c]; if (boxDrawingDefinition) { - drawBoxDrawingChar(ctx, boxDrawingDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight, devicePixelRatio); + drawBoxDrawingChar(ctx, boxDrawingDefinition, xOffset, yOffset, deviceCellWidth, deviceCellHeight, devicePixelRatio); return true; } const powerlineDefinition = powerlineDefinitions[c]; if (powerlineDefinition) { - drawPowerlineChar(ctx, powerlineDefinition, xOffset, yOffset, scaledCellWidth, scaledCellHeight, fontSize, devicePixelRatio); + drawPowerlineChar(ctx, powerlineDefinition, xOffset, yOffset, deviceCellWidth, deviceCellHeight, fontSize, devicePixelRatio); return true; } @@ -418,13 +418,13 @@ function drawBlockElementChar( charDefinition: IBlockVector[], xOffset: number, yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number + deviceCellWidth: number, + deviceCellHeight: number ): void { for (let i = 0; i < charDefinition.length; i++) { const box = charDefinition[i]; - const xEighth = scaledCellWidth / 8; - const yEighth = scaledCellHeight / 8; + const xEighth = deviceCellWidth / 8; + const yEighth = deviceCellHeight / 8; ctx.fillRect( xOffset + box.x * xEighth, yOffset + box.y * yEighth, @@ -441,8 +441,8 @@ function drawPatternChar( charDefinition: number[][], xOffset: number, yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number + deviceCellWidth: number, + deviceCellHeight: number ): void { let patternSet = cachedPatterns.get(charDefinition); if (!patternSet) { @@ -492,7 +492,7 @@ function drawPatternChar( patternSet.set(fillStyle, pattern); } ctx.fillStyle = pattern; - ctx.fillRect(xOffset, yOffset, scaledCellWidth, scaledCellHeight); + ctx.fillRect(xOffset, yOffset, deviceCellWidth, deviceCellHeight); } /** @@ -540,8 +540,8 @@ function drawBoxDrawingChar( charDefinition: { [fontWeight: number]: string | ((xp: number, yp: number) => string) }, xOffset: number, yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number, + deviceCellWidth: number, + deviceCellHeight: number, devicePixelRatio: number ): void { ctx.strokeStyle = ctx.fillStyle; @@ -551,7 +551,7 @@ function drawBoxDrawingChar( let actualInstructions: string; if (typeof instructions === 'function') { const xp = .15; - const yp = .15 / scaledCellHeight * scaledCellWidth; + const yp = .15 / deviceCellHeight * deviceCellWidth; actualInstructions = instructions(xp, yp); } else { actualInstructions = instructions; @@ -567,7 +567,7 @@ function drawBoxDrawingChar( if (!args[0] || !args[1]) { continue; } - f(ctx, translateArgs(args, scaledCellWidth, scaledCellHeight, xOffset, yOffset, true, devicePixelRatio)); + f(ctx, translateArgs(args, deviceCellWidth, deviceCellHeight, xOffset, yOffset, true, devicePixelRatio)); } ctx.stroke(); ctx.closePath(); @@ -579,8 +579,8 @@ function drawPowerlineChar( charDefinition: IVectorShape, xOffset: number, yOffset: number, - scaledCellWidth: number, - scaledCellHeight: number, + deviceCellWidth: number, + deviceCellHeight: number, fontSize: number, devicePixelRatio: number ): void { @@ -601,8 +601,8 @@ function drawPowerlineChar( } f(ctx, translateArgs( args, - scaledCellWidth, - scaledCellHeight, + deviceCellWidth, + deviceCellHeight, xOffset, yOffset, false, diff --git a/src/browser/renderer/shared/RendererUtils.ts b/src/browser/renderer/shared/RendererUtils.ts index 0f60dc29..052f2894 100644 --- a/src/browser/renderer/shared/RendererUtils.ts +++ b/src/browser/renderer/shared/RendererUtils.ts @@ -3,6 +3,8 @@ * @license MIT */ +import { IDimensions, IOffset, IRenderDimensions } from 'browser/renderer/shared/Types'; + export function throwIfFalsy(value: T | undefined | null): T { if (!value) { throw new Error('value must not be falsy'); @@ -28,3 +30,29 @@ function isBoxOrBlockGlyph(codepoint: number): boolean { export function excludeFromContrastRatioDemands(codepoint: number): boolean { return isPowerlineGlyph(codepoint) || isBoxOrBlockGlyph(codepoint); } + +export function createRenderDimensions(): IRenderDimensions { + return { + css: { + canvas: createDimension(), + cell: createDimension() + }, + device: { + canvas: createDimension(), + cell: createDimension(), + char: { + width: 0, + height: 0, + left: 0, + top: 0 + } + } + }; +} + +function createDimension(): IDimensions { + return { + width: 0, + height: 0 + }; +} diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index 162c7bdf..23deb8a3 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -98,8 +98,8 @@ export class TextureAtlas implements ITextureAtlas { this._cacheCtx = throwIfFalsy(this.cacheCanvas.getContext('2d', { alpha: true })); this._tmpCanvas = document.createElement('canvas'); - this._tmpCanvas.width = this._config.scaledCellWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2; - this._tmpCanvas.height = this._config.scaledCellHeight + TMP_CANVAS_GLYPH_PADDING * 2; + this._tmpCanvas.width = this._config.deviceCellWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2; + this._tmpCanvas.height = this._config.deviceCellHeight + TMP_CANVAS_GLYPH_PADDING * 2; this._tmpCtx = throwIfFalsy(this._tmpCanvas.getContext('2d', { alpha: this._config.allowTransparency, willReadFrequently: true @@ -345,12 +345,12 @@ export class TextureAtlas implements ITextureAtlas { // Allow 1 cell width per character, with a minimum of 2 (CJK), plus some padding. This is used // to draw the glyph to the canvas as well as to restrict the bounding box search to ensure // giant ligatures (eg. =====>) don't impact overall performance. - const allowedWidth = this._config.scaledCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; + const allowedWidth = this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; if (this._tmpCanvas.width < allowedWidth) { this._tmpCanvas.width = allowedWidth; } // Include line height when drawing glyphs - const allowedHeight = this._config.scaledCellHeight + TMP_CANVAS_GLYPH_PADDING * 4; + const allowedHeight = this._config.deviceCellHeight + TMP_CANVAS_GLYPH_PADDING * 4; if (this._tmpCanvas.height < allowedHeight) { this._tmpCanvas.height = allowedHeight; } @@ -411,7 +411,7 @@ export class TextureAtlas implements ITextureAtlas { // Draw custom characters if applicable let customGlyph = false; if (this._config.customGlyphs !== false) { - customGlyph = tryDrawCustomChar(this._tmpCtx, chars, padding, padding, this._config.scaledCellWidth, this._config.scaledCellHeight, this._config.fontSize, this._config.devicePixelRatio); + customGlyph = tryDrawCustomChar(this._tmpCtx, chars, padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight, this._config.fontSize, this._config.devicePixelRatio); } // Whether to clear pixels based on a threshold difference between the glyph color and the @@ -452,15 +452,15 @@ export class TextureAtlas implements ITextureAtlas { // Underline style/stroke this._tmpCtx.beginPath(); const xLeft = padding; - const yTop = Math.ceil(padding + this._config.scaledCharHeight) - yOffset; - const yMid = padding + this._config.scaledCharHeight + lineWidth - yOffset; - const yBot = Math.ceil(padding + this._config.scaledCharHeight + lineWidth * 2) - yOffset; + const yTop = Math.ceil(padding + this._config.deviceCharHeight) - yOffset; + const yMid = padding + this._config.deviceCharHeight + lineWidth - yOffset; + const yBot = Math.ceil(padding + this._config.deviceCharHeight + lineWidth * 2) - yOffset; for (let i = 0; i < chWidth; i++) { this._tmpCtx.save(); - const xChLeft = xLeft + i * this._config.scaledCellWidth; - const xChRight = xLeft + (i + 1) * this._config.scaledCellWidth; - const xChMid = xChLeft + this._config.scaledCellWidth / 2; + const xChLeft = xLeft + i * this._config.deviceCellWidth; + const xChRight = xLeft + (i + 1) * this._config.deviceCellWidth; + const xChMid = xChLeft + this._config.deviceCellWidth / 2; switch (this._workAttributeData.extended.underlineStyle) { case UnderlineStyle.DOUBLE: this._tmpCtx.moveTo(xChLeft, yTop); @@ -471,18 +471,18 @@ export class TextureAtlas implements ITextureAtlas { case UnderlineStyle.CURLY: // Choose the bezier top and bottom based on the device pixel ratio, the curly line is // made taller when the line width is as otherwise it's not very clear otherwise. - const yCurlyBot = lineWidth <= 1 ? yBot : Math.ceil(padding + this._config.scaledCharHeight - lineWidth / 2) - yOffset; - const yCurlyTop = lineWidth <= 1 ? yTop : Math.ceil(padding + this._config.scaledCharHeight + lineWidth / 2) - yOffset; + const yCurlyBot = lineWidth <= 1 ? yBot : Math.ceil(padding + this._config.deviceCharHeight - lineWidth / 2) - yOffset; + const yCurlyTop = lineWidth <= 1 ? yTop : Math.ceil(padding + this._config.deviceCharHeight + lineWidth / 2) - yOffset; // Clip the left and right edges of the underline such that it can be drawn just outside // the edge of the cell to ensure a continuous stroke when there are multiple underlined // glyphs adjacent to one another. const clipRegion = new Path2D(); - clipRegion.rect(xChLeft, yTop, this._config.scaledCellWidth, yBot - yTop); + clipRegion.rect(xChLeft, yTop, this._config.deviceCellWidth, yBot - yTop); this._tmpCtx.clip(clipRegion); // Start 1/2 cell before and end 1/2 cells after to ensure a smooth curve with other cells - this._tmpCtx.moveTo(xChLeft - this._config.scaledCellWidth / 2, yMid); + this._tmpCtx.moveTo(xChLeft - this._config.deviceCellWidth / 2, yMid); this._tmpCtx.bezierCurveTo( - xChLeft - this._config.scaledCellWidth / 2, yCurlyTop, + xChLeft - this._config.deviceCellWidth / 2, yCurlyTop, xChLeft, yCurlyTop, xChLeft, yMid ); @@ -498,8 +498,8 @@ export class TextureAtlas implements ITextureAtlas { ); this._tmpCtx.bezierCurveTo( xChRight, yCurlyBot, - xChRight + this._config.scaledCellWidth / 2, yCurlyBot, - xChRight + this._config.scaledCellWidth / 2, yMid + xChRight + this._config.deviceCellWidth / 2, yCurlyBot, + xChRight + this._config.deviceCellWidth / 2, yMid ); break; case UnderlineStyle.DOTTED: @@ -543,11 +543,11 @@ export class TextureAtlas implements ITextureAtlas { // outline around the whole glyph, as well as additional pixels in the glyph at the top // which would increase GPU memory demands const clipRegion = new Path2D(); - clipRegion.rect(xLeft, yTop - Math.ceil(lineWidth / 2), this._config.scaledCellWidth, yBot - yTop + Math.ceil(lineWidth / 2)); + clipRegion.rect(xLeft, yTop - Math.ceil(lineWidth / 2), this._config.deviceCellWidth, yBot - yTop + Math.ceil(lineWidth / 2)); this._tmpCtx.clip(clipRegion); this._tmpCtx.lineWidth = this._config.devicePixelRatio * 3; this._tmpCtx.strokeStyle = backgroundColor.css; - this._tmpCtx.strokeText(chars, padding, padding + this._config.scaledCharHeight); + this._tmpCtx.strokeText(chars, padding, padding + this._config.deviceCharHeight); this._tmpCtx.restore(); } } @@ -556,21 +556,21 @@ export class TextureAtlas implements ITextureAtlas { // Draw the character if (!customGlyph) { - this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight); + this._tmpCtx.fillText(chars, padding, padding + this._config.deviceCharHeight); } // If this charcater is underscore and beyond the cell bounds, shift it up until it is visible // even on the bottom row, try for a maximum of 5 pixels. if (chars === '_' && !this._config.allowTransparency) { - let isBeyondCellBounds = clearColor(this._tmpCtx.getImageData(padding, padding, this._config.scaledCellWidth, this._config.scaledCellHeight), backgroundColor, foregroundColor, enableClearThresholdCheck); + let isBeyondCellBounds = clearColor(this._tmpCtx.getImageData(padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight), backgroundColor, foregroundColor, enableClearThresholdCheck); if (isBeyondCellBounds) { for (let offset = 1; offset <= 5; offset++) { this._tmpCtx.save(); this._tmpCtx.fillStyle = backgroundColor.css; this._tmpCtx.fillRect(0, 0, this._tmpCanvas.width, this._tmpCanvas.height); this._tmpCtx.restore(); - this._tmpCtx.fillText(chars, padding, padding + this._config.scaledCharHeight - offset); - isBeyondCellBounds = clearColor(this._tmpCtx.getImageData(padding, padding, this._config.scaledCellWidth, this._config.scaledCellHeight), backgroundColor, foregroundColor, enableClearThresholdCheck); + this._tmpCtx.fillText(chars, padding, padding + this._config.deviceCharHeight - offset); + isBeyondCellBounds = clearColor(this._tmpCtx.getImageData(padding, padding, this._config.deviceCellWidth, this._config.deviceCellHeight), backgroundColor, foregroundColor, enableClearThresholdCheck); if (!isBeyondCellBounds) { break; } @@ -585,8 +585,8 @@ export class TextureAtlas implements ITextureAtlas { this._tmpCtx.lineWidth = lineWidth; this._tmpCtx.strokeStyle = this._tmpCtx.fillStyle; this._tmpCtx.beginPath(); - this._tmpCtx.moveTo(padding, padding + Math.floor(this._config.scaledCharHeight / 2) - yOffset); - this._tmpCtx.lineTo(padding + this._config.scaledCharWidth * chWidth, padding + Math.floor(this._config.scaledCharHeight / 2) - yOffset); + this._tmpCtx.moveTo(padding, padding + Math.floor(this._config.deviceCharHeight / 2) - yOffset); + this._tmpCtx.lineTo(padding + this._config.deviceCharWidth * chWidth, padding + Math.floor(this._config.deviceCharHeight / 2) - yOffset); this._tmpCtx.stroke(); } @@ -697,8 +697,8 @@ export class TextureAtlas implements ITextureAtlas { */ private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean, customGlyph: boolean, padding: number): IRasterizedGlyph { boundingBox.top = 0; - const height = restrictedGlyph ? this._config.scaledCellHeight : this._tmpCanvas.height; - const width = restrictedGlyph ? this._config.scaledCellWidth : allowedWidth; + const height = restrictedGlyph ? this._config.deviceCellHeight : this._tmpCanvas.height; + const width = restrictedGlyph ? this._config.deviceCellWidth : allowedWidth; let found = false; for (let y = 0; y < height; y++) { for (let x = 0; x < width; x++) { @@ -770,8 +770,8 @@ export class TextureAtlas implements ITextureAtlas { y: (boundingBox.bottom - boundingBox.top + 1) / TEXTURE_HEIGHT }, offset: { - x: -boundingBox.left + padding + ((restrictedGlyph || customGlyph) ? Math.floor((this._config.scaledCellWidth - this._config.scaledCharWidth) / 2) : 0), - y: -boundingBox.top + padding + ((restrictedGlyph || customGlyph) ? this._config.lineHeight === 1 ? 0 : Math.round((this._config.scaledCellHeight - this._config.scaledCharHeight) / 2) : 0) + x: -boundingBox.left + padding + ((restrictedGlyph || customGlyph) ? Math.floor((this._config.deviceCellWidth - this._config.deviceCharWidth) / 2) : 0), + y: -boundingBox.top + padding + ((restrictedGlyph || customGlyph) ? this._config.lineHeight === 1 ? 0 : Math.round((this._config.deviceCellHeight - this._config.deviceCharHeight) / 2) : 0) } }; } diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index 61a90890..433d48a2 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -4,7 +4,7 @@ */ import { FontWeight, Terminal } from 'xterm'; -import { IColorSet, ReadonlyColorSet } from 'browser/Types'; +import { IColorSet } from 'browser/Types'; import { IDisposable } from 'common/Types'; import { IEvent } from 'common/EventEmitter'; @@ -17,29 +17,42 @@ export interface ICharAtlasConfig { fontFamily: string; fontWeight: FontWeight; fontWeightBold: FontWeight; - scaledCellWidth: number; - scaledCellHeight: number; - scaledCharWidth: number; - scaledCharHeight: number; + deviceCellWidth: number; + deviceCellHeight: number; + deviceCharWidth: number; + deviceCharHeight: number; allowTransparency: boolean; drawBoldTextInBrightColors: boolean; minimumContrastRatio: number; colors: IColorSet; } +export interface IDimensions { + width: number; + height: number; +} + +export interface IOffset { + top: number; + left: number; +} + 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; + /** + * Dimensions measured in CSS pixels (ie. device pixels / device pixel ratio). + */ + css: { + canvas: IDimensions; + cell: IDimensions; + }; + /** + * Dimensions measured in actual pixels as rendered to the device. + */ + device: { + canvas: IDimensions; + cell: IDimensions; + char: IDimensions & IOffset; + }; } export interface IRequestRedrawEvent { diff --git a/src/browser/services/MouseService.ts b/src/browser/services/MouseService.ts index 2f5550c9..38561dfd 100644 --- a/src/browser/services/MouseService.ts +++ b/src/browser/services/MouseService.ts @@ -23,8 +23,8 @@ export class MouseService implements IMouseService { colCount, rowCount, this._charSizeService.hasValidSize, - this._renderService.dimensions.actualCellWidth, - this._renderService.dimensions.actualCellHeight, + this._renderService.dimensions.css.cell.width, + this._renderService.dimensions.css.cell.height, isSelection ); } @@ -37,14 +37,14 @@ export class MouseService implements IMouseService { if (!this._charSizeService.hasValidSize || coords[0] < 0 || coords[1] < 0 - || coords[0] >= this._renderService.dimensions.canvasWidth - || coords[1] >= this._renderService.dimensions.canvasHeight) { + || coords[0] >= this._renderService.dimensions.css.canvas.width + || coords[1] >= this._renderService.dimensions.css.canvas.height) { return undefined; } return { - col: Math.floor(coords[0] / this._renderService.dimensions.actualCellWidth), - row: Math.floor(coords[1] / this._renderService.dimensions.actualCellHeight), + col: Math.floor(coords[0] / this._renderService.dimensions.css.cell.width), + row: Math.floor(coords[1] / this._renderService.dimensions.css.cell.height), x: Math.floor(coords[0]), y: Math.floor(coords[1]) }; diff --git a/src/browser/services/RenderService.ts b/src/browser/services/RenderService.ts index 190967db..75ca2867 100644 --- a/src/browser/services/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -186,7 +186,7 @@ export class RenderService extends Disposable implements IRenderService { return; } // Don't fire the event if the dimensions haven't changed - if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) { + if (this._renderer.dimensions.css.canvas.width === this._canvasWidth && this._renderer.dimensions.css.canvas.height === this._canvasHeight) { return; } this._onDimensionsChange.fire(this._renderer.dimensions); diff --git a/src/browser/services/SelectionService.test.ts b/src/browser/services/SelectionService.test.ts index f8a15e51..67158def 100644 --- a/src/browser/services/SelectionService.test.ts +++ b/src/browser/services/SelectionService.test.ts @@ -49,8 +49,8 @@ describe('SelectionService', () => { bufferService = new MockBufferService(20, 20, optionsService); buffer = bufferService.buffer; const renderService = new MockRenderService(); - renderService.dimensions.canvasHeight = 10 * 20; - renderService.dimensions.canvasWidth = 10 * 20; + renderService.dimensions.css.canvas.height = 10 * 20; + renderService.dimensions.css.canvas.width = 10 * 20; selectionService = new TestSelectionService(bufferService, optionsService, renderService); }); diff --git a/src/browser/services/SelectionService.ts b/src/browser/services/SelectionService.ts index 763f938b..486c1941 100644 --- a/src/browser/services/SelectionService.ts +++ b/src/browser/services/SelectionService.ts @@ -408,7 +408,7 @@ export class SelectionService extends Disposable implements ISelectionService { */ private _getMouseEventScrollAmount(event: MouseEvent): number { let offset = getCoordsRelativeToElement(this._coreBrowserService.window, event, this._screenElement)[1]; - const terminalHeight = this._renderService.dimensions.canvasHeight; + const terminalHeight = this._renderService.dimensions.css.canvas.height; if (offset >= 0 && offset <= terminalHeight) { return 0; } diff --git a/test/api/InputHandler.api.ts b/test/api/InputHandler.api.ts index 8192bfed..d83fcb1f 100644 --- a/test/api/InputHandler.api.ts +++ b/test/api/InputHandler.api.ts @@ -601,9 +601,9 @@ async function getCursor(): Promise<{ col: number, row: number }> { async function getDimensions(): Promise { const dim: IRenderDimensions = await page.evaluate(`term._core._renderService.dimensions`); return { - cellWidth: dim.actualCellWidth.toFixed(0), - cellHeight: dim.actualCellHeight.toFixed(0), - width: dim.canvasWidth.toFixed(0), - height: dim.canvasHeight.toFixed(0) + cellWidth: dim.css.cell.width.toFixed(0), + cellHeight: dim.css.cell.height.toFixed(0), + width: dim.css.canvas.width.toFixed(0), + height: dim.css.canvas.height.toFixed(0) }; } diff --git a/test/api/MouseTracking.api.ts b/test/api/MouseTracking.api.ts index 1b00fee5..8a64a59a 100644 --- a/test/api/MouseTracking.api.ts +++ b/test/api/MouseTracking.api.ts @@ -48,7 +48,7 @@ async function cellPos(col: number, row: number): Promise { (function() { const rect = window.term.element.getBoundingClientRect(); const dim = term._core._renderService.dimensions; - return {left: rect.left, top: rect.top, bottom: rect.bottom, right: rect.right, width: dim.actualCellWidth, height: dim.actualCellHeight}; + return {left: rect.left, top: rect.top, bottom: rect.bottom, right: rect.right, width: dim.css.cell.width, height: dim.css.cell.height}; })(); `); return [col * coords.width + coords.left + 2, row * coords.height + coords.top + 2]; diff --git a/test/api/Terminal.api.ts b/test/api/Terminal.api.ts index 27fb51a7..f1edf65c 100644 --- a/test/api/Terminal.api.ts +++ b/test/api/Terminal.api.ts @@ -7,6 +7,7 @@ import { assert } from 'chai'; import { pollFor, timeout, writeSync, openTerminal, launchBrowser } from './TestUtils'; import { Browser, Page } from 'playwright'; import { fail } from 'assert'; +import { IRenderDimensions } from 'browser/renderer/shared/Types'; const APP = 'http://127.0.0.1:3001/test'; @@ -720,7 +721,7 @@ describe('API Integration Tests', function(): void { await page.evaluate(`window.term = new Terminal()`); await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`); await page.evaluate(`document.querySelector('#terminal-container').style.display=''`); - await pollFor(page, `window.term._core._renderService.dimensions.actualCellWidth > 0`, true); + await pollFor(page, `window.term._core._renderService.dimensions.css.cell.width > 0`, true); }); describe('registerDecoration', () => { @@ -1032,21 +1033,6 @@ interface IDimensions { renderDimensions: IRenderDimensions; } -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; -} - async function getDimensions(): Promise { return await page.evaluate(` (function() { @@ -1062,8 +1048,8 @@ async function getDimensions(): Promise { async function getCellCoordinates(dimensions: IDimensions, col: number, row: number): Promise<{ x: number, y: number }> { return { - x: dimensions.left + dimensions.renderDimensions.scaledCellWidth * (col - 0.5), - y: dimensions.top + dimensions.renderDimensions.scaledCellHeight * (row - 0.5) + x: dimensions.left + dimensions.renderDimensions.device.cell.width * (col - 0.5), + y: dimensions.top + dimensions.renderDimensions.device.cell.height * (row - 0.5) }; }