src/vs/editor/common/viewModel/modelLineProjection.ts/ModelLineProjection/getViewLinesData
class ModelLineProjection:	public getViewLinesData(model: ISimpleModel, modelLineNumber: number, outputLineIdx: number, lineCount: number, globalStartIndex: number, needed: boolean[], result: Array<ViewLineData | null>): void {
		this._assertVisible();

		const lineBreakData = this._projectionData;

		const injectionOffsets = lineBreakData.injectionOffsets;
		const injectionOptions = lineBreakData.injectionOptions;

		let inlineDecorationsPerOutputLine: SingleLineInlineDecoration[][] | null = null;

		if (injectionOffsets) {
			inlineDecorationsPerOutputLine = [];
			let totalInjectedTextLengthBefore = 0;
			let currentInjectedOffset = 0;

			for (let outputLineIndex = 0; outputLineIndex < lineBreakData.getOutputLineCount(); outputLineIndex++) {
				const inlineDecorations = new Array<SingleLineInlineDecoration>();
				inlineDecorationsPerOutputLine[outputLineIndex] = inlineDecorations;

				const lineStartOffsetInInputWithInjections = outputLineIndex > 0 ? lineBreakData.breakOffsets[outputLineIndex - 1] : 0;
				const lineEndOffsetInInputWithInjections = lineBreakData.breakOffsets[outputLineIndex];

				while (currentInjectedOffset < injectionOffsets.length) {
					const length = injectionOptions![currentInjectedOffset].content.length;
					const injectedTextStartOffsetInInputWithInjections = injectionOffsets[currentInjectedOffset] + totalInjectedTextLengthBefore;
					const injectedTextEndOffsetInInputWithInjections = injectedTextStartOffsetInInputWithInjections + length;

					if (injectedTextStartOffsetInInputWithInjections > lineEndOffsetInInputWithInjections) {
						// Injected text only starts in later wrapped lines.
						break;
					}

					if (lineStartOffsetInInputWithInjections < injectedTextEndOffsetInInputWithInjections) {
						// Injected text ends after or in this line (but also starts in or before this line).
						const options = injectionOptions![currentInjectedOffset];
						if (options.inlineClassName) {
							const offset = (outputLineIndex > 0 ? lineBreakData.wrappedTextIndentLength : 0);
							const start = offset + Math.max(injectedTextStartOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, 0);
							const end = offset + Math.min(injectedTextEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections);
							if (start !== end) {
								inlineDecorations.push(new SingleLineInlineDecoration(start, end, options.inlineClassName, options.inlineClassNameAffectsLetterSpacing!));
							}
						}
					}

					if (injectedTextEndOffsetInInputWithInjections <= lineEndOffsetInInputWithInjections) {
						totalInjectedTextLengthBefore += length;
						currentInjectedOffset++;
					} else {
						// injected text breaks into next line, process it again
						break;
					}
				}
			}
		}

		let lineWithInjections: LineTokens;
		if (injectionOffsets) {
			lineWithInjections = model.tokenization.getLineTokens(modelLineNumber).withInserted(injectionOffsets.map((offset, idx) => ({
				offset,
				text: injectionOptions![idx].content,
				tokenMetadata: LineTokens.defaultTokenMetadata
			})));
		} else {
			lineWithInjections = model.tokenization.getLineTokens(modelLineNumber);
		}

		for (let outputLineIndex = outputLineIdx; outputLineIndex < outputLineIdx + lineCount; outputLineIndex++) {
			const globalIndex = globalStartIndex + outputLineIndex - outputLineIdx;
			if (!needed[globalIndex]) {
				result[globalIndex] = null;
				continue;
			}
			result[globalIndex] = this._getViewLineData(lineWithInjections, inlineDecorationsPerOutputLine ? inlineDecorationsPerOutputLine[outputLineIndex] : null, outputLineIndex);
		}
	}