From fdd55454e0827e74e46cac8d1842bb38a6a5f2de Mon Sep 17 00:00:00 2001 From: "kmcclusk%netscape.com" Date: Wed, 12 Dec 2001 01:35:31 +0000 Subject: [PATCH] Move management of the backbuffer from the viewmanager to the rendering context and make the backbuffer transient on WIN32 and GTK. bug 95952 sr=attinasi r=karnaze git-svn-id: svn://10.0.0.236/trunk@110332 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/gfx/public/nsIRenderingContext.h | 29 +++ mozilla/gfx/public/nsRenderingContextImpl.h | 62 ++++++ mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp | 13 ++ mozilla/gfx/src/gtk/nsRenderingContextGTK.h | 3 + mozilla/gfx/src/nsRenderingContextImpl.cpp | 171 +++++++++++++++ .../gfx/src/shared/nsRenderingContextImpl.cpp | 171 +++++++++++++++ .../gfx/src/windows/nsRenderingContextWin.cpp | 16 ++ .../gfx/src/windows/nsRenderingContextWin.h | 4 + mozilla/view/src/nsViewManager.cpp | 200 ++---------------- mozilla/view/src/nsViewManager.h | 47 ---- mozilla/widget/src/gtk/nsWindow.cpp | 4 + 11 files changed, 494 insertions(+), 226 deletions(-) diff --git a/mozilla/gfx/public/nsIRenderingContext.h b/mozilla/gfx/public/nsIRenderingContext.h index 61b19cad5c8..7f24bd11537 100644 --- a/mozilla/gfx/public/nsIRenderingContext.h +++ b/mozilla/gfx/public/nsIRenderingContext.h @@ -751,6 +751,35 @@ public: //~~~ NS_IMETHOD RetrieveCurrentNativeGraphicData(PRUint32 * ngd) = 0; + + /** + * Get a drawing surface used as a backbuffer. + * Depending on the platform this will either cause a backbuffer surface to be allocated + * or an existing cached backbuffer will be returned. If the backbuffer is being cached + * asking for aMaxSize which is different from a previous request may cause the platform + * to dump it's cached backbuffer and reallocate a backbuffer of a size which will allow aMaxSize + * buffer to be allocated. + * + * @param aRequestedSize size of the backbuffer area requested + * @param aMaxSize maximum size that may be requested for the backbuffer + * @param aBackbuffer drawing surface used as the backbuffer + */ + NS_IMETHOD GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer) = 0; + + /** + * Release a drawing surface used as the backbuffer + * If the platform caches the backbuffer this call will destroy it. + */ + NS_IMETHOD ReleaseBackbuffer(void) = 0; + + /** + * Destroy the drawing surface used as the backbuffer. If the platform + * does not maintain a cached backbuffer this call will do nothing. + */ + NS_IMETHOD DestroyCachedBackbuffer(void) = 0; + + + #ifdef MOZ_MATHML /** * Returns bounding metrics (in app units) of an 8-bit character string diff --git a/mozilla/gfx/public/nsRenderingContextImpl.h b/mozilla/gfx/public/nsRenderingContextImpl.h index c526a15fe1d..14ec2d067b7 100644 --- a/mozilla/gfx/public/nsRenderingContextImpl.h +++ b/mozilla/gfx/public/nsRenderingContextImpl.h @@ -41,6 +41,7 @@ #include "nsIRenderingContext.h" #include "nsPoint.h" +#include "nsSize.h" typedef struct { @@ -115,6 +116,10 @@ public: */ NS_IMETHOD FillStdPolygon(const nsPoint aPoints[], PRInt32 aNumPoints) { return NS_OK; } + NS_IMETHOD GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer); + NS_IMETHOD ReleaseBackbuffer(void); + NS_IMETHOD DestroyCachedBackbuffer(void); + #ifdef IBMBIDI /** * Let the device context know whether we want text reordered with @@ -157,10 +162,67 @@ protected: void cdelete(int i); void cinsert(int i,int y,const nsPoint aPointArray[],PRInt32 aNumPts); + /** + * Determine if a rect's width and height will fit within a specified width and height + * @param aRect rectangle to test + * @param aWidth width to determine if the rectangle's width will fit within + * @param aHeight height to determine if the rectangles height will fit within + * @returns PR_TRUE if the rect width and height fits with aWidth, aHeight, PR_FALSE + * otherwise. + */ + + PRBool RectFitsInside(const nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const; + + /** + * Determine if two rectangles width and height will fit within a specified width and height + * @param aRect1 first rectangle to test + * @param aRect1 second rectangle to test + * @param aWidth width to determine if both rectangle's width will fit within + * @param aHeight height to determine if both rectangles height will fit within + * @returns PR_TRUE if the rect1's and rect2's width and height fits with aWidth, + * aHeight, PR_FALSE otherwise. + */ + PRBool BothRectsFitInside(const nsRect& aRect1, const nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const; + + /** + * Return an offscreen surface size from a set of discrete surface sizes. + * The smallest discrete surface size that can enclose both the Maximum widget + * size (@see GetMaxWidgetBounds) and the requested size is returned. + * + * @param aMaxBackbufferSize Maximum size that may be requested for the backbuffer + * @param aRequestedSize Requested size for the offscreen. + * @param aSurfaceSize contains the surface size + */ + void CalculateDiscreteSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aSize); + + /** + * Get the size of the offscreen drawing surface.. + * + * @param aMaxBackbufferSize Maximum size that may be requested for the backbuffer + * @param aRequestedSize Desired size for the offscreen. + * @param aSurfaceSize Offscreen adjusted to a discrete size which encloses aRequestedSize. + */ + void GetDrawingSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aSurfaceSize); + + /** + * Utility method used to implement NS_IMETHOD GetBackbuffer + * + * @param aRequestedSize size of the backbuffer area requested + * @param aMaxSize maximum size that may be requested for the backbuffer + * @param aBackbuffer drawing surface used as the backbuffer + * @param aCacheBackbuffer PR_TRUE then the backbuffer will be cached, if PR_FALSE it is created each time + */ + nsresult AllocateBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer, PRBool aCacheBackbuffer); + public: protected: nsPenMode mPenMode; +private: + static nsDrawingSurface gBackbuffer; //singleton backbuffer + static nsRect gBackbufferBounds; //backbuffer bounds + // Largest requested offscreen size if larger than a full screen. + static nsSize gLargestRequestedSize; }; diff --git a/mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp b/mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp index 43bfa87efcf..213e4d6300b 100644 --- a/mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp +++ b/mozilla/gfx/src/gtk/nsRenderingContextGTK.cpp @@ -2047,3 +2047,16 @@ NS_IMETHODIMP nsRenderingContextGTK::DrawScaledImage(imgIContainer *aImage, cons UpdateGC(); return nsRenderingContextImpl::DrawScaledImage(aImage, aSrcRect, aDestRect); } + +NS_IMETHODIMP nsRenderingContextGTK::GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer) +{ + // Do not cache the backbuffer. On GTK it is more efficient to allocate + // the backbuffer as needed and it doesn't cause a performance hit. @see bug 95952 + return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE); +} + +NS_IMETHODIMP nsRenderingContextGTK::ReleaseBackbuffer(void) { + // Do not cache the backbuffer. On GTK it is more efficient to allocate + // the backbuffer as needed and it doesn't cause a performance hit. @see bug 95952 + return DestroyCachedBackbuffer(); +} diff --git a/mozilla/gfx/src/gtk/nsRenderingContextGTK.h b/mozilla/gfx/src/gtk/nsRenderingContextGTK.h index 902f0e48127..a34e518eed6 100644 --- a/mozilla/gfx/src/gtk/nsRenderingContextGTK.h +++ b/mozilla/gfx/src/gtk/nsRenderingContextGTK.h @@ -188,6 +188,9 @@ public: NS_IMETHOD DrawImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsPoint * aDestPoint); NS_IMETHOD DrawScaledImage(imgIContainer *aImage, const nsRect * aSrcRect, const nsRect * aDestRect); + NS_IMETHOD GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer); + NS_IMETHOD ReleaseBackbuffer(void); + #ifdef MOZ_MATHML /** * Returns metrics (in app units) of an 8-bit character string diff --git a/mozilla/gfx/src/nsRenderingContextImpl.cpp b/mozilla/gfx/src/nsRenderingContextImpl.cpp index e75d84b134e..3a5228cb500 100644 --- a/mozilla/gfx/src/nsRenderingContextImpl.cpp +++ b/mozilla/gfx/src/nsRenderingContextImpl.cpp @@ -45,6 +45,10 @@ const nsPoint *gPts; +nsDrawingSurface nsRenderingContextImpl::gBackbuffer = nsnull; +nsRect nsRenderingContextImpl::gBackbufferBounds = nsRect(0, 0, 0, 0); +nsSize nsRenderingContextImpl::gLargestRequestedSize = nsSize(0, 0); + // comparison routines for qsort PRInt32 PR_CALLBACK compare_ind(const void *u,const void *v){return gPts[(PRInt32)*((PRInt32*)u)].y <= gPts[(PRInt32)*((PRInt32*)v)].y ? -1 : 1;} PRInt32 PR_CALLBACK compare_active(const void *u,const void *v){return ((Edge*)u)->x <= ((Edge*)v)->x ? -1 : 1;} @@ -451,6 +455,173 @@ PRInt32 flag = NS_COPYBITS_TO_BACK_BUFFER | NS_COPYBITS_XFORM_DEST_VALUES; } } +NS_IMETHODIMP nsRenderingContextImpl::GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer) +{ + // Default implementation assumes the backbuffer will be cached. + // If the platform implementation does not require the backbuffer to + // be cached override this method and make the following call instead: + // AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE); + return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_TRUE); +} + +nsresult nsRenderingContextImpl::AllocateBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer, PRBool aCacheBackbuffer) +{ + nsRect newBounds; + nsresult rv = NS_OK; + + if (! aCacheBackbuffer) { + newBounds = aRequestedSize; + } else { + GetDrawingSurfaceSize(aMaxSize, aRequestedSize, newBounds); + } + + if ((nsnull == gBackbuffer) + || (gBackbufferBounds.width != newBounds.width) + || (gBackbufferBounds.height != newBounds.height)) + { + if (gBackbuffer) { + //destroy existing DS + DestroyDrawingSurface(gBackbuffer); + gBackbuffer = nsnull; + } + + rv = CreateDrawingSurface(&newBounds, 0, gBackbuffer); + // printf("Allocating a new drawing surface %d %d\n", newBounds.width, newBounds.height); + if (NS_SUCCEEDED(rv)) { + gBackbufferBounds = newBounds; + SelectOffScreenDrawingSurface(gBackbuffer); + } else { + gBackbufferBounds.SetRect(0,0,0,0); + gBackbuffer = nsnull; + } + } else { + SelectOffScreenDrawingSurface(gBackbuffer); + + float p2t; + nsCOMPtr dx; + GetDeviceContext(*getter_AddRefs(dx)); + dx->GetDevUnitsToAppUnits(p2t); + nsRect bounds = aRequestedSize; + bounds *= p2t; + + PRBool clipEmpty; + SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty); + } + + aBackbuffer = gBackbuffer; + return rv; +} + +NS_IMETHODIMP nsRenderingContextImpl::ReleaseBackbuffer(void) +{ + // If the platform does not require the backbuffer to be cached + // override this method and call DestroyCachedBackbuffer + return NS_OK; +} + +NS_IMETHODIMP nsRenderingContextImpl::DestroyCachedBackbuffer(void) +{ + if (gBackbuffer) { + DestroyDrawingSurface(gBackbuffer); + gBackbuffer = nsnull; + } + return NS_OK; +} + +PRBool nsRenderingContextImpl::RectFitsInside(const nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const +{ + if (aRect.width > aWidth) + return (PR_FALSE); + + if (aRect.height > aHeight) + return (PR_FALSE); + + return PR_TRUE; +} + +PRBool nsRenderingContextImpl::BothRectsFitInside(const nsRect& aRect1, const nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const +{ + if (PR_FALSE == RectFitsInside(aRect1, aWidth, aHeight)) { + return PR_FALSE; + } + + if (PR_FALSE == RectFitsInside(aRect2, aWidth, aHeight)) { + return PR_FALSE; + } + + aNewSize.width = aWidth; + aNewSize.height = aHeight; + + return PR_TRUE; +} + +void nsRenderingContextImpl::GetDrawingSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aNewSize) +{ + CalculateDiscreteSurfaceSize(aMaxBackbufferSize, aRequestedSize, aNewSize); + aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); +} + +void nsRenderingContextImpl::CalculateDiscreteSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aSurfaceSize) +{ + // Get the height and width of the screen + PRInt32 height; + PRInt32 width; + + nsCOMPtr dx; + GetDeviceContext(*getter_AddRefs(dx)); + dx->GetDeviceSurfaceDimensions(width, height); + + float devUnits; + dx->GetDevUnitsToAppUnits(devUnits); + PRInt32 screenHeight = NSToIntRound(float( height) / devUnits ); + PRInt32 screenWidth = NSToIntRound(float( width) / devUnits ); + + // These tests must go from smallest rectangle to largest rectangle. + + // 1/8 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 8, screenHeight / 8, aSurfaceSize)) { + return; + } + + // 1/4 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 4, screenHeight / 4, aSurfaceSize)) { + return; + } + + // 1/2 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 2, screenHeight / 2, aSurfaceSize)) { + return; + } + + // 3/4 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, (screenWidth * 3) / 4, (screenHeight * 3) / 4, aSurfaceSize)) { + return; + } + + // 3/4 screen width full screen height + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, (screenWidth * 3) / 4, screenHeight, aSurfaceSize)) { + return; + } + + // Full screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth, screenHeight, aSurfaceSize)) { + return; + } + + // Bigger than Full Screen use the largest request every made. + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, gLargestRequestedSize.width, gLargestRequestedSize.height, aSurfaceSize)) { + return; + } else { + gLargestRequestedSize.width = PR_MAX(aRequestedSize.width, aMaxBackbufferSize.width); + gLargestRequestedSize.height = PR_MAX(aRequestedSize.height, aMaxBackbufferSize.height); + aSurfaceSize.width = gLargestRequestedSize.width; + aSurfaceSize.height = gLargestRequestedSize.height; + // printf("Expanding the largested requested size to %d %d\n", gLargestRequestedSize.width, gLargestRequestedSize.height); + } +} + + + #ifdef IBMBIDI /** * Let the device context know whether we want text reordered with diff --git a/mozilla/gfx/src/shared/nsRenderingContextImpl.cpp b/mozilla/gfx/src/shared/nsRenderingContextImpl.cpp index e75d84b134e..3a5228cb500 100644 --- a/mozilla/gfx/src/shared/nsRenderingContextImpl.cpp +++ b/mozilla/gfx/src/shared/nsRenderingContextImpl.cpp @@ -45,6 +45,10 @@ const nsPoint *gPts; +nsDrawingSurface nsRenderingContextImpl::gBackbuffer = nsnull; +nsRect nsRenderingContextImpl::gBackbufferBounds = nsRect(0, 0, 0, 0); +nsSize nsRenderingContextImpl::gLargestRequestedSize = nsSize(0, 0); + // comparison routines for qsort PRInt32 PR_CALLBACK compare_ind(const void *u,const void *v){return gPts[(PRInt32)*((PRInt32*)u)].y <= gPts[(PRInt32)*((PRInt32*)v)].y ? -1 : 1;} PRInt32 PR_CALLBACK compare_active(const void *u,const void *v){return ((Edge*)u)->x <= ((Edge*)v)->x ? -1 : 1;} @@ -451,6 +455,173 @@ PRInt32 flag = NS_COPYBITS_TO_BACK_BUFFER | NS_COPYBITS_XFORM_DEST_VALUES; } } +NS_IMETHODIMP nsRenderingContextImpl::GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer) +{ + // Default implementation assumes the backbuffer will be cached. + // If the platform implementation does not require the backbuffer to + // be cached override this method and make the following call instead: + // AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE); + return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_TRUE); +} + +nsresult nsRenderingContextImpl::AllocateBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer, PRBool aCacheBackbuffer) +{ + nsRect newBounds; + nsresult rv = NS_OK; + + if (! aCacheBackbuffer) { + newBounds = aRequestedSize; + } else { + GetDrawingSurfaceSize(aMaxSize, aRequestedSize, newBounds); + } + + if ((nsnull == gBackbuffer) + || (gBackbufferBounds.width != newBounds.width) + || (gBackbufferBounds.height != newBounds.height)) + { + if (gBackbuffer) { + //destroy existing DS + DestroyDrawingSurface(gBackbuffer); + gBackbuffer = nsnull; + } + + rv = CreateDrawingSurface(&newBounds, 0, gBackbuffer); + // printf("Allocating a new drawing surface %d %d\n", newBounds.width, newBounds.height); + if (NS_SUCCEEDED(rv)) { + gBackbufferBounds = newBounds; + SelectOffScreenDrawingSurface(gBackbuffer); + } else { + gBackbufferBounds.SetRect(0,0,0,0); + gBackbuffer = nsnull; + } + } else { + SelectOffScreenDrawingSurface(gBackbuffer); + + float p2t; + nsCOMPtr dx; + GetDeviceContext(*getter_AddRefs(dx)); + dx->GetDevUnitsToAppUnits(p2t); + nsRect bounds = aRequestedSize; + bounds *= p2t; + + PRBool clipEmpty; + SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty); + } + + aBackbuffer = gBackbuffer; + return rv; +} + +NS_IMETHODIMP nsRenderingContextImpl::ReleaseBackbuffer(void) +{ + // If the platform does not require the backbuffer to be cached + // override this method and call DestroyCachedBackbuffer + return NS_OK; +} + +NS_IMETHODIMP nsRenderingContextImpl::DestroyCachedBackbuffer(void) +{ + if (gBackbuffer) { + DestroyDrawingSurface(gBackbuffer); + gBackbuffer = nsnull; + } + return NS_OK; +} + +PRBool nsRenderingContextImpl::RectFitsInside(const nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const +{ + if (aRect.width > aWidth) + return (PR_FALSE); + + if (aRect.height > aHeight) + return (PR_FALSE); + + return PR_TRUE; +} + +PRBool nsRenderingContextImpl::BothRectsFitInside(const nsRect& aRect1, const nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const +{ + if (PR_FALSE == RectFitsInside(aRect1, aWidth, aHeight)) { + return PR_FALSE; + } + + if (PR_FALSE == RectFitsInside(aRect2, aWidth, aHeight)) { + return PR_FALSE; + } + + aNewSize.width = aWidth; + aNewSize.height = aHeight; + + return PR_TRUE; +} + +void nsRenderingContextImpl::GetDrawingSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aNewSize) +{ + CalculateDiscreteSurfaceSize(aMaxBackbufferSize, aRequestedSize, aNewSize); + aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); +} + +void nsRenderingContextImpl::CalculateDiscreteSurfaceSize(const nsRect& aMaxBackbufferSize, const nsRect& aRequestedSize, nsRect& aSurfaceSize) +{ + // Get the height and width of the screen + PRInt32 height; + PRInt32 width; + + nsCOMPtr dx; + GetDeviceContext(*getter_AddRefs(dx)); + dx->GetDeviceSurfaceDimensions(width, height); + + float devUnits; + dx->GetDevUnitsToAppUnits(devUnits); + PRInt32 screenHeight = NSToIntRound(float( height) / devUnits ); + PRInt32 screenWidth = NSToIntRound(float( width) / devUnits ); + + // These tests must go from smallest rectangle to largest rectangle. + + // 1/8 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 8, screenHeight / 8, aSurfaceSize)) { + return; + } + + // 1/4 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 4, screenHeight / 4, aSurfaceSize)) { + return; + } + + // 1/2 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth / 2, screenHeight / 2, aSurfaceSize)) { + return; + } + + // 3/4 screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, (screenWidth * 3) / 4, (screenHeight * 3) / 4, aSurfaceSize)) { + return; + } + + // 3/4 screen width full screen height + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, (screenWidth * 3) / 4, screenHeight, aSurfaceSize)) { + return; + } + + // Full screen + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, screenWidth, screenHeight, aSurfaceSize)) { + return; + } + + // Bigger than Full Screen use the largest request every made. + if (BothRectsFitInside(aRequestedSize, aMaxBackbufferSize, gLargestRequestedSize.width, gLargestRequestedSize.height, aSurfaceSize)) { + return; + } else { + gLargestRequestedSize.width = PR_MAX(aRequestedSize.width, aMaxBackbufferSize.width); + gLargestRequestedSize.height = PR_MAX(aRequestedSize.height, aMaxBackbufferSize.height); + aSurfaceSize.width = gLargestRequestedSize.width; + aSurfaceSize.height = gLargestRequestedSize.height; + // printf("Expanding the largested requested size to %d %d\n", gLargestRequestedSize.width, gLargestRequestedSize.height); + } +} + + + #ifdef IBMBIDI /** * Let the device context know whether we want text reordered with diff --git a/mozilla/gfx/src/windows/nsRenderingContextWin.cpp b/mozilla/gfx/src/windows/nsRenderingContextWin.cpp index c7ba51ef8fe..8b6663affc9 100644 --- a/mozilla/gfx/src/windows/nsRenderingContextWin.cpp +++ b/mozilla/gfx/src/windows/nsRenderingContextWin.cpp @@ -2988,6 +2988,22 @@ nsRenderingContextWin::ConditionRect(nsRect& aSrcRect, RECT& aDestRect) : (aSrcRect.x+aSrcRect.width); } + +NS_IMETHODIMP +nsRenderingContextWin::GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer) +{ + // Do not cache the backbuffer. On WIN32 it is faster to get allocate + // the backbuffer as needed. @see bug 95952 + return AllocateBackbuffer(aRequestedSize, aMaxSize, aBackbuffer, PR_FALSE); +} + +NS_IMETHODIMP +nsRenderingContextWin::ReleaseBackbuffer(void) { + // Destroy the backbuffer. Do not cache it. On WIN32 it is faster to get allocate + // the backbuffer as needed. @see bug 95952 + return DestroyCachedBackbuffer(); +} + #ifdef IBMBIDI /** * Let the device context know whether we want text reordered with diff --git a/mozilla/gfx/src/windows/nsRenderingContextWin.h b/mozilla/gfx/src/windows/nsRenderingContextWin.h index 5d698029a8d..c6b98c5feb6 100644 --- a/mozilla/gfx/src/windows/nsRenderingContextWin.h +++ b/mozilla/gfx/src/windows/nsRenderingContextWin.h @@ -192,6 +192,10 @@ public: // nsIRenderingContextWin NS_IMETHOD CreateDrawingSurface(HDC aDC, nsDrawingSurface &aSurface); + NS_IMETHOD GetBackbuffer(const nsRect &aRequestedSize, const nsRect &aMaxSize, nsDrawingSurface &aBackbuffer); + + NS_IMETHOD ReleaseBackbuffer(void); + #ifdef MOZ_MATHML NS_IMETHOD GetBoundingMetrics(const char* aString, diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index 6b63219bfe7..449992678a2 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -275,21 +275,15 @@ nsViewManager::PostInvalidateEvent() } PRInt32 nsViewManager::mVMCount = 0; -nsDrawingSurface nsViewManager::mDrawingSurface = nsnull; -nsRect nsViewManager::mDSBounds = nsRect(0, 0, 0, 0); - nsIRenderingContext* nsViewManager::gCleanupContext = nsnull; nsDrawingSurface nsViewManager::gOffScreen = nsnull; nsDrawingSurface nsViewManager::gBlack = nsnull; nsDrawingSurface nsViewManager::gWhite = nsnull; nsSize nsViewManager::gOffScreenSize = nsSize(0, 0); -nsSize nsViewManager::gLargestRequestedSize = nsSize(0, 0); - // Weakly held references to all of the view managers nsVoidArray* nsViewManager::gViewManagers = nsnull; PRUint32 nsViewManager::gLastUserEventTime = 0; -PRBool nsViewManager::gTransitoryBackbuffer = PR_FALSE; nsViewManager::nsViewManager() { @@ -357,8 +351,8 @@ nsViewManager::~nsViewManager() // viewmanager is typically destroyed during XPCOM shutdown. if (gCleanupContext) { - if (nsnull != mDrawingSurface) - gCleanupContext->DestroyDrawingSurface(mDrawingSurface); + + gCleanupContext->DestroyCachedBackbuffer(); if (nsnull != gOffScreen) gCleanupContext->DestroyDrawingSurface(gOffScreen); @@ -373,7 +367,6 @@ nsViewManager::~nsViewManager() NS_ASSERTION(PR_FALSE, "Cleanup of drawing surfaces + offscreen buffer failed"); } - mDrawingSurface = nsnull; gOffScreen = nsnull; gWhite = nsnull; gBlack = nsnull; @@ -487,11 +480,6 @@ NS_IMETHODIMP nsViewManager::Init(nsIDeviceContext* aContext) NS_ASSERTION(nsnull != mEventQueue, "event queue is null"); } - - nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); - if (prefs) { - prefs->GetBoolPref("layout.transitory.backbuffer", &gTransitoryBackbuffer); - } return rv; } @@ -664,13 +652,19 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIReg } if (aUpdateFlags & NS_VMREFRESH_DOUBLE_BUFFER) - { - nsCOMPtr widget; - aView->GetWidget(*getter_AddRefs(widget)); - widget->GetClientBounds(wrect); - wrect.x = wrect.y = 0; - ds = GetDrawingSurface(*localcx, wrect); + { + nsCOMPtr widget; + aView->GetWidget(*getter_AddRefs(widget)); + widget->GetClientBounds(wrect); + wrect.x = wrect.y = 0; + + nsRect maxWidgetSize; + GetMaxWidgetBounds(maxWidgetSize); + if NS_FAILED(localcx->GetBackbuffer(wrect, maxWidgetSize, ds)) { + //Failed to get backbuffer so turn off double buffering + aUpdateFlags &= ~NS_VMREFRESH_DOUBLE_BUFFER; } + } nsRect viewRect; aView->GetBounds(viewRect); @@ -721,11 +715,7 @@ void nsViewManager::Refresh(nsView *aView, nsIRenderingContext *aContext, nsIReg mRecursiveRefreshPending = PR_FALSE; } - if ((gTransitoryBackbuffer) && (mDrawingSurface)) { - //Destroy backbuffer drawing surface - localcx->DestroyDrawingSurface(mDrawingSurface); - mDrawingSurface = nsnull; - } + localcx->ReleaseBackbuffer(); #ifdef NS_VM_PERF_METRICS MOZ_TIMER_DEBUGLOG(("Stop: nsViewManager::Refresh(region), this=%p\n", this)); @@ -1830,13 +1820,13 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent, nsEventStatus *aS case NS_DISPLAYCHANGED: - // Reset the offscreens width and height - // so it will be reallocated the next time it needs to - // draw. It needs to be reallocated because it's depth - // has changed. @see bugzilla bug 6061 + //Destroy the cached backbuffer to force a new backbuffer + //be constructed with the appropriate display depth. + //@see bugzilla bug 6061 *aStatus = nsEventStatus_eConsumeDoDefault; - mDSBounds.width = 0; - mDSBounds.height = 0; + if (gCleanupContext) { + gCleanupContext->DestroyCachedBackbuffer(); + } break; @@ -2502,164 +2492,16 @@ void nsViewManager::GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const // printf("WIDGET BOUNDS %d %d\n", aMaxWidgetBounds.width, aMaxWidgetBounds.height); } -PRBool nsViewManager::RectFitsInside(nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const -{ - if (aRect.width > aWidth) - return (PR_FALSE); - - if (aRect.height > aHeight) - return (PR_FALSE); - - return PR_TRUE; -} - -PRBool nsViewManager::BothRectsFitInside(nsRect& aRect1, nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const -{ - if (PR_FALSE == RectFitsInside(aRect1, aWidth, aHeight)) { - return PR_FALSE; - } - - if (PR_FALSE == RectFitsInside(aRect2, aWidth, aHeight)) { - return PR_FALSE; - } - - aNewSize.width = aWidth; - aNewSize.height = aHeight; - - return PR_TRUE; -} - - -void nsViewManager::CalculateDiscreteSurfaceSize(nsRect& aRequestedSize, nsRect& aSurfaceSize) const -{ - nsRect aMaxWidgetSize; - GetMaxWidgetBounds(aMaxWidgetSize); - - // Get the height and width of the screen - PRInt32 height; - PRInt32 width; - NS_ASSERTION(mContext != nsnull, "The device context is null"); - mContext->GetDeviceSurfaceDimensions(width, height); - - float devUnits; - mContext->GetDevUnitsToAppUnits(devUnits); - PRInt32 screenHeight = NSToIntRound(float( height) / devUnits ); - PRInt32 screenWidth = NSToIntRound(float( width) / devUnits ); - - // These tests must go from smallest rectangle to largest rectangle. - - // 1/8 screen - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth / 8, screenHeight / 8, aSurfaceSize)) { - return; - } - - // 1/4 screen - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth / 4, screenHeight / 4, aSurfaceSize)) { - return; - } - - // 1/2 screen - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth / 2, screenHeight / 2, aSurfaceSize)) { - return; - } - - // 3/4 screen - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, (screenWidth * 3) / 4, (screenHeight * 3) / 4, aSurfaceSize)) { - return; - } - - // 3/4 screen width full screen height - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, (screenWidth * 3) / 4, screenHeight, aSurfaceSize)) { - return; - } - - // Full screen - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, screenWidth, screenHeight, aSurfaceSize)) { - return; - } - - // Bigger than Full Screen use the largest request every made. - if (BothRectsFitInside(aRequestedSize, aMaxWidgetSize, gLargestRequestedSize.width, gLargestRequestedSize.height, aSurfaceSize)) { - return; - } else { - gLargestRequestedSize.width = PR_MAX(aRequestedSize.width, aMaxWidgetSize.width); - gLargestRequestedSize.height = PR_MAX(aRequestedSize.height, aMaxWidgetSize.height); - aSurfaceSize.width = gLargestRequestedSize.width; - aSurfaceSize.height = gLargestRequestedSize.height; - // printf("Expanding the largested requested size to %d %d\n", gLargestRequestedSize.width, gLargestRequestedSize.height); - } -} - -void nsViewManager::GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aNewSize) const -{ - CalculateDiscreteSurfaceSize(aRequestedSize, aNewSize); - aNewSize.MoveTo(aRequestedSize.x, aRequestedSize.y); -} - PRInt32 nsViewManager::GetViewManagerCount() { return mVMCount; } - const nsVoidArray* nsViewManager::GetViewManagerArray() { return gViewManagers; } - -nsDrawingSurface nsViewManager::GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds) -{ - nsRect newBounds; - - if (gTransitoryBackbuffer) { - newBounds = aBounds; - } else { - GetDrawingSurfaceSize(aBounds, newBounds); - } - - - if ((nsnull == mDrawingSurface) - || (mDSBounds.width != newBounds.width) - || (mDSBounds.height != newBounds.height)) - { - if (mDrawingSurface) { - //destroy existing DS - aContext.DestroyDrawingSurface(mDrawingSurface); - mDrawingSurface = nsnull; - } - - nsresult rv = aContext.CreateDrawingSurface(&newBounds, 0, mDrawingSurface); - // printf("Allocating a new drawing surface %d %d\n", newBounds.width, newBounds.height); - if (NS_SUCCEEDED(rv)) { - mDSBounds = newBounds; - aContext.SelectOffScreenDrawingSurface(mDrawingSurface); - } else { - mDSBounds.SetRect(0,0,0,0); - mDrawingSurface = nsnull; - } - } else { - aContext.SelectOffScreenDrawingSurface(mDrawingSurface); - - float p2t; - mContext->GetDevUnitsToAppUnits(p2t); - nsRect bounds = aBounds; - bounds *= p2t; - - PRBool clipEmpty; - aContext.SetClipRect(bounds, nsClipCombine_kReplace, clipEmpty); - - // This is not be needed. Only the part of the offscreen that has been - // rendered to should be displayed so there no need to - // clear it out. - //nscolor col = NS_RGB(255,255,255); - //aContext.SetColor(col); - //aContext.FillRect(bounds); - } - - return mDrawingSurface; -} - NS_IMETHODIMP nsViewManager::ShowQuality(PRBool aShow) { if (nsnull != mRootScrollable) diff --git a/mozilla/view/src/nsViewManager.h b/mozilla/view/src/nsViewManager.h index ab5a20d447d..d5e65273b17 100644 --- a/mozilla/view/src/nsViewManager.h +++ b/mozilla/view/src/nsViewManager.h @@ -212,8 +212,6 @@ public: NS_IMETHOD SetRootScrollableView(nsIScrollableView *aScrollable); NS_IMETHOD GetRootScrollableView(nsIScrollableView **aScrollable); - nsDrawingSurface GetDrawingSurface(nsIRenderingContext &aContext, nsRect& aBounds); - NS_IMETHOD Display(nsIView *aView, nscoord aX, nscoord aY, const nsRect& aClipRect); NS_IMETHOD AddCompositeListener(nsICompositeListener *aListener); @@ -352,45 +350,6 @@ private: */ void GetMaxWidgetBounds(nsRect& aMaxWidgetBounds) const; - /** - * Determine if a rect's width and height will fit within a specified width and height - * @param aRect rectangle to test - * @param aWidth width to determine if the rectangle's width will fit within - * @param aHeight height to determine if the rectangles height will fit within - * @returns PR_TRUE if the rect width and height fits with aWidth, aHeight, PR_FALSE - * otherwise. - */ - PRBool RectFitsInside(nsRect& aRect, PRInt32 aWidth, PRInt32 aHeight) const; - - /** - * Determine if two rectangles width and height will fit within a specified width and height - * @param aRect1 first rectangle to test - * @param aRect1 second rectangle to test - * @param aWidth width to determine if both rectangle's width will fit within - * @param aHeight height to determine if both rectangles height will fit within - * @returns PR_TRUE if the rect1's and rect2's width and height fits with aWidth, - * aHeight, PR_FALSE otherwise. - */ - PRBool BothRectsFitInside(nsRect& aRect1, nsRect& aRect2, PRInt32 aWidth, PRInt32 aHeight, nsRect& aNewSize) const; - - /** - * Return an offscreen surface size from a set of discrete surface sizes. - * The smallest discrete surface size that can enclose both the Maximum widget - * size (@see GetMaxWidgetBounds) and the requested size is returned. - * - * @param aRequestedSize Requested size for the offscreen. - * @param aSurfaceSize contains the surface size - */ - void CalculateDiscreteSurfaceSize(nsRect& aRequestedSize, nsRect& aSize) const; - - /** - * Get the size of the offscreen drawing surface.. - * - * @param aRequestedSize Desired size for the offscreen. - * @param aSurfaceSize Offscreen adjusted to a discrete size which encloses aRequestedSize. - */ - void GetDrawingSurfaceSize(nsRect& aRequestedSize, nsRect& aSurfaceSize) const; - public: // NOT in nsIViewManager, so private to the view module nsView* GetRootView() const { return mRootView; } nsView* GetMouseEventGrabber() const { return mMouseGrabber; } @@ -423,8 +382,6 @@ private: //from here to public should be static and locked... MMP static PRInt32 mVMCount; //number of viewmanagers - static nsDrawingSurface mDrawingSurface; //single drawing surface - static nsRect mDSBounds; //for all VMs //blending buffers static nsDrawingSurface gOffScreen; @@ -435,12 +392,8 @@ private: //Rendering context used to cleanup the blending buffers static nsIRenderingContext* gCleanupContext; - // Largest requested offscreen size if larger than a full screen. - static nsSize gLargestRequestedSize; - //list of view managers static nsVoidArray *gViewManagers; - static PRBool gTransitoryBackbuffer; //compositor regions nsIRegion *mOpaqueRgn; diff --git a/mozilla/widget/src/gtk/nsWindow.cpp b/mozilla/widget/src/gtk/nsWindow.cpp index 959bdd2ea39..59b8ae72522 100644 --- a/mozilla/widget/src/gtk/nsWindow.cpp +++ b/mozilla/widget/src/gtk/nsWindow.cpp @@ -737,6 +737,10 @@ void nsWindow::DoPaint (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight, nsIRegion *aClipRegion) { + //Don't dispatch paint event if widget's height or width is 0 + if ((mBounds.width == 0) || (mBounds.height == 0)) { + return; + } #ifdef NS_DEBUG if (this == debugWidget) {