From 6ced3014cf2989acb22877aa755c68c3c479bb04 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 27 May 2022 10:37:04 -0700 Subject: [PATCH] Support opaque selections in DOM renderer Brings the DOM renderer closer to the webgl renderer which draws the text on top of the selection. This is done by leveraging the override system similar to in webgl and as well as forcing the element above the selection. This also improves contrast color caching for the DOM renderer. This should result in a slight performance hit but only when a selection is being made. The improved contrast seems worth it. Fixes #3838 --- src/browser/renderer/dom/DomRenderer.ts | 2 +- .../renderer/dom/DomRendererRowFactory.ts | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index fdeef91c..a966e6f9 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -226,7 +226,7 @@ export class DomRenderer extends Disposable implements IRenderer { `}` + `${this._terminalSelector} .${SELECTION_CLASS} div {` + ` position: absolute;` + - ` background-color: ${this._colors.selectionTransparent.css};` + + ` background-color: ${this._colors.selectionOpaque.css};` + `}`; // Colors this._colors.ansi.forEach((c, i) => { diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index 266d7587..39fd4fdd 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -206,14 +206,22 @@ export class DomRendererRowFactory { } // Apply selection foreground if applicable + const isInSelection = this._isCellInSelection(x, row); if (!isTop) { - if (this._colors.selectionForeground && this._isCellInSelection(x, row)) { + if (this._colors.selectionForeground && isInSelection) { fgColorMode = Attributes.CM_RGB; fg = this._colors.selectionForeground.rgba >> 8 & 0xFFFFFF; fgOverride = this._colors.selectionForeground; } } + // If in the selection, force the element to be above the selection to improve contrast and + // support opaque selections + if (isInSelection) { + bgOverride = this._colors.selectionOpaque; + isTop = true; + } + // If it's a top decoration, render above the selection if (isTop) { charElement.classList.add(`xterm-decoration-top`); @@ -226,7 +234,7 @@ export class DomRendererRowFactory { if (cell.isBold() && fg < 8 && this._optionsService.rawOptions.drawBoldTextInBrightColors) { fg += 8; } - if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.ansi[fg], cell, undefined, undefined)) { + if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.ansi[fg], cell, bgOverride, undefined)) { charElement.classList.add(`xterm-fg-${fg}`); } break; @@ -242,7 +250,7 @@ export class DomRendererRowFactory { break; case Attributes.CM_DEFAULT: default: - if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.foreground, cell, undefined, undefined)) { + if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.foreground, cell, bgOverride, undefined)) { if (isInverse) { charElement.classList.add(`xterm-fg-${INVERTED_DEFAULT_COLOR}`); } @@ -279,16 +287,14 @@ export class DomRendererRowFactory { // Try get from cache first, only use the cache when there are no decoration overrides let adjustedColor: IColor | undefined | null = undefined; - if (!bgOverride || !fgOverride) { - adjustedColor = this._colors.contrastCache.getColor(this._workCell.bg, this._workCell.fg); + if (!bgOverride && !fgOverride) { + adjustedColor = this._colors.contrastCache.getColor(bg.rgba, fg.rgba); } // Calculate and store in cache if (adjustedColor === undefined) { adjustedColor = color.ensureContrastRatio(bgOverride || bg, fgOverride || fg, this._optionsService.rawOptions.minimumContrastRatio); - if (!bgOverride || !fgOverride) { - this._colors.contrastCache.setColor(this._workCell.bg, this._workCell.fg, adjustedColor ?? null); - } + this._colors.contrastCache.setColor((bgOverride || bg).rgba, (fgOverride || fg).rgba, adjustedColor ?? null); } if (adjustedColor) {