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.
This commit is contained in:
rjesup%wgate.com 2001-09-06 23:00:49 +00:00
parent d0e2a62257
commit 58d0356b53
7 changed files with 250 additions and 180 deletions

View File

@ -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)

View File

@ -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<bottom) && !mAlphaValid; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + left;
for (unsigned x=left; x<right; x++) {
if (*(alpha++)!=255) {
mAlphaValid=PR_TRUE;
break;
}
}
}
}
// 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));
// 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; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & leftmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to first full byte
leftindex++;
}
// check the trailing bits
if (mIsSpacer && (rightmask != 0xff)) {
PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * aUpdateRect->y + rightindex;
for (unsigned y=aUpdateRect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & rightmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to last full byte
rightindex--;
}
// check the middle bytes
if (mIsSpacer && (leftindex <= rightindex)) {
for (unsigned y=aUpdateRect->y; (y<bottom) && mIsSpacer; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + leftindex;
// check if the image has an all-opaque 8-bit alpha mask
if ((mAlphaDepth==8) && !mAlphaValid) {
for (unsigned y=rect->y; (y<bottom) && !mAlphaValid; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + left;
for (unsigned x=left; x<right; x++) {
if (*(alpha++)!=0) {
mIsSpacer = PR_FALSE;
if (*(alpha++)!=255) {
mAlphaValid=PR_TRUE;
break;
}
}
}
}
// 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));
// 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; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & leftmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to first full byte
leftindex++;
}
// check the trailing bits
if (mIsSpacer && (rightmask != 0xff)) {
PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + rightindex;
for (unsigned y=rect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & rightmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to last full byte
rightindex--;
}
// check the middle bytes
if (mIsSpacer && (leftindex <= rightindex)) {
for (unsigned y=rect->y; (y<bottom) && mIsSpacer; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + leftindex;
for (unsigned x=left; x<right; x++) {
if (*(alpha++)!=0) {
mIsSpacer = PR_FALSE;
break;
}
}
}
}
}
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,
rect->x, 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);

View File

@ -28,6 +28,7 @@
#include "X11/Xlib.h"
#include "X11/Xutil.h"
#include <gdk/gdk.h>
#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;

View File

@ -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:

View File

@ -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
#endif

View File

@ -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; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & leftmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to first full byte
leftindex++;
}
unsigned bottom, left, right;
bottom = rect->y + 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; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & rightmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to last full byte
rightindex--;
}
// check the middle bytes
if (mIsSpacer && (leftindex <= rightindex)) {
for (unsigned y=aUpdateRect->y; (y<bottom) && mIsSpacer; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + leftindex;
// check if the image has an all-opaque 8-bit alpha mask
if ((mAlphaDepth==8) && !mAlphaValid) {
for (unsigned y=rect->y; (y<bottom) && !mAlphaValid; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + left;
for (unsigned x=left; x<right; x++) {
if (*(alpha++)!=0) {
mIsSpacer = PR_FALSE;
if (*(alpha++)!=255) {
mAlphaValid=PR_TRUE;
break;
}
}
}
}
}
if (mAlphaValid && mImagePixmap) {
XFreePixmap(mDisplay, mImagePixmap);
mImagePixmap = 0;
}
if (!mAlphaValid) {
CreateOffscreenPixmap(mWidth, mHeight);
// 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));
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; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & leftmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to first full byte
leftindex++;
}
// check the trailing bits
if (mIsSpacer && (rightmask != 0xff)) {
PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + rightindex;
for (unsigned y=rect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
if (*ptr & rightmask) {
mIsSpacer = PR_FALSE;
break;
}
}
// move to last full byte
rightindex--;
}
// check the middle bytes
if (mIsSpacer && (leftindex <= rightindex)) {
for (unsigned y=rect->y; (y<bottom) && mIsSpacer; y++) {
unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + leftindex;
for (unsigned x=left; x<right; x++) {
if (*(alpha++)!=0) {
mIsSpacer = PR_FALSE;
break;
}
}
}
}
}
xxlib_draw_rgb_image_dithalign(
if (mAlphaValid && mImagePixmap) {
XFreePixmap(mDisplay, mImagePixmap);
mImagePixmap = 0;
}
if (!mAlphaValid) {
CreateOffscreenPixmap(mWidth, mHeight);
if (!sXbitGC) {
XGCValues gcv;
memset(&gcv, 0, sizeof(XGCValues));
gcv.function = GXcopy;
sXbitGC = XCreateGC(mDisplay, mImagePixmap, GCFunction, &gcv);
}
xxlib_draw_rgb_image_dithalign(
mXlibRgbHandle,
mImagePixmap, sXbitGC,
aUpdateRect->x, 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);

View File

@ -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
};