Back to index

lightning-sunbird  0.9+nobinonly
nsImageBeOS.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  *   Daniel Switkin, Mathias Agopian and Sergei Dolgov
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsImageBeOS.h"
00040 #include "nsRenderingContextBeOS.h"
00041 #include "nspr.h"
00042 #include <Looper.h>
00043 #include <Bitmap.h>
00044 #include <View.h>
00045 
00046 NS_IMPL_ISUPPORTS1(nsImageBeOS, nsIImage)
00047 
00048 nsImageBeOS::nsImageBeOS()
00049   : mImage(nsnull)
00050   , mImageBits(nsnull)
00051   , mWidth(0)
00052   , mHeight(0)
00053   , mDepth(0)
00054   , mRowBytes(0)
00055   , mSizeImage(0)
00056   , mDecodedX1(PR_INT32_MAX)
00057   , mDecodedY1(PR_INT32_MAX)
00058   , mDecodedX2(0)
00059   , mDecodedY2(0)
00060   , mAlphaBits(nsnull)
00061   , mAlphaRowBytes(0)
00062   , mAlphaDepth(0)
00063   , mFlags(0)
00064   , mNumBytesPixel(0)
00065   , mImageCurrent(PR_FALSE)
00066   , mOptimized(PR_FALSE)
00067   , mTileBitmap(nsnull)
00068 {
00069 }
00070 
00071 nsImageBeOS::~nsImageBeOS() 
00072 {
00073        if (nsnull != mImage) 
00074        {
00075               delete mImage;
00076               mImage = nsnull;
00077        }
00078                      
00079        if (mTileBitmap) 
00080        {
00081               delete mTileBitmap;
00082               mTileBitmap = nsnull;
00083        }
00084 
00085        if (nsnull != mImageBits) 
00086        {
00087               delete [] mImageBits;
00088               mImageBits = nsnull;
00089        }
00090        if (nsnull != mAlphaBits) 
00091        {
00092               delete [] mAlphaBits;
00093               mAlphaBits = nsnull;
00094        }
00095 }
00096 
00097 nsresult nsImageBeOS::Init(PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,
00098                                                  nsMaskRequirements aMaskRequirements) 
00099 {
00100        // Assumed: Init only gets called once by gfxIImageFrame
00101        // Only 24 bit depths are supported for the platform independent bits
00102        if (24 == aDepth) 
00103        {
00104               mNumBytesPixel = 3;
00105        }
00106        else 
00107        {
00108               NS_ASSERTION(PR_FALSE, "unexpected image depth");
00109               return NS_ERROR_UNEXPECTED;
00110        }
00111        
00112        mWidth = aWidth;
00113        mHeight = aHeight;
00114        mDepth = aDepth;
00115        mRowBytes = (mWidth * mDepth) >> 5;
00116        if (((PRUint32)mWidth * mDepth) & 0x1F) 
00117               mRowBytes++;
00118        mRowBytes <<= 2;
00119        mSizeImage = mRowBytes * mHeight;
00120 
00121        mImageBits = new PRUint8[mSizeImage];
00122 
00123        switch (aMaskRequirements) 
00124        {
00125               case nsMaskRequirements_kNeeds1Bit:
00126                      mAlphaRowBytes = (aWidth + 7) / 8;
00127                      mAlphaDepth = 1;
00128                      // 32-bit align each row
00129                      mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
00130                      mAlphaBits = new PRUint8[mAlphaRowBytes * aHeight];
00131                      memset(mAlphaBits, 255, mAlphaRowBytes * aHeight);
00132                      break;
00133               case nsMaskRequirements_kNeeds8Bit:
00134                      mAlphaRowBytes = aWidth;
00135                      mAlphaDepth = 8;
00136                      // 32-bit align each row
00137                      mAlphaRowBytes = (mAlphaRowBytes + 3) & ~0x3;
00138                      mAlphaBits = new PRUint8[mAlphaRowBytes * aHeight];
00139                      break;
00140        }
00141        
00142        return NS_OK;
00143 }
00144 
00145 // This is a notification that the platform independent bits have changed. Therefore,
00146 // the contents of the BBitmap are no longer up to date. By setting the mImageCurrent
00147 // flag to false, we can be sure that the BBitmap will be updated before it gets blit.
00148 // TO DO: It would be better to cache the updated rectangle here, and only copy the
00149 // area that has changed in CreateImage().
00150 void nsImageBeOS::ImageUpdated(nsIDeviceContext *aContext, PRUint8 aFlags, nsRect *aUpdateRect) 
00151 {
00152        // This should be 0'd out by Draw()
00153        mFlags = aFlags;
00154        mImageCurrent = PR_FALSE;
00155 
00156        mDecodedX1 = PR_MIN(mDecodedX1, aUpdateRect->x);
00157        mDecodedY1 = PR_MIN(mDecodedY1, aUpdateRect->y);
00158 
00159        if (aUpdateRect->YMost() > mDecodedY2)
00160               mDecodedY2 = aUpdateRect->YMost();
00161        if (aUpdateRect->XMost() > mDecodedX2)
00162               mDecodedX2 = aUpdateRect->XMost();
00163 } 
00164 
00168 PRBool nsImageBeOS::GetIsImageComplete() {
00169   return mDecodedX1 == 0 &&
00170          mDecodedY1 == 0 &&
00171          mDecodedX2 == mWidth &&
00172          mDecodedY2 == mHeight;
00173 }
00174 
00175 // Draw the bitmap, this method has a source and destination coordinates
00176 NS_IMETHODIMP nsImageBeOS::Draw(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface,
00177        PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
00178        PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight) 
00179 {
00180        // Don't bother to draw nothing           
00181        if (!aSWidth || !aSHeight || !aDWidth || !aDHeight)
00182               return NS_OK;
00183        if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
00184               return NS_OK;
00185 
00186        // As we do all scaling with Be API (DrawBitmap), using float is safe and convinient       
00187        float srcX = aSX, srcY = aSY, srcMostX = aSX + aSWidth, srcMostY = aSY + aSHeight;
00188        float dstX = aDX, dstY = aDY, dstMostX = aDX + aDWidth, dstMostY = aDY + aDHeight;
00189        float  scaleX = float(aDWidth)/float(aSWidth), scaleY = float(aDHeight)/float(aSHeight);
00190 
00191        if (!mImageCurrent || (nsnull == mImage)) 
00192               BuildImage(aSurface);
00193        if (nsnull == mImage || mImage->BitsLength() == 0) 
00194               return NS_ERROR_FAILURE;
00195 
00196        // Limit the image rectangle to the size of the image data which
00197        // has been validated. 
00198        if ((mDecodedY1 > 0)) 
00199        {
00200               srcY = float(PR_MAX(mDecodedY1, aSY));
00201        }
00202        if ((mDecodedX1 > 0))
00203        {
00204               srcX = float(PR_MAX(mDecodedX1, aSX));
00205        }
00206        // When targeting BRects, MostX/Y is more natural than Width/Heigh
00207        if ((mDecodedY2 < mHeight)) 
00208               srcMostY = float(PR_MIN(mDecodedY2, aSY + aSHeight));
00209 
00210        if ((mDecodedX2 < mWidth)) 
00211               srcMostX = float(PR_MIN(mDecodedX2, aSX + aSWidth));
00212 
00213        dstX = float(srcX - aSX)*scaleX + float(aDX);
00214        dstY = float(srcY - aSY)*scaleY + float(aDY);
00215        dstMostX = dstMostX - (float(aSWidth + aSX) - srcMostX)*scaleX;
00216        dstMostY =    dstMostY - (float(aSHeight + aSY) - srcMostY)*scaleY;
00217 
00218        nsDrawingSurfaceBeOS *beosdrawing = (nsDrawingSurfaceBeOS *)aSurface;
00219        BView *view;
00220 
00221        // LockAndUpdateView() sets proper clipping region here and elsewhere in nsImageBeOS.
00222        if (((nsRenderingContextBeOS&)aContext).LockAndUpdateView()) 
00223        {
00224               beosdrawing->AcquireView(&view);
00225               if (view) 
00226               {
00227                      // TODO: With future locking update check if restricting clipping region 
00228                      // to decoded values fastens things up - in this case clipping must be reset to 0
00229                      // at unlocking or before getting native region in LockAndUpdateView().
00230 
00231                      // Only use B_OP_ALPHA when there is an alpha channel present, as it is much slower
00232                      if (0 != mAlphaDepth) 
00233                      {
00234                             view->SetDrawingMode(B_OP_ALPHA);
00235                             view->DrawBitmap(mImage, BRect(srcX, srcY, srcMostX - 1, srcMostY - 1),
00236                                    BRect(dstX, dstY, dstMostX - 1, dstMostY - 1));
00237                             view->SetDrawingMode(B_OP_COPY);
00238                      }
00239                      else 
00240                      {
00241                             view->DrawBitmap(mImage, BRect(srcX, srcY, srcMostX - 1, srcMostY - 1),
00242                                    BRect(dstX, dstY, dstMostX - 1, dstMostY - 1));
00243                      }
00244                      // view was locked by LockAndUpdateView() before it was aquired. So unlock.
00245               }
00246               ((nsRenderingContextBeOS&)aContext).UnlockView();
00247               beosdrawing->ReleaseView();
00248        }
00249        
00250        mFlags = 0;
00251        return NS_OK;
00252 }
00253 
00254 // Draw the bitmap, this draw just has destination coordinates
00255 NS_IMETHODIMP nsImageBeOS::Draw(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface,
00256        PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) 
00257 {
00258        //Don't bother to draw nothing            
00259        if (!aWidth || !aHeight)
00260               return NS_OK;
00261        if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
00262               return NS_OK;
00263 
00264        if (!mImageCurrent || (nsnull == mImage)) 
00265               BuildImage(aSurface);
00266        if (nsnull == mImage) 
00267               return NS_ERROR_FAILURE;
00268 
00269        PRInt32 validX = 0, validY = 0, validMostX = mWidth, validMostY = mHeight;
00270 
00271        // XXX kipp: this is temporary code until we eliminate the
00272        // width/height arguments from the draw method.
00273        aWidth = PR_MIN(aWidth, mWidth);
00274        aHeight = PR_MIN(aHeight, mHeight);
00275 
00276        if ((mDecodedY2 < aHeight)) 
00277               validMostY = mDecodedY2;
00278 
00279        if ((mDecodedX2 < aWidth)) 
00280               validMostX = mDecodedX2;
00281 
00282        if ((mDecodedY1 > 0)) 
00283               validY = mDecodedY1;
00284        if ((mDecodedX1 > 0)) 
00285               validX = mDecodedX1;
00286                      
00287        nsDrawingSurfaceBeOS *beosdrawing = (nsDrawingSurfaceBeOS *)aSurface;
00288        BView *view;
00289 
00290        if (((nsRenderingContextBeOS&)aContext).LockAndUpdateView()) 
00291        {
00292               beosdrawing->AcquireView(&view);
00293               if (view) 
00294               {
00295                      // See TODO clipping comment above - code ready for use:
00296                      // BRegion tmpreg(BRect(aX + validX, aY + validY, aX + validMostX - 1, aY + validMostY - 1));
00297                      // view->ConstrainClippingRegion(&tmpreg);
00298                      
00299                      // Only use B_OP_ALPHA when there is an alpha channel present, as it is much slower
00300                      if (0 != mAlphaDepth) 
00301                      {
00302                             view->SetDrawingMode(B_OP_ALPHA);
00303                             view->DrawBitmap(mImage, BRect(validX, validY, validMostX - 1, validMostY - 1), 
00304                                                         BRect(aX + validX, aY + validY, aX + validMostX - 1, aY + validMostY - 1));
00305                             view->SetDrawingMode(B_OP_COPY);
00306                      } 
00307                      else 
00308                      {
00309                             view->DrawBitmap(mImage, BRect(validX, validY, validMostX - 1, validMostY - 1), 
00310                                                         BRect(aX + validX, aY + validY, aX + validMostX - 1, aY + validMostY - 1));
00311                      }
00312               }
00313               ((nsRenderingContextBeOS&)aContext).UnlockView();
00314               beosdrawing->ReleaseView();
00315        }
00316 
00317        mFlags = 0;
00318        return NS_OK;
00319 }
00320 
00321 NS_IMETHODIMP nsImageBeOS::DrawTile(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface,
00322        PRInt32 aSXOffset, PRInt32 aSYOffset, PRInt32 aPadX, PRInt32 aPadY, const nsRect &aTileRect) 
00323 {
00324        // Don't bother to draw nothing    
00325        if (!aTileRect.width || !aTileRect.height)
00326               return NS_OK;
00327        if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
00328               return NS_OK;
00329 
00330        if (!mImageCurrent || (nsnull == mImage)) 
00331               BuildImage(aSurface);
00332        if (nsnull == mImage || mImage->BitsLength() == 0) 
00333               return NS_ERROR_FAILURE;
00334 
00335        PRInt32 validX = 0, validY = 0, validMostX = mWidth, validMostY = mHeight;
00336 
00337        // Limit the image rectangle to the size of the image data which
00338        // has been validated.
00339        if ((mDecodedY2 < mHeight)) 
00340               validMostY = mDecodedY2;
00341 
00342        if ((mDecodedX2 < mWidth)) 
00343               validMostX = mDecodedX2;
00344 
00345        if ((mDecodedY1 > 0)) 
00346               validY = mDecodedY1;
00347 
00348        if ((mDecodedX1 > 0)) 
00349               validX = mDecodedX1;
00350 
00351        nsDrawingSurfaceBeOS *beosdrawing = (nsDrawingSurfaceBeOS *)aSurface;
00352        BView *view = 0;
00353        if (((nsRenderingContextBeOS&)aContext).LockAndUpdateView()) 
00354        {
00355               beosdrawing->AcquireView(&view);
00356               if (view) 
00357               {
00358                BRegion rgn(BRect(aTileRect.x, aTileRect.y,
00359                                    aTileRect.x + aTileRect.width - 1, aTileRect.y + aTileRect.height - 1));
00360            view->ConstrainClippingRegion(&rgn);
00361 
00362                      // Force transparency for bitmap blitting in case of padding even if mAlphaDepth == 0
00363                      if (0 != mAlphaDepth || aPadX || aPadY) 
00364                             view->SetDrawingMode(B_OP_ALPHA);
00365                      // Creating temporary bitmap, compatible with mImage and  with size of area to be filled with tiles
00366                      // Reuse existing if possible
00367                      if (!mTileBitmap || mTileBitmap->Bounds().IntegerWidth() + 1 != aTileRect.width || mTileBitmap->Bounds().IntegerHeight() + 1 != aTileRect.height)
00368                      {
00369                             if (mTileBitmap)
00370                             {
00371                                    delete mTileBitmap;
00372                                    mTileBitmap = nsnull;
00373                             }
00374                             mTileBitmap = new BBitmap(BRect(0, 0, aTileRect.width - 1, aTileRect.height -1), mImage->ColorSpace(), false);
00375                      }
00376                      
00377                      int32 tmpbitlength = mTileBitmap->BitsLength();
00378 
00379                      if (!mTileBitmap || tmpbitlength == 0)
00380                      {
00381                             // Failed. Cleaning things a bit.
00382                             ((nsRenderingContextBeOS&)aContext).UnlockView();
00383                             if (mTileBitmap)
00384                             {
00385                                    delete mTileBitmap;
00386                                    mTileBitmap = nsnull;
00387                             }
00388                             beosdrawing->ReleaseView();
00389                             return NS_ERROR_FAILURE;
00390                      }
00391 
00392                      uint32 *dst0 = (uint32 *)mTileBitmap->Bits();
00393                      uint32 *src0 = (uint32 *)mImage->Bits();
00394                      uint32 *dst = dst0;
00395                      uint32 dstRowLength = mTileBitmap->BytesPerRow()/4;
00396                      uint32 dstColHeight = tmpbitlength/mTileBitmap->BytesPerRow();
00397 
00398                      // Filling mTileBitmap with transparent color to preserve padding areas on destination 
00399                      uint32 filllength = tmpbitlength/4;
00400                      if (0 != mAlphaDepth  || aPadX || aPadY) 
00401                      {
00402                             for (uint32 i=0, *dst = dst0; i < filllength; ++i)
00403                                    *(dst++) = B_TRANSPARENT_MAGIC_RGBA32;
00404                      }
00405 
00406                      // Rendering mImage tile to temporary bitmap
00407                      uint32 *src = src0; dst = dst0;
00408                      for (uint32 y = 0, yy = aSYOffset; y < dstColHeight; ++y) 
00409                      {                                  
00410                             src = src0 + yy*mWidth;
00411                             dst = dst0 + y*dstRowLength;
00412                             // Avoid unnecessary job outside update rect
00413                             if (yy >= validY && yy <= validMostY)
00414                             {
00415                                    for (uint32 x = 0, xx = aSXOffset; x < dstRowLength; ++x) 
00416                                    {
00417                                           // Avoid memwrite if outside update rect
00418                                           if (xx >= validX && xx <= validMostX)
00419                                                  dst[x] = src[xx];
00420                                           if (++xx == mWidth)
00421                                           {
00422                                                  // Width of source reached. Adding horizontal paddding.
00423                                                  xx = 0;
00424                                                  x += aPadX;
00425                                           }
00426                                    }
00427                             }
00428                             if (++yy == mHeight)
00429                             {
00430                                    // Height of source reached. Adding vertical paddding.
00431                                    yy = 0;
00432                                    y += aPadY;
00433                             }
00434                      }
00435                      // Flushing tile bitmap to proper area in drawable BView       
00436                      view->DrawBitmap(mTileBitmap, BPoint(aTileRect.x , aTileRect.y ));
00437                      view->SetDrawingMode(B_OP_COPY);
00438                      view->Sync();
00439               }
00440               ((nsRenderingContextBeOS&)aContext).UnlockView();
00441               beosdrawing->ReleaseView();
00442        }
00443        mFlags = 0;
00444        return NS_OK;
00445 }
00446 
00447 // If not yet optimized, delete mImageBits and mAlphaBits here to save memory,
00448 // since the image will never change again and no one else will need to get the
00449 // platform independent bits.
00450 nsresult nsImageBeOS::Optimize(nsIDeviceContext *aContext) 
00451 {
00452        if (!mOptimized) 
00453        {
00454               // Make sure the BBitmap is up to date
00455               CreateImage(NULL);
00456               
00457               // Release Mozilla-specific data
00458               if (nsnull != mImageBits) 
00459               {
00460                      delete [] mImageBits;
00461                      mImageBits = nsnull;
00462               }
00463               if (nsnull != mAlphaBits) 
00464               {
00465                      delete [] mAlphaBits;
00466                      mAlphaBits = nsnull;
00467               }
00468               
00469               mOptimized = PR_TRUE;
00470        }
00471        return NS_OK;
00472 }
00473 
00474 // Not implemented at the moment. It's unclear whether this is necessary for
00475 // the BeOS port or not. BBitmap::Lock/UnlockBits()  may be used if necessary
00476 NS_IMETHODIMP nsImageBeOS::LockImagePixels(PRBool aMaskPixels) 
00477 {
00478        // we may need some sort of syncing here in future
00479        return NS_OK;
00480 }
00481 
00482 // Same as above.
00483 NS_IMETHODIMP nsImageBeOS::UnlockImagePixels(PRBool aMaskPixels) 
00484 {
00485        return NS_OK;
00486 }
00487 
00488 nsresult nsImageBeOS::BuildImage(nsIDrawingSurface* aDrawingSurface) 
00489 {
00490        CreateImage(aDrawingSurface);
00491        return NS_OK;
00492 }
00493 
00494 // This function is responsible for copying the platform independent bits (mImageBits
00495 // and mAlphaBits) into a BBitmap so it can be drawn using the Be APIs. Since it is
00496 // expensive to create and destroy a BBitmap for this purpose, we will keep this bitmap
00497 // around, which also prevents the need to copy the bits if they have not changed.
00498 void nsImageBeOS::CreateImage(nsIDrawingSurface* aSurface) 
00499 {
00500        PRInt32 validX = 0, validY = 0, validMostX = mWidth, validMostY = mHeight;
00501 
00502        if (mImageBits) 
00503        {
00504               if (24 != mDepth) 
00505               {
00506                      NS_ASSERTION(PR_FALSE, "unexpected image depth");
00507                      return;
00508               }
00509               
00510               // If the previous BBitmap is the right dimensions and colorspace, then reuse it.
00511               const color_space cs = B_RGBA32;
00512               if (nsnull != mImage) 
00513               {
00514                      BRect bounds = mImage->Bounds();
00515                      if (bounds.IntegerWidth() < validMostX - 1 || bounds.IntegerHeight() < validMostY - 1 ||
00516                             mImage->ColorSpace() != cs) 
00517                      {
00518                             
00519                             delete mImage;
00520                             mImage = new BBitmap(BRect(0, 0, validMostX - 1, validMostY - 1), cs, false);
00521                      } 
00522                      else 
00523                      {
00524                             // Don't copy the data twice if the BBitmap is up to date
00525                             if (mImageCurrent) return;
00526                      }
00527               } 
00528               else 
00529               {
00530                      // No BBitmap exists, so create one and update it
00531                      mImage = new BBitmap(BRect(0, 0, mWidth - 1, mHeight - 1), cs, false);
00532               }
00533               
00534               // Only the data that has changed (the rectangle supplied to ImageUpdated())
00535               // needs to be copied to the BBitmap. 
00536               
00537               if ((mDecodedY2 < mHeight)) 
00538                      validMostY = mDecodedY2;
00539 
00540               if ((mDecodedX2 < mWidth)) 
00541                      validMostX = mDecodedX2;
00542 
00543               if ((mDecodedY1 > 0)) 
00544                      validY = mDecodedY1;
00545               if ((mDecodedX1 > 0)) 
00546                      validX = mDecodedX1;
00547               
00548               if (mDecodedX2 < mDecodedX1 || mDecodedY2 < mDecodedY1)
00549                      return;
00550 
00551               // Making up a 32 bit double word for the destination is much more efficient
00552               // than writing each byte separately on some CPUs. For example, BeOS does not
00553               // support write-combining on the Athlon/Duron family.
00554               
00555               // Using mRowBytes as source stride due alignment of mImageBits array to 4.
00556               // Destination stride is mWidth, as mImage always uses RGB(A)32 
00557               if (mImage && mImage->IsValid()) 
00558               {
00559                      uint32 *dest, *dst0 = (uint32 *)mImage->Bits() + validX;
00560                      uint8 *src, *src0 = mImageBits + 3*validX; 
00561                      if (mAlphaBits) 
00562                      {
00563                             uint8 a, *alpha = mAlphaBits + validY*mAlphaRowBytes;;
00564                             for (int y = validY; y < validMostY; ++y) 
00565                             {
00566                                    dest = dst0 + y*mWidth;
00567                                    src = src0 + y*mRowBytes;
00568                                    for (int x = validX; x < validMostX; ++x) 
00569                                    {
00570                                           if(1 == mAlphaDepth)
00571                                                  a = (alpha[x / 8] & (1 << (7 - (x % 8)))) ? 255 : 0;
00572                                           else
00573                                                  a = alpha[x];
00574                                           *dest++ = (a << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
00575                                           src += 3;
00576                                    }
00577                                    alpha += mAlphaRowBytes;
00578                             }
00579                      } 
00580                      else 
00581                      {
00582                             // Fixed 255 in the alpha channel to mean completely opaque
00583                             for (int y = validY; y < validMostY; ++y) 
00584                             {
00585                                    dest = dst0 + y*mWidth;
00586                                    src = src0 + y*mRowBytes;
00587                                    for (int x = validX; x < validMostX; ++x) 
00588                                    {
00589                                           *dest++ = 0xff000000 | (src[2] << 16) | (src[1] << 8) | src[0];
00590                                           src += 3;
00591                                    }
00592                             }
00593                      }
00594                      
00595                      // The contents of the BBitmap now match mImageBits (and mAlphaBits),
00596                      // so mark the flag up to date to prevent extra copies in the future.
00597                      mImageCurrent = PR_TRUE;
00598               }
00599        }
00600 }
00601 
00602 // Since this function does not touch either the source or destination BBitmap,
00603 // there is no need to call CreateImage(). The platform independent bits will get
00604 // copied to the BBitmap if and when it gets blit. Code is derived from GTK version,
00605 // but some wordy constant math is moved out of loops for performance
00606 NS_IMETHODIMP nsImageBeOS::DrawToImage(nsIImage* aDstImage, 
00607                                                                       nscoord aDX, nscoord aDY, 
00608                                                                       nscoord aDWidth, nscoord aDHeight)
00609 {
00610        nsImageBeOS *dest = NS_STATIC_CAST(nsImageBeOS *, aDstImage);
00611 
00612        if (!dest)
00613               return NS_ERROR_FAILURE;
00614 
00615        if (aDX >= dest->mWidth || aDY >= dest->mHeight)
00616               return NS_OK;
00617 
00618        PRUint8 *rgbPtr=0, *alphaPtr=0;
00619        PRUint32 rgbStride, alphaStride;
00620 
00621        rgbPtr = mImageBits;
00622        rgbStride = mRowBytes;
00623        alphaPtr = mAlphaBits;
00624        alphaStride = mAlphaRowBytes;
00625 
00626        PRInt32 y;
00627        PRInt32 ValidWidth = ( aDWidth < ( dest->mWidth - aDX ) ) ? aDWidth : ( dest->mWidth - aDX ); 
00628        PRInt32 ValidHeight = ( aDHeight < ( dest->mHeight - aDY ) ) ? aDHeight : ( dest->mHeight - aDY );
00629 
00630        // now composite the two images together
00631        switch (mAlphaDepth)
00632        {
00633               case 1:
00634               {
00635                      PRUint8 *dst = dest->mImageBits + aDY*dest->mRowBytes + 3*aDX;
00636                      PRUint8 *dstAlpha = dest->mAlphaBits + aDY*dest->mAlphaRowBytes;
00637                      PRUint8 *src = rgbPtr;
00638                      PRUint8 *alpha = alphaPtr;
00639                      PRUint8 offset = aDX & 0x7; // x starts at 0
00640                      PRUint8 offset_8U = 8U - offset;
00641                      int iterations = (ValidWidth+7)/8; // round up
00642                      PRUint32  dst_it_stride = dest->mRowBytes - 3*8*iterations;
00643                      PRUint32  src_it_stride = rgbStride - 3*8*iterations;
00644                      PRUint32  alpha_it_stride = alphaStride - iterations;
00645 
00646                      for (y=0; y < ValidHeight; ++y)
00647                      {
00648                             for (int x=0; x < ValidWidth; x += 8, dst += 24, src += 24)
00649                             {
00650                                    PRUint8 alphaPixels = *alpha++;
00651                                    PRInt32  VW_x = ValidWidth-x;
00652                                    if (alphaPixels == 0)
00653                                           continue; // all 8 transparent; jump forward
00654 
00655                                    // 1 or more bits are set, handle dstAlpha now - may not be aligned.
00656                                    // Are all 8 of these alpha pixels used?
00657                                    if (x+7 >= ValidWidth)
00658                                    {
00659                                           alphaPixels &= 0xff << (8 - VW_x); // no, mask off unused
00660                                           if (alphaPixels == 0)
00661                                                  continue;  // no 1 alpha pixels left
00662                                    }
00663                                    if (offset == 0)
00664                                    {
00665                                           dstAlpha[(aDX+x)>>3] |= alphaPixels; // the cheap aligned case
00666                                    }
00667                                    else
00668                                    {
00669                                           dstAlpha[(aDX+x)>>3] |= alphaPixels >> offset;
00670                                           // avoid write if no 1's to write - also avoids going past end of array
00671                                           // compiler should merge the common sub-expressions
00672                                           if (alphaPixels << offset_8U)
00673                                                  dstAlpha[((aDX+x)>>3) + 1] |= alphaPixels << offset_8U;
00674                                    }
00675           
00676                                    if (alphaPixels == 0xff)
00677                                    {
00678                                           // fix - could speed up by gathering a run of 0xff's and doing 1 memcpy
00679                                           // all 8 pixels set; copy and jump forward
00680                                           memcpy(dst,src,24);
00681                                           continue;
00682                                    }
00683                                    else
00684                                    {
00685                                           // else mix of 1's and 0's in alphaPixels, do 1 bit at a time
00686                                           // Don't go past end of line!
00687                                           PRUint8 *d = dst, *s = src;
00688                                           for (PRUint8 aMask = 1<<7, j = 0; aMask && j < VW_x; aMask >>= 1, ++j)
00689                                           {
00690                                                  // if this pixel is opaque then copy into the destination image
00691                                                  if (alphaPixels & aMask)
00692                                                  {
00693                                                         // might be faster with *d++ = *s++ 3 times?
00694                                                         d[0] = s[0];
00695                                                         d[1] = s[1];
00696                                                         d[2] = s[2];
00697                                                         // dstAlpha bit already set
00698                                                  }
00699                                                  d += 3;
00700                                                  s += 3;
00701                                           }
00702                                    }
00703                             }
00704                             // at end of each line, bump pointers. 
00705                             dst = dst + dst_it_stride;
00706                             src = src + src_it_stride;
00707                             alpha = alpha + alpha_it_stride;
00708                             dstAlpha += dest->mAlphaRowBytes;
00709                      }
00710               }
00711               break;
00712               case 0:
00713               default:
00714                      for (y=0; y < ValidHeight; ++y)
00715                             memcpy(dest->mImageBits + (y+aDY)*dest->mRowBytes + 3*aDX, 
00716                                           rgbPtr + y*rgbStride, 3*ValidWidth);
00717        }
00718        // ImageUpdated() won't be called in this case, so we need to mark the destination
00719        // image as changed. This will cause its data to be copied in the BBitmap when it
00720        // tries to blit. The source has not been modified, so its status has not changed.
00721        nsRect rect(aDX, aDY, ValidWidth, ValidHeight);
00722        dest->ImageUpdated(nsnull, 0, &rect);
00723        mImageCurrent = PR_TRUE;
00724 
00725        return NS_OK;
00726 }