diff options
| -rw-r--r-- | cocoa/ScintillaCocoa.mm | 10 | ||||
| -rw-r--r-- | doc/ScintillaDoc.html | 21 | ||||
| -rw-r--r-- | doc/ScintillaHistory.html | 6 | ||||
| -rw-r--r-- | include/Scintilla.h | 6 | ||||
| -rw-r--r-- | include/Scintilla.iface | 12 | ||||
| -rw-r--r-- | src/Document.cxx | 28 | ||||
| -rw-r--r-- | src/Document.h | 2 | ||||
| -rw-r--r-- | src/Editor.cxx | 80 | ||||
| -rw-r--r-- | src/Editor.h | 6 | 
9 files changed, 161 insertions, 10 deletions
| diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm index 8b95aae0e..982ca0423 100644 --- a/cocoa/ScintillaCocoa.mm +++ b/cocoa/ScintillaCocoa.mm @@ -1801,13 +1801,15 @@ void ScintillaCocoa::WillDraw(NSRect rect)  {    RefreshStyleData();    PRectangle rcWillDraw = NSRectToPRectangle(rect); -  int positionAfterRect = PositionAfterArea(rcWillDraw); -  pdoc->EnsureStyledTo(positionAfterRect); +  const int posAfterArea = PositionAfterArea(rcWillDraw); +  const int posAfterMax = PositionAfterMaxStyling(posAfterArea, true); +  pdoc->StyleToAdjustingLineDuration(posAfterMax); +  StartIdleStyling(posAfterMax < posAfterArea);    NotifyUpdateUI();    if (WrapLines(wsVisible)) {      // Wrap may have reduced number of lines so more lines may need to be styled -    positionAfterRect = PositionAfterArea(rcWillDraw); -    pdoc->EnsureStyledTo(positionAfterRect); +    const int posAfterAreaWrapped = PositionAfterArea(rcWillDraw); +    pdoc->EnsureStyledTo(posAfterAreaWrapped);      // The wrapping process has changed the height of some lines so redraw all.      Redraw();    } diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index e77c064c3..34722f259 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -82,7 +82,7 @@      <h1>Scintilla Documentation</h1> -    <p>Last edited 31 July 2015 NH</p> +    <p>Last edited 11 November 2015 NH</p>      <p>There is <a class="jump" href="Design.html">an overview of the internal design of      Scintilla</a>.<br /> @@ -2391,6 +2391,8 @@ struct Sci_TextToFind {       <a class="message" href="#SCI_SETSTYLING">SCI_SETSTYLING(int length, int style)</a><br />       <a class="message" href="#SCI_SETSTYLINGEX">SCI_SETSTYLINGEX(int length, const char      *styles)</a><br /> +     <a class="message" href="#SCI_SETIDLESTYLING">SCI_SETIDLESTYLING(int idleStyling)</a><br /> +     <a class="message" href="#SCI_GETIDLESTYLING">SCI_GETIDLESTYLING</a><br />       <a class="message" href="#SCI_SETLINESTATE">SCI_SETLINESTATE(int line, int value)</a><br />       <a class="message" href="#SCI_GETLINESTATE">SCI_GETLINESTATE(int line)</a><br />       <a class="message" href="#SCI_GETMAXLINESTATE">SCI_GETMAXLINESTATE</a><br /> @@ -2426,6 +2428,23 @@ struct Sci_TextToFind {      <code>SCI_STARTSTYLING</code> should be called before the first call to this.      </p> +    <p><b id="SCI_SETIDLESTYLING">SCI_SETIDLESTYLING(int idleStyling)</b><br /> +     <b id="SCI_GETIDLESTYLING">SCI_GETIDLESTYLING</b><br /> +     By default, <code>SC_IDLESTYLING_NONE</code> (0), +     syntax styling is performed for all the currently visible text before displaying it. +     On very large files, this may make scrolling down slow. +     With <code>SC_IDLESTYLING_TOVISIBLE</code> (1), +     a small amount of styling is performed before display and then +     further styling is performed incrementally in the background as an idle-time task. +     This may result in the text initially appearing uncoloured and then, some time later, it is coloured. +     Text after the currently visible portion may be styled in the background with <code>SC_IDLESTYLING_AFTERVISIBLE</code> (2). +     To style both before and after the visible text in the background use <code>SC_IDLESTYLING_ALL</code> (3). +    </p> +    <p> +     Since wrapping also needs to perform styling and also uses idle time, this setting has no effect when +     the document is displayed wrapped. +    </p> +      <p><b id="SCI_SETLINESTATE">SCI_SETLINESTATE(int line, int value)</b><br />       <b id="SCI_GETLINESTATE">SCI_GETLINESTATE(int line)</b><br />       As well as the 8 bits of lexical state stored for each character there is also an integer diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 9aea9b6e3..0639d28fb 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -497,6 +497,12 @@  	Released 6 November 2015.  	</li>  	<li> +	Allow painting without first styling all visible text then styling in the background +	using idle-time. This helps performance when scrolling down in very large documents. +	Can also incrementally style after the visible area to the end of the document so that +	the document is already styled when the user scrolls to it. +	</li> +	<li>  	On GTK+ on OS X, fix warning during destruction.  	<a href="http://sourceforge.net/p/scintilla/bugs/1777/">Bug #1777</a>.  	</li> diff --git a/include/Scintilla.h b/include/Scintilla.h index e3443409b..c985cea77 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -506,6 +506,12 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,  #define SCI_WORDSTARTPOSITION 2266  #define SCI_WORDENDPOSITION 2267  #define SCI_ISRANGEWORD 2691 +#define SC_IDLESTYLING_NONE 0 +#define SC_IDLESTYLING_TOVISIBLE 1 +#define SC_IDLESTYLING_AFTERVISIBLE 2 +#define SC_IDLESTYLING_ALL 3 +#define SCI_SETIDLESTYLING 2692 +#define SCI_GETIDLESTYLING 2693  #define SC_WRAP_NONE 0  #define SC_WRAP_WORD 1  #define SC_WRAP_CHAR 2 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index ad50a2aaf..04fd767cd 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -1260,6 +1260,18 @@ fun int WordEndPosition=2267(position pos, bool onlyWordCharacters)  # Is the range start..end considered a word?  fun bool IsRangeWord=2691(position start, position end) +enu IdleStyling=SC_IDLESTYLING_ +val SC_IDLESTYLING_NONE=0 +val SC_IDLESTYLING_TOVISIBLE=1 +val SC_IDLESTYLING_AFTERVISIBLE=2 +val SC_IDLESTYLING_ALL=3 + +# Sets limits to idle styling. +set void SetIdleStyling=2692(int idleStyling,) + +# Retrieve the limits to idle styling. +get int GetIdleStyling=2693(,) +  enu Wrap=SC_WRAP_  val SC_WRAP_NONE=0  val SC_WRAP_WORD=1 diff --git a/src/Document.cxx b/src/Document.cxx index 9201e162f..65c63c138 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -109,6 +109,7 @@ Document::Document() {  	useTabs = true;  	tabIndents = true;  	backspaceUnindents = false; +	durationStyleOneLine = 0.00001;  	matchesValid = false;  	regex = 0; @@ -1892,6 +1893,33 @@ void Document::EnsureStyledTo(int pos) {  	}  } +void Document::StyleToAdjustingLineDuration(int pos) { +	// Place bounds on the duration used to avoid glitches spiking it +	// and so causing slow styling or non-responsive scrolling +	const double minDurationOneLine = 0.000001; +	const double maxDurationOneLine = 0.0001; + +	// Alpha value for exponential smoothing. +	// Most recent value contributes 25% to smoothed value. +	const double alpha = 0.25; + +	const Sci_Position lineFirst = LineFromPosition(GetEndStyled()); +	ElapsedTime etStyling; +	EnsureStyledTo(pos); +	const double durationStyling = etStyling.Duration(); +	const Sci_Position lineLast = LineFromPosition(GetEndStyled()); +	if (lineLast >= lineFirst + 8) { +		// Only adjust for styling multiple lines to avoid instability +		const double durationOneLine = durationStyling / (lineLast - lineFirst); +		durationStyleOneLine = alpha * durationOneLine + (1.0 - alpha) * durationStyleOneLine; +		if (durationStyleOneLine < minDurationOneLine) { +			durationStyleOneLine = minDurationOneLine; +		} else if (durationStyleOneLine > maxDurationOneLine) { +			durationStyleOneLine = maxDurationOneLine; +		} +	} +} +  void Document::LexerChanged() {  	// Tell the watchers the lexer has changed.  	for (std::vector<WatcherWithUserData>::iterator it = watchers.begin(); it != watchers.end(); ++it) { diff --git a/src/Document.h b/src/Document.h index ea8ddfbed..71a45879e 100644 --- a/src/Document.h +++ b/src/Document.h @@ -246,6 +246,7 @@ public:  	bool useTabs;  	bool tabIndents;  	bool backspaceUnindents; +	double durationStyleOneLine;  	DecorationList decorations; @@ -400,6 +401,7 @@ public:  	bool SCI_METHOD SetStyles(Sci_Position length, const char *styles);  	int GetEndStyled() const { return endStyled; }  	void EnsureStyledTo(int pos); +	void StyleToAdjustingLineDuration(int pos);  	void LexerChanged();  	int GetStyleClock() const { return styleClock; }  	void IncrementStyleClock(); diff --git a/src/Editor.cxx b/src/Editor.cxx index 6141b0628..a86f8c96e 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -173,6 +173,8 @@ Editor::Editor() {  	paintAbandonedByStyling = false;  	paintingAllText = false;  	willRedrawAll = false; +	idleStyling = SC_IDLESTYLING_NONE; +	needIdleStyling = false;  	modEventMask = SC_MODEVENTMASKALL; @@ -919,7 +921,7 @@ void Editor::ScrollTo(int line, bool moveThumb) {  		SetTopLine(topLineNew);  		// Optimize by styling the view as this will invalidate any needed area  		// which could abort the initial paint if discovered later. -		StyleToPositionInView(PositionAfterArea(GetClientRectangle())); +		StyleAreaBounded(GetClientRectangle(), true);  #ifndef UNDER_CE  		// Perform redraw rather than scroll if many lines would be redrawn anyway.  		if (performBlit) { @@ -1692,7 +1694,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  	paintAbandonedByStyling = false; -	StyleToPositionInView(PositionAfterArea(rcArea)); +	StyleAreaBounded(rcArea, false);  	PRectangle rcClient = GetClientRectangle();  	//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d)   %d\n", @@ -4893,6 +4895,8 @@ bool Editor::Idle() {  		// No more wrapping  		if (!wrapPending.NeedsWrap())  			wrappingDone = true; +	} else if (needIdleStyling) { +		IdleStyling();  	}  	// Add more idle things to do here, but make sure idleDone is @@ -4900,7 +4904,7 @@ bool Editor::Idle() {  	// false will stop calling this idle function until SetIdle() is  	// called again. -	idleDone = wrappingDone; // && thatDone && theOtherThingDone... +	idleDone = wrappingDone && !needIdleStyling; // && thatDone && theOtherThingDone...  	return !idleDone;  } @@ -5003,12 +5007,71 @@ void Editor::StyleToPositionInView(Position pos) {  	}  } +int Editor::PositionAfterMaxStyling(int posMax, bool scrolling) const { +	if ((idleStyling == SC_IDLESTYLING_NONE) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) { +		// Both states do not limit styling +		return posMax; +	} + +	// Try to keep time taken by styling reasonable so interaction remains smooth. +	// When scrolling, allow less time to ensure responsive +	const double secondsAllowed = scrolling ? 0.005 : 0.02; + +	const int linesToStyle = Platform::Clamp(static_cast<int>(secondsAllowed / pdoc->durationStyleOneLine), +		10, 0x10000); +	const int stylingMaxLine = std::min( +		static_cast<int>(pdoc->LineFromPosition(pdoc->GetEndStyled()) + linesToStyle), +		pdoc->LinesTotal()); +	return std::min(static_cast<int>(pdoc->LineStart(stylingMaxLine)), posMax); +} + +void Editor::StartIdleStyling(bool truncatedLastStyling) { +	if ((idleStyling == SC_IDLESTYLING_ALL) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) { +		if (pdoc->GetEndStyled() < pdoc->Length()) { +			// Style remainder of document in idle time +			needIdleStyling = true; +		} +	} else if (truncatedLastStyling) { +		needIdleStyling = true; +	} + +	if (needIdleStyling) { +		SetIdle(true); +	} +} + +// Style for an area but bound the amount of styling to remain responsive +void Editor::StyleAreaBounded(PRectangle rcArea, bool scrolling) { +	const int posAfterArea = PositionAfterArea(rcArea); +	const int posAfterMax = PositionAfterMaxStyling(posAfterArea, scrolling); +	if (posAfterMax < posAfterArea) { +		// Idle styling may be performed before current visible area +		// Style a bit now then style further in idle time +		pdoc->StyleToAdjustingLineDuration(posAfterMax); +	} else { +		// Can style all wanted now. +		StyleToPositionInView(posAfterArea); +	} +	StartIdleStyling(posAfterMax < posAfterArea); +} + +void Editor::IdleStyling() { +	const int posAfterArea = PositionAfterArea(GetClientRectangle()); +	const int endGoal = (idleStyling >= SC_IDLESTYLING_AFTERVISIBLE) ? +		pdoc->Length() : posAfterArea; +	const int posAfterMax = PositionAfterMaxStyling(endGoal, false); +	pdoc->StyleToAdjustingLineDuration(posAfterMax); +	if (pdoc->GetEndStyled() >= endGoal) { +		needIdleStyling = false; +	} +} +  void Editor::IdleWork() {  	// Style the line after the modification as this allows modifications that change just the  	// line of the modification to heal instead of propagating to the rest of the window. -	if (workNeeded.items & WorkNeeded::workStyle) +	if (workNeeded.items & WorkNeeded::workStyle) {  		StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2)); - +	}  	NotifyUpdateUI();  	workNeeded.Reset();  } @@ -6400,6 +6463,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  	case SCI_ISRANGEWORD:  		return pdoc->IsWordAt(static_cast<int>(wParam), static_cast<int>(lParam)); +	 +	case SCI_SETIDLESTYLING: +		idleStyling = static_cast<int>(wParam); +		break; + +	case SCI_GETIDLESTYLING: +		return idleStyling;  	case SCI_SETWRAPMODE:  		if (vs.SetWrapState(static_cast<int>(wParam))) { diff --git a/src/Editor.h b/src/Editor.h index 7b88cbab0..0d788b5a8 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -234,6 +234,8 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	bool paintingAllText;  	bool willRedrawAll;  	WorkNeeded workNeeded; +	int idleStyling; +	bool needIdleStyling;  	int modEventMask; @@ -525,6 +527,10 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	int PositionAfterArea(PRectangle rcArea) const;  	void StyleToPositionInView(Position pos); +	int PositionAfterMaxStyling(int posMax, bool scrolling) const; +	void StartIdleStyling(bool truncatedLastStyling); +	void StyleAreaBounded(PRectangle rcArea, bool scrolling); +	void IdleStyling();  	virtual void IdleWork();  	virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo=0); | 
