提交 634d1167 编写于 作者: A Alex Dima

Add intermediary step in view line rendering

上级 cd17a283
...@@ -122,10 +122,13 @@ export class ViewLine implements IVisibleLineData { ...@@ -122,10 +122,13 @@ export class ViewLine implements IVisibleLineData {
return false; return false;
} }
let isWhitespaceOnly = /^\s*$/.test(renderLineInput.lineContent);
this._renderedViewLine = createRenderedLine( this._renderedViewLine = createRenderedLine(
this._renderedViewLine ? this._renderedViewLine.domNode : null, this._renderedViewLine ? this._renderedViewLine.domNode : null,
renderLineInput, renderLineInput,
this._context.model.mightContainRTL(), this._context.model.mightContainRTL(),
isWhitespaceOnly,
renderLine(renderLineInput) renderLine(renderLineInput)
); );
return true; return true;
...@@ -183,12 +186,12 @@ class RenderedViewLine { ...@@ -183,12 +186,12 @@ class RenderedViewLine {
*/ */
private _pixelOffsetCache: number[]; private _pixelOffsetCache: number[];
constructor(domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, renderLineOutput: RenderLineOutput) { constructor(domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, isWhitespaceOnly: boolean, renderLineOutput: RenderLineOutput) {
this.domNode = domNode; this.domNode = domNode;
this.input = renderLineInput; this.input = renderLineInput;
this.html = renderLineOutput.output; this.html = renderLineOutput.output;
this._characterMapping = renderLineOutput.characterMapping; this._characterMapping = renderLineOutput.characterMapping;
this._isWhitespaceOnly = renderLineOutput.isWhitespaceOnly; this._isWhitespaceOnly = isWhitespaceOnly;
this._cachedWidth = -1; this._cachedWidth = -1;
this._pixelOffsetCache = null; this._pixelOffsetCache = null;
...@@ -376,17 +379,17 @@ class WebKitRenderedViewLine extends RenderedViewLine { ...@@ -376,17 +379,17 @@ class WebKitRenderedViewLine extends RenderedViewLine {
} }
} }
const createRenderedLine: (domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, renderLineOutput: RenderLineOutput) => RenderedViewLine = (function () { const createRenderedLine: (domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, isWhitespaceOnly: boolean, renderLineOutput: RenderLineOutput) => RenderedViewLine = (function () {
if (browser.isWebKit) { if (browser.isWebKit) {
return createWebKitRenderedLine; return createWebKitRenderedLine;
} }
return createNormalRenderedLine; return createNormalRenderedLine;
})(); })();
function createWebKitRenderedLine(domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, renderLineOutput: RenderLineOutput): RenderedViewLine { function createWebKitRenderedLine(domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, isWhitespaceOnly: boolean, renderLineOutput: RenderLineOutput): RenderedViewLine {
return new WebKitRenderedViewLine(domNode, renderLineInput, modelContainsRTL, renderLineOutput); return new WebKitRenderedViewLine(domNode, renderLineInput, modelContainsRTL, isWhitespaceOnly, renderLineOutput);
} }
function createNormalRenderedLine(domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, renderLineOutput: RenderLineOutput): RenderedViewLine { function createNormalRenderedLine(domNode: FastDomNode, renderLineInput: RenderLineInput, modelContainsRTL: boolean, isWhitespaceOnly: boolean, renderLineOutput: RenderLineOutput): RenderedViewLine {
return new RenderedViewLine(domNode, renderLineInput, modelContainsRTL, renderLineOutput); return new RenderedViewLine(domNode, renderLineInput, modelContainsRTL, isWhitespaceOnly, renderLineOutput);
} }
...@@ -166,12 +166,10 @@ export class RenderLineOutput { ...@@ -166,12 +166,10 @@ export class RenderLineOutput {
readonly characterMapping: CharacterMapping; readonly characterMapping: CharacterMapping;
readonly output: string; readonly output: string;
readonly isWhitespaceOnly: boolean;
constructor(characterMapping: CharacterMapping, output: string, isWhitespaceOnly: boolean) { constructor(characterMapping: CharacterMapping, output: string) {
this.characterMapping = characterMapping; this.characterMapping = characterMapping;
this.output = output; this.output = output;
this.isWhitespaceOnly = isWhitespaceOnly;
} }
} }
...@@ -189,8 +187,7 @@ export function renderLine(input: RenderLineInput): RenderLineOutput { ...@@ -189,8 +187,7 @@ export function renderLine(input: RenderLineInput): RenderLineOutput {
return new RenderLineOutput( return new RenderLineOutput(
new CharacterMapping(0), new CharacterMapping(0),
// This is basically for IE's hit test to work // This is basically for IE's hit test to work
'<span><span>&nbsp;</span></span>', '<span><span>&nbsp;</span></span>'
true
); );
} }
...@@ -198,7 +195,10 @@ export function renderLine(input: RenderLineInput): RenderLineOutput { ...@@ -198,7 +195,10 @@ export function renderLine(input: RenderLineInput): RenderLineOutput {
throw new Error('Cannot render non empty line without line parts!'); throw new Error('Cannot render non empty line without line parts!');
} }
return renderLineActual(lineText, lineTextLength, tabSize, spaceWidth, actualLineParts, renderWhitespace, renderControlCharacters, charBreakIndex); let viewParts = toViewParts(lineText, lineTextLength, tabSize, spaceWidth, actualLineParts, renderWhitespace, renderControlCharacters, charBreakIndex);
return renderViewParts(viewParts);
// return renderLineActual(lineText, lineTextLength, tabSize, spaceWidth, actualLineParts, renderWhitespace, renderControlCharacters, charBreakIndex);
} }
function isWhitespace(type: string): boolean { function isWhitespace(type: string): boolean {
...@@ -214,20 +214,40 @@ function controlCharacterToPrintable(characterCode: number): string { ...@@ -214,20 +214,40 @@ function controlCharacterToPrintable(characterCode: number): string {
return String.fromCharCode(_controlCharacterSequenceConversionStart + characterCode); return String.fromCharCode(_controlCharacterSequenceConversionStart + characterCode);
} }
function renderLineActual(lineText: string, lineTextLength: number, tabSize: number, spaceWidth: number, actualLineParts: ViewLineToken[], renderWhitespace: 'none' | 'boundary' | 'all', renderControlCharacters: boolean, charBreakIndex: number): RenderLineOutput { class ViewPart2 {
public readonly className: string;
public readonly htmlContent: string;
public readonly forceWidth: number;
constructor(className: string, htmlContent: string, forceWidth: number) {
this.className = className;
this.htmlContent = htmlContent;
this.forceWidth = forceWidth;
}
}
class ViewParts2 {
public readonly parts: ViewPart2[];
public readonly characterMapping: CharacterMapping;
constructor(parts: ViewPart2[], characterMapping: CharacterMapping) {
this.parts = parts;
this.characterMapping = characterMapping;
}
}
function toViewParts(lineText: string, lineTextLength: number, tabSize: number, spaceWidth: number, actualLineParts: ViewLineToken[], renderWhitespace: 'none' | 'boundary' | 'all', renderControlCharacters: boolean, charBreakIndex: number): ViewParts2 {
lineTextLength = +lineTextLength; lineTextLength = +lineTextLength;
tabSize = +tabSize; tabSize = +tabSize;
charBreakIndex = +charBreakIndex; charBreakIndex = +charBreakIndex;
let charIndex = 0; let charIndex = 0;
let out = '';
let charOffsetInPart = 0; let charOffsetInPart = 0;
let tabsCharDelta = 0; let tabsCharDelta = 0;
let isWhitespaceOnly = /^\s*$/.test(lineText);
let characterMapping = new CharacterMapping(Math.min(lineTextLength, charBreakIndex) + 1); let characterMapping = new CharacterMapping(Math.min(lineTextLength, charBreakIndex) + 1);
out += '<span>'; let result: ViewPart2[] = [], resultLen = 0;
for (let partIndex = 0, partIndexLen = actualLineParts.length; partIndex < partIndexLen; partIndex++) { for (let partIndex = 0, partIndexLen = actualLineParts.length; partIndex < partIndexLen; partIndex++) {
let part = actualLineParts[partIndex]; let part = actualLineParts[partIndex];
...@@ -271,18 +291,14 @@ function renderLineActual(lineText: string, lineTextLength: number, tabSize: num ...@@ -271,18 +291,14 @@ function renderLineActual(lineText: string, lineTextLength: number, tabSize: num
charOffsetInPart++; charOffsetInPart++;
if (charIndex >= charBreakIndex) { if (charIndex >= charBreakIndex) {
out += `<span class="${part.type}" style="width:${(spaceWidth * partContentCnt)}px">${partContent}&hellip;</span></span>`; result[resultLen++] = new ViewPart2(part.type, partContent + '&hellip;', 0);
characterMapping.setPartData(charIndex, partIndex, charOffsetInPart); characterMapping.setPartData(charIndex, partIndex, charOffsetInPart);
return new RenderLineOutput( return new ViewParts2(result, characterMapping);
characterMapping,
out,
isWhitespaceOnly
);
} }
} }
out += `<span class="${part.type}" style="width:${(spaceWidth * partContentCnt)}px">${partContent}</span>`; result[resultLen++] = new ViewPart2(part.type, partContent, (spaceWidth * partContentCnt));
} else { } else {
out += `<span class="${part.type}">`; let partContent = '';
for (; charIndex < toCharIndex; charIndex++) { for (; charIndex < toCharIndex; charIndex++) {
characterMapping.setPartData(charIndex, partIndex, charOffsetInPart); characterMapping.setPartData(charIndex, partIndex, charOffsetInPart);
...@@ -294,75 +310,81 @@ function renderLineActual(lineText: string, lineTextLength: number, tabSize: num ...@@ -294,75 +310,81 @@ function renderLineActual(lineText: string, lineTextLength: number, tabSize: num
tabsCharDelta += insertSpacesCount - 1; tabsCharDelta += insertSpacesCount - 1;
charOffsetInPart += insertSpacesCount - 1; charOffsetInPart += insertSpacesCount - 1;
while (insertSpacesCount > 0) { while (insertSpacesCount > 0) {
out += '&nbsp;'; partContent += '&nbsp;';
insertSpacesCount--; insertSpacesCount--;
} }
break; break;
case CharCode.Space: case CharCode.Space:
out += '&nbsp;'; partContent += '&nbsp;';
break; break;
case CharCode.LessThan: case CharCode.LessThan:
out += '&lt;'; partContent += '&lt;';
break; break;
case CharCode.GreaterThan: case CharCode.GreaterThan:
out += '&gt;'; partContent += '&gt;';
break; break;
case CharCode.Ampersand: case CharCode.Ampersand:
out += '&amp;'; partContent += '&amp;';
break; break;
case CharCode.Null: case CharCode.Null:
out += '&#00;'; partContent += '&#00;';
break; break;
case CharCode.UTF8_BOM: case CharCode.UTF8_BOM:
case CharCode.LINE_SEPARATOR_2028: case CharCode.LINE_SEPARATOR_2028:
out += '\ufffd'; partContent += '\ufffd';
break; break;
case CharCode.CarriageReturn: case CharCode.CarriageReturn:
// zero width space, because carriage return would introduce a line break // zero width space, because carriage return would introduce a line break
out += '&#8203'; partContent += '&#8203';
break; break;
default: default:
if (renderControlCharacters && isControlCharacter(charCode)) { if (renderControlCharacters && isControlCharacter(charCode)) {
out += controlCharacterToPrintable(charCode); partContent += controlCharacterToPrintable(charCode);
} else { } else {
out += lineText.charAt(charIndex); partContent += lineText.charAt(charIndex);
} }
} }
charOffsetInPart++; charOffsetInPart++;
if (charIndex >= charBreakIndex) { if (charIndex >= charBreakIndex) {
out += '&hellip;</span></span>'; result[resultLen++] = new ViewPart2(part.type, partContent + '&hellip;', 0);
characterMapping.setPartData(charIndex, partIndex, charOffsetInPart); characterMapping.setPartData(charIndex, partIndex, charOffsetInPart);
return new RenderLineOutput( return new ViewParts2(result, characterMapping);
characterMapping,
out,
isWhitespaceOnly
);
} }
} }
result[resultLen++] = new ViewPart2(part.type, partContent, 0);
out += '</span>';
} }
} }
out += '</span>';
// When getting client rects for the last character, we will position the // When getting client rects for the last character, we will position the
// text range at the end of the span, insteaf of at the beginning of next span // text range at the end of the span, insteaf of at the beginning of next span
characterMapping.setPartData(lineTextLength, actualLineParts.length - 1, charOffsetInPart); characterMapping.setPartData(lineTextLength, actualLineParts.length - 1, charOffsetInPart);
return new RenderLineOutput( return new ViewParts2(result, characterMapping);
characterMapping, }
out,
isWhitespaceOnly function renderViewParts(viewParts: ViewParts2): RenderLineOutput {
); const parts = viewParts.parts;
let out = '<span>';
for (let i = 0, len = parts.length; i < len; i++) {
let part = parts[i];
if (part.forceWidth) {
out += `<span class="${part.className}" style="width:${part.forceWidth}px">${part.htmlContent}</span>`;
} else {
out += `<span class="${part.className}">${part.htmlContent}</span>`;
}
}
out += '</span>';
return new RenderLineOutput(viewParts.characterMapping, out);
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册