From 16af532b270d9f6e2d56912a9567a7ec78f5d9d0 Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Wed, 23 Aug 2000 14:58:22 +0000 Subject: [PATCH] NOT PART OF BUILD. Checking in nsViewManager2 semi-rewrite as nsViewManager. Bug 39621. r=kmcclusk,a=waterson --- view/src/nsViewManager.cpp | 4901 ++++++++++++++++++++---------------- view/src/nsViewManager.h | 143 +- 2 files changed, 2854 insertions(+), 2190 deletions(-) diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 2e66e6243ad0..2f018e5bf1d4 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: true; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file @@ -17,7 +17,9 @@ * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Contributor(s): Patrick C. Beard + * Kevin McCluskey + * Robert O'Callahan */ #include "nsViewManager.h" @@ -37,55 +39,95 @@ 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); -//#define GS_DEBUG - #define UPDATE_QUANTUM 1000 / 40 +/** + A note about platform assumptions: + + We assume all native widgets are opaque. + + We assume that a widget is z-ordered on top of its parent. + + We do NOT assume anything about the relative z-ordering of sibling widgets. + In particular, nsIWidget->SetZIndex is basically ignored. + Setting the widget z-index "correctly" (so that plugins etc have the correct + z-order) and then exploiting that z-order to better optimize invalidation + and refresh is a hard problem and remains future work. (Not that this has + been broken --- this has NEVER worked.) +*/ + //#define NO_DOUBLE_BUFFER -#define NEW_COMPOSITOR -#define USE_DISPLAY_LIST_ELEMENTS -//used for debugging new compositor -//#define SHOW_RECTS -//#define SHOW_DISPLAYLIST +// if defined widget changes like moves and resizes are defered until and done +// all in one pass. +//#define CACHE_WIDGET_CHANGES -//display list flags -#define RENDER_VIEW 0x0000 -#define VIEW_INCLUDED 0x0001 -#define PUSH_CLIP 0x0002 -#define POP_CLIP 0x0004 +// display list flags +#define VIEW_RENDERED 0x00000001 +#define PUSH_CLIP 0x00000002 +#define POP_CLIP 0x00000004 +#define VIEW_TRANSPARENT 0x00000008 +#define VIEW_TRANSLUCENT 0x00000010 +#define VIEW_CLIPPED 0x00000020 -#define DISPLAYLIST_INC 1 +// compositor per-view flags +#define IS_PARENT_OF_REFRESHED_VIEW 0x00000001 +#define IS_Z_PLACEHOLDER_VIEW 0x80000000 -//display list elements -struct DisplayListElement { - nsIView* mView; - nsRect mClip; - PRUint32 mFlags; +#define SUPPORT_TRANSLUCENT_VIEWS + +// display list elements +struct DisplayListElement2 { + nsIView* mView; // coordinates relative to the repainting view + nsRect mBounds; + nscoord mAbsX, mAbsY; + PRUint32 mFlags; + PRInt32 mZIndex; }; +struct DisplayZTreeNode { + nsIView* mView; // May be null + DisplayZTreeNode* mZSibling; + + // We can't have BOTH an mZChild and an mDisplayElement + DisplayZTreeNode* mZChild; + DisplayListElement2* mDisplayElement; +}; + +static void DestroyZTreeNode(DisplayZTreeNode* aNode) { + if (nsnull != aNode) { + DestroyZTreeNode(aNode->mZChild); + DestroyZTreeNode(aNode->mZSibling); + delete aNode->mDisplayElement; + delete 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 - #ifdef NS_VIEWMANAGER_NEEDS_TIMER static void vm_timer_callback(nsITimer *aTimer, void *aClosure) { - nsViewManager *vm = (nsViewManager *)aClosure; - printf("ViewManager timer callback\n"); + nsViewManager *vm = (nsViewManager *)aClosure; - //restart the timer + printf("ViewManager2 timer callback\n"); + + //restart the timer - if (vm->mTrueFrameRate == vm->mFrameRate) - { - PRUint32 fr = vm->mFrameRate; + if (vm->mTrueFrameRate == vm->mFrameRate) + { + PRUint32 fr = vm->mFrameRate; - vm->mFrameRate = 0; - vm->SetFrameRate(fr); - } -//printf("timer composite...\n"); + vm->mFrameRate = 0; + vm->SetFrameRate(fr); + } + //printf("timer composite...\n"); #ifndef XP_MAC //XXX temporary: The Mac doesn't need the timer to repaint but // obviously this is not the good method to disable the thing. @@ -93,7 +135,7 @@ static void vm_timer_callback(nsITimer *aTimer, void *aClosure) // (set UPDATE_QUANTUM to 0, or simply not create the timer) // don't work for now. We'll fix that and then disable the // Mac timers as we should. - vm->Composite(); + vm->Composite(); #endif } #endif @@ -107,145 +149,338 @@ static void blinkRect(nsIRenderingContext* context, const nsRect& r) } #endif +class nsZPlaceholderView : public nsIView +{ +public: + nsZPlaceholderView(nsIView* aParent) { mParent = aParent; } + + NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW + + // nsISupports + NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr) + { if (nsnull == aInstancePtr) { + return NS_ERROR_NULL_POINTER; + } + + *aInstancePtr = nsnull; + + if (aIID.Equals(NS_GET_IID(nsIView)) || (aIID.Equals(NS_GET_IID(nsISupports)))) { + *aInstancePtr = (void*)(nsIView*)this; + return NS_OK; + } + + return NS_NOINTERFACE; + } + + // nsIView + NS_IMETHOD Init(nsIViewManager* aManager, + const nsRect &aBounds, + const nsIView *aParent, + nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow) + { return NS_OK; } + + NS_IMETHOD Destroy() + { delete this; return NS_OK; } + NS_IMETHOD GetViewManager(nsIViewManager *&aViewMgr) const + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD Paint(nsIRenderingContext& rc, const nsRect& rect, + PRUint32 aPaintFlags, PRBool &aResult) + { aResult = PR_TRUE; return NS_OK; } + NS_IMETHOD Paint(nsIRenderingContext& rc, const nsIRegion& region, + PRUint32 aPaintFlags, PRBool &aResult) + { aResult = PR_TRUE; return NS_OK; } + NS_IMETHOD HandleEvent(nsGUIEvent *event, PRUint32 aEventFlags, nsEventStatus* aStatus, PRBool aForceHandle, PRBool& aHandled) + { aHandled = PR_FALSE; return NS_OK; } + NS_IMETHOD SetPosition(nscoord x, nscoord y) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetPosition(nscoord *x, nscoord *y) const + { *x = 0; *y = 0; return NS_OK; } + NS_IMETHOD SetDimensions(nscoord width, nscoord height, PRBool aPaint = PR_TRUE) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetDimensions(nscoord *width, nscoord *height) const + { *width = 0; *height = 0; return NS_OK; } + NS_IMETHOD SetBounds(const nsRect &aBounds, PRBool aPaint = PR_TRUE) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD SetBounds(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aPaint = PR_TRUE) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetBounds(nsRect &aBounds) const + { aBounds.SetRect(0, 0, 0, 0); return NS_OK; } + NS_IMETHOD SetChildClip(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetChildClip(nscoord *aLeft, nscoord *aTop, nscoord *aRight, nscoord *aBottom) const + { *aLeft = 0; *aTop = 0; *aRight = 0; *aBottom = 0; return NS_OK; } + NS_IMETHOD SetVisibility(nsViewVisibility visibility) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetVisibility(nsViewVisibility &aVisibility) const + { aVisibility = nsViewVisibility_kHide; return NS_OK; } + NS_IMETHOD SetZParent(nsIView *aZParent) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetZParent(nsIView *&aZParent) const + { aZParent = nsnull; return NS_OK; } + NS_IMETHOD SetZIndex(PRInt32 aZIndex) + { mZindex = aZIndex; return NS_OK; } + NS_IMETHOD GetZIndex(PRInt32 &aZIndex) const + { aZIndex = mZindex; return NS_OK; } + NS_IMETHOD SetAutoZIndex(PRBool aAutoZIndex) + { if (aAutoZIndex) + mVFlags |= NS_VIEW_PUBLIC_FLAG_AUTO_ZINDEX; + else + mVFlags &= ~NS_VIEW_PUBLIC_FLAG_AUTO_ZINDEX; + return NS_OK; + } + NS_IMETHOD GetAutoZIndex(PRBool &aAutoZIndex) const + { aAutoZIndex = ((mVFlags & NS_VIEW_PUBLIC_FLAG_AUTO_ZINDEX) != 0); + return NS_OK; + } + NS_IMETHOD SetFloating(PRBool aFloatingView) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetFloating(PRBool &aFloatingView) const + { aFloatingView = PR_FALSE; return NS_OK; } + NS_IMETHOD SetParent(nsIView *aParent) + { mParent = aParent; return NS_OK; } + NS_IMETHOD GetParent(nsIView *&aParent) const + { aParent = mParent; return NS_OK; } + NS_IMETHOD GetNextSibling(nsIView *&aNextSibling) const + { aNextSibling = mNextSibling; return NS_OK; } + NS_IMETHOD SetNextSibling(nsIView* aNextSibling) + { mNextSibling = aNextSibling; return NS_OK; } + NS_IMETHOD InsertChild(nsIView *child, nsIView *sibling) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD RemoveChild(nsIView *child) + { NS_ASSERTION(mReparentedChild == child, "Removing incorrect child"); + mReparentedChild = nsnull; + return NS_ERROR_NOT_IMPLEMENTED; + } + NS_IMETHOD GetChildCount(PRInt32 &aCount) const + { aCount = 0; return NS_OK; } + NS_IMETHOD GetChild(PRInt32 index, nsIView*& aChild) const + { aChild = nsnull; return NS_OK; } + NS_IMETHOD SetTransform(nsTransform2D &aXForm) + { return NS_OK; } + NS_IMETHOD GetTransform(nsTransform2D &aXForm) const + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD SetOpacity(float opacity) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetOpacity(float &aOpacity) const + { return NS_OK; } + NS_IMETHOD HasTransparency(PRBool &aTransparent) const + { return NS_OK; } + NS_IMETHOD SetContentTransparency(PRBool aTransparent) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD SetClientData(void *aData) + { return NS_OK; } + NS_IMETHOD GetClientData(void *&aData) const + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetOffsetFromWidget(nscoord *aDx, nscoord *aDy, nsIWidget *&aWidget) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetDirtyRegion(nsIRegion*& aRegion) const + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD CreateWidget(const nsIID &aWindowIID, + nsWidgetInitData *aWidgetInitData = nsnull, + nsNativeWidget aNative = nsnull, + PRBool aEnableDragDrop = PR_TRUE) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD SetWidget(nsIWidget *aWidget) + { return NS_OK; } + NS_IMETHOD GetWidget(nsIWidget *&aWidget) const + { aWidget = nsnull; return NS_OK; } + NS_IMETHOD HasWidget(PRBool *aHasWidget) const + { *aHasWidget = PR_FALSE; return NS_OK; } + NS_IMETHOD List(FILE* out, PRInt32 aIndent) const + { return NS_OK; } + NS_IMETHOD SetViewFlags(PRUint32 aFlags) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD ClearViewFlags(PRUint32 aFlags) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetViewFlags(PRUint32 *aFlags) const + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetScratchPoint(nsPoint **aPoint) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD SetCompositorFlags(PRUint32 aFlags) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetCompositorFlags(PRUint32 *aFlags) + { *aFlags = IS_Z_PLACEHOLDER_VIEW; return NS_OK; } + NS_IMETHOD GetExtents(nsRect *aExtents) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD GetClippedRect(nsRect& aClippedRect, PRBool& aIsClipped, PRBool& aEmpty) const + { aClippedRect.SetRect(0, 0, 0, 0); aIsClipped = PR_TRUE; aEmpty = PR_TRUE; return NS_OK; } + + NS_IMETHOD IgnoreSetPosition(PRBool aShouldIgnore) + { return NS_OK; } + NS_IMETHOD SynchWidgetSizePosition() + { return NS_OK; } + + NS_IMETHOD SetReparentedZChild(nsIView *aChild) + { mReparentedChild = aChild; return NS_OK; } + +protected: + virtual ~nsZPlaceholderView() + { if (nsnull != mReparentedChild) { + mReparentedChild->SetZParent(nsnull); + } + if (nsnull != mParent) + { + nsIViewManager* vm = nsnull; + mParent->GetViewManager(vm); + if (nsnull != vm) + { + vm->RemoveChild(mParent, this); + } + else + { + mParent->RemoveChild(this); + } + } + } + +protected: + nsIView *mParent; + + nsIView *mNextSibling; + nsIView *mReparentedChild; + PRInt32 mZindex; + PRInt32 mVFlags; + +private: + NS_IMETHOD_(nsrefcnt) AddRef(void) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } + NS_IMETHOD_(nsrefcnt) Release(void) + { NS_ASSERTION(PR_FALSE, "Unimplemented"); return NS_ERROR_NOT_IMPLEMENTED; } +}; + + + PRInt32 nsViewManager::mVMCount = 0; nsDrawingSurface nsViewManager::mDrawingSurface = nsnull; nsRect nsViewManager::mDSBounds = nsRect(0, 0, 0, 0); nsDrawingSurface nsViewManager::gOffScreen = nsnull; -nsDrawingSurface nsViewManager::gRed = nsnull; -nsDrawingSurface nsViewManager::gBlue = nsnull; -PRInt32 nsViewManager::gBlendWidth = 0; -PRInt32 nsViewManager::gBlendHeight = 0; +nsDrawingSurface nsViewManager::gBlack = nsnull; +nsDrawingSurface nsViewManager::gWhite = nsnull; +nsSize nsViewManager::gOffScreenSize = nsSize(0, 0); +nsSize nsViewManager::gLargestRequestedSize = nsSize(0, 0); + + +// Weakly held references to all of the view managers +nsVoidArray* nsViewManager::gViewManagers = nsnull; static NS_DEFINE_IID(knsViewManagerIID, NS_IVIEWMANAGER_IID); -nsViewManager :: nsViewManager() +nsViewManager::nsViewManager() { - NS_INIT_REFCNT(); - mVMCount++; - mUpdateBatchCnt = 0; - mCompositeListeners = nsnull; + NS_INIT_REFCNT(); + + if (mVMCount == 0) { + //Create a vector to hold each view manager + gViewManagers = new nsVoidArray; + } + gViewManagers->AppendElement(this); + + mVMCount++; + // NOTE: we use a zeroing operator new, so all data members are + // assumed to be cleared here. mX = 0; mY = 0; + mCachingWidgetChanges = 0; + } -nsViewManager :: ~nsViewManager() +nsViewManager::~nsViewManager() { #ifdef NS_VIEWMANAGER_NEEDS_TIMER - if (nsnull != mTimer) - { - mTimer->Cancel(); //XXX this should not be necessary. MMP - } + if (nsnull != mTimer) { + mTimer->Cancel(); //XXX this should not be necessary. MMP + } #endif - NS_IF_RELEASE(mRootWindow); + NS_IF_RELEASE(mRootWindow); - mRootScrollable = nsnull; + mRootScrollable = nsnull; - NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers"); - --mVMCount; + NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers"); + --mVMCount; - if ((0 == mVMCount) && - ((nsnull != mDrawingSurface) || (nsnull != gOffScreen) || - (nsnull != gRed) || (nsnull != gBlue))) - { - nsIRenderingContext *rc; + PRBool removed = gViewManagers->RemoveElement(this); + NS_ASSERTION(removed, "Viewmanager instance not was not in the global list of viewmanagers"); - nsresult rv = nsComponentManager::CreateInstance(kRenderingContextCID, - nsnull, - NS_GET_IID(nsIRenderingContext), - (void **)&rc); + if ((0 == mVMCount) && + ((nsnull != mDrawingSurface) || (nsnull != gOffScreen) || + (nsnull != gBlack) || (nsnull != gWhite))) + { + delete gViewManagers; + gViewManagers = nsnull; - if (NS_OK == rv) - { - if (nsnull != mDrawingSurface) - rc->DestroyDrawingSurface(mDrawingSurface); + nsCOMPtr rc; + nsresult rv = nsComponentManager::CreateInstance(kRenderingContextCID, + nsnull, + NS_GET_IID(nsIRenderingContext), + getter_AddRefs(rc)); - if (nsnull != gOffScreen) - rc->DestroyDrawingSurface(gOffScreen); + if (NS_OK == rv) + { + if (nsnull != mDrawingSurface) + rc->DestroyDrawingSurface(mDrawingSurface); - if (nsnull != gRed) - rc->DestroyDrawingSurface(gRed); + if (nsnull != gOffScreen) + rc->DestroyDrawingSurface(gOffScreen); - if (nsnull != gBlue) - rc->DestroyDrawingSurface(gBlue); + if (nsnull != gBlack) + rc->DestroyDrawingSurface(gBlack); - NS_RELEASE(rc); - } + if (nsnull != gWhite) + rc->DestroyDrawingSurface(gWhite); + } - mDrawingSurface = nsnull; - gOffScreen = nsnull; - gRed = nsnull; - gBlue = nsnull; - gBlendWidth = 0; - gBlendHeight = 0; - } + mDrawingSurface = nsnull; + gOffScreen = nsnull; + gBlack = nsnull; + gWhite = nsnull; + gOffScreenSize.SizeTo(0, 0); + } - mObserver = nsnull; - mContext = nsnull; + mObserver = nsnull; + mContext = nsnull; - if (nsnull != mDisplayList) - { - PRInt32 count = mDisplayList->Count(); - for (PRInt32 index = 0; index < count; index++) { - DisplayListElement* element = (DisplayListElement*) mDisplayList->ElementAt(index); - if (element != nsnull) - delete element; + NS_IF_RELEASE(mBlender); + NS_IF_RELEASE(mOpaqueRgn); + NS_IF_RELEASE(mTmpRgn); + + NS_IF_RELEASE(mOffScreenCX); + NS_IF_RELEASE(mBlackCX); + NS_IF_RELEASE(mWhiteCX); + + if (nsnull != mCompositeListeners) { + mCompositeListeners->Clear(); + NS_RELEASE(mCompositeListeners); } - - delete mDisplayList; - mDisplayList = nsnull; - } - - if (nsnull != mTransRgn) - { - if (nsnull != mTransRects) - mTransRgn->FreeRects(mTransRects); - - NS_RELEASE(mTransRgn); - } - - NS_IF_RELEASE(mBlender); - NS_IF_RELEASE(mOpaqueRgn); - NS_IF_RELEASE(mTRgn); - NS_IF_RELEASE(mRCRgn); - - NS_IF_RELEASE(mOffScreenCX); - NS_IF_RELEASE(mRedCX); - NS_IF_RELEASE(mBlueCX); - - if (nsnull != mCompositeListeners) { - mCompositeListeners->Clear(); - NS_RELEASE(mCompositeListeners); - } } NS_IMPL_QUERY_INTERFACE(nsViewManager, knsViewManagerIID) -NS_IMPL_ADDREF(nsViewManager); + NS_IMPL_ADDREF(nsViewManager); nsrefcnt nsViewManager::Release(void) { - /* Note funny ordering of use of mRefCnt. We were seeing a problem - during the deletion of a view hierarchy where child views, - while being destroyed, referenced this view manager and caused - the Destroy part of this method to be re-entered. Waiting until - the destruction has finished to decrement the refcount - prevents that. + /* Note funny ordering of use of mRefCnt. We were seeing a problem + during the deletion of a view hierarchy where child views, + while being destroyed, referenced this view manager and caused + the Destroy part of this method to be re-entered. Waiting until + the destruction has finished to decrement the refcount + prevents that. */ - NS_LOG_RELEASE(this, mRefCnt - 1, "nsViewManager"); - if (mRefCnt == 1) - { - if (nsnull != mRootView) { - // Destroy any remaining views - mRootView->Destroy(); - mRootView = nsnull; - } - delete this; - return 0; - } - mRefCnt--; - return mRefCnt; + NS_LOG_RELEASE(this, mRefCnt - 1, "nsViewManager"); + if (mRefCnt == 1) + { + if (nsnull != mRootView) { + // Destroy any remaining views + mRootView->Destroy(); + mRootView = nsnull; + } + delete this; + return 0; + } + mRefCnt--; + return mRefCnt; } static nsresult CreateRegion(nsIComponentManager* componentManager, nsIRegion* *result) @@ -262,7 +497,7 @@ static nsresult CreateRegion(nsIComponentManager* componentManager, nsIRegion* * // We don't hold a reference to the presentation context because it // holds a reference to us. -NS_IMETHODIMP nsViewManager :: Init(nsIDeviceContext* aContext, nscoord aX, nscoord aY) +NS_IMETHODIMP nsViewManager::Init(nsIDeviceContext* aContext, nscoord aX, nscoord aY) { nsresult rv; @@ -275,6 +510,9 @@ NS_IMETHODIMP nsViewManager :: Init(nsIDeviceContext* aContext, nscoord aX, nsco return NS_ERROR_ALREADY_INITIALIZED; } mContext = aContext; + mContext->GetAppUnitsToDevUnits(mTwipsToPixels); + mContext->GetDevUnitsToAppUnits(mPixelsToTwips); + mFrameRate = 0; mTrueFrameRate = 0; mTransCnt = 0; @@ -289,13 +527,14 @@ NS_IMETHODIMP nsViewManager :: Init(nsIDeviceContext* aContext, nscoord aX, nsco mKeyGrabber = nsnull; // create regions + mOpaqueRgn = nsnull; + mTmpRgn = nsnull; + nsIComponentManager* componentManager = nsnull; rv = NS_GetGlobalComponentManager(&componentManager); if (NS_SUCCEEDED(rv)) { - rv = CreateRegion(componentManager, &mTransRgn); - rv = CreateRegion(componentManager, &mOpaqueRgn); - rv = CreateRegion(componentManager, &mTRgn); - rv = CreateRegion(componentManager, &mRCRgn); + CreateRegion(componentManager, &mOpaqueRgn); + CreateRegion(componentManager, &mTmpRgn); } mX = aX; @@ -304,1140 +543,930 @@ NS_IMETHODIMP nsViewManager :: Init(nsIDeviceContext* aContext, nscoord aX, nsco return rv; } -NS_IMETHODIMP nsViewManager :: GetRootView(nsIView *&aView) +NS_IMETHODIMP nsViewManager::GetRootView(nsIView *&aView) { - aView = mRootView; - return NS_OK; + aView = mRootView; + return NS_OK; } NS_IMETHODIMP nsViewManager :: SetRootView(nsIView *aView, nsIWidget* aWidget) { - UpdateTransCnt(mRootView, aView); - // Do NOT destroy the current root view. It's the caller's responsibility - // to destroy it - mRootView = aView; + UpdateTransCnt(mRootView, aView); + // Do NOT destroy the current root view. It's the caller's responsibility + // to destroy it + mRootView = aView; - //now get the window too. - NS_IF_RELEASE(mRootWindow); + //now get the window too. + NS_IF_RELEASE(mRootWindow); - // The window must be specified through one of the following: - //* a) The aView has a nsIWidget instance or - //* b) the aWidget parameter is an nsIWidget instance to render into - //* that is not owned by a view. - //* c) aView has a parent view managed by a different view manager or + // The window must be specified through one of the following: + //* a) The aView has a nsIWidget instance or + //* b) the aWidget parameter is an nsIWidget instance to render into + //* that is not owned by a view. + //* c) aView has a parent view managed by a different view manager or - if (nsnull != aWidget) { - mRootWindow = aWidget; - NS_ADDREF(mRootWindow); - return NS_OK; - } + if (nsnull != aWidget) { + mRootWindow = aWidget; + NS_ADDREF(mRootWindow); + return NS_OK; + } - // case b) The aView has a nsIWidget instance - if (nsnull != mRootView) { - mRootView->GetWidget(mRootWindow); - if (nsnull != mRootWindow) { - return NS_OK; - } - } + // case b) The aView has a nsIWidget instance + if (nsnull != mRootView) { + mRootView->GetWidget(mRootWindow); + if (nsnull != mRootWindow) { + return NS_OK; + } + } - // case c) aView has a parent view managed by a different view manager + // case c) aView has a parent view managed by a different view manager - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: GetFrameRate(PRUint32 &aRate) +NS_IMETHODIMP nsViewManager::GetFrameRate(PRUint32 &aRate) { - aRate = mTrueFrameRate; - return NS_OK; + aRate = mTrueFrameRate; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: SetFrameRate(PRUint32 aFrameRate) +NS_IMETHODIMP nsViewManager::SetFrameRate(PRUint32 aFrameRate) { - nsresult rv = NS_OK; + nsresult rv = NS_OK; - if (aFrameRate != mFrameRate) - { + if (aFrameRate != mFrameRate) + { #ifdef NS_VIEWMANAGER_NEEDS_TIMER - //XXX: Reimplement using a repeating timer - if (nsnull != mTimer) - { - mTimer->Cancel(); //XXX this should not be necessary. MMP - } + if (nsnull != mTimer) + { + mTimer->Cancel(); //XXX this should not be necessary. MMP + } #endif - mFrameRate = aFrameRate; - mTrueFrameRate = aFrameRate; + mFrameRate = aFrameRate; + mTrueFrameRate = aFrameRate; - if (mFrameRate != 0) - { + if (mFrameRate != 0) + { #ifdef NS_VIEWMANAGER_NEEDS_TIMER - mTimer = do_CreateInstance("component://netscape/timer", &rv); + mTimer = do_CreateInstance("component://netscape/timer", &rv); - if (NS_OK == rv) - mTimer->Init(vm_timer_callback, this, 1000 / mFrameRate); + if (NS_OK == rv) + mTimer->Init(vm_timer_callback, this, 1000 / mFrameRate); #endif - } - } + } + + } - return rv; + + return rv; } -NS_IMETHODIMP nsViewManager :: GetWindowDimensions(nscoord *width, nscoord *height) +NS_IMETHODIMP nsViewManager::GetWindowDimensions(nscoord *width, nscoord *height) { - if (nsnull != mRootView) - mRootView->GetDimensions(width, height); - else - { - *width = 0; - *height = 0; - } - return NS_OK; + if (nsnull != mRootView) + mRootView->GetDimensions(width, height); + else + { + *width = 0; + *height = 0; + } + return NS_OK; } -NS_IMETHODIMP nsViewManager :: SetWindowDimensions(nscoord width, nscoord height) +NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord width, nscoord height) { - // Resize the root view - if (nsnull != mRootView) - mRootView->SetDimensions(width, height); + // Resize the root view + if (nsnull != mRootView) + mRootView->SetDimensions(width, height); //printf("new dims: %d %d\n", width, height); // Inform the presentation shell that we've been resized - if (nsnull != mObserver) - mObserver->ResizeReflow(mRootView, width, height); -//printf("reflow done\n"); + if (nsnull != mObserver) + mObserver->ResizeReflow(mRootView, width, height); + //printf("reflow done\n"); - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: ResetScrolling(void) +NS_IMETHODIMP nsViewManager::ResetScrolling(void) { - if (nsnull != mRootScrollable) - mRootScrollable->ComputeScrollOffsets(PR_TRUE); + if (nsnull != mRootScrollable) + mRootScrollable->ComputeScrollOffsets(PR_TRUE); - return NS_OK; + return NS_OK; } -void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsIRegion *region, PRUint32 aUpdateFlags) +void nsViewManager::Refresh(nsIView *aView, nsIRenderingContext *aContext, nsIRegion *region, PRUint32 aUpdateFlags) { - nsRect wrect; - nsIRenderingContext *localcx = nsnull; - nsDrawingSurface ds = nsnull; + nsRect wrect; + nsCOMPtr localcx; + nsDrawingSurface ds = nsnull; - if (PR_FALSE == mRefreshEnabled) - return; - -#ifdef NS_VM_PERF_METRICS - MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this)); - MOZ_TIMER_RESET(mWatch); - - MOZ_TIMER_DEBUGLOG(("Start: nsViewManager::Refresh(region)\n")); - MOZ_TIMER_START(mWatch); -#endif - - NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); - - mPainting = PR_TRUE; - -//printf("refreshing region...\n"); - //force double buffering because of non-opaque views? - - if (mTransCnt > 0) - aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; - -#ifdef NO_DOUBLE_BUFFER - aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER; -#endif - - if (nsnull == aContext) - { - localcx = CreateRenderingContext(*aView); - - //couldn't get rendering context. this is ok at init time atleast - if (nsnull == localcx) { - mPainting = PR_FALSE; - return; - } - } - else - localcx = aContext; - - // notify the listeners. - if (nsnull != mCompositeListeners) { - PRUint32 listenerCount; - if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { - nsICompositeListener* listener; - for (PRUint32 i = 0; i < listenerCount; i++) { - if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), (void**)&listener))) { - listener->WillRefreshRegion(this, aView, aContext, region, aUpdateFlags); - NS_RELEASE(listener); - } - } - } - } - - if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) - { - nsIWidget* widget; - - aView->GetWidget(widget); - widget->GetClientBounds(wrect); - - wrect.x = wrect.y = 0; - - NS_RELEASE(widget); - - ds = GetDrawingSurface(*localcx, wrect); - } - - PRBool result; - nsRect trect; - - if (nsnull != region) - localcx->SetClipRegion(*region, nsClipCombine_kUnion, result); - - aView->GetBounds(trect); - - localcx->SetClipRect(trect, nsClipCombine_kIntersect, result); - - RenderViews(aView, *localcx, trect, result); - - if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) -#ifdef NEW_COMPOSITOR - localcx->CopyOffScreenBits(ds, wrect.x, wrect.y, wrect, 0); -#else - localcx->CopyOffScreenBits(ds, wrect.x, wrect.y, wrect, NS_COPYBITS_USE_SOURCE_CLIP_REGION); -#endif - - if (localcx != aContext) - NS_RELEASE(localcx); - - // Subtract the area we just painted from the dirty region - if ((nsnull != region) && !region->IsEmpty()) - { - nsRect pixrect = trect; - float t2p; - - mContext->GetAppUnitsToDevUnits(t2p); - - pixrect.ScaleRoundIn(t2p); - region->Subtract(pixrect.x, pixrect.y, pixrect.width, pixrect.height); - } - - mLastRefresh = PR_IntervalNow(); - - mPainting = PR_FALSE; - - // notify the listeners. - if (nsnull != mCompositeListeners) { - PRUint32 listenerCount; - if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { - nsICompositeListener* listener; - for (PRUint32 i = 0; i < listenerCount; i++) { - if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), (void**)&listener))) { - listener->DidRefreshRegion(this, aView, aContext, region, aUpdateFlags); - NS_RELEASE(listener); - } - } - } - } - -#ifdef NS_VM_PERF_METRICS - MOZ_TIMER_DEBUGLOG(("Stop: nsViewManager::Refresh(region), this=%p\n", this)); - MOZ_TIMER_STOP(mWatch); - MOZ_TIMER_LOG(("vm1 Paint time (this=%p): ", this)); - MOZ_TIMER_PRINT(mWatch); -#endif -} - -void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, const nsRect *rect, PRUint32 aUpdateFlags) -{ - nsRect wrect, brect; - nsIRenderingContext *localcx = nsnull; - nsDrawingSurface ds = nsnull; - - if (PR_FALSE == mRefreshEnabled) - return; - -#ifdef NS_VM_PERF_METRICS - MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this)); - MOZ_TIMER_RESET(mWatch); - - MOZ_TIMER_DEBUGLOG(("Start: nsViewManager::Refresh(region)\n")); - MOZ_TIMER_START(mWatch); -#endif - - NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); - - mPainting = PR_TRUE; - - //force double buffering because of non-opaque views? - -//printf("refreshing rect... "); -//stdout << *rect; -//printf("\n"); - if (mTransCnt > 0) - aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; - -#ifdef NO_DOUBLE_BUFFER - aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER; -#endif - - if (nsnull == aContext) - { - localcx = CreateRenderingContext(*aView); - - //couldn't get rendering context. this is ok if at startup - if (nsnull == localcx) { - mPainting = PR_FALSE; - return; - } - } - else - localcx = aContext; - - // notify the listeners. - if (nsnull != mCompositeListeners) { - PRUint32 listenerCount; - if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { - nsICompositeListener* listener; - for (PRUint32 i = 0; i < listenerCount; i++) { - if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), (void**)&listener))) { - listener->WillRefreshRect(this, aView, aContext, rect, aUpdateFlags); - NS_RELEASE(listener); - } - } - } - } - - if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) - { - nsIWidget* widget; - - aView->GetWidget(widget); - widget->GetClientBounds(wrect); - - brect = wrect; - wrect.x = wrect.y = 0; - - NS_RELEASE(widget); - - ds = GetDrawingSurface(*localcx, wrect); - } - - nsRect trect = *rect; - - PRBool result; - - localcx->SetClipRect(trect, nsClipCombine_kReplace, result); - - RenderViews(aView, *localcx, trect, result); - - if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) -#ifdef NEW_COMPOSITOR - { -#ifdef XP_MAC - // localcx->SelectOffScreenDrawingSurface(nsnull); - // blinkRect(localcx, trect); - localcx->CopyOffScreenBits(ds, wrect.x, wrect.y, wrect, 0); -#else -#if defined(XP_UNIX) || defined(XP_OS2) - localcx->SetClipRect(trect, nsClipCombine_kReplace, result); -#endif //unix - localcx->CopyOffScreenBits(ds, brect.x, brect.y, brect, 0); -#endif //mac - } -#else - localcx->CopyOffScreenBits(ds, wrect.x, wrect.y, wrect, NS_COPYBITS_USE_SOURCE_CLIP_REGION); -#endif - - - if (localcx != aContext) - NS_RELEASE(localcx); - -#if 0 - // Subtract the area we just painted from the dirty region - nsIRegion *dirtyRegion; - aView->GetDirtyRegion(dirtyRegion); - - if ((nsnull != dirtyRegion) && !dirtyRegion->IsEmpty()) - { - nsRect pixrect = trect; - float t2p; - - mContext->GetAppUnitsToDevUnits(t2p); - - pixrect.ScaleRoundIn(t2p); - dirtyRegion->Subtract(pixrect.x, pixrect.y, pixrect.width, pixrect.height); - NS_RELEASE(dirtyRegion); - } -#endif - - mLastRefresh = PR_IntervalNow(); - - mPainting = PR_FALSE; - - // notify the listeners. - if (nsnull != mCompositeListeners) { - PRUint32 listenerCount; - if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { - nsICompositeListener* listener; - for (PRUint32 i = 0; i < listenerCount; i++) { - if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), (void**)&listener))) { - listener->DidRefreshRect(this, aView, aContext, rect, aUpdateFlags); - NS_RELEASE(listener); - } - } - } - } - -#ifdef NS_VM_PERF_METRICS - MOZ_TIMER_DEBUGLOG(("Stop: nsViewManager::Refresh(region), this=%p\n", this)); - MOZ_TIMER_STOP(mWatch); - MOZ_TIMER_LOG(("vm1 Paint time (this=%p): ", this)); - MOZ_TIMER_PRINT(mWatch); -#endif -} - -//states - -typedef enum -{ - FRONT_TO_BACK_RENDER = 1, - FRONT_TO_BACK_ACCUMULATE, - BACK_TO_FRONT_TRANS, - BACK_TO_FRONT_OPACITY, - FRONT_TO_BACK_CLEANUP, - FRONT_TO_BACK_POP_SEARCH, - COMPOSITION_DONE -} nsCompState; - -//bit shifts -#define TRANS_PROPERTY_TRANS 0 -#define TRANS_PROPERTY_OPACITY 1 - -#ifdef SHOW_RECTS -static PRInt32 evenodd = 0; -#endif - -void nsViewManager :: RenderViews(nsIView *aRootView, nsIRenderingContext& aRC, const nsRect& aRect, PRBool &aResult) -{ -#ifdef NEW_COMPOSITOR - - PRBool isFloatingView = PR_FALSE; - if (NS_SUCCEEDED(aRootView->GetFloating(isFloatingView)) && isFloatingView) { - // floating views are rendered locally (and act globally). - // Paint the view. The clipping rect was set above set don't clip again. - aRootView->Paint(aRC, aRect, NS_VIEW_FLAG_CLIP_SET, aResult); + if (PR_FALSE == mRefreshEnabled) return; + +#ifdef NS_VM_PERF_METRICS + MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this)); + MOZ_TIMER_RESET(mWatch); + + MOZ_TIMER_DEBUGLOG(("Start: nsViewManager::Refresh(region)\n")); + MOZ_TIMER_START(mWatch); +#endif + + NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); + + mPainting = PR_TRUE; + + //printf("refreshing region...\n"); + //force double buffering because of non-opaque views? + + if (mTransCnt > 0) + aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; + +#ifdef NO_DOUBLE_BUFFER + aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER; +#endif + + if (nsnull == aContext) + { + localcx = getter_AddRefs(CreateRenderingContext(*aView)); + + //couldn't get rendering context. this is ok at init time atleast + if (nsnull == localcx) { + mPainting = PR_FALSE; + return; + } + } else { + // plain assignment grabs another reference. + localcx = aContext; + } + + // notify the listeners. + if (nsnull != mCompositeListeners) { + PRUint32 listenerCount; + if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { + nsCOMPtr listener; + for (PRUint32 i = 0; i < listenerCount; i++) { + if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), getter_AddRefs(listener)))) { + listener->WillRefreshRegion(this, aView, aContext, region, aUpdateFlags); + } + } + } } -#define SET_STATE(x) { prevstate = state; state = (x); } + if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) + { + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + widget->GetClientBounds(wrect); + wrect.x = wrect.y = 0; + ds = GetDrawingSurface(*localcx, wrect); + } - PRInt32 flatlen = 0, cnt; - nsCompState state = FRONT_TO_BACK_RENDER, prevstate; - PRInt32 transprop = 0; - PRInt32 increment = DISPLAYLIST_INC; - PRInt32 loopstart = 0, backstart; - PRInt32 loopend; - PRInt32 accumstart; - float t2p, p2t; - PRInt32 rgnrect; - nsRect localrect, trect; - PRBool useopaque = PR_FALSE; - nsRegionRectSet onerect, *rectset; - - nsCOMPtr paintedRgn; - if (NS_FAILED(nsComponentManager::CreateInstance(kRegionCID, nsnull, NS_GET_IID(nsIRegion), (void**) getter_AddRefs(paintedRgn)))) - return; - paintedRgn->Init(); + PRBool result; + nsRect trect; - //printf("-------------begin paint------------\n"); - if (aRootView && mRootView) { - nscoord ox = 0, oy = 0; + if (nsnull != region) + localcx->SetClipRegion(*region, nsClipCombine_kUnion, result); - ComputeViewOffset(aRootView, &ox, &oy, 1); - CreateDisplayList(mRootView, &flatlen, ox, oy, aRootView, &aRect); - } + aView->GetBounds(trect); - loopend = flatlen; + localcx->SetClipRect(trect, nsClipCombine_kIntersect, result); - mContext->GetAppUnitsToDevUnits(t2p); - mContext->GetDevUnitsToAppUnits(p2t); + RenderViews(aView, *localcx, trect, result); -#ifdef SHOW_DISPLAYLIST - ShowDisplayList(flatlen); + if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) + localcx->CopyOffScreenBits(ds, wrect.x, wrect.y, wrect, NS_COPYBITS_USE_SOURCE_CLIP_REGION); + + // Subtract the area we just painted from the dirty region + if ((nsnull != region) && !region->IsEmpty()) { + nsRect pixrect = trect; + float t2p; + + mContext->GetAppUnitsToDevUnits(t2p); + + pixrect.ScaleRoundIn(t2p); + region->Subtract(pixrect.x, pixrect.y, pixrect.width, pixrect.height); + } + + mLastRefresh = PR_IntervalNow(); + + mPainting = PR_FALSE; + + // notify the listeners. + if (nsnull != mCompositeListeners) { + PRUint32 listenerCount; + if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { + nsCOMPtr listener; + for (PRUint32 i = 0; i < listenerCount; i++) { + if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), getter_AddRefs(listener)))) { + listener->DidRefreshRegion(this, aView, aContext, region, aUpdateFlags); + } + } + } + } + +#ifdef NS_VM_PERF_METRICS + MOZ_TIMER_DEBUGLOG(("Stop: nsViewManager::Refresh(region), this=%p\n", this)); + MOZ_TIMER_STOP(mWatch); + MOZ_TIMER_LOG(("vm2 Paint time (this=%p): ", this)); + MOZ_TIMER_PRINT(mWatch); #endif - while (state != COMPOSITION_DONE) - { - nsIView *curview; - nsRect *currect; - PRUint32 curflags; - PRBool pushing; - PRInt32 pushcnt = 0; - PRBool clipstate; +} - for (cnt = loopstart; (increment > 0) ? (cnt < loopend) : (cnt > loopend); cnt += increment) - { - DisplayListElement* curelement = (DisplayListElement*) mDisplayList->ElementAt(cnt); - if (nsnull == curelement) - continue; - curview = curelement->mView; - currect = &curelement->mClip; - curflags = curelement->mFlags; - - if ((nsnull != curview) && (nsnull != currect)) - { - PRBool hasWidget = DoesViewHaveNativeWidget(*curview); - PRBool isBottom = cnt == (flatlen - DISPLAYLIST_INC); +void nsViewManager::Refresh(nsIView *aView, nsIRenderingContext *aContext, const nsRect *rect, PRUint32 aUpdateFlags) +{ + nsRect wrect, brect; + nsCOMPtr localcx; + nsDrawingSurface ds = nsnull; - if (curflags & PUSH_CLIP) - { - if (state == BACK_TO_FRONT_OPACITY) - { - mOffScreenCX->PopState(clipstate); - mRedCX->PopState(clipstate); - mBlueCX->PopState(clipstate); + if (PR_FALSE == mRefreshEnabled) + return; - // permanently remove any painted opaque views. - mOffScreenCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); - mRedCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); - mRedCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); +#ifdef NS_VM_PERF_METRICS + MOZ_TIMER_DEBUGLOG(("Reset nsViewManager::Refresh(region), this=%p\n", this)); + MOZ_TIMER_RESET(mWatch); - --pushcnt; - NS_ASSERTION((pushcnt >= 0), "underflow"); - } - else if (state == BACK_TO_FRONT_TRANS) - { - aRC.PopState(clipstate); - --pushcnt; - NS_ASSERTION((pushcnt >= 0), "underflow"); - - // permanently remove any painted opaque views. - aRC.SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); - } - else - { - pushing = FRONT_TO_BACK_RENDER; - - aRC.PushState(); - aRC.SetClipRect(*currect, nsClipCombine_kIntersect, clipstate); - - ++pushcnt; - } - } - else if (curflags & POP_CLIP) - { - if (state == BACK_TO_FRONT_OPACITY) - { - pushing = BACK_TO_FRONT_OPACITY; - - mOffScreenCX->PushState(); - mRedCX->PushState(); - mBlueCX->PushState(); - - mOffScreenCX->SetClipRect(*currect, nsClipCombine_kIntersect, clipstate); - mRedCX->SetClipRect(*currect, nsClipCombine_kIntersect, clipstate); - mBlueCX->SetClipRect(*currect, nsClipCombine_kIntersect, clipstate); - - ++pushcnt; - } - else if (state == BACK_TO_FRONT_TRANS) - { - pushing = FRONT_TO_BACK_RENDER; - - aRC.PushState(); - aRC.SetClipRect(*currect, nsClipCombine_kIntersect, clipstate); - - ++pushcnt; - } - else - { - aRC.PopState(clipstate); - --pushcnt; - NS_ASSERTION((pushcnt >= 0), "underflow"); - - // permanently remove any painted opaque views. - aRC.SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); - } - - if (state == FRONT_TO_BACK_POP_SEARCH) - { - aRC.SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - - if (!clipstate) - state = prevstate; - else if (pushcnt == 0) - aResult = clipstate; - } - } - else -// if (isBottom) -// if (!hasWidget || isBottom) - { - nsPoint *point; - - curview->GetScratchPoint(&point); - - if (!hasWidget || (hasWidget && point->x)) - { - PRBool trans = PR_FALSE; - float opacity = 1.0f; - PRBool translucent = PR_FALSE; - - if (!isBottom) - { - curview->HasTransparency(trans); - curview->GetOpacity(opacity); - - translucent = opacity < 1.0f; - } - - switch (state) - { - case FRONT_TO_BACK_RENDER: - if (trans || translucent) - { - if (mTransRgn && mOpaqueRgn) - { - //need to finish using back to front till this point - SET_STATE(FRONT_TO_BACK_ACCUMULATE) - - if (pushcnt == 0) - accumstart = cnt; - else - accumstart = 0; - - mTransRgn->SetTo(0, 0, 0, 0); - mOpaqueRgn->SetTo(0, 0, 0, 0); - } - - //falls through - } - else - { - RenderView(curview, aRC, aRect, *currect, aResult); - - // accumulate region of all rendered opaque views. - trect.IntersectRect(*currect, aRect), trect *= t2p; - paintedRgn->Union(trect.x, trect.y, trect.width, trect.height); - - if (aResult == PR_FALSE) - { - aRC.SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - - if (clipstate) - { - if (pushcnt > 0) - SET_STATE(FRONT_TO_BACK_POP_SEARCH) - else - aResult = clipstate; - } - } - - break; - } - - case FRONT_TO_BACK_ACCUMULATE: - { - trect.IntersectRect(*currect, aRect); - trect *= t2p; - - if (trans || translucent || - mTransRgn->ContainsRect(trect.x, trect.y, trect.width, trect.height) || - mOpaqueRgn->ContainsRect(trect.x, trect.y, trect.width, trect.height)) - { - transprop |= (trans << TRANS_PROPERTY_TRANS) | (translucent << TRANS_PROPERTY_OPACITY); - curelement->mFlags = (VIEW_INCLUDED | curflags); - - if (!isBottom) - { -//printf("adding %d %d %d %d\n", trect.x, trect.y, trect.width, trect.height); - if (trans || translucent) - mTransRgn->Union(trect.x, trect.y, trect.width, trect.height); - else - mOpaqueRgn->Union(trect.x, trect.y, trect.width, trect.height); - } - } - else - { - RenderView(curview, aRC, aRect, *currect, aResult); - - // accumulate region of all rendered opaque views. - trect.IntersectRect(*currect, aRect), trect *= t2p; - paintedRgn->Union(trect.x, trect.y, trect.width, trect.height); - - if (aResult == PR_FALSE) - { - aRC.SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - - if (clipstate) - { - if (pushcnt > 0) - SET_STATE(FRONT_TO_BACK_POP_SEARCH) - else - aResult = clipstate; - } - } - } - - break; - } - - case FRONT_TO_BACK_POP_SEARCH: - break; - - case BACK_TO_FRONT_TRANS: - if ((curflags & VIEW_INCLUDED) && localrect.Intersects(*currect)) - { - RenderView(curview, aRC, localrect, *currect, clipstate); - } - - break; - - case FRONT_TO_BACK_CLEANUP: - if ((curflags & VIEW_INCLUDED) && !trans && - !translucent && localrect.Intersects(*currect)) - { - RenderView(curview, aRC, localrect, *currect, aResult); - - if (aResult == PR_FALSE) - { - aRC.SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - - if (clipstate) - { - if (pushcnt > 0) - SET_STATE(FRONT_TO_BACK_POP_SEARCH) - else - aResult = clipstate; - } - } - } - - break; - - case BACK_TO_FRONT_OPACITY: - if (curflags & VIEW_INCLUDED) - { - nsRect blendrect, pixrect; - - if (blendrect.IntersectRect(*currect, localrect)) - { - pixrect = blendrect; - - pixrect.x -= localrect.x; - pixrect.y -= localrect.y; - - pixrect *= t2p; - - //if there is nothing to render in terms of pixels, - //just bag it right here. - - if ((pixrect.width == 0) || (pixrect.height == 0)) - break; - - if (!translucent) - RenderView(curview, *mOffScreenCX, localrect, *currect, clipstate); - else - { - if (trans) - { - mRedCX->SetColor(NS_RGB(255, 0, 0)); - mRedCX->FillRect(blendrect); -#ifdef SHOW_RECTS - mRedCX->SetColor(NS_RGB(255 - evenodd, evenodd, 255 - evenodd)); - mRedCX->DrawLine(blendrect.x, blendrect.y, blendrect.x + blendrect.width, blendrect.y + blendrect.height); + MOZ_TIMER_DEBUGLOG(("Start: nsViewManager::Refresh(region)\n")); + MOZ_TIMER_START(mWatch); #endif - } - RenderView(curview, *mRedCX, localrect, *currect, clipstate); + NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); - if (trans) - { - mBlueCX->SetColor(NS_RGB(0, 0, 255)); - mBlueCX->FillRect(blendrect); -#ifdef SHOW_RECTS - mBlueCX->SetColor(NS_RGB(255 - evenodd, evenodd, 255 - evenodd)); - mBlueCX->DrawLine(blendrect.x, blendrect.y, blendrect.x + blendrect.width, blendrect.y + blendrect.height); + mPainting = PR_TRUE; + + //force double buffering because of non-opaque views? + + //printf("refreshing rect... "); + //stdout << *rect; + //printf("\n"); + if (mTransCnt > 0) + aUpdateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; + +#ifdef NO_DOUBLE_BUFFER + aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER; #endif - RenderView(curview, *mBlueCX, localrect, *currect, clipstate); - } - if (nsnull == mBlender) - { - if (NS_OK == nsComponentManager::CreateInstance(kBlenderCID, nsnull, NS_GET_IID(nsIBlender), (void **)&mBlender)) - mBlender->Init(mContext); - } + if (nsnull == aContext) + { + localcx = getter_AddRefs(CreateRenderingContext(*aView)); - if (nsnull != mBlender) - mBlender->Blend(pixrect.x, pixrect.y, - pixrect.width, pixrect.height, - mRedCX, mOffScreenCX, - pixrect.x, pixrect.y, - opacity, trans ? mBlueCX : nsnull, - NS_RGB(255, 0, 0), NS_RGB(0, 0, 255)); - } - } - } + //couldn't get rendering context. this is ok if at startup + if (nsnull == localcx) { + mPainting = PR_FALSE; + return; + } + } else { + // plain assignment adds a ref + localcx = aContext; + } - break; + // notify the listeners. + if (nsnull != mCompositeListeners) { + PRUint32 listenerCount; + if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { + nsCOMPtr listener; + for (PRUint32 i = 0; i < listenerCount; i++) { + if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), getter_AddRefs(listener)))) { + listener->WillRefreshRect(this, aView, aContext, rect, aUpdateFlags); + } + } + } + } - default: - break; - } - } - else - { - if (state == BACK_TO_FRONT_OPACITY) - { - mOffScreenCX->SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - mRedCX->SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - mBlueCX->SetClipRect(*currect, nsClipCombine_kSubtract, clipstate); - } - else - aRC.SetClipRect(*currect, nsClipCombine_kSubtract, aResult); - } + if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) + { + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + widget->GetClientBounds(wrect); + brect = wrect; + wrect.x = wrect.y = 0; + ds = GetDrawingSurface(*localcx, wrect); + } + + nsRect trect = *rect; + + PRBool result; + + localcx->SetClipRect(trect, nsClipCombine_kReplace, result); + + RenderViews(aView, *localcx, trect, result); + + if ((aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) && ds) + localcx->CopyOffScreenBits(ds, wrect.x, wrect.y, wrect, NS_COPYBITS_USE_SOURCE_CLIP_REGION); + +#if 0 + // Subtract the area we just painted from the dirty region + nsIRegion* dirtyRegion; + aView->GetDirtyRegion(dirtyRegion); + + if ((nsnull != dirtyRegion) && !dirtyRegion->IsEmpty()) + { + nsRect pixrect = trect; + float t2p; + + mContext->GetAppUnitsToDevUnits(t2p); + + pixrect.ScaleRoundIn(t2p); + dirtyRegion->Subtract(pixrect.x, pixrect.y, pixrect.width, pixrect.height); + NS_RELEASE(dirtyRegion); + } +#endif + + mLastRefresh = PR_IntervalNow(); + + mPainting = PR_FALSE; + + // notify the listeners. + if (nsnull != mCompositeListeners) { + PRUint32 listenerCount; + if (NS_SUCCEEDED(mCompositeListeners->Count(&listenerCount))) { + nsCOMPtr listener; + for (PRUint32 i = 0; i < listenerCount; i++) { + if (NS_SUCCEEDED(mCompositeListeners->QueryElementAt(i, NS_GET_IID(nsICompositeListener), getter_AddRefs(listener)))) { + listener->DidRefreshRect(this, aView, aContext, rect, aUpdateFlags); + } + } + } + } + +#ifdef NS_VM_PERF_METRICS + MOZ_TIMER_DEBUGLOG(("Stop: nsViewManager::Refresh(region), this=%p\n", this)); + MOZ_TIMER_STOP(mWatch); + MOZ_TIMER_LOG(("vm2 Paint time (this=%p): ", this)); + MOZ_TIMER_PRINT(mWatch); +#endif +} + +// Perform a *stable* sort of the buffer by increasing Z-index. The common case is +// when many or all z-indices are equal and the list is mostly sorted; make sure +// that's fast (should be linear time if all z-indices are equal). +static void ApplyZOrderStableSort(nsVoidArray &aBuffer, nsVoidArray &aMergeTmp, PRInt32 aStart, PRInt32 aEnd) { + if (aEnd - aStart <= 6) { + // do a fast bubble sort for the small sizes + for (PRInt32 i = aEnd - 1; i > aStart; i--) { + PRBool sorted = PR_TRUE; + for (PRInt32 j = aStart; j < i; j++) { + DisplayListElement2* e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(j)); + DisplayListElement2* e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(j + 1)); + if (e1->mZIndex > e2->mZIndex) { + sorted = PR_FALSE; + aBuffer.ReplaceElementAt(e2, j); + aBuffer.ReplaceElementAt(e1, j + 1); } - - if (aResult == PR_TRUE) - break; + } + if (sorted) { + return; } } + } else { + // merge sort for the rest + PRInt32 mid = (aEnd + aStart)/2; - NS_ASSERTION((pushcnt >= 0), "underflow"); + ApplyZOrderStableSort(aBuffer, aMergeTmp, aStart, mid); + ApplyZOrderStableSort(aBuffer, aMergeTmp, mid, aEnd); - while (pushcnt-- > 0) - { - NS_ASSERTION((pushcnt >= 0), "underflow"); + DisplayListElement2* e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(mid - 1)); + DisplayListElement2* e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(mid)); - if (pushing == BACK_TO_FRONT_OPACITY) - { - mOffScreenCX->PopState(clipstate); - mRedCX->PopState(clipstate); - mBlueCX->PopState(clipstate); + // fast common case: the list is already completely sorted + if (e1->mZIndex <= e2->mZIndex) { + return; + } + // we have some merging to do. - // permanently remove any painted opaque views. - mOffScreenCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); - mRedCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); - mBlueCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); + PRInt32 i1 = aStart; + PRInt32 i2 = mid; + + e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i1)); + e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i2)); + while (i1 < mid || i2 < aEnd) { + if (i1 < mid && (i2 == aEnd || e1->mZIndex <= e2->mZIndex)) { + aMergeTmp.AppendElement(e1); + i1++; + if (i1 < mid) { + e1 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i1)); + } } else { - aRC.PopState(clipstate); - - // permanently remove any painted opaque views. - aRC.SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate); + aMergeTmp.AppendElement(e2); + i2++; + if (i2 < aEnd) { + e2 = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i2)); + } } } - switch (state) - { - case FRONT_TO_BACK_ACCUMULATE: - SET_STATE((transprop & (1 << TRANS_PROPERTY_OPACITY)) ? BACK_TO_FRONT_OPACITY : BACK_TO_FRONT_TRANS) + for (PRInt32 i = aStart; i < aEnd; i++) { + aBuffer.ReplaceElementAt(aMergeTmp.ElementAt(i - aStart), i); + } - if ((curflags & (POP_CLIP | PUSH_CLIP)) || (state == BACK_TO_FRONT_OPACITY)) - backstart = flatlen - DISPLAYLIST_INC; - else - { - backstart = flatlen - (DISPLAYLIST_INC << 1); + aMergeTmp.Clear(); + } +} - //render the bottom most view - RenderView(curview, aRC, aRect, *currect, aResult); - } +// The display-element (indirect) children of aNode are extracted and appended to aBuffer in +// z-order, with the bottom-most elements first. +// Their z-index is set to the z-index they will have in aNode's parent. +// I.e. if aNode's view has "z-index: auto", the nodes will keep their z-index, otherwise +// their z-indices will all be equal to the z-index value of aNode's view. +static void SortByZOrder(DisplayZTreeNode *aNode, nsVoidArray &aBuffer, nsVoidArray &aMergeTmp, PRBool aForceSort) { + PRBool autoZIndex = PR_TRUE; + PRInt32 explicitZIndex = 0; - //get a snapshot of the current clip so that we can exclude areas - //already excluded in it from the transparency region - aRC.GetClipRegion(&mRCRgn); - - if (!mOpaqueRgn->IsEmpty()) - useopaque = PR_TRUE; - - if (mTRgn) - { - PRInt32 x, y, w, h; - - mTransRgn->GetBoundingBox(&x, &y, &w, &h); - - mTRgn->SetTo(x, y, w, h); - mTRgn->Subtract(*mRCRgn); - - mTransRgn->Subtract(*mTRgn); - mTransRgn->GetBoundingBox(&x, &y, &w, &h); - - // permanently remove any opaque painted views. - mTransRgn->Subtract(*paintedRgn); - - aRC.SetClipRegion(*mTransRgn, nsClipCombine_kReplace, aResult); - - //did that finish everything? - if (aResult == PR_TRUE) - { - SET_STATE(COMPOSITION_DONE) - continue; - } - - mTransRgn->GetRects(&mTransRects); - - //see if it might be better to ignore the rects and just do everything as one operation... - - if ((state == BACK_TO_FRONT_TRANS) && - (mTransRects->mNumRects > 1) && - (mTransRects->mArea >= PRUint32(w * h * 0.9f))) - { - rectset = &onerect; - - rectset->mNumRects = 1; - - rectset->mRects[0].x = x; - rectset->mRects[0].y = y; - rectset->mRects[0].width = w; - rectset->mRects[0].height = h; - } - else - rectset = mTransRects; - - rgnrect = 0; - -#ifdef SHOW_RECTS - evenodd = 255 - evenodd; -#endif - } - //falls through - - case BACK_TO_FRONT_TRANS: - case BACK_TO_FRONT_OPACITY: - if (rgnrect > 0) - { - if (state == BACK_TO_FRONT_OPACITY) - { -#ifdef SHOW_RECTS - mOffScreenCX->SetColor(NS_RGB(255 - evenodd, evenodd, 255 - evenodd)); - mOffScreenCX->DrawRect(localrect); -#endif - mOffScreenCX->Translate(localrect.x, localrect.y); - mRedCX->Translate(localrect.x, localrect.y); - mBlueCX->Translate(localrect.x, localrect.y); - - //buffer swap. - aRC.CopyOffScreenBits(gOffScreen, 0, 0, localrect, NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); - } - else - { -#ifdef SHOW_RECTS - aRC.SetColor(NS_RGB(255 - evenodd, evenodd, 255 - evenodd)); - aRC.DrawRect(localrect); - -// for (int xxxxx = 0; xxxxx < 50000000; xxxxx++); -#endif - } - //if this is the last rect, we don't need to subtract it, cause - //we're done with this region. - if (rgnrect < (PRInt32)rectset->mNumRects) - aRC.SetClipRect(localrect, nsClipCombine_kSubtract, aResult); - } - - if (rgnrect < (PRInt32)rectset->mNumRects) - { - loopstart = backstart; - loopend = accumstart - DISPLAYLIST_INC; - increment = -DISPLAYLIST_INC; - - localrect.x = rectset->mRects[rgnrect].x; - localrect.y = rectset->mRects[rgnrect].y; - localrect.width = rectset->mRects[rgnrect].width; - localrect.height = rectset->mRects[rgnrect].height; - - if (state == BACK_TO_FRONT_OPACITY) - { - //prepare offscreen buffers - - if ((localrect.width > gBlendWidth) || (localrect.height > gBlendHeight)) - { - nsRect bitrect = nsRect(0, 0, localrect.width, localrect.height); - - NS_IF_RELEASE(mOffScreenCX); - NS_IF_RELEASE(mRedCX); - NS_IF_RELEASE(mBlueCX); - - if (nsnull != gOffScreen) - { - aRC.DestroyDrawingSurface(gOffScreen); - gOffScreen = nsnull; - } - - aRC.CreateDrawingSurface(&bitrect, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gOffScreen); - - if (nsnull != gRed) - { - aRC.DestroyDrawingSurface(gRed); - gRed = nsnull; - } - - aRC.CreateDrawingSurface(&bitrect, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gRed); - - if (nsnull != gBlue) - { - aRC.DestroyDrawingSurface(gBlue); - gBlue = nsnull; - } - - aRC.CreateDrawingSurface(&bitrect, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gBlue); - - gBlendWidth = localrect.width; - gBlendHeight = localrect.height; -//printf("offscr: %d, %d (%d, %d)\n", w, h, accumrect.width, accumrect.height); - } - - // bug 5062: recreate the local blending contexts if necessary, since global drawing surfaces may have - // been created while viewing another page, have to make sure local contexts exist. - if (mOffScreenCX == NULL) { - if (NS_OK == nsComponentManager::CreateInstance(kRenderingContextCID, nsnull, NS_GET_IID(nsIRenderingContext), (void **)&mOffScreenCX)) - mOffScreenCX->Init(mContext, gOffScreen); - } - if (mRedCX == NULL) { - if (NS_OK == nsComponentManager::CreateInstance(kRenderingContextCID, nsnull, NS_GET_IID(nsIRenderingContext), (void **)&mRedCX)) - mRedCX->Init(mContext, gRed); - } - if (mBlueCX == NULL) { - if (NS_OK == nsComponentManager::CreateInstance(kRenderingContextCID, nsnull, NS_GET_IID(nsIRenderingContext), (void **)&mBlueCX)) - mBlueCX->Init(mContext, gBlue); - } - - if ((nsnull == gOffScreen) || (nsnull == gRed)) - SET_STATE(BACK_TO_FRONT_TRANS) - } - -//printf("rect: %d %d %d %d\n", localrect.x, localrect.y, localrect.width, localrect.height); - localrect *= p2t; - rgnrect++; - - if (state == BACK_TO_FRONT_OPACITY) - { - mOffScreenCX->Translate(-localrect.x, -localrect.y); - mRedCX->Translate(-localrect.x, -localrect.y); - mBlueCX->Translate(-localrect.x, -localrect.y); - - mOffScreenCX->SetClipRect(localrect, nsClipCombine_kReplace, clipstate); - mRedCX->SetClipRect(localrect, nsClipCombine_kReplace, clipstate); - mBlueCX->SetClipRect(localrect, nsClipCombine_kReplace, clipstate); - } - } - else - { - if (useopaque) - { - mOpaqueRgn->Subtract(*mTransRgn); - - if (!mOpaqueRgn->IsEmpty()) - { - SET_STATE(FRONT_TO_BACK_CLEANUP) - - loopstart = accumstart; - loopend = flatlen; - increment = DISPLAYLIST_INC; - - mOpaqueRgn->GetBoundingBox(&localrect.x, &localrect.y, &localrect.width, &localrect.height); - - localrect *= p2t; - - // permanently remove any opaque painted views. - mOpaqueRgn->Subtract(*paintedRgn); - - aRC.SetClipRegion(*mOpaqueRgn, nsClipCombine_kReplace, aResult); - - //did that finish everything? - if (aResult == PR_TRUE) - SET_STATE(COMPOSITION_DONE) - - break; - } - } - - SET_STATE(COMPOSITION_DONE) - } - - break; - - default: - case FRONT_TO_BACK_CLEANUP: - case FRONT_TO_BACK_RENDER: - SET_STATE(COMPOSITION_DONE) - break; + if (nsnull != aNode->mView) { + aNode->mView->GetAutoZIndex(autoZIndex); + if (!autoZIndex) { + aNode->mView->GetZIndex(explicitZIndex); } } - if (nsnull != aRootView) - ComputeViewOffset(aRootView, nsnull, nsnull, 0); + if (nsnull == aNode->mZChild) { + if (nsnull != aNode->mDisplayElement) { + aBuffer.AppendElement(aNode->mDisplayElement); + aNode->mDisplayElement->mZIndex = explicitZIndex; + aNode->mDisplayElement = nsnull; + } + return; + } -#undef SET_STATE - -#else - - // Paint the view. The clipping rect was set above set don't clip again. - aRootView->Paint(aRC, aRect, NS_VIEW_FLAG_CLIP_SET, aResult); - -#endif -} - -void nsViewManager :: RenderView(nsIView *aView, nsIRenderingContext &aRC, const nsRect &aDamageRect, nsRect &aGlobalRect, PRBool &aResult) -{ - nsRect drect; - - NS_ASSERTION(!(nsnull == aView), "no view"); - - aRC.PushState(); - - aRC.Translate(aGlobalRect.x, aGlobalRect.y); - - drect.IntersectRect(aDamageRect, aGlobalRect); - - drect.x -= aGlobalRect.x; - drect.y -= aGlobalRect.y; - - aView->Paint(aRC, drect, NS_VIEW_FLAG_JUST_PAINT, aResult); - - aRC.PopState(aResult); -} - -void nsViewManager::UpdateDirtyViews(nsIView *aView, nsRect *aParentRect) const -{ - nsRect bounds; - aView->GetBounds(bounds); - - // translate parent rect into child coords. - nsRect parDamage; - if (nsnull != aParentRect) { - parDamage = *aParentRect; - parDamage.IntersectRect(bounds, parDamage); - parDamage.MoveBy(-bounds.x, -bounds.y); - } else - parDamage = bounds; - - if (PR_FALSE == parDamage.IsEmpty()) { - nsIWidget *widget; - aView->GetWidget(widget); - if (nsnull != widget) { - float scale; - nsRect pixrect = parDamage; - - mContext->GetAppUnitsToDevUnits(scale); - pixrect.ScaleRoundOut(scale); - -//printf("invalidating: view %x (pix) %d, %d\n", aView, pixrect.width, pixrect.height); - widget->Invalidate(pixrect, PR_FALSE); - - NS_RELEASE(widget); + DisplayZTreeNode *child; + PRInt32 childStartIndex = aBuffer.Count(); + for (child = aNode->mZChild; nsnull != child; child = child->mZSibling) { + SortByZOrder(child, aBuffer, aMergeTmp, PR_FALSE); + } + PRInt32 childEndIndex = aBuffer.Count(); + PRBool hasClip = PR_FALSE; + + if (childEndIndex - childStartIndex >= 2) { + DisplayListElement2* firstChild = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(childStartIndex)); + if (0 != (firstChild->mFlags & PUSH_CLIP) && firstChild->mView == aNode->mView) { + hasClip = PR_TRUE; } } - // Check our child views - nsIView *child; + if (hasClip) { + ApplyZOrderStableSort(aBuffer, aMergeTmp, childStartIndex + 1, childEndIndex - 1); + + if (autoZIndex && childEndIndex - childStartIndex >= 3) { + // If we're an auto-z-index, then we have to worry about the possibility that some of + // our children may be moved by the z-sorter beyond the bounds of the PUSH...POP clip + // instructions. So basically, we ensure that around every group of children of + // equal z-index, there is a PUSH...POP element pair with the same z-index. The stable + // z-sorter will not break up such a group. + // Note that if we're not an auto-z-index set, then our children will never be broken + // up so we don't need to do this. + // We also don't have to worry if we have no real children. + DisplayListElement2* ePush = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(childStartIndex)); + DisplayListElement2* eFirstChild = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(childStartIndex + 1)); - aView->GetChild(0, child); + ePush->mZIndex = eFirstChild->mZIndex; - while (nsnull != child) { - UpdateDirtyViews(child, &parDamage); - child->GetNextSibling(child); + DisplayListElement2* ePop = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(childEndIndex - 1)); + DisplayListElement2* eLastChild = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(childEndIndex - 2)); + + ePop->mZIndex = eLastChild->mZIndex; + + DisplayListElement2* e = eFirstChild; + for (PRInt32 i = childStartIndex + 1; i < childEndIndex - 2; i++) { + DisplayListElement2* eNext = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i + 1)); + NS_ASSERTION(e->mZIndex <= eNext->mZIndex, "Display Z-list is not sorted!!"); + if (e->mZIndex != eNext->mZIndex) { + // need to insert a POP for the last sequence and a PUSH for the next sequence + DisplayListElement2* newPop = new DisplayListElement2; + DisplayListElement2* newPush = new DisplayListElement2; + + *newPop = *ePop; + newPop->mZIndex = e->mZIndex; + *newPush = *ePush; + newPush->mZIndex = eNext->mZIndex; + aBuffer.InsertElementAt(newPop, i + 1); + aBuffer.InsertElementAt(newPush, i + 2); + i += 2; + childEndIndex += 2; + } + e = eNext; + } + } + } else if (aForceSort || !autoZIndex) { + ApplyZOrderStableSort(aBuffer, aMergeTmp, childStartIndex, childEndIndex); } + + if (!autoZIndex) { + for (PRInt32 i = childStartIndex; i < childEndIndex; i++) { + DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, aBuffer.ElementAt(i)); + element->mZIndex = explicitZIndex; + } + } +} + +static void PushStateAndClip(nsIRenderingContext **aRCs, PRInt32 aRCCount, nsRect &aRect, + PRInt32 aDX, PRInt32 aDY) { + PRBool clipEmpty; + nsRect rect = aRect; + for (PRInt32 i = 0; i < aRCCount; i++) { + aRCs[i]->PushState(); + if (i == 1) { + rect.x -= aDX; + rect.y -= aDY; + } + aRCs[i]->SetClipRect(rect, nsClipCombine_kIntersect, clipEmpty); + } +} + +static void PopState(nsIRenderingContext **aRCs, PRInt32 aRCCount) { + PRBool clipEmpty; + for (PRInt32 i = 0; i < aRCCount; i++) { + aRCs[i]->PopState(clipEmpty); + } +} + +void nsViewManager::RenderViews(nsIView *aRootView, nsIRenderingContext& aRC, const nsRect& aRect, PRBool &aResult) +{ + // compute this view's origin + nsPoint origin(0, 0); + ComputeViewOffset(aRootView, &origin); + + nsIView *displayRoot = aRootView; + for (;;) { + // Mark the view as a parent of the rendered view. + displayRoot->SetCompositorFlags(IS_PARENT_OF_REFRESHED_VIEW); + + nsIView *displayParent = nsnull; + displayRoot->GetParent(displayParent); + + if (nsnull == displayParent) { + break; + } + PRBool isFloating = PR_FALSE; + displayRoot->GetFloating(isFloating); + PRBool isParentFloating = PR_FALSE; + displayParent->GetFloating(isParentFloating); + + if (isFloating && !isParentFloating) { + break; + } + displayRoot = displayParent; + + nsRect bounds; + displayRoot->GetBounds(bounds); + } + + DisplayZTreeNode *zTree; + + // We accumulate the bounds of widgets obscuring aRootView's widget into mOpaqueRgn. + // In OptimizeDisplayList, display list elements which lie behind obscuring native + // widgets are dropped. + if (nsnull != mOpaqueRgn) { + mOpaqueRgn->SetTo(0, 0, 0, 0); + } + + nsPoint displayRootOrigin(0, 0); + ComputeViewOffset(displayRoot, &displayRootOrigin); + + // Create the Z-ordered view tree + CreateDisplayList(displayRoot, PR_FALSE, zTree, PR_FALSE, origin.x, origin.y, + aRootView, &aRect, nsnull, displayRootOrigin.x, displayRootOrigin.y); + mMapPlaceholderViewToZTreeNode.Reset(); + + if (nsnull != zTree) { + // Apply proper Z-order handling + nsAutoVoidArray mergeTmp; + + SortByZOrder(zTree, mDisplayList, mergeTmp, PR_TRUE); + // This builds the display list in reverse order to the way the old + // nsViewManager did it. C'est la vie, it's easier this way. + } + + mDisplayListCount = mDisplayList.Count(); + + DestroyZTreeNode(zTree); + + nsRect fakeClipRect; + PRInt32 index = 0; + PRBool anyRendered; + ReapplyClipInstructions(PR_FALSE, fakeClipRect, index); + + OptimizeDisplayList(aRect); + + // initialize various counters. These are updated in OptimizeDisplayListClipping. + mTranslucentViewCount = 0; + mTranslucentArea.SetRect(0, 0, 0, 0); + + index = 0; + OptimizeDisplayListClipping(PR_FALSE, fakeClipRect, index, anyRendered); + + // We keep a list of all the rendering contexts whose clip rects + // need to be updated. + nsIRenderingContext* RCList[4]; + PRInt32 RCCount = 1; + RCList[0] = &aRC; + + // create blending buffers, if necessary. + if (mTranslucentViewCount > 0) { + nsresult rv = CreateBlendingBuffers(aRC); + NS_ASSERTION((rv == NS_OK), "not enough memory to blend"); + if (NS_FAILED(rv)) { + // fall back by just rendering with transparency. + mTranslucentViewCount = 0; + for (PRInt32 i = mDisplayListCount - 1; i>= 0; --i) { + DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(i)); + element->mFlags &= ~VIEW_TRANSLUCENT; + } + } else { + RCCount = 4; + RCList[1] = mBlackCX; + RCList[2] = mWhiteCX; + RCList[3] = mOffScreenCX; + } + + // DEBUGGING: fill in complete offscreen image in green, to see if we've got a blending bug. + //mOffScreenCX->SetColor(NS_RGB(0, 255, 0)); + //mOffScreenCX->FillRect(nsRect(0, 0, gOffScreenSize.width, gOffScreenSize.height)); + } + + // draw all views in the display list, from back to front. + for (PRInt32 i = 0; i < mDisplayListCount; i++) { + DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(i)); + if (element->mFlags & VIEW_RENDERED) { + // typical case, just rendering a view. + // RenderView(element->mView, aRC, aRect, element->mBounds, aResult); + if (element->mFlags & VIEW_CLIPPED) { + //Render the view using the clip rect set by it's ancestors + PushStateAndClip(RCList, RCCount, element->mBounds, mTranslucentArea.x, mTranslucentArea.y); + RenderDisplayListElement(element, aRC); + PopState(RCList, RCCount); + } else { + RenderDisplayListElement(element, aRC); + } + + } else { + // special case, pushing or popping clipping. + if (element->mFlags & PUSH_CLIP) { + PushStateAndClip(RCList, RCCount, element->mBounds, mTranslucentArea.x, mTranslucentArea.y); + } else { + if (element->mFlags & POP_CLIP) { + PopState(RCList, RCCount); + } + } + } + + delete element; + } + + // flush bits back to screen. + // Must flush back when no clipping is in effect. + if (mTranslucentViewCount > 0) { + // DEBUG: is this getting through? + // mOffScreenCX->SetColor(NS_RGB(0, 0, 0)); + // mOffScreenCX->DrawRect(nsRect(0, 0, mTranslucentArea.width, mTranslucentArea.height)); + aRC.CopyOffScreenBits(gOffScreen, 0, 0, mTranslucentArea, + NS_COPYBITS_XFORM_DEST_VALUES | + NS_COPYBITS_TO_BACK_BUFFER); + // DEBUG: what rectangle are we blitting? + // aRC.SetColor(NS_RGB(0, 0, 0)); + // aRC.DrawRect(mTranslucentArea); + } + + mDisplayList.Clear(); + + nsIView *marker = aRootView; + while (marker != nsnull) { + // Mark the view with specified flags. + marker->SetCompositorFlags(0); + marker->GetParent(marker); + } +} + +void nsViewManager::RenderView(nsIView *aView, nsIRenderingContext &aRC, const nsRect &aDamageRect, nsRect &aGlobalRect, PRBool &aResult) +{ + nsRect drect; + + NS_ASSERTION((nsnull != aView), "no view"); + + aRC.PushState(); + + aRC.Translate(aGlobalRect.x, aGlobalRect.y); + + drect.IntersectRect(aDamageRect, aGlobalRect); + + drect.x -= aGlobalRect.x; + drect.y -= aGlobalRect.y; + + // should use blender here if opacity < 1.0 + + aView->Paint(aRC, drect, NS_VIEW_FLAG_JUST_PAINT, aResult); + + aRC.PopState(aResult); +} + +void nsViewManager::RenderDisplayListElement(DisplayListElement2* element, nsIRenderingContext &aRC) +{ + PRBool isTranslucent = (element->mFlags & VIEW_TRANSLUCENT) != 0; + PRBool clipEmpty; + if (!isTranslucent) { + aRC.PushState(); + + nscoord x = element->mAbsX, y = element->mAbsY; + aRC.Translate(x, y); + + nsRect drect(element->mBounds.x - x, element->mBounds.y - y, + element->mBounds.width, element->mBounds.height); + + element->mView->Paint(aRC, drect, NS_VIEW_FLAG_JUST_PAINT, clipEmpty); + + aRC.PopState(clipEmpty); + } + +#if defined(SUPPORT_TRANSLUCENT_VIEWS) + if (mTranslucentViewCount > 0 && (isTranslucent || mTranslucentArea.Intersects(element->mBounds))) { + // transluscency case. if this view is transluscent, have to use the nsIBlender, otherwise, just + // render in the offscreen. when we reach the last transluscent view, then we flush the bits + // to the onscreen rendering context. + + // compute the origin of the view, relative to the offscreen buffer, which has the + // same dimensions as mTranslucentArea. + nscoord x = element->mAbsX, y = element->mAbsY; + nscoord viewX = x - mTranslucentArea.x, viewY = y - mTranslucentArea.y; + + nsRect damageRect(element->mBounds); + damageRect.IntersectRect(damageRect, mTranslucentArea); + // -> coordinates relative to element->mView origin + damageRect.x -= x, damageRect.y -= y; + + if (element->mFlags & VIEW_TRANSLUCENT) { + nsIView* view = element->mView; + + // paint the view twice, first in the black buffer, then the white; + // the blender will pick up the touched pixels only. + PaintView(view, *mBlackCX, viewX, viewY, damageRect); + // DEBUGGING ONLY + //aRC.CopyOffScreenBits(gBlack, 0, 0, element->mBounds, + // NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); + + PaintView(view, *mWhiteCX, viewX, viewY, damageRect); + // DEBUGGING ONLY + //aRC.CopyOffScreenBits(gWhite, 0, 0, element->mBounds, + // NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); + //mOffScreenCX->CopyOffScreenBits(gWhite, 0, 0, nsRect(viewX, viewY, damageRect.width, damageRect.height), + // NS_COPYBITS_XFORM_DEST_VALUES | NS_COPYBITS_TO_BACK_BUFFER); + + float opacity; + view->GetOpacity(opacity); + + // -> coordinates relative to mTranslucentArea origin + damageRect.x += viewX, damageRect.y += viewY; + + // perform the blend itself. + nsRect damageRectInPixels = damageRect; + damageRectInPixels *= mTwipsToPixels; + if (damageRectInPixels.width > 0 && damageRectInPixels.height > 0) { + mBlender->Blend(damageRectInPixels.x, damageRectInPixels.y, + damageRectInPixels.width, damageRectInPixels.height, + mBlackCX, mOffScreenCX, + damageRectInPixels.x, damageRectInPixels.y, + opacity, mWhiteCX, + NS_RGB(0, 0, 0), NS_RGB(255, 255, 255)); + } + + // Set the contexts back to their default colors + // We do that here because we know that whatever the clip region is, + // everything we just painted is within the clip region so we are + // sure to be able to overwrite it now. + mBlackCX->SetColor(NS_RGB(0, 0, 0)); + mBlackCX->FillRect(damageRect); + mWhiteCX->SetColor(NS_RGB(255, 255, 255)); + mWhiteCX->FillRect(damageRect); + } else { + PaintView(element->mView, *mOffScreenCX, viewX, viewY, damageRect); + } + } +#endif +} + +void nsViewManager::PaintView(nsIView *aView, nsIRenderingContext &aRC, nscoord x, nscoord y, + const nsRect &aDamageRect) +{ + aRC.PushState(); + aRC.Translate(x, y); + PRBool unused; + aView->Paint(aRC, aDamageRect, NS_VIEW_FLAG_JUST_PAINT, unused); + aRC.PopState(unused); +} + +inline PRInt32 nextPowerOf2(PRInt32 value) +{ + PRInt32 result = 1; + while (value > result) + result <<= 1; + return result; +} + +static nsresult NewOffscreenContext(nsIDeviceContext* deviceContext, nsDrawingSurface surface, + const nsSize& size, nsIRenderingContext* *aResult) +{ + nsresult rv; + nsIRenderingContext* context; + rv = nsComponentManager::CreateInstance(kRenderingContextCID, nsnull, + NS_GET_IID(nsIRenderingContext), + (void **)&context); + if (NS_FAILED(rv)) + return rv; + rv = context->Init(deviceContext, surface); + if (NS_FAILED(rv)) + return rv; + + // always initialize clipping, linux won't draw images otherwise. + PRBool clipEmpty; + nsRect clip(0, 0, size.width, size.height); + context->SetClipRect(clip, nsClipCombine_kReplace, clipEmpty); + + *aResult = context; + return NS_OK; +} + +nsresult nsViewManager::CreateBlendingBuffers(nsIRenderingContext &aRC) +{ + nsresult rv; + + // create a blender, if none exists already. + if (nsnull == mBlender) { + rv = nsComponentManager::CreateInstance(kBlenderCID, nsnull, NS_GET_IID(nsIBlender), (void **)&mBlender); + if (NS_FAILED(rv)) + return rv; + rv = mBlender->Init(mContext); + if (NS_FAILED(rv)) + return rv; + } + + // ensure that the global drawing surfaces are large enough. + if (mTranslucentArea.width > gOffScreenSize.width || mTranslucentArea.height > gOffScreenSize.height) { + nsRect offscreenBounds(0, 0, mTranslucentArea.width, mTranslucentArea.height); + offscreenBounds.ScaleRoundOut(mTwipsToPixels); + offscreenBounds.width = nextPowerOf2(offscreenBounds.width); + offscreenBounds.height = nextPowerOf2(offscreenBounds.height); + + NS_IF_RELEASE(mOffScreenCX); + NS_IF_RELEASE(mBlackCX); + NS_IF_RELEASE(mWhiteCX); + + if (nsnull != gOffScreen) { + aRC.DestroyDrawingSurface(gOffScreen); + gOffScreen = nsnull; + } + rv = aRC.CreateDrawingSurface(&offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gOffScreen); + if (NS_FAILED(rv)) + return rv; + + if (nsnull != gBlack) { + aRC.DestroyDrawingSurface(gBlack); + gBlack = nsnull; + } + aRC.CreateDrawingSurface(&offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gBlack); + if (NS_FAILED(rv)) + return rv; + + if (nsnull != gWhite) { + aRC.DestroyDrawingSurface(gWhite); + gWhite = nsnull; + } + aRC.CreateDrawingSurface(&offscreenBounds, NS_CREATEDRAWINGSURFACE_FOR_PIXEL_ACCESS, gWhite); + if (NS_FAILED(rv)) + return rv; + + offscreenBounds.ScaleRoundIn(mPixelsToTwips); + gOffScreenSize.width = offscreenBounds.width; + gOffScreenSize.height = offscreenBounds.height; + } + + // recreate local offscreen & blending contexts, if necessary. + if (mOffScreenCX == nsnull) { + rv = NewOffscreenContext(mContext, gOffScreen, gOffScreenSize, &mOffScreenCX); + if (NS_FAILED(rv)) + return rv; + } + if (mBlackCX == nsnull) { + rv = NewOffscreenContext(mContext, gBlack, gOffScreenSize, &mBlackCX); + if (NS_FAILED(rv)) + return rv; + } + if (mWhiteCX == nsnull) { + rv = NewOffscreenContext(mContext, gWhite, gOffScreenSize, &mWhiteCX); + if (NS_FAILED(rv)) + return rv; + } + + nsRect fillArea = mTranslucentArea; + fillArea.x = 0; + fillArea.y = 0; + + mBlackCX->SetColor(NS_RGB(0, 0, 0)); + mBlackCX->FillRect(fillArea); + mWhiteCX->SetColor(NS_RGB(255, 255, 255)); + mWhiteCX->FillRect(fillArea); + + return NS_OK; } void nsViewManager::ProcessPendingUpdates(nsIView* aView) @@ -1466,18 +1495,18 @@ void nsViewManager::ProcessPendingUpdates(nsIView* aView) } } -NS_IMETHODIMP nsViewManager :: Composite() +NS_IMETHODIMP nsViewManager::Composite() { - if (mUpdateCnt > 0) - { - if (nsnull != mRootWindow) - mRootWindow->Update(); + if (mUpdateCnt > 0) + { + if (nsnull != mRootWindow) + mRootWindow->Update(); - mUpdateCnt = 0; - PauseTimer(); - } + mUpdateCnt = 0; + PauseTimer(); + } - return NS_OK; + return NS_OK; } NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags) @@ -1489,81 +1518,175 @@ NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags) return UpdateView(aView, bounds, aUpdateFlags); } + +// Invalidate all widgets which overlap the view, other than the view's own widgets. +NS_IMETHODIMP +nsViewManager::UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY) +{ + nsPoint origin(0, 0); + ComputeViewOffset(aView, &origin); + nsRect damageRect; + aView->GetBounds(damageRect); + damageRect.x = origin.x; + damageRect.y = origin.y; + + // if this is a floating view, it isn't covered by any widgets other than + // its children, which are handled by the widget scroller. + PRBool viewIsFloating = PR_FALSE; + aView->GetFloating(viewIsFloating); + if (viewIsFloating) { + return NS_OK; + } + + UpdateAllCoveringWidgets(mRootView, aView, damageRect); + Composite(); + return NS_OK; +} + +// Returns true if this view's widget(s) completely cover the rectangle +// The specified rectangle, relative to aView, is invalidated in every widget child of aView. +// If non-null, aTarget and its children are ignored and only widgets above aTarget's widget +// in Z-order are invalidated (if possible). +PRBool nsViewManager::UpdateAllCoveringWidgets(nsIView *aView, nsIView *aTarget, nsRect &aDamagedRect) +{ + if (aView == aTarget) { + return PR_TRUE; + } + + nsRect bounds; + aView->GetBounds(bounds); + bounds.x = 0; // aDamagedRect is already in this view's coordinate system + bounds.y = 0; + PRBool overlap = bounds.IntersectRect(bounds, aDamagedRect); + + if (!overlap) { + return PR_FALSE; + } + + PRBool hasWidget = PR_FALSE; + aView->HasWidget(&hasWidget); + PRBool covering = PR_FALSE; + + if (hasWidget && bounds == aDamagedRect) { + covering = PR_TRUE; + } + + nsIView* childView = nsnull; + aView->GetChild(0, childView); + PRBool childCovers = PR_FALSE; + while (nsnull != childView) { + nsRect childRect = bounds; + nsRect childBounds; + childView->GetBounds(childBounds); + childRect.x -= childBounds.x; + childRect.y -= childBounds.y; + if (UpdateAllCoveringWidgets(childView, aTarget, childRect)) { + childCovers = PR_TRUE; + // we can't stop here. We're not making any assumptions about how the child + // widgets are z-ordered, and we can't risk failing to invalidate the top-most + // one. + } + childView->GetNextSibling(childView); + } + + if (hasWidget && !childCovers) { + ++mUpdateCnt; + + if (!mRefreshEnabled) { + // accumulate this rectangle in the view's dirty region, so we can process it later. + AddRectToDirtyRegion(aView, bounds); + } else { + float t2p; + mContext->GetAppUnitsToDevUnits(t2p); + bounds.ScaleRoundOut(t2p); + + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + widget->Invalidate(bounds, PR_FALSE); + } + } + + return covering || childCovers; +} + NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags) { NS_PRECONDITION(nsnull != aView, "null view"); + // Only Update the rectangle region of the rect that intersects the view's non clipped rectangle + nsRect clippedRect; + PRBool isClipped; + PRBool isEmpty; + aView->GetClippedRect(clippedRect, isClipped, isEmpty); + if (isEmpty) { + return NS_OK; + } + + nsRect damagedRect; + damagedRect.x = aRect.x; + damagedRect.y = aRect.y; + damagedRect.width = aRect.width; + damagedRect.height = aRect.height; + clippedRect.x = 0; + clippedRect.y = 0; + damagedRect.IntersectRect(aRect, clippedRect); + // If the rectangle is not visible then abort // without invalidating. This is a performance // enhancement since invalidating a native widget // can be expensive. - if (! IsRectVisible(aView, aRect)) { + // This also checks for silly request like damagedRect.width = 0 or damagedRect.height = 0 + if (! IsRectVisible(aView, damagedRect)) { return NS_OK; } + // if this is a floating view, it isn't covered by any widgets other than + // its children. In that case we walk up to its parent widget and use + // that as the root to update from. This also means we update areas that + // may be outside the parent view(s), which is necessary for floaters. + PRBool viewIsFloating = PR_FALSE; + aView->GetFloating(viewIsFloating); + if (viewIsFloating) { + nsIView* widgetParent = aView; + PRBool hasWidget = PR_FALSE; + widgetParent->HasWidget(&hasWidget); + + while (!hasWidget) { + nsRect bounds; + widgetParent->GetBounds(bounds); + damagedRect.x += bounds.x; + damagedRect.y += bounds.y; + + widgetParent->GetParent(widgetParent); + widgetParent->HasWidget(&hasWidget); + } + + UpdateAllCoveringWidgets(widgetParent, nsnull, damagedRect); + } else { + nsPoint origin(damagedRect.x, damagedRect.y); + ComputeViewOffset(aView, &origin); + damagedRect.x = origin.x; + damagedRect.y = origin.y; + + UpdateAllCoveringWidgets(mRootView, nsnull, damagedRect); + } + + ++mUpdateCnt; + if (!mRefreshEnabled) { - // accumulate this rectangle in the view's dirty region, so we can process it later. - if (aRect.width != 0 && aRect.height != 0) { - AddRectToDirtyRegion(aView, aRect); - ++mUpdateCnt; - } return NS_OK; } - // Ignore any silly requests... - if ((aRect.width == 0) || (aRect.height == 0)) - return NS_OK; - - // is this view even visible? - nsViewVisibility visibility; - aView->GetVisibility(visibility); - if (visibility == nsViewVisibility_kHide) - return NS_OK; - - // Find the nearest view (including this view) that has a widget - nsIView *widgetView = GetWidgetView(aView); - if (nsnull != widgetView) { - if (0 == mUpdateCnt) - RestartTimer(); - - mUpdateCnt++; - -#if 0 - // Transform damaged rect to widgetView's coordinate system. - nsRect widgetRect = aRect; - nsIView *parentView = aView; - while (parentView != widgetView) { - nscoord x, y; - parentView->GetPosition(&x, &y); - widgetRect.x += x; - widgetRect.y += y; - parentView->GetParent(parentView); - } - - // Add this rect to the widgetView's dirty region. - if (nsnull != widgetView) - UpdateDirtyViews(widgetView, &widgetRect); -#else - // Go ahead and invalidate the entire rectangular area. - // regardless of parentage. - nsRect widgetRect = aRect; - ViewToWidget(aView, widgetView, widgetRect); - nsCOMPtr widget; - widgetView->GetWidget(*getter_AddRefs(widget)); - widget->Invalidate(widgetRect, PR_FALSE); -#endif - - // See if we should do an immediate refresh or wait - if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { - Composite(); - } else if ((mTrueFrameRate > 0) && !(aUpdateFlags & NS_VMREFRESH_NO_SYNC)) { - // or if a sync paint is allowed and it's time for the compositor to - // do a refresh - PRInt32 deltams = PR_IntervalToMilliseconds(PR_IntervalNow() - mLastRefresh); - if (deltams > (1000 / (PRInt32)mTrueFrameRate)) - Composite(); - } - } + // See if we should do an immediate refresh or wait + if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { + Composite(); + } else if ((mTrueFrameRate > 0) && !(aUpdateFlags & NS_VMREFRESH_NO_SYNC)) { + // or if a sync paint is allowed and it's time for the compositor to + // do a refresh + PRInt32 deltams = PR_IntervalToMilliseconds(PR_IntervalNow() - mLastRefresh); + if (deltams > (1000 / (PRInt32)mTrueFrameRate)) + Composite(); + } return NS_OK; } @@ -1588,365 +1711,402 @@ void nsViewManager::UpdateViews(nsIView *aView, PRUint32 aUpdateFlags) } } -NS_IMETHODIMP nsViewManager :: DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aStatus) +NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aStatus) { - *aStatus = nsEventStatus_eIgnore; + *aStatus = nsEventStatus_eIgnore; - switch(aEvent->message) - { - case NS_SIZE: - { - nsIView* view = nsView::GetViewFor(aEvent->widget); + switch(aEvent->message) + { + case NS_SIZE: + { + nsIView* view = nsView::GetViewFor(aEvent->widget); - if (nsnull != view) - { - nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width; - nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height; - width = ((nsSizeEvent*)aEvent)->mWinWidth; - height = ((nsSizeEvent*)aEvent)->mWinHeight; + if (nsnull != view) + { + nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width; + nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height; + width = ((nsSizeEvent*)aEvent)->mWinWidth; + height = ((nsSizeEvent*)aEvent)->mWinHeight; - // The root view may not be set if this is the resize associated with - // window creation + // The root view may not be set if this is the resize associated with + // window creation - if (view == mRootView) - { - // Convert from pixels to twips - float p2t; - mContext->GetDevUnitsToAppUnits(p2t); + if (view == mRootView) + { + // Convert from pixels to twips + float p2t; + mContext->GetDevUnitsToAppUnits(p2t); -//printf("resize: (pix) %d, %d\n", width, height); - SetWindowDimensions(NSIntPixelsToTwips(width, p2t), - NSIntPixelsToTwips(height, p2t)); - *aStatus = nsEventStatus_eConsumeNoDefault; - } - } + //printf("resize: (pix) %d, %d\n", width, height); + SetWindowDimensions(NSIntPixelsToTwips(width, p2t), + NSIntPixelsToTwips(height, p2t)); + *aStatus = nsEventStatus_eConsumeNoDefault; + } + } - break; - } + break; + } - case NS_PAINT: - { - nsIView *view = nsView::GetViewFor(aEvent->widget); + case NS_PAINT: + { + nsIView *view = nsView::GetViewFor(aEvent->widget); - if (nsnull != view) - { - // The rect is in device units, and it's in the coordinate space of its - // associated window. - nsRect damrect = *((nsPaintEvent*)aEvent)->rect; + if (nsnull != view) + { + // The rect is in device units, and it's in the coordinate space of its + // associated window. + nsRect damrect = *((nsPaintEvent*)aEvent)->rect; - float p2t; - mContext->GetDevUnitsToAppUnits(p2t); - damrect.ScaleRoundOut(p2t); + float p2t; + mContext->GetDevUnitsToAppUnits(p2t); + damrect.ScaleRoundOut(p2t); - // Do an immediate refresh - if (nsnull != mContext) - { - nsRect viewrect; - float varea; + // Do an immediate refresh + if (nsnull != mContext) + { + nsRect viewrect; + float varea; - // Check that there's actually something to paint - view->GetBounds(viewrect); - viewrect.x = viewrect.y = 0; - varea = (float)viewrect.width * viewrect.height; + // Check that there's actually something to paint + view->GetBounds(viewrect); + viewrect.x = viewrect.y = 0; + varea = (float)viewrect.width * viewrect.height; - if (varea > 0.0000001f) - { - // nsRect arearect; - PRUint32 updateFlags = 0; + if (varea > 0.0000001f) + { + // nsRect arearect; + PRUint32 updateFlags = 0; - // Auto double buffering logic. - // See if the paint region is greater than .25 the area of our view. - // If so, enable double buffered painting. + // Auto double buffering logic. + // See if the paint region is greater than .25 the area of our view. + // If so, enable double buffered painting. - // XXX These two lines cause a lot of flicker for drag-over re-drawing - rods - //arearect.IntersectRect(damrect, viewrect); + // XXX These two lines cause a lot of flicker for drag-over re-drawing - rods + //arearect.IntersectRect(damrect, viewrect); - //if ((((float)arearect.width * arearect.height) / varea) > 0.25f) - // XXX rods - updateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; + //if ((((float)arearect.width * arearect.height) / varea) > 0.25f) + // XXX rods + updateFlags |= NS_VMREFRESH_DOUBLE_BUFFER; -//printf("refreshing: view: %x, %d, %d, %d, %d\n", view, trect.x, trect.y, trect.width, trect.height); - // Refresh the view - Refresh(view, ((nsPaintEvent*)aEvent)->renderingContext, &damrect, updateFlags); - } - } + //printf("refreshing: view: %x, %d, %d, %d, %d\n", view, damrect.x, damrect.y, damrect.width, damrect.height); + // Refresh the view + Refresh(view, ((nsPaintEvent*)aEvent)->renderingContext, &damrect, updateFlags); + } + } - *aStatus = nsEventStatus_eConsumeNoDefault; - } + *aStatus = nsEventStatus_eConsumeNoDefault; + } - break; - } + break; + } - case NS_DESTROY: - *aStatus = nsEventStatus_eConsumeNoDefault; - break; + case NS_DESTROY: + *aStatus = nsEventStatus_eConsumeNoDefault; + break; - default: - { - nsIView* baseView; - nsIView* view; - nsPoint offset; - nsIScrollbar* sb; + default: + { + nsIView* baseView; + nsIView* view; + nsPoint offset; + nsIScrollbar* sb; - //Find the view whose coordinates system we're in. - baseView = nsView::GetViewFor(aEvent->widget); + //Find the view whose coordinates system we're in. + baseView = nsView::GetViewFor(aEvent->widget); - //Find the view to which we're initially going to send the event - //for hittesting. - if (nsnull != mMouseGrabber && NS_IS_MOUSE_EVENT(aEvent)) { - view = mMouseGrabber; - } - else if (nsnull != mKeyGrabber && NS_IS_KEY_EVENT(aEvent)) { - view = mKeyGrabber; - } - else if (NS_OK == aEvent->widget->QueryInterface(NS_GET_IID(nsIScrollbar), (void**)&sb)) { - view = baseView; - NS_RELEASE(sb); - } - else { - view = mRootView; - } + //Find the view to which we're initially going to send the event + //for hittesting. + if (nsnull != mMouseGrabber && (NS_IS_MOUSE_EVENT(aEvent) || NS_IS_DRAG_EVENT(aEvent))) { + view = mMouseGrabber; + } + else if (nsnull != mKeyGrabber && NS_IS_KEY_EVENT(aEvent)) { + view = mKeyGrabber; + } + else if (NS_OK == aEvent->widget->QueryInterface(NS_GET_IID(nsIScrollbar), (void**)&sb)) { + view = baseView; + NS_RELEASE(sb); + } + else { + view = mRootView; + } - if (nsnull != view) { - //Calculate the proper offset for the view we're going to - offset.x = offset.y = 0; - if (baseView != view) { - //Get offset from root of baseView - nsIView *parent; - nsRect bounds; + if (nsnull != view) { + //Calculate the proper offset for the view we're going to + offset.x = offset.y = 0; + if (baseView != view) { + //Get offset from root of baseView + nsIView *parent; + nsRect bounds; - parent = baseView; - while (nsnull != parent) { - parent->GetBounds(bounds); - offset.x += bounds.x; - offset.y += bounds.y; - parent->GetParent(parent); - } + parent = baseView; + while (nsnull != parent) { + parent->GetBounds(bounds); + offset.x += bounds.x; + offset.y += bounds.y; + parent->GetParent(parent); + } - //Subtract back offset from root of view - parent = view; - while (nsnull != parent) { - parent->GetBounds(bounds); - offset.x -= bounds.x; - offset.y -= bounds.y; - parent->GetParent(parent); - } + //Subtract back offset from root of view + parent = view; + while (nsnull != parent) { + parent->GetBounds(bounds); + offset.x -= bounds.x; + offset.y -= bounds.y; + parent->GetParent(parent); + } - } + } - //Dispatch the event - float p2t, t2p; + //Dispatch the event + float p2t, t2p; - mContext->GetDevUnitsToAppUnits(p2t); - mContext->GetAppUnitsToDevUnits(t2p); + mContext->GetDevUnitsToAppUnits(p2t); + mContext->GetAppUnitsToDevUnits(t2p); - //Before we start mucking with coords, make sure we know our baseline - aEvent->refPoint.x = aEvent->point.x; - aEvent->refPoint.y = aEvent->point.y; + //Before we start mucking with coords, make sure we know our baseline + aEvent->refPoint.x = aEvent->point.x; + aEvent->refPoint.y = aEvent->point.y; - aEvent->point.x = NSIntPixelsToTwips(aEvent->point.x, p2t); - aEvent->point.y = NSIntPixelsToTwips(aEvent->point.y, p2t); + aEvent->point.x = NSIntPixelsToTwips(aEvent->point.x, p2t); + aEvent->point.y = NSIntPixelsToTwips(aEvent->point.y, p2t); - aEvent->point.x += offset.x; - aEvent->point.y += offset.y; + aEvent->point.x += offset.x; + aEvent->point.y += offset.y; - PRBool handled = PR_FALSE; - view->HandleEvent(aEvent, NS_VIEW_FLAG_CHECK_CHILDREN | - NS_VIEW_FLAG_CHECK_PARENT | - NS_VIEW_FLAG_CHECK_SIBLINGS, - aStatus, - PR_TRUE, - handled); + PRBool handled = PR_FALSE; + view->HandleEvent(aEvent, NS_VIEW_FLAG_CHECK_CHILDREN | + NS_VIEW_FLAG_CHECK_PARENT | + NS_VIEW_FLAG_CHECK_SIBLINGS, + aStatus, + PR_TRUE, + handled); - aEvent->point.x -= offset.x; - aEvent->point.y -= offset.y; + aEvent->point.x -= offset.x; + aEvent->point.y -= offset.y; - aEvent->point.x = NSTwipsToIntPixels(aEvent->point.x, t2p); - aEvent->point.y = NSTwipsToIntPixels(aEvent->point.y, t2p); + aEvent->point.x = NSTwipsToIntPixels(aEvent->point.x, t2p); + aEvent->point.y = NSTwipsToIntPixels(aEvent->point.y, t2p); - // - // if the event is an nsTextEvent, we need to map the reply back into platform coordinates - // - if (aEvent->message==NS_TEXT_EVENT) { - ((nsTextEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.x, t2p); - ((nsTextEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.y, t2p); - ((nsTextEvent*)aEvent)->theReply.mCursorPosition.width=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.width, t2p); - ((nsTextEvent*)aEvent)->theReply.mCursorPosition.height=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.height, t2p); - } - if((aEvent->message==NS_COMPOSITION_START) || - (aEvent->message==NS_COMPOSITION_QUERY)) { - ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x,t2p); - ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y,t2p); - ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width,t2p); - ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height,t2p); - } - } + // + // if the event is an nsTextEvent, we need to map the reply back into platform coordinates + // + if (aEvent->message==NS_TEXT_EVENT) { + ((nsTextEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.x, t2p); + ((nsTextEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.y, t2p); + ((nsTextEvent*)aEvent)->theReply.mCursorPosition.width=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.width, t2p); + ((nsTextEvent*)aEvent)->theReply.mCursorPosition.height=NSTwipsToIntPixels(((nsTextEvent*)aEvent)->theReply.mCursorPosition.height, t2p); + } + if((aEvent->message==NS_COMPOSITION_START) || + (aEvent->message==NS_COMPOSITION_QUERY)) { + ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x,t2p); + ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y,t2p); + ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.width,t2p); + ((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.height,t2p); + } + } - break; - } - } + break; + } + } - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: GrabMouseEvents(nsIView *aView, PRBool &aResult) +NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult) { - mMouseGrabber = aView; - aResult = PR_TRUE; - return NS_OK; -} - -NS_IMETHODIMP nsViewManager :: GrabKeyEvents(nsIView *aView, PRBool &aResult) -{ - mKeyGrabber = aView; - aResult = PR_TRUE; - return NS_OK; -} - -NS_IMETHODIMP nsViewManager :: GetMouseEventGrabber(nsIView *&aView) -{ - aView = mMouseGrabber; - return NS_OK; -} - -NS_IMETHODIMP nsViewManager :: GetKeyEventGrabber(nsIView *&aView) -{ - aView = mKeyGrabber; - return NS_OK; -} - -NS_IMETHODIMP nsViewManager :: InsertChild(nsIView *parent, nsIView *child, nsIView *sibling, - PRBool above) -{ - NS_PRECONDITION(nsnull != parent, "null ptr"); - NS_PRECONDITION(nsnull != child, "null ptr"); - - if ((nsnull != parent) && (nsnull != child)) +#ifdef DEBUG_mjudge + if (aView) { - nsIView *kid; - nsIView *prev = nsnull; - - //verify that the sibling exists... - - parent->GetChild(0, kid); - - while (nsnull != kid) - { - if (kid == sibling) - break; - - //get the next sibling view - - prev = kid; - kid->GetNextSibling(kid); - } - - if (nsnull != kid) - { - //it's there, so do the insertion - - if (PR_TRUE == above) - parent->InsertChild(child, prev); - else - parent->InsertChild(child, sibling); - } - - UpdateTransCnt(nsnull, child); - - // if the parent view is marked as "floating", make the newly added view float as well. - PRBool isFloating = PR_FALSE; - parent->GetFloating(isFloating); - child->SetFloating(isFloating); - - //and mark this area as dirty if the view is visible... - - nsViewVisibility visibility; - child->GetVisibility(visibility); - - if (nsViewVisibility_kHide != visibility) - UpdateView(child, NS_VMREFRESH_NO_SYNC); + printf("capturing mouse events for view %x\n",aView); } - return NS_OK; + printf("removing mouse capture from view %x\n",mMouseGrabber); +#endif + + mMouseGrabber = aView; + aResult = PR_TRUE; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: InsertZPlaceholder(nsIView *parent, nsIView *child, PRInt32 zindex) +NS_IMETHODIMP nsViewManager::GrabKeyEvents(nsIView *aView, PRBool &aResult) { - return NS_ERROR_NOT_IMPLEMENTED; + mKeyGrabber = aView; + aResult = PR_TRUE; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: InsertChild(nsIView *parent, nsIView *child, PRInt32 zindex) +NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView) { - NS_PRECONDITION(nsnull != parent, "null ptr"); - NS_PRECONDITION(nsnull != child, "null ptr"); + aView = mMouseGrabber; + return NS_OK; +} - if ((nsnull != parent) && (nsnull != child)) - { - nsIView *kid; - nsIView *prev = nsnull; +NS_IMETHODIMP nsViewManager::GetKeyEventGrabber(nsIView *&aView) +{ + aView = mKeyGrabber; + return NS_OK; +} - //find the right insertion point... +NS_IMETHODIMP nsViewManager::InsertChild(nsIView *parent, nsIView *child, nsIView *sibling, + PRBool above) +{ + NS_PRECONDITION(nsnull != parent, "null ptr"); + NS_PRECONDITION(nsnull != child, "null ptr"); - parent->GetChild(0, kid); + if ((nsnull != parent) && (nsnull != child)) + { + nsIView *kid; + nsIView *prev = nsnull; - while (nsnull != kid) + //verify that the sibling exists... + + parent->GetChild(0, kid); + + while (nsnull != kid) + { + if (kid == sibling) + break; + + //get the next sibling view + + prev = kid; + kid->GetNextSibling(kid); + } + + if (nsnull != kid) + { + //it's there, so do the insertion + + if (PR_TRUE == above) + parent->InsertChild(child, prev); + else + parent->InsertChild(child, sibling); + } + + UpdateTransCnt(nsnull, child); + + // if the parent view is marked as "floating", make the newly added view float as well. + PRBool isFloating = PR_FALSE; + parent->GetFloating(isFloating); + if (isFloating) + child->SetFloating(isFloating); + + //and mark this area as dirty if the view is visible... + + nsViewVisibility visibility; + child->GetVisibility(visibility); + + if (nsViewVisibility_kHide != visibility) + UpdateView(child, NS_VMREFRESH_NO_SYNC); + } + return NS_OK; +} + +NS_IMETHODIMP nsViewManager::InsertZPlaceholder(nsIView *parent, nsIView *child, PRInt32 zindex) +{ + NS_PRECONDITION(nsnull != parent, "null ptr"); + NS_PRECONDITION(nsnull != child, "null ptr"); + + if ((nsnull != parent) && (nsnull != child)) { - PRInt32 idx; + nsIView *kid; + nsIView *prev = nsnull; + + parent->GetChild(0, kid); + while (nsnull != kid) + { + PRInt32 idx; + kid->GetZIndex(idx); + + if (zindex >= idx) + break; + + prev = kid; + kid->GetNextSibling(kid); + } - kid->GetZIndex(idx); + nsZPlaceholderView* placeholder = new nsZPlaceholderView(parent); + placeholder->SetReparentedZChild(child); + child->SetZParent(placeholder); - if (zindex >= idx) - break; - - //get the next sibling view - - prev = kid; - kid->GetNextSibling(kid); + parent->InsertChild(placeholder, prev); } - - //in case this hasn't been set yet... maybe we should not do this? MMP - - child->SetZIndex(zindex); - parent->InsertChild(child, prev); - - UpdateTransCnt(nsnull, child); - - // if the parent view is marked as "floating", make the newly added view float as well. - PRBool isFloating = PR_FALSE; - parent->GetFloating(isFloating); - child->SetFloating(isFloating); - - //and mark this area as dirty if the view is visible... - nsViewVisibility visibility; - child->GetVisibility(visibility); - - if (nsViewVisibility_kHide != visibility) - UpdateView(child, NS_VMREFRESH_NO_SYNC); - } - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: RemoveChild(nsIView *parent, nsIView *child) +NS_IMETHODIMP nsViewManager::InsertChild(nsIView *parent, nsIView *child, PRInt32 zindex) { - NS_PRECONDITION(nsnull != parent, "null ptr"); - NS_PRECONDITION(nsnull != child, "null ptr"); + NS_PRECONDITION(nsnull != parent, "null ptr"); + NS_PRECONDITION(nsnull != child, "null ptr"); - if ((nsnull != parent) && (nsnull != child)) - { - UpdateTransCnt(child, nsnull); - UpdateView(child, NS_VMREFRESH_NO_SYNC); - parent->RemoveChild(child); - } + if ((nsnull != parent) && (nsnull != child)) + { + nsIView *kid; + nsIView *prev = nsnull; - return NS_OK; + //find the right insertion point... + + parent->GetChild(0, kid); + + while (nsnull != kid) + { + PRInt32 idx; + + kid->GetZIndex(idx); + + if (zindex >= idx) + break; + + //get the next sibling view + + prev = kid; + kid->GetNextSibling(kid); + } + + //in case this hasn't been set yet... maybe we should not do this? MMP + + child->SetZIndex(zindex); + parent->InsertChild(child, prev); + + UpdateTransCnt(nsnull, child); + + // if the parent view is marked as "floating", make the newly added view float as well. + PRBool isFloating = PR_FALSE; + parent->GetFloating(isFloating); + if (isFloating) + child->SetFloating(isFloating); + + //and mark this area as dirty if the view is visible... + nsViewVisibility visibility; + child->GetVisibility(visibility); + + if (nsViewVisibility_kHide != visibility) + UpdateView(child, NS_VMREFRESH_NO_SYNC); + } + return NS_OK; } -NS_IMETHODIMP nsViewManager :: MoveViewBy(nsIView *aView, nscoord aX, nscoord aY) +NS_IMETHODIMP nsViewManager::RemoveChild(nsIView *parent, nsIView *child) { - nscoord x, y; + NS_PRECONDITION(nsnull != parent, "null ptr"); + NS_PRECONDITION(nsnull != child, "null ptr"); - aView->GetPosition(&x, &y); - MoveViewTo(aView, aX + x, aY + y); - return NS_OK; + if ((nsnull != parent) && (nsnull != child)) + { + UpdateTransCnt(child, nsnull); + UpdateView(child, NS_VMREFRESH_NO_SYNC); + parent->RemoveChild(child); + } + + return NS_OK; +} + +NS_IMETHODIMP nsViewManager::MoveViewBy(nsIView *aView, nscoord aX, nscoord aY) +{ + nscoord x, y; + + aView->GetPosition(&x, &y); + MoveViewTo(aView, aX + x, aY + y); + return NS_OK; } NS_IMETHODIMP nsViewManager::MoveViewTo(nsIView *aView, nscoord aX, nscoord aY) @@ -1987,94 +2147,103 @@ NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, nscoord width, nscoord h else parentView = aView; - // resize the view. - aView->SetDimensions(width, height); + // resize the view. + nsViewVisibility visibility; + aView->GetVisibility(visibility); -#if 1 - // refresh the bounding box of old and new areas. - nscoord maxWidth = (oldWidth < width ? width : oldWidth); - nscoord maxHeight = (oldHeight < height ? height : oldHeight); - nsRect boundingArea(x, y, maxWidth, maxHeight); - UpdateView(parentView, boundingArea, NS_VMREFRESH_NO_SYNC); -#else - // brute force, invalidate old and new areas. I don't understand - // why just refreshing the bounding box is insufficient. - nsRect oldBounds(x, y, oldWidth, oldHeight); - UpdateView(parentView, oldBounds, NS_VMREFRESH_NO_SYNC); - UpdateView(parentView, NS_VMREFRESH_NO_SYNC); -#endif + // Prevent Invalidation of hidden views + if (visibility == nsViewVisibility_kHide) { + aView->SetDimensions(width, height, PR_FALSE); + } else { + aView->SetDimensions(width, height, PR_TRUE); + nscoord maxWidth = (oldWidth < width ? width : oldWidth); + nscoord maxHeight = (oldHeight < height ? height : oldHeight); + nsRect boundingArea(x, y, maxWidth, maxHeight); + UpdateView(parentView, boundingArea, NS_VMREFRESH_NO_SYNC); + } } return NS_OK; } -NS_IMETHODIMP nsViewManager :: SetViewChildClip(nsIView *aView, nsRect *aRect) +NS_IMETHODIMP nsViewManager::SetViewChildClip(nsIView *aView, nsRect *aRect) { - NS_ASSERTION(!(nsnull == aView), "no view"); - NS_ASSERTION(!(nsnull == aRect), "no clip"); + NS_ASSERTION(!(nsnull == aView), "no view"); + NS_ASSERTION(!(nsnull == aRect), "no clip"); - aView->SetChildClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost()); + aView->SetChildClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost()); - UpdateView(aView, *aRect, NS_VMREFRESH_NO_SYNC); + UpdateView(aView, *aRect, NS_VMREFRESH_NO_SYNC); - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: SetViewVisibility(nsIView *aView, nsViewVisibility aVisible) +NS_IMETHODIMP nsViewManager::SetViewVisibility(nsIView *aView, nsViewVisibility aVisible) { - nsViewVisibility oldVisible; - aView->GetVisibility(oldVisible); - if (aVisible != oldVisible) { - aView->SetVisibility(aVisible); - if (nsViewVisibility_kHide == aVisible) { - nsIView* parentView = nsnull; - aView->GetParent(parentView); - if (parentView) { - nsRect bounds; - aView->GetBounds(bounds); - UpdateView(parentView, bounds, NS_VMREFRESH_NO_SYNC); - } - } - else { - UpdateView(aView, NS_VMREFRESH_NO_SYNC); - } - } - return NS_OK; + nsViewVisibility oldVisible; + aView->GetVisibility(oldVisible); + if (aVisible != oldVisible) { + aView->SetVisibility(aVisible); + + PRBool hasWidget = PR_FALSE; + aView->HasWidget(&hasWidget); + if (!hasWidget) { + if (nsViewVisibility_kHide == aVisible) { + nsIView* parentView = nsnull; + aView->GetParent(parentView); + if (parentView) { + nsRect bounds; + aView->GetBounds(bounds); + UpdateView(parentView, bounds, NS_VMREFRESH_NO_SYNC); + } + } + else { + UpdateView(aView, NS_VMREFRESH_NO_SYNC); + } + } + } + return NS_OK; } -NS_IMETHODIMP nsViewManager :: SetViewZIndex(nsIView *aView, PRInt32 aZIndex) +NS_IMETHODIMP nsViewManager::SetViewZIndex(nsIView *aView, PRInt32 aZIndex) { - nsresult rv; + nsresult rv = NS_OK; - NS_ASSERTION(!(nsnull == aView), "no view"); + NS_ASSERTION((aView != nsnull), "no view"); - PRInt32 oldidx; +#if 0 + // a little hack to check out a theory: don't let floating views have any other z-index. + PRBool isFloating = PR_FALSE; + aView->GetFloating(isFloating); + if (isFloating) { + NS_ASSERTION((aZIndex == 0x7FFFFFFF), "floating view's z-index messed up"); + aZIndex = 0x7FFFFFFF; + } +#endif - aView->GetZIndex(oldidx); + PRInt32 oldidx; + aView->GetZIndex(oldidx); - if (oldidx != aZIndex) - { - nsIView *parent; + if (oldidx != aZIndex) { + nsIView *parent; + aView->GetParent(parent); + if (nsnull != parent) { + //we don't just call the view manager's RemoveChild() + //so that we can avoid two trips trough the UpdateView() + //code (one for removal, one for insertion). MMP + parent->RemoveChild(aView); + UpdateTransCnt(aView, nsnull); + rv = InsertChild(parent, aView, aZIndex); + } + } - aView->GetParent(parent); - - if (nsnull != parent) - { - //we don't just call the view manager's RemoveChild() - //so that we can avoid two trips trough the UpdateView() - //code (one for removal, one for insertion). MMP - - parent->RemoveChild(aView); - UpdateTransCnt(aView, nsnull); - rv = InsertChild(parent, aView, aZIndex); + nsIView* zParentView = nsnull; + aView->GetZParent(zParentView); + if (nsnull != zParentView) { + SetViewZIndex(zParentView, aZIndex); } - else - rv = NS_OK; - } - else - rv = NS_OK; - return rv; + return rv; } NS_IMETHODIMP nsViewManager::SetViewAutoZIndex(nsIView *aView, PRBool aAutoZIndex) @@ -2082,267 +2251,376 @@ NS_IMETHODIMP nsViewManager::SetViewAutoZIndex(nsIView *aView, PRBool aAutoZInde return aView->SetAutoZIndex(aAutoZIndex); } -NS_IMETHODIMP nsViewManager :: MoveViewAbove(nsIView *aView, nsIView *aOther) +NS_IMETHODIMP nsViewManager::MoveViewAbove(nsIView *aView, nsIView *aOther) { - nsresult rv; + nsresult rv; - NS_ASSERTION(!(nsnull == aView), "no view"); - NS_ASSERTION(!(nsnull == aOther), "no view"); + NS_ASSERTION(!(nsnull == aView), "no view"); + NS_ASSERTION(!(nsnull == aOther), "no view"); - nsIView *nextview; + nsIView *nextview; - aView->GetNextSibling(nextview); + aView->GetNextSibling(nextview); - if (nextview != aOther) - { - nsIView *parent; + if (nextview != aOther) + { + nsIView *parent; - aView->GetParent(parent); + aView->GetParent(parent); - if (nsnull != parent) - { - //we don't just call the view manager's RemoveChild() - //so that we can avoid two trips trough the UpdateView() - //code (one for removal, one for insertion). MMP + if (nsnull != parent) + { + //we don't just call the view manager's RemoveChild() + //so that we can avoid two trips trough the UpdateView() + //code (one for removal, one for insertion). MMP - parent->RemoveChild(aView); - UpdateTransCnt(aView, nsnull); - rv = InsertChild(parent, aView, aOther, PR_TRUE); - } - else - rv = NS_OK; - } - else - rv = NS_OK; + parent->RemoveChild(aView); + UpdateTransCnt(aView, nsnull); + rv = InsertChild(parent, aView, aOther, PR_TRUE); + } + else + rv = NS_OK; + } + else + rv = NS_OK; - return rv; + return rv; } -NS_IMETHODIMP nsViewManager :: MoveViewBelow(nsIView *aView, nsIView *aOther) +NS_IMETHODIMP nsViewManager::MoveViewBelow(nsIView *aView, nsIView *aOther) { - nsresult rv; + nsresult rv; - NS_ASSERTION(!(nsnull == aView), "no view"); - NS_ASSERTION(!(nsnull == aOther), "no view"); + NS_ASSERTION(!(nsnull == aView), "no view"); + NS_ASSERTION(!(nsnull == aOther), "no view"); - nsIView *nextview; + nsIView *nextview; - aOther->GetNextSibling(nextview); + aOther->GetNextSibling(nextview); - if (nextview != aView) - { - nsIView *parent; + if (nextview != aView) + { + nsIView *parent; - aView->GetParent(parent); + aView->GetParent(parent); - if (nsnull != parent) + if (nsnull != parent) + { + //we don't just call the view manager's RemoveChild() + //so that we can avoid two trips trough the UpdateView() + //code (one for removal, one for insertion). MMP + + parent->RemoveChild(aView); + UpdateTransCnt(aView, nsnull); + rv = InsertChild(parent, aView, aOther, PR_FALSE); + } + else + rv = NS_OK; + } + else + rv = NS_OK; + + return rv; +} + +NS_IMETHODIMP nsViewManager::IsViewShown(nsIView *aView, PRBool &aResult) +{ + aResult = PR_TRUE; + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsViewManager::GetViewClipAbsolute(nsIView *aView, nsRect *rect, PRBool &aResult) +{ + aResult = PR_TRUE; + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP nsViewManager::SetViewContentTransparency(nsIView *aView, PRBool aTransparent) +{ + PRBool trans; + + aView->HasTransparency(trans); + + if (trans != aTransparent) + { + UpdateTransCnt(aView, nsnull); + aView->SetContentTransparency(aTransparent); + UpdateTransCnt(nsnull, aView); + UpdateView(aView, NS_VMREFRESH_NO_SYNC); + } + + return NS_OK; +} + +NS_IMETHODIMP nsViewManager::SetViewOpacity(nsIView *aView, float aOpacity) +{ + float opacity; + + aView->GetOpacity(opacity); + + if (opacity != aOpacity) + { + UpdateTransCnt(aView, nsnull); + aView->SetOpacity(aOpacity); + UpdateTransCnt(nsnull, aView); + UpdateView(aView, NS_VMREFRESH_NO_SYNC); + } + + return NS_OK; +} + +NS_IMETHODIMP nsViewManager::SetViewObserver(nsIViewObserver *aObserver) +{ + mObserver = aObserver; + return NS_OK; +} + +NS_IMETHODIMP nsViewManager::GetViewObserver(nsIViewObserver *&aObserver) +{ + if (nsnull != mObserver) { + aObserver = mObserver; + NS_ADDREF(mObserver); + return NS_OK; + } else + return NS_ERROR_NO_INTERFACE; +} + +NS_IMETHODIMP nsViewManager::GetDeviceContext(nsIDeviceContext *&aContext) +{ + NS_IF_ADDREF(mContext); + aContext = mContext; + return NS_OK; +} + +void nsViewManager::GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const +{ + // Go through the list of viewmanagers and get the maximum width and + // height of their widgets + aMaxWidgetBounds.width = 0; + aMaxWidgetBounds.height = 0; + PRInt32 index = 0; + for (index = 0; index < mVMCount; index++) { + + nsIViewManager* vm = (nsIViewManager*)gViewManagers->ElementAt(index); + nsCOMPtr rootWidget; + + if(NS_SUCCEEDED(vm->GetWidget(getter_AddRefs(rootWidget))) && rootWidget) { - //we don't just call the view manager's RemoveChild() - //so that we can avoid two trips trough the UpdateView() - //code (one for removal, one for insertion). MMP - - parent->RemoveChild(aView); - UpdateTransCnt(aView, nsnull); - rv = InsertChild(parent, aView, aOther, PR_FALSE); + nsRect widgetBounds; + rootWidget->GetBounds(widgetBounds); + aMaxWidgetBounds.width = max(aMaxWidgetBounds.width, widgetBounds.width); + aMaxWidgetBounds.height = max(aMaxWidgetBounds.height, widgetBounds.height); } - else - rv = NS_OK; - } - else - rv = NS_OK; - - return rv; -} - -NS_IMETHODIMP nsViewManager :: IsViewShown(nsIView *aView, PRBool &aResult) -{ - aResult = PR_TRUE; - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP nsViewManager :: GetViewClipAbsolute(nsIView *aView, nsRect *rect, PRBool &aResult) -{ - aResult = PR_TRUE; - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP nsViewManager :: SetViewContentTransparency(nsIView *aView, PRBool aTransparent) -{ - PRBool trans; - - aView->HasTransparency(trans); - - if (trans != aTransparent) - { - UpdateTransCnt(aView, nsnull); - aView->SetContentTransparency(aTransparent); - UpdateTransCnt(nsnull, aView); - UpdateView(aView, NS_VMREFRESH_NO_SYNC); } - return NS_OK; +// printf("WIDGET BOUNDS %d %d\n", aMaxWidgetBounds.width, aMaxWidgetBounds.height); } -NS_IMETHODIMP nsViewManager :: SetViewOpacity(nsIView *aView, float aOpacity) +PRBool nsViewManager::RectFitsInside(nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const { - float opacity; + if (aRect.width > aWidth) + return (PR_FALSE); - aView->GetOpacity(opacity); + if (aRect.height > aHeight) + return (PR_FALSE); - if (opacity != aOpacity) - { - UpdateTransCnt(aView, nsnull); - aView->SetOpacity(aOpacity); - UpdateTransCnt(nsnull, aView); - UpdateView(aView, NS_VMREFRESH_NO_SYNC); + return PR_TRUE; +} + +PRBool nsViewManager::BothRectsFitInside(nsRect& aRect1, nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const +{ + if (PR_FALSE == RectFitsInside(aRect1, aWidth, aHeight)) { + return PR_FALSE; } - return NS_OK; -} - -NS_IMETHODIMP nsViewManager :: SetViewObserver(nsIViewObserver *aObserver) -{ - mObserver = aObserver; - return NS_OK; -} - -NS_IMETHODIMP nsViewManager :: GetViewObserver(nsIViewObserver *&aObserver) -{ - if (nsnull != mObserver) - { - aObserver = mObserver; - NS_ADDREF(mObserver); - return NS_OK; + if (PR_FALSE == RectFitsInside(aRect2, aWidth, aHeight)) { + return PR_FALSE; } - else - return NS_ERROR_NO_INTERFACE; + + aNewSize.width = aWidth; + aNewSize.height = aHeight; + + return PR_TRUE; } -NS_IMETHODIMP nsViewManager :: GetDeviceContext(nsIDeviceContext *&aContext) + +void nsViewManager::CalculateDiscreteSurfaceSize(nsRect& aRequestedSize, nsRect& aSurfaceSize) const { - NS_IF_ADDREF(mContext); - aContext = mContext; - return NS_OK; + nsRect aMaxWidgetSize; + GetMaxWidgetBounds(aMaxWidgetSize); + + // Get the height and width of the screen + PRInt32 height; + PRInt32 width; + NS_ASSERTION(mContext != nsnull, "The device context is null"); + mContext->GetDeviceSurfaceDimensions(width, height); + + float devUnits; + mContext->GetDevUnitsToAppUnits(devUnits); + PRInt32 screenHeight = NSToIntRound(float( height) / devUnits ); + PRInt32 screenWidth = NSToIntRound(float( width) / devUnits ); + + // These tests must go from smallest rectangle to largest rectangle. + + // 1/8 screen + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth / 8, screenHeight / 8, aSurfaceSize)) { + return; + } + + // 1/4 screen + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth / 4, screenHeight / 4, aSurfaceSize)) { + return; + } + + // 1/2 screen + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth / 2, screenHeight / 2, aSurfaceSize)) { + return; + } + + // 3/4 screen + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, (screenWidth * 3) / 4, (screenHeight * 3) / 4, aSurfaceSize)) { + return; + } + + // 3/4 screen width full screen height + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, (screenWidth * 3) / 4, screenHeight, aSurfaceSize)) { + return; + } + + // Full screen + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth, screenHeight, aSurfaceSize)) { + return; + } + + // Bigger than Full Screen use the largest request every made. + if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, gLargestRequestedSize.width, gLargestRequestedSize.height, aSurfaceSize)) { + return; + } else { + gLargestRequestedSize.width = PR_MAX(aRequestedSize.width, aMaxWidgetSize.width); + gLargestRequestedSize.height = PR_MAX(aRequestedSize.height, aMaxWidgetSize.height); + aSurfaceSize.width = gLargestRequestedSize.width; + aSurfaceSize.height = gLargestRequestedSize.height; + // printf("Expanding the largested requested size to %d %d\n", gLargestRequestedSize.width, gLargestRequestedSize.height); + } } -#ifndef max -#define max(a, b) ((a) < (b) ? (b) : (a)) -#endif +void nsViewManager::GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aNewSize) const +{ + CalculateDiscreteSurfaceSize(aRequestedSize, aNewSize); + aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); +} -nsDrawingSurface nsViewManager :: GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds) + +nsDrawingSurface nsViewManager::GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds) { - if ((nsnull == mDrawingSurface) - || (mDSBounds.width < aBounds.width) - || (mDSBounds.height < aBounds.height)) - { - nsRect newBounds; - newBounds.MoveTo(aBounds.x, aBounds.y); - newBounds.width = max(aBounds.width, mDSBounds.width); - newBounds.height = max(aBounds.height, mDSBounds.height); + nsRect newBounds; + GetDrawingSurfaceSize(aBounds, newBounds); - if (mDrawingSurface) { - //destroy existing DS - aContext.DestroyDrawingSurface(mDrawingSurface); - mDrawingSurface = nsnull; - } + if ((nsnull == mDrawingSurface) + || (mDSBounds.width != newBounds.width) + || (mDSBounds.height != newBounds.height)) + { + if (mDrawingSurface) { + //destroy existing DS + aContext.DestroyDrawingSurface(mDrawingSurface); + mDrawingSurface = nsnull; + } - nsresult rv = aContext.CreateDrawingSurface(&newBounds, 0, mDrawingSurface); - - if (NS_SUCCEEDED(rv)) { - mDSBounds = newBounds; + nsresult rv = aContext.CreateDrawingSurface(&newBounds, 0, mDrawingSurface); + // printf("Allocating a new drawing surface %d %d\n", newBounds.width, newBounds.height); + if (NS_SUCCEEDED(rv)) { + mDSBounds = newBounds; + aContext.SelectOffScreenDrawingSurface(mDrawingSurface); + } else { + mDSBounds.SetRect(0,0,0,0); + mDrawingSurface = nsnull; + } + } else { aContext.SelectOffScreenDrawingSurface(mDrawingSurface); - } - else { - mDSBounds.SetRect(0,0,0,0); - mDrawingSurface = nsnull; - } - } - else { - aContext.SelectOffScreenDrawingSurface(mDrawingSurface); - float p2t; - mContext->GetDevUnitsToAppUnits(p2t); - nsRect bounds = aBounds; - bounds *= p2t; + float p2t; + mContext->GetDevUnitsToAppUnits(p2t); + nsRect bounds = aBounds; + bounds *= p2t; - PRBool clipEmpty; - aContext.SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty); + PRBool clipEmpty; + aContext.SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty); - nscolor col = NS_RGB(255,255,255); - aContext.SetColor(col); - //aContext.FillRect(bounds); - } + // This is not be needed. Only the part of the offscreen that has been + // rendered to should be displayed so there no need to + // clear it out. + //nscolor col = NS_RGB(255,255,255); + //aContext.SetColor(col); + //aContext.FillRect(bounds); + } - return mDrawingSurface; + return mDrawingSurface; } -NS_IMETHODIMP nsViewManager :: ShowQuality(PRBool aShow) +NS_IMETHODIMP nsViewManager::ShowQuality(PRBool aShow) { - if (nsnull != mRootScrollable) - mRootScrollable->ShowQuality(aShow); + if (nsnull != mRootScrollable) + mRootScrollable->ShowQuality(aShow); - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: GetShowQuality(PRBool &aResult) +NS_IMETHODIMP nsViewManager::GetShowQuality(PRBool &aResult) { - if (nsnull != mRootScrollable) - mRootScrollable->GetShowQuality(aResult); + if (nsnull != mRootScrollable) + mRootScrollable->GetShowQuality(aResult); - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: SetQuality(nsContentQuality aQuality) +NS_IMETHODIMP nsViewManager::SetQuality(nsContentQuality aQuality) { - if (nsnull != mRootScrollable) - mRootScrollable->SetQuality(aQuality); + if (nsnull != mRootScrollable) + mRootScrollable->SetQuality(aQuality); - return NS_OK; + return NS_OK; } -nsIRenderingContext * nsViewManager :: CreateRenderingContext(nsIView &aView) +nsIRenderingContext * nsViewManager::CreateRenderingContext(nsIView &aView) { - nsIView *par = &aView; - nsIWidget *win; - nsIRenderingContext *cx = nsnull; - nscoord x, y, ax = 0, ay = 0; + nsIView *par = &aView; + nsCOMPtr win; + nsIRenderingContext *cx = nsnull; + nscoord x, y, ax = 0, ay = 0; - do - { - par->GetWidget(win); + do + { + par->GetWidget(*getter_AddRefs(win)); + if (nsnull != win) + break; - if (nsnull != win) - break; + //get absolute coordinates of view, but don't + //add in view pos since the first thing you ever + //need to do when painting a view is to translate + //the rendering context by the views pos and other parts + //of the code do this for us... - //get absolute coordinates of view, but don't - //add in view pos since the first thing you ever - //need to do when painting a view is to translate - //the rendering context by the views pos and other parts - //of the code do this for us... + if (par != &aView) + { + par->GetPosition(&x, &y); - if (par != &aView) - { - par->GetPosition(&x, &y); + ax += x; + ay += y; + } - ax += x; - ay += y; - } + par->GetParent(par); + } + while (nsnull != par); - par->GetParent(par); - } - while (nsnull != par); + if (nsnull != win) + { + mContext->CreateRenderingContext(&aView, cx); - if (nsnull != win) - { - mContext->CreateRenderingContext(&aView, cx); + if (nsnull != cx) + cx->Translate(ax, ay); + } - if (nsnull != cx) - cx->Translate(ax, ay); - - NS_RELEASE(win); - } - - return cx; + return cx; } void nsViewManager::AddRectToDirtyRegion(nsIView* aView, const nsRect &aRect) const @@ -2366,162 +2644,163 @@ void nsViewManager::AddRectToDirtyRegion(nsIView* aView, const nsRect &aRect) co void nsViewManager::UpdateTransCnt(nsIView *oldview, nsIView *newview) { - if (nsnull != oldview) - { - PRBool hasTransparency; - float opacity; + if (nsnull != oldview) + { + PRBool hasTransparency; + float opacity; - oldview->HasTransparency(hasTransparency); - oldview->GetOpacity(opacity); + oldview->HasTransparency(hasTransparency); + oldview->GetOpacity(opacity); - if (hasTransparency || (1.0f != opacity)) - mTransCnt--; - } + if (hasTransparency || (1.0f != opacity)) + mTransCnt--; + } - if (nsnull != newview) - { - PRBool hasTransparency; - float opacity; + if (nsnull != newview) + { + PRBool hasTransparency; + float opacity; - newview->HasTransparency(hasTransparency); - newview->GetOpacity(opacity); + newview->HasTransparency(hasTransparency); + newview->GetOpacity(opacity); - if (hasTransparency || (1.0f != opacity)) - mTransCnt++; - } + if (hasTransparency || (1.0f != opacity)) + mTransCnt++; + } } -NS_IMETHODIMP nsViewManager :: DisableRefresh(void) +NS_IMETHODIMP nsViewManager::DisableRefresh(void) { - if (mUpdateBatchCnt > 0) - return NS_OK; + if (mUpdateBatchCnt > 0) + return NS_OK; - mRefreshEnabled = PR_FALSE; - return NS_OK; + mRefreshEnabled = PR_FALSE; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: EnableRefresh(PRUint32 aUpdateFlags) +NS_IMETHODIMP nsViewManager::EnableRefresh(PRUint32 aUpdateFlags) { - if (mUpdateBatchCnt > 0) - return NS_OK; + if (mUpdateBatchCnt > 0) + return NS_OK; - mRefreshEnabled = PR_TRUE; + mRefreshEnabled = PR_TRUE; - if (mUpdateCnt > 0) - ProcessPendingUpdates(mRootView); + if (mUpdateCnt > 0) + ProcessPendingUpdates(mRootView); - if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { + if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE) { - if (mTrueFrameRate > 0) - { - PRInt32 deltams = PR_IntervalToMilliseconds(PR_IntervalNow() - mLastRefresh); + if (mTrueFrameRate > 0) + { + PRInt32 deltams = PR_IntervalToMilliseconds(PR_IntervalNow() - mLastRefresh); - if (deltams > (1000 / (PRInt32)mTrueFrameRate)) - Composite(); - } - } + if (deltams > (1000 / (PRInt32)mTrueFrameRate)) + Composite(); + } + } - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: BeginUpdateViewBatch(void) +NS_IMETHODIMP nsViewManager::BeginUpdateViewBatch(void) { - nsresult result = NS_OK; + nsresult result = NS_OK; - if (mUpdateBatchCnt == 0) - result = DisableRefresh(); + if (mUpdateBatchCnt == 0) + result = DisableRefresh(); - if (NS_SUCCEEDED(result)) - ++mUpdateBatchCnt; + if (NS_SUCCEEDED(result)) + ++mUpdateBatchCnt; - return result; + return result; } -NS_IMETHODIMP nsViewManager :: EndUpdateViewBatch(PRUint32 aUpdateFlags) +NS_IMETHODIMP nsViewManager::EndUpdateViewBatch(PRUint32 aUpdateFlags) { - nsresult result = NS_OK; + nsresult result = NS_OK; - --mUpdateBatchCnt; + --mUpdateBatchCnt; - NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!"); + NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!"); - if (mUpdateBatchCnt < 0) - { - mUpdateBatchCnt = 0; - return NS_ERROR_FAILURE; - } + if (mUpdateBatchCnt < 0) + { + mUpdateBatchCnt = 0; + return NS_ERROR_FAILURE; + } - if (mUpdateBatchCnt == 0) - result = EnableRefresh(aUpdateFlags); + if (mUpdateBatchCnt == 0) + result = EnableRefresh(aUpdateFlags); - return result; + return result; } -NS_IMETHODIMP nsViewManager :: SetRootScrollableView(nsIScrollableView *aScrollable) +NS_IMETHODIMP nsViewManager::SetRootScrollableView(nsIScrollableView *aScrollable) { - mRootScrollable = aScrollable; + mRootScrollable = aScrollable; - //XXX this needs to go away when layout start setting this bit on it's own. MMP - if (mRootScrollable) - mRootScrollable->SetScrollProperties(NS_SCROLL_PROPERTY_ALWAYS_BLIT); + //XXX this needs to go away when layout start setting this bit on it's own. MMP + if (mRootScrollable) + mRootScrollable->SetScrollProperties(NS_SCROLL_PROPERTY_ALWAYS_BLIT); - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: GetRootScrollableView(nsIScrollableView **aScrollable) +NS_IMETHODIMP nsViewManager::GetRootScrollableView(nsIScrollableView **aScrollable) { - *aScrollable = mRootScrollable; - return NS_OK; + *aScrollable = mRootScrollable; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: Display(nsIView* aView) +NS_IMETHODIMP nsViewManager::Display(nsIView* aView) { - nsIRenderingContext *localcx = nsnull; - nsRect trect; + nsIRenderingContext *localcx = nsnull; + nsRect trect; - if (PR_FALSE == mRefreshEnabled) - return NS_OK; + if (PR_FALSE == mRefreshEnabled) + return NS_OK; - NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); + NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted"); - mPainting = PR_TRUE; + mPainting = PR_TRUE; - mContext->CreateRenderingContext(localcx); + mContext->CreateRenderingContext(localcx); - //couldn't get rendering context. this is ok if at startup - if (nsnull == localcx) - { - mPainting = PR_FALSE; - return NS_ERROR_FAILURE; - } + //couldn't get rendering context. this is ok if at startup + if (nsnull == localcx) + { + mPainting = PR_FALSE; + return NS_ERROR_FAILURE; + } - aView->GetBounds(trect); - nscoord x = trect.x, y = trect.y; + aView->GetBounds(trect); + nscoord x = trect.x, y = trect.y; - // XXX Temporarily reset the position to (0, 0), that way when we paint - // we won't end up translating incorrectly - aView->SetPosition(0, 0); + // XXX Temporarily reset the position to (0, 0), that way when we paint + // we won't end up translating incorrectly + aView->SetPosition(0, 0); - PRBool result; + PRBool result; - trect.x = trect.y = 0; - localcx->SetClipRect(trect, nsClipCombine_kReplace, result); + trect.x = trect.y = 0; + localcx->SetClipRect(trect, nsClipCombine_kReplace, result); - // Paint the view. The clipping rect was set above set don't clip again. - aView->Paint(*localcx, trect, NS_VIEW_FLAG_CLIP_SET, result); + // Paint the view. The clipping rect was set above set don't clip again. + //aView->Paint(*localcx, trect, NS_VIEW_FLAG_CLIP_SET, result); + RenderViews(aView,*localcx,trect,result); - // XXX Reset the view's origin - aView->SetPosition(x, y); + // XXX Reset the view's origin + aView->SetPosition(x, y); - NS_RELEASE(localcx); + NS_RELEASE(localcx); - mPainting = PR_FALSE; + mPainting = PR_FALSE; - return NS_OK; + return NS_OK; } -NS_IMETHODIMP nsViewManager :: AddCompositeListener(nsICompositeListener* aListener) +NS_IMETHODIMP nsViewManager::AddCompositeListener(nsICompositeListener* aListener) { if (nsnull == mCompositeListeners) { nsresult rv = NS_NewISupportsArray(&mCompositeListeners); @@ -2531,7 +2810,7 @@ NS_IMETHODIMP nsViewManager :: AddCompositeListener(nsICompositeListener* aListe return mCompositeListeners->AppendElement(aListener); } -NS_IMETHODIMP nsViewManager :: RemoveCompositeListener(nsICompositeListener* aListener) +NS_IMETHODIMP nsViewManager::RemoveCompositeListener(nsICompositeListener* aListener) { if (nsnull != mCompositeListeners) { return mCompositeListeners->RemoveElement(aListener); @@ -2539,53 +2818,52 @@ NS_IMETHODIMP nsViewManager :: RemoveCompositeListener(nsICompositeListener* aLi return NS_ERROR_FAILURE; } - NS_IMETHODIMP nsViewManager::GetWidgetForView(nsIView *aView, nsIWidget **aWidget) { - *aWidget = nsnull; - nsIView *view = aView; - PRBool hasWidget = PR_FALSE; - while (!hasWidget && view) - { - view->HasWidget(&hasWidget); - if (!hasWidget) - view->GetParent(view); - } + *aWidget = nsnull; + nsIView *view = aView; + PRBool hasWidget = PR_FALSE; + while (!hasWidget && view) + { + view->HasWidget(&hasWidget); + if (!hasWidget) + view->GetParent(view); + } - if (hasWidget) { - // Widget was found in the view hierarchy - view->GetWidget(*aWidget); - } else { - // No widget was found in the view hierachy, so use try to use the mRootWindow - if (nsnull != mRootWindow) { + if (hasWidget) { + // Widget was found in the view hierarchy + view->GetWidget(*aWidget); + } else { + // No widget was found in the view hierachy, so use try to use the mRootWindow + if (nsnull != mRootWindow) { #ifdef NS_DEBUG - nsCOMPtr vm; - nsCOMPtr thisInstance(this); - aView->GetViewManager(*getter_AddRefs(vm)); - NS_ASSERTION(thisInstance == vm, "Must use the view instances view manager when calling GetWidgetForView"); + nsCOMPtr vm; + nsCOMPtr thisInstance(this); + aView->GetViewManager(*getter_AddRefs(vm)); + NS_ASSERTION(thisInstance == vm, "Must use the view instances view manager when calling GetWidgetForView"); #endif - *aWidget = mRootWindow; - NS_ADDREF(mRootWindow); - } - } + *aWidget = mRootWindow; + NS_ADDREF(mRootWindow); + } + } - return NS_OK; + return NS_OK; } NS_IMETHODIMP nsViewManager::GetWidget(nsIWidget **aWidget) { - NS_IF_ADDREF(mRootWindow); - *aWidget = mRootWindow; - return NS_OK; + NS_IF_ADDREF(mRootWindow); + *aWidget = mRootWindow; + return NS_OK; } NS_IMETHODIMP nsViewManager::ForceUpdate() { - if (mRootWindow) { - mRootWindow->Update(); - } - return NS_OK; + if (mRootWindow) { + mRootWindow->Update(); + } + return NS_OK; } NS_IMETHODIMP nsViewManager::GetOffset(nscoord *aX, nscoord *aY) @@ -2597,273 +2875,534 @@ NS_IMETHODIMP nsViewManager::GetOffset(nscoord *aX, nscoord *aY) return NS_OK; } +static nsresult EnsureZTreeNodeCreated(nsIView* aView, DisplayZTreeNode* &aNode) { + if (nsnull == aNode) { + aNode = new DisplayZTreeNode; -PRBool nsViewManager :: CreateDisplayList(nsIView *aView, PRInt32 *aIndex, - nscoord aOriginX, nscoord aOriginY, nsIView *aRealView, - const nsRect *aDamageRect, nsIView *aTopView, - nsVoidArray *aArray, nscoord aX, nscoord aY) -{ - PRInt32 numkids, zindex; - PRBool hasWidget, retval = PR_FALSE; - nsIClipView *clipper = nsnull; - nsPoint *point; - nsIView *child = nsnull; - - NS_ASSERTION(!(!aView), "no view"); - NS_ASSERTION(!(!aIndex), "no index"); - - if (!aArray) - { - if (!mDisplayList) - mDisplayList = new nsVoidArray(8); - - aArray = mDisplayList; - - if (!aArray) - return PR_TRUE; - } - - if (!aTopView) - aTopView = aView; - - nsRect lrect; - - aView->GetBounds(lrect); - - if (aView == aTopView) - { - lrect.x = 0; - lrect.y = 0; - } - - lrect.x += aX; - lrect.y += aY; - - aView->QueryInterface(NS_GET_IID(nsIClipView), (void **)&clipper); - aView->GetChildCount(numkids); - aView->GetScratchPoint(&point); - - hasWidget = DoesViewHaveNativeWidget(*aView); - - if (numkids > 0) - { - if (clipper && (!hasWidget || (hasWidget && point->x))) - { - lrect.x -= aOriginX; - lrect.y -= aOriginY; - - retval = AddToDisplayList(aArray, aIndex, aView, lrect, PUSH_CLIP); - - if (retval) - return retval; - - lrect.x += aOriginX; - lrect.y += aOriginY; + if (nsnull == aNode) { + return NS_ERROR_OUT_OF_MEMORY; } + aNode->mView = aView; + aNode->mDisplayElement = nsnull; + aNode->mZChild = nsnull; + aNode->mZSibling = nsnull; + } + return NS_OK; +} - if (!hasWidget || (hasWidget && point->x)) -// if ((aView == aTopView) || (aView == aRealView)) -// if ((aView == aTopView) || !hasWidget || (aView == aRealView)) -// if ((aView == aTopView) || !(hasWidget && clipper) || (aView == aRealView)) - { - for (aView->GetChild(0, child); nsnull != child; child->GetNextSibling(child)) - { - child->GetZIndex(zindex); - if (zindex < 0) - break; - retval = CreateDisplayList(child, aIndex, aOriginX, aOriginY, aRealView, aDamageRect, aTopView, aArray, lrect.x, lrect.y); - if (retval) - break; +PRBool nsViewManager::CreateDisplayList(nsIView *aView, PRBool aReparentedViewsPresent, + DisplayZTreeNode* &aResult, PRBool aInsideRealView, + nscoord aOriginX, nscoord aOriginY, nsIView *aRealView, + const nsRect *aDamageRect, nsIView *aTopView, + nscoord aX, nscoord aY) +{ + PRBool retval = PR_FALSE; + + aResult = nsnull; + + NS_ASSERTION((aView != nsnull), "no view"); + + if (!aTopView) + aTopView = aView; + + nsRect bounds; + aView->GetBounds(bounds); + + if (aView == aTopView) { + bounds.x = 0; + bounds.y = 0; + } + + // -> to global coordinates (relative to aTopView) + bounds.x += aX; + bounds.y += aY; + + // is this a clip view? + PRBool isClipView = IsClipView(aView); + PRBool overlap; + nsRect irect; + + // -> to refresh-frame coordinates (relative to aRealView) + bounds.x -= aOriginX; + bounds.y -= aOriginY; + if (aDamageRect) { + overlap = irect.IntersectRect(bounds, *aDamageRect); + if (isClipView) { + aDamageRect = &irect; } } - } - - lrect.x -= aOriginX; - lrect.y -= aOriginY; - -// if (clipper) - if (clipper && (!hasWidget || (hasWidget && point->x))) - { - if (numkids > 0) - retval = AddToDisplayList(aArray, aIndex, aView, lrect, POP_CLIP); - } - else if (!retval) - { - nsViewVisibility vis; - float opacity; - PRBool overlap; - PRBool trans; - nsRect irect; - - aView->GetVisibility(vis); - aView->GetOpacity(opacity); - aView->HasTransparency(trans); - - if (aDamageRect) - overlap = irect.IntersectRect(lrect, *aDamageRect); else overlap = PR_TRUE; - if ((nsViewVisibility_kShow == vis) && (opacity > 0.0f) && overlap) - { - retval = AddToDisplayList(aArray, aIndex, aView, lrect, 0); + // -> to global coordinates (relative to aTopView) + bounds.x += aOriginX; + bounds.y += aOriginY; - if (retval || !trans && (opacity == 1.0f) && (irect == *aDamageRect)) - retval = PR_TRUE; + if (!overlap && isClipView) { + return PR_FALSE; } - - // any children with negative z-indices? - if (!retval && nsnull != child) { - lrect.x += aOriginX; - lrect.y += aOriginY; - for (; nsnull != child; child->GetNextSibling(child)) { - retval = CreateDisplayList(child, aIndex, aOriginX, aOriginY, aRealView, aDamageRect, aTopView, aArray, lrect.x, lrect.y); - if (retval) + + if (!aReparentedViewsPresent) { + nsIView *childView = nsnull; + for (aView->GetChild(0, childView); nsnull != childView; childView->GetNextSibling(childView)) { + nsIView *zParent = nsnull; + childView->GetZParent(zParent); + if (nsnull != zParent) { + aReparentedViewsPresent = PR_TRUE; break; - } + } + } + + if (!overlap && !aReparentedViewsPresent) { + return PR_FALSE; + } } - } - - return retval; + + if (aInsideRealView && nsnull != mOpaqueRgn) { + PRBool hasWidget = PR_FALSE; + aView->HasWidget(&hasWidget); + if (hasWidget) { + mOpaqueRgn->Union(bounds.x - aOriginX, bounds.y - aOriginY, bounds.width, bounds.height); + } + } + + PRInt32 childCount; + nsIView *childView = nsnull; + aView->GetChildCount(childCount); + if (childCount > 0) { + if (isClipView) { + // -> to refresh-frame coordinates (relative to aRealView) + bounds.x -= aOriginX; + bounds.y -= aOriginY; + + retval = AddToDisplayList(aView, aResult, bounds, bounds, POP_CLIP, aX - aOriginX, aY - aOriginY); + + if (retval) + return retval; + + // -> to global coordinates (relative to aTopView) + bounds.x += aOriginX; + bounds.y += aOriginY; + } + + for (aView->GetChild(0, childView); nsnull != childView; childView->GetNextSibling(childView)) { + PRInt32 zindex; + childView->GetZIndex(zindex); + if (zindex < 0) + break; + + DisplayZTreeNode* createdNode; + retval = CreateDisplayList(childView, aReparentedViewsPresent, createdNode, + aInsideRealView || aRealView == aView, + aOriginX, aOriginY, aRealView, aDamageRect, aTopView, bounds.x, bounds.y); + if (createdNode != nsnull) { + EnsureZTreeNodeCreated(aView, aResult); + createdNode->mZSibling = aResult->mZChild; + aResult->mZChild = createdNode; + } + + if (retval) + break; + } + } + + if (!retval) { + if (overlap) { + // -> to refresh-frame coordinates (relative to aRealView) + bounds.x -= aOriginX; + bounds.y -= aOriginY; + + nsViewVisibility visibility; + float opacity; + PRBool transparent; + + aView->GetVisibility(visibility); + aView->GetOpacity(opacity); + aView->HasTransparency(transparent); + + if ((nsViewVisibility_kShow == visibility) && (opacity > 0.0f)) { + PRUint32 flags = VIEW_RENDERED; + if (transparent) + flags |= VIEW_TRANSPARENT; +#if defined(SUPPORT_TRANSLUCENT_VIEWS) + if (opacity < 1.0f) + flags |= VIEW_TRANSLUCENT; +#endif + retval = AddToDisplayList(aView, aResult, bounds, irect, flags, aX - aOriginX, aY - aOriginY); + } + + // -> to global coordinates (relative to aTopView) + bounds.x += aOriginX; + bounds.y += aOriginY; + } else { + PRUint32 compositorFlags = 0; + aView->GetCompositorFlags(&compositorFlags); + + if (0 != (compositorFlags & IS_Z_PLACEHOLDER_VIEW)) { + EnsureZTreeNodeCreated(aView, aResult); + mMapPlaceholderViewToZTreeNode.Put(new nsVoidKey(aView), aResult); + } + } + + // any children with negative z-indices? + if (!retval && nsnull != childView) { + for (; nsnull != childView; childView->GetNextSibling(childView)) { + DisplayZTreeNode* createdNode; + retval = CreateDisplayList(childView, aReparentedViewsPresent, createdNode, + aInsideRealView || aRealView == aView, + aOriginX, aOriginY, aRealView, aDamageRect, aTopView, bounds.x, bounds.y); + if (createdNode != nsnull) { + EnsureZTreeNodeCreated(aView, aResult); + createdNode->mZSibling = aResult->mZChild; + aResult->mZChild = createdNode; + } + + if (retval) + break; + } + } + } + + if (childCount > 0 && isClipView) { + // -> to refresh-frame coordinates (relative to aRealView) + bounds.x -= aOriginX; + bounds.y -= aOriginY; + + if (AddToDisplayList(aView, aResult, bounds, bounds, PUSH_CLIP, aX - aOriginX, aY - aOriginY)) { + retval = PR_TRUE; + } + } + + // Reparent any views that need reparenting in the Z-order tree + if (nsnull != aResult) { + DisplayZTreeNode* child; + DisplayZTreeNode** prev = &aResult->mZChild; + for (child = aResult->mZChild; nsnull != child; child = *prev) { + nsIView *zParent = nsnull; + if (nsnull != child->mView) { + child->mView->GetZParent(zParent); + } + if (nsnull != zParent) { + // unlink the child from the tree + *prev = child->mZSibling; + child->mZSibling = nsnull; + + nsVoidKey key(zParent); + DisplayZTreeNode* placeholder = (DisplayZTreeNode *)mMapPlaceholderViewToZTreeNode.Remove(&key); + + if (nsnull != placeholder) { + NS_ASSERTION((placeholder->mDisplayElement == nsnull), "placeholder already has elements?"); + NS_ASSERTION((placeholder->mZChild == nsnull), "placeholder already has Z-children?"); + placeholder->mDisplayElement = child->mDisplayElement; + placeholder->mView = child->mView; + placeholder->mZChild = child->mZChild; + delete child; + } else { + // the placeholder was never added to the display list ... + // we don't need to display, then + DestroyZTreeNode(child); + } + } else { + prev = &child->mZSibling; + } + } + } + + return retval; } -PRBool nsViewManager :: AddToDisplayList(nsVoidArray *aArray, PRInt32 *aIndex, nsIView *aView, nsRect &aRect, PRUint32 aFlags) +PRBool nsViewManager::AddToDisplayList(nsIView *aView, DisplayZTreeNode* &aParent, nsRect &aClipRect, nsRect& aDirtyRect, PRUint32 aFlags,nscoord aAbsX, nscoord aAbsY) { - PRInt32 index = (*aIndex)++; - DisplayListElement* element = (DisplayListElement*) mDisplayList->ElementAt(index); - if (element == nsnull) { - element = new DisplayListElement; + PRBool empty; + PRBool clipped; + nsRect clipRect; + + aView->GetClippedRect(clipRect, clipped, empty); + if (empty) { + return PR_FALSE; + } + clipRect.x += aAbsX; + clipRect.y += aAbsY; + + if (!clipped) { + clipRect = aClipRect; + } + + PRBool overlap = clipRect.IntersectRect(clipRect, aDirtyRect); + if (!overlap) { + return PR_FALSE; + } + + DisplayListElement2* element = new DisplayListElement2; if (element == nsnull) { - *aIndex = index; + return PR_TRUE; + } + DisplayZTreeNode* node = new DisplayZTreeNode; + if (nsnull == node) { + delete element; return PR_TRUE; } - mDisplayList->ReplaceElementAt(element, index); + + EnsureZTreeNodeCreated(aView, aParent); + + node->mDisplayElement = element; + node->mView = nsnull; + node->mZChild = nsnull; + node->mZSibling = aParent->mZChild; + aParent->mZChild = node; + + element->mView = aView; + element->mBounds = clipRect; + element->mAbsX = aClipRect.x; + element->mAbsY = aClipRect.y; + element->mFlags = aFlags; + if (clipped) { + element->mFlags |= VIEW_CLIPPED; + } + + return PR_FALSE; +} + +// Make sure that all PUSH_CLIP/POP_CLIP pairs are honored. +// They might not be because of the Z-reparenting mess: a fixed-position view might have +// created a display element with bounds that do not reflect the clipping instructions that now +// surround the element. This would cause problems in the optimizer. +void nsViewManager::ReapplyClipInstructions(PRBool aHaveClip, nsRect& aClipRect, PRInt32& aIndex) +{ + while (aIndex < mDisplayListCount) { + DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(aIndex)); + PRInt32 curIndex = aIndex; + aIndex++; + + if (element->mFlags & VIEW_RENDERED) { + if (aHaveClip && !element->mBounds.IntersectRect(aClipRect, element->mBounds)) { + element->mFlags &= ~VIEW_RENDERED; + } + } + + if (element->mFlags & PUSH_CLIP) { + nsRect newClip; + if (aHaveClip) { + newClip.IntersectRect(aClipRect, element->mBounds); + } else { + newClip = element->mBounds; + } + + ReapplyClipInstructions(PR_TRUE, newClip, aIndex); + } + + if (element->mFlags & POP_CLIP) { + return; + } + } +} + +// walk the display list, looking for opaque views, and remove any views that are behind them and totally occluded. +// We rely on a good region implementation. If nsIRegion doesn't cut it, we can disable this +// optimization ... or better still, fix nsIRegion on that platform. It seems to be good on Windows. +nsresult nsViewManager::OptimizeDisplayList(const nsRect& aDamageRect) +{ + if (nsnull == mOpaqueRgn || nsnull == mTmpRgn) { + return NS_OK; + } + + PRInt32 count = mDisplayListCount; + for (PRInt32 i = count - 1; i >= 0; i--) { + DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(i)); + if (element->mFlags & VIEW_RENDERED) { + mTmpRgn->SetTo(element->mBounds.x, element->mBounds.y, element->mBounds.width, element->mBounds.height); + mTmpRgn->Subtract(*mOpaqueRgn); + + if (mTmpRgn->IsEmpty()) { + element->mFlags &= ~VIEW_RENDERED; + } else { + mTmpRgn->GetBoundingBox(&element->mBounds.x, &element->mBounds.y, + &element->mBounds.width, &element->mBounds.height); + + // a view is opaque if it is neither transparent nor transluscent + if (!(element->mFlags & (VIEW_TRANSPARENT | VIEW_TRANSLUCENT))) { + mOpaqueRgn->Union(element->mBounds.x, element->mBounds.y, element->mBounds.width, element->mBounds.height); + } + } + } + } + + return NS_OK; +} + +// Remove redundant PUSH/POP_CLIP pairs. These could be expensive. +// We also count the translucent views and compute the translucency area in +// this pass. +void nsViewManager::OptimizeDisplayListClipping(PRBool aHaveClip, nsRect& aClipRect, PRInt32& aIndex, + PRBool& aAnyRendered) +{ + aAnyRendered = PR_FALSE; + + while (aIndex < mDisplayListCount) { + DisplayListElement2* element = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(aIndex)); + PRInt32 curIndex = aIndex; + aIndex++; + + if (element->mFlags & VIEW_RENDERED) { + // count number of translucent views, and + // accumulate a rectangle of all translucent + // views. this will be used to determine which + // views need to be rendered into the blending + // buffers. + if (element->mFlags & VIEW_TRANSLUCENT) { + if (mTranslucentViewCount++ == 0) { + mTranslucentArea = element->mBounds; + } else { + mTranslucentArea.UnionRect(mTranslucentArea, element->mBounds); + } + } + + aAnyRendered = PR_TRUE; + + if (aHaveClip && (element->mFlags & VIEW_CLIPPED)) { + nsRect newClip; + newClip.IntersectRect(aClipRect, element->mBounds); + // no need to clip if the clip rect doesn't change + if (newClip == aClipRect) { + element->mFlags &= ~VIEW_CLIPPED; + } + } + } + + if (element->mFlags & PUSH_CLIP) { + nsRect newClip; + if (aHaveClip) { + newClip.IntersectRect(aClipRect, element->mBounds); + } else { + newClip = element->mBounds; + } + + PRBool anyRenderedViews = PR_FALSE; + OptimizeDisplayListClipping(PR_TRUE, newClip, aIndex, anyRenderedViews); + DisplayListElement2* popElement = NS_STATIC_CAST(DisplayListElement2*, mDisplayList.ElementAt(aIndex - 1)); + NS_ASSERTION(popElement->mFlags & POP_CLIP, "Must end with POP!"); + + if (anyRenderedViews) { + aAnyRendered = PR_TRUE; + } + if (!anyRenderedViews || (aHaveClip && newClip == aClipRect)) { + // no need to clip if nothing's going to be rendered + // ... or if the clip rect didn't change + element->mFlags &= ~PUSH_CLIP; + popElement->mFlags &= ~POP_CLIP; + } + } + + if (element->mFlags & POP_CLIP) { + return; + } } - - element->mView = aView; - element->mClip = aRect; - element->mFlags = aFlags; - - return PR_FALSE; } void nsViewManager::ShowDisplayList(PRInt32 flatlen) { - char nest[400]; - PRInt32 newnestcnt, nestcnt = 0, cnt; + char nest[400]; + PRInt32 newnestcnt, nestcnt = 0, cnt; - for (cnt = 0; cnt < 400; cnt++) - nest[cnt] = ' '; + for (cnt = 0; cnt < 400; cnt++) + nest[cnt] = ' '; - float t2p; - mContext->GetAppUnitsToDevUnits(t2p); + float t2p; + mContext->GetAppUnitsToDevUnits(t2p); - printf("### display list length=%d ###\n", flatlen); + printf("### display list length=%d ###\n", flatlen); - for (cnt = 0; cnt < flatlen; cnt += DISPLAYLIST_INC) - { - nsIView *view, *parent; - nsRect rect; - PRUint32 flags; - PRInt32 zindex; + for (cnt = 0; cnt < flatlen; cnt++) { + nsIView *view, *parent; + nsRect rect; + PRUint32 flags; + PRInt32 zindex; - DisplayListElement* element = (DisplayListElement*) mDisplayList->ElementAt(cnt); - view = element->mView; - rect = element->mClip; - flags = element->mFlags; + DisplayListElement2* element = (DisplayListElement2*) mDisplayList.ElementAt(cnt); + view = element->mView; + rect = element->mBounds; + flags = element->mFlags; - nest[nestcnt << 1] = 0; + nest[nestcnt << 1] = 0; - view->GetParent(parent); - view->GetZIndex(zindex); - rect *= t2p; - printf("%snsIView@%p [z=%d, x=%d, y=%d, w=%d, h=%d, p=%p]\n", - nest, view, zindex, - rect.x, rect.y, rect.width, rect.height, parent); + view->GetParent(parent); + view->GetZIndex(zindex); + rect *= t2p; + printf("%snsIView@%p [z=%d, x=%d, y=%d, w=%d, h=%d, p=%p]\n", + nest, view, zindex, + rect.x, rect.y, rect.width, rect.height, parent); - newnestcnt = nestcnt; + newnestcnt = nestcnt; - if (flags) - { - printf("%s", nest); + if (flags) + { + printf("%s", nest); - if (flags & POP_CLIP) { - printf("POP_CLIP "); - newnestcnt--; - } + if (flags & POP_CLIP) { + printf("POP_CLIP "); + newnestcnt--; + } - if (flags & PUSH_CLIP) { - printf("PUSH_CLIP "); - newnestcnt++; - } + if (flags & PUSH_CLIP) { + printf("PUSH_CLIP "); + newnestcnt++; + } - if (flags & VIEW_INCLUDED) - printf("VIEW_INCLUDED "); + if (flags & VIEW_RENDERED) + printf("VIEW_RENDERED "); - printf("\n"); + printf("\n"); + } + + nest[nestcnt << 1] = ' '; + + nestcnt = newnestcnt; + } +} + +void nsViewManager::ComputeViewOffset(nsIView *aView, nsPoint *aOrigin) +{ + if (aOrigin) { + while (aView != nsnull) { + // compute the view's global position in the view hierarchy. + nsRect bounds; + aView->GetBounds(bounds); + aOrigin->x += bounds.x; + aOrigin->y += bounds.y; + + nsIView *parent; + aView->GetParent(parent); + aView = parent; + } } - - nest[nestcnt << 1] = ' '; - - nestcnt = newnestcnt; - } } -void nsViewManager :: ComputeViewOffset(nsIView *aView, nscoord *aX, nscoord *aY, PRInt32 aFlag) +PRBool nsViewManager::DoesViewHaveNativeWidget(nsIView* aView) { - nsIView *parent; - nsRect bounds; - nsPoint *point; - - aView->GetScratchPoint(&point); - - point->x = aFlag; - - aView->GetBounds(bounds); - - if (aX && aY) - { - *aX += bounds.x; - *aY += bounds.y; - } - - aView->GetParent(parent); - - if (parent) - ComputeViewOffset(parent, aX, aY, aFlag); + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + if (nsnull != widget) + return (nsnull != widget->GetNativeData(NS_NATIVE_WIDGET)); + return PR_FALSE; } -PRBool nsViewManager :: DoesViewHaveNativeWidget(nsIView &aView) +PRBool nsViewManager::IsClipView(nsIView* aView) { - nsIWidget *widget; - PRBool retval = PR_FALSE; - - aView.GetWidget(widget); - - if (nsnull != widget) - { - void *nativewidget; - - nativewidget = widget->GetNativeData(NS_NATIVE_WIDGET); - NS_RELEASE(widget); - - if (nsnull != nativewidget) - retval = PR_TRUE; - } - - return retval; + nsIClipView *clipView = nsnull; + nsresult rv = aView->QueryInterface(NS_GET_IID(nsIClipView), (void **)&clipView); + return (rv == NS_OK && clipView != nsnull); } -void nsViewManager :: PauseTimer(void) +void nsViewManager::PauseTimer(void) { - PRUint32 oldframerate = mTrueFrameRate; - SetFrameRate(0); - mTrueFrameRate = oldframerate; + PRUint32 oldframerate = mTrueFrameRate; + SetFrameRate(0); + mTrueFrameRate = oldframerate; } -void nsViewManager :: RestartTimer(void) +void nsViewManager::RestartTimer(void) { - SetFrameRate(mTrueFrameRate); + SetFrameRate(mTrueFrameRate); } nsIView* nsViewManager::GetWidgetView(nsIView *aView) const @@ -2899,7 +3438,6 @@ void nsViewManager::ViewToWidget(nsIView *aView, nsIView* aWidgetView, nsRect &a aRect.ScaleRoundOut(t2p); } - nsresult nsViewManager::GetVisibleRect(nsRect& aVisibleRect) { nsresult rv = NS_OK; @@ -2912,7 +3450,7 @@ nsresult nsViewManager::GetVisibleRect(nsRect& aVisibleRect) // Determine the visible rect in the scrolled view's coordinate space. // The size of the visible area is the clip view size const nsIView* clipView; - + scrollingView->GetScrollPosition(aVisibleRect.x, aVisibleRect.y); scrollingView->GetClipView(&clipView); clipView->GetDimensions(&aVisibleRect.width, &aVisibleRect.height); @@ -2956,6 +3494,17 @@ nsresult nsViewManager::GetAbsoluteRect(nsIView *aView, const nsRect &aRect, PRBool nsViewManager::IsRectVisible(nsIView *aView, const nsRect &aRect) { + if (aRect.width == 0 || aRect.height == 0) { + return PR_FALSE; + } + + // is this view even visible? + nsViewVisibility visibility; + aView->GetVisibility(visibility); + if (visibility == nsViewVisibility_kHide) { + return PR_FALSE; + } + // Calculate the absolute coordinates for the visible rectangle nsRect visibleRect; if (GetVisibleRect(visibleRect) == NS_ERROR_FAILURE) { @@ -2989,24 +3538,60 @@ PRBool nsViewManager::IsRectVisible(nsIView *aView, const nsRect &aRect) return overlaps; } + NS_IMETHODIMP nsViewManager::IsCachingWidgetChanges(PRBool* aCaching) { +#ifdef CACHE_WIDGET_CHANGES + *aCaching = (mCachingWidgetChanges > 0); +#else *aCaching = PR_FALSE; +#endif + return NS_OK; } NS_IMETHODIMP nsViewManager::CacheWidgetChanges(PRBool aCache) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsViewManager::UpdateViewAfterScroll(nsIView *aView, PRInt32 aDX, PRInt32 aDY) { + +#ifdef CACHE_WIDGET_CHANGES + if (aCache == PR_TRUE) + mCachingWidgetChanges++; + else + mCachingWidgetChanges--; + + NS_ASSERTION(mCachingWidgetChanges >= 0, "One too many decrements"); + + // if we turned it off. Then move and size all the widgets. + if (mCachingWidgetChanges == 0) + ProcessWidgetChanges(mRootView); +#endif + + return NS_OK; +} + +nsresult +nsViewManager::ProcessWidgetChanges(nsIView* aView) +{ + //printf("---------Begin Sync----------\n"); + nsresult rv = aView->SynchWidgetSizePosition(); + if (NS_FAILED(rv)) + return rv; + + nsIView *child; + aView->GetChild(0, child); + while (nsnull != child) { + rv = ProcessWidgetChanges(child); + if (NS_FAILED(rv)) + return rv; + + child->GetNextSibling(child); + } + + //printf("---------End Sync----------\n"); + return NS_OK; } - diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index f0144dc92463..0e3ef1820d31 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: true; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file @@ -31,20 +31,24 @@ #include "prtime.h" #include "prinrval.h" #include "nsVoidArray.h" +#include "nsHashtable.h" #include "nsIScrollableView.h" #include "nsIRegion.h" #include "nsIBlender.h" -// Uncomment this line to enable the performance timer for the view manager. +class nsISupportsArray; +struct DisplayListElement2; +struct DisplayZTreeNode; + +//Uncomment the following line to enable generation of viewmanager performance data. #ifdef MOZ_PERF_METRICS -//#define NS_VM_PERF_METRICS 1 +//#define NS_VM_PERF_METRICS 1 #endif #ifdef NS_VM_PERF_METRICS #include "nsTimer.h" #endif -class nsISupportsArray; // Dont want to get rid of timer code, because we may want to use it // if we go to a implementation where we have invalidates that have been queued @@ -152,20 +156,19 @@ public: NS_IMETHOD GetWidget(nsIWidget **aWidget); NS_IMETHOD ForceUpdate(); NS_IMETHOD GetOffset(nscoord *aX, nscoord *aY); - + NS_IMETHOD IsCachingWidgetChanges(PRBool* aCaching); NS_IMETHOD CacheWidgetChanges(PRBool aCache); - - protected: virtual ~nsViewManager(); private: nsIRenderingContext *CreateRenderingContext(nsIView &aView); void AddRectToDirtyRegion(nsIView* aView, const nsRect &aRect) const; - void UpdateDirtyViews(nsIView *aView, nsRect *aParentRect) const; void UpdateTransCnt(nsIView *oldview, nsIView *newview); + PRBool UpdateAllCoveringWidgets(nsIView *aView, nsIView *aTarget, nsRect &aDamagedRect); + void ProcessPendingUpdates(nsIView *aView); void UpdateViews(nsIView *aView, PRUint32 aUpdateFlags); @@ -175,17 +178,33 @@ private: const nsRect *rect, PRUint32 aUpdateFlags); void RenderViews(nsIView *aRootView, nsIRenderingContext& aRC, const nsRect& aRect, PRBool &aResult); + void RenderView(nsIView *aView, nsIRenderingContext &aRC, const nsRect &aDamageRect, nsRect &aGlobalRect, PRBool &aResult); - PRBool CreateDisplayList(nsIView *aView, PRInt32 *aIndex, nscoord aOriginX, nscoord aOriginY, - nsIView *aRealView, const nsRect *aDamageRect = nsnull, - nsIView *aTopView = nsnull, nsVoidArray *aArray = nsnull, - nscoord aX = 0, nscoord aY = 0); - PRBool AddToDisplayList(nsVoidArray *aArray, PRInt32 *aIndex, - nsIView *aView, nsRect &aRect, PRUint32 aFlags); + + void RenderDisplayListElement(DisplayListElement2* element, nsIRenderingContext &aRC); + + void PaintView(nsIView *aView, nsIRenderingContext &aRC, nscoord x, nscoord y, + const nsRect &aDamageRect); + + nsresult CreateBlendingBuffers(nsIRenderingContext &aRC); + + PRBool CreateDisplayList(nsIView *aView, PRBool aReparentedViewsPresent, DisplayZTreeNode* &aResult, nscoord aOriginX, nscoord aOriginY, + PRBool aInsideRealView, nsIView *aRealView, const nsRect *aDamageRect = nsnull, + nsIView *aTopView = nsnull, nscoord aX = 0, nscoord aY = 0); + PRBool AddToDisplayList(nsIView *aView, DisplayZTreeNode* &aParent, nsRect &aClipRect, nsRect& aDirtyRect, PRUint32 aFlags, nscoord aAbsX, nscoord aAbsY); + void ReapplyClipInstructions(PRBool aHaveClip, nsRect& aClipRect, PRInt32& aIndex); + nsresult OptimizeDisplayList(const nsRect& aDamageRect); + // Remove redundant PUSH/POP_CLIP pairs. + void OptimizeDisplayListClipping(PRBool aHaveClip, nsRect& aClipRect, PRInt32& aIndex, + PRBool& aAnyRendered); void ShowDisplayList(PRInt32 flatlen); - void ComputeViewOffset(nsIView *aView, nscoord *aX, nscoord *aY, PRInt32 aFlag); - PRBool DoesViewHaveNativeWidget(nsIView &aView); + void ComputeViewOffset(nsIView *aView, nsPoint *aOrigin); + + // Predicates + PRBool DoesViewHaveNativeWidget(nsIView* aView); + PRBool IsClipView(nsIView* aView); + void PauseTimer(void); void RestartTimer(void); @@ -204,7 +223,7 @@ private: void ViewToWidget(nsIView *aView, nsIView* aWidgetView, nsRect &aRect) const; // void WidgetToView(nsIView* aView, nsRect &aWidgetRect); - /** + /** * Transforms a rectangle from specified view's coordinate system to * an absolute coordinate rectangle which can be compared against the * rectangle returned by GetVisibleRect to determine visibility. @@ -233,8 +252,62 @@ private: */ PRBool IsRectVisible(nsIView *aView, const nsRect &aRect); + nsresult ProcessWidgetChanges(nsIView* aView); + + // Utilities used to size the offscreen drawing surface + + /** + * Determine the maximum and width and height of all of the + * view manager's widgets. + * + * @param aMaxWidgetBounds the maximum width and height of all view managers + * widgets on exit. + */ + void GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const; + + /** + * Determine if a rect's width and height will fit within a specified width and height + * @param aRect rectangle to test + * @param aWidth width to determine if the rectangle's width will fit within + * @param aHeight height to determine if the rectangles height will fit within + * @returns PR_TRUE if the rect width and height fits with aWidth, aHeight, PR_FALSE + * otherwise. + */ + PRBool RectFitsInside(nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const; + + /** + * Determine if two rectangles width and height will fit within a specified width and height + * @param aRect1 first rectangle to test + * @param aRect1 second rectangle to test + * @param aWidth width to determine if both rectangle's width will fit within + * @param aHeight height to determine if both rectangles height will fit within + * @returns PR_TRUE if the rect1's and rect2's width and height fits with aWidth, + * aHeight, PR_FALSE otherwise. + */ + PRBool BothRectsFitInside(nsRect& aRect1, nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const; + + /** + * Return an offscreen surface size from a set of discrete surface sizes. + * The smallest discrete surface size that can enclose both the Maximum widget + * size (@see GetMaxWidgetBounds) and the requested size is returned. + * + * @param aRequestedSize Requested size for the offscreen. + * @param aSurfaceSize contains the surface size + */ + void CalculateDiscreteSurfaceSize(nsRect& aRequestedSize, nsRect& aSize) const; + + /** + * Get the size of the offscreen drawing surface.. + * + * @param aRequestedSize Desired size for the offscreen. + * @param aSurfaceSize Offscreen adjusted to a discrete size which encloses aRequestedSize. + */ + void GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aSurfaceSize) const; + private: nsIDeviceContext *mContext; + float mTwipsToPixels; + float mPixelsToTwips; nsIViewObserver *mObserver; nsIWidget *mRootWindow; PRIntervalTime mLastRefresh; @@ -245,8 +318,14 @@ private: nsIView *mKeyGrabber; PRInt32 mUpdateCnt; PRInt32 mUpdateBatchCnt; - nsVoidArray *mDisplayList; + PRInt32 mDisplayListCount; + nsVoidArray mDisplayList; + PRInt32 mTranslucentViewCount; + nsRect mTranslucentArea; // bounding box of all translucent views. nsIScrollableView *mRootScrollable; + PRInt32 mCachingWidgetChanges; + + nsHashtable mMapPlaceholderViewToZTreeNode; //from here to public should be static and locked... MMP static PRInt32 mVMCount; //number of viewmanagers @@ -255,32 +334,33 @@ private: //blending buffers static nsDrawingSurface gOffScreen; - static nsDrawingSurface gRed; - static nsDrawingSurface gBlue; - static PRInt32 gBlendWidth; - static PRInt32 gBlendHeight; + static nsDrawingSurface gBlack; + static nsDrawingSurface gWhite; + static nsSize gOffScreenSize; + + // 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; - nsIRegion *mRCRgn; - nsIRegion *mTRgn; - nsRegionRectSet *mTransRects; + nsIRegion *mTmpRgn; nsIBlender *mBlender; nsIRenderingContext *mOffScreenCX; - nsIRenderingContext *mRedCX; - nsIRenderingContext *mBlueCX; + nsIRenderingContext *mBlackCX; + nsIRenderingContext *mWhiteCX; nsISupportsArray *mCompositeListeners; public: //these are public so that our timer callback can poke them. -#if NS_VIEWMANAGER_NEEDS_TIMER +#ifdef NS_VIEWMANAGER_NEEDS_TIMER nsCOMPtr mTimer; #endif - nsRect mDirtyRect; nsIView *mRootView; PRUint32 mFrameRate; PRUint32 mTrueFrameRate; @@ -294,5 +374,4 @@ protected: #endif }; -#endif - +#endif /* nsViewManager_h___ */