Closed
Bug 97895
Opened 23 years ago
Closed 23 years ago
Old page gets repainted when leaving a page (Back and Forward performance)
Categories
(Core :: Layout, defect, P1)
Core
Layout
Tracking
()
RESOLVED
FIXED
mozilla0.9.6
People
(Reporter: sfraser_bugs, Assigned: bryner)
References
Details
Attachments
(3 files, 2 obsolete files)
4.12 KB,
text/plain
|
Details | |
8.70 KB,
patch
|
Details | Diff | Splinter Review | |
1.95 KB,
patch
|
Details | Diff | Splinter Review |
One reason for our poor back/forward performance is probably that we redraw the entire old page when leaving it, when the user clicks on a link, or goes Forward or Back, or even Reloads. This is easy to show by editing a local page, and doing a Reload; the page is redrawn once with the old source, then again with the new source. It's obvious to see if double buffering is turned off.
Reporter | ||
Comment 1•23 years ago
|
||
Reporter | ||
Comment 2•23 years ago
|
||
The attachment shows the stack for a full-screen Invalidate that gets done before we leave the old page; the old page gets redrawn as a result of the invalidate here.
Reporter | ||
Comment 3•23 years ago
|
||
The reason for this Invalidate() is that we create a new nsWindow for the nsScrollPortView of the new page contents, then resize it, but this all happens while we're still showing the contents of the old page. Paint suppression ensures that the new pages gets redrawn later on. I also note here that PresShell::InitialReflow() gets the prefs service, and the value of the "nglayout.initialpaint.delay" pref every time. This should probably be cached.
Comment 4•23 years ago
|
||
Reassigning to dbaron, or if he objects, maybe waterson?
Assignee: karnaze → dbaron
Reporter | ||
Comment 5•23 years ago
|
||
What's bad here is that nsScrollBoxFrame (and nsScrollFrame) always creates its scrolling view as visible. This seems wrong. We also need to fix the Mac code to ignore invalidates on invisible windows.
Reporter | ||
Comment 6•23 years ago
|
||
It turns out that we can always make the view hidden in nsScrollBoxFrame::CreateScrollingView(), because nsContainerFrame::SyncFrameViewAfterReflow() later makes it visible, but only after the resize that is causing the bad invalidate. I wonder if nsScrollFrame should be treated the same way?
Summary: Old page gets redrawn when leaving a page (Back and Forward performance) → Old page gets repainted when leaving a page (Back and Forward performance)
Severity: normal → major
Status: NEW → ASSIGNED
Priority: -- → P1
Target Milestone: --- → mozilla0.9.6
I see the same problem on GTK and Windows. I wonder at what level we should be blocking this -- whether Invalidate should do a visibility check, or whether Resize should do it before calling Invalidate, or what? I guess it doesn't make much sense for Invalidate to be called on a window that isn't visible.
Comment 8•23 years ago
|
||
Check this web site... http://www.fileplanet.com/ redraws after redraws here onload and unload.
Assignee | ||
Comment 9•23 years ago
|
||
I can take this one.
Assignee: dbaron → bryner
Status: ASSIGNED → NEW
Just for reference, one thing bryner mentioned when we discussed this earlier was that it would probably be easier to fix this with changes to the view code than the widget code since they don't have to be done for each port.
Reporter | ||
Comment 11•23 years ago
|
||
I think the fix for this will require that one can hide or show entire view hierarchies, while maintaining the visibility of individual views. Views need some notion of 'latent visibility' or soemthing. Note that the Mac widget code still needs fixing to not invalidate when a widget is not visible.
Comment 12•23 years ago
|
||
Try implementing Validate(). I call Validate() when using paint suppression, but Validate() is only implemented on Win32.
Reporter | ||
Comment 13•23 years ago
|
||
It seems that Validate() is called _before_ the invalidates that cause the problem. The root of the problem still seems to be that even when painting is suppressed (which I assume to mean that the content viewer is not visible), view creation can cause invalidates on screen.
Assignee | ||
Comment 14•23 years ago
|
||
roc, do you have any thoughts on this?
We could add another layer of paint suppression in the view code, but I think this is unnecessarily complex. Instead of adding new APIs and fields and whatnot to the view code, isn't it simpler and more logical to just whack each widget implementation to ignore invalidates on hidden widgets? This would require no new interfaces and I really, really detest unnecessarily fat interfaces. Having said that, I don't understand why this is a problem on Windows or any other platform where we use native objects for widgets. Windows should already suppress invalidates on hidden HWNDs, I would have thought.
Reporter | ||
Comment 16•23 years ago
|
||
We're creating visible views in nsScrollBoxFrame (and nsScrollFrame) even when painting is suppressed (the pres shell is not shown). I assume that these views will create visible widgets, but is it the case that visibility of a child widget depends on its parent widget being visible? Or is the visibility of child widgets indpendent of that of the parent?
Assignee | ||
Comment 17•23 years ago
|
||
Yes, creating a visible view makes it so the widget is shown when CreateWidget is called. I've found that this is also happening in nsDocumentViewer::Init -- it creates a view as shown in MakeWindow, then calls CreateWidget, then hides the widget. On linux, this causes full-window invalidates on both the newly created widget and the widget for the current page. Making it create the view initially as hidden gives me a 2.3% speedup. So, in the case of the widget created by Scroll[Box]Frame, it is marked as shown but its parent is hidden. I think it's reasonable to assume that the child widget is implicitly hidden. We could certainly make Invalidate() ignore the call if this widget OR any of its ancestors are hidden, but do we really want to walk up the parent widget chain every time Invalidate is called?
I think it's unreasonable that calling Invalidate() on a widget that's hidden or has a hidden ancestor can cause some other widget(s) to be repainted. After all, we didn't ask for that widget to be repainted. Note that if other widgets are being repainted, then some piece of code must be walking up to a common ancestor and then back down again, just to translate the damage rectangle into the right coordinate system for the widgets that get painted. So it should be little additional burden to check for visibility on the way up.
Assignee | ||
Comment 19•23 years ago
|
||
Assignee | ||
Comment 20•23 years ago
|
||
This patch sets the root view's visibility instead of the widget's visibility for paint suppression. That lets us avoid two extra invalidates that were happening because of the view's widget being shown and then immediately hidden (one invalidate on the new view, one on the old view). I'm seeing about a 3% improvement in page load times with this on Linux.
Assignee | ||
Comment 21•23 years ago
|
||
Note that this patch doesn't yet address the original invalidate Simon found, these are separate.
Does setting the visibility of the view affect the visibility of its widget? And does the visibility of a view affect the visibility of its children? Does it affect how they handle UpdateView?
> Does setting the visibility of the view affect the visibility of its widget? No. > And does the visibility of a view affect the visibility of its children? No. Visible children of hidden views will be painted.
Assignee | ||
Comment 24•23 years ago
|
||
>> Does setting the visibility of the view affect the visibility of its widget? >No. roc, are you sure about that? See the following code from nsView::SetVisibility: if (nsnull != mWindow) { #ifndef HIDE_ALL_WIDGETS if (mVis == nsViewVisibility_kShow) mWindow->Show(PR_TRUE); else #endif mWindow->Show(PR_FALSE); }
Hmm, I stand corrected. Now I wonder how our support for visible frames inside hidden frames is working. Maybe it isn't.
Assignee | ||
Comment 26•23 years ago
|
||
roc, can you think of any problems that would arise from the patch I attached to hide the root view instead of its widget during paint suppression? If this will cause unintended side effects, we can change the CreateWidget method to let the caller specify whether the widget's visibility should be made the same as the view's, but I prefer this solution because it's cleaner (and it also allows UpdateView to do less work).
Assignee | ||
Comment 27•23 years ago
|
||
I'm not seeing any performance boost at all on win32 from this patch... probably because it implements the call to Validate(). We shouldn't really _need_ a Validate method... it looks like this was just working around the invalidates that were caused by showing and hiding the root view's widget. hyatt, if these invalidates can be avoided (as in my patch), can we remove Validate() entirely?
Assignee | ||
Updated•23 years ago
|
Attachment #55495 -
Attachment is obsolete: true
Assignee | ||
Comment 28•23 years ago
|
||
Comment on attachment 55495 [details] [diff] [review] Show and hide the view instead of the widget for paint suppression actually, this doesn't work quite right... it seems to break paint suppression entirely
Assignee | ||
Comment 29•23 years ago
|
||
The reason my previous patch breaks paint suppression is that nsContainerFrame::SyncFrameViewAfterReflow (called from PresShell::InitialReflow) determines that the view should be visible from the frame's style data, and sets it to be visible... in the current case, that ends up being a no-op because the view is already shown, even though its widget is hidden, so nsViewManager::SetViewVisibility returns early and nsView::SetVisibility is never called to sync the widget's visibility with the view's visibility. With my patch, the new visibility is not the same as the old visibility, so SetVisibility is called and the view is shown. So, using the view's visibility isn't going to work because reflows will happen before paint suppression is done. I'd suggest that instead, we let the caller to nsView::CreateWidget specify whether the widget's visibility should be set to the view's visibility. Since widgets start off hidden, that will prevent the invalidates. That still leaves Simon's invalidate stack and the issue of invalidates on widgets that are visible but have hidden ancestors. I'd argue that this checking should be done at the widget level, even though it means more work, because someone could invalidate a region of the widget without going through the view system at all. Does that make sense, or should we not be worrying about that case?
Assignee | ||
Comment 30•23 years ago
|
||
Assignee | ||
Comment 31•23 years ago
|
||
So, I'm actually reasonably sure that this patch fixes any painting that we might have been doing. I don't think the stack Simon attached is actually causing any paints, because it's on the newly created widget, so the presshell is suppressing painting. This also means that implementing Validate() on all of the platforms will work equally as well as my patch. Should we do that instead?
Assignee | ||
Comment 32•23 years ago
|
||
Comment on attachment 55525 [details] [diff] [review] patch to make nsView::CreateWidget not set the widget visibility ok, per conversation with hyatt, we're going to eliminate usage of Validate in nsDocumentViewer, but leave it as an API on nsIWidget... which I also now have an implementation for on gtk.
Attachment #55525 -
Attachment is obsolete: true
Assignee | ||
Comment 33•23 years ago
|
||
Assignee | ||
Comment 34•23 years ago
|
||
Reporter | ||
Comment 35•23 years ago
|
||
Comment on attachment 55682 [details] [diff] [review] first-cut patch from danm to impl Validate on mac This won't work for Carbon. You need InvalidateWindowRgn/Rect.
Attachment #55682 -
Flags: needs-work+
Comment 36•23 years ago
|
||
Comment on attachment 55680 [details] [diff] [review] patch v2 r/sr=blizzard
Comment 37•23 years ago
|
||
sr=hyatt (on 55680)
Assignee | ||
Comment 38•23 years ago
|
||
Checked in the patch... should I close this bug and file a separate bug on the extra painting that's happening on Mac?
Comment 39•23 years ago
|
||
The bryner-man. Bryner-roo. Buh-ryner-ino: http://tinderbox.mozilla.org/showbuilds.cgi?tree=SeaMonkey-Testerbox
Comment 40•23 years ago
|
||
Someone was not looking too close at the numbers, if lower is assumed to be better, in milliseconds, then the numbers there are better after this checkin, not worse. Someone was seeing the ghost of 1590'ish, when in fact the number is 1490'ish. The before number was hovering around 1520. so its a 70 millisecond increase in load time :) This is a great tool however for finding quickly and accurately who's at fault for what :)
Comment 41•23 years ago
|
||
Um, which of "The bryner-man. Bryner-roo. Buh-ryner-ino." led you to believe that I was complaining.
Comment 42•23 years ago
|
||
oh, sorry ;) people normally, at least to date, dont normally comment on tinderbox, comment on speed-ups :) my mistake.
Assignee | ||
Comment 43•23 years ago
|
||
Closing out this bug. I filed mac-specific bug 107827 for Invalidates on hidden widgets causing visible widgets to paint, and bug 107828 for implementing Validate on mac.
Status: NEW → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
You need to log in
before you can comment on or make changes to this bug.
Description
•