From 4979e9d2be746ff526647726e8615cba87c5c4bf Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 26 Aug 2022 13:26:00 -0700 Subject: [PATCH 1/2] Show test characters in underline test --- demo/client.ts | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index 64c694f5a5..a053b59edd 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -766,12 +766,23 @@ function underlineTest() { term.write('\n\n\r'); term.writeln('Underline styles:'); term.writeln(''); - term.writeln(`${u(0)}4:0m - No underline`); - term.writeln(`${u(1)}4:1m - Straight`); - term.writeln(`${u(2)}4:2m - Double`); - term.writeln(`${u(3)}4:3m - Curly`); - term.writeln(`${u(4)}4:4m - Dotted`); - term.writeln(`${u(5)}4:5m - Dashed\x1b[0m`); + function showSequence(id: number, name: string) { + let alphabet = ''; + for (let i = 97; i < 123; i++) { + alphabet += String.fromCharCode(i); + } + let numbers = ''; + for (let i = 0; i < 10; i++) { + numbers += i.toString(); + } + return `${u(id)}4:${id}m - ${name}\x1b[4:0m`.padEnd(33, ' ') + `${u(id)}${alphabet} ${numbers}\x1b[4:0m`; + } + term.writeln(showSequence(0, 'No underline')); + term.writeln(showSequence(1, 'Straight')); + term.writeln(showSequence(2, 'Double')); + term.writeln(showSequence(3, 'Curly')); + term.writeln(showSequence(4, 'Dotted')); + term.writeln(showSequence(5, 'Dashed')); term.writeln(''); term.writeln(`Underline colors (256 color mode):`); term.writeln(''); From 7ffd9e1f7f24e35d79796118535177d59cc96f97 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 26 Aug 2022 14:16:02 -0700 Subject: [PATCH 2/2] Only draw character outline if it has a descent Fixes #4059 --- .../src/atlas/WebglCharAtlas.ts | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts index 90d13e5547..2af88b9217 100644 --- a/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts +++ b/addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts @@ -533,18 +533,26 @@ export class WebglCharAtlas implements IDisposable { // This only works when transparency is disabled because it's not clear how to clear stroked // text if (!this._config.allowTransparency && chars !== ' ') { - // This translates to 1/2 the line width in either direction + // Measure the text, only draw the stroke if there is a descent beyond an alphabetic text + // baseline this._tmpCtx.save(); - // Clip the region to only draw in valid pixels near the underline to avoid a slight - // outline around the whole glyph, as well as additional pixels in the glyph at the top - // which would increase GPU memory demands - const clipRegion = new Path2D(); - clipRegion.rect(xLeft, yTop - Math.ceil(lineWidth / 2), this._config.scaledCellWidth, yBot - yTop + Math.ceil(lineWidth / 2)); - this._tmpCtx.clip(clipRegion); - this._tmpCtx.lineWidth = window.devicePixelRatio * 3; - this._tmpCtx.strokeStyle = backgroundColor.css; - this._tmpCtx.strokeText(chars, padding, padding + this._config.scaledCharHeight); + this._tmpCtx.textBaseline = 'alphabetic'; + const metrics = this._tmpCtx.measureText(chars); this._tmpCtx.restore(); + if ('actualBoundingBoxDescent' in metrics && metrics.actualBoundingBoxDescent > 0) { + // This translates to 1/2 the line width in either direction + this._tmpCtx.save(); + // Clip the region to only draw in valid pixels near the underline to avoid a slight + // outline around the whole glyph, as well as additional pixels in the glyph at the top + // which would increase GPU memory demands + const clipRegion = new Path2D(); + clipRegion.rect(xLeft, yTop - Math.ceil(lineWidth / 2), this._config.scaledCellWidth, yBot - yTop + Math.ceil(lineWidth / 2)); + this._tmpCtx.clip(clipRegion); + this._tmpCtx.lineWidth = window.devicePixelRatio * 3; + this._tmpCtx.strokeStyle = backgroundColor.css; + this._tmpCtx.strokeText(chars, padding, padding + this._config.scaledCharHeight); + this._tmpCtx.restore(); + } } } }