Back to index

lightning-sunbird  0.9+nobinonly
nsImageXlib.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Peter Hartshorn <peter@igelaus.com.au>
00024  *   Stuart Parmenter <pavlov@netscape.com>
00025  *   Tim Rowley <tor@cs.brown.edu> -- 8bit alpha compositing
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsImageXlib.h"
00042 #include "nsDrawingSurfaceXlib.h"
00043 #include "nsRenderingContextXlib.h"
00044 #include "xlibrgb.h"
00045 #include "prlog.h"
00046 #include "nsRect.h"
00047 #include "drawers.h"
00048 #include "imgScaler.h"
00049 
00050 #define IsFlagSet(a,b) ((a) & (b))
00051 
00052 #ifdef PR_LOGGING 
00053 static PRLogModuleInfo *ImageXlibLM = PR_NewLogModule("ImageXlib");
00054 #endif /* PR_LOGGING */ 
00055 
00056 /* XXX we are simply creating a GC and setting its function to Copy.
00057    we shouldn't be doing this every time this method is called.  this creates
00058    way more trips to the server than we should be doing so we are creating a
00059    static one.
00060 */
00061 static GC s1bitGC = 0;
00062 static GC sXbitGC = 0;
00063 
00064 XlibRgbHandle *nsImageXlib::mXlibRgbHandle = nsnull;
00065 Display       *nsImageXlib::mDisplay       = nsnull;
00066 
00067 nsImageXlib::nsImageXlib()
00068 : mImageBits(nsnull)
00069 , mAlphaBits(nsnull)
00070 , mWidth(0)
00071 , mHeight(0)
00072 , mDepth(0)
00073 , mRowBytes(0)
00074 , mSizeImage(0)
00075 , mNumBytesPixel(0)
00076 , mImagePixmap(nsnull)
00077 , mAlphaPixmap(nsnull)
00078 , mAlphaDepth(0)
00079 , mAlphaRowBytes(0)
00080 , mAlphaValid(PR_FALSE)
00081 , mIsSpacer(PR_TRUE)
00082 , mGC(nsnull)
00083 , mPendingUpdate(PR_FALSE)
00084 , mDecodedX1(PR_INT32_MAX)
00085 , mDecodedY1(PR_INT32_MAX)
00086 , mDecodedX2(0)
00087 , mDecodedY2(0)
00088 {
00089   PR_LOG(ImageXlibLM, PR_LOG_DEBUG, ("nsImageXlib::nsImageXlib()\n"));
00090 
00091   if (!mXlibRgbHandle) {
00092     mXlibRgbHandle = xxlib_find_handle(XXLIBRGB_DEFAULT_HANDLE);
00093     mDisplay = xxlib_rgb_get_display(mXlibRgbHandle);
00094   }  
00095   
00096   if (!mXlibRgbHandle || !mDisplay)
00097     abort();
00098 }
00099 
00100 nsImageXlib::~nsImageXlib()
00101 {
00102   PR_LOG(ImageXlibLM, PR_LOG_DEBUG,("nsImageXlib::nsImageXlib()\n"));
00103   if (nsnull != mImageBits) {
00104     delete[] mImageBits;
00105     mImageBits = nsnull;
00106   }
00107   if (nsnull != mAlphaBits) {
00108     delete[] mAlphaBits;
00109     mAlphaBits = nsnull;
00110 
00111     if (mAlphaPixmap != nsnull) 
00112     {
00113       // The display cant be null.  It gets fetched from the drawing 
00114       // surface used to create the pixmap.  It gets assigned once
00115       // in Draw()
00116       NS_ASSERTION(nsnull != mDisplay,"display is null.");
00117 
00118 #ifdef XLIB_PIXMAP_DEBUG
00119       printf("XFreePixmap(display = %p)\n",mDisplay);
00120 #endif
00121 
00122       XFreePixmap(mDisplay, mAlphaPixmap);
00123 
00124     }
00125   }
00126 
00127   if (mImagePixmap != 0) 
00128   {
00129     NS_ASSERTION(nsnull != mDisplay,"display is null.");
00130 
00131 #ifdef XLIB_PIXMAP_DEBUG
00132     printf("XFreePixmap(display = %p)\n",mDisplay);
00133 #endif
00134 
00135     XFreePixmap(mDisplay, mImagePixmap);
00136   }
00137 
00138   if(mGC)
00139   {
00140     XFreeGC(mDisplay, mGC);
00141     mGC=nsnull;
00142   }
00143   if(sXbitGC && mDisplay) // Sometimes mDisplay is null, let orhers free
00144   {
00145     XFreeGC(mDisplay, sXbitGC);
00146     sXbitGC=nsnull;
00147   }
00148   if(s1bitGC && mDisplay) // Sometimes mDisplay is null, let orhers free
00149   {
00150     XFreeGC(mDisplay, s1bitGC);
00151     s1bitGC=nsnull;
00152   }
00153   
00154 }
00155 
00156 NS_IMPL_ISUPPORTS1(nsImageXlib, nsIImage)
00157 
00158 nsresult nsImageXlib::Init(PRInt32 aWidth, PRInt32 aHeight,
00159                            PRInt32 aDepth, nsMaskRequirements aMaskRequirements)
00160 {
00161   // gfxImageFrame makes sure nsImageXlib::Init gets called only once
00162   if ((aWidth == 0) || (aHeight == 0))
00163     return NS_ERROR_FAILURE;
00164 
00165   if (24 == aDepth) {
00166     mNumBytesPixel = 3;
00167   } else {
00168     NS_ASSERTION(PR_FALSE, "unexpected image depth");
00169     return NS_ERROR_UNEXPECTED;
00170   }
00171 
00172   mWidth = aWidth;
00173   mHeight = aHeight;
00174   mDepth = aDepth;
00175 
00176   // Create the memory for the image
00177   ComputeMetrics();
00178 
00179   mImageBits = (PRUint8*)new PRUint8[mSizeImage];
00180 
00181   switch(aMaskRequirements) {
00182     case nsMaskRequirements_kNeeds1Bit:
00183       mAlphaRowBytes = (aWidth  + 7) / 8;
00184       mAlphaDepth = 1;
00185 
00186       // 32-bit align each row
00187       mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
00188 
00189       mAlphaBits = new unsigned char[mAlphaRowBytes * aHeight];
00190       break;
00191 
00192     case nsMaskRequirements_kNeeds8Bit:
00193       mAlphaRowBytes = aWidth;
00194       mAlphaDepth = 8;
00195 
00196       // 32-bit align each row
00197       mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
00198       mAlphaBits = new unsigned char[mAlphaRowBytes * aHeight];
00199       break;
00200 
00201     default:
00202       break; // avoid compiler warning
00203   }
00204   return NS_OK;
00205 }
00206 
00207 //---------------------------------------------------------------------
00208 
00209 PRInt32 nsImageXlib::GetHeight()
00210 {
00211   return mHeight;
00212 }
00213 
00214 PRInt32 nsImageXlib::GetWidth()
00215 {
00216   return mWidth;
00217 }
00218 
00219 PRUint8 *nsImageXlib::GetBits()
00220 {
00221   return mImageBits;
00222 }
00223 
00224 void *nsImageXlib::GetBitInfo()
00225 {
00226   return nsnull;
00227 }
00228 
00229 PRInt32 nsImageXlib::GetLineStride()
00230 {
00231   return mRowBytes;
00232 }
00233 
00234 nsColorMap *nsImageXlib::GetColorMap()
00235 {
00236   return nsnull;
00237 }
00238 
00239 PRUint8 *nsImageXlib::GetAlphaBits()
00240 {
00241   return mAlphaBits;
00242 }
00243 
00244 PRInt32 nsImageXlib::GetAlphaLineStride()
00245 {
00246   return mAlphaRowBytes;
00247 }
00248 
00249 //-----------------------------------------------------------------------
00250 
00251 // Set up the palette to the passed in color array, RGB only in this array
00252 void nsImageXlib::ImageUpdated(nsIDeviceContext *aContext,
00253                                PRUint8 aFlags,
00254                                nsRect *aUpdateRect)
00255 {
00256   mPendingUpdate = PR_TRUE;
00257   mUpdateRegion.Or(mUpdateRegion, *aUpdateRect);
00258 
00259   mDecodedX1 = PR_MIN(mDecodedX1, aUpdateRect->x);
00260   mDecodedY1 = PR_MIN(mDecodedY1, aUpdateRect->y);
00261 
00262   if (aUpdateRect->YMost() > mDecodedY2)
00263     mDecodedY2 = aUpdateRect->YMost();
00264   if (aUpdateRect->XMost() > mDecodedX2)
00265     mDecodedX2 = aUpdateRect->XMost();
00266 }
00267 
00271 PRBool nsImageXlib::GetIsImageComplete() {
00272   return mDecodedX1 == 0 &&
00273          mDecodedY1 == 0 &&
00274          mDecodedX2 == mWidth &&
00275          mDecodedY2 == mHeight;
00276 }
00277 
00278 void nsImageXlib::UpdateCachedImage()
00279 {
00280   nsRegionRectIterator ri(mUpdateRegion);
00281   const nsRect *rect;
00282 
00283   while (rect = ri.Next()) {
00284 
00285 //  fprintf(stderr, "ImageUpdated %p x,y=(%d %d) width,height=(%d %d)\n",
00286 //          this, rect->x, rect->y, rect->width, rect->height);
00287 
00288     unsigned bottom, left, right;
00289     bottom = rect->y + rect->height;
00290     left   = rect->x;
00291     right  = left + rect->width;
00292 
00293     // check if the image has an all-opaque 8-bit alpha mask
00294     if ((mAlphaDepth==8) && !mAlphaValid) {
00295       for (unsigned y=rect->y; (y<bottom) && !mAlphaValid; y++) {
00296         unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + left;
00297         for (unsigned x=left; x<right; x++) {
00298           if (*(alpha++)!=255) {
00299             mAlphaValid=PR_TRUE;
00300             break;
00301           }
00302         }
00303       }
00304     }
00305 
00306     // check if the image is a spacer
00307     if ((mAlphaDepth==1) && mIsSpacer) {
00308       // mask of the leading/trailing bits in the update region
00309       PRUint8  leftmask   = 0xff  >> (left & 0x7);
00310       PRUint8  rightmask  = 0xff  << (7 - ((right-1) & 0x7));
00311 
00312       // byte where the first/last bits of the update region are located
00313       PRUint32 leftindex  = left      >> 3;
00314       PRUint32 rightindex = (right-1) >> 3;
00315 
00316       // first/last bits in the same byte - combine mask into leftmask
00317       // and fill rightmask so we don't try using it
00318       if (leftindex == rightindex) {
00319         leftmask &= rightmask;
00320         rightmask = 0xff;
00321       }
00322 
00323       // check the leading bits
00324       if (leftmask != 0xff) {
00325         PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + leftindex;
00326         for (unsigned y=rect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
00327           if (*ptr & leftmask) {
00328             mIsSpacer = PR_FALSE;
00329             break;
00330           }
00331         }
00332         // move to first full byte
00333         leftindex++;
00334       }
00335 
00336       // check the trailing bits
00337       if (mIsSpacer && (rightmask != 0xff)) {
00338         PRUint8 *ptr = mAlphaBits + mAlphaRowBytes * rect->y + rightindex;
00339         for (unsigned y=rect->y; y<bottom; y++, ptr+=mAlphaRowBytes) {
00340           if (*ptr & rightmask) {
00341             mIsSpacer = PR_FALSE;
00342             break;
00343           }
00344         }
00345         // move to last full byte
00346         rightindex--;
00347       }
00348     
00349       // check the middle bytes
00350       if (mIsSpacer && (leftindex <= rightindex)) {
00351         for (unsigned y=rect->y; (y<bottom) && mIsSpacer; y++) {
00352           unsigned char *alpha = mAlphaBits + mAlphaRowBytes*y + leftindex;
00353           for (unsigned x=left; x<right; x++) {
00354             if (*(alpha++)!=0) {
00355               mIsSpacer = PR_FALSE;
00356               break;
00357             }
00358           }
00359         }
00360       }
00361     }
00362 
00363     if (mAlphaValid && mImagePixmap) {
00364       XFreePixmap(mDisplay, mImagePixmap);
00365       mImagePixmap = 0;
00366     }
00367     
00368     if (!mAlphaValid) {
00369       CreateOffscreenPixmap(mWidth, mHeight);
00370 
00371       if (!sXbitGC) {
00372         XGCValues gcv;
00373         memset(&gcv, 0, sizeof(XGCValues));
00374         gcv.function = GXcopy;
00375         sXbitGC  = XCreateGC(mDisplay, mImagePixmap, GCFunction, &gcv);
00376       }
00377       xxlib_draw_rgb_image_dithalign(
00378                      mXlibRgbHandle,
00379                      mImagePixmap, sXbitGC,
00380                      rect->x, rect->y,
00381                      rect->width, rect->height,
00382                      XLIB_RGB_DITHER_MAX,
00383                      mImageBits + mRowBytes * rect->y + 3 * rect->x,
00384                      mRowBytes,
00385                      rect->x, rect->y);
00386     }
00387   }
00388 
00389   mUpdateRegion.SetEmpty();
00390   mPendingUpdate = PR_FALSE;
00391   mFlags = nsImageUpdateFlags_kBitsChanged; // this should be 0'd out by Draw()
00392 }
00393 
00394 NS_IMETHODIMP
00395 nsImageXlib::DrawScaled(nsIRenderingContext &aContext,
00396                         nsIDrawingSurface* aSurface,
00397                         PRInt32 aSX, PRInt32 aSY,
00398                         PRInt32 aSWidth, PRInt32 aSHeight,
00399                         PRInt32 aDX, PRInt32 aDY,
00400                         PRInt32 aDWidth, PRInt32 aDHeight)
00401 {
00402 
00403   PRInt32 origSHeight = aSHeight, origDHeight = aDHeight;
00404   PRInt32 origSWidth = aSWidth, origDWidth = aDWidth;
00405 
00406   if (aSWidth < 0 || aDWidth < 0 || aSHeight < 0 || aDHeight < 0)
00407     return NS_ERROR_FAILURE;
00408 
00409   if (0 == aSWidth || 0 == aDWidth || 0 == aSHeight || 0 == aDHeight)
00410     return NS_OK;
00411 
00412   if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
00413     return NS_OK;
00414 
00415   // limit the size of the blit to the amount of the image read in
00416   if (aSX + aSWidth > mDecodedX2) {
00417     aDWidth -= ((aSX + aSWidth - mDecodedX2)*origDWidth)/origSWidth;
00418     aSWidth -= (aSX + aSWidth) - mDecodedX2;
00419   }
00420   if (aSX < mDecodedX1) {
00421     aDX += ((mDecodedX1 - aSX)*origDWidth)/origSWidth;
00422     aSX = mDecodedX1;
00423   }
00424 
00425   if (aSY + aSHeight > mDecodedY2) {
00426     aDHeight -= ((aSY + aSHeight - mDecodedY2)*origDHeight)/origSHeight;
00427     aSHeight -= (aSY + aSHeight) - mDecodedY2;
00428     }
00429   if (aSY < mDecodedY1) {
00430     aDY += ((mDecodedY1 - aSY)*origDHeight)/origSHeight;
00431     aSY = mDecodedY1;
00432   }
00433 
00434   if ((aDWidth <= 0 || aDHeight <= 0) || (aSWidth <= 0 || aSHeight <= 0))
00435     return NS_OK;
00436 
00437   nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
00438 
00439   if (mAlphaDepth == 1)
00440     CreateAlphaBitmap(mWidth, mHeight);
00441 
00442   if ((mAlphaDepth == 8) && mAlphaValid) {
00443     DrawComposited(aContext, aSurface,
00444         aSX, aSY, aSWidth, aSHeight,
00445         aDX, aDY, aDWidth, aDHeight);
00446     return NS_OK;
00447   }
00448 
00449 #ifdef HAVE_XIE
00450   /* XIE seriosly loses scaling images with alpha */
00451   if (!mAlphaDepth) {
00452     /* Draw with XIE */
00453     PRBool succeeded = PR_FALSE;
00454 
00455     xGC *xiegc = ((nsRenderingContextXlib&)aContext).GetGC();
00456     Drawable drawable; drawing->GetDrawable(drawable);
00457     succeeded = DrawScaledImageXIE(mDisplay, drawable,
00458                                    *xiegc,
00459                                    mImagePixmap,
00460                                    mWidth, mHeight,
00461                                    aSX, aSY,
00462                                    aSWidth, aSHeight,
00463                                    aDX, aDY,
00464                                    aDWidth, aDHeight);
00465     xiegc->Release();
00466     if (succeeded)
00467       return NS_OK;
00468   }
00469 #endif
00470 
00471   /* the good scaling way, right from GTK */
00472   GC gc = 0;
00473   Pixmap pixmap = 0;
00474 
00475   if (mAlphaDepth==1) {
00476     PRUint32 scaledRowBytes = (origDWidth+7)>>3;   // round to next byte
00477     PRUint8 *scaledAlpha = (PRUint8 *)nsMemory::Alloc(origDHeight*scaledRowBytes);
00478     
00479     // code below attempts to draw the image without the mask if mask
00480     // creation fails for some reason.  thus no easy-out "return"
00481     if (scaledAlpha) {
00482       memset(scaledAlpha, 0, origDHeight*scaledRowBytes);
00483       RectStretch(mWidth, mHeight, origDWidth, origDHeight,
00484                   0, 0, aDWidth - 1, aDHeight - 1,
00485                   mAlphaBits, mAlphaRowBytes, scaledAlpha, scaledRowBytes, 1);
00486 
00487       pixmap = XCreatePixmap(mDisplay, DefaultRootWindow(mDisplay),
00488                              aDWidth, aDHeight, 1);
00489       XImage *ximage = 0;
00490       
00491       if (pixmap) {
00492         ximage = XCreateImage(mDisplay, xxlib_rgb_get_visual(mXlibRgbHandle),
00493                               1, XYPixmap, 0, (char *)scaledAlpha,
00494                               aDWidth, aDHeight,
00495                               8, scaledRowBytes);
00496       }
00497       if (ximage) {
00498         ximage->bits_per_pixel=1;
00499         ximage->bitmap_bit_order=MSBFirst;
00500         ximage->byte_order = MSBFirst;
00501 
00502         GC tmpGC;
00503         XGCValues gcv;
00504         memset(&gcv, 0, sizeof(XGCValues));
00505         gcv.function = GXcopy;
00506         tmpGC = XCreateGC(mDisplay, pixmap, GCFunction, &gcv);
00507         if (tmpGC) {
00508           XPutImage(mDisplay, pixmap, tmpGC, ximage,
00509                     0, 0, 0, 0, aDWidth, aDHeight);
00510           XFreeGC(mDisplay, tmpGC);
00511         } else {
00512           // can't write into the clip mask - destroy so we don't use it
00513           if (pixmap)
00514              XFreePixmap(mDisplay, pixmap);
00515           pixmap = 0;
00516         }
00517 
00518         ximage->data = 0;
00519         XDestroyImage(ximage);
00520       }
00521       nsMemory::Free(scaledAlpha);
00522     }
00523   }
00524 
00525   xGC *imageGC = nsnull;
00526 
00527   if (pixmap) {
00528     XGCValues values;
00529 
00530     memset(&values, 0, sizeof(XGCValues));
00531     values.clip_x_origin = aDX;
00532     values.clip_y_origin = aDY;
00533     values.clip_mask = pixmap;
00534     Drawable drawable; drawing->GetDrawable(drawable);
00535     gc = XCreateGC(mDisplay, drawable,
00536                    GCClipXOrigin | GCClipYOrigin | GCClipMask,
00537                    &values);
00538   } else {
00539     imageGC = ((nsRenderingContextXlib&)aContext).GetGC();
00540     gc = *imageGC;
00541   }
00542 
00543   PRUint8 *scaledRGB = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
00544   if (scaledRGB && gc) {
00545     RectStretch(mWidth, mHeight, origDWidth, origDHeight,
00546                 0, 0, aDWidth - 1, aDHeight - 1,
00547                 mImageBits, mRowBytes, scaledRGB, 3*aDWidth, 24);
00548 
00549     Drawable drawable; drawing->GetDrawable(drawable);
00550     xxlib_draw_rgb_image(mXlibRgbHandle, drawable, gc,
00551                          aDX, aDY, aDWidth, aDHeight,
00552                          XLIB_RGB_DITHER_MAX,
00553                          scaledRGB, 3*aDWidth);
00554     nsMemory::Free(scaledRGB);
00555   }
00556 
00557   if (imageGC)
00558     imageGC->Release();
00559   else
00560     if (gc)
00561       XFreeGC(mDisplay, gc);
00562   if (pixmap)
00563     XFreePixmap(mDisplay, pixmap);
00564 
00565   mFlags = 0;
00566 
00567   return NS_OK;
00568 }
00569 
00570 // Draw the bitmap, this method has a source and destination coordinates
00571 NS_IMETHODIMP
00572 nsImageXlib::Draw(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface,
00573                   PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
00574                   PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
00575 {
00576   if (aSurface == nsnull)
00577     return NS_ERROR_FAILURE;
00578 
00579   if (mPendingUpdate)
00580     UpdateCachedImage();
00581 
00582   if ((mAlphaDepth == 1) && mIsSpacer)
00583     return NS_OK;
00584 
00585   if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
00586     return NS_OK;
00587 
00588   if (aSWidth != aDWidth || aSHeight != aDHeight) {
00589     return DrawScaled(aContext, aSurface, aSX, aSY, aSWidth, aSHeight,
00590                       aDX, aDY, aDWidth, aDHeight);
00591   }
00592 
00593   if (aSWidth <= 0 || aDWidth <= 0 || aSHeight <= 0 || aDHeight <= 0) {
00594     NS_ASSERTION(aSWidth > 0 && aDWidth > 0 && aSHeight > 0 && aDHeight > 0,
00595                  "You can't draw an image with a 0 width or height!");
00596     return NS_OK;
00597   }
00598 
00599   // limit the size of the blit to the amount of the image read in
00600   PRInt32 j = aSX + aSWidth;
00601   PRInt32 z;
00602   if (j > mDecodedX2) {
00603     z = j - mDecodedX2;
00604     aDWidth -= z;
00605     aSWidth -= z;
00606   }
00607   if (aSX < mDecodedX1) {
00608     aDX += mDecodedX1 - aSX;
00609     aSX = mDecodedX1;
00610   }
00611 
00612   j = aSY + aSHeight;
00613   if (j > mDecodedY2) {
00614     z = j - mDecodedY2;
00615     aDHeight -= z;
00616     aSHeight -= z;
00617   }
00618   if (aSY < mDecodedY1) {
00619     aDY += mDecodedY1 - aSY;
00620     aSY = mDecodedY1;
00621   }
00622 
00623   if (aDWidth <= 0 || aDHeight <= 0 || aSWidth <= 0 || aSHeight <= 0)
00624     return NS_OK;
00625 
00626   if ((mAlphaDepth == 8) && mAlphaValid) {
00627     DrawComposited(aContext, aSurface,
00628         aSX, aSY, aSWidth, aSHeight,
00629         aDX, aDY, aSWidth, aSHeight);
00630     return NS_OK;
00631   }
00632 
00633   nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
00634 
00635   if (mAlphaDepth == 1)
00636     CreateAlphaBitmap(mWidth, mHeight);
00637 
00638   GC copyGC;
00639   xGC *gc = ((nsRenderingContextXlib&)aContext).GetGC();
00640 
00641   if (mAlphaPixmap) {
00642     if (mGC) {                /* reuse GC */
00643       copyGC = mGC;
00644       SetupGCForAlpha(copyGC, aDX - aSX, aDY - aSY);
00645     } else {                  /* make a new one */
00646       /* this repeats things done in SetupGCForAlpha */
00647       XGCValues xvalues;
00648       memset(&xvalues, 0, sizeof(XGCValues));
00649       unsigned long xvalues_mask = 0;
00650       xvalues.clip_x_origin = aDX - aSX;
00651       xvalues.clip_y_origin = aDY - aSY;
00652       if (IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
00653         xvalues_mask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
00654         xvalues.clip_mask = mAlphaPixmap;
00655       }
00656       Drawable drawable; drawing->GetDrawable(drawable);
00657       mGC = XCreateGC(mDisplay, drawable, xvalues_mask , &xvalues);
00658       copyGC = mGC;
00659     }
00660   } else {  /* !mAlphaPixmap */
00661     copyGC = *gc;
00662   }
00663 
00664   Drawable drawable; drawing->GetDrawable(drawable);
00665   XCopyArea(mDisplay, mImagePixmap, drawable,
00666         copyGC, aSX, aSY, aSWidth, aSHeight, aDX, aDY);
00667 
00668   gc->Release();
00669   mFlags = 0;
00670   return NS_OK;
00671 }
00672 
00673 // -----------------------------------------------------------------
00674 // 8-bit alpha composite drawing
00675 
00676 static unsigned
00677 findIndex32(unsigned mask)
00678 {
00679   switch (mask)
00680   {
00681     case 0xff:
00682       return 3;
00683     case 0xff00:
00684       return 2;
00685     case 0xff0000:
00686       return 1;
00687     default:
00688       return 0;
00689   }
00690 }
00691 
00692 static unsigned
00693 findIndex24(unsigned mask)
00694 {
00695   switch(mask)
00696   {
00697     case 0xff:
00698       return 2;
00699     case 0xff00:
00700       return 1;
00701     default:
00702       return 0;
00703   }
00704 }
00705 
00706 
00707 // 32-bit (888) truecolor convert/composite function
00708 void nsImageXlib::DrawComposited32(PRBool isLSB, PRBool flipBytes,
00709                                    PRUint8 *imageOrigin, PRUint32 imageStride,
00710                                    PRUint8 *alphaOrigin, PRUint32 alphaStride,
00711                                    unsigned width, unsigned height,
00712                                    XImage *ximage, unsigned char *readData)
00713 {
00714   Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
00715   unsigned redIndex   = findIndex32(visual->red_mask);
00716   unsigned greenIndex = findIndex32(visual->green_mask);
00717   unsigned blueIndex  = findIndex32(visual->blue_mask);
00718 
00719   if (flipBytes^isLSB)
00720   {
00721     redIndex   = 3-redIndex;
00722     greenIndex = 3-greenIndex;
00723     blueIndex  = 3-blueIndex;
00724   }
00725 
00726   for (unsigned y=0; y<height; y++)
00727   {
00728     unsigned char *baseRow   = (unsigned char *)ximage->data
00729                                             +y*ximage->bytes_per_line;
00730     unsigned char *targetRow = readData     +3*(y*ximage->width);
00731     unsigned char *imageRow  = imageOrigin  +y*imageStride;
00732     unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
00733 
00734     for (unsigned i=0; i<width;
00735          i++, baseRow+=4, targetRow+=3, imageRow+=3, alphaRow++)
00736     {
00737       unsigned alpha = *alphaRow;
00738       MOZ_BLEND(targetRow[0], baseRow[redIndex],   imageRow[0], alpha);
00739       MOZ_BLEND(targetRow[1], baseRow[greenIndex], imageRow[1], alpha);
00740       MOZ_BLEND(targetRow[2], baseRow[blueIndex],  imageRow[2], alpha);
00741     }
00742   }
00743 }
00744 
00745 // 24-bit (888) truecolor convert/composite function
00746 void
00747 nsImageXlib::DrawComposited24(PRBool isLSB, PRBool flipBytes,
00748                              PRUint8 *imageOrigin, PRUint32 imageStride,
00749                              PRUint8 *alphaOrigin, PRUint32 alphaStride,
00750                              unsigned width, unsigned height,
00751                              XImage *ximage, unsigned char *readData)
00752 {
00753   Visual *visual      = xxlib_rgb_get_visual(mXlibRgbHandle);
00754   unsigned redIndex   = findIndex24(visual->red_mask);
00755   unsigned greenIndex = findIndex24(visual->green_mask);
00756   unsigned blueIndex  = findIndex24(visual->blue_mask);
00757 
00758   if (flipBytes^isLSB) {
00759     redIndex   = 2-redIndex;
00760     greenIndex = 2-greenIndex;
00761     blueIndex  = 2-blueIndex;
00762   }
00763 
00764   for (unsigned y=0; y<height; y++) {
00765     unsigned char *baseRow   = (unsigned char *)ximage->data
00766                                             +y*ximage->bytes_per_line;
00767     unsigned char *targetRow = readData     +3*(y*ximage->width);
00768     unsigned char *imageRow  = imageOrigin  +y*imageStride;
00769     unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
00770 
00771     for (unsigned i=0; i<width;
00772          i++, baseRow+=3, targetRow+=3, imageRow+=3, alphaRow++) {
00773       unsigned alpha = *alphaRow;
00774       MOZ_BLEND(targetRow[0], baseRow[redIndex],   imageRow[0], alpha);
00775       MOZ_BLEND(targetRow[1], baseRow[greenIndex], imageRow[1], alpha);
00776       MOZ_BLEND(targetRow[2], baseRow[blueIndex],  imageRow[2], alpha);
00777     }
00778   }
00779 }
00780 
00781 unsigned nsImageXlib::scaled6[1<<6] = {
00782   3,   7,  11,  15,  19,  23,  27,  31,  35,  39,  43,  47,  51,  55,  59,  63,
00783  67,  71,  75,  79,  83,  87,  91,  95,  99, 103, 107, 111, 115, 119, 123, 127,
00784 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187, 191,
00785 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255
00786 };
00787 
00788 unsigned nsImageXlib::scaled5[1<<5] = {
00789   7,  15,  23,  31,  39,  47,  55,  63,  71,  79,  87,  95, 103, 111, 119, 127,
00790 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247, 255
00791 };
00792 
00793 // 16-bit ([56][56][56]) truecolor convert/composite function
00794 void
00795 nsImageXlib::DrawComposited16(PRBool isLSB, PRBool flipBytes,
00796                              PRUint8 *imageOrigin, PRUint32 imageStride,
00797                              PRUint8 *alphaOrigin, PRUint32 alphaStride,
00798                              unsigned width, unsigned height,
00799                              XImage *ximage, unsigned char *readData)
00800 {
00801   Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
00802 
00803   unsigned *redScale   = (xxlib_get_prec_from_mask(visual->red_mask)   == 5)
00804                           ? scaled5 : scaled6;
00805   unsigned *greenScale = (xxlib_get_prec_from_mask(visual->green_mask) == 5)
00806                           ? scaled5 : scaled6;
00807   unsigned *blueScale  = (xxlib_get_prec_from_mask(visual->blue_mask)  == 5)
00808                           ? scaled5 : scaled6;
00809 
00810   unsigned long redShift   = xxlib_get_shift_from_mask(visual->red_mask);
00811   unsigned long greenShift = xxlib_get_shift_from_mask(visual->green_mask);
00812   unsigned long blueShift  = xxlib_get_shift_from_mask(visual->blue_mask);
00813 
00814   for (unsigned y=0; y<height; y++) {
00815     unsigned char *baseRow   = (unsigned char *)ximage->data
00816                                             +y*ximage->bytes_per_line;
00817     unsigned char *targetRow = readData     +3*(y*ximage->width);
00818     unsigned char *imageRow  = imageOrigin  +y*imageStride;
00819     unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
00820     for (unsigned i=0; i<width;
00821          i++, baseRow+=2, targetRow+=3, imageRow+=3, alphaRow++) {
00822       unsigned pix;
00823       if (flipBytes) {
00824         unsigned char tmp[2];
00825         tmp[0] = baseRow[1];
00826         tmp[1] = baseRow[0];
00827         pix = *((short *)tmp);
00828       } else
00829         pix = *((short *)baseRow);
00830       unsigned alpha = *alphaRow;
00831       MOZ_BLEND(targetRow[0],
00832                 redScale[(pix&visual->red_mask) >> redShift], 
00833                 imageRow[0], alpha);
00834       MOZ_BLEND(targetRow[1],
00835                 greenScale[(pix&visual->green_mask) >> greenShift], 
00836                 imageRow[1], alpha);
00837       MOZ_BLEND(targetRow[2],
00838                 blueScale[(pix&visual->blue_mask) >> blueShift], 
00839                 imageRow[2], alpha);
00840     }
00841   }
00842 }
00843 
00844 // Generic convert/composite function
00845 void
00846 nsImageXlib::DrawCompositedGeneral(PRBool isLSB, PRBool flipBytes,
00847                                   PRUint8 *imageOrigin, PRUint32 imageStride,
00848                                   PRUint8 *alphaOrigin, PRUint32 alphaStride,
00849                                   unsigned width, unsigned height,
00850                                   XImage *ximage, unsigned char *readData)
00851 {
00852   Visual *visual = xxlib_rgb_get_visual(mXlibRgbHandle);
00853 
00854   unsigned char *target = readData;
00855 
00856   // flip bytes
00857   if (flipBytes && (ximage->bits_per_pixel>=16)) {
00858     for (int row=0; row<ximage->height; row++) {
00859       unsigned char *ptr =
00860         (unsigned char*)ximage->data + row*ximage->bytes_per_line;
00861       if (ximage->bits_per_pixel==24) {  // Aurgh....
00862         for (int col=0;
00863              col<ximage->bytes_per_line;
00864              col+=(ximage->bits_per_pixel/8)) {
00865           unsigned char tmp;
00866           tmp = *ptr;
00867           *ptr = *(ptr+2);
00868           *(ptr+2) = tmp;
00869           ptr+=3;
00870         }
00871         continue;
00872       }
00873 
00874       for (int col=0;
00875                col<ximage->bytes_per_line;
00876                col+=(ximage->bits_per_pixel/8)) {
00877         unsigned char tmp;
00878         switch (ximage->bits_per_pixel) {
00879         case 16:
00880           tmp = *ptr;
00881           *ptr = *(ptr+1);
00882           *(ptr+1) = tmp;
00883           ptr+=2;
00884           break;
00885         case 32:
00886           tmp = *ptr;
00887           *ptr = *(ptr+3);
00888           *(ptr+3) = tmp;
00889           tmp = *(ptr+1);
00890           *(ptr+1) = *(ptr+2);
00891           *(ptr+2) = tmp;
00892           ptr+=4;
00893           break;
00894         }
00895       }
00896     }
00897   }
00898 
00899   unsigned redScale   = 8 - xxlib_get_prec_from_mask(visual->red_mask);
00900   unsigned greenScale = 8 - xxlib_get_prec_from_mask(visual->green_mask);
00901   unsigned blueScale  = 8 - xxlib_get_prec_from_mask(visual->blue_mask);
00902   unsigned redFill    = 0xff >> xxlib_get_prec_from_mask(visual->red_mask);
00903   unsigned greenFill  = 0xff >> xxlib_get_prec_from_mask(visual->green_mask);
00904   unsigned blueFill   = 0xff >> xxlib_get_prec_from_mask(visual->blue_mask);
00905 
00906   unsigned long redShift   = xxlib_get_shift_from_mask(visual->red_mask);
00907   unsigned long greenShift = xxlib_get_shift_from_mask(visual->green_mask);
00908   unsigned long blueShift  = xxlib_get_shift_from_mask(visual->blue_mask);
00909 
00910   for (int row=0; row<ximage->height; row++) {
00911     unsigned char *ptr =
00912       (unsigned char *)ximage->data + row*ximage->bytes_per_line;
00913     for (int col=0; col<ximage->width; col++) {
00914       unsigned pix = 0;
00915       switch (ximage->bits_per_pixel) {
00916       case 1:
00917         pix = (*ptr>>(col%8))&1;
00918         if ((col%8)==7)
00919           ptr++;
00920         break;
00921       case 4:
00922         pix = (col&1)?(*ptr>>4):(*ptr&0xf);
00923         if (col&1)
00924           ptr++;
00925         break;
00926       case 8:
00927         pix = *ptr++;
00928         break;
00929       case 16:
00930         pix = *((short *)ptr);
00931         ptr+=2;
00932         break;
00933       case 24:
00934         if (isLSB)
00935           pix = (*(ptr+2)<<16) | (*(ptr+1)<<8) | *ptr;
00936         else
00937           pix = (*ptr<<16) | (*(ptr+1)<<8) | *(ptr+2);
00938         ptr+=3;
00939         break;
00940       case 32:
00941         pix = *((unsigned *)ptr);
00942         ptr+=4;
00943         break;
00944       }
00945 
00946       *target++ =
00947         redFill|((pix&visual->red_mask) >> redShift)<<redScale;
00948       *target++ =
00949         greenFill|((pix&visual->green_mask) >> greenShift)<<greenScale;
00950       *target++ =
00951         blueFill|((pix&visual->blue_mask) >> blueShift)<<blueScale;
00952     }
00953   }
00954 
00955   // now composite
00956   for (unsigned y=0; y<height; y++) {
00957     unsigned char *targetRow = readData+3*y*width;
00958     unsigned char *imageRow  = imageOrigin  +y*imageStride;
00959     unsigned char *alphaRow  = alphaOrigin  +y*alphaStride;
00960     for (unsigned i=0; i<width; i++) {
00961       unsigned alpha = alphaRow[i];
00962       MOZ_BLEND(targetRow[3*i],   targetRow[3*i],   imageRow[3*i],   alpha);
00963       MOZ_BLEND(targetRow[3*i+1], targetRow[3*i+1], imageRow[3*i+1], alpha);
00964       MOZ_BLEND(targetRow[3*i+2], targetRow[3*i+2], imageRow[3*i+2], alpha);
00965     }
00966   }
00967 }
00968 
00969 void
00970 nsImageXlib::DrawComposited(nsIRenderingContext &aContext,
00971                             nsIDrawingSurface* aSurface,
00972                             PRInt32 aSX, PRInt32 aSY,
00973                             PRInt32 aSWidth, PRInt32 aSHeight,
00974                             PRInt32 aDX, PRInt32 aDY,
00975                             PRInt32 aDWidth, PRInt32 aDHeight)
00976 {
00977   if ((aDWidth==0) || (aDHeight==0))
00978     return;
00979 
00980   nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
00981   Drawable drawable; drawing->GetDrawable(drawable);
00982   Visual  *visual   = xxlib_rgb_get_visual(mXlibRgbHandle);
00983 
00984   // I hate clipping... too!
00985   PRUint32 surfaceWidth, surfaceHeight;
00986   drawing->GetDimensions(&surfaceWidth, &surfaceHeight);
00987 
00988   int readX, readY;
00989   unsigned readWidth, readHeight, destX, destY;
00990 
00991   if ((aDY >= (int)surfaceHeight) || (aDX >= (int)surfaceWidth) ||
00992       (aDY + aDHeight <= 0) || (aDX + aDWidth <= 0)) {
00993     // This should never happen if the layout engine is sane,
00994     // as it means we're trying to draw an image which is outside
00995     // the drawing surface.  Bulletproof gfx for now...
00996     return;
00997   }
00998 
00999   if (aDX < 0) {
01000     readX = 0;   readWidth = aDWidth + aDX;    destX = aSX - aDX;
01001   } else {
01002     readX = aDX;  readWidth = aDWidth;       destX = aSX;
01003   }
01004   if (aDY < 0) {
01005     readY = 0;   readHeight = aDHeight + aDY;  destY = aSY - aDY;
01006   } else { 
01007     readY = aDY;  readHeight = aDHeight;     destY = aSY;
01008   }
01009 
01010   if (readX+readWidth > surfaceWidth)
01011   readWidth = surfaceWidth-readX;                                             
01012   if (readY+readHeight > surfaceHeight)
01013     readHeight = surfaceHeight-readY;
01014 
01015   if ((readHeight <= 0) || (readWidth <= 0))
01016     return;
01017 
01018   //  fprintf(stderr, "aX=%d aY=%d, aWidth=%u aHeight=%u\n", aX, aY, aWidth, aHeight);
01019   //  fprintf(stderr, "surfaceWidth=%u surfaceHeight=%u\n", surfaceWidth, surfaceHeight);
01020   //  fprintf(stderr, "readX=%u readY=%u readWidth=%u readHeight=%u destX=%u destY=%u\n\n",
01021   //          readX, readY, readWidth, readHeight, destX, destY);
01022 
01023   XImage *ximage = XGetImage(mDisplay, drawable,
01024                              readX, readY, readWidth, readHeight,
01025                              AllPlanes, ZPixmap);
01026 
01027   NS_ASSERTION((ximage != NULL), "XGetImage() failed");
01028   if (!ximage)
01029     return;
01030 
01031   unsigned char *readData = 
01032     (unsigned char *)nsMemory::Alloc(3*readWidth*readHeight);
01033 
01034   PRUint8 *scaledImage = 0;
01035   PRUint8 *scaledAlpha = 0;
01036   PRUint8 *imageOrigin, *alphaOrigin;
01037   PRUint32 imageStride, alphaStride;
01038 
01039   /* image needs to be scaled */
01040   if ((aSWidth!=aDWidth) || (aSHeight!=aDHeight)) {
01041     PRUint32 x1, y1, x2, y2;
01042     x1 = (destX*aSWidth)/aDWidth;
01043     y1 = (destY*aSHeight)/aDHeight;
01044     x2 = ((destX+readWidth)*aSWidth)/aDWidth;
01045     y2 = ((destY+readHeight)*aSHeight)/aDHeight;
01046 
01047     scaledImage = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
01048     scaledAlpha = (PRUint8 *)nsMemory::Alloc(aDWidth*aDHeight);
01049     if (!scaledImage || !scaledAlpha) {
01050       XDestroyImage(ximage);
01051       nsMemory::Free(readData);
01052       if (scaledImage)
01053         nsMemory::Free(scaledImage);
01054       if (scaledAlpha)
01055         nsMemory::Free(scaledAlpha);
01056       return;
01057     }
01058     RectStretch(aSWidth, aSHeight, aDWidth, aDHeight,
01059                 0, 0, aDWidth-1, aDHeight-1,
01060                 mImageBits, mRowBytes, scaledImage, 3*readWidth, 24);
01061     RectStretch(x1, y1, x2-1, y2-1,
01062                 0, 0, aDWidth-1, aDHeight-1,
01063                 mAlphaBits, mAlphaRowBytes, scaledAlpha, readWidth, 8);
01064     imageOrigin = scaledImage;
01065     imageStride = 3*readWidth;
01066     alphaOrigin = scaledAlpha;
01067     alphaStride = readWidth;
01068   } else {
01069     imageOrigin = mImageBits + destY*mRowBytes + 3*destX;
01070     imageStride = mRowBytes;
01071     alphaOrigin = mAlphaBits + destY*mAlphaRowBytes + destX;
01072     alphaStride = mAlphaRowBytes;
01073   }
01074 
01075   PRBool isLSB;
01076   unsigned int test = 1;
01077   isLSB = (((char *)&test)[0]) ? 1 : 0;
01078   int red_prec   = xxlib_get_prec_from_mask(visual->red_mask);
01079   int green_prec = xxlib_get_prec_from_mask(visual->green_mask);
01080   int blue_prec  = xxlib_get_prec_from_mask(visual->blue_mask);
01081   
01082 
01083   PRBool flipBytes =
01084     ( isLSB && ximage->byte_order != LSBFirst) ||
01085     (!isLSB && ximage->byte_order == LSBFirst);
01086 
01087   if ((ximage->bits_per_pixel==32) &&
01088       (red_prec == 8) &&
01089       (green_prec == 8) &&
01090       (blue_prec == 8))
01091     DrawComposited32(isLSB, flipBytes, 
01092                      imageOrigin, imageStride,
01093                      alphaOrigin, alphaStride, 
01094                      readWidth, readHeight, ximage, readData);
01095   else if ((ximage->bits_per_pixel==24) &&
01096       (red_prec == 8) &&
01097       (green_prec == 8) &&
01098       (blue_prec == 8))
01099     DrawComposited24(isLSB, flipBytes, 
01100                      imageOrigin, imageStride,
01101                      alphaOrigin, alphaStride, 
01102                      readWidth, readHeight, ximage, readData);
01103   else if ((ximage->bits_per_pixel==16) &&
01104            ((red_prec == 5)   || (red_prec == 6)) &&
01105            ((green_prec == 5) || (green_prec == 6)) &&
01106            ((blue_prec == 5)  || (blue_prec == 6)))
01107     DrawComposited16(isLSB, flipBytes,
01108                      imageOrigin, imageStride,
01109                      alphaOrigin, alphaStride, 
01110                      readWidth, readHeight, ximage, readData);
01111   else
01112     DrawCompositedGeneral(isLSB, flipBytes,
01113                      imageOrigin, imageStride,
01114                      alphaOrigin, alphaStride, 
01115                      readWidth, readHeight, ximage, readData);
01116 
01117   xGC *imageGC = ((nsRenderingContextXlib&)aContext).GetGC();
01118   xxlib_draw_rgb_image(mXlibRgbHandle, drawable, *imageGC,
01119                        readX, readY, readWidth, readHeight,
01120                        XLIB_RGB_DITHER_MAX,
01121                        readData, 3*readWidth);
01122   XDestroyImage(ximage);
01123   imageGC->Release();
01124   nsMemory::Free(readData);
01125   if (scaledImage)
01126     nsMemory::Free(scaledImage);
01127   if (scaledAlpha)
01128     nsMemory::Free(scaledAlpha);
01129   mFlags = 0;
01130 }
01131 
01132 void nsImageXlib::CreateAlphaBitmap(PRInt32 aWidth, PRInt32 aHeight)
01133 {
01134   XImage *x_image = nsnull;
01135   XGCValues gcv;
01136 
01137   /* Create gc clip-mask on demand */
01138   if (mAlphaBits && IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
01139 
01140     if (!mAlphaPixmap)
01141       mAlphaPixmap = XCreatePixmap(mDisplay, DefaultRootWindow(mDisplay),
01142                                    aWidth, aHeight, 1);
01143 
01144     // Make an image out of the alpha-bits created by the image library
01145     x_image = XCreateImage(mDisplay, xxlib_rgb_get_visual(mXlibRgbHandle),
01146                            1, /* visual depth...1 for bitmaps */
01147                            XYPixmap,
01148                            0, /* x offset, XXX fix this */
01149                            (char *)mAlphaBits,  /* cast away our sign. */
01150                            aWidth,
01151                            aHeight,
01152                            32, /* bitmap pad */
01153                            mAlphaRowBytes); /* bytes per line */
01154 
01155     x_image->bits_per_pixel=1;
01156 
01157     /* Image library always places pixels left-to-right MSB to LSB */
01158     x_image->bitmap_bit_order = MSBFirst;
01159 
01160     /* This definition doesn't depend on client byte ordering
01161        because the image library ensures that the bytes in
01162        bitmask data are arranged left to right on the screen,
01163        low to high address in memory. */
01164     x_image->byte_order = MSBFirst;
01165 #if defined(IS_LITTLE_ENDIAN)
01166     // no, it's still MSB XXX check on this!!
01167     //      x_image->byte_order = LSBFirst;
01168 #elif defined (IS_BIG_ENDIAN)
01169     x_image->byte_order = MSBFirst;
01170 #else
01171 #error ERROR! Endianness is unknown;
01172 #endif
01173 
01174     /* Copy the XImage to mAlphaPixmap */
01175     if (!s1bitGC) {
01176       memset(&gcv, 0, sizeof(XGCValues));
01177       gcv.function = GXcopy;
01178       s1bitGC = XCreateGC(mDisplay, mAlphaPixmap, GCFunction, &gcv);
01179     }
01180 
01181     XPutImage(mDisplay, mAlphaPixmap, s1bitGC, x_image, 0, 0, 0, 0,
01182               aWidth, aHeight);
01183 
01184     /* Now we are done with the temporary image */
01185     x_image->data = 0;          /* Don't free the IL_Pixmap's bits. */
01186     XDestroyImage(x_image);
01187   }
01188 }
01189 
01190 void nsImageXlib::CreateOffscreenPixmap(PRInt32 aWidth, PRInt32 aHeight)
01191 {
01192   if (mImagePixmap == nsnull) {
01193     mImagePixmap = XCreatePixmap(mDisplay, XDefaultRootWindow(mDisplay),
01194                                  aWidth, aHeight,
01195                                  xxlib_rgb_get_depth(mXlibRgbHandle));
01196   }
01197 }
01198 
01199 void nsImageXlib::SetupGCForAlpha(GC aGC, PRInt32 aX, PRInt32 aY)
01200 {
01201   if (mAlphaPixmap)
01202   {
01203     XGCValues xvalues;
01204     memset(&xvalues, 0, sizeof(XGCValues));
01205     unsigned long xvalues_mask = 0;
01206     xvalues.clip_x_origin = aX;
01207     xvalues.clip_y_origin = aY;
01208     xvalues_mask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
01209     xvalues.function = GXcopy;
01210     xvalues.clip_mask = mAlphaPixmap;
01211 
01212     XChangeGC(mDisplay, aGC, xvalues_mask, &xvalues);
01213   }
01214 }
01215 
01216 // Draw the bitmap. This draw just has destination coordinates
01217 NS_IMETHODIMP
01218 nsImageXlib::Draw(nsIRenderingContext &aContext,
01219                   nsIDrawingSurface* aSurface,
01220                   PRInt32 aX, PRInt32 aY,
01221                   PRInt32 aWidth, PRInt32 aHeight)
01222 {
01223   if (mPendingUpdate)
01224     UpdateCachedImage();
01225 
01226   if ((mAlphaDepth == 1) && mIsSpacer)
01227     return NS_OK;
01228 
01229   if (aSurface == nsnull)
01230     return NS_ERROR_FAILURE;
01231 
01232   if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
01233     return NS_OK;
01234 
01235   if ((mAlphaDepth == 8) && mAlphaValid) {
01236     DrawComposited(aContext, aSurface,
01237         0, 0, aWidth, aHeight,
01238         aX, aY, aWidth, aHeight);
01239     return NS_OK;
01240   }
01241 
01242   // XXX it is said that this is temporary code
01243   if ((aWidth != mWidth) || (aHeight != mHeight)) {
01244     aWidth = mWidth;
01245     aHeight = mHeight;
01246   }
01247 
01248   nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
01249   
01250   PRInt32
01251     validX = 0,
01252     validY = 0,
01253     validWidth = aWidth,
01254     validHeight = aHeight;
01255 
01256   if ((mDecodedY2 < aHeight)) {
01257     validHeight = mDecodedY2 - mDecodedY1;
01258   }
01259   if ((mDecodedX2 < aWidth)) {
01260     validWidth = mDecodedX2 - mDecodedX1;
01261   }
01262   if ((mDecodedY1 > 0)) {
01263     validHeight -= mDecodedY1;
01264     validY = mDecodedY1;
01265   }
01266   if ((mDecodedX1 > 0)) {
01267     validHeight -= mDecodedX1;
01268     validX = mDecodedX1;
01269   }
01270 
01271   CreateAlphaBitmap(aWidth, aHeight);
01272 
01273   GC copyGC;
01274   xGC *gc = ((nsRenderingContextXlib&)aContext).GetGC();
01275 
01276   if (mAlphaPixmap) {
01277     if (mGC) {                /* reuse GC */
01278       copyGC = mGC;
01279     SetupGCForAlpha(copyGC, aX, aY);
01280     } else {                  /* make a new one */
01281       /* this repeats things done in SetupGCForAlpha */
01282       XGCValues xvalues;
01283       memset(&xvalues, 0, sizeof(XGCValues));
01284       unsigned long xvalues_mask = 0;
01285       xvalues.clip_x_origin = aX;
01286       xvalues.clip_y_origin = aY;
01287       if (IsFlagSet(nsImageUpdateFlags_kBitsChanged, mFlags)) {
01288         xvalues_mask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
01289         xvalues.clip_mask = mAlphaPixmap;
01290       }
01291       Drawable drawable; drawing->GetDrawable(drawable);
01292       mGC = XCreateGC(mDisplay, drawable, xvalues_mask , &xvalues);
01293       copyGC = mGC;
01294     }
01295   } else {  /* !mAlphaPixmap */
01296     copyGC = *gc;
01297   }
01298 
01299   Drawable drawable; drawing->GetDrawable(drawable);
01300   XCopyArea(mDisplay, mImagePixmap, drawable,
01301             copyGC, validX, validY,
01302             validWidth, validHeight,
01303             validX + aX, validY + aY);
01304 
01305   gc->Release();
01306 
01307   mFlags = 0;
01308   return NS_OK;
01309 }
01310 
01311 void nsImageXlib::TilePixmap(Pixmap src, Pixmap dest, PRInt32 aSXOffset,
01312                              PRInt32 aSYOffset, const nsRect &destRect,
01313                              const nsRect &clipRect, PRBool useClip)
01314 {
01315   GC gc;
01316   XGCValues values;
01317   unsigned long valuesMask;
01318   memset(&values, 0, sizeof(XGCValues));
01319   values.fill_style = FillTiled;
01320   values.tile = src;
01321   values.ts_x_origin = destRect.x - aSXOffset;
01322   values.ts_y_origin = destRect.y - aSYOffset;
01323   valuesMask = GCTile | GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle;
01324   gc = XCreateGC(mDisplay, src, valuesMask, &values);
01325 
01326   if (useClip) {
01327     XRectangle xrectangle;
01328     xrectangle.x = clipRect.x;
01329     xrectangle.y = clipRect.y;
01330     xrectangle.width = clipRect.width;
01331     xrectangle.height = clipRect.height;
01332     XSetClipRectangles(mDisplay, gc, 0, 0, &xrectangle, 1, Unsorted);
01333   }
01334 
01335   XFillRectangle(mDisplay, dest, gc, destRect.x, destRect.y,
01336                  destRect.width, destRect.height);
01337 
01338   XFreeGC(mDisplay, gc);
01339 }
01340 
01341 NS_IMETHODIMP nsImageXlib::DrawTile(nsIRenderingContext &aContext,
01342                                     nsIDrawingSurface* aSurface,
01343                                     PRInt32 aSXOffset, PRInt32 aSYOffset,
01344                                     PRInt32 aPadX, PRInt32 aPadY,
01345                                     const nsRect &aTileRect)
01346 {
01347   if (mPendingUpdate)
01348     UpdateCachedImage();
01349 
01350   if ((mAlphaDepth == 1) && mIsSpacer)
01351     return NS_OK;
01352 
01353   if (aTileRect.width <= 0 || aTileRect.height <= 0) {
01354     return NS_OK;
01355   }
01356 
01357   if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
01358     return NS_OK;
01359 
01360   nsIDrawingSurfaceXlib *drawing = NS_STATIC_CAST(nsIDrawingSurfaceXlib *, aSurface);
01361 
01362   PRBool partial = PR_FALSE;
01363 
01364   PRInt32
01365     validX = 0,
01366     validY = 0,
01367     validWidth = mWidth,
01368     validHeight = mHeight;
01369 
01370   // limit the image rectangle to the size of the image data which
01371   // has been validated.
01372   if (mDecodedY2 < mHeight) {
01373     validHeight = mDecodedY2 - mDecodedY1;
01374     partial = PR_TRUE;
01375   }
01376   if (mDecodedX2 < mWidth) {
01377     validWidth = mDecodedX2 - mDecodedX1;
01378     partial = PR_TRUE;
01379   }
01380   if (mDecodedY1 > 0) {   
01381     validHeight -= mDecodedY1;
01382     validY = mDecodedY1;
01383     partial = PR_TRUE;
01384   }
01385   if (mDecodedX1 > 0) {
01386     validWidth -= mDecodedX1;
01387     validX = mDecodedX1;
01388     partial = PR_TRUE;
01389   }
01390   
01391   if (validWidth == 0 || validHeight == 0) {
01392     return NS_OK;
01393   }
01394    
01395   if (partial || ((mAlphaDepth == 8) && mAlphaValid) || (aPadX || aPadY)) {
01396     PRInt32 aY0 = aTileRect.y - aSYOffset,
01397             aX0 = aTileRect.x - aSXOffset,
01398             aY1 = aTileRect.y + aTileRect.height,
01399             aX1 = aTileRect.x + aTileRect.width;
01400 
01401     // Set up clipping and call Draw().
01402     aContext.PushState();
01403     ((nsRenderingContextXlib&)aContext).SetClipRectInPixels(
01404       aTileRect, nsClipCombine_kIntersect);
01405     ((nsRenderingContextXlib&)aContext).UpdateGC();
01406     for (PRInt32 y = aY0; y < aY1; y += mHeight + aPadY)
01407       for (PRInt32 x = aX0; x < aX1; x += mWidth + aPadX)
01408         Draw(aContext,aSurface, x, y,
01409              PR_MIN(validWidth, aX1 - x),
01410              PR_MIN(validHeight, aY1 - y));
01411 
01412     aContext.PopState();
01413 
01414     return NS_OK;
01415   }
01416 
01417   CreateOffscreenPixmap(mWidth, mHeight);
01418 
01419   if (mAlphaDepth == 1) {
01420     Pixmap tileImg;
01421     Pixmap tileMask;
01422 
01423     CreateAlphaBitmap(validWidth, validHeight);
01424 
01425     nsRect tmpRect(0,0,aTileRect.width, aTileRect.height);
01426 
01427     XlibRgbHandle *drawingXHandle; 
01428     drawing->GetXlibRgbHandle(drawingXHandle);
01429     tileImg = XCreatePixmap(mDisplay, mImagePixmap,
01430                             aTileRect.width, aTileRect.height,
01431                             xxlib_rgb_get_depth(drawingXHandle));
01432     TilePixmap(mImagePixmap, tileImg, aSXOffset, aSYOffset, tmpRect,
01433                tmpRect, PR_FALSE);
01434 
01435     // tile alpha mask
01436     tileMask = XCreatePixmap(mDisplay, mAlphaPixmap,
01437                              aTileRect.width, aTileRect.height, mAlphaDepth);
01438     TilePixmap(mAlphaPixmap, tileMask, aSXOffset, aSYOffset, tmpRect,
01439                tmpRect, PR_FALSE);
01440 
01441     GC fgc;
01442     XGCValues values;
01443     unsigned long valuesMask;
01444 
01445     Drawable drawable; drawing->GetDrawable(drawable);
01446     memset(&values, 0, sizeof(XGCValues));
01447     values.clip_mask = tileMask;
01448     values.clip_x_origin = aTileRect.x;
01449     values.clip_y_origin = aTileRect.y;
01450     valuesMask = GCClipXOrigin | GCClipYOrigin | GCClipMask;
01451     fgc = XCreateGC(mDisplay, drawable, valuesMask, &values);
01452 
01453     XCopyArea(mDisplay, tileImg, drawable,
01454               fgc, 0,0,
01455               aTileRect.width, aTileRect.height,
01456               aTileRect.x, aTileRect.y);
01457 
01458     XFreePixmap(mDisplay, tileImg);
01459     XFreePixmap(mDisplay, tileMask);
01460     XFreeGC(mDisplay, fgc);
01461 
01462   } else {
01463     // In the non-alpha case, xlib can tile for us
01464     nsRect clipRect;
01465     PRBool isValid;
01466 
01467     aContext.GetClipRect(clipRect, isValid);
01468 
01469     Drawable drawable; drawing->GetDrawable(drawable);
01470     TilePixmap(mImagePixmap, drawable, aSXOffset, aSYOffset,
01471                aTileRect, clipRect, PR_FALSE);
01472   }
01473 
01474   mFlags = 0;
01475   return NS_OK;
01476 }
01477 
01478 
01479 //----------------------------------------------------------------------
01480 nsresult nsImageXlib::Optimize(nsIDeviceContext *aContext)
01481 {
01482   return NS_OK;
01483 }
01484 
01485 //----------------------------------------------------------------------
01486 // Lock the image pixels.
01487 NS_IMETHODIMP
01488 nsImageXlib::LockImagePixels(PRBool aMaskPixels)
01489 {
01490   return NS_OK;
01491 }
01492 
01493 //---------------------------------------------------------------------
01494 // unlock the image pixels. Implement this if you need it.
01495 NS_IMETHODIMP
01496 nsImageXlib::UnlockImagePixels(PRBool aMaskPixels)
01497 {
01498   return NS_OK;
01499 }
01500 
01501 NS_IMETHODIMP nsImageXlib::DrawToImage(nsIImage* aDstImage,
01502                                        nscoord aDX, nscoord aDY,
01503                                        nscoord aDWidth, nscoord aDHeight)
01504 {
01505   nsImageXlib *dest = NS_STATIC_CAST(nsImageXlib *, aDstImage);
01506   if (!dest)
01507     return NS_ERROR_FAILURE;
01508 
01509   if (aDX >= dest->mWidth || aDY >= dest->mHeight)
01510     return NS_OK;
01511 
01512   if (mPendingUpdate)
01513     UpdateCachedImage();
01514 
01515   if (!dest->mImagePixmap)
01516     dest->CreateOffscreenPixmap(dest->mWidth, dest->mHeight);
01517   
01518   if (!dest->mImagePixmap || !mImagePixmap)
01519     return NS_ERROR_FAILURE;
01520 
01521   GC gc = XCreateGC(mDisplay, dest->mImagePixmap, 0, NULL);
01522 
01523   if (mAlphaDepth == 1)
01524     CreateAlphaBitmap(mWidth, mHeight);
01525   
01526   if (mAlphaPixmap)
01527     SetupGCForAlpha(gc, aDX, aDY);
01528 
01529   XCopyArea(dest->mDisplay, mImagePixmap, dest->mImagePixmap, gc,
01530             0, 0, mWidth, mHeight, aDX, aDY);
01531 
01532   XFreeGC(mDisplay, gc);
01533 
01534   if (!mIsSpacer || !mAlphaDepth)
01535     dest->mIsSpacer = PR_FALSE;
01536 
01537   // need to copy the mImageBits in case we're rendered scaled
01538   PRUint8 *scaledImage = 0, *scaledAlpha = 0;
01539   PRUint8 *rgbPtr=0, *alphaPtr=0;
01540   PRUint32 rgbStride, alphaStride = 0;
01541 
01542   if ((aDWidth != mWidth) || (aDHeight != mHeight)) {
01543     // scale factor in DrawTo... start scaling
01544     scaledImage = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
01545     if (!scaledImage)
01546       return NS_ERROR_OUT_OF_MEMORY;
01547 
01548     RectStretch(mWidth, mHeight, aDWidth, aDHeight,
01549                 0, 0, aDWidth-1, aDHeight-1,
01550                 mImageBits, mRowBytes, scaledImage, 3*aDWidth, 24);
01551 
01552     if (mAlphaDepth) {
01553       if (mAlphaDepth==1)
01554         alphaStride = (aDWidth+7)>>3;    // round to next byte
01555       else
01556         alphaStride = aDWidth;
01557 
01558       scaledAlpha = (PRUint8 *)nsMemory::Alloc(alphaStride*aDHeight);
01559       if (!scaledAlpha) {
01560         nsMemory::Free(scaledImage);
01561         return NS_ERROR_OUT_OF_MEMORY;
01562       }
01563 
01564       RectStretch(mWidth, mHeight, aDWidth, aDHeight,
01565                   0, 0, aDWidth-1, aDHeight-1,
01566                   mAlphaBits, mAlphaRowBytes, scaledAlpha, alphaStride,
01567                   mAlphaDepth);
01568     }
01569     rgbPtr = scaledImage;
01570     rgbStride = 3*aDWidth;
01571     alphaPtr = scaledAlpha;
01572   } else {
01573     rgbPtr = mImageBits;
01574     rgbStride = mRowBytes;
01575     alphaPtr = mAlphaBits;
01576     alphaStride = mAlphaRowBytes;
01577   }
01578 
01579   PRInt32 y;
01580   PRInt32 ValidWidth = ( aDWidth < ( dest->mWidth - aDX ) ) ? aDWidth : ( dest->mWidth - aDX ); 
01581   PRInt32 ValidHeight = ( aDHeight < ( dest->mHeight - aDY ) ) ? aDHeight : ( dest->mHeight - aDY );
01582 
01583   // now composite the two images together
01584   switch (mAlphaDepth) {
01585   case 1:
01586     {
01587       PRUint8 *dst = dest->mImageBits + aDY*dest->mRowBytes + 3*aDX;
01588       PRUint8 *dstAlpha = dest->mAlphaBits + aDY*dest->mAlphaRowBytes;
01589       PRUint8 *src = rgbPtr;
01590       PRUint8 *alpha = alphaPtr;
01591       PRUint8 offset = aDX & 0x7; // x starts at 0
01592       int iterations = (ValidWidth+7)/8; // round up
01593 
01594       for (y=0; y<aDHeight; y++) {
01595         for (int x=0; x<ValidWidth; x += 8, dst += 3*8, src += 3*8) {
01596           PRUint8 alphaPixels = *alpha++;
01597           if (alphaPixels == 0) {
01598             // all 8 transparent; jump forward
01599             continue;
01600           }
01601 
01602           // 1 or more bits are set, handle dstAlpha now - may not be aligned.
01603           // Are all 8 of these alpha pixels used?
01604           if (x+7 >= ValidWidth) {
01605             alphaPixels &= 0xff << (8 - (ValidWidth-x)); // no, mask off unused
01606             if (alphaPixels == 0)
01607               continue;  // no 1 alpha pixels left
01608           }
01609           if (offset == 0) {
01610             dstAlpha[(aDX+x)>>3] |= alphaPixels; // the cheap aligned case
01611           }
01612           else {
01613             dstAlpha[(aDX+x)>>3]       |= alphaPixels >> offset;
01614             // avoid write if no 1's to write - also avoids going past end of array
01615             PRUint8 alphaTemp = alphaPixels << (8U - offset);
01616             if (alphaTemp & 0xff)
01617               dstAlpha[((aDX+x)>>3) + 1] |= alphaTemp;
01618           }
01619 
01620           if (alphaPixels == 0xff) {
01621             // fix - could speed up by gathering a run of 0xff's and doing 1 memcpy
01622             // all 8 pixels set; copy and jump forward
01623             memcpy(dst,src,8*3);
01624             continue;
01625           }
01626           else {
01627             // else mix of 1's and 0's in alphaPixels, do 1 bit at a time
01628             // Don't go past end of line!
01629             PRUint8 *d = dst, *s = src;
01630             for (PRUint8 aMask = 1<<7, j = 0; aMask && j < ValidWidth-x; aMask >>= 1, j++) {
01631               // if this pixel is opaque then copy into the destination image
01632               if (alphaPixels & aMask) {
01633                 // might be faster with *d++ = *s++ 3 times?
01634                 d[0] = s[0];
01635                 d[1] = s[1];
01636                 d[2] = s[2];
01637                 // dstAlpha bit already set
01638               }
01639               d += 3;
01640               s += 3;
01641             }
01642           }
01643         }
01644         // at end of each line, bump pointers.  Use wordy code because of
01645         // bug 127455 to avoid possibility of unsigned underflow
01646         dst = (dst - 3*8*iterations) + dest->mRowBytes;
01647         src = (src - 3*8*iterations) + rgbStride;
01648         alpha = (alpha - iterations) + alphaStride;
01649         dstAlpha += dest->mAlphaRowBytes;
01650       }
01651     }
01652     break;
01653   case 8:
01654     // fix? Does this matter?  GTK doesn't support this.  Others?
01655     for (y=0; y<ValidHeight; y++) {
01656       PRUint8 *dst = dest->mImageBits + (y+aDY)*dest->mRowBytes + 3*aDX;
01657       PRUint8 *dstAlpha = 
01658         dest->mAlphaBits + (y+aDY)*dest->mAlphaRowBytes + aDX;
01659       PRUint8 *src = rgbPtr + y*rgbStride; 
01660       PRUint8 *alpha = alphaPtr + y*alphaStride;
01661       for (int x=0; x<ValidWidth; x++, dst+=3, dstAlpha++, src+=3, alpha++) {
01662 
01663         // blend this pixel over the destination image
01664         unsigned val = *alpha;
01665         MOZ_BLEND(dst[0], dst[0], src[0], val);
01666         MOZ_BLEND(dst[1], dst[1], src[1], val);
01667         MOZ_BLEND(dst[2], dst[2], src[2], val);
01668         MOZ_BLEND(*dstAlpha, *dstAlpha, val, val);
01669       }
01670     }
01671     break;
01672   case 0:
01673   default:
01674     for (y=0; y<ValidHeight; y++)
01675       memcpy(dest->mImageBits + (y+aDY)*dest->mRowBytes + 3*aDX, 
01676              rgbPtr + y*rgbStride,
01677              3*ValidWidth);
01678   }
01679   if (scaledAlpha)
01680     nsMemory::Free(scaledAlpha);
01681   if (scaledImage)
01682     nsMemory::Free(scaledImage);
01683 
01684   return NS_OK;
01685 }