aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authornyamatongwe <unknown>2013-06-18 14:55:30 +1000
committernyamatongwe <unknown>2013-06-18 14:55:30 +1000
commit99cf2f1c4d3479f94b61b0879b922effe766d393 (patch)
tree7bd07a3fa77e0069005cb7acc14087289cfdc7e9 /src
parent71851f214226abf8bd20a5236bf6760dee4e5c11 (diff)
downloadscintilla-mirror-99cf2f1c4d3479f94b61b0879b922effe766d393.tar.gz
Simplify line wrapping code, minimize lines wrapped and avoid rewrapping lines.
Diffstat (limited to 'src')
-rw-r--r--src/Editor.cxx186
-rw-r--r--src/Editor.h44
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);