|
3 | 3 | * @license MIT |
4 | 4 | */ |
5 | 5 |
|
6 | | -import { throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; |
| 6 | +import { isEmoji, throwIfFalsy } from 'browser/renderer/shared/RendererUtils'; |
7 | 7 | import { TextureAtlas } from 'browser/renderer/shared/TextureAtlas'; |
8 | 8 | import { IRasterizedGlyph, IRenderDimensions, ITextureAtlas } from 'browser/renderer/shared/Types'; |
9 | 9 | import { NULL_CELL_CODE } from 'common/buffer/Constants'; |
10 | 10 | import { Disposable, toDisposable } from 'common/Lifecycle'; |
11 | 11 | import { Terminal } from '@xterm/xterm'; |
12 | 12 | import { IRenderModel, IWebGL2RenderingContext, IWebGLVertexArrayObject } from './Types'; |
13 | 13 | import { createProgram, GLTexture, PROJECTION_MATRIX } from './WebglUtils'; |
| 14 | +import type { IOptionsService } from 'common/services/Services'; |
14 | 15 |
|
15 | 16 | interface IVertices { |
16 | 17 | attributes: Float32Array; |
@@ -111,7 +112,8 @@ export class GlyphRenderer extends Disposable { |
111 | 112 | constructor( |
112 | 113 | private readonly _terminal: Terminal, |
113 | 114 | private readonly _gl: IWebGL2RenderingContext, |
114 | | - private _dimensions: IRenderDimensions |
| 115 | + private _dimensions: IRenderDimensions, |
| 116 | + private readonly _optionsService: IOptionsService |
115 | 117 | ) { |
116 | 118 | super(); |
117 | 119 |
|
@@ -212,15 +214,15 @@ export class GlyphRenderer extends Disposable { |
212 | 214 | return this._atlas ? this._atlas.beginFrame() : true; |
213 | 215 | } |
214 | 216 |
|
215 | | - public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, lastBg: number): void { |
| 217 | + public updateCell(x: number, y: number, code: number, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void { |
216 | 218 | // Since this function is called for every cell (`rows*cols`), it must be very optimized. It |
217 | 219 | // should not instantiate any variables unless a new glyph is drawn to the cache where the |
218 | 220 | // slight slowdown is acceptable for the developer ergonomics provided as it's a once of for |
219 | 221 | // each glyph. |
220 | | - this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, lastBg); |
| 222 | + this._updateCell(this._vertices.attributes, x, y, code, bg, fg, ext, chars, width, lastBg); |
221 | 223 | } |
222 | 224 |
|
223 | | - private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, bg: number, fg: number, ext: number, chars: string, lastBg: number): void { |
| 225 | + private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, bg: number, fg: number, ext: number, chars: string, width: number, lastBg: number): void { |
224 | 226 | $i = (y * this._terminal.cols + x) * INDICES_PER_CELL; |
225 | 227 |
|
226 | 228 | // Exit early if this is a null character, allow space character to continue as it may have |
@@ -275,6 +277,21 @@ export class GlyphRenderer extends Disposable { |
275 | 277 | array[$i + 8] = $glyph.sizeClipSpace.y; |
276 | 278 | } |
277 | 279 | // a_cellpos only changes on resize |
| 280 | + |
| 281 | + // Reduce scale horizontally for wide glyphs printed in cells that would overlap with the |
| 282 | + // following cell (ie. the width is not 2). |
| 283 | + if (this._optionsService.rawOptions.rescaleOverlappingGlyphs) { |
| 284 | + if ( |
| 285 | + // Is single cell width |
| 286 | + width === 1 && |
| 287 | + // Glyph exceeds cell bounds, + 1 to avoid hurting readability |
| 288 | + $glyph.size.x > this._dimensions.device.cell.width + 1 && |
| 289 | + // Never rescale emoji |
| 290 | + code && !isEmoji(code) |
| 291 | + ) { |
| 292 | + array[$i + 2] = (this._dimensions.device.cell.width - /* improve readability */1) / this._dimensions.device.canvas.width; // - 1 to improve readability |
| 293 | + } |
| 294 | + } |
278 | 295 | } |
279 | 296 |
|
280 | 297 | public clear(): void { |
|
0 commit comments