<commit_before>/**
 * Copyright (c) 2018 The xterm.js authors. All rights reserved.
 * @license MIT
 */

import { GlyphRenderer } from './GlyphRenderer';
import { LinkRenderLayer } from './renderLayer/LinkRenderLayer';
import { CursorRenderLayer } from './renderLayer/CursorRenderLayer';
import { acquireCharAtlas } from './atlas/CharAtlasCache';
import { WebglCharAtlas } from './atlas/WebglCharAtlas';
import { RectangleRenderer } from './RectangleRenderer';
import { IWebGL2RenderingContext } from './Types';
import { RenderModel, COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel';
import { Disposable } from 'common/Lifecycle';
import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
import { Terminal, IEvent } from 'xterm';
import { IRenderLayer } from './renderLayer/Types';
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types';
import { ITerminal, IColorSet } from 'browser/Types';
import { EventEmitter } from 'common/EventEmitter';
import { CellData } from 'common/buffer/CellData';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { ICharacterJoinerService } from 'browser/services/Services';
import { CharData, ICellData } from 'common/Types';
import { AttributeData } from 'common/buffer/AttributeData';
import { IDecorationService } from 'common/services/Services';

export class WebglRenderer extends Disposable implements IRenderer {
  private _renderLayers: IRenderLayer[];
  private _charAtlas: WebglCharAtlas | undefined;
  private _devicePixelRatio: number;

  private _model: RenderModel = new RenderModel();
  private _workCell: CellData = new CellData();
  private _workColors: { fg: number, bg: number } = { fg: 0, bg: 0 };

  private _canvas: HTMLCanvasElement;
  private _gl: IWebGL2RenderingContext;
  private _rectangleRenderer: RectangleRenderer;
  private _glyphRenderer: GlyphRenderer;

  public dimensions: IRenderDimensions;

  private _core: ITerminal;
  private _isAttached: boolean;

  private _onRequestRedraw = new EventEmitter<IRequestRedrawEvent>();
  public get onRequestRedraw(): IEvent<IRequestRedrawEvent> { return this._onRequestRedraw.event; }

  private _onContextLoss = new EventEmitter<void>();
  public get onContextLoss(): IEvent<void> { return this._onContextLoss.event; }

  constructor(
    private _terminal: Terminal,
    private _colors: IColorSet,
    private readonly _characterJoinerService: ICharacterJoinerService,
    private readonly _decorationService: IDecorationService,
    preserveDrawingBuffer?: boolean
  ) {
    super();

    this._core = (this._terminal as any)._core;

    this._renderLayers = [
      new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core),
      new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._core, this._onRequestRedraw)
    ];
    this.dimensions = {
      scaledCharWidth: 0,
      scaledCharHeight: 0,
      scaledCellWidth: 0,
      scaledCellHeight: 0,
      scaledCharLeft: 0,
      scaledCharTop: 0,
      scaledCanvasWidth: 0,
      scaledCanvasHeight: 0,
      canvasWidth: 0,
      canvasHeight: 0,
      actualCellWidth: 0,
      actualCellHeight: 0
    };
    this._devicePixelRatio = window.devicePixelRatio;
    this._updateDimensions();

    this._canvas = document.createElement('canvas');

    const contextAttributes = {
      antialias: false,
      depth: false,
      preserveDrawingBuffer
    };
    this._gl = this._canvas.getContext('webgl2', contextAttributes) as IWebGL2RenderingContext;
    if (!this._gl) {
      throw new Error('WebGL2 not supported ' + this._gl);
    }

    this.register(addDisposableDomListener(this._canvas, 'webglcontextlost', (e) => { this._onContextLoss.fire(e); }));

    this._core.screenElement!.appendChild(this._canvas);

    this._rectangleRenderer = this.register(new RectangleRenderer(this._terminal, this._colors, this._gl, this.dimensions));
    this._glyphRenderer = this.register(new GlyphRenderer(this._terminal, this._colors, this._gl, this.dimensions));

    // Update dimensions and acquire char atlas
    this.onCharSizeChanged();

    this._isAttached = document.body.contains(this._core.screenElement!);
  }

  public dispose(): void {
    for (const l of this._renderLayers) {
      l.dispose();
    }
    this._canvas.parentElement?.removeChild(this._canvas);
    super.dispose();
  }

  public get textureAtlas(): HTMLCanvasElement | undefined {
    return this._charAtlas?.cacheCanvas;
  }

  public setColors(colors: IColorSet): void {
    this._colors = colors;
    // Clear layers and force a full render
    for (const l of this._renderLayers) {
      l.setColors(this._terminal, this._colors);
      l.reset(this._terminal);
    }

    this._rectangleRenderer.setColors();
    this._glyphRenderer.setColors();

    this._refreshCharAtlas();

    // Force a full refresh
    this._model.clear();
  }
<commit_msg>Remove terminal from cache on disposal<commit_after>/**
 * Copyright (c) 2018 The xterm.js authors. All rights reserved.
 * @license MIT
 */

