added support of irregular damage regions to viewmanager.

git-svn-id: svn://10.0.0.236/trunk@2999 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
michaelp
1998-06-03 03:12:52 +00:00
parent 964270c59d
commit 6dabba1783
9 changed files with 203 additions and 20 deletions

View File

@@ -66,6 +66,10 @@ void nsRegionUnix :: Subtract(const nsIRegion &aRegion)
{
}
void nsRegionUnix :: Subtract(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
{
}
PRBool nsRegionUnix :: IsEmpty(void)
{
return PR_FALSE;

View File

@@ -119,6 +119,19 @@ public:
**/
virtual void Subtract(const nsIRegion &aRegion) = 0;
/**
* destructively subtract a rect from this region
*
* @param aX xoffset of rect to subtract with region
* @param aY yoffset of rect to subtract with region
* @param aWidth width of rect to subtract with region
* @param aHeight height of rect to subtract with region
* @return void
*
**/
virtual void Subtract(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) = 0;
/**
* is this region empty? i.e. does it contain any pixels

View File

@@ -69,7 +69,7 @@ void nsRegionWin :: Intersect(const nsIRegion &aRegion)
{
nsRegionWin *pRegion = (nsRegionWin *)&aRegion;
mRegionType = ::CombineRgn(mRegion, pRegion->mRegion, mRegion, RGN_AND);
mRegionType = ::CombineRgn(mRegion, mRegion, pRegion->mRegion, RGN_AND);
}
void nsRegionWin :: Intersect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
@@ -77,7 +77,7 @@ void nsRegionWin :: Intersect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aH
HRGN tRegion;
tRegion = ::CreateRectRgn(aX, aY, aX + aWidth, aY + aHeight);
mRegionType = ::CombineRgn(mRegion, tRegion, mRegion, RGN_AND);
mRegionType = ::CombineRgn(mRegion, mRegion, tRegion, RGN_AND);
::DeleteObject(tRegion);
}
@@ -86,7 +86,7 @@ void nsRegionWin :: Union(const nsIRegion &aRegion)
{
nsRegionWin *pRegion = (nsRegionWin *)&aRegion;
mRegionType = ::CombineRgn(mRegion, pRegion->mRegion, mRegion, RGN_OR);
mRegionType = ::CombineRgn(mRegion, mRegion, pRegion->mRegion, RGN_OR);
}
void nsRegionWin :: Union(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
@@ -94,7 +94,7 @@ void nsRegionWin :: Union(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeigh
HRGN tRegion;
tRegion = ::CreateRectRgn(aX, aY, aX + aWidth, aY + aHeight);
mRegionType = ::CombineRgn(mRegion, tRegion, mRegion, RGN_OR);
mRegionType = ::CombineRgn(mRegion, mRegion, tRegion, RGN_OR);
::DeleteObject(tRegion);
}
@@ -106,6 +106,16 @@ void nsRegionWin :: Subtract(const nsIRegion &aRegion)
mRegionType = ::CombineRgn(mRegion, mRegion, pRegion->mRegion, RGN_DIFF);
}
void nsRegionWin :: Subtract(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight)
{
HRGN tRegion;
tRegion = ::CreateRectRgn(aX, aY, aX + aWidth, aY + aHeight);
mRegionType = ::CombineRgn(mRegion, mRegion, tRegion, RGN_DIFF);
::DeleteObject(tRegion);
}
PRBool nsRegionWin :: IsEmpty(void)
{
return (mRegionType == NULLREGION) ? PR_TRUE : PR_FALSE;

View File

@@ -38,6 +38,7 @@ public:
virtual void Union(const nsIRegion &aRegion);
virtual void Union(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight);
virtual void Subtract(const nsIRegion &aRegion);
virtual void Subtract(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight);
virtual PRBool IsEmpty(void);
virtual PRBool IsEqual(const nsIRegion &aRegion);
virtual void GetBoundingBox(PRInt32 *aX, PRInt32 *aY, PRInt32 *aWidth, PRInt32 *aHeight);

View File

@@ -475,12 +475,33 @@ void nsRenderingContextWin :: SetClipRegion(const nsIRegion& aRegion, nsClipComb
{
nsRegionWin *pRegion = (nsRegionWin *)&aRegion;
HRGN hrgn = pRegion->GetHRGN();
int cmode;
switch (aCombine)
{
case nsClipCombine_kIntersect:
cmode = RGN_AND;
break;
case nsClipCombine_kUnion:
cmode = RGN_OR;
break;
case nsClipCombine_kSubtract:
cmode = RGN_DIFF;
break;
default:
case nsClipCombine_kReplace:
cmode = RGN_COPY;
break;
}
if (NULL != hrgn)
{
mStates->mFlags &= ~FLAG_LOCAL_CLIP_VALID;
PushClipState();
::SelectClipRgn(mDC, hrgn);
::ExtSelectClipRgn(mDC, hrgn, cmode);
}
}

View File

@@ -134,8 +134,8 @@ public:
* @param region nsIRegion to be updated
* @param aUpdateFlags see bottom of nsIViewManager.h for description
*/
virtual void Refresh(nsIRenderingContext *aContext, nsIRegion *region,
PRUint32 aUpdateFlags) = 0;
virtual void Refresh(nsIView *aView, nsIRenderingContext *aContext,
nsIRegion *region, PRUint32 aUpdateFlags) = 0;
/**
* Called to refresh an area of the root window. Often called in
@@ -352,5 +352,7 @@ public:
#define NS_VMREFRESH_SCREEN_RECT 0x0002
//update view now?
#define NS_VMREFRESH_IMMEDIATE 0x0004
//prevent "sync painting"
#define NS_VMREFRESH_NO_SYNC 0x0008
#endif // nsIViewManager_h___

View File

@@ -86,10 +86,7 @@ nsEventStatus PR_CALLBACK HandleEvent(nsGUIEvent *aEvent)
nsRect vrect, trect = *((nsPaintEvent*)aEvent)->rect;
nsIDeviceContext *dx = px->GetDeviceContext();
trect.x = NS_TO_INT_ROUND(trect.x * convert);
trect.y = NS_TO_INT_ROUND(trect.y * convert);
trect.width = NS_TO_INT_ROUND(trect.width * convert);
trect.height = NS_TO_INT_ROUND(trect.height * convert);
trect *= convert;
//see if the paint region is greater than .75 the area of our root view.
//if so, enable double buffered painting.

View File

@@ -24,11 +24,14 @@
#include "nsIDeviceContext.h"
#include "nsGfxCIID.h"
#include "nsIScrollableView.h"
#include "nsIRegion.h"
static const PRBool gsDebug = PR_FALSE;
#define UPDATE_QUANTUM 1000 / 40
//#define USE_DIRTY_RECT
static void vm_timer_callback(nsITimer *aTimer, void *aClosure)
{
nsViewManager *vm = (nsViewManager *)aClosure;
@@ -58,6 +61,7 @@ nsViewManager :: ~nsViewManager()
NS_IF_RELEASE(mRootWindow);
NS_IF_RELEASE(mRootView);
NS_IF_RELEASE(mDirtyRegion);
if (nsnull != mDrawingSurface)
{
@@ -272,8 +276,69 @@ void nsViewManager :: ResetScrolling(void)
}
}
void nsViewManager :: Refresh(nsIRenderingContext *aContext, nsIRegion *region, PRUint32 aUpdateFlags)
void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsIRegion *region, PRUint32 aUpdateFlags)
{
nsRect wrect;
nsIRenderingContext *localcx = nsnull;
nscoord xoff, yoff;
float scale;
if (nsnull == aContext)
{
localcx = CreateRenderingContext(*aView);
//couldn't get rendering context. ack.
if (nsnull == localcx)
{
NS_ASSERTION(PR_FALSE, "unable to create rendering context.");
return;
}
}
else
localcx = aContext;
if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER)
{
mRootWindow->GetBounds(wrect);
nsDrawingSurface ds = GetDrawingSurface(*localcx, wrect);
localcx->SelectOffScreenDrawingSurface(ds);
}
scale = mContext->GetTwipsToPixels();
GetWindowOffsets(&xoff, &yoff);
region->Offset(NS_TO_INT_ROUND(-xoff * scale), NS_TO_INT_ROUND(-yoff * scale));
// localcx->SetClipRegion(*region, nsClipCombine_kIntersect);
localcx->SetClipRegion(*region, nsClipCombine_kReplace);
region->Offset(NS_TO_INT_ROUND(xoff * scale), NS_TO_INT_ROUND(yoff * scale));
localcx->Translate(-xoff, -yoff);
nsRect trect;
region->GetBoundingBox(&trect.x, &trect.y, &trect.width, &trect.height);
trect *= mContext->GetPixelsToTwips();
localcx->PushState();
aView->Paint(*localcx, trect, 0);
localcx->PopState();
if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER)
localcx->CopyOffScreenBits(wrect);
if (localcx != aContext)
NS_RELEASE(localcx);
//is the dirty region the same as the region we just painted?
if ((region == mDirtyRegion) || region->IsEqual(*mDirtyRegion))
ClearDirtyRegion();
else
mDirtyRegion->Subtract(*region);
mLastRefresh = PR_Now();
}
void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsRect *rect, PRUint32 aUpdateFlags)
@@ -289,10 +354,10 @@ void nsViewManager :: Refresh(nsIView *aView, nsIRenderingContext *aContext, nsR
//couldn't get rendering context. ack.
if (nsnull == localcx)
{
printf("unable to get rc\n");
{
NS_ASSERTION(PR_FALSE, "unable to create rendering context.");
return;
}
}
}
else
localcx = aContext;
@@ -328,6 +393,8 @@ printf("unable to get rc\n");
if (localcx != aContext)
NS_RELEASE(localcx);
#ifdef USE_DIRTY_RECT
nsRect updaterect = *rect;
//does our dirty rect intersect the rect we just painted?
@@ -341,13 +408,36 @@ printf("unable to get rc\n");
ClearDirtyRegion();
}
#else
//subtract the area we just painted from the dirty region
if ((nsnull != mDirtyRegion) && !mDirtyRegion->IsEmpty())
{
nsRect pixrect = trect;
pixrect *= mContext->GetTwipsToPixels();
mDirtyRegion->Subtract(pixrect.x, pixrect.y, pixrect.width, pixrect.height);
}
#endif
mLastRefresh = PR_Now();
}
void nsViewManager :: Composite()
{
if ((nsnull != mRootView) && (mDirtyRect.IsEmpty() == PR_FALSE))
#ifdef USE_DIRTY_RECT
if ((nsnull != mRootView) && !mDirtyRect.IsEmpty())
Refresh(mRootView, nsnull, &mDirtyRect, NS_VMREFRESH_DOUBLE_BUFFER);
#else
if ((nsnull != mRootView) && (nsnull != mDirtyRegion) && !mDirtyRegion->IsEmpty())
Refresh(mRootView, nsnull, mDirtyRegion, NS_VMREFRESH_DOUBLE_BUFFER);
#endif
}
void nsViewManager :: UpdateView(nsIView *aView, nsIRegion *aRegion, PRUint32 aUpdateFlags)
@@ -388,16 +478,28 @@ void nsViewManager :: UpdateView(nsIView *aView, const nsRect &aRect, PRUint32 a
while (par = par->GetParent());
}
#ifdef USE_DIRTY_RECT
if (mDirtyRect.IsEmpty())
mDirtyRect = trect;
else
mDirtyRect.UnionRect(mDirtyRect, trect);
#else
AddRectToDirtyRegion(trect);
#endif
if (nsnull != mContext)
{
if (aUpdateFlags & NS_VMREFRESH_IMMEDIATE)
#ifdef USE_DIRTY_RECT
Refresh(mRootView, nsnull, &mDirtyRect, aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER);
else if (mFrameRate > 0)
#else
Refresh(mRootView, nsnull, mDirtyRegion, aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER);
#endif
else if ((mFrameRate > 0) && !(aUpdateFlags & NS_VMREFRESH_NO_SYNC))
{
PRTime now = PR_Now();
PRTime conversion, ustoms;
@@ -524,7 +626,7 @@ void nsViewManager :: RemoveChild(nsIView *parent, nsIView *child)
if ((nsnull != parent) && (nsnull != child))
{
UpdateView(child, nsnull, 0);
UpdateView(child, nsnull, NS_VMREFRESH_NO_SYNC);
parent->RemoveChild(child);
}
}
@@ -678,10 +780,19 @@ nsDrawingSurface nsViewManager :: GetDrawingSurface(nsIRenderingContext &aContex
void nsViewManager :: ClearDirtyRegion()
{
#ifdef USE_DIRTY_RECT
mDirtyRect.x = 0;
mDirtyRect.y = 0;
mDirtyRect.width = 0;
mDirtyRect.height = 0;
#else
if (nsnull != mDirtyRegion)
mDirtyRegion->SetTo(0, 0, 0, 0);
#endif
}
nsIRenderingContext * nsViewManager :: CreateRenderingContext(nsIView &aView)
@@ -727,3 +838,25 @@ nsIRenderingContext * nsViewManager :: CreateRenderingContext(nsIView &aView)
return cx;
}
void nsViewManager :: AddRectToDirtyRegion(nsRect &aRect)
{
if (nsnull == mDirtyRegion)
{
static NS_DEFINE_IID(kRegionCID, NS_REGION_CID);
static NS_DEFINE_IID(kIRegionIID, NS_IREGION_IID);
nsresult rv = NSRepository::CreateInstance(kRegionCID,
nsnull,
kIRegionIID,
(void **)&mDirtyRegion);
if (NS_OK != rv)
return;
}
nsRect trect = aRect;
trect *= mContext->GetTwipsToPixels();
mDirtyRegion->Union(trect.x, trect.y, trect.width, trect.height);
}

View File

@@ -73,8 +73,8 @@ public:
// the region or rectangle passed in should be in the window's
// coordinate space. Often called in response to a paint/redraw event
// from the native windowing system.
virtual void Refresh(nsIRenderingContext *aContext, nsIRegion *region,
PRUint32 aUpdateFlags);
virtual void Refresh(nsIView *aView, nsIRenderingContext *aContext,
nsIRegion *region, PRUint32 aUpdateFlags);
virtual void Refresh(nsIView* aView, nsIRenderingContext *aContext,
nsRect *rect, PRUint32 aUpdateFlags);
@@ -170,12 +170,14 @@ public:
private:
~nsViewManager();
nsIRenderingContext *CreateRenderingContext(nsIView &aView);
void AddRectToDirtyRegion(nsRect &aRect);
nsIPresContext *mContext;
nsIWidget *mRootWindow;
nsRect mDSBounds;
nsDrawingSurface mDrawingSurface;
PRTime mLastRefresh;
nsIRegion *mDirtyRegion;
public:
//these are public so that our timer callback can poke them.