2733 lines
71 KiB
C++
2733 lines
71 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
#include "nsViewManager.h"
|
|
#include "nsUnitConversion.h"
|
|
#include "nsIRenderingContext.h"
|
|
#include "nsIDeviceContext.h"
|
|
#include "nsGfxCIID.h"
|
|
#include "nsIScrollableView.h"
|
|
#include "nsView.h"
|
|
#include "nsIScrollbar.h"
|
|
#include "nsIClipView.h"
|
|
#include "nsISupportsArray.h"
|
|
#include "nsICompositeListener.h"
|
|
#include "nsCOMPtr.h"
|
|
|
|
static NS_DEFINE_IID(kBlenderCID, NS_BLENDER_CID);
|
|
static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
|
|
static NS_DEFINE_IID(kRenderingContextCID, NS_RENDERING_CONTEXT_CID);
|
|
|
|
//#define GS_DEBUG
|
|
|
|
#define UPDATE_QUANTUM 1000 / 40
|
|
|
|
//#define NO_DOUBLE_BUFFER
|
|
#define NEW_COMPOSITOR
|
|
#define USE_DISPLAY_LIST_ELEMENTS
|
|
|
|
//used for debugging new compositor
|
|
//#define SHOW_RECTS
|
|
//#define SHOW_DISPLAYLIST
|
|
|
|
//display list flags
|
|
#define RENDER_VIEW 0x0000
|
|
#define VIEW_INCLUDED 0x0001
|
|
#define PUSH_CLIP 0x0002
|
|
#define POP_CLIP 0x0004
|
|
|
|
#define DISPLAYLIST_INC 1
|
|
|
|
//display list elements
|
|
struct DisplayListElement {
|
|
nsIView* mView;
|
|
nsRect mClip;
|
|
PRUint32 mFlags;
|
|
};
|
|
|
|
static void vm_timer_callback(nsITimer *aTimer, void *aClosure)
|
|
{
|
|
nsViewManager *vm = (nsViewManager *)aClosure;
|
|
|
|
//restart the timer
|
|
|
|
if (vm->mTrueFrameRate == vm->mFrameRate)
|
|
{
|
|
PRUint32 fr = vm->mFrameRate;
|
|
|
|
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.
|
|
// It's that way for now because the proper solutions
|
|
// (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();
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
static void blinkRect(nsIRenderingContext* context, const nsRect& r)
|
|
{
|
|
context->InvertRect(r);
|
|
::PR_Sleep(::PR_MillisecondsToInterval(100));
|
|
context->InvertRect(r);
|
|
}
|
|
#endif
|
|
|
|
PRUint32 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;
|
|
|
|
static NS_DEFINE_IID(knsViewManagerIID, NS_IVIEWMANAGER_IID);
|
|
|
|
nsViewManager :: nsViewManager()
|
|
{
|
|
NS_INIT_REFCNT();
|
|
mVMCount++;
|
|
mUpdateBatchCnt = 0;
|
|
mCompositeListeners = nsnull;
|
|
}
|
|
|
|
nsViewManager :: ~nsViewManager()
|
|
{
|
|
if (nsnull != mTimer)
|
|
{
|
|
mTimer->Cancel(); //XXX this should not be necessary. MMP
|
|
NS_RELEASE(mTimer);
|
|
}
|
|
|
|
NS_IF_RELEASE(mRootWindow);
|
|
|
|
mRootScrollable = nsnull;
|
|
|
|
NS_ASSERTION((mVMCount > 0), "underflow of viewmanagers");
|
|
--mVMCount;
|
|
|
|
if ((0 == mVMCount) &&
|
|
((nsnull != mDrawingSurface) || (nsnull != gOffScreen) ||
|
|
(nsnull != gRed) || (nsnull != gBlue)))
|
|
{
|
|
nsIRenderingContext *rc;
|
|
|
|
nsresult rv = nsComponentManager::CreateInstance(kRenderingContextCID,
|
|
nsnull,
|
|
NS_GET_IID(nsIRenderingContext),
|
|
(void **)&rc);
|
|
|
|
if (NS_OK == rv)
|
|
{
|
|
if (nsnull != mDrawingSurface)
|
|
rc->DestroyDrawingSurface(mDrawingSurface);
|
|
|
|
if (nsnull != gOffScreen)
|
|
rc->DestroyDrawingSurface(gOffScreen);
|
|
|
|
if (nsnull != gRed)
|
|
rc->DestroyDrawingSurface(gRed);
|
|
|
|
if (nsnull != gBlue)
|
|
rc->DestroyDrawingSurface(gBlue);
|
|
|
|
NS_RELEASE(rc);
|
|
}
|
|
|
|
mDrawingSurface = nsnull;
|
|
gOffScreen = nsnull;
|
|
gRed = nsnull;
|
|
gBlue = nsnull;
|
|
gBlendWidth = 0;
|
|
gBlendHeight = 0;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
|
|
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.
|
|
*/
|
|
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)
|
|
{
|
|
*result = nsnull;
|
|
nsIRegion* region = nsnull;
|
|
nsresult rv = componentManager->CreateInstance(kRegionCID, nsnull, NS_GET_IID(nsIRegion), (void**)®ion);
|
|
if (NS_SUCCEEDED(rv)) {
|
|
rv = region->Init();
|
|
*result = region;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
// We don't hold a reference to the presentation context because it
|
|
// holds a reference to us.
|
|
NS_IMETHODIMP nsViewManager :: Init(nsIDeviceContext* aContext)
|
|
{
|
|
nsresult rv;
|
|
|
|
NS_PRECONDITION(nsnull != aContext, "null ptr");
|
|
|
|
if (nsnull == aContext) {
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
if (nsnull != mContext) {
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
}
|
|
mContext = aContext;
|
|
|
|
mDSBounds.Empty();
|
|
mTimer = nsnull;
|
|
mFrameRate = 0;
|
|
mTrueFrameRate = 0;
|
|
mTransCnt = 0;
|
|
|
|
rv = SetFrameRate(UPDATE_QUANTUM);
|
|
|
|
mLastRefresh = PR_IntervalNow();
|
|
|
|
mRefreshEnabled = PR_TRUE;
|
|
|
|
mMouseGrabber = nsnull;
|
|
mKeyGrabber = nsnull;
|
|
|
|
// create regions
|
|
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);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: GetRootView(nsIView *&aView)
|
|
{
|
|
aView = mRootView;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetRootView(nsIView *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);
|
|
|
|
if (nsnull != mRootView)
|
|
mRootView->GetWidget(mRootWindow);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: GetFrameRate(PRUint32 &aRate)
|
|
{
|
|
aRate = mTrueFrameRate;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetFrameRate(PRUint32 aFrameRate)
|
|
{
|
|
nsresult rv;
|
|
|
|
if (aFrameRate != mFrameRate)
|
|
{
|
|
if (nsnull != mTimer)
|
|
{
|
|
mTimer->Cancel(); //XXX this should not be necessary. MMP
|
|
NS_RELEASE(mTimer);
|
|
}
|
|
|
|
mFrameRate = aFrameRate;
|
|
mTrueFrameRate = aFrameRate;
|
|
|
|
if (mFrameRate != 0)
|
|
{
|
|
rv = NS_NewTimer(&mTimer);
|
|
|
|
if (NS_OK == rv)
|
|
mTimer->Init(vm_timer_callback, this, 1000 / mFrameRate);
|
|
}
|
|
else
|
|
rv = NS_OK;
|
|
}
|
|
else
|
|
rv = NS_OK;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: GetWindowDimensions(nscoord *width, nscoord *height)
|
|
{
|
|
if (nsnull != mRootView)
|
|
mRootView->GetDimensions(width, height);
|
|
else
|
|
{
|
|
*width = 0;
|
|
*height = 0;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetWindowDimensions(nscoord width, nscoord 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");
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: ResetScrolling(void)
|
|
{
|
|
if (nsnull != mRootScrollable)
|
|
mRootScrollable->ComputeScrollOffsets(PR_TRUE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsIRegion *region, PRUint32 aUpdateFlags)
|
|
{
|
|
nsRect wrect;
|
|
nsIRenderingContext *localcx = nsnull;
|
|
nsDrawingSurface ds = nsnull;
|
|
|
|
if (PR_FALSE == mRefreshEnabled)
|
|
return;
|
|
|
|
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)
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
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)
|
|
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
|
|
#ifdef XP_UNIX
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//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
|
|
|
|
#define SET_STATE(x) { prevstate = state; state = (x); }
|
|
|
|
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<nsIRegion> paintedRgn;
|
|
if (NS_FAILED(nsComponentManager::CreateInstance(kRegionCID, nsnull, NS_GET_IID(nsIRegion), (void**) getter_AddRefs(paintedRgn))))
|
|
return;
|
|
paintedRgn->Init();
|
|
|
|
//printf("-------------begin paint------------\n");
|
|
if (aRootView && mRootView) {
|
|
nscoord ox = 0, oy = 0;
|
|
|
|
ComputeViewOffset(aRootView, &ox, &oy, 1);
|
|
CreateDisplayList(mRootView, &flatlen, ox, oy, aRootView, &aRect);
|
|
}
|
|
|
|
loopend = flatlen;
|
|
|
|
mContext->GetAppUnitsToDevUnits(t2p);
|
|
mContext->GetDevUnitsToAppUnits(p2t);
|
|
|
|
#ifdef SHOW_DISPLAYLIST
|
|
ShowDisplayList(flatlen);
|
|
#endif
|
|
|
|
while (state != COMPOSITION_DONE)
|
|
{
|
|
nsIView *curview;
|
|
nsRect *currect;
|
|
PRUint32 curflags;
|
|
PRBool pushing;
|
|
PRUint32 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);
|
|
|
|
if (curflags & PUSH_CLIP)
|
|
{
|
|
if (state == BACK_TO_FRONT_OPACITY)
|
|
{
|
|
mOffScreenCX->PopState(clipstate);
|
|
mRedCX->PopState(clipstate);
|
|
mBlueCX->PopState(clipstate);
|
|
|
|
// permanently remove any painted opaque views.
|
|
mOffScreenCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
mRedCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
mRedCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
|
|
pushcnt--;
|
|
NS_ASSERTION(!((PRInt32)pushcnt < 0), "underflow");
|
|
}
|
|
else if (state == BACK_TO_FRONT_TRANS)
|
|
{
|
|
aRC.PopState(clipstate);
|
|
pushcnt--;
|
|
NS_ASSERTION(!((PRInt32)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(!((PRInt32)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);
|
|
#endif
|
|
}
|
|
|
|
RenderView(curview, *mRedCX, localrect, *currect, clipstate);
|
|
|
|
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);
|
|
#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 != 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));
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
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 (aResult == PR_TRUE)
|
|
break;
|
|
}
|
|
}
|
|
|
|
NS_ASSERTION(!((PRInt32)pushcnt < 0), "underflow");
|
|
|
|
while (pushcnt--)
|
|
{
|
|
NS_ASSERTION(!((PRInt32)pushcnt < 0), "underflow");
|
|
|
|
if (pushing == BACK_TO_FRONT_OPACITY)
|
|
{
|
|
mOffScreenCX->PopState(clipstate);
|
|
mRedCX->PopState(clipstate);
|
|
mBlueCX->PopState(clipstate);
|
|
|
|
// permanently remove any painted opaque views.
|
|
mOffScreenCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
mRedCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
mBlueCX->SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
} else {
|
|
aRC.PopState(clipstate);
|
|
|
|
// permanently remove any painted opaque views.
|
|
aRC.SetClipRegion(*paintedRgn, nsClipCombine_kSubtract, clipstate);
|
|
}
|
|
}
|
|
|
|
switch (state)
|
|
{
|
|
case FRONT_TO_BACK_ACCUMULATE:
|
|
SET_STATE((transprop & (1 << TRANS_PROPERTY_OPACITY)) ? BACK_TO_FRONT_OPACITY : BACK_TO_FRONT_TRANS)
|
|
|
|
if ((curflags & (POP_CLIP | PUSH_CLIP)) || (state == BACK_TO_FRONT_OPACITY))
|
|
backstart = flatlen - DISPLAYLIST_INC;
|
|
else
|
|
{
|
|
backstart = flatlen - (DISPLAYLIST_INC << 1);
|
|
|
|
//render the bottom most view
|
|
RenderView(curview, aRC, aRect, *currect, aResult);
|
|
}
|
|
|
|
//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 != aRootView)
|
|
ComputeViewOffset(aRootView, nsnull, nsnull, 0);
|
|
|
|
#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);
|
|
}
|
|
}
|
|
|
|
// Check our child views
|
|
nsIView *child;
|
|
|
|
aView->GetChild(0, child);
|
|
|
|
while (nsnull != child) {
|
|
UpdateDirtyViews(child, &parDamage);
|
|
child->GetNextSibling(child);
|
|
}
|
|
}
|
|
|
|
void nsViewManager::ProcessPendingUpdates(nsIView* aView)
|
|
{
|
|
PRBool hasWidget;
|
|
aView->HasWidget(&hasWidget);
|
|
if (hasWidget) {
|
|
nsCOMPtr<nsIRegion> dirtyRegion;
|
|
aView->GetDirtyRegion(*getter_AddRefs(dirtyRegion));
|
|
if (dirtyRegion != nsnull && !dirtyRegion->IsEmpty()) {
|
|
nsCOMPtr<nsIWidget> widget;
|
|
aView->GetWidget(*getter_AddRefs(widget));
|
|
if (widget) {
|
|
widget->InvalidateRegion(dirtyRegion, PR_FALSE);
|
|
}
|
|
dirtyRegion->Init();
|
|
}
|
|
}
|
|
|
|
// process pending updates in child view.
|
|
nsIView* childView = nsnull;
|
|
aView->GetChild(0, childView);
|
|
while (nsnull != childView) {
|
|
ProcessPendingUpdates(childView);
|
|
childView->GetNextSibling(childView);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: Composite()
|
|
{
|
|
if (mUpdateCnt > 0)
|
|
{
|
|
if (nsnull != mRootWindow)
|
|
mRootWindow->Update();
|
|
|
|
mUpdateCnt = 0;
|
|
PauseTimer();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, PRUint32 aUpdateFlags)
|
|
{
|
|
// Mark the entire view as damaged
|
|
nsRect bounds;
|
|
aView->GetBounds(bounds);
|
|
bounds.x = bounds.y = 0;
|
|
return UpdateView(aView, bounds, aUpdateFlags);
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager::UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 aUpdateFlags)
|
|
{
|
|
NS_PRECONDITION(nsnull != aView, "null view");
|
|
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<nsIWidget> 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();
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager::UpdateAllViews(PRUint32 aUpdateFlags)
|
|
{
|
|
UpdateViews(mRootView, aUpdateFlags);
|
|
return NS_OK;
|
|
}
|
|
|
|
void nsViewManager::UpdateViews(nsIView *aView, PRUint32 aUpdateFlags)
|
|
{
|
|
// update this view.
|
|
UpdateView(aView, aUpdateFlags);
|
|
|
|
// update all children as well.
|
|
nsIView* childView = nsnull;
|
|
aView->GetChild(0, childView);
|
|
while (nsnull != childView) {
|
|
UpdateViews(childView, aUpdateFlags);
|
|
childView->GetNextSibling(childView);
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aStatus)
|
|
{
|
|
*aStatus = nsEventStatus_eIgnore;
|
|
|
|
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;
|
|
|
|
// 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);
|
|
|
|
//printf("resize: (pix) %d, %d\n", width, height);
|
|
SetWindowDimensions(NSIntPixelsToTwips(width, p2t),
|
|
NSIntPixelsToTwips(height, p2t));
|
|
*aStatus = nsEventStatus_eConsumeNoDefault;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
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;
|
|
|
|
float p2t;
|
|
mContext->GetDevUnitsToAppUnits(p2t);
|
|
damrect.ScaleRoundOut(p2t);
|
|
|
|
// 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;
|
|
|
|
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.
|
|
|
|
// 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;
|
|
|
|
//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);
|
|
}
|
|
}
|
|
|
|
*aStatus = nsEventStatus_eConsumeNoDefault;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case NS_DESTROY:
|
|
*aStatus = nsEventStatus_eConsumeNoDefault;
|
|
break;
|
|
|
|
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 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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
//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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
PRBool handled = PR_FALSE;
|
|
view->HandleEvent(aEvent, NS_VIEW_FLAG_CHECK_CHILDREN |
|
|
NS_VIEW_FLAG_CHECK_PARENT |
|
|
NS_VIEW_FLAG_CHECK_SIBLINGS,
|
|
aStatus,
|
|
handled);
|
|
|
|
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);
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
if (aEvent->message==NS_COMPOSITION_START) {
|
|
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.x,t2p);
|
|
((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y=NSTwipsToIntPixels(((nsCompositionEvent*)aEvent)->theReply.mCursorPosition.y,t2p);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
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))
|
|
{
|
|
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);
|
|
|
|
//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 :: InsertChild(nsIView *parent, nsIView *child, PRInt32 zindex)
|
|
{
|
|
NS_PRECONDITION(nsnull != parent, "null ptr");
|
|
NS_PRECONDITION(nsnull != child, "null ptr");
|
|
|
|
if ((nsnull != parent) && (nsnull != child))
|
|
{
|
|
nsIView *kid;
|
|
nsIView *prev = nsnull;
|
|
|
|
//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);
|
|
|
|
//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 :: RemoveChild(nsIView *parent, nsIView *child)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
nscoord oldX, oldY;
|
|
aView->GetPosition(&oldX, &oldY);
|
|
aView->SetPosition(aX, aY);
|
|
|
|
// only do damage control if the view is visible
|
|
|
|
if ((aX != oldX) || (aY != oldY)) {
|
|
nsViewVisibility visibility;
|
|
aView->GetVisibility(visibility);
|
|
if (visibility != nsViewVisibility_kHide) {
|
|
nsRect bounds;
|
|
aView->GetBounds(bounds);
|
|
nsRect oldArea(oldX, oldY, bounds.width, bounds.height);
|
|
nsIView* parentView;
|
|
aView->GetParent(parentView);
|
|
UpdateView(parentView, oldArea, NS_VMREFRESH_NO_SYNC);
|
|
nsRect newArea(aX, aY, bounds.width, bounds.height);
|
|
UpdateView(parentView, newArea, NS_VMREFRESH_NO_SYNC);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager::ResizeView(nsIView *aView, nscoord width, nscoord height)
|
|
{
|
|
nscoord oldWidth, oldHeight;
|
|
aView->GetDimensions(&oldWidth, &oldHeight);
|
|
if ((width != oldWidth) || (height != oldHeight)) {
|
|
nscoord x = 0, y = 0;
|
|
nsIView* parentView = nsnull;
|
|
aView->GetParent(parentView);
|
|
if (parentView != nsnull)
|
|
aView->GetPosition(&x, &y);
|
|
else
|
|
parentView = aView;
|
|
|
|
// resize the view.
|
|
aView->SetDimensions(width, height);
|
|
|
|
#if 0
|
|
// 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
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetViewClip(nsIView *aView, nsRect *aRect)
|
|
{
|
|
NS_ASSERTION(!(nsnull == aView), "no view");
|
|
NS_ASSERTION(!(nsnull == aRect), "no clip");
|
|
|
|
aView->SetClip(aRect->x, aRect->y, aRect->XMost(), aRect->YMost());
|
|
|
|
UpdateView(aView, *aRect, NS_VMREFRESH_NO_SYNC);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetViewZIndex(nsIView *aView, PRInt32 aZIndex)
|
|
{
|
|
nsresult rv;
|
|
|
|
NS_ASSERTION(!(nsnull == aView), "no view");
|
|
|
|
PRInt32 oldidx;
|
|
|
|
aView->GetZIndex(oldidx);
|
|
|
|
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);
|
|
}
|
|
else
|
|
rv = NS_OK;
|
|
}
|
|
else
|
|
rv = NS_OK;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager::SetViewAutoZIndex(nsIView *aView, PRBool aAutoZIndex)
|
|
{
|
|
return aView->SetAutoZIndex(aAutoZIndex);
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: MoveViewAbove(nsIView *aView, nsIView *aOther)
|
|
{
|
|
nsresult rv;
|
|
|
|
NS_ASSERTION(!(nsnull == aView), "no view");
|
|
NS_ASSERTION(!(nsnull == aOther), "no view");
|
|
|
|
nsIView *nextview;
|
|
|
|
aView->GetNextSibling(nextview);
|
|
|
|
if (nextview != aOther)
|
|
{
|
|
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, aOther, PR_TRUE);
|
|
}
|
|
else
|
|
rv = NS_OK;
|
|
}
|
|
else
|
|
rv = NS_OK;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: MoveViewBelow(nsIView *aView, nsIView *aOther)
|
|
{
|
|
nsresult rv;
|
|
|
|
NS_ASSERTION(!(nsnull == aView), "no view");
|
|
NS_ASSERTION(!(nsnull == aOther), "no view");
|
|
|
|
nsIView *nextview;
|
|
|
|
aOther->GetNextSibling(nextview);
|
|
|
|
if (nextview != aView)
|
|
{
|
|
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, 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;
|
|
}
|
|
|
|
#ifndef max
|
|
#define max(a, b) ((a) < (b) ? (b) : (a))
|
|
#endif
|
|
|
|
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);
|
|
|
|
if (mDrawingSurface) {
|
|
//destroy existing DS
|
|
aContext.DestroyDrawingSurface(mDrawingSurface);
|
|
mDrawingSurface = nsnull;
|
|
}
|
|
|
|
nsresult rv = aContext.CreateDrawingSurface(&newBounds, 0, mDrawingSurface);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
mDSBounds = newBounds;
|
|
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;
|
|
|
|
PRBool clipEmpty;
|
|
aContext.SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty);
|
|
|
|
nscolor col = NS_RGB(255,255,255);
|
|
aContext.SetColor(col);
|
|
//aContext.FillRect(bounds);
|
|
}
|
|
|
|
return mDrawingSurface;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: ShowQuality(PRBool aShow)
|
|
{
|
|
if (nsnull != mRootScrollable)
|
|
mRootScrollable->ShowQuality(aShow);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: GetShowQuality(PRBool &aResult)
|
|
{
|
|
if (nsnull != mRootScrollable)
|
|
mRootScrollable->GetShowQuality(aResult);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetQuality(nsContentQuality aQuality)
|
|
{
|
|
if (nsnull != mRootScrollable)
|
|
mRootScrollable->SetQuality(aQuality);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsIRenderingContext * nsViewManager :: CreateRenderingContext(nsIView &aView)
|
|
{
|
|
nsIView *par = &aView;
|
|
nsIWidget *win;
|
|
nsIRenderingContext *cx = nsnull;
|
|
nscoord x, y, ax = 0, ay = 0;
|
|
|
|
do
|
|
{
|
|
par->GetWidget(win);
|
|
|
|
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...
|
|
|
|
if (par != &aView)
|
|
{
|
|
par->GetPosition(&x, &y);
|
|
|
|
ax += x;
|
|
ay += y;
|
|
}
|
|
|
|
par->GetParent(par);
|
|
}
|
|
while (nsnull != par);
|
|
|
|
if (nsnull != win)
|
|
{
|
|
mContext->CreateRenderingContext(&aView, cx);
|
|
|
|
if (nsnull != cx)
|
|
cx->Translate(ax, ay);
|
|
|
|
NS_RELEASE(win);
|
|
}
|
|
|
|
return cx;
|
|
}
|
|
|
|
void nsViewManager::AddRectToDirtyRegion(nsIView* aView, const nsRect &aRect) const
|
|
{
|
|
// Find a view with an associated widget. We'll transform this rect from the
|
|
// current view's coordinate system to a "heavyweight" parent view, then convert
|
|
// the rect to pixel coordinates, and accumulate the rect into that view's dirty region.
|
|
nsRect widgetRect = aRect;
|
|
nsIView* widgetView = GetWidgetView(aView);
|
|
ViewToWidget(aView, widgetView, widgetRect);
|
|
|
|
// Get the dirty region associated with the widget view
|
|
nsCOMPtr<nsIRegion> dirtyRegion;
|
|
if (NS_SUCCEEDED(widgetView->GetDirtyRegion(*getter_AddRefs(dirtyRegion)))) {
|
|
// add this rect to the widget view's dirty region.
|
|
dirtyRegion->Union(widgetRect.x, widgetRect.y, widgetRect.width, widgetRect.height);
|
|
}
|
|
}
|
|
|
|
void nsViewManager::UpdateTransCnt(nsIView *oldview, nsIView *newview)
|
|
{
|
|
if (nsnull != oldview)
|
|
{
|
|
PRBool hasTransparency;
|
|
float opacity;
|
|
|
|
oldview->HasTransparency(hasTransparency);
|
|
oldview->GetOpacity(opacity);
|
|
|
|
if (hasTransparency || (1.0f != opacity))
|
|
mTransCnt--;
|
|
}
|
|
|
|
if (nsnull != newview)
|
|
{
|
|
PRBool hasTransparency;
|
|
float opacity;
|
|
|
|
newview->HasTransparency(hasTransparency);
|
|
newview->GetOpacity(opacity);
|
|
|
|
if (hasTransparency || (1.0f != opacity))
|
|
mTransCnt++;
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: DisableRefresh(void)
|
|
{
|
|
if (mUpdateBatchCnt > 0)
|
|
return NS_OK;
|
|
|
|
mRefreshEnabled = PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: EnableRefresh(void)
|
|
{
|
|
if (mUpdateBatchCnt > 0)
|
|
return NS_OK;
|
|
|
|
mRefreshEnabled = PR_TRUE;
|
|
|
|
if (mUpdateCnt > 0)
|
|
ProcessPendingUpdates(mRootView);
|
|
|
|
if (mTrueFrameRate > 0)
|
|
{
|
|
PRInt32 deltams = PR_IntervalToMilliseconds(PR_IntervalNow() - mLastRefresh);
|
|
|
|
if (deltams > (1000 / (PRInt32)mTrueFrameRate))
|
|
Composite();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: BeginUpdateViewBatch(void)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
if (mUpdateBatchCnt == 0)
|
|
result = DisableRefresh();
|
|
|
|
if (NS_SUCCEEDED(result))
|
|
++mUpdateBatchCnt;
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: EndUpdateViewBatch(void)
|
|
{
|
|
nsresult result = NS_OK;
|
|
|
|
--mUpdateBatchCnt;
|
|
|
|
NS_ASSERTION(mUpdateBatchCnt >= 0, "Invalid batch count!");
|
|
|
|
if (mUpdateBatchCnt < 0)
|
|
{
|
|
mUpdateBatchCnt = 0;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (mUpdateBatchCnt == 0)
|
|
result = EnableRefresh();
|
|
|
|
return result;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: SetRootScrollableView(nsIScrollableView *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);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: GetRootScrollableView(nsIScrollableView **aScrollable)
|
|
{
|
|
*aScrollable = mRootScrollable;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: Display(nsIView* aView)
|
|
{
|
|
nsIRenderingContext *localcx = nsnull;
|
|
nsRect trect;
|
|
|
|
if (PR_FALSE == mRefreshEnabled)
|
|
return NS_OK;
|
|
|
|
NS_ASSERTION(!(PR_TRUE == mPainting), "recursive painting not permitted");
|
|
|
|
mPainting = PR_TRUE;
|
|
|
|
mContext->CreateRenderingContext(localcx);
|
|
|
|
//couldn't get rendering context. this is ok if at startup
|
|
if (nsnull == localcx)
|
|
{
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
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);
|
|
|
|
PRBool 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);
|
|
|
|
// XXX Reset the view's origin
|
|
aView->SetPosition(x, y);
|
|
|
|
NS_RELEASE(localcx);
|
|
|
|
mPainting = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: AddCompositeListener(nsICompositeListener* aListener)
|
|
{
|
|
if (nsnull == mCompositeListeners) {
|
|
nsresult rv = NS_NewISupportsArray(&mCompositeListeners);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
}
|
|
return mCompositeListeners->AppendElement(aListener);
|
|
}
|
|
|
|
NS_IMETHODIMP nsViewManager :: RemoveCompositeListener(nsICompositeListener* aListener)
|
|
{
|
|
if (nsnull != mCompositeListeners) {
|
|
return mCompositeListeners->RemoveElement(aListener);
|
|
}
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
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 (!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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
if (retval || !trans && (opacity == 1.0f) && (irect == *aDamageRect))
|
|
retval = PR_TRUE;
|
|
}
|
|
|
|
// 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)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
PRBool nsViewManager :: AddToDisplayList(nsVoidArray *aArray, PRInt32 *aIndex, nsIView *aView, nsRect &aRect, PRUint32 aFlags)
|
|
{
|
|
PRInt32 index = (*aIndex)++;
|
|
DisplayListElement* element = (DisplayListElement*) mDisplayList->ElementAt(index);
|
|
if (element == nsnull) {
|
|
element = new DisplayListElement;
|
|
if (element == nsnull) {
|
|
*aIndex = index;
|
|
return PR_TRUE;
|
|
}
|
|
mDisplayList->ReplaceElementAt(element, index);
|
|
}
|
|
|
|
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;
|
|
|
|
for (cnt = 0; cnt < 400; cnt++)
|
|
nest[cnt] = ' ';
|
|
|
|
float t2p;
|
|
mContext->GetAppUnitsToDevUnits(t2p);
|
|
|
|
printf("### display list length=%d ###\n", flatlen);
|
|
|
|
for (cnt = 0; cnt < flatlen; cnt += DISPLAYLIST_INC)
|
|
{
|
|
nsIView *view, *parent;
|
|
nsRect rect;
|
|
PRUint32 flags;
|
|
PRInt32 zindex;
|
|
|
|
DisplayListElement* element = (DisplayListElement*) mDisplayList->ElementAt(cnt);
|
|
view = element->mView;
|
|
rect = element->mClip;
|
|
flags = element->mFlags;
|
|
|
|
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);
|
|
|
|
newnestcnt = nestcnt;
|
|
|
|
if (flags)
|
|
{
|
|
printf("%s", nest);
|
|
|
|
if (flags & POP_CLIP) {
|
|
printf("POP_CLIP ");
|
|
newnestcnt--;
|
|
}
|
|
|
|
if (flags & PUSH_CLIP) {
|
|
printf("PUSH_CLIP ");
|
|
newnestcnt++;
|
|
}
|
|
|
|
if (flags & VIEW_INCLUDED)
|
|
printf("VIEW_INCLUDED ");
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
nest[nestcnt << 1] = ' ';
|
|
|
|
nestcnt = newnestcnt;
|
|
}
|
|
}
|
|
|
|
void nsViewManager :: ComputeViewOffset(nsIView *aView, nscoord *aX, nscoord *aY, PRInt32 aFlag)
|
|
{
|
|
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);
|
|
}
|
|
|
|
PRBool nsViewManager :: DoesViewHaveNativeWidget(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;
|
|
}
|
|
|
|
void nsViewManager :: PauseTimer(void)
|
|
{
|
|
PRUint32 oldframerate = mTrueFrameRate;
|
|
SetFrameRate(0);
|
|
mTrueFrameRate = oldframerate;
|
|
}
|
|
|
|
void nsViewManager :: RestartTimer(void)
|
|
{
|
|
SetFrameRate(mTrueFrameRate);
|
|
}
|
|
|
|
nsIView* nsViewManager::GetWidgetView(nsIView *aView) const
|
|
{
|
|
while (aView != nsnull) {
|
|
PRBool hasWidget;
|
|
aView->HasWidget(&hasWidget);
|
|
if (hasWidget)
|
|
return aView;
|
|
aView->GetParent(aView);
|
|
}
|
|
return nsnull;
|
|
}
|
|
|
|
void nsViewManager::ViewToWidget(nsIView *aView, nsIView* aWidgetView, nsRect &aRect) const
|
|
{
|
|
while (aView != aWidgetView) {
|
|
nscoord x, y;
|
|
aView->GetPosition(&x, &y);
|
|
aRect.MoveBy(x, y);
|
|
aView->GetParent(aView);
|
|
}
|
|
|
|
// intersect aRect with bounds of aWidgetView, to prevent generating any illegal rectangles.
|
|
nsRect bounds;
|
|
aWidgetView->GetBounds(bounds);
|
|
bounds.x = bounds.y = 0;
|
|
aRect.IntersectRect(aRect, bounds);
|
|
|
|
// finally, convert to device coordinates.
|
|
float t2p;
|
|
mContext->GetAppUnitsToDevUnits(t2p);
|
|
aRect.ScaleRoundOut(t2p);
|
|
}
|