Skip to content

Commit b0c29ca

Browse files
authored
Merge pull request #3932 from Tyriar/tyriar/dim_bg
Fix inverse dim rendering on canvas+webgl
2 parents 1af6175 + 48142ec commit b0c29ca

File tree

7 files changed

+77
-29
lines changed

7 files changed

+77
-29
lines changed

addons/xterm-addon-canvas/src/TextRenderLayer.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { CellData } from 'common/buffer/CellData';
1414
import { IOptionsService, IBufferService, IDecorationService } from 'common/services/Services';
1515
import { ICharacterJoinerService } from 'browser/services/Services';
1616
import { JoinedCellData } from 'browser/services/CharacterJoinerService';
17+
import { color, css } from 'common/Color';
1718

1819
/**
1920
* This CharData looks like a null character, which will forc a clear and render
@@ -177,6 +178,12 @@ export class TextRenderLayer extends BaseRenderLayer {
177178
nextFillStyle = this._colors.ansi[cell.getBgColor()].css;
178179
}
179180

181+
// Apply dim to the background, this is relatively slow as the CSS is re-parsed but dim is
182+
// rarely used
183+
if (nextFillStyle && cell.isDim()) {
184+
nextFillStyle = color.multiplyOpacity(css.toColor(nextFillStyle), 0.5).css;
185+
}
186+
180187
// Get any decoration foreground/background overrides, this must be fetched before the early
181188
// exist but applied after inverse
182189
let isTop = false;

addons/xterm-addon-canvas/src/atlas/DynamicCharAtlas.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,18 @@ export class DynamicCharAtlas extends BaseCharAtlas {
225225
// around the anti-aliased edges of the glyph, and it would look too dark.
226226
return TRANSPARENT_COLOR;
227227
}
228+
let result: IColor;
228229
if (glyph.bg === INVERTED_DEFAULT_COLOR) {
229-
return this._config.colors.foreground;
230+
result = this._config.colors.foreground;
231+
} else if (glyph.bg < 256) {
232+
result = this._getColorFromAnsiIndex(glyph.bg);
233+
} else {
234+
result = this._config.colors.background;
230235
}
231-
if (glyph.bg < 256) {
232-
return this._getColorFromAnsiIndex(glyph.bg);
236+
if (glyph.dim) {
237+
result = color.blend(this._config.colors.background, color.multiplyOpacity(result, 0.5));
233238
}
234-
return this._config.colors.background;
239+
return result;
235240
}
236241

237242
private _getForegroundColor(glyph: IGlyphIdentifier): IColor {
@@ -274,6 +279,7 @@ export class DynamicCharAtlas extends BaseCharAtlas {
274279
if (glyph.dim) {
275280
this._tmpCtx.globalAlpha = DIM_OPACITY;
276281
}
282+
277283
// Draw the character
278284
this._tmpCtx.fillText(glyph.chars, 0, this._config.scaledCharHeight);
279285

addons/xterm-addon-webgl/src/RectangleRenderer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { createProgram, expandFloat32Array, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils';
77
import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext } from './Types';
8-
import { Attributes, FgFlags } from 'common/buffer/Constants';
8+
import { Attributes, BgFlags, FgFlags } from 'common/buffer/Constants';
99
import { Terminal } from 'xterm';
1010
import { IColor } from 'common/Types';
1111
import { IColorSet } from 'browser/Types';
@@ -244,8 +244,9 @@ export class RectangleRenderer extends Disposable {
244244
const r = ((rgba >> 24) & 0xFF) / 255;
245245
const g = ((rgba >> 16) & 0xFF) / 255;
246246
const b = ((rgba >> 8 ) & 0xFF) / 255;
247+
const a = bg & BgFlags.DIM ? 0.5 : 1;
247248

248-
this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, 1);
249+
this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, a);
249250
}
250251

251252
private _addRectangle(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, r: number, g: number, b: number, a: number): void {

addons/xterm-addon-webgl/src/WebglRenderer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { RectangleRenderer } from './RectangleRenderer';
1212
import { IWebGL2RenderingContext } from './Types';
1313
import { RenderModel, COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel';
1414
import { Disposable, toDisposable } from 'common/Lifecycle';
15-
import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
15+
import { Attributes, BgFlags, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
1616
import { Terminal, IEvent } from 'xterm';
1717
import { IRenderLayer } from './renderLayer/Types';
1818
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types';
@@ -25,6 +25,7 @@ import { ICharacterJoinerService } from 'browser/services/Services';
2525
import { CharData, ICellData } from 'common/Types';
2626
import { AttributeData } from 'common/buffer/AttributeData';
2727
import { IDecorationService } from 'common/services/Services';
28+
import { color, rgba as rgbaNs } from 'common/Color';
2829

2930
export class WebglRenderer extends Disposable implements IRenderer {
3031
private _renderLayers: IRenderLayer[];

addons/xterm-addon-webgl/src/atlas/WebglCharAtlas.ts

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -189,58 +189,84 @@ export class WebglCharAtlas implements IDisposable {
189189
return this._config.colors.ansi[idx];
190190
}
191191

192-
private _getBackgroundColor(bgColorMode: number, bgColor: number, inverse: boolean): IColor {
192+
private _getBackgroundColor(bgColorMode: number, bgColor: number, inverse: boolean, dim: boolean): IColor {
193193
if (this._config.allowTransparency) {
194194
// The background color might have some transparency, so we need to render it as fully
195195
// transparent in the atlas. Otherwise we'd end up drawing the transparent background twice
196196
// around the anti-aliased edges of the glyph, and it would look too dark.
197197
return TRANSPARENT_COLOR;
198198
}
199199

200+
let result: IColor;
200201
switch (bgColorMode) {
201202
case Attributes.CM_P16:
202203
case Attributes.CM_P256:
203-
return this._getColorFromAnsiIndex(bgColor);
204+
result = this._getColorFromAnsiIndex(bgColor);
205+
break;
204206
case Attributes.CM_RGB:
205207
const arr = AttributeData.toColorRGB(bgColor);
206208
// TODO: This object creation is slow
207-
return {
208-
rgba: bgColor << 8,
209-
css: `#${toPaddedHex(arr[0])}${toPaddedHex(arr[1])}${toPaddedHex(arr[2])}`
210-
};
209+
result = rgba.toColor(arr[0], arr[1], arr[2]);
210+
break;
211211
case Attributes.CM_DEFAULT:
212212
default:
213213
if (inverse) {
214-
return this._config.colors.foreground;
214+
result = this._config.colors.foreground;
215+
} else {
216+
result = this._config.colors.background;
215217
}
216-
return this._config.colors.background;
218+
break;
219+
}
220+
221+
if (dim) {
222+
// Blend here instead of using opacity because transparent colors mess with clipping the
223+
// glyph's bounding box
224+
result = color.blend(this._config.colors.background, color.multiplyOpacity(result, 0.5));
217225
}
226+
227+
return result;
218228
}
219229

220-
private _getForegroundColor(bg: number, bgColorMode: number, bgColor: number, fg: number, fgColorMode: number, fgColor: number, inverse: boolean, bold: boolean, excludeFromContrastRatioDemands: boolean): IColor {
221-
const minimumContrastColor = this._getMinimumContrastColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, bold, excludeFromContrastRatioDemands);
230+
private _getForegroundColor(bg: number, bgColorMode: number, bgColor: number, fg: number, fgColorMode: number, fgColor: number, inverse: boolean, dim: boolean, bold: boolean, excludeFromContrastRatioDemands: boolean): IColor {
231+
// TODO: Pass dim along to get min contrast?
232+
const minimumContrastColor = this._getMinimumContrastColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, false, bold, excludeFromContrastRatioDemands);
222233
if (minimumContrastColor) {
223234
return minimumContrastColor;
224235
}
225236

237+
let result: IColor;
226238
switch (fgColorMode) {
227239
case Attributes.CM_P16:
228240
case Attributes.CM_P256:
229241
if (this._config.drawBoldTextInBrightColors && bold && fgColor < 8) {
230242
fgColor += 8;
231243
}
232-
return this._getColorFromAnsiIndex(fgColor);
244+
result = this._getColorFromAnsiIndex(fgColor);
245+
break;
233246
case Attributes.CM_RGB:
234247
const arr = AttributeData.toColorRGB(fgColor);
235-
return rgba.toColor(arr[0], arr[1], arr[2]);
248+
result = rgba.toColor(arr[0], arr[1], arr[2]);
249+
break;
236250
case Attributes.CM_DEFAULT:
237251
default:
238252
if (inverse) {
239-
// Inverse should always been opaque, even when transparency is used
240-
return color.opaque(this._config.colors.background);
253+
result = this._config.colors.background;
254+
} else {
255+
result = this._config.colors.foreground;
241256
}
242-
return this._config.colors.foreground;
243257
}
258+
259+
// Always use an opaque color regardless of allowTransparency
260+
if (this._config.allowTransparency) {
261+
result = color.opaque(result);
262+
}
263+
264+
// Apply dim to the color, opacity is fine to use for the foreground color
265+
if (dim) {
266+
result = color.multiplyOpacity(result, 0.5);
267+
}
268+
269+
return result;
244270
}
245271

246272
private _resolveBackgroundRgba(bgColorMode: number, bgColor: number, inverse: boolean): number {
@@ -357,7 +383,7 @@ export class WebglCharAtlas implements IDisposable {
357383
}
358384

359385
// draw the background
360-
const backgroundColor = this._getBackgroundColor(bgColorMode, bgColor, inverse);
386+
const backgroundColor = this._getBackgroundColor(bgColorMode, bgColor, inverse, dim);
361387
// Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, regardless of
362388
// transparency in backgroundColor
363389
this._tmpCtx.globalCompositeOperation = 'copy';
@@ -373,14 +399,9 @@ export class WebglCharAtlas implements IDisposable {
373399
this._tmpCtx.textBaseline = TEXT_BASELINE;
374400

375401
const powerLineGlyph = chars.length === 1 && isPowerlineGlyph(chars.charCodeAt(0));
376-
const foregroundColor = this._getForegroundColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, bold, excludeFromContrastRatioDemands(chars.charCodeAt(0)));
402+
const foregroundColor = this._getForegroundColor(bg, bgColorMode, bgColor, fg, fgColorMode, fgColor, inverse, dim, bold, excludeFromContrastRatioDemands(chars.charCodeAt(0)));
377403
this._tmpCtx.fillStyle = foregroundColor.css;
378404

379-
// Apply alpha to dim the character
380-
if (dim) {
381-
this._tmpCtx.globalAlpha = DIM_OPACITY;
382-
}
383-
384405
// For powerline glyphs left/top padding is excluded (https://github.com/microsoft/vscode/issues/120129)
385406
const padding = powerLineGlyph ? 0 : TMP_CANVAS_GLYPH_PADDING;
386407

src/browser/renderer/dom/DomRendererRowFactory.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ export class DomRendererRowFactory {
249249
}
250250
}
251251

252+
// If there is no background override by now it's the original color, so apply dim if needed
253+
if (!bgOverride) {
254+
if (cell.isDim()) {
255+
bgOverride = color.multiplyOpacity(resolvedBg, 0.5);
256+
}
257+
}
258+
252259
// Foreground
253260
switch (fgColorMode) {
254261
case Attributes.CM_P16:

src/common/Color.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ export namespace color {
8484
};
8585
}
8686

87+
export function multiplyOpacity(color: IColor, factor: number): IColor {
88+
const a = color.rgba & 0xFF;
89+
return opacity(color, (a * factor) / 0xFF);
90+
}
91+
8792
export function toColorRGB(color: IColor): IColorRGB {
8893
return [(color.rgba >> 24) & 0xFF, (color.rgba >> 16) & 0xFF, (color.rgba >> 8) & 0xFF];
8994
}

0 commit comments

Comments
 (0)