未验证 提交 7bcbf8d4 编写于 作者: A Alexandru Dima 提交者: GitHub

Merge pull request #92291 from microsoft/alex/validate-monospace-assumptions

Validate monospace assumptions
......@@ -42,6 +42,8 @@ const canUseFastRenderedViewLine = (function () {
return true;
})();
let monospaceAssumptionsAreValid = true;
const alwaysRenderInlineSelection = (browser.isEdge);
export class DomReadingContext {
......@@ -248,7 +250,7 @@ export class ViewLine implements IVisibleLine {
sb.appendASCIIString('</div>');
let renderedViewLine: IRenderedViewLine | null = null;
if (canUseFastRenderedViewLine && lineData.isBasicASCII && options.useMonospaceOptimizations && output.containsForeignElements === ForeignElementType.None) {
if (monospaceAssumptionsAreValid && canUseFastRenderedViewLine && lineData.isBasicASCII && options.useMonospaceOptimizations && output.containsForeignElements === ForeignElementType.None) {
if (lineData.content.length < 300 && renderLineInput.lineTokens.getCount() < 100) {
// Browser rounding errors have been observed in Chrome and IE, so using the fast
// view line only for short lines. Please test before removing the length check...
......@@ -304,6 +306,29 @@ export class ViewLine implements IVisibleLine {
return this._renderedViewLine.getWidthIsFast();
}
public needsMonospaceFontCheck(): boolean {
if (!this._renderedViewLine) {
return false;
}
return (this._renderedViewLine instanceof FastRenderedViewLine);
}
public monospaceAssumptionsAreValid(): boolean {
if (!this._renderedViewLine) {
return monospaceAssumptionsAreValid;
}
if (this._renderedViewLine instanceof FastRenderedViewLine) {
return this._renderedViewLine.monospaceAssumptionsAreValid();
}
return monospaceAssumptionsAreValid;
}
public onMonospaceAssumptionsInvalidated(): void {
if (this._renderedViewLine && this._renderedViewLine instanceof FastRenderedViewLine) {
this._renderedViewLine = this._renderedViewLine.toSlowRenderedLine();
}
}
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): VisibleRanges | null {
if (!this._renderedViewLine) {
return null;
......@@ -382,6 +407,24 @@ class FastRenderedViewLine implements IRenderedViewLine {
return true;
}
public monospaceAssumptionsAreValid(): boolean {
if (!this.domNode) {
return monospaceAssumptionsAreValid;
}
const expectedWidth = this.getWidth();
const actualWidth = (<HTMLSpanElement>this.domNode.domNode.firstChild).offsetWidth;
if (Math.abs(expectedWidth - actualWidth) >= 2) {
// more than 2px off
console.warn(`monospace assumptions have been violated, therefore disabling monospace optimizations!`);
monospaceAssumptionsAreValid = false;
}
return monospaceAssumptionsAreValid;
}
public toSlowRenderedLine(): RenderedViewLine {
return createRenderedLine(this.domNode, this.input, this._characterMapping, false, ForeignElementType.None);
}
public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {
const startPosition = this._getCharPosition(startColumn);
const endPosition = this._getCharPosition(endColumn);
......
......@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./viewLines';
import * as platform from 'vs/base/common/platform';
import { FastDomNode } from 'vs/base/browser/fastDomNode';
import { RunOnceScheduler } from 'vs/base/common/async';
import { Configuration } from 'vs/editor/browser/config/configuration';
......@@ -106,6 +107,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
// --- width
private _maxLineWidth: number;
private readonly _asyncUpdateLineWidths: RunOnceScheduler;
private readonly _asyncCheckMonospaceFontAssumptions: RunOnceScheduler;
private _horizontalRevealRequest: HorizontalRevealRequest | null;
private readonly _lastRenderedData: LastRenderedData;
......@@ -140,6 +142,9 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
this._asyncUpdateLineWidths = new RunOnceScheduler(() => {
this._updateLineWidthsSlow();
}, 200);
this._asyncCheckMonospaceFontAssumptions = new RunOnceScheduler(() => {
this._checkMonospaceFontAssumptions();
}, 2000);
this._lastRenderedData = new LastRenderedData();
......@@ -148,6 +153,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
public dispose(): void {
this._asyncUpdateLineWidths.dispose();
this._asyncCheckMonospaceFontAssumptions.dispose();
super.dispose();
}
......@@ -513,6 +519,37 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
return allWidthsComputed;
}
private _checkMonospaceFontAssumptions(): void {
// Problems with monospace assumptions are more apparent for longer lines,
// as small rounding errors start to sum up, so we will select the longest
// line for a closer inspection
let longestLineNumber = -1;
let longestWidth = -1;
const rendStartLineNumber = this._visibleLines.getStartLineNumber();
const rendEndLineNumber = this._visibleLines.getEndLineNumber();
for (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {
const visibleLine = this._visibleLines.getVisibleLine(lineNumber);
if (visibleLine.needsMonospaceFontCheck()) {
const lineWidth = visibleLine.getWidth();
if (lineWidth > longestWidth) {
longestWidth = lineWidth;
longestLineNumber = lineNumber;
}
}
}
if (longestLineNumber === -1) {
return;
}
if (!this._visibleLines.getVisibleLine(longestLineNumber).monospaceAssumptionsAreValid()) {
for (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {
const visibleLine = this._visibleLines.getVisibleLine(lineNumber);
visibleLine.onMonospaceAssumptionsInvalidated();
}
}
}
public prepareRender(): void {
throw new Error('Not supported');
}
......@@ -571,6 +608,18 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
this._asyncUpdateLineWidths.schedule();
}
if (platform.isLinux && !this._asyncCheckMonospaceFontAssumptions.isScheduled()) {
const rendStartLineNumber = this._visibleLines.getStartLineNumber();
const rendEndLineNumber = this._visibleLines.getEndLineNumber();
for (let lineNumber = rendStartLineNumber; lineNumber <= rendEndLineNumber; lineNumber++) {
const visibleLine = this._visibleLines.getVisibleLine(lineNumber);
if (visibleLine.needsMonospaceFontCheck()) {
this._asyncCheckMonospaceFontAssumptions.schedule();
break;
}
}
}
// (3) handle scrolling
this._linesContent.setLayerHinting(this._canUseLayerHinting);
this._linesContent.setContain('strict');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册