mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Merge pull request #5278 from Tyriar/liga_texture_limit
Handle glyph widths up to the maximum device texture size
This commit is contained in:
@@ -33,6 +33,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
||||
private _charAtlasDisposable = this._register(new MutableDisposable());
|
||||
private _charAtlas: ITextureAtlas | undefined;
|
||||
private _devicePixelRatio: number;
|
||||
private _deviceMaxTextureSize: number;
|
||||
private _observerDisposable = this._register(new MutableDisposable());
|
||||
|
||||
private _model: RenderModel = new RenderModel();
|
||||
@@ -102,6 +103,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
||||
throw new Error('WebGL2 not supported ' + this._gl);
|
||||
}
|
||||
|
||||
this._deviceMaxTextureSize = this._gl.getParameter(this._gl.MAX_TEXTURE_SIZE);
|
||||
|
||||
this._register(addDisposableListener(this._canvas, 'webglcontextlost', (e) => {
|
||||
console.log('webglcontextlost event received');
|
||||
// Prevent the default behavior in order to enable WebGL context restoration.
|
||||
@@ -272,7 +275,8 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
||||
this.dimensions.device.cell.height,
|
||||
this.dimensions.device.char.width,
|
||||
this.dimensions.device.char.height,
|
||||
this._coreBrowserService.dpr
|
||||
this._coreBrowserService.dpr,
|
||||
this._deviceMaxTextureSize
|
||||
);
|
||||
if (this._charAtlas !== atlas) {
|
||||
this._onChangeTextureAtlas.fire(atlas.pages[0].canvas);
|
||||
|
||||
@@ -94,7 +94,8 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
|
||||
if (this._deviceCharWidth <= 0 && this._deviceCharHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr);
|
||||
|
||||
this._charAtlas = acquireTextureAtlas(terminal, this._optionsService.rawOptions, colorSet, this._deviceCellWidth, this._deviceCellHeight, this._deviceCharWidth, this._deviceCharHeight, this._coreBrowserService.dpr, 2048);
|
||||
this._charAtlas.warmUp();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,10 @@ export function acquireTextureAtlas(
|
||||
deviceCellHeight: number,
|
||||
deviceCharWidth: number,
|
||||
deviceCharHeight: number,
|
||||
devicePixelRatio: number
|
||||
devicePixelRatio: number,
|
||||
deviceMaxTextureSize: number
|
||||
): ITextureAtlas {
|
||||
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio);
|
||||
const newConfig = generateConfig(deviceCellWidth, deviceCellHeight, deviceCharWidth, deviceCharHeight, options, colors, devicePixelRatio, deviceMaxTextureSize);
|
||||
|
||||
// Check to see if the terminal already owns this config
|
||||
for (let i = 0; i < charAtlasCache.length; i++) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { ITerminalOptions } from '@xterm/xterm';
|
||||
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
|
||||
import { NULL_COLOR } from 'common/Color';
|
||||
|
||||
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number): ICharAtlasConfig {
|
||||
export function generateConfig(deviceCellWidth: number, deviceCellHeight: number, deviceCharWidth: number, deviceCharHeight: number, options: Required<ITerminalOptions>, colors: ReadonlyColorSet, devicePixelRatio: number, deviceMaxTextureSize: number): ICharAtlasConfig {
|
||||
// null out some fields that don't matter
|
||||
const clonedColors: IColorSet = {
|
||||
foreground: colors.foreground,
|
||||
@@ -34,6 +34,7 @@ export function generateConfig(deviceCellWidth: number, deviceCellHeight: number
|
||||
return {
|
||||
customGlyphs: options.customGlyphs,
|
||||
devicePixelRatio,
|
||||
deviceMaxTextureSize,
|
||||
letterSpacing: options.letterSpacing,
|
||||
lineHeight: options.lineHeight,
|
||||
deviceCellWidth: deviceCellWidth,
|
||||
|
||||
@@ -66,6 +66,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
|
||||
// The set of atlas pages that can be written to
|
||||
private _activePages: AtlasPage[] = [];
|
||||
private _overflowSizePage: AtlasPage | undefined;
|
||||
|
||||
private _tmpCanvas: HTMLCanvasElement;
|
||||
// A temporary context that glyphs are drawn to before being transfered to the atlas.
|
||||
@@ -431,7 +432,7 @@ 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 = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._textureSize);
|
||||
const allowedWidth = Math.min(this._config.deviceCellWidth * Math.max(chars.length, 2) + TMP_CANVAS_GLYPH_PADDING * 2, this._config.deviceMaxTextureSize);
|
||||
if (this._tmpCanvas.width < allowedWidth) {
|
||||
this._tmpCanvas.width = allowedWidth;
|
||||
}
|
||||
@@ -772,6 +773,27 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new page for oversized glyphs as they come up
|
||||
if (rasterizedGlyph.size.x > this._textureSize) {
|
||||
if (!this._overflowSizePage) {
|
||||
this._overflowSizePage = new AtlasPage(this._document, this._config.deviceMaxTextureSize);
|
||||
this.pages.push(this._overflowSizePage);
|
||||
|
||||
// Request the model to be cleared to refresh all texture pages.
|
||||
this._requestClearModel = true;
|
||||
this._onAddTextureAtlasCanvas.fire(this._overflowSizePage.canvas);
|
||||
}
|
||||
activePage = this._overflowSizePage;
|
||||
activeRow = this._overflowSizePage.currentRow;
|
||||
// Move to next row if necessary
|
||||
if (activeRow.x + rasterizedGlyph.size.x >= activePage.canvas.width) {
|
||||
activeRow.x = 0;
|
||||
activeRow.y += activeRow.height;
|
||||
activeRow.height = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a new page if too much vertical space would be wasted or there is not enough room
|
||||
// left in the page. The previous active row will become fixed in the process as it now has a
|
||||
// fixed height
|
||||
@@ -782,6 +804,7 @@ export class TextureAtlas implements ITextureAtlas {
|
||||
if (activePage.currentRow.y + activePage.currentRow.height + rasterizedGlyph.size.y >= activePage.canvas.height) {
|
||||
// Find the first page with room to create the new row on
|
||||
let candidatePage: AtlasPage | undefined;
|
||||
|
||||
for (const p of this._activePages) {
|
||||
if (p.currentRow.y + p.currentRow.height + rasterizedGlyph.size.y < p.canvas.height) {
|
||||
candidatePage = p;
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { Event } from 'vs/base/common/event';
|
||||
export interface ICharAtlasConfig {
|
||||
customGlyphs: boolean;
|
||||
devicePixelRatio: number;
|
||||
deviceMaxTextureSize: number;
|
||||
letterSpacing: number;
|
||||
lineHeight: number;
|
||||
fontSize: number;
|
||||
|
||||
Reference in New Issue
Block a user