From 26f777e1150977623d836b67db6ca975b599661c Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Fri, 11 Feb 2005 16:23:57 +0000 Subject: [PATCH] Don't flush out reflow while scrolling. Possible fix for crash bug 281173, r+sr=roc, a=caillon. git-svn-id: svn://10.0.0.236/trunk@169106 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/view/src/nsScrollPortView.cpp | 3 +- mozilla/view/src/nsViewManager.cpp | 99 +++++++++++++++------------ mozilla/view/src/nsViewManager.h | 7 +- 3 files changed, 61 insertions(+), 48 deletions(-) diff --git a/mozilla/view/src/nsScrollPortView.cpp b/mozilla/view/src/nsScrollPortView.cpp index 546935fee9f..5e430982457 100644 --- a/mozilla/view/src/nsScrollPortView.cpp +++ b/mozilla/view/src/nsScrollPortView.cpp @@ -500,6 +500,7 @@ void nsScrollPortView::Scroll(nsView *aScrolledView, nsPoint aTwipsDelta, nsPoin if (!scrollWidget) { + NS_ASSERTION(!canBitBlit, "Someone screwed up"); nsPoint offsetToWidget; GetNearestWidget(&offsetToWidget); // We're moving the child widgets because we are scrolling. But @@ -527,7 +528,7 @@ void nsScrollPortView::Scroll(nsView *aScrolledView, nsPoint aTwipsDelta, nsPoin // Scroll the contents of the widget by the specfied amount, and scroll // the child widgets scrollWidget->Scroll(aPixDelta.x, aPixDelta.y, nsnull); - mViewManager->UpdateViewAfterScroll(this, aTwipsDelta.x, aTwipsDelta.y); + mViewManager->UpdateViewAfterScroll(this); } } } diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index f45b4e5181b..e924806a578 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -1701,6 +1701,9 @@ nsViewManager::WillBitBlit(nsView* aView, nsPoint aScrollAmount) NS_PRECONDITION(aView, "Must have a view"); NS_PRECONDITION(aView->HasWidget(), "View must have a widget"); + NS_PRECONDITION(!mInScroll, "Nested scrolls?"); + mInScroll = PR_TRUE; + // Since the view is actually moving the widget by -aScrollAmount, that's the // offset we want to use when accumulating dirty rects. AccumulateIntersectionsIntoDirtyRegion(aView, GetRootView(), -aScrollAmount); @@ -1708,27 +1711,28 @@ nsViewManager::WillBitBlit(nsView* aView, nsPoint aScrollAmount) // Invalidate all widgets which overlap the view, other than the view's own widgets. void -nsViewManager::UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY) +nsViewManager::UpdateViewAfterScroll(nsView *aView) { - nsView* view = NS_STATIC_CAST(nsView*, aView); - + NS_ASSERTION(RootViewManager()->mInScroll, + "Someone forgot to call WillBitBlit()"); // Look at the view's clipped rect. It may be that part of the view is clipped out // in which case we don't need to worry about invalidating the clipped-out part. - nsRect damageRect = view->GetClippedRect(); + nsRect damageRect = aView->GetClippedRect(); if (damageRect.IsEmpty()) { return; } - damageRect.MoveBy(ComputeViewOffset(view)); + damageRect.MoveBy(ComputeViewOffset(aView)); // if this is a floating view, it isn't covered by any widgets other than // its children, which are handled by the widget scroller. - if (view->GetFloating()) { + if (aView->GetFloating()) { return; } - UpdateWidgetArea(RootViewManager()->GetRootView(), nsRegion(damageRect), view); + UpdateWidgetArea(RootViewManager()->GetRootView(), nsRegion(damageRect), aView); Composite(); + mInScroll = PR_FALSE; } /** @@ -1999,17 +2003,20 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS // Just notify our own view observer that we're about to paint // XXXbz do we need to notify other view observers for viewmanagers // in our tree? - nsIViewObserver* observer = GetViewObserver(); - if (observer) { - // Do an update view batch, and make sure we don't process those - // invalidates right now. Note that the observer may try to - // reenter this code from inside WillPaint() by trying to do a - // synchronous paint, but since refresh will be disabled it won't - // be able to do the paint. We should really sort out the rules - // on our synch painting api.... - BeginUpdateViewBatch(); - observer->WillPaint(); - EndUpdateViewBatch(NS_VMREFRESH_DEFERRED); + // Make sure to not send WillPaint notifications while scrolling + if (!mInScroll) { + nsIViewObserver* observer = GetViewObserver(); + if (observer) { + // Do an update view batch, and make sure we don't process + // those invalidates right now. Note that the observer may try + // to reenter this code from inside WillPaint() by trying to do + // a synchronous paint, but since refresh will be disabled it + // won't be able to do the paint. We should really sort out + // the rules on our synch painting api.... + BeginUpdateViewBatch(); + observer->WillPaint(); + EndUpdateViewBatch(NS_VMREFRESH_DEFERRED); + } } Refresh(view, event->renderingContext, region, NS_VMREFRESH_DOUBLE_BUFFER); @@ -4220,35 +4227,39 @@ nsViewManager::FlushPendingInvalidates() // we don't go through two invalidate-processing cycles). NS_ASSERTION(gViewManagers, "Better have a viewmanagers array!"); - // Disable refresh while we notify our view observers, so that if they do - // vie w update batches we don't reenter this code and so that we batch - // all of them together. We don't use - // BeginUpdateViewBatch/EndUpdateViewBatch, since that would reenter this - // exact code, but we want the effect of a single big update batch. - PRBool refreshEnabled = mRefreshEnabled; - mRefreshEnabled = PR_FALSE; - ++mUpdateBatchCnt; - - PRInt32 index; - for (index = 0; index < mVMCount; index++) { - nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index); - if (vm->RootViewManager() == this) { - // One of our kids - nsIViewObserver* observer = vm->GetViewObserver(); - if (observer) { - observer->WillPaint(); - NS_ASSERTION(mUpdateBatchCnt == 1, "Observer did not end view batch?"); + // Make sure to not send WillPaint notifications while scrolling + if (!mInScroll) { + // Disable refresh while we notify our view observers, so that if they do + // view update batches we don't reenter this code and so that we batch + // all of them together. We don't use + // BeginUpdateViewBatch/EndUpdateViewBatch, since that would reenter this + // exact code, but we want the effect of a single big update batch. + PRBool refreshEnabled = mRefreshEnabled; + mRefreshEnabled = PR_FALSE; + ++mUpdateBatchCnt; + + PRInt32 index; + for (index = 0; index < mVMCount; index++) { + nsViewManager* vm = (nsViewManager*)gViewManagers->ElementAt(index); + if (vm->RootViewManager() == this) { + // One of our kids + nsIViewObserver* observer = vm->GetViewObserver(); + if (observer) { + observer->WillPaint(); + NS_ASSERTION(mUpdateBatchCnt == 1, + "Observer did not end view batch?"); + } } } + + --mUpdateBatchCnt; + // Someone could have called EnableRefresh on us from inside WillPaint(). + // Only reset the old mRefreshEnabled value if the current value is false. + if (!mRefreshEnabled) { + mRefreshEnabled = refreshEnabled; + } } - - --mUpdateBatchCnt; - // Someone could have called EnableRefresh on us from inside WillPaint(). - // Only reset the old mRefreshEnabled value if the current value is false. - if (!mRefreshEnabled) { - mRefreshEnabled = refreshEnabled; - } - + if (mHasPendingUpdates) { ProcessPendingUpdates(mRootView); mHasPendingUpdates = PR_FALSE; diff --git a/mozilla/view/src/nsViewManager.h b/mozilla/view/src/nsViewManager.h index 9494189526f..b206dbc8f7a 100644 --- a/mozilla/view/src/nsViewManager.h +++ b/mozilla/view/src/nsViewManager.h @@ -462,10 +462,10 @@ public: // NOT in nsIViewManager, so private to the view module * Called to inform the view manager that a view has scrolled. * The view manager will invalidate any widgets which may need * to be rerendered. - * @param aView view to paint. should be root view - * @param aUpdateFlags see bottom of nsIViewManager.h for description + * @param aView view to paint. should be the nsScrollPortView that + * got scrolled. */ - void UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY); + void UpdateViewAfterScroll(nsView *aView); PRBool CanScrollWithBitBlt(nsView* aView); @@ -525,6 +525,7 @@ private: PRPackedBool mPainting; PRPackedBool mRecursiveRefreshPending; PRPackedBool mHasPendingUpdates; + PRPackedBool mInScroll; //from here to public should be static and locked... MMP static PRInt32 mVMCount; //number of viewmanagers