Skip to content

Commit bb04e41

Browse files
committed
Fixes microsoft#90391: Split lines into spans of at most 16384 characters
1 parent 2e3bbc2 commit bb04e41

1 file changed

Lines changed: 25 additions & 11 deletions

File tree

src/vs/editor/browser/view/domLineBreaksComputer.ts

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ function createLineBreaks(requests: string[], fontInfo: FontInfo, tabSize: numbe
149149
return result;
150150
}
151151

152+
const enum Constants {
153+
SPAN_MODULO_LIMIT = 16384
154+
}
155+
152156
function renderLine(lineContent: string, initialVisibleColumn: number, tabSize: number, width: number, sb: IStringBuilder): [number[], number[]] {
153157
sb.appendASCIIString('<div style="width:');
154158
sb.appendASCIIString(String(width));
@@ -164,7 +168,11 @@ function renderLine(lineContent: string, initialVisibleColumn: number, tabSize:
164168
let visibleColumns: number[] = [];
165169
let nextCharCode = (0 < len ? lineContent.charCodeAt(0) : CharCode.Null);
166170

171+
sb.appendASCIIString('<span>');
167172
for (let charIndex = 0; charIndex < len; charIndex++) {
173+
if (charIndex !== 0 && charIndex % Constants.SPAN_MODULO_LIMIT === 0) {
174+
sb.appendASCIIString('</span><span>');
175+
}
168176
charOffsets[charIndex] = charOffset;
169177
visibleColumns[charIndex] = visibleColumn;
170178
const charCode = nextCharCode;
@@ -227,6 +235,7 @@ function renderLine(lineContent: string, initialVisibleColumn: number, tabSize:
227235
charOffset += producedCharacters;
228236
visibleColumn += charWidth;
229237
}
238+
sb.appendASCIIString('</span>');
230239

231240
charOffsets[lineContent.length] = charOffset;
232241
visibleColumns[lineContent.length] = visibleColumn;
@@ -240,10 +249,15 @@ function readLineBreaks(range: Range, lineDomNode: HTMLDivElement, lineContent:
240249
if (lineContent.length <= 1) {
241250
return null;
242251
}
243-
const textContentNode = lineDomNode.firstChild!;
252+
const spans = <HTMLSpanElement[]>Array.prototype.slice.call(lineDomNode.children, 0);
244253

245254
const breakOffsets: number[] = [];
246-
discoverBreaks(range, textContentNode, charOffsets, 0, null, lineContent.length - 1, null, breakOffsets);
255+
try {
256+
discoverBreaks(range, spans, charOffsets, 0, null, lineContent.length - 1, null, breakOffsets);
257+
} catch (err) {
258+
console.log(err);
259+
return null;
260+
}
247261

248262
if (breakOffsets.length === 0) {
249263
return null;
@@ -255,13 +269,13 @@ function readLineBreaks(range: Range, lineDomNode: HTMLDivElement, lineContent:
255269

256270
type MaybeRects = ClientRectList | DOMRectList | null;
257271

258-
function discoverBreaks(range: Range, textContentNode: Node, charOffsets: number[], low: number, lowRects: MaybeRects, high: number, highRects: MaybeRects, result: number[]): void {
272+
function discoverBreaks(range: Range, spans: HTMLSpanElement[], charOffsets: number[], low: number, lowRects: MaybeRects, high: number, highRects: MaybeRects, result: number[]): void {
259273
if (low === high) {
260274
return;
261275
}
262276

263-
lowRects = lowRects || readClientRect(range, textContentNode, charOffsets[low], charOffsets[low + 1]);
264-
highRects = highRects || readClientRect(range, textContentNode, charOffsets[high], charOffsets[high + 1]);
277+
lowRects = lowRects || readClientRect(range, spans, charOffsets[low], charOffsets[low + 1]);
278+
highRects = highRects || readClientRect(range, spans, charOffsets[high], charOffsets[high + 1]);
265279

266280
if (Math.abs(lowRects[0].top - highRects[0].top) <= 0.1) {
267281
// same line
@@ -276,13 +290,13 @@ function discoverBreaks(range: Range, textContentNode: Node, charOffsets: number
276290
}
277291

278292
const mid = low + ((high - low) / 2) | 0;
279-
const midRects = readClientRect(range, textContentNode, charOffsets[mid], charOffsets[mid + 1]);
280-
discoverBreaks(range, textContentNode, charOffsets, low, lowRects, mid, midRects, result);
281-
discoverBreaks(range, textContentNode, charOffsets, mid, midRects, high, highRects, result);
293+
const midRects = readClientRect(range, spans, charOffsets[mid], charOffsets[mid + 1]);
294+
discoverBreaks(range, spans, charOffsets, low, lowRects, mid, midRects, result);
295+
discoverBreaks(range, spans, charOffsets, mid, midRects, high, highRects, result);
282296
}
283297

284-
function readClientRect(range: Range, textContentNode: Node, startOffset: number, endOffset: number): ClientRectList | DOMRectList {
285-
range.setStart(textContentNode, startOffset);
286-
range.setEnd(textContentNode, endOffset);
298+
function readClientRect(range: Range, spans: HTMLSpanElement[], startOffset: number, endOffset: number): ClientRectList | DOMRectList {
299+
range.setStart(spans[(startOffset / Constants.SPAN_MODULO_LIMIT) | 0].firstChild!, startOffset % Constants.SPAN_MODULO_LIMIT);
300+
range.setEnd(spans[(endOffset / Constants.SPAN_MODULO_LIMIT) | 0].firstChild!, endOffset % Constants.SPAN_MODULO_LIMIT);
287301
return range.getClientRects();
288302
}

0 commit comments

Comments
 (0)