From 58d0356b5391100b1fbae9fb899b42c739d77634 Mon Sep 17 00:00:00 2001 From: "rjesup%wgate.com" Date: Thu, 6 Sep 2001 23:00:49 +0000 Subject: [PATCH] bug 93999: reduce number of image creations in gtk/xlib. Patch by imot (Tomi.Leppikangas@oulu.fi). r=pavlov, sr=brendan, r=bbaetz on c++ issues, jst said "check it in" on c++ issues. --- gfx/src/Makefile.in | 4 +- gfx/src/gtk/nsImageGTK.cpp | 208 ++++++++++++++++++++--------------- gfx/src/gtk/nsImageGTK.h | 5 + gfx/src/nsRegion.cpp | 4 +- gfx/src/nsRegion.h | 9 +- gfx/src/xlib/nsImageXlib.cpp | 195 ++++++++++++++++++-------------- gfx/src/xlib/nsImageXlib.h | 5 + 7 files changed, 250 insertions(+), 180 deletions(-) diff --git a/gfx/src/Makefile.in b/gfx/src/Makefile.in index 377257f6dbf9..164d73c02332 100644 --- a/gfx/src/Makefile.in +++ b/gfx/src/Makefile.in @@ -87,8 +87,8 @@ CPPSRCS = \ nsPrintOptionsImpl.cpp \ $(NULL) -ifeq ($(MOZ_WIDGET_TOOLKIT),os2) -CPPSRCS += \ +ifneq (,$(filter gtk xlib os2,$(MOZ_WIDGET_TOOLKIT))) +CPPSRCS += \ nsRegion.cpp \ nsRegionImpl.cpp \ $(NULL) diff --git a/gfx/src/gtk/nsImageGTK.cpp b/gfx/src/gtk/nsImageGTK.cpp index b4b86c329099..f08a5b654567 100644 --- a/gfx/src/gtk/nsImageGTK.cpp +++ b/gfx/src/gtk/nsImageGTK.cpp @@ -73,6 +73,7 @@ nsImageGTK::nsImageGTK() mNaturalHeight = 0; mAlphaValid = PR_FALSE; mIsSpacer = PR_TRUE; + mPendingUpdate = PR_FALSE; #ifdef TRACE_IMAGE_ALLOCATION printf("nsImageGTK::nsImageGTK(this=%p)\n", @@ -279,12 +280,15 @@ void nsImageGTK::MoveAlphaMask(PRInt32 aX, PRInt32 aY) { } -//------------------------------------------------------------ - -// set up the palette to the passed in color array, RGB only in this array void nsImageGTK::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect) +{ + mPendingUpdate = PR_TRUE; + mUpdateRegion.Or(mUpdateRegion, *aUpdateRect); +} + +void nsImageGTK::UpdateCachedImage() { #ifdef TRACE_IMAGE_ALLOCATION printf("nsImageGTK::ImageUpdated(this=%p,%d)\n", @@ -292,105 +296,112 @@ void nsImageGTK::ImageUpdated(nsIDeviceContext *aContext, aFlags); #endif + nsRegionRectIterator ri(mUpdateRegion); + const nsRect *rect; + + while (rect = ri.Next()) { + // fprintf(stderr, "ImageUpdated %p x,y=(%d %d) width,height=(%d %d)\n", -// this, aUpdateRect->x, aUpdateRect->y, aUpdateRect->width, -// aUpdateRect->height); +// this, rect->x, rect->y, rect->width, rect->height); - unsigned bottom, left, right; - bottom = aUpdateRect->y + aUpdateRect->height; - left = aUpdateRect->x; - right = left + aUpdateRect->width; + unsigned bottom, left, right; + bottom = rect->y + rect->height; + left = rect->x; + right = left + rect->width; - // check if the image has an all-opaque 8-bit alpha mask - if ((mAlphaDepth==8) && !mAlphaValid) { - for (unsigned y=aUpdateRect->y; (y> (left & 0x7); - PRUint8 rightmask = 0xff << (7 - ((right-1) & 0x7)); - - // byte where the first/last bits of the update region are located - PRUint32 leftindex = left >> 3; - PRUint32 rightindex = (right-1) >> 3; - - // first/last bits in the same byte - combine mask into leftmask - // and fill rightmask so we don't try using it - if (leftindex == rightindex) { - leftmask &= rightmask; - rightmask = 0xff; - } - - // check the leading bits - if (leftmask != 0xff) { - PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * aUpdateRect->y + leftindex; - for (unsigned y=aUpdateRect->y; yy + rightindex; - for (unsigned y=aUpdateRect->y; yy; (yy; (y> (left & 0x7); + PRUint8 rightmask = 0xff << (7 - ((right-1) & 0x7)); + + // byte where the first/last bits of the update region are located + PRUint32 leftindex = left >> 3; + PRUint32 rightindex = (right-1) >> 3; + + // first/last bits in the same byte - combine mask into leftmask + // and fill rightmask so we don't try using it + if (leftindex == rightindex) { + leftmask &= rightmask; + rightmask = 0xff; + } + + // check the leading bits + if (leftmask != 0xff) { + PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + leftindex; + for (unsigned y=rect->y; yy + rightindex; + for (unsigned y=rect->y; yy; (yx, rect->y, + rect->width, rect->height, + GDK_RGB_DITHER_MAX, + mImageBits + mRowBytes*rect->y + 3*rect->x, + mRowBytes, + rect->x, rect->y); + } } - if (mAlphaValid && mImagePixmap) { - gdk_pixmap_unref(mImagePixmap); - mImagePixmap = 0; - } - - if (!mAlphaValid) { - CreateOffscreenPixmap(mWidth, mHeight); - if (!sXbitGC) - sXbitGC = gdk_gc_new(mImagePixmap); - - gdk_draw_rgb_image_dithalign(mImagePixmap, sXbitGC, - aUpdateRect->x, aUpdateRect->y, - aUpdateRect->width, aUpdateRect->height, - GDK_RGB_DITHER_MAX, - mImageBits + mRowBytes*aUpdateRect->y + 3*aUpdateRect->x, - mRowBytes, - aUpdateRect->x, aUpdateRect->y); - } - - mFlags = aFlags; // this should be 0'd out by Draw() + mUpdateRegion.Empty(); + mPendingUpdate = PR_FALSE; + mFlags = nsImageUpdateFlags_kBitsChanged; // this should be 0'd out by Draw() } #ifdef CHEAP_PERFORMANCE_MEASURMENT @@ -543,6 +554,9 @@ nsImageGTK::Draw(nsIRenderingContext &aContext, nsDrawingSurface aSurface, { g_return_val_if_fail ((aSurface != nsnull), NS_ERROR_FAILURE); + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth==1) && mIsSpacer) return NS_OK; @@ -1241,6 +1255,9 @@ nsImageGTK::Draw(nsIRenderingContext &aContext, { g_return_val_if_fail ((aSurface != nsnull), NS_ERROR_FAILURE); + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth==1) && mIsSpacer) return NS_OK; @@ -1411,6 +1428,12 @@ NS_IMETHODIMP nsImageGTK::DrawTile(nsIRenderingContext &aContext, aTileRect.width, aTileRect.height, this); #endif + if (mPendingUpdate) + UpdateCachedImage(); + + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth==1) && mIsSpacer) return NS_OK; @@ -1573,6 +1596,9 @@ NS_IMETHODIMP nsImageGTK::DrawToImage(nsIImage* aDstImage, if (!dest) return NS_ERROR_FAILURE; + + if (mPendingUpdate) + UpdateCachedImage(); if (!dest->mImagePixmap) { dest->CreateOffscreenPixmap(dest->mWidth, dest->mHeight); diff --git a/gfx/src/gtk/nsImageGTK.h b/gfx/src/gtk/nsImageGTK.h index a08b0051763c..26889e6b6f8e 100644 --- a/gfx/src/gtk/nsImageGTK.h +++ b/gfx/src/gtk/nsImageGTK.h @@ -28,6 +28,7 @@ #include "X11/Xlib.h" #include "X11/Xutil.h" #include +#include "nsRegion.h" #undef Bool @@ -82,6 +83,7 @@ public: PRInt32 aSXOffset, PRInt32 aSYOffset, const nsRect &aTileRect); + void UpdateCachedImage(); virtual void ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect); virtual nsresult Init(PRInt32 aWidth, PRInt32 aHeight, @@ -187,6 +189,8 @@ private: PRInt32 mDecodedX2; PRInt32 mDecodedY2; + nsRegion mUpdateRegion; + // alpha layer members PRInt16 mAlphaRowBytes; // alpha bytes per row PRInt16 mAlphaWidth; // alpha layer width @@ -194,6 +198,7 @@ private: PRInt8 mAlphaDepth; // alpha layer depth PRPackedBool mAlphaValid; PRPackedBool mIsSpacer; + PRPackedBool mPendingUpdate; PRPackedBool mIsTopToBottom; PRInt8 mNumBytesPixel; diff --git a/gfx/src/nsRegion.cpp b/gfx/src/nsRegion.cpp index d2edebf7c66c..6f527a6a8b71 100644 --- a/gfx/src/nsRegion.cpp +++ b/gfx/src/nsRegion.cpp @@ -59,9 +59,9 @@ class RgnRectMemoryAllocator } void FreeChunk (void* aChunk) { delete [] aChunk; } - void* NextChunk (const void* aThisChunk) const { return *NS_STATIC_CAST (void**, aThisChunk); } + void* NextChunk (void* aThisChunk) const { return *NS_STATIC_CAST (void**, aThisChunk); } - nsRegion::RgnRect* ChunkHead (const void* aThisChunk) const + nsRegion::RgnRect* ChunkHead (void* aThisChunk) const { return NS_REINTERPRET_CAST (nsRegion::RgnRect*, NS_STATIC_CAST (PRUint8*, aThisChunk) + sizeof (void*)); } public: diff --git a/gfx/src/nsRegion.h b/gfx/src/nsRegion.h index 64a536f834b4..0e09f7ddda35 100644 --- a/gfx/src/nsRegion.h +++ b/gfx/src/nsRegion.h @@ -39,8 +39,6 @@ struct nsRectFast : public nsRect nsRectFast () {} // No need to call parent constructor to set default values nsRectFast (PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) : nsRect (aX, aY, aWidth, aHeight) {} nsRectFast (const nsRect& aRect) : nsRect (aRect) {} - operator nsRect () { return *NS_STATIC_CAST (nsRect*, this); } - #if 1 // Override nsRect methods to make them inline. Do not check for emptiness. PRBool Contains (const nsRectFast &aRect) const @@ -100,12 +98,13 @@ class nsRegion inline void* operator new (size_t); inline void operator delete (void* aRect, size_t); - operator = (const RgnRect& aRect) // Do not overwrite prev/next pointers + RgnRect& operator = (const RgnRect& aRect) // Do not overwrite prev/next pointers { x = aRect.x; y = aRect.y; width = aRect.width; height = aRect.height; + return *this; } }; @@ -234,7 +233,7 @@ private: { MoveInto (aDestRegion, mRectListHead.next); } nsRegion (const nsRegion& aRegion); // Prevent copying of regions - operator = (const nsRegion& aRegion); + nsRegion& operator = (const nsRegion& aRegion); }; @@ -272,4 +271,4 @@ public: }; -#endif \ No newline at end of file +#endif diff --git a/gfx/src/xlib/nsImageXlib.cpp b/gfx/src/xlib/nsImageXlib.cpp index 12e262e245b1..138d21b8d209 100644 --- a/gfx/src/xlib/nsImageXlib.cpp +++ b/gfx/src/xlib/nsImageXlib.cpp @@ -74,6 +74,8 @@ nsImageXlib::nsImageXlib() mGC = nsnull; mNaturalWidth = 0; mNaturalHeight = 0; + mPendingUpdate = PR_FALSE; + if (!mXlibRgbHandle) mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE); if (!mXlibRgbHandle) @@ -299,106 +301,124 @@ void nsImageXlib::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect) { - unsigned bottom, left, right; - bottom = aUpdateRect->y + aUpdateRect->height; - left = aUpdateRect->x; - right = left + aUpdateRect->width; - - // check if the image has an all-opaque 8-bit alpha mask - if ((mAlphaDepth == 8) && !mAlphaValid) { - for (unsigned y = aUpdateRect->y; (y < bottom) && !mAlphaValid; y++) { - unsigned char *alpha = mAlphaBits + mAlphaRowBytes * y + left; - for (unsigned x = left; x < right; x++) { - if (*(alpha++) != 255) { - mAlphaValid = PR_TRUE; - break; - } - } - } - } + mPendingUpdate = PR_TRUE; + mUpdateRegion.Or(mUpdateRegion, *aUpdateRect); +} - // check if the image is a spacer - if ((mAlphaDepth==1) && mIsSpacer) { - // mask of the leading/trailing bits in the update region - PRUint8 leftmask = 0xff >> (left & 0x7); - PRUint8 rightmask = 0xff << (7 - ((right-1) & 0x7)); +void nsImageXlib::UpdateCachedImage() +{ + nsRegionRectIterator ri(mUpdateRegion); + const nsRect *rect; - // byte where the first/last bits of the update region are located - PRUint32 leftindex = left >> 3; - PRUint32 rightindex = (right-1) >> 3; + while (rect = ri.Next()) { - // first/last bits in the same byte - combine mask into leftmask - // and fill rightmask so we don't try using it - if (leftindex == rightindex) { - leftmask &= rightmask; - rightmask = 0xff; - } +// fprintf(stderr, "ImageUpdated %p x,y=(%d %d) width,height=(%d %d)\n", +// this, rect->x, rect->y, rect->width, rect->height); - // check the leading bits - if (leftmask != 0xff) { - PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * aUpdateRect->y + leftindex; - for (unsigned y=aUpdateRect->y; yy + rect->height; + left = rect->x; + right = left + rect->width; - // check the trailing bits - if (mIsSpacer && (rightmask != 0xff)) { - PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * aUpdateRect->y + rightindex; - for (unsigned y=aUpdateRect->y; yy; (yy; (y> (left & 0x7); + PRUint8 rightmask = 0xff << (7 - ((right-1) & 0x7)); - if (!sXbitGC) { - XGCValues gcv; - memset(&gcv, 0, sizeof(XGCValues)); - gcv.function = GXcopy; - sXbitGC = XCreateGC(mDisplay, mImagePixmap, GCFunction, &gcv); + // byte where the first/last bits of the update region are located + PRUint32 leftindex = left >> 3; + PRUint32 rightindex = (right-1) >> 3; + + // first/last bits in the same byte - combine mask into leftmask + // and fill rightmask so we don't try using it + if (leftindex == rightindex) { + leftmask &= rightmask; + rightmask = 0xff; + } + + // check the leading bits + if (leftmask != 0xff) { + PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + leftindex; + for (unsigned y=rect->y; yy + rightindex; + for (unsigned y=rect->y; yy; (yx, aUpdateRect->y, - aUpdateRect->width, aUpdateRect->height, + rect->x, rect->y, + rect->width, rect->height, XLIB_RGB_DITHER_MAX, - mImageBits + mRowBytes * aUpdateRect->y + 3 * aUpdateRect->x, + mImageBits + mRowBytes * rect->y + 3 * rect->x, mRowBytes, aUpdateRect->x, aUpdateRect->y); + } } - mFlags = aFlags; // this should be 0'd out by Draw() + + mUpdateRegion.Empty(); + mPendingUpdate = PR_FALSE; + mFlags = nsImageUpdateFlags_kBitsChanged; // this should be 0'd out by Draw() } NS_IMETHODIMP @@ -580,6 +600,9 @@ nsImageXlib::Draw(nsIRenderingContext &aContext, nsDrawingSurface aSurface, if (aSurface == nsnull) return NS_ERROR_FAILURE; + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth == 1) && mIsSpacer) return NS_OK; @@ -1225,6 +1248,9 @@ nsImageXlib::Draw(nsIRenderingContext &aContext, PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) { + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth == 1) && mIsSpacer) return NS_OK; @@ -1342,6 +1368,9 @@ NS_IMETHODIMP nsImageXlib::DrawTile(nsIRenderingContext &aContext, nsRect &aSrcRect, nsRect &aTileRect) { + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth == 1) && mIsSpacer) return NS_OK; @@ -1452,6 +1481,9 @@ NS_IMETHODIMP nsImageXlib::DrawTile(nsIRenderingContext &aContext, PRInt32 aSXOffset, PRInt32 aSYOffset, const nsRect &aTileRect) { + if (mPendingUpdate) + UpdateCachedImage(); + if ((mAlphaDepth == 1) && mIsSpacer) return NS_OK; @@ -1619,6 +1651,9 @@ NS_IMETHODIMP nsImageXlib::DrawToImage(nsIImage* aDstImage, if (!dest) return NS_ERROR_FAILURE; + if (mPendingUpdate) + UpdateCachedImage(); + if (!dest->mImagePixmap) dest->CreateOffscreenPixmap(dest->mWidth, dest->mHeight); diff --git a/gfx/src/xlib/nsImageXlib.h b/gfx/src/xlib/nsImageXlib.h index 6660d00f99c8..1c8e955f5d66 100644 --- a/gfx/src/xlib/nsImageXlib.h +++ b/gfx/src/xlib/nsImageXlib.h @@ -28,6 +28,7 @@ #include "nsIImage.h" #include "nsPoint.h" #include "nsGCCache.h" +#include "nsRegion.h" #include "xlibrgb.h" // class nsDrawingSurfaceXlib; @@ -84,6 +85,7 @@ public: PRInt32 aSXOffset, PRInt32 aSYOffset, const nsRect &aTileRect); + void UpdateCachedImage(); virtual void ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect); virtual nsresult Init(PRInt32 aWidth, PRInt32 aHeight, @@ -195,6 +197,8 @@ private: PRInt32 mDecodedX2; PRInt32 mDecodedY2; + nsRegion mUpdateRegion; + static XlibRgbHandle *mXlibRgbHandle; Display *mDisplay; @@ -205,6 +209,7 @@ private: PRInt16 mAlphaHeight; // alpha layer height PRPackedBool mAlphaValid; PRPackedBool mIsSpacer; + PRPackedBool mPendingUpdate; PRUint8 mFlags; // flags set by ImageUpdated };