Skip to content

Commit

Permalink
Merge pull request #4611 from SimonSiefke/constructed-stylesheets
Browse files Browse the repository at this point in the history
feature: use constructed style sheets for dom render so that it works with csp style-src 'self'
  • Loading branch information
Tyriar authored Jul 27, 2023
2 parents 679c149 + 5f80fe0 commit 5889344
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 12 deletions.
23 changes: 11 additions & 12 deletions src/browser/renderer/dom/DomRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { color } from 'common/Color';
import { EventEmitter } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, IInstantiationService, IOptionsService } from 'common/services/Services';
import { createStyle, IStyleSheet } from './StyleSheet';

const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
const ROW_CONTAINER_CLASS = 'xterm-rows';
Expand All @@ -32,8 +33,8 @@ export class DomRenderer extends Disposable implements IRenderer {
private _rowFactory: DomRendererRowFactory;
private _terminalClass: number = nextTerminalId++;

private _themeStyleElement!: HTMLStyleElement;
private _dimensionsStyleElement!: HTMLStyleElement;
private _themeStyle!: IStyleSheet;
private _dimensionsStyle!: IStyleSheet;
private _rowContainer: HTMLElement;
private _rowElements: HTMLElement[] = [];
private _selectionContainer: HTMLElement;
Expand Down Expand Up @@ -88,8 +89,8 @@ export class DomRenderer extends Disposable implements IRenderer {
// https://github.com/xtermjs/xterm.js/issues/2960
this._rowContainer.remove();
this._selectionContainer.remove();
this._themeStyleElement.remove();
this._dimensionsStyleElement.remove();
this._themeStyle.dispose();
this._dimensionsStyle.dispose();
}));
}

Expand All @@ -116,9 +117,8 @@ export class DomRenderer extends Disposable implements IRenderer {
element.style.overflow = 'hidden';
}

if (!this._dimensionsStyleElement) {
this._dimensionsStyleElement = document.createElement('style');
this._screenElement.appendChild(this._dimensionsStyleElement);
if (!this._dimensionsStyle) {
this._dimensionsStyle = createStyle(this._screenElement);
}

const styles =
Expand All @@ -129,17 +129,16 @@ export class DomRenderer extends Disposable implements IRenderer {
` width: ${this.dimensions.css.cell.width}px` +
`}`;

this._dimensionsStyleElement.textContent = styles;
this._dimensionsStyle.setCss(styles);

this._selectionContainer.style.height = this._viewportElement.style.height;
this._screenElement.style.width = `${this.dimensions.css.canvas.width}px`;
this._screenElement.style.height = `${this.dimensions.css.canvas.height}px`;
}

private _injectCss(colors: ReadonlyColorSet): void {
if (!this._themeStyleElement) {
this._themeStyleElement = document.createElement('style');
this._screenElement.appendChild(this._themeStyleElement);
if (!this._themeStyle) {
this._themeStyle = createStyle(this._screenElement);
}

// Base CSS
Expand Down Expand Up @@ -236,7 +235,7 @@ export class DomRenderer extends Disposable implements IRenderer {
`${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR}.${DIM_CLASS} { color: ${color.multiplyOpacity(color.opaque(colors.background), 0.5).css}; }` +
`${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${colors.foreground.css}; }`;

this._themeStyleElement.textContent = styles;
this._themeStyle.setCss(styles);
}

public handleDevicePixelRatioChange(): void {
Expand Down
39 changes: 39 additions & 0 deletions src/browser/renderer/dom/StyleSheet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export interface IStyleSheet {
dispose: () => void;
setCss: (value: string) => void;
}

const createCssStyleSheet = (): IStyleSheet => {
const sheet = new CSSStyleSheet();
document.adoptedStyleSheets.push(sheet);
return {
dispose() {
const index = document.adoptedStyleSheets.indexOf(sheet);
document.adoptedStyleSheets.splice(index, 1);
},
setCss(css) {
sheet.replaceSync(css);
}
};
};

const createStyleElement = (parent: HTMLElement): IStyleSheet => {
const element = document.createElement('style');
parent.append(element);
return {
dispose() {
element.remove();
},
setCss(css) {
element.textContent = css;
}
};
};

export const createStyle = (parent: HTMLElement): IStyleSheet => {
try {
return createCssStyleSheet();
} catch {
return createStyleElement(parent);
}
};

0 comments on commit 5889344

Please sign in to comment.