Defer invalidates using PL_event so they can be combined with reflow invalidates. This improves performances by reducing the number of paint messages and eliminates flicker bug 36849 sr=roc+moz@cs.cmu.edu r=rods@netscape.com
git-svn-id: svn://10.0.0.236/trunk@85207 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user