Back to index

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

#include <nsICODecoder.h>

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

List of all members.

Public Member Functions

NS_DECL_ISUPPORTS
NS_DECL_IMGIDECODER 
nsICODecoder ()
virtual ~nsICODecoder ()
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.

Private Member Functions

nsresult ProcessData (const char *aBuffer, PRUint32 aCount)
void ProcessDirEntry (IconDirEntry &aTarget)
void ProcessInfoHeader ()
nsresult SetImageData ()
nsresult SetAlphaData ()
PRUint32 CalcAlphaRowSize ()

Static Private Member Functions

static NS_METHOD ReadSegCb (nsIInputStream *aIn, void *aClosure, const char *aFromRawSegment, PRUint32 aToOffset, PRUint32 aCount, PRUint32 *aWriteCount)
 Callback for ReadSegments to avoid copying the data.

Private Attributes

nsCOMPtr< imgIDecoderObservermObserver
nsCOMPtr< imgIContainermImage
nsCOMPtr< gfxIImageFramemFrame
PRUint8 mHaveAlphaData
PRPackedBool mDecodingAndMask
PRUint32 mPos
PRUint16 mNumIcons
PRUint16 mCurrIcon
PRUint32 mImageOffset
char mDirEntryArray [16]
IconDirEntry mDirEntry
char mBIHraw [40]
BMPINFOHEADER mBIH
PRUint32 mNumColors
colorTablemColors
PRUint8mRow
PRUint32 mRowBytes
PRInt32 mCurLine
nsresult mStatus
PRUint8mDecodedBuffer
PRUint8mAlphaBuffer
PRPackedBool mIsCursor

Detailed Description

Definition at line 79 of file nsICODecoder.h.


Constructor & Destructor Documentation

Definition at line 143 of file nsICODecoder.cpp.

Definition at line 156 of file nsICODecoder.cpp.

{
}

Member Function Documentation

Definition at line 135 of file nsICODecoder.cpp.

{
  PRUint32 rowSize = (mDirEntry.mWidth + 7) / 8; // +7 to round up
  if (rowSize % 4)
    rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
  return rowSize;
}

Here is the caller graph for this function:

void imgIDecoder::close ( ) [inherited]

Closes the stream.

void imgIDecoder::flush ( ) [inherited]

Flushes the stream.

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 nsICODecoder::ProcessData ( const char *  aBuffer,
PRUint32  aCount 
) [private]

