Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Static Public Member Functions | Private Attributes
nsGIFDecoder2 Class Reference

#include <nsGIFDecoder2.h>

Inheritance diagram for nsGIFDecoder2:
Inheritance graph
[legend]
Collaboration diagram for nsGIFDecoder2:
Collaboration graph
[legend]

List of all members.

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER 
nsGIFDecoder2 ()
 ~nsGIFDecoder2 ()
nsresult ProcessData (unsigned char *data, PRUint32 count, PRUint32 *_retval)
NS_METHOD FlushImageData ()
void init (in imgILoad aLoad)
 Initalize an image decoder.
void close ()
 Closes the stream.
void flush ()
 Flushes the stream.
unsigned long writeFrom (in nsIInputStream inStr, in unsigned long count)
 Writes data into the stream from an input stream.

Static Public Member Functions

static int BeginGIF (void *aClientData, PRUint32 aLogicalScreenWidth, PRUint32 aLogicalScreenHeight, PRUint8 aBackgroundRGBIndex)
static int EndGIF (void *aClientData, int aAnimationLoopCount)
static int BeginImageFrame (void *aClientData, PRUint32 aFrameNumber, PRUint32 aFrameXOffset, PRUint32 aFrameYOffset, PRUint32 aFrameWidth, PRUint32 aFrameHeight)
static int EndImageFrame (void *aClientData, PRUint32 aFrameNumber, PRUint32 aDelayTimeout)
static int HaveDecodedRow (void *aClientData, PRUint8 *aRowBufPtr, int aRow, int aDuplicateCount, int aInterlacePass)

Private Attributes

nsCOMPtr< imgIContainermImageContainer
nsCOMPtr< gfxIImageFramemImageFrame
nsCOMPtr< imgIDecoderObservermObserver
PRInt32 mCurrentRow
PRInt32 mLastFlushedRow
gif_structmGIFStruct
PRUint8mAlphaLine
PRUint8mRGBLine
PRUint32 mRGBLineMaxSize
PRUint32 mAlphaLineMaxSize
PRUint8 mBackgroundRGBIndex
PRUint8 mCurrentPass
PRUint8 mLastFlushedPass
PRPackedBool mGIFOpen

Detailed Description

Definition at line 62 of file nsGIFDecoder2.h.


Constructor & Destructor Documentation

Definition at line 92 of file nsGIFDecoder2.cpp.

{
  Close();
}

Member Function Documentation

int nsGIFDecoder2::BeginGIF ( void aClientData,
PRUint32  aLogicalScreenWidth,
PRUint32  aLogicalScreenHeight,
PRUint8  aBackgroundRGBIndex 
) [static]

Definition at line 272 of file nsGIFDecoder2.cpp.

{
  // If we have passed an illogical screen size, bail and hope that we'll get
  // set later by the first frame's local image header.
  if(aLogicalScreenWidth == 0 || aLogicalScreenHeight == 0)
    return 0;
    
  // copy GIF info into imagelib structs
  nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);

  decoder->mBackgroundRGBIndex = aBackgroundRGBIndex;

  if (decoder->mObserver)
    decoder->mObserver->OnStartDecode(nsnull);

  decoder->mImageContainer->Init(aLogicalScreenWidth, aLogicalScreenHeight, decoder->mObserver);

  if (decoder->mObserver)
    decoder->mObserver->OnStartContainer(nsnull, decoder->mImageContainer);

  decoder->mGIFOpen = PR_TRUE;
  return 0;
}

Here is the caller graph for this function:

int nsGIFDecoder2::BeginImageFrame ( void aClientData,
PRUint32  aFrameNumber,
PRUint32  aFrameXOffset,
PRUint32  aFrameYOffset,
PRUint32  aFrameWidth,
PRUint32  aFrameHeight 
) [static]

Definition at line 323 of file nsGIFDecoder2.cpp.

