Back to index

lightning-sunbird  0.9+nobinonly
nsImageOS2.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Mozilla OS/2 libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * John Fairhurst, <john_fairhurst@iname.com>.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either of the GNU General Public License Version 2 or later (the "GPL"),
00025  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK *****
00036  *
00037  * This Original Code has been modified by IBM Corporation. Modifications made by IBM 
00038  * described herein are Copyright (c) International Business Machines Corporation, 2000.
00039  * Modifications to Mozilla code or documentation identified per MPL Section 3.3
00040  *
00041  * Date             Modified by     Description of modification
00042  * 05/11/2000       IBM Corp.      Make it look more like Windows.
00043  */
00044 
00045 #include "nsGfxDefs.h"
00046 #include <stdlib.h>
00047 #include <new> // for new(std::nothrow)
00048 
00049 #include "nsImageOS2.h"
00050 #include "nsRenderingContextOS2.h"
00051 #include "nsDeviceContextOS2.h"
00052 #include "imgScaler.h"
00053 
00054 #define MAX_BUFFER_WIDTH        128
00055 #define MAX_BUFFER_HEIGHT       128
00056 
00057 #ifdef XP_OS2_VACPP
00058 // Needed to zero the stack since there is an uninitialized var in the engine
00059 // If you find that printing bitmaps with transparency results in black images then
00060 // take off the # define and use for all OS2 compilers
00061 // This was discovered when the temp bitmap bit depth used in images2::Draw was changed
00062 // from 8 to 24.  It worked in debug but failed in retail.  Investigation revealed GpiErase
00063 // was failing due to a function receiving an uninitialized variable and the stack had invalid
00064 // values (for retail). This function will zero the stack and return leaving a clean stack.
00065 // A parameter is used to ensure the optimizer will compile the code.  Make sure the parameter
00066 // is not larger than the buff size
00067 // The OS2 defect 272592 will fix this in future releases of the engine
00068 extern "C" int zeroStack(int index)
00069 {
00070   #define CLEAR_BUF_SIZE 1024
00071   BYTE buf[CLEAR_BUF_SIZE];
00072   memset(buf, 0, CLEAR_BUF_SIZE * sizeof(BYTE));
00073   return buf[index];
00074 }
00075 #else
00076 #define zeroStack(x)
00077 #endif
00078 
00079 struct MONOBITMAPINFO
00080 {
00081    BITMAPINFOHEADER2 bmpInfo;
00082    RGB2 argbColor [2];
00083 
00084    operator PBITMAPINFO2 ()       { return (PBITMAPINFO2) &bmpInfo; }
00085    operator PBITMAPINFOHEADER2 () { return &bmpInfo; }
00086 
00087    MONOBITMAPINFO( PBITMAPINFO2 pBI)
00088    {
00089       memcpy( &bmpInfo, pBI, sizeof( BITMAPINFOHEADER2));
00090       bmpInfo.cBitCount = 1;
00091 
00092       argbColor [0].bRed      = 0;
00093       argbColor [0].bGreen    = 0;
00094       argbColor [0].bBlue     = 0;
00095       argbColor [0].fcOptions = 0;
00096       argbColor [1].bRed      = 255;
00097       argbColor [1].bGreen    = 255;
00098       argbColor [1].bBlue     = 255;
00099       argbColor [1].fcOptions = 0;
00100    }
00101 };
00102 
00103 
00104 PRUint8 nsImageOS2::gBlenderLookup [65536];    // Global table for fast alpha blending
00105 PRBool  nsImageOS2::gBlenderReady = PR_FALSE;
00106 
00107 
00108 
00109 NS_IMPL_ISUPPORTS1(nsImageOS2, nsIImage)
00110 
00111 //------------------------------------------------------------
00112 nsImageOS2::nsImageOS2()
00113 : mInfo(0)
00114 , mDeviceDepth(0)
00115 , mRowBytes(0)
00116 , mImageBits(0)
00117 , mIsOptimized(PR_FALSE)
00118 , mColorMap(0)
00119 , mDecodedRect()
00120 , mAlphaBits(0)
00121 , mAlphaDepth(0)
00122 , mARowBytes(0)
00123 {
00124    if (gBlenderReady != PR_TRUE)
00125      BuildBlenderLookup ();
00126 }
00127 
00128 nsImageOS2::~nsImageOS2()
00129 {
00130    CleanUp(PR_TRUE);
00131 }
00132 
00133 nsresult nsImageOS2::Init( PRInt32 aWidth, PRInt32 aHeight, PRInt32 aDepth,
00134                            nsMaskRequirements aMaskRequirements)
00135 {
00136    // gfxIImageFrame only allows one init of nsImageOS2
00137 
00138    // (copying windows code - what about monochrome?  Oh well.)
00139    NS_ASSERTION( aDepth == 24 || aDepth == 8, "Bad image depth");
00140 
00141    // Work out size of bitmap to allocate
00142    mRowBytes = RASWIDTH(aWidth,aDepth);
00143 
00144    mImageBits = new(std::nothrow) PRUint8 [aHeight * mRowBytes];
00145    if (!mImageBits) 
00146      return NS_ERROR_OUT_OF_MEMORY;
00147 
00148    // Set up bitmapinfo header
00149    int cols = -1;
00150    if( aDepth == 8) cols = COLOR_CUBE_SIZE;
00151    else if( aDepth <= 32) cols = 0;
00152 
00153    int szStruct = sizeof( BITMAPINFOHEADER2) + cols * sizeof( RGB2);
00154 
00155    mInfo = (PBITMAPINFO2) calloc( szStruct, 1);
00156    mInfo->cbFix = sizeof( BITMAPINFOHEADER2);
00157    mInfo->cx = aWidth;
00158    mInfo->cy = aHeight;
00159    mInfo->cPlanes = 1;
00160    mInfo->cBitCount = (USHORT) aDepth;
00161 
00162    // We can't set up the bitmap colour table yet.
00163 
00164    // init color map.
00165    // XP will update the color map & then call ImageUpdated(), at which
00166    // point we can change the color table in the bitmapinfo.
00167    if( aDepth == 8)
00168    {
00169       mColorMap = new nsColorMap;
00170       mColorMap->NumColors = COLOR_CUBE_SIZE;
00171       mColorMap->Index = new PRUint8[3 * mColorMap->NumColors];
00172    }
00173 
00174    // Allocate stuff for mask bitmap
00175    if( aMaskRequirements != nsMaskRequirements_kNoMask)
00176    {
00177       if( aMaskRequirements == nsMaskRequirements_kNeeds1Bit)
00178       {
00179          mAlphaDepth = 1;
00180       }
00181       else
00182       {
00183          NS_ASSERTION( nsMaskRequirements_kNeeds8Bit == aMaskRequirements,
00184                        "unexpected mask depth");
00185          mAlphaDepth = 8;
00186       }
00187 
00188       // 32-bit align each row
00189       mARowBytes = RASWIDTH (aWidth, mAlphaDepth);
00190 
00191       mAlphaBits = new(std::nothrow) PRUint8 [aHeight * mARowBytes];
00192       if (!mAlphaBits) {
00193         // deallocation is done in ::CleanUp() from the destructor
00194         return NS_ERROR_OUT_OF_MEMORY;
00195       }
00196    }
00197 
00198    return NS_OK;
00199 }
00200 
00201 void nsImageOS2::CleanUp(PRBool aCleanUpAll)
00202 {
00203    // OS2TODO to handle aCleanUpAll param
00204 
00205    if( mImageBits) {
00206       delete [] mImageBits; 
00207       mImageBits = 0;
00208    }
00209    if( mInfo) {
00210       free( mInfo);
00211       mInfo = 0;
00212    }
00213    if( mColorMap) {
00214       if( mColorMap->Index)
00215          delete [] mColorMap->Index;
00216       delete mColorMap;
00217       mColorMap = 0;
00218    }
00219    if( mAlphaBits) {
00220       delete [] mAlphaBits; 
00221       mAlphaBits = 0;
00222    }
00223 }
00224 
00225 void nsImageOS2::ImageUpdated( nsIDeviceContext *aContext,
00226                                PRUint8 aFlags, nsRect *aUpdateRect)
00227 {
00228    mDecodedRect.UnionRect(mDecodedRect, *aUpdateRect);
00229 
00230    if (!aContext) {
00231       return;
00232    } /* endif */
00233    // This is where we can set the bitmap colour table, as the XP code
00234    // has filled in the colour map.  It would be cute to be able to alias
00235    // the bitmap colour table as the mColorMap->Index thing, but the formats
00236    // are unfortunately different.  Rats.
00237 
00238    aContext->GetDepth( mDeviceDepth);
00239 
00240    if( (aFlags & nsImageUpdateFlags_kColorMapChanged) && mInfo->cBitCount == 8)
00241    {
00242       PRGB2 pBmpEntry  = mInfo->argbColor;
00243       PRUint8 *pMapByte = mColorMap->Index;
00244 
00245       for( PRInt32 i = 0; i < mColorMap->NumColors; i++, pBmpEntry++)
00246       {
00247          pBmpEntry->bRed   = *pMapByte++;
00248          pBmpEntry->bGreen = *pMapByte++;
00249          pBmpEntry->bBlue  = *pMapByte++;
00250       }
00251    }
00252    else if( aFlags & nsImageUpdateFlags_kBitsChanged)
00253    {
00254       // jolly good...
00255    }
00256 }
00257 
00261 PRBool nsImageOS2::GetIsImageComplete() {
00262   return mInfo &&
00263          mDecodedRect.x == 0 &&
00264          mDecodedRect.y == 0 &&
00265          mDecodedRect.width == (PRInt32)mInfo->cx &&
00266          mDecodedRect.height == (PRInt32)mInfo->cy;
00267 }
00268 
00269 void nsImageOS2::BuildBlenderLookup (void)
00270 {
00271   for (int y = 0 ; y < 256 ; y++)
00272     for (int x = 0 ; x < 256 ; x++)
00273       gBlenderLookup [y * 256 + x] = y * x / 255;
00274 
00275   gBlenderReady = PR_TRUE;
00276 }
00277 
00278 nsresult nsImageOS2::Draw( nsIRenderingContext &aContext,
00279                            nsIDrawingSurface* aSurface,
00280                            PRInt32 aX, PRInt32 aY,
00281                            PRInt32 aWidth, PRInt32 aHeight)
00282 {
00283    return Draw( aContext, aSurface,
00284                 0, 0, mInfo->cx, mInfo->cy,
00285                 aX, aY, aWidth, aHeight);
00286 }
00287 
00291 void nsImageOS2 :: DrawComposited24(unsigned char *aBits,
00292                           PRUint8 *aImageRGB, PRUint32 aStrideRGB,
00293                           PRUint8 *aImageAlpha, PRUint32 aStrideAlpha,
00294                           int aWidth, int aHeight)
00295 {
00296   PRInt32 targetRowBytes = ((aWidth * 3) + 3) & ~3;
00297 
00298   for (int y = 0; y < aHeight; y++) {
00299     unsigned char *targetRow = aBits + y * targetRowBytes;
00300     unsigned char *imageRow = aImageRGB + y * aStrideRGB;
00301     unsigned char *alphaRow = aImageAlpha + y * aStrideAlpha;
00302 
00303     for (int x = 0; x < aWidth;
00304          x++, targetRow += 3, imageRow += 3, alphaRow++) {
00305       unsigned alpha = *alphaRow;
00306       MOZ_BLEND(targetRow[0], targetRow[0], imageRow[0], alpha);
00307       MOZ_BLEND(targetRow[1], targetRow[1], imageRow[1], alpha);
00308       MOZ_BLEND(targetRow[2], targetRow[2], imageRow[2], alpha);
00309     }
00310   }
00311 }
00312 
00313 NS_IMETHODIMP 
00314 nsImageOS2 :: Draw(nsIRenderingContext &aContext, nsIDrawingSurface* aSurface,
00315                   PRInt32 aSX, PRInt32 aSY, PRInt32 aSWidth, PRInt32 aSHeight,
00316                   PRInt32 aDX, PRInt32 aDY, PRInt32 aDWidth, PRInt32 aDHeight)
00317 {
00318   nsresult rv = NS_OK;
00319 
00320    PRInt32 origSHeight = aSHeight, origDHeight = aDHeight;
00321    PRInt32 origSWidth = aSWidth, origDWidth = aDWidth;
00322 
00323    if (mInfo == nsnull || aSWidth < 0 || aDWidth < 0 || aSHeight < 0 || aDHeight < 0) 
00324       return NS_ERROR_FAILURE;
00325 
00326    if (0 == aSWidth || 0 == aDWidth || 0 == aSHeight || 0 == aDHeight)
00327       return NS_OK;
00328 
00329    // limit the size of the blit to the amount of the image read in
00330    PRInt32 aSX2 = aSX + aSWidth;
00331 
00332    if (aSX2 > mDecodedRect.XMost()) 
00333       aSX2 = mDecodedRect.XMost();
00334 
00335    if (aSX < mDecodedRect.x) {
00336       aDX += (mDecodedRect.x - aSX) * origDWidth / origSWidth;
00337       aSX = mDecodedRect.x;
00338    }
00339   
00340    aSWidth = aSX2 - aSX;
00341    aDWidth -= (origSWidth - aSWidth) * origDWidth / origSWidth;
00342   
00343    if (aSWidth <= 0 || aDWidth <= 0)
00344       return NS_OK;
00345 
00346    PRInt32 aSY2 = aSY + aSHeight;
00347 
00348    if (aSY2 > mDecodedRect.YMost())
00349       aSY2 = mDecodedRect.YMost();
00350 
00351    if (aSY < mDecodedRect.y) {
00352       aDY += (mDecodedRect.y - aSY) * origDHeight / origSHeight;
00353       aSY = mDecodedRect.y;
00354    }
00355 
00356    aSHeight = aSY2 - aSY;
00357    aDHeight -= (origSHeight - aSHeight) * origDHeight / origSHeight;
00358 
00359    if (aSHeight <= 0 || aDHeight <= 0)
00360       return NS_OK;
00361 
00362    nsDrawingSurfaceOS2 *surf = (nsDrawingSurfaceOS2*) aSurface;
00363  
00364 
00365    nsRect trect( aDX, aDY, aDWidth, aDHeight);
00366    RECTL  rcl;
00367    surf->NS2PM_ININ (trect, rcl);
00368 
00369    // Set up blit coord array
00370    POINTL aptl[ 4] = { { rcl.xLeft, rcl.yBottom },              // TLL
00371                        { rcl.xRight, rcl.yTop },                // TUR
00372                        { aSX, mInfo->cy - (aSY + aSHeight) },   // SLL
00373                        { aSX + aSWidth, mInfo->cy - aSY } };    // SUR
00374                        
00375    PRBool fPrinting = PR_FALSE;
00376    nsIDeviceContext*  context;
00377    aContext.GetDeviceContext(context);
00378    if (((nsDeviceContextOS2 *)context)->mPrintDC) {
00379       fPrinting = PR_TRUE;
00380    }
00381 
00382    if( mAlphaDepth == 0)
00383    {
00384       // no transparency, just blit it
00385       GFX (::GpiDrawBits (surf->GetPS (), mImageBits, mInfo, 4, aptl, ROP_SRCCOPY, BBO_IGNORE), GPI_ERROR);
00386    }
00387    else if( mAlphaDepth == 1)
00388    {
00389       if (!fPrinting) {
00390          // > The transparent areas of the mask are coloured black (0).
00391          // > the transparent areas of the pixmap are coloured black (0).
00392          // > Note this does *not* mean that all black pels are transparent!
00393          // >
00394          // > Thus all we need to do is AND the mask onto the target, taking
00395          // > out pels that are not transparent, and then OR the image onto
00396          // > the target.
00397          // >
00398          // > For monochrome bitmaps GPI replaces 1 with IMAGEBUNDLE foreground
00399          // > color and 0 with background color. To make this work with ROP_SRCAND
00400          // > we set foreground to black and background to white. Thus AND with 
00401          // > 1 (opaque) in mask maps to AND with IMAGEBUNDLE foreground (which is 0)
00402          // > always gives 0 - clears opaque region to zeros. 
00403    
00404          // Apply mask to target, clear pels we will fill in from the image
00405          MONOBITMAPINFO MaskBitmapInfo (mInfo);
00406          GFX (::GpiDrawBits (surf->GetPS (), mAlphaBits, MaskBitmapInfo, 4, aptl, ROP_SRCAND, BBO_IGNORE), GPI_ERROR);
00407    
00408          // Now combine image with target
00409          GFX (::GpiDrawBits (surf->GetPS (), mImageBits, mInfo, 4, aptl, ROP_SRCPAINT, BBO_IGNORE), GPI_ERROR);
00410       } else {
00411          // Find the compatible device context and create a memory one
00412          HDC hdcCompat = GFX (::GpiQueryDevice (surf->GetPS ()), HDC_ERROR);
00413    
00414          rv = NS_ERROR_FAILURE;
00415        
00416          // create non-inclusive rect for GpiBitBlt
00417          RECTL dest;
00418          surf->NS2PM_INEX (trect, dest);
00419    
00420          DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 };
00421          HDC MemDC = ::DevOpenDC( (HAB)0, OD_MEMORY, "*", 5, (PDEVOPENDATA) &dop, hdcCompat);
00422    
00423          if( MemDC != DEV_ERROR )
00424          {   
00425            // create the PS
00426            SIZEL sizel = { 0, 0 };
00427            HPS MemPS = GFX (::GpiCreatePS (0, MemDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC), GPI_ERROR);
00428    
00429            if( MemPS != GPI_ERROR )
00430            {
00431              GFX (::GpiCreateLogColorTable (MemPS, 0, LCOLF_RGB, 0, 0, 0), FALSE);
00432    
00433              // now create a bitmap of the right size
00434              HBITMAP hMemBmp;
00435              BITMAPINFOHEADER2 bihMem = { 0 };
00436    
00437              bihMem.cbFix = sizeof (BITMAPINFOHEADER2);
00438              bihMem.cx = aSWidth;
00439              bihMem.cy = aSHeight;
00440              bihMem.cPlanes = 1;
00441              LONG lBitCount = 0;
00442              GFX (::DevQueryCaps( hdcCompat, CAPS_COLOR_BITCOUNT, 1, &lBitCount), FALSE);
00443              lBitCount = 24; // For printing
00444              bihMem.cBitCount = lBitCount;
00445              
00446              hMemBmp = GFX (::GpiCreateBitmap (MemPS, &bihMem, 0, 0, 0), GPI_ERROR);
00447    
00448              if( hMemBmp != GPI_ERROR )
00449              {
00450                GFX (::GpiSetBitmap (MemPS, hMemBmp), HBM_ERROR);
00451                zeroStack(10);
00452                GpiErase(MemPS);
00453    
00454                // Now combine image with target
00455                // Set up blit coord array
00456                POINTL aptlNew[ 4] = { { 0, 0 },              // TLL
00457                                       { bihMem.cx, bihMem.cy },                // TUR
00458                                       { aSX, mInfo->cy - (aSY + aSHeight) },   // SLL
00459                                       { aSX + aSWidth+1, mInfo->cy - aSY+1 } };    // SUR
00460    
00461                // Apply mask to target, clear pels we will fill in from the image
00462                MONOBITMAPINFO MaskBitmapInfo (mInfo);                                   
00463                GFX (::GpiDrawBits (MemPS, mAlphaBits, MaskBitmapInfo, 4, aptlNew, ROP_SRCAND, BBO_IGNORE), GPI_ERROR);
00464           
00465                // Now combine image with target
00466                GFX (::GpiDrawBits (MemPS, mImageBits, mInfo, 4, aptlNew, ROP_SRCPAINT, BBO_IGNORE), GPI_ERROR);
00467    
00468                // Transfer bitmap from memory bitmap back to device
00469                POINTL aptlMemToDev [4] = { {dest.xLeft, dest.yBottom},   // TLL - device (Dx1, Dy2)
00470                                            {dest.xRight, dest.yTop},     // TUR - device (Dx2, Dy1)
00471                                            {0, 0},                       // SLL - mem bitmap (0, 0)
00472                                            {bihMem.cx, bihMem.cy} };      // SUR - mem bitmap (cx, cy)
00473    
00474                GFX (::GpiBitBlt (surf->GetPS (), MemPS, 4, aptlMemToDev, ROP_SRCCOPY, BBO_IGNORE), GPI_ERROR);
00475                
00476                rv = NS_OK;
00477                                                                    
00478                GFX (::GpiSetBitmap (MemPS, NULLHANDLE), HBM_ERROR);
00479                GFX (::GpiDeleteBitmap (hMemBmp), FALSE);
00480              }
00481            
00482              GFX (::GpiDestroyPS (MemPS), FALSE);
00483            }
00484        
00485            ::DevCloseDC (MemDC);
00486          }
00487       }
00488    } else
00489    {
00490       // Find the compatible device context and create a memory one
00491       HDC hdcCompat = GFX (::GpiQueryDevice (surf->GetPS ()), HDC_ERROR);
00492 
00493       rv = NS_ERROR_FAILURE;
00494     
00495        // create non-inclusive rect for GpiBitBlt
00496       RECTL dest;
00497       surf->NS2PM_INEX (trect, dest);
00498 
00499       DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 };
00500       HDC MemDC = ::DevOpenDC( (HAB)0, OD_MEMORY, "*", 5, (PDEVOPENDATA) &dop, hdcCompat);
00501 
00502       if( MemDC != DEV_ERROR )
00503       {   
00504         // create the PS
00505         SIZEL sizel = { 0, 0 };
00506         HPS MemPS = GFX (::GpiCreatePS (0, MemDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC), GPI_ERROR);
00507 
00508         if( MemPS != GPI_ERROR )
00509         {
00510           GFX (::GpiCreateLogColorTable (MemPS, 0, LCOLF_RGB, 0, 0, 0), FALSE);
00511 
00512           // now create a bitmap of the right size
00513           HBITMAP hMemBmp;
00514           BITMAPINFOHEADER2 bihMem = { 0 };
00515 
00516           bihMem.cbFix = sizeof (BITMAPINFOHEADER2);
00517           bihMem.cx = aDWidth;
00518           bihMem.cy = aDHeight;
00519           bihMem.cPlanes = 1;
00520           LONG lBitCount = 0;
00521           GFX (::DevQueryCaps( hdcCompat, CAPS_COLOR_BITCOUNT, 1, &lBitCount), FALSE);
00522           if (!fPrinting)
00523           {
00524             bihMem.cBitCount = (USHORT) lBitCount;
00525           }
00526           else  // Printing
00527           {
00528             // bihMem.cBitCount = (USHORT) lBitCount;
00529             bihMem.cBitCount = 24;
00530           }
00531 
00532           hMemBmp = GFX (::GpiCreateBitmap (MemPS, &bihMem, 0, 0, 0), GPI_ERROR);
00533 
00534           if( hMemBmp != GPI_ERROR )
00535           {
00536             GFX (::GpiSetBitmap (MemPS, hMemBmp), HBM_ERROR);
00537 
00538             POINTL aptlDevToMem [4] = { {0, 0},                       // TLL - mem bitmap (0, 0)
00539                                         {bihMem.cx, bihMem.cy},       // TUR - mem bitmap (cx, cy)
00540                                         {dest.xLeft, dest.yBottom},   // SLL - device (Dx1, Dy2)
00541                                         {dest.xRight, dest.yTop} };   // SUR - device (Dx2, Dy1)
00542 
00543             GFX (::GpiBitBlt (MemPS, surf->GetPS (), 4, aptlDevToMem, ROP_SRCCOPY, BBO_IGNORE), GPI_ERROR);
00544 
00545             // Now we want direct access to bitmap raw data. 
00546             // Must copy data again because GpiSetBitmap doesn't provide pointer to
00547             // start of raw bit data ?? (DJ)
00548             BITMAPINFOHEADER2 bihDirect = { 0 };
00549             bihDirect.cbFix   = sizeof (BITMAPINFOHEADER2);
00550             bihDirect.cPlanes = 1;
00551             bihDirect.cBitCount = 24;
00552 
00553             int RawDataSize = bihMem.cy * RASWIDTH (bihMem.cx, 24);
00554             PRUint8* pRawBitData = (PRUint8*)malloc (RawDataSize);
00555 
00556             if( pRawBitData )
00557             {
00558               LONG rc = GFX (::GpiQueryBitmapBits (MemPS, 0, bihMem.cy, (PBYTE)pRawBitData, (PBITMAPINFO2)&bihDirect), GPI_ALTERROR);
00559 
00560               if( rc != GPI_ALTERROR )
00561               {
00562               PRUint8 *imageRGB, *imageAlpha;
00563               PRUint32 strideRGB, strideAlpha;
00564 
00565               /* Both scaled and unscaled images come through this code - save
00566                  work if not scaling */
00567               if ((aSWidth != aDWidth) || (aSHeight != aDHeight)) {
00568                 /* Scale our image to match */
00569                 imageRGB = (PRUint8 *)nsMemory::Alloc(3*aDWidth*aDHeight);
00570                 imageAlpha = (PRUint8 *)nsMemory::Alloc(aDWidth*aDHeight);
00571                     
00572                 if (!imageRGB || !imageAlpha) {
00573                   if (imageRGB)
00574                     nsMemory::Free(imageRGB);
00575                   if (imageAlpha)
00576                     nsMemory::Free(imageAlpha);
00577 
00578                   free(pRawBitData);
00579                   GFX (::GpiSetBitmap (MemPS, NULLHANDLE), HBM_ERROR);
00580                   GFX (::GpiDeleteBitmap (hMemBmp), FALSE);
00581                   GFX (::GpiDestroyPS (MemPS), FALSE);
00582                   ::DevCloseDC (MemDC);
00583 
00584                   return NS_ERROR_FAILURE;
00585                 }
00586                     
00587                 strideRGB = 3 * aDWidth;
00588                 strideAlpha = aDWidth;
00589                 RectStretch(aSWidth, aSHeight, aDWidth, aDHeight, 0, 0, aDWidth-1, aDHeight-1,
00590                            mImageBits, mRowBytes, imageRGB, strideRGB, 24);
00591                 RectStretch(aSWidth, aSHeight, aDWidth, aDHeight, 0, 0, aDWidth-1, aDHeight-1,
00592                            mAlphaBits, mARowBytes, imageAlpha, strideAlpha, 8);
00593               } else {
00594                   PRUint32 srcy = mInfo->cy - (aSY + aSHeight);
00595                 imageRGB = mImageBits + srcy * mRowBytes + aSX * 3;
00596                 imageAlpha = mAlphaBits + srcy * mARowBytes + aSX;
00597                 strideRGB = mRowBytes;
00598                 strideAlpha = mARowBytes;
00599               }
00600 
00601               /* Do composite */
00602               DrawComposited24(pRawBitData, imageRGB, strideRGB, imageAlpha, strideAlpha,
00603                              aDWidth, aDHeight);
00604                 
00605               if ((aSWidth != aDWidth) || (aSHeight != aDHeight)) {
00606                 /* Free scaled images */
00607                 nsMemory::Free(imageRGB);
00608                 nsMemory::Free(imageAlpha);
00609               }
00610         
00611                 // Copy modified memory back to memory bitmap
00612                 GFX (::GpiSetBitmapBits (MemPS, 0, bihMem.cy, (PBYTE)pRawBitData, (PBITMAPINFO2)&bihDirect), GPI_ALTERROR);
00613               
00614                 // Transfer bitmap from memory bitmap back to device
00615                 POINTL aptlMemToDev [4] = { {dest.xLeft, dest.yBottom},   // TLL - device (Dx1, Dy2)
00616                                             {dest.xRight, dest.yTop},     // TUR - device (Dx2, Dy1)
00617                                             {0, 0},                       // SLL - mem bitmap (0, 0)
00618                                             {bihMem.cx, bihMem.cy} };      // SUR - mem bitmap (cx, cy)
00619 
00620                 GFX (::GpiBitBlt (surf->GetPS (), MemPS, 4, aptlMemToDev, ROP_SRCCOPY, BBO_IGNORE), GPI_ERROR);
00621             
00622                 rv = NS_OK;
00623               }
00624 
00625               free (pRawBitData);
00626             }
00627 
00628             GFX (::GpiSetBitmap (MemPS, NULLHANDLE), HBM_ERROR);
00629             GFX (::GpiDeleteBitmap (hMemBmp), FALSE);
00630           }
00631         
00632           GFX (::GpiDestroyPS (MemPS), FALSE);
00633         }
00634     
00635         ::DevCloseDC (MemDC);
00636       }
00637    }
00638 
00639    return rv;
00640 }
00641 
00642 nsresult nsImageOS2::Optimize( nsIDeviceContext* aContext)
00643 {
00644    // Defer this until we have a PS...
00645    mIsOptimized = PR_TRUE;
00646    return NS_OK;
00647 }
00648 
00649 //------------------------------------------------------------
00650 // lock the image pixels. implement this if you need it
00651 NS_IMETHODIMP
00652 nsImageOS2::LockImagePixels(PRBool aMaskPixels)
00653 {
00654   return NS_OK;
00655 }
00656 
00657 //------------------------------------------------------------
00658 // unlock the image pixels. implement this if you need it
00659 NS_IMETHODIMP
00660 nsImageOS2::UnlockImagePixels(PRBool aMaskPixels)
00661 {
00662   return NS_OK;
00663 } 
00664 
00665 void
00666 nsImageOS2::BuildTile (HPS hpsTile, PRUint8* pImageBits, PBITMAPINFO2 pBitmapInfo,
00667                        nscoord aTileWidth, nscoord aTileHeight, float scale)
00668 {
00669    // If bitmap not fully loaded, then first fill area with background color.
00670    if (nsRect (0, 0, mInfo->cx, mInfo->cy) != mDecodedRect)
00671    {
00672       POINTL pt1 = { 0, 0 };                                                   // LL - in
00673       POINTL pt2 = { mInfo->cx, mInfo->cy };                                   // UR - ex
00674 
00675 #ifdef DEBUG
00676       GFX (::GpiSetColor (hpsTile, MK_RGB (255, 255, 0)), FALSE);              // yellow eye-catcher
00677 #else
00678       GFX (::GpiSetColor (hpsTile, MK_RGB (255, 255, 255)), FALSE);
00679 #endif
00680       GFX (::GpiMove (hpsTile, &pt1), FALSE);
00681       GFX (::GpiBox (hpsTile, DRO_FILL, &pt2, 0, 0), GPI_ERROR);
00682    }
00683 
00684    // Set up blit coord array
00685    POINTL aptl [4] = { {mDecodedRect.x, mDecodedRect.y},                         // TLL - in
00686                        {mDecodedRect.XMost () - 1, mDecodedRect.YMost () - 1},   // TUR - in
00687                        {mDecodedRect.x, mDecodedRect.y},                         // SLL - in
00688                        {mDecodedRect.XMost (), mDecodedRect.YMost ()} };         // SUR - ex
00689 
00690    // Scale up
00691    aptl[0].x = (LONG)(aptl[0].x * scale);
00692    aptl[0].y = (LONG)(aptl[0].y * scale);
00693    aptl[1].x = (LONG)(mDecodedRect.XMost() * scale) - 1;
00694    aptl[1].y = (LONG)(mDecodedRect.YMost() * scale) - 1;
00695    
00696    // Draw bitmap once into temporary PS
00697    GFX (::GpiDrawBits (hpsTile, (PBYTE)pImageBits, pBitmapInfo, 4, aptl, ROP_SRCCOPY, BBO_IGNORE), GPI_ERROR);
00698 
00699    PRInt32 DestWidth  = (PRInt32)(mInfo->cx * scale);
00700    PRInt32 DestHeight = (PRInt32)(mInfo->cy * scale);
00701 
00702    // Copy bitmap horizontally, doubling each time
00703    if (DestWidth > 0) {
00704       while (DestWidth < aTileWidth)
00705       {
00706          POINTL aptlCopy [3] = { {DestWidth, 0},                     // TLL - in
00707                                  {2 * DestWidth, DestHeight},        // TUR - ex
00708                                  {0, 0} };                           // SLL - in
00709 
00710          GFX (::GpiBitBlt (hpsTile, hpsTile, 3, aptlCopy, ROP_SRCCOPY, 0L), GPI_ERROR);
00711          DestWidth *= 2;
00712       }
00713    }
00714 
00715    // Copy bitmap vertically, doubling each time
00716    if (DestHeight > 0) {
00717       while (DestHeight < aTileHeight)
00718       {
00719          POINTL aptlCopy [4] = { {0, DestHeight},                    // TLL - in
00720                                  {DestWidth, 2 * DestHeight},        // TUR - ex
00721                                  {0, 0} };                           // SLL - in
00722 
00723          GFX (::GpiBitBlt (hpsTile, hpsTile, 3, aptlCopy, ROP_SRCCOPY, 0L), GPI_ERROR);
00724          DestHeight *= 2;
00725       }
00726    }
00727 }
00728 
00733 NS_IMETHODIMP nsImageOS2::DrawTile(nsIRenderingContext &aContext,
00734                                    nsIDrawingSurface* aSurface,
00735                                    PRInt32 aSXOffset, PRInt32 aSYOffset,
00736                                    PRInt32 aPadX, PRInt32 aPadY,
00737                                    const nsRect &aTileRect)
00738 {
00739    if (aTileRect.IsEmpty ())
00740       return NS_OK;
00741 
00742    PRBool didTile = PR_FALSE;
00743    PRInt32 ImageWidth = mInfo->cx;
00744    PRInt32 ImageHeight = mInfo->cy;
00745    PRBool padded = (aPadX || aPadY);
00746 
00747    // Get the scale - if greater than 1 then do slow tile which
00748    nsIDeviceContext *theDeviceContext;
00749    float scale;
00750    aContext.GetDeviceContext(theDeviceContext);
00751    theDeviceContext->GetCanonicalPixelScale(scale);
00752 
00753    nsRect ValidRect (0, 0, ImageWidth, ImageHeight);
00754    ValidRect.IntersectRect (ValidRect, mDecodedRect);
00755    PRInt32 DestScaledWidth = PR_MAX(PRInt32(ValidRect.width * scale), 1);
00756    PRInt32 DestScaledHeight = PR_MAX(PRInt32(ValidRect.height * scale), 1);
00757 
00758    nsRect DrawRect = aTileRect;
00759    DrawRect.MoveBy (-aSXOffset, -aSYOffset);
00760    DrawRect.SizeBy (aSXOffset, aSYOffset);
00761 
00762    // Don't bother tiling if we only have to draw the bitmap a couple of times
00763    // Can't tile with 8bit alpha masks because need access destination bitmap values
00764    if ((ImageWidth < DrawRect.width / 2 || ImageHeight < DrawRect.height / 2) &&
00765        (ImageWidth <= MAX_BUFFER_WIDTH) && (ImageHeight <= MAX_BUFFER_HEIGHT) &&
00766        mAlphaDepth <= 1 &&
00767        !padded)
00768    {
00769       nsDrawingSurfaceOS2 *surf = (nsDrawingSurfaceOS2*) aSurface;
00770 
00771       // Find the compatible device context and create a memory one
00772       HDC hdcCompat = GFX (::GpiQueryDevice (surf->GetPS ()), HDC_ERROR);
00773 
00774       DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 };
00775       HDC MemDC = GFX (::DevOpenDC( (HAB)0, OD_MEMORY, "*", 5, (PDEVOPENDATA) &dop, hdcCompat), DEV_ERROR);
00776 
00777       if( DEV_ERROR != MemDC)
00778       {
00779          // create the PS
00780          SIZEL sizel = { 0, 0 };
00781          HPS MemPS = GFX (::GpiCreatePS (0, MemDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC), GPI_ERROR);
00782 
00783          if( GPI_ERROR != MemPS)
00784          {
00785             GFX (::GpiCreateLogColorTable (MemPS, 0, LCOLF_RGB, 0, 0, 0), FALSE);
00786 
00787             // now create a bitmap of the right size
00788             BITMAPINFOHEADER2 hdr = { 0 };
00789 
00790             hdr.cbFix = sizeof( BITMAPINFOHEADER2);
00791             // Maximum size of tiled area (could do this better)
00792             PRInt32 endWidth = DestScaledWidth;
00793             while( endWidth < DrawRect.width)
00794                endWidth *= 2;
00795 
00796             PRInt32 endHeight = DestScaledHeight;
00797             while( endHeight < DrawRect.height)
00798                endHeight *= 2;
00799 
00800             hdr.cx = endWidth;
00801             hdr.cy = endHeight;
00802             hdr.cPlanes = 1;
00803 
00804             // find bitdepth
00805             LONG lBitCount = 0;
00806             GFX (::DevQueryCaps( hdcCompat, CAPS_COLOR_BITCOUNT, 1, &lBitCount), FALSE);
00807             hdr.cBitCount = (USHORT) lBitCount;
00808 
00809             RECTL  rcl;
00810             surf->NS2PM_INEX (aTileRect, rcl);
00811 
00812             POINTL aptlTile [3] = { {rcl.xLeft, rcl.yBottom},                                 // TLL - in
00813                                     {rcl.xRight, rcl.yTop},                                   // TUR - ex
00814                                     {aSXOffset, endHeight - aTileRect.height - aSYOffset} };  // SLL - in
00815             // For some reason offset does not work well with scaled output
00816             if (scale > 1.0)
00817             {
00818                aptlTile[2].x = 0;
00819                aptlTile[2].y = endHeight - aTileRect.height;
00820             }
00821             HBITMAP hMemBmp = GFX (::GpiCreateBitmap (MemPS, &hdr, 0, 0, 0), GPI_ERROR);
00822             if (hMemBmp != GPI_ERROR)
00823             {
00824                LONG ImageROP = ROP_SRCCOPY;
00825 
00826                GFX (::GpiSetBitmap (MemPS, hMemBmp), HBM_ERROR);
00827 
00828                if (mAlphaDepth == 1)
00829                {
00830                   LONG BlackColor = GFX (::GpiQueryColorIndex (MemPS, 0, MK_RGB (0x00, 0x00, 0x00)), GPI_ALTERROR);    // CLR_BLACK;
00831                   LONG WhiteColor = GFX (::GpiQueryColorIndex (MemPS, 0, MK_RGB (0xFF, 0xFF, 0xFF)), GPI_ALTERROR);    // CLR_WHITE;
00832 
00833                   // WORKAROUND:
00834                   // PostScript drivers up to version 30.732 have problems with GpiQueryColorIndex.
00835                   // If we are in LCOL_RGB mode it doesn't return passed RGB color but returns error instead.
00836 
00837                   if (BlackColor == GPI_ALTERROR) BlackColor = MK_RGB (0x00, 0x00, 0x00);
00838                   if (WhiteColor == GPI_ALTERROR) WhiteColor = MK_RGB (0xFF, 0xFF, 0xFF);
00839 
00840                   // Set image foreground and background colors. These are used in transparent images for blitting 1-bit masks.
00841                   // To invert colors on ROP_SRCAND we map 1 to black and 0 to white
00842                   IMAGEBUNDLE ib;
00843                   ib.lColor     = BlackColor;        // map 1 in mask to 0x000000 (black) in destination
00844                   ib.lBackColor = WhiteColor;        // map 0 in mask to 0xFFFFFF (white) in destination
00845                   ib.usMixMode  = FM_OVERPAINT;
00846                   ib.usBackMixMode = BM_OVERPAINT;
00847                   GFX (::GpiSetAttrs (MemPS, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR | IBB_MIX_MODE | IBB_BACK_MIX_MODE, 0, (PBUNDLE)&ib), FALSE);
00848 
00849                   MONOBITMAPINFO MaskBitmapInfo (mInfo);
00850                   BuildTile (MemPS, mAlphaBits, MaskBitmapInfo, DrawRect.width, DrawRect.height, scale);
00851 
00852                   // Apply mask to target, clear pels we will fill in from the image
00853                   GFX (::GpiBitBlt (surf->GetPS (), MemPS, 3, aptlTile, ROP_SRCAND, 0L), GPI_ERROR);
00854 
00855                   ImageROP = ROP_SRCPAINT;    // Original image must be combined with mask
00856                }
00857 
00858                BuildTile (MemPS, mImageBits, mInfo, DrawRect.width, DrawRect.height, scale);
00859 
00860                GFX (::GpiBitBlt (surf->GetPS (), MemPS, 3, aptlTile, ImageROP, 0L), GPI_ERROR);
00861 
00862                didTile = PR_TRUE;
00863 
00864                // Must deselect bitmap from PS before freeing bitmap and PS.
00865                GFX (::GpiSetBitmap (MemPS, NULLHANDLE), HBM_ERROR);
00866                GFX (::GpiDeleteBitmap (hMemBmp), FALSE);
00867             }
00868             GFX (::GpiDestroyPS (MemPS), FALSE);
00869          }
00870          GFX (::DevCloseDC (MemDC), DEV_ERROR);
00871       }
00872    }
00873 
00874    // If we failed to tile the bitmap, then use the old, slow, reliable way
00875    if( didTile == PR_FALSE)
00876    {
00877       // put the DestRect into absolute coordintes of the device
00878       PRInt32 y0 = aTileRect.y - aSYOffset;
00879       PRInt32 x0 = aTileRect.x - aSXOffset;
00880       PRInt32 y1 = aTileRect.y + aTileRect.height;
00881       PRInt32 x1 = aTileRect.x + aTileRect.width;
00882 
00883       // this is the width and height of the image in pixels
00884       // we need to map this to the pixel height of the device
00885       nscoord ScaledTileWidth = PR_MAX(PRInt32(ImageWidth*scale), 1);
00886       nscoord ScaledTileHeight = PR_MAX(PRInt32(ImageHeight*scale), 1);
00887 
00888       for (PRInt32 y = y0; y < y1; y += (PRInt32)(ScaledTileHeight + aPadY * scale))
00889       {
00890         for (PRInt32 x = x0; x < x1;  x += (PRInt32)(ScaledTileWidth + aPadX * scale))
00891         {
00892           Draw(aContext, aSurface,
00893                0, 0, PR_MIN(ValidRect.width, x1 - x), PR_MIN(ValidRect.height, y1 - y),
00894                x, y, PR_MIN(DestScaledWidth, x1-x), PR_MIN(DestScaledHeight, y1 - y));
00895         }
00896       }
00897    }
00898    return NS_OK;
00899 }
00900 
00901 
00902 void nsImageOS2::NS2PM_ININ( const nsRect &in, RECTL &rcl)
00903 {
00904   PRUint32 ulHeight = GetHeight ();
00905 
00906   rcl.xLeft = in.x;
00907   rcl.xRight = in.x + in.width - 1;
00908   rcl.yTop = ulHeight - in.y - 1;
00909   rcl.yBottom = rcl.yTop - in.height + 1;
00910 }
00911 
00912 
00913 // ---------------------------------------------------
00914 //     Update mImageBits with content of new mBitmap
00915 //
00916 NS_IMETHODIMP nsImageOS2::UpdateImageBits( HPS aPS )
00917 {
00918   BITMAPINFOHEADER2 rawInfo = { 0 };
00919   rawInfo.cbFix   = sizeof (BITMAPINFOHEADER2);
00920   rawInfo.cPlanes = 1;
00921   rawInfo.cBitCount = mInfo->cBitCount;
00922 
00923   int RawDataSize = mInfo->cy * RASWIDTH (mInfo->cx, mInfo->cBitCount);
00924   PRUint8* pRawBitData = new(std::nothrow) PRUint8 [RawDataSize];
00925 
00926   if (pRawBitData)
00927   {
00928     GFX (::GpiQueryBitmapBits (aPS, 0, mInfo->cy, (PBYTE)pRawBitData, (PBITMAPINFO2)&rawInfo), GPI_ALTERROR);
00929     delete [] mImageBits;
00930     mImageBits = pRawBitData;
00931     return NS_OK;
00932   }
00933   else
00934     return NS_ERROR_OUT_OF_MEMORY;
00935 }
00936 
00937 NS_IMETHODIMP nsImageOS2::DrawToImage(nsIImage* aDstImage,
00938                                       nscoord aDX, nscoord aDY,
00939                                       nscoord aDWidth, nscoord aDHeight)
00940 {
00941   nsresult rc = NS_OK;
00942 
00943   DEVOPENSTRUC dop = { 0, 0, 0, 0, 0 };
00944   SIZEL sizel = { 0, 0 };
00945 
00946   if (mInfo == nsnull || aDWidth < 0 || aDHeight < 0) 
00947     return NS_ERROR_FAILURE;
00948 
00949   if (0 == aDWidth || 0 == aDHeight)
00950     return NS_OK;
00951 
00952   // Create a memory DC that is compatible with the screen
00953   HDC MemDC = GFX (::DevOpenDC( 0/*hab*/, OD_MEMORY, "*", 5,
00954                    (PDEVOPENDATA) &dop, (HDC)0), DEV_ERROR);
00955 
00956   // create the PS
00957   HPS MemPS = GFX (::GpiCreatePS (0/*hab*/, MemDC, &sizel, PU_PELS | GPIT_MICRO | GPIA_ASSOC), GPI_ERROR);
00958 
00959   GFX (::GpiCreateLogColorTable (MemPS, 0, LCOLF_RGB, 0, 0, 0), FALSE);
00960 
00961   nsImageOS2* destImg = NS_STATIC_CAST(nsImageOS2*, aDstImage); 
00962 
00963   HBITMAP hTmpBitmap = GFX (::GpiCreateBitmap (MemPS, (PBITMAPINFOHEADER2)destImg->mInfo,
00964                                                CBM_INIT, (PBYTE)destImg->mImageBits,
00965                                                destImg->mInfo), GPI_ERROR);
00966   GFX (::GpiSetBitmap (MemPS, hTmpBitmap), HBM_ERROR);
00967   
00968   nsRect trect( aDX, aDY, aDWidth, aDHeight);
00969   RECTL  rcl;
00970   destImg->NS2PM_ININ (trect, rcl);
00971 
00972   // Set up blit coord array
00973   POINTL aptl [4] = { {rcl.xLeft, rcl.yBottom},              // TLL - in
00974                       {rcl.xRight, rcl.yTop},                // TUR - in
00975                       {0, 0},                                // SLL - in
00976                       {mInfo->cx, mInfo->cy} };              // SUR - ex
00977 
00978   if( 1==mAlphaDepth && mAlphaBits)
00979   {
00980     LONG BlackColor = GFX (::GpiQueryColorIndex (MemPS, 0, MK_RGB (0x00, 0x00, 0x00)), GPI_ALTERROR);    // CLR_BLACK;
00981     LONG WhiteColor = GFX (::GpiQueryColorIndex (MemPS, 0, MK_RGB (0xFF, 0xFF, 0xFF)), GPI_ALTERROR);    // CLR_WHITE;
00982     if (BlackColor == GPI_ALTERROR) BlackColor = MK_RGB (0x00, 0x00, 0x00);
00983     if (WhiteColor == GPI_ALTERROR) WhiteColor = MK_RGB (0xFF, 0xFF, 0xFF);
00984 
00985     // Set image foreground and background colors. These are used in transparent images for blitting 1-bit masks.
00986     // To invert colors on ROP_SRCAND we map 1 to black and 0 to white
00987     IMAGEBUNDLE ib;
00988     ib.lColor     = BlackColor;        // map 1 in mask to 0x000000 (black) in destination
00989     ib.lBackColor = WhiteColor;        // map 0 in mask to 0xFFFFFF (white) in destination
00990     ib.usMixMode  = FM_OVERPAINT;
00991     ib.usBackMixMode = BM_OVERPAINT;
00992     GFX (::GpiSetAttrs (MemPS, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR | IBB_MIX_MODE | IBB_BACK_MIX_MODE, 0, (PBUNDLE)&ib), FALSE);
00993 
00994     // Apply mask to target, clear pels we will fill in from the image
00995     MONOBITMAPINFO MaskBitmapInfo (mInfo);
00996     GFX (::GpiDrawBits (MemPS, mAlphaBits, MaskBitmapInfo, 4, aptl, ROP_SRCAND,
00997                         BBO_IGNORE), GPI_ERROR);
00998 
00999     // Now combine image with target
01000     GFX (::GpiDrawBits (MemPS, mImageBits, mInfo, 4, aptl, ROP_SRCPAINT, 
01001                         BBO_IGNORE), GPI_ERROR);
01002   } else {
01003     // alpha depth of 8 not used (yet?)
01004     NS_ASSERTION( mAlphaDepth != 8, "Alpha depth of 8 not implemented in DrawToImage" );
01005 
01006     // no transparency, just blit it
01007     GFX (::GpiDrawBits (MemPS, mImageBits, mInfo, 4, aptl, ROP_SRCCOPY,
01008                         BBO_IGNORE), GPI_ERROR);
01009   }
01010 
01011   rc = destImg->UpdateImageBits (MemPS);
01012 
01013   GFX (::GpiSetBitmap (MemPS, NULLHANDLE), HBM_ERROR);
01014   GFX (::GpiDeleteBitmap (hTmpBitmap), FALSE);
01015   GFX (::GpiDestroyPS (MemPS), FALSE);
01016   GFX (::DevCloseDC (MemDC), DEV_ERROR);
01017 
01018   return rc;
01019 }