未验证 提交 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 () { ...@@ -42,6 +42,8 @@ const canUseFastRenderedViewLine = (function () {
return true; return true;
})(); })();
let monospaceAssumptionsAreValid = true;
const alwaysRenderInlineSelection = (browser.isEdge); const alwaysRenderInlineSelection = (browser.isEdge);
export class DomReadingContext { export class DomReadingContext {
...@@ -248,7 +250,7 @@ export class ViewLine implements IVisibleLine { ...@@ -248,7 +250,7 @@ export class ViewLine implements IVisibleLine {
sb.appendASCIIString('</div>'); sb.appendASCIIString('</div>');
let renderedViewLine: IRenderedViewLine | null = null; 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) { if (lineData.content.length < 300 && renderLineInput.lineTokens.getCount() < 100) {
// Browser rounding errors have been observed in Chrome and IE, so using the fast // 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... // view line only for short lines. Please test before removing the length check...
...@@ -304,6 +306,29 @@ export class ViewLine implements IVisibleLine { ...@@ -304,6 +306,29 @@ export class ViewLine implements IVisibleLine {
return this._renderedViewLine.getWidthIsFast(); 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 { public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): VisibleRanges | null {
if (!this._renderedViewLine) { if (!this._renderedViewLine) {
return null; return null;
...@@ -382,6 +407,24 @@ class FastRenderedViewLine implements IRenderedViewLine { ...@@ -382,6 +407,24 @@ class FastRenderedViewLine implements IRenderedViewLine {
return true; 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 { public getVisibleRangesForRange(startColumn: number, endColumn: number, context: DomReadingContext): HorizontalRange[] | null {
const startPosition = this._getCharPosition(startColumn); const startPosition = this._getCharPosition(startColumn);
const endPosition = this._getCharPosition(endColumn); const endPosition = this._getCharPosition(endColumn);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import 'vs/css!./viewLines'; import 'vs/css!./viewLines';
import * as platform from 'vs/base/common/platform';
import { FastDomNode } from 'vs/base/browser/fastDomNode'; import { FastDomNode } from 'vs/base/browser/fastDomNode';
import { RunOnceScheduler } from 'vs/base/common/async'; import { RunOnceScheduler } from 'vs/base/common/async';
import { Configuration } from 'vs/editor/browser/config/configuration'; import { Configuration } from 'vs/editor/browser/config/configuration';
...@@ -106,6 +107,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>, ...@@ -106,6 +107,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
// --- width // --- width
private _maxLineWidth: number; private _maxLineWidth: number;
private readonly _asyncUpdateLineWidths: RunOnceScheduler; private readonly _asyncUpdateLineWidths: RunOnceScheduler;
private readonly _asyncCheckMonospaceFontAssumptions: RunOnceScheduler;
private _horizontalRevealRequest: HorizontalRevealRequest | null; private _horizontalRevealRequest: HorizontalRevealRequest | null;
private readonly _lastRenderedData: LastRenderedData; private readonly _lastRenderedData: LastRenderedData;
...@@ -140,6 +142,9 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>, ...@@ -140,6 +142,9 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
this._asyncUpdateLineWidths = new RunOnceScheduler(() => { this._asyncUpdateLineWidths = new RunOnceScheduler(() => {
this._updateLineWidthsSlow(); this._updateLineWidthsSlow();
}, 200); }, 200);
this._asyncCheckMonospaceFontAssumptions = new RunOnceScheduler(() => {
this._checkMonospaceFontAssumptions();
}, 2000);
this._lastRenderedData = new LastRenderedData(); this._lastRenderedData = new LastRenderedData();
...@@ -148,6 +153,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>, ...@@ -148,6 +153,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
public dispose(): void { public dispose(): void {
this._asyncUpdateLineWidths.dispose(); this._asyncUpdateLineWidths.dispose();
this._asyncCheckMonospaceFontAssumptions.dispose();
super.dispose(); super.dispose();
} }
...@@ -513,6 +519,37 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>, ...@@ -513,6 +519,37 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
return allWidthsComputed; 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 { public prepareRender(): void {
throw new Error('Not supported'); throw new Error('Not supported');
} }
...@@ -571,6 +608,18 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>, ...@@ -571,6 +608,18 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost<ViewLine>,
this._asyncUpdateLineWidths.schedule(); 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 // (3) handle scrolling
this._linesContent.setLayerHinting(this._canUseLayerHinting); this._linesContent.setLayerHinting(this._canUseLayerHinting);
this._linesContent.setContain('strict'); this._linesContent.setContain('strict');
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册