xterm-addon-webgl
Advanced tools
Comparing version 0.11.0-beta.6 to 0.11.0-beta.7
@@ -41,3 +41,3 @@ "use strict"; | ||
this._tmpCanvas = document.createElement('canvas'); | ||
this._tmpCanvas.width = this._config.scaledCharWidth * 2 + TMP_CANVAS_GLYPH_PADDING * 2; | ||
this._tmpCanvas.width = this._config.scaledCharWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2; | ||
this._tmpCanvas.height = this._config.scaledCharHeight + TMP_CANVAS_GLYPH_PADDING * 2; | ||
@@ -238,2 +238,6 @@ this._tmpCtx = WebglUtils_1.throwIfFalsy(this._tmpCanvas.getContext('2d', { alpha: this._config.allowTransparency })); | ||
this.hasCanvasChanged = true; | ||
var allowedWidth = this._config.scaledCharWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; | ||
if (this._tmpCanvas.width < allowedWidth) { | ||
this._tmpCanvas.width = allowedWidth; | ||
} | ||
this._tmpCtx.save(); | ||
@@ -291,3 +295,3 @@ this._workAttributeData.fg = fg; | ||
} | ||
var rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, isPowerlineGlyph); | ||
var rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, isPowerlineGlyph); | ||
var clippedImageData = this._clipImageData(imageData, this._workBoundingBox); | ||
@@ -308,10 +312,10 @@ if (this._currentRowX + this._config.scaledCharWidth > TEXTURE_WIDTH) { | ||
}; | ||
WebglCharAtlas.prototype._findGlyphBoundingBox = function (imageData, boundingBox, restrictedGlyph) { | ||
WebglCharAtlas.prototype._findGlyphBoundingBox = function (imageData, boundingBox, allowedWidth, restrictedGlyph) { | ||
boundingBox.top = 0; | ||
var height = restrictedGlyph ? this._config.scaledCharHeight : this._tmpCanvas.height; | ||
var width = restrictedGlyph ? this._config.scaledCharWidth : this._tmpCanvas.width; | ||
var width = restrictedGlyph ? this._config.scaledCharWidth : allowedWidth; | ||
var found = false; | ||
for (var y = 0; y < height; y++) { | ||
for (var x = 0; x < width; x++) { | ||
var alphaOffset = y * width * 4 + x * 4 + 3; | ||
var alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -331,3 +335,3 @@ boundingBox.top = y; | ||
for (var y = 0; y < height; y++) { | ||
var alphaOffset = y * width * 4 + x * 4 + 3; | ||
var alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -347,3 +351,3 @@ boundingBox.left = x; | ||
for (var y = 0; y < height; y++) { | ||
var alphaOffset = y * width * 4 + x * 4 + 3; | ||
var alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -363,3 +367,3 @@ boundingBox.right = x; | ||
for (var x = 0; x < width; x++) { | ||
var alphaOffset = y * width * 4 + x * 4 + 3; | ||
var alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -366,0 +370,0 @@ boundingBox.bottom = y; |
@@ -23,4 +23,5 @@ "use strict"; | ||
var renderService = terminal._core._renderService; | ||
var characterJoinerService = terminal._core._characterJoinerService; | ||
var colors = terminal._core._colorManager.colors; | ||
this._renderer = new WebglRenderer_1.WebglRenderer(terminal, colors, this._preserveDrawingBuffer); | ||
this._renderer = new WebglRenderer_1.WebglRenderer(terminal, colors, characterJoinerService, this._preserveDrawingBuffer); | ||
this._renderer.onContextLoss(function () { return _this._onContextLoss.fire(); }); | ||
@@ -27,0 +28,0 @@ renderService.setRenderer(this._renderer); |
@@ -16,3 +16,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.WebglRenderer = void 0; | ||
exports.JoinedCellData = exports.WebglRenderer = void 0; | ||
var GlyphRenderer_1 = require("./GlyphRenderer"); | ||
@@ -29,8 +29,10 @@ var LinkRenderLayer_1 = require("./renderLayer/LinkRenderLayer"); | ||
var Lifecycle_2 = require("browser/Lifecycle"); | ||
var AttributeData_1 = require("common/buffer/AttributeData"); | ||
var WebglRenderer = (function (_super) { | ||
__extends(WebglRenderer, _super); | ||
function WebglRenderer(_terminal, _colors, preserveDrawingBuffer) { | ||
function WebglRenderer(_terminal, _colors, _characterJoinerService, preserveDrawingBuffer) { | ||
var _this = _super.call(this) || this; | ||
_this._terminal = _terminal; | ||
_this._colors = _colors; | ||
_this._characterJoinerService = _characterJoinerService; | ||
_this._model = new RenderModel_1.RenderModel(); | ||
@@ -239,2 +241,3 @@ _this._workCell = new CellData_1.CellData(); | ||
var terminal = this._core; | ||
var cell = this._workCell; | ||
for (var y = start; y <= end; y++) { | ||
@@ -244,6 +247,15 @@ var row = y + terminal.buffer.ydisp; | ||
this._model.lineLengths[y] = 0; | ||
var joinedRanges = this._characterJoinerService.getJoinedCharacters(row); | ||
for (var x = 0; x < terminal.cols; x++) { | ||
line.loadCell(x, this._workCell); | ||
var chars = this._workCell.getChars(); | ||
var code = this._workCell.getCode(); | ||
line.loadCell(x, cell); | ||
var isJoined = false; | ||
var lastCharX = x; | ||
if (joinedRanges.length > 0 && x === joinedRanges[0][0]) { | ||
isJoined = true; | ||
var range = joinedRanges.shift(); | ||
cell = new JoinedCellData(cell, line.translateToString(true, range[0], range[1]), range[1] - range[0]); | ||
lastCharX = range[1] - 1; | ||
} | ||
var chars = cell.getChars(); | ||
var code = cell.getCode(); | ||
var i = ((y * terminal.cols) + x) * RenderModel_1.RENDER_MODEL_INDICIES_PER_CELL; | ||
@@ -254,4 +266,4 @@ if (code !== Constants_1.NULL_CELL_CODE) { | ||
if (this._model.cells[i] === code && | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_BG_OFFSET] === this._workCell.bg && | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_FG_OFFSET] === this._workCell.fg) { | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_BG_OFFSET] === cell.bg && | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_FG_OFFSET] === cell.fg) { | ||
continue; | ||
@@ -263,5 +275,15 @@ } | ||
this._model.cells[i] = code; | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_BG_OFFSET] = this._workCell.bg; | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_FG_OFFSET] = this._workCell.fg; | ||
this._glyphRenderer.updateCell(x, y, code, this._workCell.bg, this._workCell.fg, chars); | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_BG_OFFSET] = cell.bg; | ||
this._model.cells[i + RenderModel_1.RENDER_MODEL_FG_OFFSET] = cell.fg; | ||
this._glyphRenderer.updateCell(x, y, code, cell.bg, cell.fg, chars); | ||
if (isJoined) { | ||
cell = this._workCell; | ||
for (x++; x < lastCharX; x++) { | ||
var j = ((y * terminal.cols) + x) * RenderModel_1.RENDER_MODEL_INDICIES_PER_CELL; | ||
this._glyphRenderer.updateCell(x, y, Constants_1.NULL_CELL_CODE, 0, 0, Constants_1.NULL_CELL_CHAR); | ||
this._model.cells[j] = Constants_1.NULL_CELL_CODE; | ||
this._model.cells[j + RenderModel_1.RENDER_MODEL_BG_OFFSET] = this._workCell.bg; | ||
this._model.cells[j + RenderModel_1.RENDER_MODEL_FG_OFFSET] = this._workCell.fg; | ||
} | ||
} | ||
} | ||
@@ -321,2 +343,35 @@ } | ||
exports.WebglRenderer = WebglRenderer; | ||
var JoinedCellData = (function (_super) { | ||
__extends(JoinedCellData, _super); | ||
function JoinedCellData(firstCell, chars, width) { | ||
var _this = _super.call(this) || this; | ||
_this.content = 0; | ||
_this.combinedData = ''; | ||
_this.fg = firstCell.fg; | ||
_this.bg = firstCell.bg; | ||
_this.combinedData = chars; | ||
_this._width = width; | ||
return _this; | ||
} | ||
JoinedCellData.prototype.isCombined = function () { | ||
return 2097152; | ||
}; | ||
JoinedCellData.prototype.getWidth = function () { | ||
return this._width; | ||
}; | ||
JoinedCellData.prototype.getChars = function () { | ||
return this.combinedData; | ||
}; | ||
JoinedCellData.prototype.getCode = function () { | ||
return 0x1FFFFF; | ||
}; | ||
JoinedCellData.prototype.setFromCharData = function (value) { | ||
throw new Error('not implemented'); | ||
}; | ||
JoinedCellData.prototype.getAsCharData = function () { | ||
return [this.fg, this.getChars(), this.getWidth(), this.getCode()]; | ||
}; | ||
return JoinedCellData; | ||
}(AttributeData_1.AttributeData)); | ||
exports.JoinedCellData = JoinedCellData; | ||
//# sourceMappingURL=WebglRenderer.js.map |
{ | ||
"name": "xterm-addon-webgl", | ||
"version": "0.11.0-beta.6", | ||
"version": "0.11.0-beta.7", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "The xterm.js authors", |
@@ -86,3 +86,3 @@ /** | ||
this._tmpCanvas = document.createElement('canvas'); | ||
this._tmpCanvas.width = this._config.scaledCharWidth * 2 + TMP_CANVAS_GLYPH_PADDING * 2; | ||
this._tmpCanvas.width = this._config.scaledCharWidth * 4 + TMP_CANVAS_GLYPH_PADDING * 2; | ||
this._tmpCanvas.height = this._config.scaledCharHeight + TMP_CANVAS_GLYPH_PADDING * 2; | ||
@@ -321,2 +321,9 @@ this._tmpCtx = throwIfFalsy(this._tmpCanvas.getContext('2d', { alpha: this._config.allowTransparency })); | ||
// 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.scaledCharWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2; | ||
if (this._tmpCanvas.width < allowedWidth) { | ||
this._tmpCanvas.width = allowedWidth; | ||
} | ||
this._tmpCtx.save(); | ||
@@ -410,3 +417,3 @@ | ||
const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, isPowerlineGlyph); | ||
const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox, allowedWidth, isPowerlineGlyph); | ||
const clippedImageData = this._clipImageData(imageData, this._workBoundingBox); | ||
@@ -444,10 +451,10 @@ | ||
*/ | ||
private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, restrictedGlyph: boolean): IRasterizedGlyph { | ||
private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox, allowedWidth: number, restrictedGlyph: boolean): IRasterizedGlyph { | ||
boundingBox.top = 0; | ||
const height = restrictedGlyph ? this._config.scaledCharHeight : this._tmpCanvas.height; | ||
const width = restrictedGlyph ? this._config.scaledCharWidth : this._tmpCanvas.width; | ||
const width = restrictedGlyph ? this._config.scaledCharWidth : allowedWidth; | ||
let found = false; | ||
for (let y = 0; y < height; y++) { | ||
for (let x = 0; x < width; x++) { | ||
const alphaOffset = y * width * 4 + x * 4 + 3; | ||
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -467,3 +474,3 @@ boundingBox.top = y; | ||
for (let y = 0; y < height; y++) { | ||
const alphaOffset = y * width * 4 + x * 4 + 3; | ||
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -483,3 +490,3 @@ boundingBox.left = x; | ||
for (let y = 0; y < height; y++) { | ||
const alphaOffset = y * width * 4 + x * 4 + 3; | ||
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -499,3 +506,3 @@ boundingBox.right = x; | ||
for (let x = 0; x < width; x++) { | ||
const alphaOffset = y * width * 4 + x * 4 + 3; | ||
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3; | ||
if (imageData.data[alphaOffset] !== 0) { | ||
@@ -502,0 +509,0 @@ boundingBox.bottom = y; |
@@ -8,3 +8,3 @@ /** | ||
import { WebglRenderer } from './WebglRenderer'; | ||
import { IRenderService } from 'browser/services/Services'; | ||
import { ICharacterJoinerService, IRenderService } from 'browser/services/Services'; | ||
import { IColorSet } from 'browser/Types'; | ||
@@ -29,4 +29,5 @@ import { EventEmitter } from 'common/EventEmitter'; | ||
const renderService: IRenderService = (<any>terminal)._core._renderService; | ||
const characterJoinerService: ICharacterJoinerService = (<any>terminal)._core._characterJoinerService; | ||
const colors: IColorSet = (<any>terminal)._core._colorManager.colors; | ||
this._renderer = new WebglRenderer(terminal, colors, this._preserveDrawingBuffer); | ||
this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, this._preserveDrawingBuffer); | ||
this._renderer.onContextLoss(() => this._onContextLoss.fire()); | ||
@@ -33,0 +34,0 @@ renderService.setRenderer(this._renderer); |
@@ -15,3 +15,3 @@ /** | ||
import { Disposable } from 'common/Lifecycle'; | ||
import { NULL_CELL_CODE } from 'common/buffer/Constants'; | ||
import { Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants'; | ||
import { Terminal, IEvent } from 'xterm'; | ||
@@ -24,2 +24,5 @@ import { IRenderLayer } from './renderLayer/Types'; | ||
import { addDisposableDomListener } from 'browser/Lifecycle'; | ||
import { ICharacterJoinerService } from 'browser/services/Services'; | ||
import { CharData, ICellData } from 'common/Types'; | ||
import { AttributeData } from 'common/buffer/AttributeData'; | ||
@@ -53,2 +56,3 @@ export class WebglRenderer extends Disposable implements IRenderer { | ||
private _colors: IColorSet, | ||
private readonly _characterJoinerService: ICharacterJoinerService, | ||
preserveDrawingBuffer?: boolean | ||
@@ -294,2 +298,3 @@ ) { | ||
const terminal = this._core; | ||
let cell: ICellData = this._workCell; | ||
@@ -300,7 +305,31 @@ for (let y = start; y <= end; y++) { | ||
this._model.lineLengths[y] = 0; | ||
const joinedRanges = this._characterJoinerService.getJoinedCharacters(row); | ||
for (let x = 0; x < terminal.cols; x++) { | ||
line.loadCell(x, this._workCell); | ||
line.loadCell(x, cell); | ||
const chars = this._workCell.getChars(); | ||
let code = this._workCell.getCode(); | ||
// If true, indicates that the current character(s) to draw were joined. | ||
let isJoined = false; | ||
let lastCharX = x; | ||
// Process any joined character ranges as needed. Because of how the | ||
// ranges are produced, we know that they are valid for the characters | ||
// and attributes of our input. | ||
if (joinedRanges.length > 0 && x === joinedRanges[0][0]) { | ||
isJoined = true; | ||
const range = joinedRanges.shift()!; | ||
// We already know the exact start and end column of the joined range, | ||
// so we get the string and width representing it directly | ||
cell = new JoinedCellData( | ||
cell, | ||
line!.translateToString(true, range[0], range[1]), | ||
range[1] - range[0] | ||
); | ||
// Skip over the cells occupied by this range in the loop | ||
lastCharX = range[1] - 1; | ||
} | ||
const chars = cell.getChars(); | ||
let code = cell.getCode(); | ||
const i = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL; | ||
@@ -314,4 +343,4 @@ | ||
if (this._model.cells[i] === code && | ||
this._model.cells[i + RENDER_MODEL_BG_OFFSET] === this._workCell.bg && | ||
this._model.cells[i + RENDER_MODEL_FG_OFFSET] === this._workCell.fg) { | ||
this._model.cells[i + RENDER_MODEL_BG_OFFSET] === cell.bg && | ||
this._model.cells[i + RENDER_MODEL_FG_OFFSET] === cell.fg) { | ||
continue; | ||
@@ -327,6 +356,20 @@ } | ||
this._model.cells[i] = code; | ||
this._model.cells[i + RENDER_MODEL_BG_OFFSET] = this._workCell.bg; | ||
this._model.cells[i + RENDER_MODEL_FG_OFFSET] = this._workCell.fg; | ||
this._model.cells[i + RENDER_MODEL_BG_OFFSET] = cell.bg; | ||
this._model.cells[i + RENDER_MODEL_FG_OFFSET] = cell.fg; | ||
this._glyphRenderer.updateCell(x, y, code, this._workCell.bg, this._workCell.fg, chars); | ||
this._glyphRenderer.updateCell(x, y, code, cell.bg, cell.fg, chars); | ||
if (isJoined) { | ||
// Restore work cell | ||
cell = this._workCell; | ||
// Null out non-first cells | ||
for (x++; x < lastCharX; x++) { | ||
const j = ((y * terminal.cols) + x) * RENDER_MODEL_INDICIES_PER_CELL; | ||
this._glyphRenderer.updateCell(x, y, NULL_CELL_CODE, 0, 0, NULL_CELL_CHAR); | ||
this._model.cells[j] = NULL_CELL_CODE; | ||
this._model.cells[j + RENDER_MODEL_BG_OFFSET] = this._workCell.bg; | ||
this._model.cells[j + RENDER_MODEL_FG_OFFSET] = this._workCell.fg; | ||
} | ||
} | ||
} | ||
@@ -448,1 +491,47 @@ } | ||
} | ||
// TODO: Share impl with core | ||
export class JoinedCellData extends AttributeData implements ICellData { | ||
private _width: number; | ||
// .content carries no meaning for joined CellData, simply nullify it | ||
// thus we have to overload all other .content accessors | ||
public content: number = 0; | ||
public fg: number; | ||
public bg: number; | ||
public combinedData: string = ''; | ||
constructor(firstCell: ICellData, chars: string, width: number) { | ||
super(); | ||
this.fg = firstCell.fg; | ||
this.bg = firstCell.bg; | ||
this.combinedData = chars; | ||
this._width = width; | ||
} | ||
public isCombined(): number { | ||
// always mark joined cell data as combined | ||
return Content.IS_COMBINED_MASK; | ||
} | ||
public getWidth(): number { | ||
return this._width; | ||
} | ||
public getChars(): string { | ||
return this.combinedData; | ||
} | ||
public getCode(): number { | ||
// code always gets the highest possible fake codepoint (read as -1) | ||
// this is needed as code is used by caches as identifier | ||
return 0x1FFFFF; | ||
} | ||
public setFromCharData(value: CharData): void { | ||
throw new Error('not implemented'); | ||
} | ||
public getAsCharData(): CharData { | ||
return [this.fg, this.getChars(), this.getWidth(), this.getCode()]; | ||
} | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
603730
5255