{
  nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
  
  decoder->mImageFrame = nsnull; // clear out our current frame reference
  decoder->mGIFStruct->x_offset = aFrameXOffset;
  decoder->mGIFStruct->y_offset = aFrameYOffset;
  decoder->mGIFStruct->width = aFrameWidth;
  decoder->mGIFStruct->height = aFrameHeight;

  if (aFrameNumber == 1) {
    // Send a onetime OnDataAvailable (Display Refresh) for the first frame
    // if it has a y-axis offset.  Otherwise, the area may never be refreshed
    // and the placeholder will remain on the screen. (Bug 37589)
    PRInt32 imgWidth;
    decoder->mImageContainer->GetWidth(&imgWidth);
    if (aFrameYOffset > 0) {
      nsIntRect r(0, 0, imgWidth, aFrameYOffset);
      decoder->mObserver->OnDataAvailable(nsnull, decoder->mImageFrame, &r);
    }
  }

  return 0;
}

Here is the caller graph for this function:

void imgIDecoder::close ( ) [inherited]

Closes the stream.

int nsGIFDecoder2::EndGIF ( void aClientData,
int  aAnimationLoopCount 
) [static]

Definition at line 301 of file nsGIFDecoder2.cpp.

{
  nsGIFDecoder2 *decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);

  if (!decoder->mGIFOpen)
    return 0;

  if (decoder->mObserver) {
    decoder->mObserver->OnStopContainer(nsnull, decoder->mImageContainer);
    decoder->mObserver->OnStopDecode(nsnull, NS_OK, nsnull);
  }
  
  decoder->mImageContainer->SetLoopCount(aAnimationLoopCount);
  decoder->mImageContainer->DecodingComplete();

  decoder->mGIFOpen = PR_FALSE;
  return 0;
}

Here is the caller graph for this function:

int nsGIFDecoder2::EndImageFrame ( void aClientData,
PRUint32  aFrameNumber,
PRUint32  aDelayTimeout 
) [static]

Definition at line 355 of file nsGIFDecoder2.cpp.

