Add minimumContrastRatio to DOM renderer

Part of #322
This commit is contained in:
Daniel Imms
2019-11-11 19:03:12 -08:00
parent 339d4d6a73
commit e46ff9ec85
8 changed files with 209 additions and 30 deletions
+1 -1
View File
@@ -79,7 +79,7 @@ export class DomRenderer extends Disposable implements IRenderer {
this._updateDimensions();
this._injectCss();
this._rowFactory = new DomRendererRowFactory(document, this._optionsService);
this._rowFactory = new DomRendererRowFactory(document, this._optionsService, this._colors);
this._element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass);
this._screenElement.appendChild(this._rowContainer);
@@ -19,7 +19,7 @@ describe('DomRendererRowFactory', () => {
beforeEach(() => {
dom = new jsdom.JSDOM('');
rowFactory = new DomRendererRowFactory(dom.window.document, new MockOptionsService({ drawBoldTextInBrightColors: true }));
rowFactory = new DomRendererRowFactory(dom.window.document, new MockOptionsService({ drawBoldTextInBrightColors: true }), {} as any);
lineData = createEmptyLineData(2);
});
@@ -6,9 +6,11 @@
import { IBufferLine } from 'common/Types';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
import { AttributeData } from 'common/buffer/AttributeData';
import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR } from 'common/buffer/Constants';
import { NULL_CELL_CODE, WHITESPACE_CELL_CHAR, Attributes } from 'common/buffer/Constants';
import { CellData } from 'common/buffer/CellData';
import { IOptionsService } from 'common/services/Services';
import { rgbRelativeLuminance, fromCss, contrastRatio, ensureContrastRatio } from 'browser/Color';
import { IColorSet, IColor } from 'browser/Types';
export const BOLD_CLASS = 'xterm-bold';
export const DIM_CLASS = 'xterm-dim';
@@ -24,11 +26,16 @@ export class DomRendererRowFactory {
private _workCell: CellData = new CellData();
constructor(
private _document: Document,
private _optionsService: IOptionsService
private readonly _document: Document,
private readonly _optionsService: IOptionsService,
private _colors: IColorSet
) {
}
public setColors(colors: IColorSet): void {
this._colors = colors;
}
public createRow(lineData: IBufferLine, isCursorRow: boolean, cursorStyle: string | undefined, cursorX: number, cursorBlink: boolean, cellWidth: number, cols: number): DocumentFragment {
const fragment = this._document.createDocumentFragment();
@@ -97,36 +104,75 @@ export class DomRendererRowFactory {
charElement.textContent = this._workCell.getChars() || WHITESPACE_CELL_CHAR;
const swapColor = this._workCell.isInverse();
// fg
if (this._workCell.isFgRGB()) {
let style = charElement.getAttribute('style') || '';
style += `${swapColor ? 'background-' : ''}color:rgb(${(AttributeData.toColorRGB(this._workCell.getFgColor())).join(',')});`;
charElement.setAttribute('style', style);
} else if (this._workCell.isFgPalette()) {
let fg = this._workCell.getFgColor();
if (this._workCell.isBold() && fg < 8 && !swapColor && this._optionsService.options.drawBoldTextInBrightColors) {
fg += 8;
}
charElement.classList.add(`xterm-${swapColor ? 'b' : 'f'}g-${fg}`);
} else if (swapColor) {
charElement.classList.add(`xterm-bg-${INVERTED_DEFAULT_COLOR}`);
let fg = this._workCell.getFgColor();
let fgColorMode = this._workCell.getFgColorMode();
let bg = this._workCell.getBgColor();
let bgColorMode = this._workCell.getBgColorMode();
const isInverse = !!this._workCell.isInverse();
if (isInverse) {
const temp = fg;
fg = bg;
bg = temp;
const temp2 = fgColorMode;
fgColorMode = bgColorMode;
bgColorMode = temp2;
}
// bg
if (this._workCell.isBgRGB()) {
let style = charElement.getAttribute('style') || '';
style += `${swapColor ? '' : 'background-'}color:rgb(${(AttributeData.toColorRGB(this._workCell.getBgColor())).join(',')});`;
charElement.setAttribute('style', style);
} else if (this._workCell.isBgPalette()) {
charElement.classList.add(`xterm-${swapColor ? 'f' : 'b'}g-${this._workCell.getBgColor()}`);
} else if (swapColor) {
charElement.classList.add(`xterm-fg-${INVERTED_DEFAULT_COLOR}`);
// Foreground
switch (fgColorMode) {
case Attributes.CM_P16:
case Attributes.CM_P256:
if (this._workCell.isBold() && fg < 8 && this._optionsService.options.drawBoldTextInBrightColors) {
fg += 8;
}
if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.ansi[fg])) {
charElement.classList.add(`xterm-fg-${fg}`);
}
break;
case Attributes.CM_RGB:
charElement.setAttribute('style', `${charElement.getAttribute('style') || ''}color:rgb(${(AttributeData.toColorRGB(fg)).join(',')});`);
break;
case Attributes.CM_DEFAULT:
default:
if (!this._applyMinimumContrast(charElement, this._colors.background, this._colors.foreground)) {
if (isInverse) {
charElement.classList.add(`xterm-fg-${INVERTED_DEFAULT_COLOR}`);
}
}
}
// Background
switch (bgColorMode) {
case Attributes.CM_P16:
case Attributes.CM_P256:
charElement.classList.add(`xterm-bg-${bg}`);
break;
case Attributes.CM_RGB:
charElement.setAttribute('style', `${charElement.getAttribute('style') || ''}background-color:rgb(${(AttributeData.toColorRGB(bg)).join(',')});`);
break;
case Attributes.CM_DEFAULT:
default:
if (isInverse) {
charElement.classList.add(`xterm-bg-${INVERTED_DEFAULT_COLOR}`);
}
}
fragment.appendChild(charElement);
}
return fragment;
}
private _applyMinimumContrast(element: HTMLElement, bg: IColor, fg: IColor): boolean {
if (this._optionsService.options.minimumContrastRatio === 1) {
return false;
}
const adustedColor = ensureContrastRatio(bg, fg, this._optionsService.options.minimumContrastRatio);
if (adustedColor) {
element.setAttribute('style', `${element.getAttribute('style') || ''}color:${adustedColor.css}`);
return true;
}
return false;
}
}