@@ -112,15 +112,6 @@
|
|||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.xterm-char-measure-element {
|
|
||||||
display: inline-block;
|
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -9999em;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xterm.enable-mouse-events {
|
.xterm.enable-mouse-events {
|
||||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
|
||||||
import { IDisposable } from 'common/Types';
|
import { IDisposable } from 'common/Types';
|
||||||
import { FontWeight } from 'common/services/Services';
|
import { FontWeight } from 'common/services/Services';
|
||||||
|
|
||||||
@@ -42,50 +43,22 @@ export class WidthCache implements IDisposable {
|
|||||||
private _fontSize = 0;
|
private _fontSize = 0;
|
||||||
private _weight: FontWeight = 'normal';
|
private _weight: FontWeight = 'normal';
|
||||||
private _weightBold: FontWeight = 'bold';
|
private _weightBold: FontWeight = 'bold';
|
||||||
private _container: HTMLDivElement;
|
private _canvasElements: WidthCacheFontVariantCanvas[] = [];
|
||||||
private _measureElements: HTMLSpanElement[] = [];
|
|
||||||
|
|
||||||
constructor(_document: Document, _helperContainer: HTMLElement) {
|
constructor(_document: Document, _helperContainer: HTMLElement) {
|
||||||
this._container = _document.createElement('div');
|
this._canvasElements = [
|
||||||
this._container.classList.add('xterm-width-cache-measure-container');
|
new WidthCacheFontVariantCanvas(),
|
||||||
this._container.setAttribute('aria-hidden', 'true');
|
new WidthCacheFontVariantCanvas(),
|
||||||
// SP should stack in spans
|
new WidthCacheFontVariantCanvas(),
|
||||||
this._container.style.whiteSpace = 'pre';
|
new WidthCacheFontVariantCanvas()
|
||||||
// avoid undercuts in non-monospace fonts from kerning
|
];
|
||||||
this._container.style.fontKerning = 'none';
|
|
||||||
|
|
||||||
const regular = _document.createElement('span');
|
|
||||||
regular.classList.add('xterm-char-measure-element');
|
|
||||||
|
|
||||||
const bold = _document.createElement('span');
|
|
||||||
bold.classList.add('xterm-char-measure-element');
|
|
||||||
bold.style.fontWeight = 'bold';
|
|
||||||
|
|
||||||
const italic = _document.createElement('span');
|
|
||||||
italic.classList.add('xterm-char-measure-element');
|
|
||||||
italic.style.fontStyle = 'italic';
|
|
||||||
|
|
||||||
const boldItalic = _document.createElement('span');
|
|
||||||
boldItalic.classList.add('xterm-char-measure-element');
|
|
||||||
boldItalic.style.fontWeight = 'bold';
|
|
||||||
boldItalic.style.fontStyle = 'italic';
|
|
||||||
|
|
||||||
// NOTE: must be in order of FontVariant
|
|
||||||
this._measureElements = [regular, bold, italic, boldItalic];
|
|
||||||
this._container.appendChild(regular);
|
|
||||||
this._container.appendChild(bold);
|
|
||||||
this._container.appendChild(italic);
|
|
||||||
this._container.appendChild(boldItalic);
|
|
||||||
|
|
||||||
_helperContainer.appendChild(this._container);
|
|
||||||
|
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this._container.remove(); // remove elements from DOM
|
this._canvasElements.length = 0;
|
||||||
this._measureElements.length = 0; // release element refs
|
this._holey = undefined; // free cache memory via GC
|
||||||
this._holey = undefined; // free cache memory via GC
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,10 +77,11 @@ export class WidthCache implements IDisposable {
|
|||||||
*/
|
*/
|
||||||
public setFont(font: string, fontSize: number, weight: FontWeight, weightBold: FontWeight): void {
|
public setFont(font: string, fontSize: number, weight: FontWeight, weightBold: FontWeight): void {
|
||||||
// skip if nothing changed
|
// skip if nothing changed
|
||||||
if (font === this._font
|
if (
|
||||||
&& fontSize === this._fontSize
|
font === this._font &&
|
||||||
&& weight === this._weight
|
fontSize === this._fontSize &&
|
||||||
&& weightBold === this._weightBold
|
weight === this._weight &&
|
||||||
|
weightBold === this._weightBold
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -117,12 +91,10 @@ export class WidthCache implements IDisposable {
|
|||||||
this._weight = weight;
|
this._weight = weight;
|
||||||
this._weightBold = weightBold;
|
this._weightBold = weightBold;
|
||||||
|
|
||||||
this._container.style.fontFamily = this._font;
|
this._canvasElements[FontVariant.REGULAR].setFont(font, fontSize, weight, false);
|
||||||
this._container.style.fontSize = `${this._fontSize}px`;
|
this._canvasElements[FontVariant.BOLD].setFont(font, fontSize, weightBold, false);
|
||||||
this._measureElements[FontVariant.REGULAR].style.fontWeight = `${weight}`;
|
this._canvasElements[FontVariant.ITALIC].setFont(font, fontSize, weight, true);
|
||||||
this._measureElements[FontVariant.BOLD].style.fontWeight = `${weightBold}`;
|
this._canvasElements[FontVariant.BOLD_ITALIC].setFont(font, fontSize, weightBold, true);
|
||||||
this._measureElements[FontVariant.ITALIC].style.fontWeight = `${weight}`;
|
|
||||||
this._measureElements[FontVariant.BOLD_ITALIC].style.fontWeight = `${weightBold}`;
|
|
||||||
|
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
@@ -160,8 +132,25 @@ export class WidthCache implements IDisposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _measure(c: string, variant: FontVariant): number {
|
protected _measure(c: string, variant: FontVariant): number {
|
||||||
const el = this._measureElements[variant];
|
return this._canvasElements[variant].measure(c);
|
||||||
el.textContent = c.repeat(WidthCacheSettings.REPEAT);
|
}
|
||||||
return el.offsetWidth / WidthCacheSettings.REPEAT;
|
}
|
||||||
|
|
||||||
|
class WidthCacheFontVariantCanvas {
|
||||||
|
private _canvas: OffscreenCanvas;
|
||||||
|
private _ctx: OffscreenCanvasRenderingContext2D;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._canvas = new OffscreenCanvas(1, 1);
|
||||||
|
this._ctx = throwIfFalsy(this._canvas.getContext('2d'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public setFont(fontFamily: string, fontSize: number, fontWeight: FontWeight, italic: boolean): void {
|
||||||
|
const fontStyle = italic ? 'italic' : '';
|
||||||
|
this._ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public measure(c: string): number {
|
||||||
|
return this._ctx.measureText(c).width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user