From b62ec44d371f10a2b540d403ecfb9a63589beae2 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 11 Dec 2010 21:01:17 +0100 Subject: [PATCH] Fixed performance issue when scrolling down for the first time in a long document. The Highlighter is calling OnHighlightStateChanged() once for each line in the document when the highlighting is initialized for the first time. For each of those calls, we were calling Redraw() to invalidate the following line. Now we avoid these unnecessary Redraw() calls by ignoring all OnHighlightStateChanged() calls for all 'scanned' lines (all lines other than the one currently being colorized). --- .../Highlighting/DocumentHighlighter.cs | 1 + .../Highlighting/HighlightingColorizer.cs | 27 +++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/DocumentHighlighter.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/DocumentHighlighter.cs index 759eada8eb..f863f6cb7d 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/DocumentHighlighter.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/DocumentHighlighter.cs @@ -114,6 +114,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// /// The line to highlight. /// A line object that represents the highlighted sections. + [ObsoleteAttribute("Use the (int lineNumber) overload instead")] public HighlightedLine HighlightLine(DocumentLine line) { if (!document.Lines.Contains(line)) diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs index 2c74cd10c2..ecebe980a4 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Highlighting/HighlightingColorizer.cs @@ -68,7 +68,7 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// protected virtual IHighlighter CreateHighlighter(TextView textView, TextDocument document) { - return new TextViewDocumentHighlighter(textView, document, ruleSet); + return new TextViewDocumentHighlighter(this, textView, document, ruleSet); } /// @@ -98,7 +98,9 @@ namespace ICSharpCode.AvalonEdit.Highlighting // This is necessary in case the document gets modified above the FirstLineInView so that the highlighting state changes. // We need to detect this case and issue a redraw (through TextViewDocumentHighligher.OnHighlightStateChanged) // before the visual line construction reuses existing lines that were built using the invalid highlighting state. - highlighter.GetSpanStack(e.FirstLineInView.LineNumber - 1); + lineNumberBeingColorized = e.FirstLineInView.LineNumber - 1; + highlighter.GetSpanStack(lineNumberBeingColorized); + lineNumberBeingColorized = 0; } } @@ -116,18 +118,24 @@ namespace ICSharpCode.AvalonEdit.Highlighting // (e.g. when the line ends with a fold marker). // But even if we didn't highlight it, we'll have to update the highlighting state for it so that the // proof inside TextViewDocumentHighlighter.OnHighlightStateChanged holds. - highlighter.GetSpanStack(context.VisualLine.LastDocumentLine.LineNumber); + lineNumberBeingColorized = context.VisualLine.LastDocumentLine.LineNumber; + highlighter.GetSpanStack(lineNumberBeingColorized); + lineNumberBeingColorized = 0; } } this.lastColorizedLine = null; } + int lineNumberBeingColorized; + /// protected override void ColorizeLine(DocumentLine line) { IHighlighter highlighter = CurrentContext.TextView.Services.GetService(typeof(IHighlighter)) as IHighlighter; if (highlighter != null) { - HighlightedLine hl = highlighter.HighlightLine(line.LineNumber); + lineNumberBeingColorized = line.LineNumber; + HighlightedLine hl = highlighter.HighlightLine(lineNumberBeingColorized); + lineNumberBeingColorized = 0; foreach (HighlightedSection section in hl.Sections) { ChangeLinePart(section.Offset, section.Offset + section.Length, visualLineElement => ApplyColorToElement(visualLineElement, section.Color)); @@ -167,18 +175,27 @@ namespace ICSharpCode.AvalonEdit.Highlighting /// sealed class TextViewDocumentHighlighter : DocumentHighlighter { + readonly HighlightingColorizer colorizer; readonly TextView textView; - public TextViewDocumentHighlighter(TextView textView, TextDocument document, HighlightingRuleSet baseRuleSet) + public TextViewDocumentHighlighter(HighlightingColorizer colorizer, TextView textView, TextDocument document, HighlightingRuleSet baseRuleSet) : base(document, baseRuleSet) { + Debug.Assert(colorizer != null); Debug.Assert(textView != null); + this.colorizer = colorizer; this.textView = textView; } protected override void OnHighlightStateChanged(DocumentLine line, int lineNumber) { base.OnHighlightStateChanged(line, lineNumber); + if (colorizer.lineNumberBeingColorized != lineNumber) { + // Ignore notifications for any line except the one we're interested in. + // This improves the performance as Redraw() can take quite some time when called repeatedly + // while scanning the document (above the visible area) for highlighting changes. + return; + } if (textView.Document != this.Document) { // May happen if document on text view was changed but some user code is still using the // existing IHighlighter instance.