UNPKG

xterm

Version:

Full xterm terminal, in your browser

88 lines (71 loc) 2.83 kB
/** * Copyright (c) 2016 The xterm.js authors. All rights reserved. * @license MIT */ import { IOptionsService } from 'common/services/Services'; import { IEvent, EventEmitter } from 'common/EventEmitter'; import { ICharSizeService } from 'browser/services/Services'; export class CharSizeService implements ICharSizeService { serviceBrand: any; public width: number = 0; public height: number = 0; private _measureStrategy: IMeasureStrategy; public get hasValidSize(): boolean { return this.width > 0 && this.height > 0; } private _onCharSizeChange = new EventEmitter<void>(); public get onCharSizeChange(): IEvent<void> { return this._onCharSizeChange.event; } constructor( readonly document: Document, readonly parentElement: HTMLElement, @IOptionsService private readonly _optionsService: IOptionsService ) { this._measureStrategy = new DomMeasureStrategy(document, parentElement, this._optionsService); } public measure(): void { const result = this._measureStrategy.measure(); if (result.width !== this.width || result.height !== this.height) { this.width = result.width; this.height = result.height; this._onCharSizeChange.fire(); } } } interface IMeasureStrategy { measure(): IReadonlyMeasureResult; } interface IReadonlyMeasureResult { readonly width: number; readonly height: number; } interface IMeasureResult { width: number; height: number; } // TODO: For supporting browsers we should also provide a CanvasCharDimensionsProvider that uses ctx.measureText class DomMeasureStrategy implements IMeasureStrategy { private _result: IMeasureResult = { width: 0, height: 0 }; private _measureElement: HTMLElement; constructor( private _document: Document, private _parentElement: HTMLElement, private _optionsService: IOptionsService ) { this._measureElement = this._document.createElement('span'); this._measureElement.classList.add('xterm-char-measure-element'); this._measureElement.textContent = 'W'; this._measureElement.setAttribute('aria-hidden', 'true'); this._parentElement.appendChild(this._measureElement); } public measure(): IReadonlyMeasureResult { this._measureElement.style.fontFamily = this._optionsService.options.fontFamily; this._measureElement.style.fontSize = `${this._optionsService.options.fontSize}px`; // Note that this triggers a synchronous layout const geometry = this._measureElement.getBoundingClientRect(); // If values are 0 then the element is likely currently display:none, in which case we should // retain the previous value. if (geometry.width !== 0 && geometry.height !== 0) { this._result.width = geometry.width; this._result.height = Math.ceil(geometry.height); } return this._result; } }