diff --git a/mozilla/content/events/src/nsEventStateManager.cpp b/mozilla/content/events/src/nsEventStateManager.cpp index 9e68ba99056..599c88ac983 100644 --- a/mozilla/content/events/src/nsEventStateManager.cpp +++ b/mozilla/content/events/src/nsEventStateManager.cpp @@ -267,6 +267,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, mCurrentTarget->SetFrameState(state); *aStatus = nsEventStatus_eIgnore; + NS_ASSERTION(aEvent, "aEvent is null. this should never happen"); if (!aEvent) return NS_ERROR_NULL_POINTER; @@ -300,6 +301,9 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, GenerateDragGesture(aPresContext, (nsGUIEvent*)aEvent); UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus); GenerateMouseEnterExit(aPresContext, (nsGUIEvent*)aEvent); + // Flush reflows and invalidates to eliminate flicker when both a reflow + // and visual change occur in an event callback. See bug #36849 + FlushPendingEvents(aPresContext); break; case NS_MOUSE_EXIT: GenerateMouseEnterExit(aPresContext, (nsGUIEvent*)aEvent); @@ -748,9 +752,7 @@ nsEventStateManager :: GenerateDragGesture ( nsIPresContext* aPresContext, nsGUI } // Now flush all pending notifications. - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - shell->FlushPendingNotifications(); + FlushPendingEvents(aPresContext); } // GenerateDragGesture nsresult @@ -1839,9 +1841,7 @@ nsEventStateManager::GenerateDragDropEnterExit(nsIPresContext* aPresContext, nsG mCurrentTargetContent = targetBeforeEvent; // Now flush all pending notifications. - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - shell->FlushPendingNotifications(); + FlushPendingEvents(aPresContext); } NS_IMETHODIMP @@ -3069,6 +3069,20 @@ void nsEventStateManager::EnsureDocument(nsIPresShell* aPresShell) { aPresShell->GetDocument(&mDocument); } +void nsEventStateManager::FlushPendingEvents(nsIPresContext* aPresContext) { + NS_PRECONDITION(nsnull != aPresContext, "nsnull ptr"); + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (nsnull != shell) { + shell->FlushPendingNotifications(); + nsCOMPtr viewManager; + nsresult result = shell->GetViewManager(getter_AddRefs(viewManager)); + if (nsnull != viewManager) { + viewManager->FlushPendingInvalidates(); + } + } +} + nsresult NS_NewEventStateManager(nsIEventStateManager** aInstancePtrResult) { nsresult rv; diff --git a/mozilla/content/events/src/nsEventStateManager.h b/mozilla/content/events/src/nsEventStateManager.h index 7f0765a3af6..5803861cb8b 100644 --- a/mozilla/content/events/src/nsEventStateManager.h +++ b/mozilla/content/events/src/nsEventStateManager.h @@ -116,6 +116,7 @@ protected: PRBool CheckDisabled(nsIContent* aContent); void EnsureDocument(nsIPresShell* aPresShell); void EnsureDocument(nsIPresContext* aPresContext); + void FlushPendingEvents(nsIPresContext* aPresContext); // These functions are for mousewheel scrolling nsIScrollableView* GetNearestScrollingView(nsIView* aView); diff --git a/mozilla/layout/events/src/nsEventStateManager.cpp b/mozilla/layout/events/src/nsEventStateManager.cpp index 9e68ba99056..599c88ac983 100644 --- a/mozilla/layout/events/src/nsEventStateManager.cpp +++ b/mozilla/layout/events/src/nsEventStateManager.cpp @@ -267,6 +267,7 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, mCurrentTarget->SetFrameState(state); *aStatus = nsEventStatus_eIgnore; + NS_ASSERTION(aEvent, "aEvent is null. this should never happen"); if (!aEvent) return NS_ERROR_NULL_POINTER; @@ -300,6 +301,9 @@ nsEventStateManager::PreHandleEvent(nsIPresContext* aPresContext, GenerateDragGesture(aPresContext, (nsGUIEvent*)aEvent); UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus); GenerateMouseEnterExit(aPresContext, (nsGUIEvent*)aEvent); + // Flush reflows and invalidates to eliminate flicker when both a reflow + // and visual change occur in an event callback. See bug #36849 + FlushPendingEvents(aPresContext); break; case NS_MOUSE_EXIT: GenerateMouseEnterExit(aPresContext, (nsGUIEvent*)aEvent); @@ -748,9 +752,7 @@ nsEventStateManager :: GenerateDragGesture ( nsIPresContext* aPresContext, nsGUI } // Now flush all pending notifications. - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - shell->FlushPendingNotifications(); + FlushPendingEvents(aPresContext); } // GenerateDragGesture nsresult @@ -1839,9 +1841,7 @@ nsEventStateManager::GenerateDragDropEnterExit(nsIPresContext* aPresContext, nsG mCurrentTargetContent = targetBeforeEvent; // Now flush all pending notifications. - nsCOMPtr shell; - aPresContext->GetShell(getter_AddRefs(shell)); - shell->FlushPendingNotifications(); + FlushPendingEvents(aPresContext); } NS_IMETHODIMP @@ -3069,6 +3069,20 @@ void nsEventStateManager::EnsureDocument(nsIPresShell* aPresShell) { aPresShell->GetDocument(&mDocument); } +void nsEventStateManager::FlushPendingEvents(nsIPresContext* aPresContext) { + NS_PRECONDITION(nsnull != aPresContext, "nsnull ptr"); + nsCOMPtr shell; + aPresContext->GetShell(getter_AddRefs(shell)); + if (nsnull != shell) { + shell->FlushPendingNotifications(); + nsCOMPtr viewManager; + nsresult result = shell->GetViewManager(getter_AddRefs(viewManager)); + if (nsnull != viewManager) { + viewManager->FlushPendingInvalidates(); + } + } +} + nsresult NS_NewEventStateManager(nsIEventStateManager** aInstancePtrResult) { nsresult rv; diff --git a/mozilla/layout/events/src/nsEventStateManager.h b/mozilla/layout/events/src/nsEventStateManager.h index 7f0765a3af6..5803861cb8b 100644 --- a/mozilla/layout/events/src/nsEventStateManager.h +++ b/mozilla/layout/events/src/nsEventStateManager.h @@ -116,6 +116,7 @@ protected: PRBool CheckDisabled(nsIContent* aContent); void EnsureDocument(nsIPresShell* aPresShell); void EnsureDocument(nsIPresContext* aPresContext); + void FlushPendingEvents(nsIPresContext* aPresContext); // These functions are for mousewheel scrolling nsIScrollableView* GetNearestScrollingView(nsIView* aView); diff --git a/mozilla/view/public/nsIViewManager.h b/mozilla/view/public/nsIViewManager.h index 1c7271be456..dbdf1e6dc10 100644 --- a/mozilla/view/public/nsIViewManager.h +++ b/mozilla/view/public/nsIViewManager.h @@ -509,13 +509,21 @@ public: NS_IMETHOD AllowDoubleBuffering(PRBool aDoubleBuffer)=0; /** - * Indicate whehter the viewmanager is currently painting + * Indicate whether the viewmanager is currently painting * * @param aPainting PR_TRUE if the viewmanager is painting * PR_FALSE otherwise */ NS_IMETHOD IsPainting(PRBool& aIsPainting)=0; + + /** + * Flush pending invalidates which have been queued up + * between DisableRefresh and EnableRefresh calls. + */ + NS_IMETHOD FlushPendingInvalidates()=0; + + }; //when the refresh happens, should it be double buffered? diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index 47ee1df5e45..049bb78aadf 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -34,10 +34,14 @@ #include "nsISupportsArray.h" #include "nsICompositeListener.h" #include "nsCOMPtr.h" +#include "nsIEventQueue.h" +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID); static NS_DEFINE_IID(kRegionCID, NS_REGION_CID); static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); #define UPDATE_QUANTUM 1000 / 40 @@ -103,13 +107,84 @@ static void DestroyZTreeNode(DisplayZTreeNode* aNode) { } } -inline nscoord max(nscoord x, nscoord y) { return (x > y ? x : y); } -inline nscoord min(nscoord x, nscoord y) { return (x < y ? x : y); } #ifdef NS_VM_PERF_METRICS #include "nsITimeRecorder.h" #endif +//-------------- Begin Invalidate Event Definition ------------------------ + +struct nsInvalidateEvent : public PLEvent { + nsInvalidateEvent(nsIViewManager* aViewManager); + ~nsInvalidateEvent() { } + + void HandleEvent() { + NS_ASSERTION(nsnull != mViewManager,"ViewManager is null"); + // Search for valid view manager before trying to access it + // This is just a safety check. We should never have a circumstance + // where the view manager has been destroyed and the invalidate event + // which it owns is still around. The invalidate event should be destroyed + // by the RevokeEvent in the viewmanager's destructor. + PRBool found = PR_FALSE; + PRInt32 index; + PRInt32 count = nsViewManager::GetViewManagerCount(); + const nsVoidArray* viewManagers = nsViewManager::GetViewManagerArray(); + for (index = 0; index < count; index++) { + nsIViewManager* vm = (nsIViewManager*)viewManagers->ElementAt(index); + if (vm == mViewManager) { + found = PR_TRUE; + } + } + + if (found) { + ((nsViewManager *)mViewManager)->ProcessInvalidateEvent(); + } else { + NS_ASSERTION(PR_FALSE, "bad view manager asked to process invalidate event"); + } + + }; + + nsIViewManager* mViewManager; // Weak Reference. The viewmanager will destroy any pending + // invalidate events in it's destructor. +}; + +static void PR_CALLBACK HandlePLEvent(nsInvalidateEvent* aEvent) +{ + NS_ASSERTION(nsnull != aEvent,"Event is null"); + aEvent->HandleEvent(); +} + +static void PR_CALLBACK DestroyPLEvent(nsInvalidateEvent* aEvent) +{ + NS_ASSERTION(nsnull != aEvent,"Event is null"); + delete aEvent; +} + +nsInvalidateEvent::nsInvalidateEvent(nsIViewManager* aViewManager) +{ + NS_ASSERTION(aViewManager, "null parameter"); + mViewManager = aViewManager; // Assign weak reference + PL_InitEvent(this, aViewManager, + (PLHandleEventProc) ::HandlePLEvent, + (PLDestroyEventProc) ::DestroyPLEvent); +} + +//-------------- End Invalidate Event Definition --------------------------- + + +void +nsViewManager::PostInvalidateEvent() +{ + if (!mPendingInvalidateEvent) { + nsInvalidateEvent* ev = new nsInvalidateEvent(NS_STATIC_CAST(nsIViewManager*, this)); + NS_ASSERTION(nsnull != ev,"InvalidateEvent is null"); + NS_ASSERTION(nsnull != mEventQueue,"Event queue is null"); + mEventQueue->PostEvent(ev); + mPendingInvalidateEvent = PR_TRUE; + } +} + + #ifdef NS_VIEWMANAGER_NEEDS_TIMER static void vm_timer_callback(nsITimer *aTimer, void *aClosure) @@ -392,6 +467,8 @@ nsViewManager::nsViewManager() mY = 0; mCachingWidgetChanges = 0; mAllowDoubleBuffering = PR_TRUE; + mHasPendingInvalidates = PR_FALSE; + mPendingInvalidateEvent = PR_FALSE; } nsViewManager::~nsViewManager() @@ -402,6 +479,13 @@ nsViewManager::~nsViewManager() } #endif + // Revoke pending invalidate events + if (mPendingInvalidateEvent) { + NS_ASSERTION(nsnull != mEventQueue,"Event queue is null"); + mPendingInvalidateEvent = PR_FALSE; + mEventQueue->RevokeEvents(this); + } + NS_IF_RELEASE(mRootWindow); mRootScrollable = nsnull; @@ -554,6 +638,16 @@ NS_IMETHODIMP nsViewManager::Init(nsIDeviceContext* aContext, nscoord aX, nscoor mX = aX; mY = aY; + + if (nsnull == mEventQueue) { + // Cache the event queue of the current UI thread + NS_WITH_SERVICE(nsIEventQueueService, eventService, kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv) && (nsnull != eventService)) { // XXX this implies that the UI is the current thread. + rv = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue)); + } + + NS_ASSERTION(nsnull != mEventQueue, "event queue is null"); + } return rv; } @@ -1535,6 +1629,7 @@ void nsViewManager::ProcessPendingUpdates(nsIView* aView) ProcessPendingUpdates(childView); childView->GetNextSibling(childView); } + } NS_IMETHODIMP nsViewManager::Composite() @@ -1637,6 +1732,7 @@ PRBool nsViewManager::UpdateAllCoveringWidgets(nsIView *aView, nsIView *aTarget, if (!mRefreshEnabled) { // accumulate this rectangle in the view's dirty region, so we can process it later. AddRectToDirtyRegion(aView, bounds); + mHasPendingInvalidates = PR_TRUE; } else { float t2p; mContext->GetAppUnitsToDevUnits(t2p); @@ -2450,8 +2546,8 @@ void nsViewManager::GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const { nsRect widgetBounds; rootWidget->GetBounds(widgetBounds); - aMaxWidgetBounds.width = max(aMaxWidgetBounds.width, widgetBounds.width); - aMaxWidgetBounds.height = max(aMaxWidgetBounds.height, widgetBounds.height); + aMaxWidgetBounds.width = PR_MAX(aMaxWidgetBounds.width, widgetBounds.width); + aMaxWidgetBounds.height = PR_MAX(aMaxWidgetBounds.height, widgetBounds.height); } } @@ -2552,6 +2648,16 @@ void nsViewManager::GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aNewSi aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); } +PRInt32 nsViewManager::GetViewManagerCount() +{ + return mVMCount; +} + +const nsVoidArray* nsViewManager::GetViewManagerArray() +{ + return gViewManagers; +} + nsDrawingSurface nsViewManager::GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds) { @@ -2727,8 +2833,12 @@ NS_IMETHODIMP nsViewManager::EnableRefresh(PRUint32 aUpdateFlags) mRefreshEnabled = PR_TRUE; - if (mUpdateCnt > 0) - ProcessPendingUpdates(mRootView); + if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { + ProcessPendingUpdates(mRootView); + mHasPendingInvalidates = PR_FALSE; + } else { + PostInvalidateEvent(); + } if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { @@ -3644,6 +3754,23 @@ nsViewManager::IsPainting(PRBool& aIsPainting) return NS_OK; } +NS_IMETHODIMP +nsViewManager::FlushPendingInvalidates() +{ + if (mHasPendingInvalidates) { + ProcessPendingUpdates(mRootView); + mHasPendingInvalidates = PR_FALSE; + } + return NS_OK; +} + +nsresult +nsViewManager::ProcessInvalidateEvent() { + FlushPendingInvalidates(); + mPendingInvalidateEvent = PR_FALSE; + return NS_OK; +} + nsresult nsViewManager::ProcessWidgetChanges(nsIView* aView) { diff --git a/mozilla/view/src/nsViewManager.h b/mozilla/view/src/nsViewManager.h index 24c11c227ea..6026a4b3cb6 100644 --- a/mozilla/view/src/nsViewManager.h +++ b/mozilla/view/src/nsViewManager.h @@ -35,6 +35,7 @@ #include "nsIScrollableView.h" #include "nsIRegion.h" #include "nsIBlender.h" +#include "nsIEventQueue.h" class nsISupportsArray; struct DisplayListElement2; @@ -161,8 +162,13 @@ public: NS_IMETHOD CacheWidgetChanges(PRBool aCache); NS_IMETHOD AllowDoubleBuffering(PRBool aDoubleBuffer); NS_IMETHOD IsPainting(PRBool& aIsPainting); + NS_IMETHOD FlushPendingInvalidates(); + nsresult ProcessInvalidateEvent(); + static PRInt32 GetViewManagerCount(); + static const nsVoidArray* GetViewManagerArray(); protected: virtual ~nsViewManager(); + void ProcessPendingUpdates(nsIView *aView); private: nsIRenderingContext *CreateRenderingContext(nsIView &aView); @@ -171,7 +177,7 @@ private: PRBool UpdateAllCoveringWidgets(nsIView *aView, nsIView *aTarget, nsRect &aDamagedRect); - void ProcessPendingUpdates(nsIView *aView); + void UpdateViews(nsIView *aView, PRUint32 aUpdateFlags); void Refresh(nsIView *aView, nsIRenderingContext *aContext, @@ -374,6 +380,10 @@ protected: nscoord mX; nscoord mY; PRBool mAllowDoubleBuffering; + PRBool mHasPendingInvalidates; + PRBool mPendingInvalidateEvent; + nsCOMPtr mEventQueue; + void PostInvalidateEvent(); #ifdef NS_VM_PERF_METRICS MOZ_TIMER_DECLARE(mWatch) // Measures compositing+paint time for current document diff --git a/mozilla/view/src/nsViewManager2.cpp b/mozilla/view/src/nsViewManager2.cpp index 83d4817d130..05a3baad242 100755 --- a/mozilla/view/src/nsViewManager2.cpp +++ b/mozilla/view/src/nsViewManager2.cpp @@ -33,10 +33,14 @@ #include "nsISupportsArray.h" #include "nsICompositeListener.h" #include "nsCOMPtr.h" +#include "nsIEventQueue.h" +#include "nsIEventQueueService.h" +#include "nsIServiceManager.h" static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID); static NS_DEFINE_IID(kRegionCID, NS_REGION_CID); static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); +static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); #define UPDATE_QUANTUM 1000 / 40 @@ -59,6 +63,7 @@ static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID); // so that we won't crash. #define SUPPORT_TRANSLUCENT_VIEWS + // display list elements struct DisplayListElement2 { nsIView* mView; @@ -68,13 +73,84 @@ struct DisplayListElement2 { PRUint32 mFlags; }; -inline nscoord max(nscoord x, nscoord y) { return (x > y ? x : y); } -inline nscoord min(nscoord x, nscoord y) { return (x < y ? x : y); } #ifdef NS_VM_PERF_METRICS #include "nsITimeRecorder.h" #endif +//-------------- Begin Invalidate Event Definition ------------------------ + +struct nsInvalidateEvent2 : public PLEvent { + nsInvalidateEvent2(nsIViewManager* aViewManager); + ~nsInvalidateEvent2() { } + + void HandleEvent() { + NS_ASSERTION(nsnull != mViewManager,"ViewManager is null"); + // Search for valid view manager before trying to access it + // This is just a safety check. We should never have a circumstance + // where the view manager has been destroyed and the invalidate event + // which it owns is still around. The invalidate event should be destroyed + // by the RevokeEvent in the viewmanager's destructor. + PRBool found = PR_FALSE; + PRInt32 index; + PRInt32 count = nsViewManager2::GetViewManagerCount(); + const nsVoidArray* viewManagers = nsViewManager2::GetViewManagerArray(); + for (index = 0; index < count; index++) { + nsIViewManager* vm = (nsIViewManager*)viewManagers->ElementAt(index); + if (vm == mViewManager) { + found = PR_TRUE; + } + } + + if (found) { + ((nsViewManager2 *)mViewManager)->ProcessInvalidateEvent(); + } else { + NS_ASSERTION(PR_FALSE, "bad view manager asked to process invalidate event"); + } + }; + + nsIViewManager* mViewManager; // Weak Reference. The viewmanager will destroy any pending + // invalidate events in it's destructor. +}; + + +static void PR_CALLBACK HandlePLEvent(nsInvalidateEvent2* aEvent) +{ + NS_ASSERTION(nsnull != aEvent,"Event is null"); + aEvent->HandleEvent(); +} + +static void PR_CALLBACK DestroyPLEvent(nsInvalidateEvent2* aEvent) +{ + NS_ASSERTION(nsnull != aEvent,"Event is null"); + delete aEvent; +} + + +nsInvalidateEvent2::nsInvalidateEvent2(nsIViewManager* aViewManager) +{ + NS_ASSERTION(aViewManager, "null parameter"); + mViewManager = aViewManager; // Assign weak reference + PL_InitEvent(this, aViewManager, + (PLHandleEventProc) ::HandlePLEvent, + (PLDestroyEventProc) ::DestroyPLEvent); +} + +//-------------- End Invalidate Event Definition --------------------------- + + +void +nsViewManager2::PostInvalidateEvent() +{ + if (!mPendingInvalidateEvent) { + nsInvalidateEvent2* ev = new nsInvalidateEvent2(NS_STATIC_CAST(nsIViewManager*, this)); + NS_ASSERTION(nsnull != ev,"InvalidateEvent is null"); + NS_ASSERTION(nsnull != mEventQueue,"Event queue is null"); + mEventQueue->PostEvent(ev); + mPendingInvalidateEvent = PR_TRUE; + } +} + #ifdef NS_VIEWMANAGER_NEEDS_TIMER static void vm_timer_callback(nsITimer *aTimer, void *aClosure) @@ -157,6 +233,8 @@ nsViewManager2::nsViewManager2() mY = 0; mCachingWidgetChanges = 0; mAllowDoubleBuffering = PR_TRUE; + mHasPendingInvalidates = PR_FALSE; + mPendingInvalidateEvent = PR_FALSE; } nsViewManager2::~nsViewManager2() @@ -167,6 +245,13 @@ nsViewManager2::~nsViewManager2() } #endif + // Revoke pending invalidate events + if (mPendingInvalidateEvent) { + NS_ASSERTION(nsnull != mEventQueue,"Event queue is null"); + mPendingInvalidateEvent = PR_FALSE; + mEventQueue->RevokeEvents(this); + } + NS_IF_RELEASE(mRootWindow); mRootScrollable = nsnull; @@ -256,8 +341,10 @@ nsViewManager2::~nsViewManager2() mCompositeListeners->Clear(); NS_RELEASE(mCompositeListeners); } + } + NS_IMPL_QUERY_INTERFACE(nsViewManager2, knsViewManagerIID) NS_IMPL_ADDREF(nsViewManager2); @@ -341,7 +428,16 @@ NS_IMETHODIMP nsViewManager2::Init(nsIDeviceContext* aContext, nscoord aX, nscoo mX = aX; mY = aY; - + + if (nsnull == mEventQueue) { + // Cache the event queue of the current UI thread + NS_WITH_SERVICE(nsIEventQueueService, eventService, kEventQueueServiceCID, &rv); + if (NS_SUCCEEDED(rv) && (nsnull != eventService)) { // XXX this implies that the UI is the current thread. + rv = eventService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(mEventQueue)); + } + + NS_ASSERTION(nsnull != mEventQueue, "event queue is null"); + } return rv; } @@ -1117,6 +1213,7 @@ void nsViewManager2::ProcessPendingUpdates(nsIView* aView) ProcessPendingUpdates(childView); childView->GetNextSibling(childView); } + } NS_IMETHODIMP nsViewManager2::Composite() @@ -1182,6 +1279,7 @@ NS_IMETHODIMP nsViewManager2::UpdateView(nsIView *aView, const nsRect &aRect, PR if (!mRefreshEnabled) { // accumulate this rectangle in the view's dirty region, so we can process it later. AddRectToDirtyRegion(aView, damagedRect); + mHasPendingInvalidates = PR_TRUE; ++mUpdateCnt; return NS_OK; } @@ -1926,8 +2024,8 @@ void nsViewManager2::GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const { nsRect widgetBounds; rootWidget->GetBounds(widgetBounds); - aMaxWidgetBounds.width = max(aMaxWidgetBounds.width, widgetBounds.width); - aMaxWidgetBounds.height = max(aMaxWidgetBounds.height, widgetBounds.height); + aMaxWidgetBounds.width = PR_MAX(aMaxWidgetBounds.width, widgetBounds.width); + aMaxWidgetBounds.height = PR_MAX(aMaxWidgetBounds.height, widgetBounds.height); } } @@ -2028,6 +2126,16 @@ void nsViewManager2::GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aNewS aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); } +PRInt32 nsViewManager2::GetViewManagerCount() +{ + return mVMCount; +} + +const nsVoidArray* nsViewManager2::GetViewManagerArray() +{ + return gViewManagers; +} + nsDrawingSurface nsViewManager2::GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds) { @@ -2203,8 +2311,14 @@ NS_IMETHODIMP nsViewManager2::EnableRefresh(PRUint32 aUpdateFlags) mRefreshEnabled = PR_TRUE; - if (mUpdateCnt > 0) - ProcessPendingUpdates(mRootView); + if (mUpdateCnt > 0) { + if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { + ProcessPendingUpdates(mRootView); + mHasPendingInvalidates = PR_FALSE; + } else { + PostInvalidateEvent(); + } + } if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { @@ -2569,8 +2683,8 @@ PRBool nsViewManager2::AddToDisplayList(PRInt32 *aIndex, nsIView *aView, nsRect mTranslucentSize.height = aDirtyRect.height; } else { mTranslucentArea.UnionRect(mTranslucentArea, aDirtyRect); - mTranslucentSize.width = max(mTranslucentSize.width, aDirtyRect.width); - mTranslucentSize.height = max(mTranslucentSize.height, aDirtyRect.height); + mTranslucentSize.width = PR_MAX(mTranslucentSize.width, aDirtyRect.width); + mTranslucentSize.height = PR_MAX(mTranslucentSize.height, aDirtyRect.height); } } @@ -2898,6 +3012,24 @@ nsViewManager2::AllowDoubleBuffering(PRBool aDoubleBuffer) return NS_OK; } +NS_IMETHODIMP +nsViewManager2::FlushPendingInvalidates() +{ + if (mHasPendingInvalidates) { + ProcessPendingUpdates(mRootView); + mHasPendingInvalidates = PR_FALSE; + } + return NS_OK; +} + +nsresult +nsViewManager2::ProcessInvalidateEvent() { + FlushPendingInvalidates(); + mPendingInvalidateEvent = PR_FALSE; + return NS_OK; +} + + NS_IMETHODIMP nsViewManager2::IsPainting(PRBool& aIsPainting) { diff --git a/mozilla/view/src/nsViewManager2.h b/mozilla/view/src/nsViewManager2.h index 78a6cab7ae8..69372fdf67a 100755 --- a/mozilla/view/src/nsViewManager2.h +++ b/mozilla/view/src/nsViewManager2.h @@ -34,6 +34,7 @@ #include "nsIScrollableView.h" #include "nsIRegion.h" #include "nsIBlender.h" +#include "nsIEventQueue.h" class nsISupportsArray; struct DisplayListElement2; @@ -159,16 +160,21 @@ public: NS_IMETHOD CacheWidgetChanges(PRBool aCache); NS_IMETHOD AllowDoubleBuffering(PRBool aDoubleBuffer); NS_IMETHOD IsPainting(PRBool& aIsPainting); + NS_IMETHOD FlushPendingInvalidates(); + nsresult ProcessInvalidateEvent(); + static PRInt32 GetViewManagerCount(); + static const nsVoidArray* GetViewManagerArray(); protected: virtual ~nsViewManager2(); - + void ProcessPendingUpdates(nsIView *aView); + private: nsIRenderingContext *CreateRenderingContext(nsIView &aView); + void AddRectToDirtyRegion(nsIView* aView, const nsRect &aRect) const; void InvalidateChildWidgets(nsIView *aView, nsRect& aDirtyRect) const; void UpdateTransCnt(nsIView *oldview, nsIView *newview); - void ProcessPendingUpdates(nsIView *aView); void UpdateViews(nsIView *aView, PRUint32 aUpdateFlags); void Refresh(nsIView *aView, nsIRenderingContext *aContext, @@ -299,6 +305,8 @@ private: */ void GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aSurfaceSize) const; + + private: nsIDeviceContext *mContext; float mTwipsToPixels; @@ -324,6 +332,8 @@ private: //from here to public should be static and locked... MMP static PRInt32 mVMCount; //number of viewmanagers + //list of view managers + static nsVoidArray *gViewManagers; static nsDrawingSurface mDrawingSurface; //single drawing surface static nsRect mDSBounds; //for all VMs @@ -340,9 +350,7 @@ private: // Largest requested offscreen size if larger than a full screen. static nsSize gLargestRequestedSize; - //list of view managers - static nsVoidArray *gViewManagers; - + //compositor regions nsIRegion *mTransRgn; nsIRegion *mOpaqueRgn; @@ -372,6 +380,10 @@ protected: nscoord mX; nscoord mY; PRBool mAllowDoubleBuffering; + PRBool mHasPendingInvalidates; + PRBool mPendingInvalidateEvent; + nsCOMPtr mEventQueue; + void PostInvalidateEvent(); #ifdef NS_VM_PERF_METRICS MOZ_TIMER_DECLARE(mWatch) // Measures compositing+paint time for current document