void PerformVisualElementConstruction(VisualLineElementGenerator[] generators)
{
TextDocument document = TextLayer.Document;
int offset = DocumentLine.Offset;
int currentLineEnd = offset + DocumentLine.Length;
int askInterestOffset = 0; // 0 or 1
while (offset + askInterestOffset <= currentLineEnd) {
int textLineEndOffset = currentLineEnd;
foreach (VisualLineElementGenerator g in generators) {
g.cachedInterest = g.GetFirstInterestedOffset(offset + askInterestOffset);
if (g.cachedInterest != -1) {
if (g.cachedInterest < offset)
throw new ArgumentOutOfRangeException(g.GetType().Name + ".GetFirstInterestedOffset",
g.cachedInterest,
"GetFirstInterestedOffset must not return an offset less than startOffset. Return -1 to signal no interest.");
if (g.cachedInterest < textLineEndOffset)
textLineEndOffset = g.cachedInterest;
}
}
Debug.Assert(textLineEndOffset >= offset);
if (textLineEndOffset > offset) {
int textElementLength = textLineEndOffset - offset;
var element = new VisualLineElement(this, offset, textElementLength);
elements.Add(element);
offset = textLineEndOffset;
}
// If no elements constructed / only zero-length elements constructed:
// do not asking the generators again for the same location (would cause endless loop)
askInterestOffset = 1;
foreach (VisualLineElementGenerator g in generators) {
if (g.cachedInterest == offset) {
VisualLineElement element = g.ConstructElement(offset);
if (element != null) {
elements.Add(element);
if (element.Text.Length > 0) {
// a non-zero-length element was constructed
askInterestOffset = 0;
offset += element.Text.Length;
if (offset > currentLineEnd) {
DocumentLine newEndLine = document.GetLineByOffset(offset);
currentLineEnd = newEndLine.Offset + newEndLine.Length;
if (currentLineEnd < offset) {
throw new InvalidOperationException(
"The VisualLineElementGenerator " + g.GetType().Name +
" produced an element which ends within the line delimiter");
}
}
break;
}
}
}
}
}
}