Definition at line 234 of file nsICODecoder.cpp.

                                                                       {
  if (!aCount) // aCount=0 means EOF
    return NS_OK;

  while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
    if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
      if ((*aBuffer != 1) && (*aBuffer != 2)) {
        return NS_ERROR_FAILURE;
      }
      mIsCursor = (*aBuffer == 2);
    }
    mPos++; aBuffer++; aCount--;
  }

  if (mPos == ICONCOUNTOFFSET && aCount >= 2) {
    mNumIcons = LITTLE_TO_NATIVE16(((PRUint16*)aBuffer)[0]);
    aBuffer += 2;
    mPos += 2;
    aCount -= 2;
  }

  if (mNumIcons == 0)
    return NS_OK; // Nothing to do.

  PRUint16 colorDepth = 0;
  while (mCurrIcon < mNumIcons) {
    if (mPos >= DIRENTRYOFFSET + (mCurrIcon*sizeof(mDirEntryArray)) && 
        mPos < DIRENTRYOFFSET + ((mCurrIcon+1)*sizeof(mDirEntryArray))) {
      PRUint32 toCopy = sizeof(mDirEntryArray) - (mPos - DIRENTRYOFFSET - mCurrIcon*sizeof(mDirEntryArray));
      if (toCopy > aCount)
        toCopy = aCount;
      memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
      mPos += toCopy;
      aCount -= toCopy;
      aBuffer += toCopy;
    }
    if (aCount == 0)
      return NS_OK; // Need more data

    IconDirEntry e;
    if (mPos == 22+mCurrIcon*sizeof(mDirEntryArray)) {
      mCurrIcon++;
      ProcessDirEntry(e);
      if ((e.mWidth == PREFICONSIZE && e.mHeight == PREFICONSIZE && e.mBitCount >= colorDepth)
           || (mCurrIcon == mNumIcons && mImageOffset == 0)) {
        mImageOffset = e.mImageOffset;

        // ensure mImageOffset is >= the size of the direntry headers (bug #245631)
        PRUint32 minImageOffset = DIRENTRYOFFSET + mNumIcons*sizeof(mDirEntryArray);
        if (mImageOffset < minImageOffset)
          return NS_ERROR_FAILURE;

        colorDepth = e.mBitCount;
        memcpy(&mDirEntry, &e, sizeof(IconDirEntry));
      }
    }
  }

  while (aCount && mPos < mImageOffset) { // Skip to our offset
    mPos++; aBuffer++; aCount--;
  }

  if (mCurrIcon == mNumIcons && mPos >= mImageOffset && mPos < mImageOffset + BITMAPINFOSIZE) {
    // We've found the icon.
    PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
    if (toCopy > aCount)
      toCopy = aCount;

    memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
    mPos += toCopy;
    aCount -= toCopy;
    aBuffer += toCopy;
  }

  if (mPos == mImageOffset + BITMAPINFOSIZE) {
    ProcessInfoHeader();
    if (mBIH.bpp <= 8) {
      switch (mBIH.bpp) {
        case 1:
          mNumColors = 2;
          break;
        case 4:
          mNumColors = 16;
          break;
        case 8:
          mNumColors = 256;
          break;
        default:
          return NS_ERROR_FAILURE;
      }

      mColors = new colorTable[mNumColors];
      if (!mColors)
        return NS_ERROR_OUT_OF_MEMORY;
    }

    nsresult rv = mImage->Init(mDirEntry.mWidth, mDirEntry.mHeight, mObserver);
    NS_ENSURE_SUCCESS(rv, rv);

    if (mIsCursor) {
      nsCOMPtr<nsIProperties> props(do_QueryInterface(mImage));
      if (props) {
        nsCOMPtr<nsISupportsPRUint32> intwrapx = do_CreateInstance("@mozilla.org/supports-PRUint32;1");
        nsCOMPtr<nsISupportsPRUint32> intwrapy = do_CreateInstance("@mozilla.org/supports-PRUint32;1");

        if (intwrapx && intwrapy) {
          intwrapx->SetData(mDirEntry.mXHotspot);
          intwrapy->SetData(mDirEntry.mYHotspot);

          props->Set("hotspotX", intwrapx);
          props->Set("hotspotY", intwrapy);
        }
      }
    }

    rv = mObserver->OnStartContainer(nsnull, mImage);
    NS_ENSURE_SUCCESS(rv, rv);

    mCurLine = mDirEntry.mHeight;
    mRow = (PRUint8*)malloc((mDirEntry.mWidth * mBIH.bpp)/8 + 4);
    // +4 because the line is padded to a 4 bit boundary, but I don't want
    // to make exact calculations here, that's unnecessary.
    // Also, it compensates rounding error.
    if (!mRow)
      return NS_ERROR_OUT_OF_MEMORY;
    
    rv = mFrame->Init(0, 0, mDirEntry.mWidth, mDirEntry.mHeight, GFXFORMATALPHA8, 24);
    NS_ENSURE_SUCCESS(rv, rv);
    rv = mImage->AppendFrame(mFrame);
    NS_ENSURE_SUCCESS(rv, rv);
    mObserver->OnStartFrame(nsnull, mFrame);
    NS_ENSURE_SUCCESS(rv, rv);
  }

  if (mColors && (mPos >= mImageOffset + BITMAPINFOSIZE) && 
                 (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
    // We will receive (mNumColors * 4) bytes of color data
    PRUint32 colorBytes = mPos - (mImageOffset + 40); // Number of bytes already received
    PRUint8 colorNum = colorBytes / 4; // Color which is currently received
    PRUint8 at = colorBytes % 4;
    while (aCount && (mPos < (mImageOffset + BITMAPINFOSIZE + mNumColors * 4))) {
      switch (at) {
        case 0:
          mColors[colorNum].blue = *aBuffer;
          break;
        case 1:
          mColors[colorNum].green = *aBuffer;
          break;
        case 2:
          mColors[colorNum].red = *aBuffer;
          break;
        case 3:
          colorNum++; // This is a padding byte
          break;
      }
      mPos++; aBuffer++; aCount--;
      at = (at + 1) % 4;
    }
  }

  if (!mDecodingAndMask && (mPos >= (mImageOffset + BITMAPINFOSIZE + mNumColors*4))) {
    if (mPos == (mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
      // Increment mPos to avoid reprocessing the info header.
      mPos++;
#if defined(XP_MAC) || defined(XP_MACOSX)
      mDecodedBuffer = (PRUint8*)malloc(mDirEntry.mHeight*mDirEntry.mWidth*4);
#else
      mDecodedBuffer = (PRUint8*)malloc(mDirEntry.mHeight*mDirEntry.mWidth*3);
#endif
      if (!mDecodedBuffer)
        return NS_ERROR_OUT_OF_MEMORY;
    }
    PRUint32 alphaRowSize;
    mFrame->GetAlphaBytesPerRow(&alphaRowSize);
    nsAutoArrayPtr<PRUint8> alphaRow; // Will only be used if bpp == 32
    if (mBIH.bpp == 32) {
      alphaRow = new PRUint8[alphaRowSize];
      if (!alphaRow)
        return NS_ERROR_OUT_OF_MEMORY;
    }

    // Ensure memory has been allocated before decoding. If we get this far 
    // without allocated memory, the file is most likely invalid.
    NS_ASSERTION(mRow, "mRow is null");
    NS_ASSERTION(mDecodedBuffer, "mDecodedBuffer is null");
    if (!mRow || !mDecodedBuffer)
      return NS_ERROR_FAILURE;

    PRUint32 rowSize = (mBIH.bpp * mDirEntry.mWidth + 7) / 8; // +7 to round up
    if (rowSize % 4)
      rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
    PRUint32 toCopy;
    do {
        toCopy = rowSize - mRowBytes;
        if (toCopy) {
            if (toCopy > aCount)
                toCopy = aCount;
            memcpy(mRow + mRowBytes, aBuffer, toCopy);
            aCount -= toCopy;
            aBuffer += toCopy;
            mRowBytes += toCopy;
        }
        if (rowSize == mRowBytes) {
            mCurLine--;
            PRUint8* decoded = mDecodedBuffer + (mCurLine * mDirEntry.mWidth * GFXBYTESPERPIXEL);
            PRUint8* p = mRow;
            PRUint8* d = decoded;
            PRUint8* alphaPos = alphaRow; // only used if bpp == 32
            PRUint32 lpos = mDirEntry.mWidth;
            switch (mBIH.bpp) {
              case 1:
                while (lpos > 0) {
                  PRInt8 bit;
                  PRUint8 idx;
                  for (bit = 7; bit >= 0 && lpos > 0; bit--) {
                      idx = (*p >> bit) & 1;
                      SetPixel(d, idx, mColors);
                      --lpos;
                  }
                  ++p;
                }
                break;
              case 4:
                while (lpos > 0) {
                  Set4BitPixel(d, *p, lpos, mColors);
                  ++p;
                }
                break;
              case 8:
                while (lpos > 0) {
                  SetPixel(d, *p, mColors);
                  --lpos;
                  ++p;
                }
                break;
              case 16:
                while (lpos > 0) {
                  SetPixel(d,
                          (p[1] & 124) << 1,
                          ((p[1] & 3) << 6) | ((p[0] & 224) >> 2),
                          (p[0] & 31) << 3);

                  --lpos;
                  p+=2;
                }
                break;
              case 32:
              case 24:
                while (lpos > 0) {
                  SetPixel(d, p[2], p[1], p[0]);
                  p += 3;
                  --lpos;
                  if (mBIH.bpp == 32)
                    mHaveAlphaData |= *alphaPos++ = *p++; // Alpha value
                }
                break;
              default:
                // This is probably the wrong place to check this...
                return NS_ERROR_FAILURE;
            }

            if (mCurLine == 0)
              mDecodingAndMask = PR_TRUE;
              
            mRowBytes = 0;

            // If 32 bit image, gotta set the alpha data here
            if (mBIH.bpp == 32)
              mFrame->SetAlphaData(alphaRow, alphaRowSize, mCurLine * alphaRowSize);
        }
    } while (!mDecodingAndMask && aCount > 0);

  }

  if (mDecodingAndMask && !mHaveAlphaData) {
    PRUint32 rowSize = CalcAlphaRowSize();

    if (mPos == (1 + mImageOffset + BITMAPINFOSIZE + mNumColors*4)) {
      mPos++;
      mRowBytes = 0;
      mCurLine = mDirEntry.mHeight;
      free(mRow);
      mRow = (PRUint8*)malloc(rowSize);
      if (!mRow)
        return NS_ERROR_OUT_OF_MEMORY;
      mAlphaBuffer = (PRUint8*)malloc(mDirEntry.mHeight*rowSize);
      if (!mAlphaBuffer)
        return NS_ERROR_OUT_OF_MEMORY;
      memset(mAlphaBuffer, 0xff, mDirEntry.mHeight*rowSize);
    }

    // Ensure memory has been allocated before decoding.
    NS_ASSERTION(mRow, "mRow is null");
    NS_ASSERTION(mAlphaBuffer, "mAlphaBuffer is null");
    if (!mRow || !mAlphaBuffer)
      return NS_ERROR_FAILURE;

    PRUint32 toCopy;
    do {
        if (mCurLine == 0) {
          return NS_OK;
        }

        toCopy = rowSize - mRowBytes;
        if (toCopy) {
            if (toCopy > aCount)
                toCopy = aCount;
            memcpy(mRow + mRowBytes, aBuffer, toCopy);
            aCount -= toCopy;
            aBuffer += toCopy;
            mRowBytes += toCopy;
        }
        if ((rowSize - mRowBytes) == 0) {
            mCurLine--;
            PRUint8* decoded = mAlphaBuffer+(mCurLine*rowSize);
            PRUint8* p = mRow;
            PRUint32 lpos = 0;
            while (lpos < rowSize) {
              PRUint8 idx = *p;
              idx ^= 255;  // We complement the value, since our method of storing transparency is opposite
                           // what Win32 uses in its masks.
              decoded[lpos] = idx;
              lpos++;
              p++;
            }
            
            mRowBytes = 0;
        }
    } while (aCount > 0);
  }

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 569 of file nsICODecoder.cpp.

{
  memset(&aTarget, 0, sizeof(aTarget));
  memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
  memcpy(&aTarget.mHeight, mDirEntryArray+1, sizeof(aTarget.mHeight));
  memcpy(&aTarget.mColorCount, mDirEntryArray+2, sizeof(aTarget.mColorCount));
  memcpy(&aTarget.mReserved, mDirEntryArray+3, sizeof(aTarget.mReserved));
  
  memcpy(&aTarget.mPlanes, mDirEntryArray+4, sizeof(aTarget.mPlanes));
  aTarget.mPlanes = LITTLE_TO_NATIVE16(aTarget.mPlanes);

  memcpy(&aTarget.mBitCount, mDirEntryArray+6, sizeof(aTarget.mBitCount));
  aTarget.mBitCount = LITTLE_TO_NATIVE16(aTarget.mBitCount);

  memcpy(&aTarget.mBytesInRes, mDirEntryArray+8, sizeof(aTarget.mBytesInRes));
  aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);

  memcpy(&aTarget.mImageOffset, mDirEntryArray+12, sizeof(aTarget.mImageOffset));
  aTarget.mImageOffset = LITTLE_TO_NATIVE32(aTarget.mImageOffset);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 590 of file nsICODecoder.cpp.

Here is the call graph for this function:

Here is the caller graph for this function:

NS_METHOD nsICODecoder::ReadSegCb ( nsIInputStream aIn,
void aClosure,
const char *  aFromRawSegment,
PRUint32  aToOffset,
PRUint32  aCount,
PRUint32 aWriteCount 
) [static, private]

Callback for ReadSegments to avoid copying the data.

Definition at line 218 of file nsICODecoder.cpp.

                                                                     {
  nsICODecoder *decoder = NS_REINTERPRET_CAST(nsICODecoder*, aClosure);
  *aWriteCount = aCount;
  decoder->mStatus = decoder->ProcessData(aFromRawSegment, aCount);
  return decoder->mStatus;
}

Here is the call graph for this function:

Definition at line 99 of file nsICODecoder.cpp.

{
  // Alpha data was already set if bpp == 32
  if (mHaveAlphaData)
    return NS_OK;

  PRUint32 bpr;
  mFrame->GetAlphaBytesPerRow(&bpr);
  // In case the decoder and frame have different sized alpha buffers, we
  // take the smaller of the two row length values as the row length to copy.
  PRUint32 rowCopyLen = PR_MIN(bpr, mDirEntry.mWidth);
  PRUint8* alphaRow = (PRUint8*)malloc(rowCopyLen);
  if (!alphaRow)
    return NS_ERROR_OUT_OF_MEMORY;

  PRUint32 decoderRowSize = CalcAlphaRowSize();
  PRUint8* alphaBufferPos = mAlphaBuffer;
  PRUint32 frameOffset = 0;

  for (PRUint32 i = 0; i < mDirEntry.mHeight; i++) {
    PRInt8 byte = 0;
    PRUint32 k = 0;
    for (PRUint32 j = 0; j < rowCopyLen; ++j) {
      if ((j % 8) == 0)
        byte = alphaBufferPos[k++];
      alphaRow[j] = byte >> 7;
      byte <<= 1;
    }
    mFrame->SetAlphaData(alphaRow, rowCopyLen, frameOffset);
    frameOffset += bpr;
    alphaBufferPos += decoderRowSize;
  }
  free(alphaRow);
  return NS_OK;
}

Here is the call graph for this function:

Definition at line 69 of file nsICODecoder.cpp.

{
  PRUint32 bpr;
  mFrame->GetImageBytesPerRow(&bpr);
 
  // Since the ICO is decoded into an exact sized array, the frame may use
  // more bytes per row of pixels than the decoding array.
#if defined(XP_MAC) || defined(XP_MACOSX)
  PRUint32 decodedLineLen = mDirEntry.mWidth * 4;
#else
  PRUint32 decodedLineLen = mDirEntry.mWidth * 3;
#endif

  PRUint8* decodeBufferPos = mDecodedBuffer;
  PRUint32 frameOffset = 0;

  for (PRUint32 i = 0;
       i < mDirEntry.mHeight;
       ++i, frameOffset += bpr, decodeBufferPos += decodedLineLen) {
    mFrame->SetImageData(decodeBufferPos, decodedLineLen, frameOffset);
  }

  nsIntRect r(0, 0, 0, 0);
  mFrame->GetWidth(&r.width);
  mFrame->GetHeight(&r.height);
  mObserver->OnDataAvailable(nsnull, mFrame, &r);

  return NS_OK;
}
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 133 of file nsICODecoder.h.

Definition at line 121 of file nsICODecoder.h.

char nsICODecoder::mBIHraw[40] [private]

Definition at line 120 of file nsICODecoder.h.

Definition at line 124 of file nsICODecoder.h.

Definition at line 128 of file nsICODecoder.h.

Definition at line 114 of file nsICODecoder.h.

Definition at line 132 of file nsICODecoder.h.

Definition at line 110 of file nsICODecoder.h.

Definition at line 118 of file nsICODecoder.h.

char nsICODecoder::mDirEntryArray[16] [private]

Definition at line 117 of file nsICODecoder.h.

Definition at line 107 of file nsICODecoder.h.

Definition at line 109 of file nsICODecoder.h.

Definition at line 106 of file nsICODecoder.h.

Definition at line 115 of file nsICODecoder.h.

Definition at line 134 of file nsICODecoder.h.

Definition at line 123 of file nsICODecoder.h.

Definition at line 113 of file nsICODecoder.h.

Definition at line 105 of file nsICODecoder.h.

Definition at line 112 of file nsICODecoder.h.

Definition at line 126 of file nsICODecoder.h.

Definition at line 127 of file nsICODecoder.h.

Definition at line 130 of file nsICODecoder.h.


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