import { GlyphRenderer } from './GlyphRenderer';
import { LinkRenderLayer } from './renderLayer/LinkRenderLayer';
import { CursorRenderLayer } from './renderLayer/CursorRenderLayer';
import { acquireCharAtlas, removeTerminalFromCache } from './atlas/CharAtlasCache';
import { WebglCharAtlas } from './atlas/WebglCharAtlas';
import { RectangleRenderer } from './RectangleRenderer';
import { IWebGL2RenderingContext } from './Types';
import { RenderModel, COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL } from './RenderModel';
import { Disposable } from 'common/Lifecycle';
import { Attributes, Content, FgFlags, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
import { Terminal, IEvent } from 'xterm';
import { IRenderLayer } from './renderLayer/Types';
import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types';
import { ITerminal, IColorSet } from 'browser/Types';
import { EventEmitter } from 'common/EventEmitter';
import { CellData } from 'common/buffer/CellData';
import { addDisposableDomListener } from 'browser/Lifecycle';
import { ICharacterJoinerService } from 'browser/services/Services';
import { CharData, ICellData } from 'common/Types';
import { AttributeData } from 'common/buffer/AttributeData';
import { IDecorationService } from 'common/services/Services';

export class WebglRenderer extends Disposable implements IRenderer {
  private _renderLayers: IRenderLayer[];
  private _charAtlas: WebglCharAtlas | undefined;
  private _devicePixelRatio: number;

  private _model: RenderModel = new RenderModel();
  private _workCell: CellData = new CellData();
  private _workColors: { fg: number, bg: number } = { fg: 0, bg: 0 };

  private _canvas: HTMLCanvasElement;
  private _gl: IWebGL2RenderingContext;
  private _rectangleRenderer: RectangleRenderer;
  private _glyphRenderer: GlyphRenderer;

  public dimensions: IRenderDimensions;

  private _core: ITerminal;
  private _isAttached: boolean;

  private _onRequestRedraw = new EventEmitter<IRequestRedrawEvent>();
  public get onRequestRedraw(): IEvent<IRequestRedrawEvent> { return this._onRequestRedraw.event; }

  private _onContextLoss = new EventEmitter<void>();
  public get onContextLoss(): IEvent<void> { return this._onContextLoss.event; }

  constructor(
    private _terminal: Terminal,
    private _colors: IColorSet,
    private readonly _characterJoinerService: ICharacterJoinerService,
    private readonly _decorationService: IDecorationService,
    preserveDrawingBuffer?: boolean
  ) {
    super();

    this._core = (this._terminal as any)._core;

    this._renderLayers = [
      new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core),
      new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._core, this._onRequestRedraw)
    ];
    this.dimensions = {
      scaledCharWidth: 0,
      scaledCharHeight: 0,
      scaledCellWidth: 0,
      scaledCellHeight: 0,
      scaledCharLeft: 0,
      scaledCharTop: 0,
      scaledCanvasWidth: 0,
      scaledCanvasHeight: 0,
      canvasWidth: 0,
      canvasHeight: 0,
      actualCellWidth: 0,
      actualCellHeight: 0
    };
    this._devicePixelRatio = window.devicePixelRatio;
    this._updateDimensions();

    this._canvas = document.createElement('canvas');

    const contextAttributes = {
      antialias: false,
      depth: false,
      preserveDrawingBuffer
    };
    this._gl = this._canvas.getContext('webgl2', contextAttributes) as IWebGL2RenderingContext;
    if (!this._gl) {
      throw new Error('WebGL2 not supported ' + this._gl);
    }

    this.register(addDisposableDomListener(this._canvas, 'webglcontextlost', (e) => { this._onContextLoss.fire(e); }));

    this._core.screenElement!.appendChild(this._canvas);

    this._rectangleRenderer = this.register(new RectangleRenderer(this._terminal, this._colors, this._gl, this.dimensions));
    this._glyphRenderer = this.register(new GlyphRenderer(this._terminal, this._colors, this._gl, this.dimensions));

    // Update dimensions and acquire char atlas
    this.onCharSizeChanged();

    this._isAttached = document.body.contains(this._core.screenElement!);
  }

  public dispose(): void {
    for (const l of this._renderLayers) {
      l.dispose();
    }
    this._canvas.parentElement?.removeChild(this._canvas);
    removeTerminalFromCache(this._terminal);
    super.dispose();
  }

  public get textureAtlas(): HTMLCanvasElement | undefined {
    return this._charAtlas?.cacheCanvas;
  }

  public setColors(colors: IColorSet): void {
    this._colors = colors;
    // Clear layers and force a full render
    for (const l of this._renderLayers) {
      l.setColors(this._terminal, this._colors);
      l.reset(this._terminal);
    }

    this._rectangleRenderer.setColors();
    this._glyphRenderer.setColors();

    this._refreshCharAtlas();

    // Force a full refresh
    this._model.clear();
  }

{'fraction_non_alphanumeric': 0.10736468500443656, 'fraction_numerical': 0.004929508035098097, 'mean_word_length': 4.364357482813326, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6430008', 'n_tokens_mistral': 3082, 'n_tokens_neox': 2971, 'n_words': 697}