Bug 121049 - [implementation] Revisit calls to StyledText.setRedraw(boolean)
Summary: [implementation] Revisit calls to StyledText.setRedraw(boolean)
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: Text (show other bugs)
Version: 3.2   Edit
Hardware: PC All
: P2 normal (vote)
Target Milestone: 3.3 M2   Edit
Assignee: Tom Hofmann CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on: 158746
Blocks:
  Show dependency tree
 
Reported: 2005-12-15 10:06 EST by Dani Megert CLA
Modified: 2006-09-26 10:56 EDT (History)
4 users (show)

See Also:


Attachments
NoMoreSetRedraw.diff (4.42 KB, patch)
2006-01-05 10:58 EST, Tom Hofmann CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dani Megert CLA 2005-12-15 10:06:18 EST
I20051214-2000

We should try to reduce the calls to StyledText.setRedraw(boolean). For example when revealing a selection, we could check up-front whether scrolling will happen or not.
Comment 1 Dani Megert CLA 2005-12-16 02:21:08 EST
*** Bug 121140 has been marked as a duplicate of this bug. ***
Comment 2 Tom Hofmann CLA 2006-01-05 05:09:00 EST
From bug 117507 comment 12:

One reason why we use setRedraw is to avoid the selection being cleared and
repainted when doing a multi-edit. This is true for operations that perform
multiple small edits and want to maintain a semantic (e.g. entire lines)
selection, e.g. for the following operations:

- shift left / right
- correct indent
- move lines

For example, when not using setRedraw on/off, the "Correct Indentation" command
becomes faster due to the performance impact of setRedraw, but it also starts
to flicker. This is due to two reasons:

- one can (almost) see every edit as the indent of each line is adjusted
- when changing the editor contents, the selection is cleared and only restored
after all edits have been performed.

So, in order to not use setRedraw in those cases, we would require some other way to bracket multiple operations and tell StyledText to hold off repainting until we're done restoring the selection.

-

Note that StyledText::handleTextChanged calls Control:update in order to give immediate user feedback (see also bug 117507 comment 15 for why this is done). This is usually a good thing, but hurts us here where we only want to repaint when we're done. 

An idea might be to introduce new API in StyledText that allows us to bracket text and selection updates:

StyledText::setEagerUpdate(boolean)

While "eager updating" is off, no update() calls would be issued in StyledText::handleTextChanged.

Felipe, does this make sense at all, or am I missing the point?
Comment 3 Tom Hofmann CLA 2006-01-05 10:14:03 EST
I quickly tested the idea outlined in comment 2 and it seems to work fine - "move lines" and "correct indentation" are noticeably smoother when only disabling the eager updating in StyledText, but not using StyledText::setRedraw and IDocumentAdapterExtension::start/stopForwardingDocumentChanges (which causes the entire text to be set when resuming). Both operations maintain a smooth selection without flickering due to the "disable eager updating" mechanism.

This is on I20051220-0800 plus ZRH inputs from 20060103.
Comment 4 Tom Hofmann CLA 2006-01-05 10:58:39 EST
Created attachment 32525 [details]
NoMoreSetRedraw.diff

This is just a quick and dirty hack to test it out. 
- The "eagerUpdate" property should probably be reference counted (like setRedraw).
- Places where setRedraw makes sense are now slower (e.g. unfolding everything in the editor). => we'd probably want to offer both versions of bracketing in IRewriteTargetExtensionX.
- I also disabled using IDocumentAdapterExtension as this really hurts us with big documents - this is only justified for very large updates, such as unfolding everything.
Comment 5 Tom Hofmann CLA 2006-01-05 11:08:25 EST
(In reply to comment #4)
> we'd probably want to offer both versions of bracketing in
> IRewriteTargetExtensionX.

To expand on that a little: I think we have two separate issues that we currently try to fix using TextViewer::setRedraw:

a) bracketing multiple edits / selection changes to avoid flickering as described in comment 2.
b) speeding up very large updates, such as expanding every folded region or formatting / shifting the entire document.

The current TextViewer::setRedraw implementation does quite well for b) (where the user expects a small delay), but hurts us in case a) where we want to bracket a couple of small updates.

The good thing is that we know which one to use. In some places we already differentiate based on how big a change is (for example, how many lines are shifted). Fixing this pr means to offer two different bracketing mechanisms to choose from, the current one for b) and one along the lines of the patch for a).
Comment 6 Steve Northover CLA 2006-01-05 12:52:43 EST
If you are successful, it should make things faster.  Despite the fact that you can't see it in some widgets, setRedraw(false) causes the entire widget to be redrawn because it can't tell where the damage is.  The redraw is hidden by SWT.DOUBLE_BUFFERED and SWT.NO_BACKGROUND.
Comment 7 Tom Hofmann CLA 2006-09-14 07:09:42 EDT
I have removed setRedraw calls in those places:

- DefaultUndoManager
- TextViewerUndoManger
- ProjectionViewer (for small updates only)
- ConvertLineDelimitersAction

The changes are tagged with te_{before,after}_removing_setRedraw.

--

One problem remains: the recommended way for clients to bracket multi-operations is to call IDocumentExtension4::start/stopRewriteSession. Clients can select between UNRESTRICTED, SEQUENTIAL and STRICTLY_SEQUENTIAL rewrite session types, which may be used by document implementations to optimize their updating strategies. However, those types do not contain any information about the expected size of an update.

TextViewer listens for document rewrite sessions and ensures the bracketing on the undo manager (begin/endCompoundChange) and also adds a pair of setRedraw calls around the rewrite session. This is often unneeded (for example when applying a simple text edit, see JavaModelUtil.applyEdit()), but may be absolutely crucial for the performance of very large updates (e.g. format all). 

I propose to add a fourth session type, UNRESTRICTED_SMALL, which can be used by clients that want to bracket a multi-edit but know that the size of the change is relatively small (e.g. up to 50 lines). TextViewer could then avoid calling setRedraw for small changes, while maintaining compatibility for the existing session types. Clients like JavaModelUtil can determine the size of a change by inspecting the edits.
Comment 8 Dani Megert CLA 2006-09-14 08:17:15 EDT
+1 to add UNRESTRICTED_SMALL
Comment 9 Tom Hofmann CLA 2006-09-14 12:00:43 EDT
fixed > 20060914
Comment 10 Dani Megert CLA 2006-09-26 10:56:59 EDT
Some of this had to be reverted, see bug 158746 for details.