{
  nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
  
  // If mImageFrame hasn't been initialized, call HaveDecodedRow to init it
  // One reason why it may not be initialized is because the frame
  // is out of the bounds of the image.
  if (!decoder->mImageFrame) {
    HaveDecodedRow(aClientData,nsnull,0,0,0);
  } else {
    // We actually have the timeout information before we get the lzw encoded 
    // image data, at least according to the spec, but we delay in setting the 
    // timeout for the image until here to help ensure that we have the whole 
    // image frame decoded before we go off and try to display another frame.
    decoder->mImageFrame->SetTimeout(aDelayTimeout);
  }
  decoder->mImageContainer->EndFrameDecode(aFrameNumber, aDelayTimeout);

  if (decoder->mObserver && decoder->mImageFrame) {
    decoder->FlushImageData();

    if (aFrameNumber == 1) {
      // If the first frame is smaller in height than the entire image, send a
      // OnDataAvailable (Display Refresh) for the area it does not have data for.
      // This will clear the remaining bits of the placeholder. (Bug 37589)
      PRInt32 imgHeight;
      PRInt32 realFrameHeight = decoder->mGIFStruct->height + decoder->mGIFStruct->y_offset;

      decoder->mImageContainer->GetHeight(&imgHeight);
      if (imgHeight > realFrameHeight) {
        PRInt32 imgWidth;
        decoder->mImageContainer->GetWidth(&imgWidth);

        nsIntRect r(0, realFrameHeight, imgWidth, imgHeight - realFrameHeight);
        decoder->mObserver->OnDataAvailable(nsnull, decoder->mImageFrame, &r);
      }
    }

    decoder->mCurrentRow = decoder->mLastFlushedRow = -1;
    decoder->mCurrentPass = decoder->mLastFlushedPass = 0;

    decoder->mObserver->OnStopFrame(nsnull, decoder->mImageFrame);
  }

  decoder->mImageFrame = nsnull;
  decoder->mGIFStruct->is_transparent = PR_FALSE;
  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void imgIDecoder::flush ( ) [inherited]

Flushes the stream.

Definition at line 185 of file nsGIFDecoder2.cpp.

{
  PRInt32 imgWidth;
  mImageContainer->GetWidth(&imgWidth);
  nsIntRect frameRect;
  mImageFrame->GetRect(frameRect);
  
  switch (mCurrentPass - mLastFlushedPass) {
    case 0: {  // same pass
      PRInt32 remainingRows = mCurrentRow - mLastFlushedRow;
      if (remainingRows) {
        nsIntRect r(0, frameRect.y + mLastFlushedRow + 1,
                    imgWidth, remainingRows);
        mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
      }    
    }
    break;
  
    case 1: {  // one pass on - need to handle bottom & top rects
      nsIntRect r(0, frameRect.y, imgWidth, mCurrentRow + 1);
      mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
      nsIntRect r2(0, frameRect.y + mLastFlushedRow + 1,
                   imgWidth, frameRect.height - mLastFlushedRow - 1);
      mObserver->OnDataAvailable(nsnull, mImageFrame, &r2);
    }
    break;

    default: {  // more than one pass on - push the whole frame
      nsIntRect r(0, frameRect.y, imgWidth, frameRect.height);
      mObserver->OnDataAvailable(nsnull, mImageFrame, &r);
    }
  }

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int nsGIFDecoder2::HaveDecodedRow ( void aClientData,
PRUint8 aRowBufPtr,
int  aRow,
int  aDuplicateCount,
int  aInterlacePass 
) [static]

Definition at line 412 of file nsGIFDecoder2.cpp.

{
  nsGIFDecoder2* decoder = NS_STATIC_CAST(nsGIFDecoder2*, aClientData);
  PRUint32 bpr, abpr;
  // We have to delay allocation of the image frame until now because
  // we won't have control block info (transparency) until now. The conrol
  // block of a GIF stream shows up after the image header since transparency
  // is added in GIF89a and control blocks are how the extensions are done.
  // How annoying.
  if(! decoder->mImageFrame) {
    gfx_format format = gfxIFormats::RGB;
    if (decoder->mGIFStruct->is_transparent) {
      format = gfxIFormats::RGB_A1;
    }

#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
    // XXX this works...
    format += 1; // RGB to BGR
#endif

    // initalize the frame and append it to the container
    decoder->mImageFrame = do_CreateInstance("@mozilla.org/gfx/image/frame;2");
    if (!decoder->mImageFrame || NS_FAILED(decoder->mImageFrame->Init(
          decoder->mGIFStruct->x_offset, decoder->mGIFStruct->y_offset, 
          decoder->mGIFStruct->width, decoder->mGIFStruct->height, format, 24))) {
      decoder->mImageFrame = 0;
      return 0;
    }

    decoder->mImageFrame->SetFrameDisposalMethod(decoder->mGIFStruct->disposal_method);
    decoder->mImageContainer->AppendFrame(decoder->mImageFrame);

    if (decoder->mObserver)
      decoder->mObserver->OnStartFrame(nsnull, decoder->mImageFrame);

    decoder->mImageFrame->GetImageBytesPerRow(&bpr);
    decoder->mImageFrame->GetAlphaBytesPerRow(&abpr);

    if (bpr > decoder->mRGBLineMaxSize) {
      decoder->mRGBLine = (PRUint8 *)PR_REALLOC(decoder->mRGBLine, bpr);
      decoder->mRGBLineMaxSize = bpr;
    }

    if (format == gfxIFormats::RGB_A1 || format == gfxIFormats::BGR_A1) {
      if (abpr > decoder->mAlphaLineMaxSize) {
        decoder->mAlphaLine = (PRUint8 *)PR_REALLOC(decoder->mAlphaLine, abpr);
        decoder->mAlphaLineMaxSize = abpr;
      }
    }
  } else {
    decoder->mImageFrame->GetImageBytesPerRow(&bpr);
    decoder->mImageFrame->GetAlphaBytesPerRow(&abpr);
  }
  
  if (aRowBufPtr) {
    PRInt32 width;
    decoder->mImageFrame->GetWidth(&width);

    gfx_format format;
    decoder->mImageFrame->GetFormat(&format);

    // XXX map the data into colors
    int cmapsize;
    PRUint8* cmap;
    cmapsize = decoder->mGIFStruct->global_colormap_size;
    cmap = decoder->mGIFStruct->global_colormap;

    if(decoder->mGIFStruct->global_colormap &&
       decoder->mGIFStruct->screen_bgcolor < cmapsize) {
      gfx_color bgColor = 0;
      PRUint32 bgIndex = decoder->mGIFStruct->screen_bgcolor * 3;
      bgColor |= cmap[bgIndex];
      bgColor |= cmap[bgIndex + 1] << 8;
      bgColor |= cmap[bgIndex + 2] << 16;
      decoder->mImageFrame->SetBackgroundColor(bgColor);
    }
    if (decoder->mGIFStruct->is_local_colormap_defined) {
      cmapsize = decoder->mGIFStruct->local_colormap_size;
      cmap = decoder->mGIFStruct->local_colormap;
    }

    if (!cmap) { // cmap could have null value if the global color table flag is 0
      for (int i = 0; i < aDuplicateCount; ++i) {
        if (format == gfxIFormats::RGB_A1 ||
            format == gfxIFormats::BGR_A1) {
          decoder->mImageFrame->SetAlphaData(nsnull,
                                             abpr, (aRowNumber+i)*abpr);
        }
        decoder->mImageFrame->SetImageData(nsnull,
                                           bpr, (aRowNumber+i)*bpr);
      }
    } else {
      PRUint8* rgbRowIndex = decoder->mRGBLine;
      PRUint8* rowBufIndex = aRowBufPtr;
      
      switch (format) {
        case gfxIFormats::RGB:
        case gfxIFormats::BGR:
        {
          while (rowBufIndex != decoder->mGIFStruct->rowend) {
#if defined(XP_MAC) || defined(XP_MACOSX)
            *rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
#endif
            if (*rowBufIndex < cmapsize) {
              PRUint32 colorIndex = *rowBufIndex * 3;
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
              *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
              *rgbRowIndex++ = cmap[colorIndex + 1]; // green
              *rgbRowIndex++ = cmap[colorIndex];     // red
#else
              *rgbRowIndex++ = cmap[colorIndex];     // red
              *rgbRowIndex++ = cmap[colorIndex + 1]; // green
              *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
#endif
            } else {
              *rgbRowIndex++ = 0;                    // red
              *rgbRowIndex++ = 0;                    // green
              *rgbRowIndex++ = 0;                    // blue
            }
            ++rowBufIndex;
          }  
          for (int i=0; i<aDuplicateCount; i++) {
            decoder->mImageFrame->SetImageData(decoder->mRGBLine,
                                               bpr, (aRowNumber+i)*bpr);
          }
          break;
        }
        case gfxIFormats::RGB_A1:
        case gfxIFormats::BGR_A1:
        {
          memset(decoder->mRGBLine, 0, bpr);
          memset(decoder->mAlphaLine, 0, abpr);
          for (PRUint32 x = 0; x < (PRUint32)width; ++x) {
            if (*rowBufIndex != decoder->mGIFStruct->tpixel) {
#if defined(XP_MAC) || defined(XP_MACOSX)
              *rgbRowIndex++ = 0; // Mac is always 32bits per pixel, this is pad
#endif
              if (*rowBufIndex < cmapsize) {
                PRUint32 colorIndex = *rowBufIndex * 3;
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
                *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
                *rgbRowIndex++ = cmap[colorIndex + 1]; // green
                *rgbRowIndex++ = cmap[colorIndex];     // red
#else
                *rgbRowIndex++ = cmap[colorIndex];     // red
                *rgbRowIndex++ = cmap[colorIndex + 1]; // green
                *rgbRowIndex++ = cmap[colorIndex + 2]; // blue
#endif
              } else {
                *rgbRowIndex++ = 0;                    // red
                *rgbRowIndex++ = 0;                    // green
                *rgbRowIndex++ = 0;                    // blue
              }
              decoder->mAlphaLine[x>>3] |= 1<<(7-x&0x7);
            } else {
#if defined(XP_MAC) || defined(XP_MACOSX)
              rgbRowIndex+=4;
#else
              rgbRowIndex+=3;
#endif
            }
            ++rowBufIndex;
          }
          for (int i=0; i<aDuplicateCount; i++) {
            decoder->mImageFrame->SetAlphaData(decoder->mAlphaLine,
                                               abpr, (aRowNumber+i)*abpr);
            decoder->mImageFrame->SetImageData(decoder->mRGBLine,
                                               bpr, (aRowNumber+i)*bpr);
          }
          break;
        }
      }
    }

    decoder->mCurrentRow = aRowNumber + aDuplicateCount - 1;
    decoder->mCurrentPass = aInterlacePass;
    if (aInterlacePass == 1)
      decoder->mLastFlushedPass = aInterlacePass;   // interlaced starts at 1
  }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void imgIDecoder::init ( in imgILoad  aLoad) [inherited]

Initalize an image decoder.

Parameters:
aRequestthe request that owns the decoder.
Note:
The decode should QI aLoad to an imgIDecoderObserver and should send decoder notifications to the request. The decoder should always pass NULL as the first two parameters to all of the imgIDecoderObserver APIs.
nsresult nsGIFDecoder2::ProcessData ( unsigned char *  data,
PRUint32  count,
PRUint32 _retval 
)

Definition at line 222 of file nsGIFDecoder2.cpp.

{
  // Push the data to the GIF decoder
  
  // First we ask if the gif decoder is ready for more data, and if so, push it.
  // In the new decoder, we should always be able to process more data since
  // we don't wait to decode each frame in an animation now.
  if (gif_write_ready(mGIFStruct)) {
    PRStatus result = gif_write(mGIFStruct, data, count);
    if (result != PR_SUCCESS)
      return NS_ERROR_FAILURE;
  }

  if (mImageFrame && mObserver) {
    FlushImageData();
    mLastFlushedRow = mCurrentRow;
    mLastFlushedPass = mCurrentPass;
  }

  *_retval = count;

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

unsigned long imgIDecoder::writeFrom ( in nsIInputStream  inStr,
in unsigned long  count 
) [inherited]

Writes data into the stream from an input stream.

Implementer's note: This method is defined by this interface in order to allow the output stream to efficiently copy the data from the input stream into its internal buffer (if any). If this method was provide as an external facility, a separate char* buffer would need to be used in order to call the output stream's other Write method.

Parameters:
fromStreamthe stream from which the data is read
countthe maximun number of bytes to write
Returns:
aWriteCount out parameter to hold the number of bytes written. if an error occurs, the writecount is undefined

Member Data Documentation

Definition at line 117 of file nsGIFDecoder2.h.

Definition at line 120 of file nsGIFDecoder2.h.

Definition at line 121 of file nsGIFDecoder2.h.

Definition at line 122 of file nsGIFDecoder2.h.

Definition at line 112 of file nsGIFDecoder2.h.

Definition at line 124 of file nsGIFDecoder2.h.

Definition at line 115 of file nsGIFDecoder2.h.

Definition at line 109 of file nsGIFDecoder2.h.

Definition at line 110 of file nsGIFDecoder2.h.

Definition at line 123 of file nsGIFDecoder2.h.

Definition at line 113 of file nsGIFDecoder2.h.

Definition at line 111 of file nsGIFDecoder2.h.

Definition at line 118 of file nsGIFDecoder2.h.

Definition at line 119 of file nsGIFDecoder2.h.


The documentation for this class was generated from the following files: