Modify variantOffset calculation logic

This commit is contained in:
tisilent
2023-08-25 14:17:36 +08:00
parent 08f7b4c53c
commit bec1642123
14 changed files with 51 additions and 89 deletions
@@ -13,7 +13,7 @@ import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { ReadonlyColorSet } from 'browser/Types';
import { CellData } from 'common/buffer/CellData';
import { WHITESPACE_CELL_CODE } from 'common/buffer/Constants';
import { IBufferService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { ICellData, IDisposable } from 'common/Types';
import { Terminal } from 'xterm';
import { IRenderLayer } from './Types';
@@ -55,11 +55,10 @@ export abstract class BaseRenderLayer extends Disposable implements IRenderLayer
protected readonly _bufferService: IBufferService,
protected readonly _optionsService: IOptionsService,
protected readonly _decorationService: IDecorationService,
protected readonly _coreBrowserService: ICoreBrowserService,
unicodeService: IUnicodeService
protected readonly _coreBrowserService: ICoreBrowserService
) {
super();
this._cellColorResolver = new CellColorResolver(this._terminal, this._selectionModel, this._decorationService, this._coreBrowserService, this._themeService, unicodeService);
this._cellColorResolver = new CellColorResolver(this._terminal, this._optionsService, this._selectionModel, this._decorationService, this._coreBrowserService, this._themeService);
this._canvas = document.createElement('canvas');
this._canvas.classList.add(`xterm-${id}-layer`);
this._canvas.style.zIndex = zIndex.toString();
+2 -3
View File
@@ -8,7 +8,7 @@ import { ITerminal } from 'browser/Types';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { setTraceLogger } from 'common/services/LogService';
import { IBufferService, IDecorationService, ILogService, IUnicodeService } from 'common/services/Services';
import { IBufferService, IDecorationService, ILogService } from 'common/services/Services';
import { ITerminalAddon, Terminal } from 'xterm';
import { CanvasRenderer } from './CanvasRenderer';
@@ -47,13 +47,12 @@ export class CanvasAddon extends Disposable implements ITerminalAddon {
const decorationService: IDecorationService = unsafeCore._decorationService;
const logService: ILogService = unsafeCore._logService;
const themeService: IThemeService = unsafeCore._themeService;
const unicodeService: IUnicodeService = unsafeCore.unicodeService;
// Set trace logger just in case it hasn't been yet which could happen when the addon is
// bundled separately to the core module
setTraceLogger(logService);
this._renderer = new CanvasRenderer(terminal, screenElement, linkifier, bufferService, charSizeService, optionsService, characterJoinerService, coreService, coreBrowserService, decorationService, themeService, unicodeService);
this._renderer = new CanvasRenderer(terminal, screenElement, linkifier, bufferService, charSizeService, optionsService, characterJoinerService, coreService, coreBrowserService, decorationService, themeService);
this.register(forwardEvent(this._renderer.onChangeTextureAtlas, this._onChangeTextureAtlas));
this.register(forwardEvent(this._renderer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas));
@@ -11,7 +11,7 @@ import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/rende
import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, ICoreService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from 'xterm';
import { CursorRenderLayer } from './CursorRenderLayer';
import { LinkRenderLayer } from './LinkRenderLayer';
@@ -43,16 +43,15 @@ export class CanvasRenderer extends Disposable implements IRenderer {
coreService: ICoreService,
private readonly _coreBrowserService: ICoreBrowserService,
decorationService: IDecorationService,
private readonly _themeService: IThemeService,
unicodeService: IUnicodeService
private readonly _themeService: IThemeService
) {
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, unicodeService),
new SelectionRenderLayer(this._terminal, this._screenElement, 1, this._bufferService, this._coreBrowserService, decorationService, this._optionsService, _themeService, unicodeService),
new LinkRenderLayer(this._terminal, this._screenElement, 2, linkifier2, this._bufferService, this._optionsService, decorationService, this._coreBrowserService, _themeService, unicodeService),
new CursorRenderLayer(this._terminal, this._screenElement, 3, this._onRequestRedraw, this._bufferService, this._optionsService, coreService, this._coreBrowserService, decorationService, _themeService, unicodeService)
new TextRenderLayer(this._terminal, this._screenElement, 0, allowTransparency, this._bufferService, this._optionsService, characterJoinerService, decorationService, this._coreBrowserService, _themeService),
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)
];
for (const layer of this._renderLayers) {
forwardEvent(layer.onAddTextureAtlasCanvas, this._onAddTextureAtlasCanvas);
@@ -11,7 +11,7 @@ import { toDisposable } from 'common/Lifecycle';
import { isFirefox } from 'common/Platform';
import { ICellData } from 'common/Types';
import { CellData } from 'common/buffer/CellData';
import { IBufferService, ICoreService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from 'xterm';
import { BaseRenderLayer } from './BaseRenderLayer';
@@ -39,10 +39,9 @@ export class CursorRenderLayer extends BaseRenderLayer {
private readonly _coreService: ICoreService,
coreBrowserService: ICoreBrowserService,
decorationService: IDecorationService,
themeService: IThemeService,
unicodeService: IUnicodeService
themeService: IThemeService
) {
super(terminal, container, 'cursor', zIndex, true, themeService, bufferService, optionsService, decorationService, coreBrowserService, unicodeService);
super(terminal, container, 'cursor', zIndex, true, themeService, bufferService, optionsService, decorationService, coreBrowserService);
this._state = {
x: 0,
y: 0,
@@ -8,7 +8,7 @@ import { is256Color } from 'browser/renderer/shared/CharAtlasUtils';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants';
import { IRenderDimensions } from 'browser/renderer/shared/Types';
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { IBufferService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from 'xterm';
import { BaseRenderLayer } from './BaseRenderLayer';
@@ -24,10 +24,9 @@ export class LinkRenderLayer extends BaseRenderLayer {
optionsService: IOptionsService,
decorationService: IDecorationService,
coreBrowserService: ICoreBrowserService,
themeService: IThemeService,
unicodeService: IUnicodeService
themeService: IThemeService
) {
super(terminal, container, 'link', zIndex, true, themeService, bufferService, optionsService, decorationService, coreBrowserService, unicodeService);
super(terminal, container, 'link', zIndex, true, themeService, bufferService, optionsService, decorationService, coreBrowserService);
this.register(linkifier2.onShowLinkUnderline(e => this._handleShowLinkUnderline(e)));
this.register(linkifier2.onHideLinkUnderline(e => this._handleHideLinkUnderline(e)));
@@ -5,7 +5,7 @@
import { IRenderDimensions } from 'browser/renderer/shared/Types';
import { BaseRenderLayer } from './BaseRenderLayer';
import { IBufferService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { Terminal } from 'xterm';
@@ -27,10 +27,9 @@ export class SelectionRenderLayer extends BaseRenderLayer {
coreBrowserService: ICoreBrowserService,
decorationService: IDecorationService,
optionsService: IOptionsService,
themeService: IThemeService,
unicodeService: IUnicodeService
themeService: IThemeService
) {
super(terminal, container, 'selection', zIndex, true, themeService, bufferService, optionsService, decorationService, coreBrowserService, unicodeService);
super(terminal, container, 'selection', zIndex, true, themeService, bufferService, optionsService, decorationService, coreBrowserService);
this._clearState();
}
@@ -10,7 +10,7 @@ import { CharData, ICellData } from 'common/Types';
import { AttributeData } from 'common/buffer/AttributeData';
import { CellData } from 'common/buffer/CellData';
import { Content, NULL_CELL_CODE } from 'common/buffer/Constants';
import { IBufferService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from 'xterm';
import { BaseRenderLayer } from './BaseRenderLayer';
import { GridCache } from './GridCache';
@@ -39,10 +39,9 @@ export class TextRenderLayer extends BaseRenderLayer {
private readonly _characterJoinerService: ICharacterJoinerService,
decorationService: IDecorationService,
coreBrowserService: ICoreBrowserService,
themeService: IThemeService,
unicodeService: IUnicodeService
themeService: IThemeService
) {
super(terminal, container, 'text', zIndex, alpha, themeService, bufferService, optionsService, decorationService, coreBrowserService, unicodeService);
super(terminal, container, 'text', zIndex, alpha, themeService, bufferService, optionsService, decorationService, coreBrowserService);
this._state = new GridCache<CharData>();
this.register(optionsService.onSpecificOptionChange('allowTransparency', value => this._setTransparency(value)));
}
+1 -3
View File
@@ -8,7 +8,7 @@ import { ITerminal } from 'browser/Types';
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { getSafariVersion, isSafari } from 'common/Platform';
import { ICoreService, IDecorationService, ILogService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
import { ITerminalAddon, Terminal } from 'xterm';
import { WebglRenderer } from './WebglRenderer';
import { setTraceLogger } from 'common/services/LogService';
@@ -54,7 +54,6 @@ export class WebglAddon extends Disposable implements ITerminalAddon {
const decorationService: IDecorationService = unsafeCore._decorationService;
const logService: ILogService = unsafeCore._logService;
const themeService: IThemeService = unsafeCore._themeService;
const unicodeService: IUnicodeService = unsafeCore.unicodeService;
// Set trace logger just in case it hasn't been yet which could happen when the addon is
// bundled separately to the core module
@@ -69,7 +68,6 @@ export class WebglAddon extends Disposable implements ITerminalAddon {
decorationService,
optionsService,
themeService,
unicodeService,
this._preserveDrawingBuffer
));
this.register(forwardEvent(this._renderer.onContextLoss, this._onContextLoss));
@@ -19,7 +19,7 @@ import { AttributeData } from 'common/buffer/AttributeData';
import { CellData } from 'common/buffer/CellData';
import { Attributes, Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
import { traceCall } from 'common/services/LogService';
import { ICoreService, IDecorationService, IOptionsService, IUnicodeService } from 'common/services/Services';
import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { IDisposable, Terminal } from 'xterm';
import { GlyphRenderer } from './GlyphRenderer';
import { RectangleRenderer } from './RectangleRenderer';
@@ -70,14 +70,13 @@ export class WebglRenderer extends Disposable implements IRenderer {
private readonly _decorationService: IDecorationService,
private readonly _optionsService: IOptionsService,
private readonly _themeService: IThemeService,
private readonly _unicodeService: IUnicodeService,
preserveDrawingBuffer?: boolean
) {
super();
this.register(this._themeService.onChangeColors(() => this._handleColorChange()));
this._cellColorResolver = new CellColorResolver(this._terminal, this._model.selection, this._decorationService, this._coreBrowserService, this._themeService, this._unicodeService);
this._cellColorResolver = new CellColorResolver(this._terminal, this._optionsService, this._model.selection, this._decorationService, this._coreBrowserService, this._themeService);
this._core = (this._terminal as any)._core;
@@ -1,9 +1,8 @@
import { computeVarinatOffset } from 'browser/renderer/shared/RendererUtils';
import { ISelectionRenderModel } from 'browser/renderer/shared/Types';
import { ICoreBrowserService, IThemeService } from 'browser/services/Services';
import { ReadonlyColorSet } from 'browser/Types';
import { Attributes, BgFlags, ExtFlags, FgFlags, NULL_CELL_CODE, UnderlineStyle } from 'common/buffer/Constants';
import { IDecorationService, IUnicodeService } from 'common/services/Services';
import { IDecorationService, IOptionsService } from 'common/services/Services';
import { ICellData } from 'common/Types';
import { Terminal } from 'xterm';
@@ -14,7 +13,6 @@ let $hasFg = false;
let $hasBg = false;
let $isSelected = false;
let $colors: ReadonlyColorSet | undefined;
let $y = -1;
let $variantOffset = 0;
export class CellColorResolver {
@@ -30,11 +28,11 @@ export class CellColorResolver {
constructor(
private readonly _terminal: Terminal,
private readonly _optionService: IOptionsService,
private readonly _selectionRenderModel: ISelectionRenderModel,
private readonly _decorationService: IDecorationService,
private readonly _coreBrowserService: ICoreBrowserService,
private readonly _themeService: IThemeService,
private readonly _unicodeService: IUnicodeService
private readonly _themeService: IThemeService
) {
}
@@ -56,15 +54,12 @@ export class CellColorResolver {
$hasFg = false;
$isSelected = false;
$colors = this._themeService.colors;
if ($y !== y) {
$variantOffset = 0;
}
$y = y;
$variantOffset = 0;
const code = cell.getCode();
if (code === NULL_CELL_CODE && cell.extended.underlineStyle !== UnderlineStyle.DOTTED) {
$variantOffset = 0;
if (code !== NULL_CELL_CODE && cell.extended.underlineStyle === UnderlineStyle.DOTTED) {
const lineWidth = Math.max(1, Math.floor(this._optionService.rawOptions.fontSize * this._coreBrowserService.dpr / 15));
$variantOffset = x * deviceCellWidth % (Math.round(lineWidth) * 2);
}
// Apply decorations on the bottom layer
@@ -151,22 +146,5 @@ export class CellColorResolver {
// Reset overrides variantOffset
this.result.ext &= ~ExtFlags.VARIANT_OFFSET;
this.result.ext |= ($variantOffset << 29) & ExtFlags.VARIANT_OFFSET;
// Compute next variantOffset
if (cell.extended.underlineStyle === UnderlineStyle.DOTTED) {
if (code !== NULL_CELL_CODE) {
const fontSize = this._terminal.options.fontSize;
const lineWidth = Math.max(1, Math.floor(fontSize! * this._coreBrowserService.dpr / 15));
let chWidth: number;
if (typeof code === 'number') {
chWidth = this._unicodeService.wcwidth(code);
} else {
chWidth = this._unicodeService.getStringCellWidth(code);
}
$variantOffset = computeVarinatOffset(deviceCellWidth * chWidth, lineWidth, $variantOffset);
}
} else {
$variantOffset = 0;
}
}
}
@@ -3,11 +3,11 @@
* @license MIT
*/
import { computeVarinatOffset } from 'browser/renderer/shared/RendererUtils';
import { computeNextVarinatOffset } from 'browser/renderer/shared/RendererUtils';
import { assert } from 'chai';
describe('RendererUtils', () => {
it('computeVarinatOffset', () => {
it('computeNextVarinatOffset', () => {
const cellWidth = 11;
const doubleCellWidth = 22;
let line = 1;
@@ -19,7 +19,7 @@ describe('RendererUtils', () => {
let result = [1, 0, 0, 0];
for (let index = 0; index < cells.length; index++) {
const cell = cells[index];
varinatOffset = computeVarinatOffset(cell, line, varinatOffset);
varinatOffset = computeNextVarinatOffset(cell, line, varinatOffset);
assert.equal(varinatOffset, result[index]);
}
@@ -31,7 +31,7 @@ describe('RendererUtils', () => {
result = [3, 2, 0 ,2];
for (let index = 0; index < cells.length; index++) {
const cell = cells[index];
varinatOffset = computeVarinatOffset(cell, line, varinatOffset);
varinatOffset = computeNextVarinatOffset(cell, line, varinatOffset);
assert.equal(varinatOffset, result[index]);
}
@@ -43,7 +43,7 @@ describe('RendererUtils', () => {
result = [5, 4, 2, 0];
for (let index = 0; index < cells.length; index++) {
const cell = cells[index];
varinatOffset = computeVarinatOffset(cell, line, varinatOffset);
varinatOffset = computeNextVarinatOffset(cell, line, varinatOffset);
assert.equal(varinatOffset, result[index]);
}
});
+1 -1
View File
@@ -57,6 +57,6 @@ function createDimension(): IDimensions {
};
}
export function computeVarinatOffset(cellWidth: number, lineWidth: number, currentOffset: number = 0): number {
export function computeNextVarinatOffset(cellWidth: number, lineWidth: number, currentOffset: number = 0): number {
return (cellWidth - (Math.round(lineWidth) * 2 - currentOffset)) % (Math.round(lineWidth) * 2);
}
+11 -17
View File
@@ -6,7 +6,7 @@
import { IColorContrastCache } from 'browser/Types';
import { DIM_OPACITY, TEXT_BASELINE } from 'browser/renderer/shared/Constants';
import { tryDrawCustomChar } from 'browser/renderer/shared/CustomGlyphs';
import { computeVarinatOffset, excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
import { computeNextVarinatOffset, excludeFromContrastRatioDemands, isPowerlineGlyph, isRestrictedPowerlineGlyph, throwIfFalsy } from 'browser/renderer/shared/RendererUtils';
import { IBoundingBox, ICharAtlasConfig, IRasterizedGlyph, ITextureAtlas } from 'browser/renderer/shared/Types';
import { NULL_COLOR, color, rgba } from 'common/Color';
import { EventEmitter } from 'common/EventEmitter';
@@ -599,26 +599,20 @@ export class TextureAtlas implements ITextureAtlas {
case UnderlineStyle.DOTTED:
const offsetWidth = nextOffset === 0 ? 0 :
(nextOffset >= lineWidth ? lineWidth * 2 - nextOffset : lineWidth - nextOffset);
if (offsetWidth === 0) {
// a line and a gap.
const isLineStart = nextOffset >= lineWidth ? false : true;
if (isLineStart === false || offsetWidth === 0) {
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
this._tmpCtx.moveTo(xChLeft, yTop);
this._tmpCtx.moveTo(xChLeft + offsetWidth, yTop);
this._tmpCtx.lineTo(xChRight, yTop);
} else {
// a line and a gap.
const isLineStart = nextOffset >= lineWidth ? false : true;
if (isLineStart === false) {
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
this._tmpCtx.moveTo(xChLeft + offsetWidth, yTop);
this._tmpCtx.lineTo(xChRight, yTop);
} else {
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
this._tmpCtx.moveTo(xChLeft, yTop);
this._tmpCtx.lineTo(xChLeft + offsetWidth, yTop);
this._tmpCtx.moveTo(xChLeft + offsetWidth + lineWidth, yTop);
this._tmpCtx.lineTo(xChRight, yTop);
}
this._tmpCtx.setLineDash([Math.round(lineWidth), Math.round(lineWidth)]);
this._tmpCtx.moveTo(xChLeft, yTop);
this._tmpCtx.lineTo(xChLeft + offsetWidth, yTop);
this._tmpCtx.moveTo(xChLeft + offsetWidth + lineWidth, yTop);
this._tmpCtx.lineTo(xChRight, yTop);
}
nextOffset = computeVarinatOffset(xChRight - xChLeft, lineWidth, nextOffset);
nextOffset = computeNextVarinatOffset(xChRight - xChLeft, lineWidth, nextOffset);
break;
case UnderlineStyle.DASHED:
this._tmpCtx.setLineDash([this._config.devicePixelRatio * 4, this._config.devicePixelRatio * 3]);
+1 -1
View File
@@ -180,7 +180,7 @@ export class ExtendedAttrs implements IExtendedAttrs {
public get underlineVarinatOffset(): number {
const val = (this._ext & ExtFlags.VARIANT_OFFSET) >> 29;
if (val < 0) {
return val ^ 4294967288;
return val ^ 0xFFFFFFF8;
}
return val;
}