diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index f0b3fab94383..d33061ee79e6 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -141,8 +141,8 @@ typedef struct CapturingContentInfo { } CapturingContentInfo; #define NS_IPRESSHELL_IID \ -{ 0x4e23d557, 0x741a, 0x4fd0,\ - { 0x91, 0x52, 0x34, 0xe2, 0xb4, 0xef, 0xe8, 0x2e } } +{ 0x3ab5b116, 0x2d73, 0x431c, \ + { 0x9a, 0x4b, 0x6c, 0x91, 0x9e, 0x42, 0x45, 0xc3 } } // Constants for ScrollContentIntoView() function #define NS_PRESSHELL_SCROLL_TOP 0 @@ -1148,6 +1148,7 @@ public: virtual bool ShouldIgnoreInvalidation() = 0; virtual void WillPaint(bool aWillSendDidPaint) = 0; virtual void DidPaint() = 0; + virtual void ScheduleViewManagerFlush() = 0; virtual void ClearMouseCaptureOnView(nsIView* aView) = 0; virtual bool IsVisible() = 0; virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) = 0; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 29e8838fd8ff..d041beca6676 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1253,6 +1253,8 @@ PresShell::Destroy() // before we destroy the frame manager, since apparently frame destruction // sometimes spins the event queue when plug-ins are involved(!). rd->RemoveLayoutFlushObserver(this); + rd->RevokeViewManagerFlush(); + mResizeEvent.Revoke(); if (mAsyncResizeTimerIsActive) { mAsyncResizeEventTimer->Cancel(); @@ -3612,6 +3614,15 @@ nsresult PresShell::GetLinkLocation(nsIDOMNode* aNode, nsAString& aLocationStrin return NS_ERROR_FAILURE; } +void +PresShell::ScheduleViewManagerFlush() +{ + nsPresContext* presContext = GetPresContext(); + if (presContext) { + presContext->RefreshDriver()->ScheduleViewManagerFlush(); + } +} + void PresShell::DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange) diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index 21eb16a9f1c4..0f1e05be004a 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -330,6 +330,7 @@ public: virtual bool ShouldIgnoreInvalidation(); virtual void WillPaint(bool aWillSendDidPaint); virtual void DidPaint(); + virtual void ScheduleViewManagerFlush(); virtual void DispatchSynthMouseMove(nsGUIEvent *aEvent, bool aFlushOnHoverChange); virtual void ClearMouseCaptureOnView(nsIView* aView); virtual bool IsVisible(); diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index acda81fda551..258f7b79faff 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -55,6 +55,7 @@ #include "jsapi.h" #include "nsContentUtils.h" #include "mozilla/Preferences.h" +#include "nsIViewManager.h" using mozilla::TimeStamp; using mozilla::TimeDuration; @@ -112,6 +113,7 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext) mThrottled(false), mTestControllingRefreshes(false), mTimerIsPrecise(false), + mViewManagerFlushIsPending(false), mLastTimerInterval(0) { mRequests.Init(); @@ -270,6 +272,7 @@ nsRefreshDriver::ObserverCount() const sum += mStyleFlushObservers.Length(); sum += mLayoutFlushObservers.Length(); sum += mFrameRequestCallbackDocs.Length(); + sum += mViewManagerFlushIsPending; return sum; } @@ -431,6 +434,11 @@ nsRefreshDriver::Notify(nsITimer *aTimer) EnsureTimerStarted(false); } + if (mViewManagerFlushIsPending) { + mViewManagerFlushIsPending = false; + mPresContext->GetPresShell()->GetViewManager()->ProcessPendingUpdates(); + } + if (mThrottled || (mTimerIsPrecise != (GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) { diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index 8c0b01dec5db..1deb044969d5 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -176,6 +176,17 @@ public: return mLayoutFlushObservers.Contains(aShell); } + /** + * Remember whether our presshell's view manager needs a flush + */ + void ScheduleViewManagerFlush() { + mViewManagerFlushIsPending = true; + EnsureTimerStarted(false); + } + void RevokeViewManagerFlush() { + mViewManagerFlushIsPending = false; + } + /** * Add a document for which we have nsIFrameRequestCallbacks */ @@ -265,6 +276,7 @@ private: a precise timer. If mTimer is null, this boolean's value can be anything. */ bool mTimerIsPrecise; + bool mViewManagerFlushIsPending; // separate arrays for each flush type we support ObserverArray mObservers[3]; diff --git a/view/public/nsIViewManager.h b/view/public/nsIViewManager.h index 98101ef8754d..ac2f114fb1aa 100644 --- a/view/public/nsIViewManager.h +++ b/view/public/nsIViewManager.h @@ -348,6 +348,12 @@ public: * the nearest enclosing popup or the root view for the root document. */ static nsIView* GetDisplayRootFor(nsIView* aView); + + /** + * Flush the accumulated dirty region to the widget and update widget + * geometry. + */ + virtual void ProcessPendingUpdates()=0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIViewManager, NS_IVIEWMANAGER_IID) diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 2a23e0c625e0..6f19d187a851 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -398,7 +398,8 @@ void nsViewManager::RenderViews(nsView *aView, nsIWidget *aWidget, } } -void nsViewManager::ProcessPendingUpdates(nsView* aView, bool aDoInvalidate) +void nsViewManager::ProcessPendingUpdatesForView(nsView* aView, + bool aDoInvalidate) { NS_ASSERTION(IsRootVM(), "Updates will be missed"); @@ -414,7 +415,7 @@ void nsViewManager::ProcessPendingUpdates(nsView* aView, bool aDoInvalidate) // process pending updates in child view. for (nsView* childView = aView->GetFirstChild(); childView; childView = childView->GetNextSibling()) { - ProcessPendingUpdates(childView, aDoInvalidate); + ProcessPendingUpdatesForView(childView, aDoInvalidate); } if (aDoInvalidate) { @@ -828,7 +829,7 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, // Make sure to sync up any widget geometry changes we // have pending before we paint. if (rootVM->mHasPendingUpdates) { - rootVM->ProcessPendingUpdates(mRootView, false); + rootVM->ProcessPendingUpdatesForView(mRootView, false); } if (view && aEvent->message == NS_PAINT) { @@ -1424,6 +1425,12 @@ nsViewManager::IsPainting(bool& aIsPainting) return NS_OK; } +void +nsViewManager::ProcessPendingUpdates() +{ + // To be implemented. +} + void nsViewManager::FlushPendingInvalidates() { @@ -1431,7 +1438,7 @@ nsViewManager::FlushPendingInvalidates() NS_ASSERTION(mUpdateBatchCnt == 0, "Must not be in an update batch!"); if (mHasPendingUpdates) { - ProcessPendingUpdates(mRootView, true); + ProcessPendingUpdatesForView(mRootView, true); mHasPendingUpdates = false; } } diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index 90afdf83f3ac..b5f1ce68cd6e 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -144,13 +144,15 @@ public: /* Update the cached RootViewManager pointer on this view manager. */ void InvalidateHierarchy(); + virtual void ProcessPendingUpdates(); + protected: virtual ~nsViewManager(); private: void FlushPendingInvalidates(); - void ProcessPendingUpdates(nsView *aView, bool aDoInvalidate); + void ProcessPendingUpdatesForView(nsView *aView, bool aDoInvalidate); void FlushDirtyRegionToWidget(nsView* aView); /** * Call WillPaint() on all view observers under this vm root.