diff --git a/mozilla/gfx/src/motif/nsRegionUnix.cpp b/mozilla/gfx/src/motif/nsRegionUnix.cpp index 681ebce5cf1..71c96e6f56c 100644 --- a/mozilla/gfx/src/motif/nsRegionUnix.cpp +++ b/mozilla/gfx/src/motif/nsRegionUnix.cpp @@ -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; diff --git a/mozilla/gfx/src/nsIRegion.h b/mozilla/gfx/src/nsIRegion.h index 9e20ece4dd1..3ac5f297291 100644 --- a/mozilla/gfx/src/nsIRegion.h +++ b/mozilla/gfx/src/nsIRegion.h @@ -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 diff --git a/mozilla/gfx/src/windows/nsRegionWin.cpp b/mozilla/gfx/src/windows/nsRegionWin.cpp index 74f9b2cddce..075a892cb98 100644 --- a/mozilla/gfx/src/windows/nsRegionWin.cpp +++ b/mozilla/gfx/src/windows/nsRegionWin.cpp @@ -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; diff --git a/mozilla/gfx/src/windows/nsRegionWin.h b/mozilla/gfx/src/windows/nsRegionWin.h index ed5d193e917..bba6510f357 100644 --- a/mozilla/gfx/src/windows/nsRegionWin.h +++ b/mozilla/gfx/src/windows/nsRegionWin.h @@ -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); diff --git a/mozilla/gfx/src/windows/nsRenderingContextWin.cpp b/mozilla/gfx/src/windows/nsRenderingContextWin.cpp index 7c615c8bbf3..4c64115eae3 100644 --- a/mozilla/gfx/src/windows/nsRenderingContextWin.cpp +++ b/mozilla/gfx/src/windows/nsRenderingContextWin.cpp @@ -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); } } diff --git a/mozilla/view/public/nsIViewManager.h b/mozilla/view/public/nsIViewManager.h index f13a25501ce..f8acae822dc 100644 --- a/mozilla/view/public/nsIViewManager.h +++ b/mozilla/view/public/nsIViewManager.h @@ -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___ diff --git a/mozilla/view/src/nsView.cpp b/mozilla/view/src/nsView.cpp index 941ce229e0e..151ea104ba8 100644 --- a/mozilla/view/src/nsView.cpp +++ b/mozilla/view/src/nsView.cpp @@ -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. diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index 005107b8db2..2e63ebdfb17 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -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); +} diff --git a/mozilla/view/src/nsViewManager.h b/mozilla/view/src/nsViewManager.h index 18a12a85fb5..7813b7580b2 100644 --- a/mozilla/view/src/nsViewManager.h +++ b/mozilla/view/src/nsViewManager.h @@ -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.