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:
kmcclusk%netscape.com
2001-01-20 04:59:39 +00:00
parent 741bf6ee31
commit 90c90d4972
9 changed files with 353 additions and 34 deletions

View File

@@ -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)
{