mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
bg/fg decorations mostly working in canvas renderer
This commit is contained in:
+1
-1
@@ -559,7 +559,7 @@ function addDecoration() {
|
||||
const decoration = term.registerDecoration({
|
||||
marker,
|
||||
backgroundColor: '#00FF00',
|
||||
foregroundColor: '#000000',
|
||||
foregroundColor: '#00FE00',
|
||||
overviewRulerOptions: { color: '#ef292980', position: 'left' }
|
||||
});
|
||||
decoration.onRender((e: HTMLElement) => {
|
||||
|
||||
@@ -13,7 +13,7 @@ import { acquireCharAtlas } from 'browser/renderer/atlas/CharAtlasCache';
|
||||
import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { IBufferService, IOptionsService } from 'common/services/Services';
|
||||
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
import { isPowerlineGlyph, throwIfFalsy } from 'browser/renderer/RendererUtils';
|
||||
import { channels, color, rgba } from 'common/Color';
|
||||
import { removeElementFromParent } from 'browser/Dom';
|
||||
@@ -52,7 +52,8 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
protected _colors: IColorSet,
|
||||
private _rendererId: number,
|
||||
protected readonly _bufferService: IBufferService,
|
||||
protected readonly _optionsService: IOptionsService
|
||||
protected readonly _optionsService: IOptionsService,
|
||||
protected readonly _decorationService: IDecorationService
|
||||
) {
|
||||
this._canvas = document.createElement('canvas');
|
||||
this._canvas.classList.add(`xterm-${id}-layer`);
|
||||
@@ -294,7 +295,7 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
* @param bold Whether the text is bold.
|
||||
*/
|
||||
protected _drawChars(cell: ICellData, x: number, y: number): void {
|
||||
const contrastColor = this._getContrastColor(cell);
|
||||
const contrastColor = this._getContrastColor(cell, x, y);
|
||||
|
||||
// skip cache right away if we draw in RGB
|
||||
// Note: to avoid bad runtime JoinedCellData will be skipped
|
||||
@@ -427,15 +428,35 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
return `${fontStyle} ${fontWeight} ${this._optionsService.rawOptions.fontSize * window.devicePixelRatio}px ${this._optionsService.rawOptions.fontFamily}`;
|
||||
}
|
||||
|
||||
private _getContrastColor(cell: CellData): IColor | undefined {
|
||||
if (this._optionsService.rawOptions.minimumContrastRatio === 1 || isPowerlineGlyph(cell.getCode())) {
|
||||
private _getContrastColor(cell: CellData, x: number, y: number): IColor | undefined {
|
||||
// Get any decoration foreground/background overrides, this must be fetched before the early
|
||||
// exist but applied after inverse
|
||||
const decorations = this._decorationService.getDecorationsOnLine(y);
|
||||
let bgOverride: number | undefined;
|
||||
let fgOverride: number | undefined;
|
||||
for (const d of decorations) {
|
||||
const xmin = d.options.x ?? 0;
|
||||
const xmax = xmin + (d.options.width ?? 1);
|
||||
if (x >= xmin && x < xmax) {
|
||||
if (d.backgroundColorRGB) {
|
||||
bgOverride = d.backgroundColorRGB.rgba;
|
||||
}
|
||||
if (d.foregroundColorRGB) {
|
||||
fgOverride = d.foregroundColorRGB.rgba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bgOverride && !fgOverride && (this._optionsService.rawOptions.minimumContrastRatio === 1 || isPowerlineGlyph(cell.getCode()))) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Try get from cache first
|
||||
const adjustedColor = this._colors.contrastCache.getColor(cell.bg, cell.fg);
|
||||
if (adjustedColor !== undefined) {
|
||||
return adjustedColor || undefined;
|
||||
if (!bgOverride && !fgOverride) {
|
||||
// Try get from cache
|
||||
const adjustedColor = this._colors.contrastCache.getColor(cell.bg, cell.fg);
|
||||
if (adjustedColor !== undefined) {
|
||||
return adjustedColor || undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let fgColor = cell.getFgColor();
|
||||
@@ -453,13 +474,18 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
bgColorMode = temp2;
|
||||
}
|
||||
|
||||
const bgRgba = this._resolveBackgroundRgba(bgColorMode, bgColor, isInverse);
|
||||
const bgRgba = this._resolveBackgroundRgba(bgOverride !== undefined ? Attributes.CM_RGB : bgColorMode, bgOverride ?? bgColor, isInverse);
|
||||
const fgRgba = this._resolveForegroundRgba(fgColorMode, fgColor, isInverse, isBold);
|
||||
const result = rgba.ensureContrastRatio(bgRgba, fgRgba, this._optionsService.rawOptions.minimumContrastRatio);
|
||||
let result = rgba.ensureContrastRatio(bgOverride ?? bgRgba, fgOverride ?? fgRgba, this._optionsService.rawOptions.minimumContrastRatio);
|
||||
|
||||
if (!result) {
|
||||
this._colors.contrastCache.setColor(cell.bg, cell.fg, null);
|
||||
return undefined;
|
||||
if (!bgOverride && !fgOverride) {
|
||||
this._colors.contrastCache.setColor(cell.bg, cell.fg, null);
|
||||
return undefined;
|
||||
}
|
||||
// If it was an override and there was no contrast change, set as the result
|
||||
// TODO: This is white when it should be green
|
||||
result = fgRgba;
|
||||
}
|
||||
|
||||
const color: IColor = {
|
||||
@@ -470,7 +496,9 @@ export abstract class BaseRenderLayer implements IRenderLayer {
|
||||
),
|
||||
rgba: result
|
||||
};
|
||||
this._colors.contrastCache.setColor(cell.bg, cell.fg, color);
|
||||
if (!bgOverride && !fgOverride) {
|
||||
this._colors.contrastCache.setColor(cell.bg, cell.fg, color);
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer';
|
||||
import { ICellData } from 'common/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services';
|
||||
import { IBufferService, IOptionsService, ICoreService, IDecorationService } from 'common/services/Services';
|
||||
import { IEventEmitter } from 'common/EventEmitter';
|
||||
import { ICoreBrowserService } from 'browser/services/Services';
|
||||
|
||||
@@ -40,9 +40,10 @@ export class CursorRenderLayer extends BaseRenderLayer {
|
||||
@IBufferService bufferService: IBufferService,
|
||||
@IOptionsService optionsService: IOptionsService,
|
||||
@ICoreService private readonly _coreService: ICoreService,
|
||||
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService
|
||||
@ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService,
|
||||
@IDecorationService decorationService: IDecorationService
|
||||
) {
|
||||
super(container, 'cursor', zIndex, true, colors, rendererId, bufferService, optionsService);
|
||||
super(container, 'cursor', zIndex, true, colors, rendererId, bufferService, optionsService, decorationService);
|
||||
this._state = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { BaseRenderLayer } from './BaseRenderLayer';
|
||||
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
|
||||
import { is256Color } from 'browser/renderer/atlas/CharAtlasUtils';
|
||||
import { IColorSet, ILinkifierEvent, ILinkifier, ILinkifier2 } from 'browser/Types';
|
||||
import { IBufferService, IOptionsService } from 'common/services/Services';
|
||||
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
|
||||
export class LinkRenderLayer extends BaseRenderLayer {
|
||||
private _state: ILinkifierEvent | undefined;
|
||||
@@ -21,9 +21,10 @@ export class LinkRenderLayer extends BaseRenderLayer {
|
||||
linkifier: ILinkifier,
|
||||
linkifier2: ILinkifier2,
|
||||
@IBufferService bufferService: IBufferService,
|
||||
@IOptionsService optionsService: IOptionsService
|
||||
@IOptionsService optionsService: IOptionsService,
|
||||
@IDecorationService decorationService: IDecorationService
|
||||
) {
|
||||
super(container, 'link', zIndex, true, colors, rendererId, bufferService, optionsService);
|
||||
super(container, 'link', zIndex, true, colors, rendererId, bufferService, optionsService, decorationService);
|
||||
linkifier.onShowLinkUnderline(e => this._onShowLinkUnderline(e));
|
||||
linkifier.onHideLinkUnderline(e => this._onHideLinkUnderline(e));
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IRenderDimensions } from 'browser/renderer/Types';
|
||||
import { BaseRenderLayer } from 'browser/renderer/BaseRenderLayer';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { IBufferService, IOptionsService } from 'common/services/Services';
|
||||
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
|
||||
|
||||
interface ISelectionState {
|
||||
start?: [number, number];
|
||||
@@ -24,9 +24,10 @@ export class SelectionRenderLayer extends BaseRenderLayer {
|
||||
colors: IColorSet,
|
||||
rendererId: number,
|
||||
@IBufferService bufferService: IBufferService,
|
||||
@IOptionsService optionsService: IOptionsService
|
||||
@IOptionsService optionsService: IOptionsService,
|
||||
@IDecorationService decorationService: IDecorationService
|
||||
) {
|
||||
super(container, 'selection', zIndex, true, colors, rendererId, bufferService, optionsService);
|
||||
super(container, 'selection', zIndex, true, colors, rendererId, bufferService, optionsService, decorationService);
|
||||
this._clearState();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { AttributeData } from 'common/buffer/AttributeData';
|
||||
import { NULL_CELL_CODE, Content } from 'common/buffer/Constants';
|
||||
import { IColorSet } from 'browser/Types';
|
||||
import { CellData } from 'common/buffer/CellData';
|
||||
import { IOptionsService, IBufferService } from 'common/services/Services';
|
||||
import { IOptionsService, IBufferService, IDecorationService } from 'common/services/Services';
|
||||
import { ICharacterJoinerService } from 'browser/services/Services';
|
||||
import { JoinedCellData } from 'browser/services/CharacterJoinerService';
|
||||
|
||||
@@ -37,9 +37,10 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
rendererId: number,
|
||||
@IBufferService bufferService: IBufferService,
|
||||
@IOptionsService optionsService: IOptionsService,
|
||||
@ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService
|
||||
@ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService,
|
||||
@IDecorationService decorationService: IDecorationService
|
||||
) {
|
||||
super(container, 'text', zIndex, alpha, colors, rendererId, bufferService, optionsService);
|
||||
super(container, 'text', zIndex, alpha, colors, rendererId, bufferService, optionsService, decorationService);
|
||||
this._state = new GridCache<CharData>();
|
||||
}
|
||||
|
||||
@@ -176,6 +177,19 @@ export class TextRenderLayer extends BaseRenderLayer {
|
||||
nextFillStyle = this._colors.ansi[cell.getBgColor()].css;
|
||||
}
|
||||
|
||||
// Get any decoration foreground/background overrides, this must be fetched before the early
|
||||
// exist but applied after inverse
|
||||
const decorations = this._decorationService.getDecorationsOnLine(y);
|
||||
for (const d of decorations) {
|
||||
const xmin = d.options.x ?? 0;
|
||||
const xmax = xmin + (d.options.width ?? 1);
|
||||
if (x >= xmin && x < xmax) {
|
||||
if (d.backgroundColorRGB) {
|
||||
nextFillStyle = d.backgroundColorRGB.css;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevFillStyle === null) {
|
||||
// This is either the first iteration, or the default background was set. Either way, we
|
||||
// don't need to draw anything.
|
||||
|
||||
@@ -105,7 +105,7 @@ export class DynamicCharAtlas extends BaseCharAtlas {
|
||||
this._cacheMap.prealloc(capacity);
|
||||
|
||||
// This is useful for debugging
|
||||
// document.body.appendChild(this._cacheCanvas);
|
||||
document.body.appendChild(this._cacheCanvas);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
||||
@@ -173,7 +173,8 @@ export class DomRendererRowFactory {
|
||||
bgColorMode = temp2;
|
||||
}
|
||||
|
||||
// Apply any decoration foreground/background overrides
|
||||
// Apply any decoration foreground/background overrides, this must happen after inverse has
|
||||
// been applied
|
||||
const decorations = this._decorationService.getDecorationsOnLine(row);
|
||||
let bgOverride: IColor | undefined;
|
||||
let fgOverride: IColor | undefined;
|
||||
|
||||
Reference in New Issue
Block a user