Back to index

lightning-sunbird  0.9+nobinonly
nsGIFDecoder2.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Chris Saari <saari@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "prmem.h"
00041 
00042 #include "nsGIFDecoder2.h"
00043 #include "nsIInputStream.h"
00044 #include "nsIComponentManager.h"
00045 #include "nsRecyclingAllocator.h"
00046 
00047 #include "imgIContainerObserver.h"
00048 
00049 #include "imgILoad.h"
00050 
00051 
00052 /*******************************************************************************
00053  * Gif decoder allocator
00054  *
00055  * For every image that gets loaded, we allocate a 'gif_struct'
00056  * This allocator tries to keep one set of these around
00057  * and reuses them; automatically fails over to use calloc/free when all
00058  * buckets are full.
00059  */
00060 const int kGifAllocatorNBucket = 3;
00061 static nsRecyclingAllocator *gGifAllocator = nsnull;
00062 
00063 void nsGifShutdown()
00064 {
00065   // Release cached buffers from zlib allocator
00066   delete gGifAllocator;
00067   gGifAllocator = nsnull;
00068 }
00069 
00070 
00072 // GIF Decoder Implementation
00073 // This is an adaptor between GIF2 and imgIDecoder
00074 
00075 NS_IMPL_ISUPPORTS1(nsGIFDecoder2, imgIDecoder)
00076 
00077 nsGIFDecoder2::nsGIFDecoder2()
00078   : mCurrentRow(-1)
00079   , mLastFlushedRow(-1)
00080   , mGIFStruct(nsnull)
00081   , mAlphaLine(nsnull)
00082   , mRGBLine(nsnull)
00083   , mAlphaLineMaxSize(0)
00084   , mRGBLineMaxSize(0)
00085   , mBackgroundRGBIndex(0)
00086   , mCurrentPass(0)
00087   , mLastFlushedPass(0)
00088   , mGIFOpen(PR_FALSE)
00089 {
00090 }
00091 
00092 nsGIFDecoder2::~nsGIFDecoder2(void)
00093 {
00094   Close();
00095 }
00096 
00097 //******************************************************************************
00099 //******************************************************************************
00100 
00101 //******************************************************************************
00102 /* void init (in imgILoad aLoad); */
00103 NS_IMETHODIMP nsGIFDecoder2::Init(imgILoad *aLoad)
00104 {
00105   mObserver = do_QueryInterface(aLoad);
00106 
00107   mImageContainer = do_CreateInstance("@mozilla.org/image/container;1?type=image/gif");
00108   aLoad->SetImage(mImageContainer);
00109   
00110   if (!gGifAllocator) {
00111     gGifAllocator = new nsRecyclingAllocator(kGifAllocatorNBucket,
00112                                              NS_DEFAULT_RECYCLE_TIMEOUT, "gif");
00113     if (!gGifAllocator)
00114       return NS_ERROR_FAILURE;
00115   }
00116   mGIFStruct = (gif_struct *)gGifAllocator->Malloc(sizeof(gif_struct));
00117   NS_ASSERTION(mGIFStruct, "gif_create failed");
00118   if (!mGIFStruct)
00119     return NS_ERROR_FAILURE;
00120 
00121   // Call GIF decoder init routine
00122   GIFInit(mGIFStruct, this);
00123 
00124   return NS_OK;
00125 }
00126 
00127 
00128 //******************************************************************************
00130 //******************************************************************************
00131 
00132 //******************************************************************************
00133 /* void close (); */
00134 NS_IMETHODIMP nsGIFDecoder2::Close()
00135 {
00136   if (mGIFStruct) {
00137     nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, mGIFStruct->clientptr);
00138     if (decoder->mImageFrame)
00139       EndImageFrame(mGIFStruct->clientptr, mGIFStruct->images_decoded + 1, 
00140                     mGIFStruct->delay_time);
00141     if (decoder->mGIFOpen)
00142       EndGIF(mGIFStruct->clientptr, mGIFStruct->loop_count);
00143 
00144     gif_destroy(mGIFStruct);
00145     if (gGifAllocator)
00146       gGifAllocator->Free(mGIFStruct);
00147     mGIFStruct = nsnull;
00148   }
00149   PR_FREEIF(mAlphaLine);
00150   PR_FREEIF(mRGBLine);
00151 
00152   return NS_OK;
00153 }
00154 
00155 //******************************************************************************
00156 /* void flush (); */
00157 NS_IMETHODIMP nsGIFDecoder2::Flush()
00158 {
00159     return NS_ERROR_NOT_IMPLEMENTED;
00160 }
00161 
00162 //******************************************************************************
00163 /* static callback from nsIInputStream::ReadSegments */
00164 static NS_METHOD ReadDataOut(nsIInputStream* in,
00165                              void* closure,
00166                              const char* fromRawSegment,
00167                              PRUint32 toOffset,
00168                              PRUint32 count,
00169                              PRUint32 *writeCount)
00170 {
00171   nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, closure);
00172   nsresult rv = decoder->ProcessData((unsigned char*)fromRawSegment, count, writeCount);
00173   if (NS_FAILED(rv)) {
00174     *writeCount = 0;
00175     return rv;
00176   }
00177 
00178   return NS_OK;
00179 }
00180 
00181 // Push any new rows according to mCurrentPass/mLastFlushedPass and
00182 // mCurrentRow/mLastFlushedRow.  Note: caller is responsible for
00183 // updating mlastFlushed{Row,Pass}.
00184 NS_METHOD
00185 nsGIFDecoder2::FlushImageData()
00186 {
00187   PRInt32 imgWidth;
00188   mImageContainer->GetWidth(&imgWidth);
00189   nsIntRect frameRect;
00190   mImageFrame->GetRect(frameRect);
00191   
00192   switch (mCurrentPass - mLastFlushedPass) {
00193     case 0: {  // same pass
00194       PRInt32 remainingRows = mCurrentRow - mLastFlushedRow;
00195       if (remainingRows) {
00196         nsIntRect r(0, frameRect.y + mLastFlushedRow + 1,
00197                     imgWidth, remainingRows);
00198         mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
00199       }    
00200     }
00201     break;
00202   
00203     case 1: {  // one pass on - need to handle bottom & top rects
00204       nsIntRect r(0, frameRect.y, imgWidth, mCurrentRow + 1);
00205       mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
00206       nsIntRect r2(0, frameRect.y + mLastFlushedRow + 1,
00207                    imgWidth, frameRect.height - mLastFlushedRow - 1);
00208       mObserver->OnDataAvailable(nsnull, mImageFrame, &r2);
00209     }
00210     break;
00211 
00212     default: {  // more than one pass on - push the whole frame
00213       nsIntRect r(0, frameRect.y, imgWidth, frameRect.height);
00214       mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
00215     }
00216   }
00217 
00218   return NS_OK;
00219 }
00220 
00221 //******************************************************************************
00222 nsresult nsGIFDecoder2::ProcessData(unsigned char *data, PRUint32 count, PRUint32 *_retval)
00223 {
00224   // Push the data to the GIF decoder
00225   
00226   // First we ask if the gif decoder is ready for more data, and if so, push it.
00227   // In the new decoder, we should always be able to process more data since
00228   // we don't wait to decode each frame in an animation now.
00229   if (gif_write_ready(mGIFStruct)) {
00230     PRStatus result = gif_write(mGIFStruct, data, count);
00231     if (result != PR_SUCCESS)
00232       return NS_ERROR_FAILURE;
00233   }
00234 
00235   if (mImageFrame && mObserver) {
00236     FlushImageData();
00237     mLastFlushedRow = mCurrentRow;
00238     mLastFlushedPass = mCurrentPass;
00239   }
00240 
00241   *_retval = count;
00242 
00243   return NS_OK;
00244 }
00245 
00246 //******************************************************************************
00247 /* unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count); */
00248 NS_IMETHODIMP nsGIFDecoder2::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
00249 {
00250   nsresult rv = inStr->ReadSegments(ReadDataOut, this,  count, _retval);
00251 
00252   /* necko doesn't propagate the errors from ReadDataOut - take matters
00253      into our own hands.  if we have at least one frame of an animated
00254      gif, then return success so we keep displaying as much as possible. */
00255   if (NS_SUCCEEDED(rv) && mGIFStruct && mGIFStruct->state == gif_error) {
00256     PRUint32 numFrames = 0;
00257     if (mImageContainer)
00258       mImageContainer->GetNumFrames(&numFrames);
00259     if (numFrames <= 0)
00260       return NS_ERROR_FAILURE;
00261   }
00262 
00263   return rv;
00264 }
00265 
00266 
00267 //******************************************************************************
00268 // GIF decoder callback methods. Part of pulic API for GIF2
00269 //******************************************************************************
00270 
00271 //******************************************************************************
00272 int nsGIFDecoder2::BeginGIF(
00273   void*    aClientData,
00274   PRUint32 aLogicalScreenWidth, 
00275   PRUint32 aLogicalScreenHeight,
00276   PRUint8  aBackgroundRGBIndex)
00277 {
00278   // If we have passed an illogical screen size, bail and hope that we'll get
00279   // set later by the first frame's local image header.
00280   if(aLogicalScreenWidth == 0 || aLogicalScreenHeight == 0)
00281     return 0;
00282     
00283   // copy GIF info into imagelib structs
00284   nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
00285 
00286   decoder->mBackgroundRGBIndex = aBackgroundRGBIndex;
00287 
00288   if (decoder->mObserver)
00289     decoder->mObserver->OnStartDecode(nsnull);
00290 
00291   decoder->mImageContainer->Init(aLogicalScreenWidth, aLogicalScreenHeight, decoder->mObserver);
00292 
00293   if (decoder->mObserver)
00294     decoder->mObserver->OnStartContainer(nsnull, decoder->mImageContainer);
00295 
00296   decoder->mGIFOpen = PR_TRUE;
00297   return 0;
00298 }
00299 
00300 //******************************************************************************
00301 int nsGIFDecoder2::EndGIF(
00302     void*    aClientData,
00303     int      aAnimationLoopCount)
00304 {
00305   nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
00306 
00307   if (!decoder->mGIFOpen)
00308     return 0;
00309 
00310   if (decoder->mObserver) {
00311     decoder->mObserver->OnStopContainer(nsnull, decoder->mImageContainer);
00312     decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
00313   }
00314   
00315   decoder->mImageContainer->SetLoopCount(aAnimationLoopCount);
00316   decoder->mImageContainer->DecodingComplete();
00317 
00318   decoder->mGIFOpen = PR_FALSE;
00319   return 0;
00320 }
00321 
00322 //******************************************************************************
00323 int nsGIFDecoder2::BeginImageFrame(
00324   void*    aClientData,
00325   PRUint32 aFrameNumber,   /* Frame number, 1-n */
00326   PRUint32 aFrameXOffset,  /* X offset in logical screen */
00327   PRUint32 aFrameYOffset,  /* Y offset in logical screen */
00328   PRUint32 aFrameWidth,    
00329   PRUint32 aFrameHeight)
00330 {
00331   nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
00332   
00333   decoder->mImageFrame = nsnull; // clear out our current frame reference
00334   decoder->mGIFStruct->x_offset = aFrameXOffset;
00335   decoder->mGIFStruct->y_offset = aFrameYOffset;
00336   decoder->mGIFStruct->width = aFrameWidth;
00337   decoder->mGIFStruct->height = aFrameHeight;
00338 
00339   if (aFrameNumber == 1) {
00340     // Send a onetime OnDataAvailable (Display Refresh) for the first frame
00341     // if it has a y-axis offset.  Otherwise, the area may never be refreshed
00342     // and the placeholder will remain on the screen. (Bug 37589)
00343     PRInt32 imgWidth;
00344     decoder->mImageContainer->GetWidth(&imgWidth);
00345     if (aFrameYOffset > 0) {
00346       nsIntRect r(0, 0, imgWidth, aFrameYOffset);
00347       decoder->mObserver->OnDataAvailable(nsnull, decoder->mImageFrame, &r);
00348     }
00349   }
00350 
00351   return 0;
00352 }
00353 
00354 //******************************************************************************
00355 int nsGIFDecoder2::EndImageFrame(
00356   void*    aClientData, 
00357   PRUint32 aFrameNumber,
00358   PRUint32 aDelayTimeout)  /* Time this frame should be displayed before the next frame 
00359                               we can't have this in the image frame init because it doesn't
00360                               show up in the GIF frame header, it shows up in a sub control
00361                               block.*/
00362 {
00363   nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
00364   
00365   // If mImageFrame hasn't been initialized, call HaveDecodedRow to init it
00366   // One reason why it may not be initialized is because the frame
00367   // is out of the bounds of the image.
00368   if (!decoder->mImageFrame) {
00369     HaveDecodedRow(aClientData,nsnull,0,0,0);
00370   } else {
00371     // We actually have the timeout information before we get the lzw encoded 
00372     // image data, at least according to the spec, but we delay in setting the 
00373     // timeout for the image until here to help ensure that we have the whole 
00374     // image frame decoded before we go off and try to display another frame.
00375     decoder->mImageFrame->SetTimeout(aDelayTimeout);
00376   }
00377   decoder->mImageContainer->EndFrameDecode(aFrameNumber, aDelayTimeout);
00378 
00379   if (decoder->mObserver && decoder->mImageFrame) {
00380     decoder->FlushImageData();
00381 
00382     if (aFrameNumber == 1) {
00383       // If the first frame is smaller in height than the entire image, send a
00384       // OnDataAvailable (Display Refresh) for the area it does not have data for.
00385       // This will clear the remaining bits of the placeholder. (Bug 37589)
00386       PRInt32 imgHeight;
00387       PRInt32 realFrameHeight = decoder->mGIFStruct->height + decoder->mGIFStruct->y_offset;
00388 
00389       decoder->mImageContainer->GetHeight(&imgHeight);
00390       if (imgHeight > realFrameHeight) {
00391         PRInt32 imgWidth;
00392         decoder->mImageContainer->GetWidth(&imgWidth);
00393 
00394         nsIntRect r(0, realFrameHeight, imgWidth, imgHeight - realFrameHeight);
00395         decoder->mObserver->OnDataAvailable(nsnull, decoder->mImageFrame, &r);
00396       }
00397     }
00398 
00399     decoder->mCurrentRow = decoder->mLastFlushedRow = -1;
00400     decoder->mCurrentPass = decoder->mLastFlushedPass = 0;
00401 
00402     decoder->mObserver->OnStopFrame(nsnull, decoder->mImageFrame);
00403   }
00404 
00405   decoder->mImageFrame = nsnull;
00406   decoder->mGIFStruct->is_transparent = PR_FALSE;
00407   return 0;
00408 }
00409   
00410 //******************************************************************************
00411 // GIF decoder callback notification that it has decoded a row
00412 int nsGIFDecoder2::HaveDecodedRow(
00413   void* aClientData,
00414   PRUint8* aRowBufPtr,   // Pointer to single scanline temporary buffer
00415   int aRowNumber,        // Row number?
00416   int aDuplicateCount,   // Number of times to duplicate the row?
00417   int aInterlacePass)    // interlace pass (1-4)
00418 {
00419   nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
00420   PRUint32 bpr, abpr;
00421   // We have to delay allocation of the image frame until now because
00422   // we won't have control block info (transparency) until now. The conrol
00423   // block of a GIF stream shows up after the image header since transparency
00424   // is added in GIF89a and control blocks are how the extensions are done.
00425   // How annoying.
00426   if(! decoder->mImageFrame) {
00427     gfx_format format = gfxIFormats::RGB;
00428     if (decoder->mGIFStruct->is_transparent) {
00429       format = gfxIFormats::RGB_A1;
00430     }
00431 
00432 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
00433     // XXX this works...
00434     format += 1; // RGB to BGR
00435 #endif
00436 
00437     // initalize the frame and append it to the container
00438     decoder->mImageFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
00439     if (!decoder->mImageFrame || NS_FAILED(decoder->mImageFrame->Init(
00440           decoder->mGIFStruct->x_offset, decoder->mGIFStruct->y_offset, 
00441           decoder->mGIFStruct->width, decoder->mGIFStruct->height, format, 24))) {
00442       decoder->mImageFrame = 0;
00443       return 0;
00444     }
00445 
00446     decoder->mImageFrame->SetFrameDisposalMethod(decoder->mGIFStruct->disposal_method);
00447     decoder->mImageContainer->AppendFrame(decoder->mImageFrame);
00448 
00449     if (decoder->mObserver)
00450       decoder->mObserver->OnStartFrame(nsnull, decoder->mImageFrame);
00451 
00452     decoder->mImageFrame->GetImageBytesPerRow(&bpr);
00453     decoder->mImageFrame->GetAlphaBytesPerRow(&abpr);
00454 
00455     if (bpr > decoder->mRGBLineMaxSize) {
00456       decoder->mRGBLine = (PRUint8 *)PR_REALLOC(decoder->mRGBLine, bpr);
00457       decoder->mRGBLineMaxSize = bpr;
00458     }
00459 
00460     if (format == gfxIFormats::RGB_A1 || format == gfxIFormats::BGR_A1) {
00461       if (abpr > decoder->mAlphaLineMaxSize) {
00462         decoder->mAlphaLine = (PRUint8 *)PR_REALLOC(decoder->mAlphaLine, abpr);
00463         decoder->mAlphaLineMaxSize = abpr;
00464       }
00465     }
00466   } else {
00467     decoder->mImageFrame->GetImageBytesPerRow(&bpr);
00468     decoder->mImageFrame->GetAlphaBytesPerRow(&abpr);
00469   }
00470   
00471   if (aRowBufPtr) {
00472     PRInt32 width;
00473     decoder->mImageFrame->GetWidth(&width);
00474 
00475     gfx_format format;
00476     decoder->mImageFrame->GetFormat(&format);
00477 
00478     // XXX map the data into colors
00479     int cmapsize;
00480     PRUint8* cmap;
00481     cmapsize = decoder->mGIFStruct->global_colormap_size;
00482     cmap = decoder->mGIFStruct->global_colormap;
00483 
00484     if(decoder->mGIFStruct->global_colormap &&
00485        decoder->mGIFStruct->screen_bgcolor < cmapsize) {
00486       gfx_color bgColor = 0;
00487       PRUint32 bgIndex = decoder->mGIFStruct->screen_bgcolor * 3;
00488       bgColor |= cmap[bgIndex];
00489       bgColor |= cmap[bgIndex + 1] << 8;
00490       bgColor |= cmap[bgIndex + 2] << 16;
00491       decoder->mImageFrame->SetBackgroundColor(bgColor);
00492     }
00493     if (decoder->mGIFStruct->is_local_colormap_defined) {
00494       cmapsize = decoder->mGIFStruct->local_colormap_size;
00495       cmap = decoder->mGIFStruct->local_colormap;
00496     }
00497 
00498     if (!cmap) { // cmap could have null value if the global color table flag is 0
00499       for (int i = 0; i < aDuplicateCount; ++i) {
00500         if (format == gfxIFormats::RGB_A1 ||
00501             format == gfxIFormats::BGR_A1) {
00502           decoder->mImageFrame->SetAlphaData(nsnull,
00503                                              abpr, (aRowNumber+i)*abpr);
00504         }
00505         decoder->mImageFrame->SetImageData(nsnull,
00506                                            bpr, (aRowNumber+i)*bpr);
00507       }
00508     } else {
00509       PRUint8* rgbRowIndex = decoder->mRGBLine;
00510       PRUint8* rowBufIndex = aRowBufPtr;
00511       
00512       switch (format) {
00513         case gfxIFormats::RGB:
00514         case gfxIFormats::BGR:
00515         {
00516           while (rowBufIndex != decoder->mGIFStruct->rowend) {
00517 #if defined(XP_MAC) || defined(XP_MACOSX)
00518             *rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
00519 #endif
00520             if (*rowBufIndex < cmapsize) {
00521               PRUint32 colorIndex = *rowBufIndex * 3;
00522 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
00523               *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
00524               *rgbRowIndex++ = cmap[colorIndex + 1]; // green
00525               *rgbRowIndex++ = cmap[colorIndex];     // red
00526 #else
00527               *rgbRowIndex++ = cmap[colorIndex];     // red
00528               *rgbRowIndex++ = cmap[colorIndex + 1]; // green
00529               *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
00530 #endif
00531             } else {
00532               *rgbRowIndex++ = 0;                    // red
00533               *rgbRowIndex++ = 0;                    // green
00534               *rgbRowIndex++ = 0;                    // blue
00535             }
00536             ++rowBufIndex;
00537           }  
00538           for (int i=0; i<aDuplicateCount; i++) {
00539             decoder->mImageFrame->SetImageData(decoder->mRGBLine,
00540                                                bpr, (aRowNumber+i)*bpr);
00541           }
00542           break;
00543         }
00544         case gfxIFormats::RGB_A1:
00545         case gfxIFormats::BGR_A1:
00546         {
00547           memset(decoder->mRGBLine, 0, bpr);
00548           memset(decoder->mAlphaLine, 0, abpr);
00549           for (PRUint32 x = 0; x < (PRUint32)width; ++x) {
00550             if (*rowBufIndex != decoder->mGIFStruct->tpixel) {
00551 #if defined(XP_MAC) || defined(XP_MACOSX)
00552               *rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
00553 #endif
00554               if (*rowBufIndex < cmapsize) {
00555                 PRUint32 colorIndex = *rowBufIndex * 3;
00556 #if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
00557                 *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
00558                 *rgbRowIndex++ = cmap[colorIndex + 1]; // green
00559                 *rgbRowIndex++ = cmap[colorIndex];     // red
00560 #else
00561                 *rgbRowIndex++ = cmap[colorIndex];     // red
00562                 *rgbRowIndex++ = cmap[colorIndex + 1]; // green
00563                 *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
00564 #endif
00565               } else {
00566                 *rgbRowIndex++ = 0;                    // red
00567                 *rgbRowIndex++ = 0;                    // green
00568                 *rgbRowIndex++ = 0;                    // blue
00569               }
00570               decoder->mAlphaLine[x>>3] |= 1<<(7-x&0x7);
00571             } else {
00572 #if defined(XP_MAC) || defined(XP_MACOSX)
00573               rgbRowIndex+=4;
00574 #else
00575               rgbRowIndex+=3;
00576 #endif
00577             }
00578             ++rowBufIndex;
00579           }
00580           for (int i=0; i<aDuplicateCount; i++) {
00581             decoder->mImageFrame->SetAlphaData(decoder->mAlphaLine,
00582                                                abpr, (aRowNumber+i)*abpr);
00583             decoder->mImageFrame->SetImageData(decoder->mRGBLine,
00584                                                bpr, (aRowNumber+i)*bpr);
00585           }
00586           break;
00587         }
00588       }
00589     }
00590 
00591     decoder->mCurrentRow = aRowNumber + aDuplicateCount - 1;
00592     decoder->mCurrentPass = aInterlacePass;
00593     if (aInterlacePass == 1)
00594       decoder->mLastFlushedPass = aInterlacePass;   // interlaced starts at 1
00595   }
00596 
00597   return 0;
00598 }