Variants to Canvas.

This commit is contained in:
tisilent
2023-08-21 19:45:38 +08:00
parent 32da1d81d5
commit cb175e513d
4 changed files with 43 additions and 13 deletions
@@ -365,7 +365,7 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
* Draws one or more characters at a cell. If possible this will draw using
* the character atlas to reduce draw time.
*/
protected _drawChars(cell: ICellData, x: number, y: number): void {
protected _drawChars(cell: ICellData, x: number, y: number, variantOffset: number = 0): void {
const chars = cell.getChars();
this._cellColorResolver.resolve(cell, x, this._bufferService.buffer.ydisp + y);
@@ -375,9 +375,9 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
let glyph: IRasterizedGlyph;
if (chars && chars.length > 1) {
glyph = this._charAtlas.getRasterizedGlyphCombinedChar(chars, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, 0, true);
glyph = this._charAtlas.getRasterizedGlyphCombinedChar(chars, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, variantOffset, true);
} else {
glyph = this._charAtlas.getRasterizedGlyph(cell.getCode() || WHITESPACE_CELL_CODE, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, 0, true);
glyph = this._charAtlas.getRasterizedGlyph(cell.getCode() || WHITESPACE_CELL_CODE, this._cellColorResolver.result.bg, this._cellColorResolver.result.fg, this._cellColorResolver.result.ext, variantOffset, true);
}
if (!glyph.size.x || !glyph.size.y) {
return;
+3 -2
View File
@@ -6,7 +6,7 @@
import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IRenderService, ISelectionService, IThemeService } from 'browser/services/Services';
import { ITerminal } from 'browser/Types';
import { CanvasRenderer } from './CanvasRenderer';
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { IBufferService, ICoreService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { ITerminalAddon, Terminal } from 'xterm';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
@@ -45,8 +45,9 @@ export class CanvasAddon extends Disposable implements ITerminalAddon {
const coreBrowserService: ICoreBrowserService = unsafeCore._coreBrowserService;
const decorationService: IDecorationService = unsafeCore._decorationService;
const themeService: IThemeService = unsafeCore._themeService;
const unicodeService: IUnicodeService = unsafeCore.unicodeService;
this._renderer = new CanvasRenderer(terminal, screenElement, linkifier, bufferService, charSizeService, optionsService, characterJoinerService, coreService, coreBrowserService, decorationService, themeService);
this._renderer = new CanvasRenderer(terminal, screenElement, linkifier, bufferService, charSizeService, optionsService, characterJoinerService, coreService, coreBrowserService, decorationService, themeService, unicodeService);
this.register(forwardEvent(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas));
this.register(forwardEvent(this._renderer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas));
renderService.setRenderer(this._renderer);
@@ -11,7 +11,7 @@ import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, ISelect
import { ILinkifier2 } from 'browser/Types';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { IBufferService, ICoreService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { Terminal } from 'xterm';
import { CursorRenderLayer } from './CursorRenderLayer';
import { LinkRenderLayer } from './LinkRenderLayer';
@@ -43,12 +43,13 @@ export class CanvasRenderer extends Disposable implements IRenderer {
coreService: ICoreService,
private readonly _coreBrowserService: ICoreBrowserService,
decorationService: IDecorationService,
private readonly _themeService: IThemeService
private readonly _themeService: IThemeService,
private readonly _unicodeService: IUnicodeService
) {
super();
const allowTransparency = this._optionsService.rawOptions.allowTransparency;
this._renderLayers = [
new TextRenderLayer(this._terminal, this._screenElement, 0, allowTransparency, this._bufferService, this._optionsService, characterJoinerService, decorationService, this._coreBrowserService, _themeService),
new TextRenderLayer(this._terminal, this._screenElement, 0, allowTransparency, this._bufferService, this._optionsService, characterJoinerService, decorationService, this._coreBrowserService, _themeService, _unicodeService),
new SelectionRenderLayer(this._terminal, this._screenElement, 1, this._bufferService, this._coreBrowserService, decorationService, this._optionsService, _themeService),
new LinkRenderLayer(this._terminal, this._screenElement, 2, linkifier2, this._bufferService, this._optionsService, decorationService, this._coreBrowserService, _themeService),
new CursorRenderLayer(this._terminal, this._screenElement, 3, this._onRequestRedraw, this._bufferService, this._optionsService, coreService, this._coreBrowserService, decorationService, _themeService)
@@ -11,7 +11,7 @@ import { AttributeData } from 'common/buffer/AttributeData';
import { NULL_CELL_CODE, Content, UnderlineStyle } from 'common/buffer/Constants';
import { IColorSet, ReadonlyColorSet } from 'browser/Types';
import { CellData } from 'common/buffer/CellData';
import { IOptionsService, IBufferService, IDecorationService } from 'common/services/Services';
import { IOptionsService, IBufferService, IDecorationService, IUnicodeService } from 'common/services/Services';
import { ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { JoinedCellData } from 'browser/services/CharacterJoinerService';
import { color, css } from 'common/Color';
@@ -41,7 +41,8 @@ export class TextRenderLayer extends BaseRenderLayer {
private readonly _characterJoinerService: ICharacterJoinerService,
decorationService: IDecorationService,
coreBrowserService: ICoreBrowserService,
themeService: IThemeService
themeService: IThemeService,
private readonly _unicodeService: IUnicodeService
) {
super(terminal, container, 'text', zIndex, alpha, themeService, bufferService, optionsService, decorationService, coreBrowserService);
this._state = new GridCache<CharData>();
@@ -74,13 +75,20 @@ export class TextRenderLayer extends BaseRenderLayer {
callback: (
cell: ICellData,
x: number,
y: number
y: number,
variantOffset: number
) => void
): void {
const fontSize = this._optionsService.rawOptions.fontSize;
const drp = this._coreBrowserService.dpr;
const lineWidth = Math.max(1, Math.floor(fontSize * drp / 15));
const deviceCellWidth = this._charAtlas?.getDeviceCellWidth();
let variantOffset: number = -1;
for (let y = firstRow; y <= lastRow; y++) {
const row = y + this._bufferService.buffer.ydisp;
const line = this._bufferService.buffer.lines.get(row);
const joinedRanges = this._characterJoinerService.getJoinedCharacters(row);
variantOffset = 0;
for (let x = 0; x < this._bufferService.cols; x++) {
line!.loadCell(x, this._workCell);
let cell = this._workCell;
@@ -92,9 +100,20 @@ export class TextRenderLayer extends BaseRenderLayer {
// The character to the left is a wide character, drawing is owned by
// the char at x-1
if (cell.getWidth() === 0) {
if (cell.extended.underlineStyle !== UnderlineStyle.DOTTED) {
variantOffset = 0;
}
continue;
}
const code = cell.getCode();
let chWidth: number;
if (typeof code === 'number') {
chWidth = this._unicodeService.wcwidth(code);
} else {
chWidth = this._unicodeService.getStringCellWidth(code);
}
// exit early for NULL and SP
// NOTE: commented out due to #4120 (needs a more clever patch to keep things performant)
// const code = cell.getCode();
@@ -148,9 +167,18 @@ export class TextRenderLayer extends BaseRenderLayer {
callback(
cell,
x,
y
y,
variantOffset
);
if (cell.extended.underlineStyle === UnderlineStyle.DOTTED) {
if (code !== NULL_CELL_CODE) {
variantOffset = ((deviceCellWidth! * chWidth) - ((lineWidth * 2) - variantOffset)) % (lineWidth * 2);
}
} else {
variantOffset = 0;
}
x = lastCharX;
}
}
@@ -235,7 +263,7 @@ export class TextRenderLayer extends BaseRenderLayer {
}
private _drawForeground(firstRow: number, lastRow: number): void {
this._forEachCell(firstRow, lastRow, (cell, x, y) => this._drawChars(cell, x, y));
this._forEachCell(firstRow, lastRow, (cell, x, y, variantOffset) => this._drawChars(cell, x, y, variantOffset ?? 0));
}
public handleGridChanged(firstRow: number, lastRow: number): void {