diff options
author | nyamatongwe <unknown> | 2013-06-18 14:55:30 +1000 |
---|---|---|
committer | nyamatongwe <unknown> | 2013-06-18 14:55:30 +1000 |
commit | 99cf2f1c4d3479f94b61b0879b922effe766d393 (patch) | |
tree | 7bd07a3fa77e0069005cb7acc14087289cfdc7e9 /src | |
parent | 71851f214226abf8bd20a5236bf6760dee4e5c11 (diff) | |
download | scintilla-mirror-99cf2f1c4d3479f94b61b0879b922effe766d393.tar.gz |
Simplify line wrapping code, minimize lines wrapped and avoid rewrapping lines.
Diffstat (limited to 'src')
-rw-r--r-- | src/Editor.cxx | 186 | ||||
-rw-r--r-- | src/Editor.h | 44 |
2 files changed, 116 insertions, 114 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx index f2e4c81b7..30f8120c0 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -212,8 +212,6 @@ Editor::Editor() { wrapState = eWrapNone; wrapWidth = LineLayout::wrapWidthInfinite; - wrapStart = wrapLineLarge; - wrapEnd = wrapLineLarge; wrapVisualFlags = 0; wrapVisualFlagsLocation = 0; wrapVisualStartIndent = 0; @@ -961,8 +959,8 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b int currentLine = pdoc->LineFromPosition(newPos.Position()); if (ensureVisible) { // In case in need of wrapping to ensure DisplayFromDoc works. - if (currentLine >= wrapStart) - WrapLines(true, -1); + if (currentLine >= wrapPending.start) + WrapLines(wsAll); XYScrollPosition newXY = XYScrollToMakeVisible( SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), xysDefault); if (simpleCaret && (newXY.xOffset == xOffset)) { @@ -1541,17 +1539,12 @@ void Editor::UpdateSystemCaret() { } void Editor::NeedWrapping(int docLineStart, int docLineEnd) { - docLineStart = Platform::Clamp(docLineStart, 0, pdoc->LinesTotal()); - if (wrapStart > docLineStart) { - wrapStart = docLineStart; +//Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd); + if (wrapPending.AddRange(docLineStart, docLineEnd)) { llc.Invalidate(LineLayout::llPositions); } - if (wrapEnd < docLineEnd) { - wrapEnd = docLineEnd; - } - wrapEnd = Platform::Clamp(wrapEnd, 0, pdoc->LinesTotal()); // Wrap lines during idle. - if ((wrapState != eWrapNone) && (wrapEnd != wrapStart)) { + if ((wrapState != eWrapNone) && wrapPending.NeedsWrap()) { SetIdle(true); } } @@ -1567,60 +1560,64 @@ bool Editor::WrapOneLine(Surface *surface, int lineToWrap) { (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); } -// Check if wrapping needed and perform any needed wrapping. -// fullwrap: if true, all lines which need wrapping will be done, -// in this single call. -// priorityWrapLineStart: If greater than or equal to zero, all lines starting from -// here to 1 page + 100 lines past will be wrapped (even if there are -// more lines under wrapping process in idle). -// If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be -// wrapped, if there are any wrapping going on in idle. (Generally this -// condition is called only from idler). +// Perform wrapping for a subset of the lines needing wrapping. +// wsAll: wrap all lines which need wrapping in this single call +// wsVisible: wrap currently visible lines +// wsIdle: wrap one page + 100 lines // Return true if wrapping occurred. -bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { - // If there are any pending wraps, do them during idle if possible. - int linesInOneCall = LinesOnScreen() + 100; - if (priorityWrapLineStart >= 0) { - // Using DocFromDisplay() here may result in chicken and egg problem in certain corner cases, - // which will hopefully be handled by added 100 lines. If some lines are still missed, idle wrapping will catch on. - int docLinesInOneCall = cs.DocFromDisplay(topLine + LinesOnScreen() + 100) - cs.DocFromDisplay(topLine); - linesInOneCall = Platform::Maximum(linesInOneCall, docLinesInOneCall); - } - if (wrapState != eWrapNone) { - if (wrapStart < wrapEnd) { - if (!SetIdle(true)) { - // Idle processing not supported so full wrap required. - fullWrap = true; - } - } - if (!fullWrap && priorityWrapLineStart >= 0 && - // .. and if the paint window is outside pending wraps - (((priorityWrapLineStart + linesInOneCall) < wrapStart) || - (priorityWrapLineStart > wrapEnd))) { - // No priority wrap pending - return false; - } - } +bool Editor::WrapLines(enum wrapScope ws) { int goodTopLine = topLine; bool wrapOccurred = false; - if (wrapStart <= pdoc->LinesTotal()) { - if (wrapState == eWrapNone) { - if (wrapWidth != LineLayout::wrapWidthInfinite) { - wrapWidth = LineLayout::wrapWidthInfinite; - for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { - cs.SetHeight(lineDoc, 1 + - (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); - } - wrapOccurred = true; + if (wrapState == eWrapNone) { + if (wrapWidth != LineLayout::wrapWidthInfinite) { + wrapWidth = LineLayout::wrapWidthInfinite; + for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { + cs.SetHeight(lineDoc, 1 + + (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); + } + wrapOccurred = true; + } + wrapPending.Reset(); + + } else if (wrapPending.NeedsWrap()) { + wrapPending.start = std::min(wrapPending.start, pdoc->LinesTotal()); + if (!SetIdle(true)) { + // Idle processing not supported so full wrap required. + ws = wsAll; + } + // Decide where to start wrapping + int lineToWrap = wrapPending.start; + int lineToWrapEnd = std::min(wrapPending.end, pdoc->LinesTotal()); + const int lineDocTop = cs.DocFromDisplay(topLine); + const int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop); + if (ws == wsVisible) { + lineToWrap = Platform::Clamp(lineDocTop-5, wrapPending.start, pdoc->LinesTotal()); + // Priority wrap to just after visible area. + // Since wrapping could reduce display lines, treat each + // as taking only one display line. + lineToWrapEnd = lineDocTop; + int lines = LinesOnScreen() + 1; + while ((lineToWrapEnd < cs.LinesInDoc()) && (lines>0)) { + if (cs.GetVisible(lineToWrapEnd)) + lines--; + lineToWrapEnd++; + } + // .. and if the paint window is outside pending wraps + if ((lineToWrap > wrapPending.end) || (lineToWrapEnd < wrapPending.start)) { + // Currently visible text does not need wrapping + return false; } - wrapStart = wrapLineLarge; - wrapEnd = wrapLineLarge; - } else { - if (wrapEnd >= pdoc->LinesTotal()) - wrapEnd = pdoc->LinesTotal(); - //ElapsedTime et; - int lineDocTop = cs.DocFromDisplay(topLine); - int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop); + } else if (ws == wsIdle) { + lineToWrapEnd = lineToWrap + LinesOnScreen() + 100; + } + const int lineEndNeedWrap = std::min(wrapPending.end, pdoc->LinesTotal()); + lineToWrapEnd = std::min(lineToWrapEnd, lineEndNeedWrap); + + // Ensure all lines being wrapped are styled. + pdoc->EnsureStyledTo(pdoc->LineStart(lineToWrapEnd)); + + if (lineToWrap < lineToWrapEnd) { + PRectangle rcTextArea = GetClientRectangle(); rcTextArea.left = vs.textStart; rcTextArea.right -= vs.rightMarginWidth; @@ -1628,56 +1625,32 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { RefreshStyleData(); AutoSurface surface(this); if (surface) { - bool priorityWrap = false; - int lastLineToWrap = wrapEnd; - int lineToWrap = wrapStart; - if (!fullWrap) { - if (priorityWrapLineStart >= 0) { - // This is a priority wrap. - lineToWrap = priorityWrapLineStart; - lastLineToWrap = priorityWrapLineStart + linesInOneCall; - priorityWrap = true; - } else { - // This is idle wrap. - lastLineToWrap = wrapStart + linesInOneCall; - } - if (lastLineToWrap >= wrapEnd) - lastLineToWrap = wrapEnd; - } // else do a fullWrap. - - // Ensure all lines being wrapped are styled. - pdoc->EnsureStyledTo(pdoc->LineEnd(lastLineToWrap)); +//Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd); - // Platform::DebugPrintf("Wraplines: full = %d, priorityStart = %d (wrapping: %d to %d)\n", fullWrap, priorityWrapLineStart, lineToWrap, lastLineToWrap); - // Platform::DebugPrintf("Pending wraps: %d to %d\n", wrapStart, wrapEnd); - while (lineToWrap < lastLineToWrap) { + while (lineToWrap < lineToWrapEnd) { if (WrapOneLine(surface, lineToWrap)) { wrapOccurred = true; } + wrapPending.Wrapped(lineToWrap); lineToWrap++; } - if (!priorityWrap) - wrapStart = lineToWrap; - // If wrapping is done, bring it to resting position - if (wrapStart >= wrapEnd) { - wrapStart = wrapLineLarge; - wrapEnd = wrapLineLarge; - } + + goodTopLine = cs.DisplayFromDoc(lineDocTop) + std::min(subLineTop, cs.GetHeight(lineDocTop)-1); } - goodTopLine = cs.DisplayFromDoc(lineDocTop); - if (subLineTop < cs.GetHeight(lineDocTop)) - goodTopLine += subLineTop; - else - goodTopLine += cs.GetHeight(lineDocTop); - //double durWrap = et.Duration(true); - //Platform::DebugPrintf("Wrap:%9.6g \n", durWrap); + } + + // If wrapping is done, bring it to resting position + if (wrapPending.start >= lineEndNeedWrap) { + wrapPending.Reset(); } } + if (wrapOccurred) { SetScrollBars(); SetTopLine(Platform::Clamp(goodTopLine, 0, MaxScrollPos())); SetVerticalScrollPos(); } + return wrapOccurred; } @@ -3565,13 +3538,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { RefreshPixMaps(surfaceWindow); } - // Call priority lines wrap on a window of lines which are likely - // to rendered with the following paint (that is wrap the visible - // lines first). - int startLineToWrap = cs.DocFromDisplay(topLine) - 5; - if (startLineToWrap < 0) - startLineToWrap = 0; - if (WrapLines(false, startLineToWrap)) { + // Wrap the visible lines if needed. + if (WrapLines(wsVisible)) { // The wrapping process has changed the height of some lines so // abandon this paint for a complete repaint. if (AbandonPaint()) { @@ -6750,9 +6718,9 @@ bool Editor::Idle() { if (!wrappingDone) { // Wrap lines during idle. - WrapLines(false, -1); + WrapLines(wsIdle); // No more wrapping - if (wrapStart == wrapEnd) + if (!wrapPending.NeedsWrap()) wrappingDone = true; } @@ -7056,8 +7024,8 @@ int Editor::ContractedFoldNext(int lineStart) const { void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { // In case in need of wrapping to ensure DisplayFromDoc works. - if (lineDoc >= wrapStart) - WrapLines(true, -1); + if (lineDoc >= wrapPending.start) + WrapLines(wsAll); if (!cs.GetVisible(lineDoc)) { // Back up to find a non-blank line diff --git a/src/Editor.h b/src/Editor.h index b47bd24c0..9105db468 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -125,6 +125,41 @@ private: } }; +struct WrapPending { + // The range of lines that need to be wrapped + enum { lineLarge = 0x7ffffff }; + int start; // When there are wraps pending, will be in document range + int end; // May be lineLarge to indicate all of document after start + WrapPending() { + start = lineLarge; + end = lineLarge; + } + void Reset() { + start = lineLarge; + end = lineLarge; + } + void Wrapped(int line) { + if (start == line) + start++; + } + bool NeedsWrap() const { + return start < end; + } + bool AddRange(int lineStart, int lineEnd) { + const bool neededWrap = NeedsWrap(); + bool changed = false; + if (start > lineStart) { + start = lineStart; + changed = true; + } + if ((end < lineEnd) || !neededWrap) { + end = lineEnd; + changed = true; + } + return changed; + } +}; + /** */ class Editor : public DocWatcher { @@ -273,10 +308,8 @@ protected: // ScintillaBase subclass needs access to much of Editor // Wrapping support enum { eWrapNone, eWrapWord, eWrapChar } wrapState; - enum { wrapLineLarge = 0x7ffffff }; int wrapWidth; - int wrapStart; - int wrapEnd; + WrapPending wrapPending; int wrapVisualFlags; int wrapVisualFlagsLocation; int wrapVisualStartIndent; @@ -390,9 +423,10 @@ protected: // ScintillaBase subclass needs access to much of Editor void InvalidateCaret(); virtual void UpdateSystemCaret(); - void NeedWrapping(int docLineStart = 0, int docLineEnd = wrapLineLarge); + void NeedWrapping(int docLineStart=0, int docLineEnd=WrapPending::lineLarge); bool WrapOneLine(Surface *surface, int lineToWrap); - bool WrapLines(bool fullWrap, int priorityWrapLineStart); + enum wrapScope {wsAll, wsVisible, wsIdle}; + bool WrapLines(enum wrapScope ws); void LinesJoin(); void LinesSplit(int pixelWidth); |