diff --git a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts index e22bc8d4e6..ff29bbf1b4 100644 --- a/addons/xterm-addon-canvas/src/BaseRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/BaseRenderLayer.ts @@ -375,9 +375,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer let glyph: IRasterizedGlyph; if (chars && chars.length > 1) { - glyph = this._charAtlas.getRasterizedGlyphCombinedChar(chars, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext); + glyph = this._charAtlas.getRasterizedGlyphCombinedChar(chars, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, true); } else { - glyph = this._charAtlas.getRasterizedGlyph(cell.getCode() || WHITESPACE_CELL_CODE, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext); + glyph = this._charAtlas.getRasterizedGlyph(cell.getCode() || WHITESPACE_CELL_CODE, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, true); } if (!glyph.size.x || !glyph.size.y) { return; diff --git a/addons/xterm-addon-webgl/src/GlyphRenderer.ts b/addons/xterm-addon-webgl/src/GlyphRenderer.ts index 80a631e0b4..1c75b3b923 100644 --- a/addons/xterm-addon-webgl/src/GlyphRenderer.ts +++ b/addons/xterm-addon-webgl/src/GlyphRenderer.ts @@ -236,9 +236,9 @@ export class GlyphRenderer extends Disposable { // Get the glyph if (chars && chars.length > 1) { - $glyph = this._atlas.getRasterizedGlyphCombinedChar(chars, bg, fg, ext); + $glyph = this._atlas.getRasterizedGlyphCombinedChar(chars, bg, fg, ext, false); } else { - $glyph = this._atlas.getRasterizedGlyph(code, bg, fg, ext); + $glyph = this._atlas.getRasterizedGlyph(code, bg, fg, ext, false); } $leftCellPadding = Math.floor((this._dimensions.device.cell.width - this._dimensions.device.char.width) / 2); diff --git a/src/browser/renderer/shared/TextureAtlas.ts b/src/browser/renderer/shared/TextureAtlas.ts index d6bf1581f7..e77e595ddd 100644 --- a/src/browser/renderer/shared/TextureAtlas.ts +++ b/src/browser/renderer/shared/TextureAtlas.ts @@ -242,12 +242,12 @@ export class TextureAtlas implements ITextureAtlas { } } - public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number): IRasterizedGlyph { - return this._getFromCacheMap(this._cacheMapCombined, chars, bg, fg, ext); + public getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean): IRasterizedGlyph { + return this._getFromCacheMap(this._cacheMapCombined, chars, bg, fg, ext, restrictToCellHeight); } - public getRasterizedGlyph(code: number, bg: number, fg: number, ext: number): IRasterizedGlyph { - return this._getFromCacheMap(this._cacheMap, code, bg, fg, ext); + public getRasterizedGlyph(code: number, bg: number, fg: number, ext: number, restrictToCellHeight: boolean): IRasterizedGlyph { + return this._getFromCacheMap(this._cacheMap, code, bg, fg, ext, restrictToCellHeight); } /** @@ -258,11 +258,12 @@ export class TextureAtlas implements ITextureAtlas { key: string | number, bg: number, fg: number, - ext: number + ext: number, + restrictToCellHeight: boolean = false ): IRasterizedGlyph { $glyph = cacheMap.get(key, bg, fg, ext); if (!$glyph) { - $glyph = this._drawToCache(key, bg, fg, ext); + $glyph = this._drawToCache(key, bg, fg, ext, restrictToCellHeight); cacheMap.set(key, bg, fg, ext, $glyph); } return $glyph; @@ -414,7 +415,7 @@ export class TextureAtlas implements ITextureAtlas { return color; } - private _drawToCache(codeOrChars: number | string, bg: number, fg: number, ext: number): IRasterizedGlyph { + private _drawToCache(codeOrChars: number | string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean = false): IRasterizedGlyph { const chars = typeof codeOrChars === 'number' ? String.fromCharCode(codeOrChars) : codeOrChars; // Uncomment for debugging @@ -534,6 +535,7 @@ export class TextureAtlas implements ITextureAtlas { const yTop = Math.ceil(padding + this._config.deviceCharHeight) - yOffset; const yMid = padding + this._config.deviceCharHeight + lineWidth - yOffset; const yBot = Math.ceil(padding + this._config.deviceCharHeight + lineWidth * 2) - yOffset; + const ySpace = lineWidth * 2; for (let i = 0; i < chWidth; i++) { this._tmpCtx.save(); @@ -542,10 +544,17 @@ export class TextureAtlas implements ITextureAtlas { const xChMid = xChLeft + this._config.deviceCellWidth / 2; switch (this._workAttributeData.extended.underlineStyle) { case UnderlineStyle.DOUBLE: - this._tmpCtx.moveTo(xChLeft, yTop); - this._tmpCtx.lineTo(xChRight, yTop); - this._tmpCtx.moveTo(xChLeft, yBot); - this._tmpCtx.lineTo(xChRight, yBot); + if (restrictToCellHeight) { + this._tmpCtx.moveTo(xChLeft, yTop - ySpace); + this._tmpCtx.lineTo(xChRight, yTop - ySpace); + this._tmpCtx.moveTo(xChLeft, yTop); + this._tmpCtx.lineTo(xChRight, yTop); + } else { + this._tmpCtx.moveTo(xChLeft, yTop); + this._tmpCtx.lineTo(xChRight, yTop); + this._tmpCtx.moveTo(xChLeft, yBot); + this._tmpCtx.lineTo(xChRight, yBot); + } break; case UnderlineStyle.CURLY: // Choose the bezier top and bottom based on the device pixel ratio, the curly line is diff --git a/src/browser/renderer/shared/Types.d.ts b/src/browser/renderer/shared/Types.d.ts index cf4513c26a..a7e55e72cd 100644 --- a/src/browser/renderer/shared/Types.d.ts +++ b/src/browser/renderer/shared/Types.d.ts @@ -107,8 +107,8 @@ export interface ITextureAtlas extends IDisposable { * Clear all glyphs from the texture atlas. */ clearTexture(): void; - getRasterizedGlyph(code: number, bg: number, fg: number, ext: number): IRasterizedGlyph; - getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number): IRasterizedGlyph; + getRasterizedGlyph(code: number, bg: number, fg: number, ext: number, restrictToCellHeight: boolean): IRasterizedGlyph; + getRasterizedGlyphCombinedChar(chars: string, bg: number, fg: number, ext: number, restrictToCellHeight: boolean): IRasterizedGlyph; } /**