LCOV - code coverage report
Current view: directory - image/decoders - nsBMPDecoder.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 387 200 51.7 %
Date: 2012-06-02 Functions: 19 16 84.2 %

       1                 : /* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla BMP Decoder.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Christian Biesinger <cbiesinger@web.de>.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Neil Rashbrook <neil@parkwaycc.co.uk>
      24                 :  *   Bobby Holley <bobbyholley@gmail.com>
      25                 :  *   Brian R. Bondy <netzen@gmail.com>
      26                 :  *
      27                 :  * Alternatively, the contents of this file may be used under the terms of
      28                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      29                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      31                 :  * of those above. If you wish to allow use of your version of this file only
      32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      33                 :  * use your version of this file under the terms of the MPL, indicate your
      34                 :  * decision by deleting the provisions above and replace them with the notice
      35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      36                 :  * the provisions above, a recipient may use your version of this file under
      37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      38                 :  *
      39                 :  * ***** END LICENSE BLOCK ***** */
      40                 : /* I got the format description from http://www.daubnet.com/formats/BMP.html */
      41                 : 
      42                 : /* This is a Cross-Platform BMP Decoder, which should work everywhere, including
      43                 :  * Big-Endian machines like the PowerPC. */
      44                 : 
      45                 : #include <stdlib.h>
      46                 : 
      47                 : #include "EndianMacros.h"
      48                 : #include "nsBMPDecoder.h"
      49                 : 
      50                 : #include "nsIInputStream.h"
      51                 : #include "RasterImage.h"
      52                 : #include "imgIContainerObserver.h"
      53                 : #include "ImageLogging.h"
      54                 : 
      55                 : namespace mozilla {
      56                 : namespace image {
      57                 : 
      58                 : #ifdef PR_LOGGING
      59            1464 : PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
      60                 : #endif
      61                 : 
      62                 : // Convert from row (1..height) to absolute line (0..height-1)
      63                 : #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
      64                 : #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
      65                 : 
      66               4 : nsBMPDecoder::nsBMPDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
      67               4 :  : Decoder(aImage, aObserver)
      68                 : {
      69               4 :   mColors = nsnull;
      70               4 :   mRow = nsnull;
      71               4 :   mImageData = nsnull;
      72               4 :   mCurPos = mPos = mNumColors = mRowBytes = 0;
      73               4 :   mOldLine = mCurLine = 1; // Otherwise decoder will never start
      74               4 :   mState = eRLEStateInitial;
      75               4 :   mStateData = 0;
      76               4 :   mLOH = WIN_HEADER_LENGTH;
      77               4 :   mUseAlphaData = mHaveAlphaData = false;
      78               4 : }
      79                 : 
      80              12 : nsBMPDecoder::~nsBMPDecoder()
      81                 : {
      82               4 :   delete[] mColors;
      83               4 :   if (mRow) {
      84               4 :       moz_free(mRow);
      85                 :   }
      86              16 : }
      87                 : 
      88                 : // Sets whether or not the BMP will use alpha data
      89                 : void 
      90               4 : nsBMPDecoder::SetUseAlphaData(bool useAlphaData) 
      91                 : {
      92               4 :   mUseAlphaData = useAlphaData;
      93               4 : }
      94                 : 
      95                 : // Obtains the bits per pixel from the internal BIH header
      96                 : PRInt32 
      97               8 : nsBMPDecoder::GetBitsPerPixel() const
      98                 : {
      99               8 :   return mBIH.bpp;
     100                 : }
     101                 : 
     102                 : // Obtains the width from the internal BIH header
     103                 : PRInt32 
     104               2 : nsBMPDecoder::GetWidth() const
     105                 : {
     106               2 :   return mBIH.width; 
     107                 : }
     108                 : 
     109                 : // Obtains the height from the internal BIH header
     110                 : PRInt32 
     111               1 : nsBMPDecoder::GetHeight() const
     112                 : {
     113               1 :   return mBIH.height; 
     114                 : }
     115                 : 
     116                 : // Obtains the internal output image buffer
     117                 : PRUint32* 
     118              48 : nsBMPDecoder::GetImageData() 
     119                 : {
     120              48 :   return mImageData;
     121                 : }
     122                 : 
     123                 : // Obtains the size of the compressed image resource
     124                 : PRInt32 
     125               6 : nsBMPDecoder::GetCompressedImageSize() const
     126                 : {
     127                 :   // For everything except BI_RGB the header field must be defined
     128               6 :   if (mBIH.compression != BI_RGB) {
     129               0 :     return mBIH.image_size;
     130                 :   }
     131                 : 
     132                 :   // mBIH.image_size isn't always filled for BI_RGB so calculate it manually
     133                 :   // The pixel array size is calculated based on extra 4 byte boundary padding
     134               6 :   PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
     135                 :   // Pad to DWORD Boundary
     136               6 :   if (rowSize % 4) {
     137               0 :     rowSize += (4 - (rowSize % 4));
     138                 :   }
     139                 : 
     140                 :   // The height should be the absolute value of what the height is in the BIH.
     141                 :   // If positive the bitmap is stored bottom to top, otherwise top to bottom
     142               6 :   PRInt32 pixelArraySize = rowSize * abs(mBIH.height); 
     143               6 :   return pixelArraySize;
     144                 : }
     145                 : 
     146                 : // Obtains whether or not a BMP file had alpha data in its 4th byte
     147                 : // for 32BPP bitmaps.  Only use after the bitmap has been processed.
     148                 : bool 
     149               1 : nsBMPDecoder::HasAlphaData() const 
     150                 : {
     151               1 :   return mHaveAlphaData;
     152                 : }
     153                 : 
     154                 : 
     155                 : void
     156               4 : nsBMPDecoder::FinishInternal()
     157                 : {
     158                 :     // We shouldn't be called in error cases
     159               4 :     NS_ABORT_IF_FALSE(!HasError(), "Can't call FinishInternal on error!");
     160                 : 
     161                 :     // We should never make multiple frames
     162               4 :     NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple BMP frames?");
     163                 : 
     164                 :     // Send notifications if appropriate
     165               4 :     if (!IsSizeDecode() && (GetFrameCount() == 1)) {
     166                 : 
     167                 :         // Invalidate
     168               4 :         nsIntRect r(0, 0, mBIH.width, mBIH.height);
     169               4 :         PostInvalidation(r);
     170                 : 
     171               4 :         PostFrameStop();
     172               4 :         PostDecodeDone();
     173                 :     }
     174               4 : }
     175                 : 
     176                 : // ----------------------------------------
     177                 : // Actual Data Processing
     178                 : // ----------------------------------------
     179                 : 
     180               0 : static void calcBitmask(PRUint32 aMask, PRUint8& aBegin, PRUint8& aLength)
     181                 : {
     182                 :     // find the rightmost 1
     183                 :     PRUint8 pos;
     184               0 :     bool started = false;
     185               0 :     aBegin = aLength = 0;
     186               0 :     for (pos = 0; pos <= 31; pos++) {
     187               0 :         if (!started && (aMask & (1 << pos))) {
     188               0 :             aBegin = pos;
     189               0 :             started = true;
     190                 :         }
     191               0 :         else if (started && !(aMask & (1 << pos))) {
     192               0 :             aLength = pos - aBegin;
     193               0 :             break;
     194                 :         }
     195                 :     }
     196               0 : }
     197                 : 
     198               0 : NS_METHOD nsBMPDecoder::CalcBitShift()
     199                 : {
     200                 :     PRUint8 begin, length;
     201                 :     // red
     202               0 :     calcBitmask(mBitFields.red, begin, length);
     203               0 :     mBitFields.redRightShift = begin;
     204               0 :     mBitFields.redLeftShift = 8 - length;
     205                 :     // green
     206               0 :     calcBitmask(mBitFields.green, begin, length);
     207               0 :     mBitFields.greenRightShift = begin;
     208               0 :     mBitFields.greenLeftShift = 8 - length;
     209                 :     // blue
     210               0 :     calcBitmask(mBitFields.blue, begin, length);
     211               0 :     mBitFields.blueRightShift = begin;
     212               0 :     mBitFields.blueLeftShift = 8 - length;
     213               0 :     return NS_OK;
     214                 : }
     215                 : 
     216                 : void
     217              14 : nsBMPDecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
     218                 : {
     219              14 :     NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
     220                 : 
     221                 :     // aCount=0 means EOF, mCurLine=0 means we're past end of image
     222              14 :     if (!aCount || !mCurLine)
     223               0 :         return;
     224                 : 
     225                 :     nsresult rv;
     226              14 :     if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
     227               8 :         PRUint32 toCopy = BFH_INTERNAL_LENGTH - mPos;
     228               8 :         if (toCopy > aCount)
     229               4 :             toCopy = aCount;
     230               8 :         memcpy(mRawBuf + mPos, aBuffer, toCopy);
     231               8 :         mPos += toCopy;
     232               8 :         aCount -= toCopy;
     233               8 :         aBuffer += toCopy;
     234                 :     }
     235              14 :     if (mPos == BFH_INTERNAL_LENGTH) {
     236               4 :         ProcessFileHeader();
     237               4 :         if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
     238               0 :             PostDataError();
     239               0 :             return;
     240                 :         }
     241               4 :         if (mBFH.bihsize == OS2_BIH_LENGTH)
     242               0 :             mLOH = OS2_HEADER_LENGTH;
     243                 :     }
     244              14 :     if (mPos >= BFH_INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
     245               4 :         PRUint32 toCopy = mLOH - mPos;
     246               4 :         if (toCopy > aCount)
     247               0 :             toCopy = aCount;
     248               4 :         memcpy(mRawBuf + (mPos - BFH_INTERNAL_LENGTH), aBuffer, toCopy);
     249               4 :         mPos += toCopy;
     250               4 :         aCount -= toCopy;
     251               4 :         aBuffer += toCopy;
     252                 :     }
     253                 : 
     254                 :     // GetNumFrames is called to ensure that if at this point mPos == mLOH but
     255                 :     // we have no data left to process, the next time WriteInternal is called
     256                 :     // we won't enter this condition again.
     257              14 :     if (mPos == mLOH && GetFrameCount() == 0) {
     258               4 :         ProcessInfoHeader();
     259               4 :         PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP is %lix%lix%lu. compression=%lu\n",
     260                 :                mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
     261                 :         // Verify we support this bit depth
     262               4 :         if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
     263                 :             mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
     264               0 :           PostDataError();
     265               0 :           return;
     266                 :         }
     267                 : 
     268                 :         // BMPs with negative width are invalid
     269                 :         // Reject extremely wide images to keep the math sane
     270               4 :         const PRInt32 k64KWidth = 0x0000FFFF;
     271               4 :         if (mBIH.width < 0 || mBIH.width > k64KWidth) {
     272               0 :             PostDataError();
     273               0 :             return;
     274                 :         }
     275                 : 
     276               4 :         PRUint32 real_height = (mBIH.height > 0) ? mBIH.height : -mBIH.height;
     277                 : 
     278                 :         // Post our size to the superclass
     279               4 :         PostSize(mBIH.width, real_height);
     280               4 :         if (HasError()) {
     281                 :           // Setting the size lead to an error; this can happen when for example
     282                 :           // a multipart channel sends an image of a different size.
     283               0 :           return;
     284                 :         }
     285                 : 
     286                 :         // We have the size. If we're doing a size decode, we got what
     287                 :         // we came for.
     288               4 :         if (IsSizeDecode())
     289               0 :             return;
     290                 : 
     291                 :         // We're doing a real decode.
     292               4 :         mOldLine = mCurLine = real_height;
     293                 : 
     294               4 :         if (mBIH.bpp <= 8) {
     295               3 :             mNumColors = 1 << mBIH.bpp;
     296               3 :             if (mBIH.colors && mBIH.colors < mNumColors)
     297               0 :                 mNumColors = mBIH.colors;
     298                 : 
     299                 :             // Always allocate 256 even though mNumColors might be smaller
     300               3 :             mColors = new colorTable[256];
     301               3 :             memset(mColors, 0, 256 * sizeof(colorTable));
     302                 :         }
     303               1 :         else if (mBIH.compression != BI_BITFIELDS && mBIH.bpp == 16) {
     304                 :             // Use default 5-5-5 format
     305               0 :             mBitFields.red   = 0x7C00;
     306               0 :             mBitFields.green = 0x03E0;
     307               0 :             mBitFields.blue  = 0x001F;
     308               0 :             CalcBitShift();
     309                 :         }
     310                 : 
     311                 :         // Make sure we have a valid value for our supported compression modes
     312                 :         // before adding the frame
     313               4 :         if (mBIH.compression != BI_RGB && mBIH.compression != BI_RLE8 && 
     314                 :             mBIH.compression != BI_RLE4 && mBIH.compression != BI_BITFIELDS) {
     315               0 :           PostDataError();
     316               0 :           return;
     317                 :         }
     318                 : 
     319                 :         // If we have RLE4 or RLE8 or BI_ALPHABITFIELDS, then ensure we
     320                 :         // have valid BPP values before adding the frame
     321               4 :         if (mBIH.compression == BI_RLE8 && mBIH.bpp != 8) {
     322               0 :           PR_LOG(gBMPLog, PR_LOG_DEBUG, 
     323                 :                  ("BMP RLE8 compression only supports 8 bits per pixel\n"));
     324               0 :           PostDataError();
     325               0 :           return;
     326                 :         }
     327               4 :         if (mBIH.compression == BI_RLE4 && mBIH.bpp != 4 && mBIH.bpp != 1) {
     328               0 :           PR_LOG(gBMPLog, PR_LOG_DEBUG, 
     329                 :                  ("BMP RLE4 compression only supports 4 bits per pixel\n"));
     330               0 :           PostDataError();
     331               0 :           return;
     332                 :         }
     333               4 :         if (mBIH.compression == BI_ALPHABITFIELDS && 
     334                 :             mBIH.bpp != 16 && mBIH.bpp != 32) {
     335               0 :           PR_LOG(gBMPLog, PR_LOG_DEBUG, 
     336                 :                  ("BMP ALPHABITFIELDS only supports 16 or 32 bits per pixel\n"));
     337               0 :           PostDataError();
     338               0 :           return;
     339                 :         }
     340                 : 
     341                 :         PRUint32 imageLength;
     342               4 :         if (mBIH.compression == BI_RLE8 || mBIH.compression == BI_RLE4 || 
     343                 :             mBIH.compression == BI_ALPHABITFIELDS) {
     344                 :             rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height, 
     345                 :                                     gfxASurface::ImageFormatARGB32,
     346               0 :                                     (PRUint8**)&mImageData, &imageLength);
     347                 :         } else {
     348                 :             // mRow is not used for RLE encoded images
     349               4 :             mRow = (PRUint8*)moz_malloc((mBIH.width * mBIH.bpp) / 8 + 4);
     350                 :             // + 4 because the line is padded to a 4 bit boundary, but I don't want
     351                 :             // to make exact calculations here, that's unnecessary.
     352                 :             // Also, it compensates rounding error.
     353               4 :             if (!mRow) {
     354               0 :                 PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
     355               0 :                 return;
     356                 :             }
     357                 : 
     358               4 :             if (mUseAlphaData) {
     359                 :               rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height, 
     360                 :                                       gfxASurface::ImageFormatARGB32,
     361               4 :                                       (PRUint8**)&mImageData, &imageLength);
     362                 :             } else {
     363                 :               rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height, 
     364                 :                                       gfxASurface::ImageFormatRGB24,
     365               0 :                                       (PRUint8**)&mImageData, &imageLength);
     366                 :             }
     367                 :         }
     368               4 :         if (NS_FAILED(rv) || !mImageData) {
     369               0 :             PostDecoderError(NS_ERROR_FAILURE);
     370               0 :             return;
     371                 :         }
     372                 : 
     373                 :         // Prepare for transparency
     374               4 :         if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
     375                 :             // Clear the image, as the RLE may jump over areas
     376               0 :             memset(mImageData, 0, imageLength);
     377                 :         }
     378                 : 
     379                 :         // Tell the superclass we're starting a frame
     380               4 :         PostFrameStart();
     381                 :     }
     382                 : 
     383              14 :     if (mColors && mPos >= mLOH) {
     384                 :       // OS/2 Bitmaps have no padding byte
     385               8 :       PRUint8 bytesPerColor = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4;
     386               8 :       if (mPos < (mLOH + mNumColors * bytesPerColor)) {
     387                 :         // Number of bytes already received
     388               8 :         PRUint32 colorBytes = mPos - mLOH; 
     389                 :         // Color which is currently received
     390               8 :         PRUint8 colorNum = colorBytes / bytesPerColor;
     391               8 :         PRUint8 at = colorBytes % bytesPerColor;
     392            3088 :         while (aCount && (mPos < (mLOH + mNumColors * bytesPerColor))) {
     393            3072 :             switch (at) {
     394                 :                 case 0:
     395             768 :                     mColors[colorNum].blue = *aBuffer;
     396             768 :                     break;
     397                 :                 case 1:
     398             768 :                     mColors[colorNum].green = *aBuffer;
     399             768 :                     break;
     400                 :                 case 2:
     401             768 :                     mColors[colorNum].red = *aBuffer;
     402                 :                     // If there is no padding byte, increment the color index
     403                 :                     // since we're done with the current color.
     404             768 :                     if (bytesPerColor == 3)
     405               0 :                       colorNum++;
     406             768 :                     break;
     407                 :                 case 3:
     408                 :                     // This is a padding byte only in Windows BMPs. Increment
     409                 :                     // the color index since we're done with the current color.
     410             768 :                     colorNum++;
     411             768 :                     break;
     412                 :             }
     413            3072 :             mPos++; aBuffer++; aCount--;
     414            3072 :             at = (at + 1) % bytesPerColor;
     415                 :         }
     416               8 :       }
     417                 :     }
     418               6 :     else if (aCount && mBIH.compression == BI_BITFIELDS && mPos < (WIN_HEADER_LENGTH + BITFIELD_LENGTH)) {
     419                 :         // If compression is used, this is a windows bitmap, hence we can
     420                 :         // use WIN_HEADER_LENGTH instead of mLOH
     421               0 :         PRUint32 toCopy = (WIN_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
     422               0 :         if (toCopy > aCount)
     423               0 :             toCopy = aCount;
     424               0 :         memcpy(mRawBuf + (mPos - WIN_HEADER_LENGTH), aBuffer, toCopy);
     425               0 :         mPos += toCopy;
     426               0 :         aBuffer += toCopy;
     427               0 :         aCount -= toCopy;
     428                 :     }
     429              14 :     if (mPos == WIN_HEADER_LENGTH + BITFIELD_LENGTH && 
     430                 :         mBIH.compression == BI_BITFIELDS) {
     431               0 :         mBitFields.red = LITTLE_TO_NATIVE32(*(PRUint32*)mRawBuf);
     432               0 :         mBitFields.green = LITTLE_TO_NATIVE32(*(PRUint32*)(mRawBuf + 4));
     433               0 :         mBitFields.blue = LITTLE_TO_NATIVE32(*(PRUint32*)(mRawBuf + 8));
     434               0 :         CalcBitShift();
     435                 :     }
     436              28 :     while (aCount && (mPos < mBFH.dataoffset)) { // Skip whatever is between header and data
     437               0 :         mPos++; aBuffer++; aCount--;
     438                 :     }
     439              14 :     if (aCount && ++mPos >= mBFH.dataoffset) {
     440                 :         // Need to increment mPos, else we might get to mPos==mLOH again
     441                 :         // From now on, mPos is irrelevant
     442               4 :         if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
     443               4 :             PRUint32 rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
     444               4 :             if (rowSize % 4) {
     445               0 :                 rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
     446                 :             }
     447                 :             PRUint32 toCopy;
     448              60 :             do {
     449              64 :                 toCopy = rowSize - mRowBytes;
     450              64 :                 if (toCopy) {
     451              64 :                     if (toCopy > aCount)
     452               0 :                         toCopy = aCount;
     453              64 :                     memcpy(mRow + mRowBytes, aBuffer, toCopy);
     454              64 :                     aCount -= toCopy;
     455              64 :                     aBuffer += toCopy;
     456              64 :                     mRowBytes += toCopy;
     457                 :                 }
     458              64 :                 if (rowSize == mRowBytes) {
     459                 :                     // Collected a whole row into mRow, process it
     460              64 :                     PRUint8* p = mRow;
     461              64 :                     PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, 0);
     462              64 :                     PRUint32 lpos = mBIH.width;
     463              64 :                     switch (mBIH.bpp) {
     464                 :                       case 1:
     465               0 :                         while (lpos > 0) {
     466                 :                           PRInt8 bit;
     467                 :                           PRUint8 idx;
     468               0 :                           for (bit = 7; bit >= 0 && lpos > 0; bit--) {
     469               0 :                               idx = (*p >> bit) & 1;
     470               0 :                               SetPixel(d, idx, mColors);
     471               0 :                               --lpos;
     472                 :                           }
     473               0 :                           ++p;
     474                 :                         }
     475               0 :                         break;
     476                 :                       case 4:
     477               0 :                         while (lpos > 0) {
     478               0 :                           Set4BitPixel(d, *p, lpos, mColors);
     479               0 :                           ++p;
     480                 :                         }
     481               0 :                         break;
     482                 :                       case 8:
     483             864 :                         while (lpos > 0) {
     484             768 :                           SetPixel(d, *p, mColors);
     485             768 :                           --lpos;
     486             768 :                           ++p;
     487                 :                         }
     488              48 :                         break;
     489                 :                       case 16:
     490               0 :                         while (lpos > 0) {
     491               0 :                           PRUint16 val = LITTLE_TO_NATIVE16(*(PRUint16*)p);
     492                 :                           SetPixel(d,
     493                 :                                   (val & mBitFields.red) >> mBitFields.redRightShift << mBitFields.redLeftShift,
     494                 :                                   (val & mBitFields.green) >> mBitFields.greenRightShift << mBitFields.greenLeftShift,
     495               0 :                                   (val & mBitFields.blue) >> mBitFields.blueRightShift << mBitFields.blueLeftShift);
     496               0 :                           --lpos;
     497               0 :                           p+=2;
     498                 :                         }
     499               0 :                         break;
     500                 :                       case 24:
     501               0 :                         while (lpos > 0) {
     502               0 :                           SetPixel(d, p[2], p[1], p[0]);
     503               0 :                           p += 2;
     504               0 :                           --lpos;
     505               0 :                           ++p;
     506                 :                         }
     507               0 :                         break;
     508                 :                       case 32:
     509             288 :                         while (lpos > 0) {
     510             256 :                           if (mUseAlphaData) {
     511             256 :                             if (!mHaveAlphaData && p[3]) {
     512                 :                               // Non-zero alpha byte detected! Clear previous
     513                 :                               // pixels that we have already processed.
     514                 :                               // This works because we know that if we 
     515                 :                               // are reaching here then the alpha data in byte 
     516                 :                               // 4 has been right all along.  And we know it
     517                 :                               // has been set to 0 the whole time, so that 
     518                 :                               // means that everything is transparent so far.
     519               2 :                               memset(mImageData + (mCurLine - 1) * GetWidth(), 0, 
     520               1 :                                      (GetHeight() - mCurLine + 1) * 
     521               3 :                                      GetWidth() * sizeof(PRUint32));
     522               1 :                               mHaveAlphaData = true;
     523                 :                             }
     524             256 :                             SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
     525                 :                           } else {
     526               0 :                             SetPixel(d, p[2], p[1], p[0]);
     527                 :                           }
     528             256 :                           p += 4;
     529             256 :                           --lpos;
     530                 :                         }
     531              16 :                         break;
     532                 :                       default:
     533               0 :                         NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
     534                 :                     }
     535              64 :                     mCurLine --;
     536              64 :                     if (mCurLine == 0) { // Finished last line
     537               4 :                       break;
     538                 :                     }
     539              60 :                     mRowBytes = 0;
     540                 : 
     541                 :                 }
     542               4 :             } while (aCount > 0);
     543                 :         }
     544               0 :         else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
     545               0 :             if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) || 
     546                 :                 ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
     547               0 :               PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
     548               0 :               PostDataError();
     549               0 :               return;
     550                 :             }
     551                 : 
     552               0 :             while (aCount > 0) {
     553                 :                 PRUint8 byte;
     554                 : 
     555               0 :                 switch(mState) {
     556                 :                     case eRLEStateInitial:
     557               0 :                         mStateData = (PRUint8)*aBuffer++;
     558               0 :                         aCount--;
     559                 : 
     560               0 :                         mState = eRLEStateNeedSecondEscapeByte;
     561               0 :                         continue;
     562                 : 
     563                 :                     case eRLEStateNeedSecondEscapeByte:
     564               0 :                         byte = *aBuffer++;
     565               0 :                         aCount--;
     566               0 :                         if (mStateData != RLE_ESCAPE) { // encoded mode
     567                 :                             // Encoded mode consists of two bytes: 
     568                 :                             // the first byte (mStateData) specifies the
     569                 :                             // number of consecutive pixels to be drawn 
     570                 :                             // using the color index contained in
     571                 :                             // the second byte
     572                 :                             // Work around bitmaps that specify too many pixels
     573               0 :                             mState = eRLEStateInitial;
     574               0 :                             PRUint32 pixelsNeeded = NS_MIN<PRUint32>(mBIH.width - mCurPos, mStateData);
     575               0 :                             if (pixelsNeeded) {
     576               0 :                                 PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
     577               0 :                                 mCurPos += pixelsNeeded;
     578               0 :                                 if (mBIH.compression == BI_RLE8) {
     579               0 :                                     do {
     580               0 :                                         SetPixel(d, byte, mColors);
     581               0 :                                         pixelsNeeded --;
     582                 :                                     } while (pixelsNeeded);
     583                 :                                 } else {
     584               0 :                                     do {
     585               0 :                                         Set4BitPixel(d, byte, pixelsNeeded, mColors);
     586                 :                                     } while (pixelsNeeded);
     587                 :                                 }
     588                 :                             }
     589               0 :                             continue;
     590                 :                         }
     591                 : 
     592               0 :                         switch(byte) {
     593                 :                             case RLE_ESCAPE_EOL:
     594                 :                                 // End of Line: Go to next row
     595               0 :                                 mCurLine --;
     596               0 :                                 mCurPos = 0;
     597               0 :                                 mState = eRLEStateInitial;
     598               0 :                                 break;
     599                 : 
     600                 :                             case RLE_ESCAPE_EOF: // EndOfFile
     601               0 :                                 mCurPos = mCurLine = 0;
     602               0 :                                 break;
     603                 : 
     604                 :                             case RLE_ESCAPE_DELTA:
     605               0 :                                 mState = eRLEStateNeedXDelta;
     606               0 :                                 continue;
     607                 : 
     608                 :                             default : // absolute mode
     609                 :                                 // Save the number of pixels to read
     610               0 :                                 mStateData = byte;
     611               0 :                                 if (mCurPos + mStateData > (PRUint32)mBIH.width) {
     612                 :                                     // We can work around bitmaps that specify one
     613                 :                                     // pixel too many, but only if their width is odd.
     614               0 :                                     mStateData -= mBIH.width & 1;
     615               0 :                                     if (mCurPos + mStateData > (PRUint32)mBIH.width) {
     616               0 :                                         PostDataError();
     617               0 :                                         return;
     618                 :                                     }
     619                 :                                 }
     620                 : 
     621                 :                                 // See if we will need to skip a byte
     622                 :                                 // to word align the pixel data
     623                 :                                 // mStateData is a number of pixels
     624                 :                                 // so allow for the RLE compression type
     625                 :                                 // Pixels RLE8=1 RLE4=2
     626                 :                                 //    1    Pad    Pad
     627                 :                                 //    2    No     Pad
     628                 :                                 //    3    Pad    No
     629                 :                                 //    4    No     No
     630               0 :                                 if (((mStateData - 1) & mBIH.compression) != 0)
     631               0 :                                     mState = eRLEStateAbsoluteMode;
     632                 :                                 else
     633               0 :                                     mState = eRLEStateAbsoluteModePadded;
     634               0 :                                 continue;
     635                 :                         }
     636               0 :                         break;
     637                 : 
     638                 :                     case eRLEStateNeedXDelta:
     639                 :                         // Handle the XDelta and proceed to get Y Delta
     640               0 :                         byte = *aBuffer++;
     641               0 :                         aCount--;
     642               0 :                         mCurPos += byte;
     643               0 :                         if (mCurPos > mBIH.width)
     644               0 :                             mCurPos = mBIH.width;
     645                 : 
     646               0 :                         mState = eRLEStateNeedYDelta;
     647               0 :                         continue;
     648                 : 
     649                 :                     case eRLEStateNeedYDelta:
     650                 :                         // Get the Y Delta and then "handle" the move
     651               0 :                         byte = *aBuffer++;
     652               0 :                         aCount--;
     653               0 :                         mState = eRLEStateInitial;
     654               0 :                         mCurLine -= NS_MIN<PRInt32>(byte, mCurLine);
     655               0 :                         break;
     656                 : 
     657                 :                     case eRLEStateAbsoluteMode: // Absolute Mode
     658                 :                     case eRLEStateAbsoluteModePadded:
     659               0 :                         if (mStateData) {
     660                 :                             // In absolute mode, the second byte (mStateData)
     661                 :                             // represents the number of pixels 
     662                 :                             // that follow, each of which contains 
     663                 :                             // the color index of a single pixel.
     664               0 :                             PRUint32* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
     665               0 :                             PRUint32* oldPos = d;
     666               0 :                             if (mBIH.compression == BI_RLE8) {
     667               0 :                                 while (aCount > 0 && mStateData > 0) {
     668               0 :                                     byte = *aBuffer++;
     669               0 :                                     aCount--;
     670               0 :                                     SetPixel(d, byte, mColors);
     671               0 :                                     mStateData--;
     672                 :                                 }
     673                 :                             } else {
     674               0 :                                 while (aCount > 0 && mStateData > 0) {
     675               0 :                                     byte = *aBuffer++;
     676               0 :                                     aCount--;
     677               0 :                                     Set4BitPixel(d, byte, mStateData, mColors);
     678                 :                                 }
     679                 :                             }
     680               0 :                             mCurPos += d - oldPos;
     681                 :                         }
     682                 : 
     683               0 :                         if (mStateData == 0) {
     684                 :                             // In absolute mode, each run must 
     685                 :                             // be aligned on a word boundary
     686                 : 
     687               0 :                             if (mState == eRLEStateAbsoluteMode) { // Word Aligned
     688               0 :                                 mState = eRLEStateInitial;
     689               0 :                             } else if (aCount > 0) {               // Not word Aligned
     690                 :                                 // "next" byte is just a padding byte
     691                 :                                 // so "move" past it and we can continue
     692               0 :                                 aBuffer++;
     693               0 :                                 aCount--;
     694               0 :                                 mState = eRLEStateInitial;
     695                 :                             }
     696                 :                         }
     697                 :                         // else state is still eRLEStateAbsoluteMode
     698               0 :                         continue;
     699                 : 
     700                 :                     default :
     701               0 :                         NS_ABORT_IF_FALSE(0, "BMP RLE decompression: unknown state!");
     702               0 :                         PostDecoderError(NS_ERROR_UNEXPECTED);
     703               0 :                         return;
     704                 :                 }
     705                 :                 // Because of the use of the continue statement
     706                 :                 // we only get here for eol, eof or y delta
     707               0 :                 if (mCurLine == 0) { // Finished last line
     708               0 :                     break;
     709                 :                 }
     710                 :             }
     711                 :         }
     712                 :     }
     713                 : 
     714              14 :     const PRUint32 rows = mOldLine - mCurLine;
     715              14 :     if (rows) {
     716                 : 
     717                 :         // Invalidate
     718                 :         nsIntRect r(0, mBIH.height < 0 ? -mBIH.height - mOldLine : mCurLine,
     719               4 :                     mBIH.width, rows);
     720               4 :         PostInvalidation(r);
     721                 : 
     722               4 :         mOldLine = mCurLine;
     723                 :     }
     724                 : 
     725              14 :     return;
     726                 : }
     727                 : 
     728               4 : void nsBMPDecoder::ProcessFileHeader()
     729                 : {
     730               4 :     memset(&mBFH, 0, sizeof(mBFH));
     731               4 :     memcpy(&mBFH.signature, mRawBuf, sizeof(mBFH.signature));
     732               4 :     memcpy(&mBFH.filesize, mRawBuf + 2, sizeof(mBFH.filesize));
     733               4 :     memcpy(&mBFH.reserved, mRawBuf + 6, sizeof(mBFH.reserved));
     734               4 :     memcpy(&mBFH.dataoffset, mRawBuf + 10, sizeof(mBFH.dataoffset));
     735               4 :     memcpy(&mBFH.bihsize, mRawBuf + 14, sizeof(mBFH.bihsize));
     736                 : 
     737                 :     // Now correct the endianness of the header
     738               4 :     mBFH.filesize = LITTLE_TO_NATIVE32(mBFH.filesize);
     739               4 :     mBFH.dataoffset = LITTLE_TO_NATIVE32(mBFH.dataoffset);
     740               4 :     mBFH.bihsize = LITTLE_TO_NATIVE32(mBFH.bihsize);
     741               4 : }
     742                 : 
     743               4 : void nsBMPDecoder::ProcessInfoHeader()
     744                 : {
     745               4 :     memset(&mBIH, 0, sizeof(mBIH));
     746               4 :     if (mBFH.bihsize == 12) { // OS/2 Bitmap
     747               0 :         memcpy(&mBIH.width, mRawBuf, 2);
     748               0 :         memcpy(&mBIH.height, mRawBuf + 2, 2);
     749               0 :         memcpy(&mBIH.planes, mRawBuf + 4, sizeof(mBIH.planes));
     750               0 :         memcpy(&mBIH.bpp, mRawBuf + 6, sizeof(mBIH.bpp));
     751                 :     }
     752                 :     else {
     753               4 :         memcpy(&mBIH.width, mRawBuf, sizeof(mBIH.width));
     754               4 :         memcpy(&mBIH.height, mRawBuf + 4, sizeof(mBIH.height));
     755               4 :         memcpy(&mBIH.planes, mRawBuf + 8, sizeof(mBIH.planes));
     756               4 :         memcpy(&mBIH.bpp, mRawBuf + 10, sizeof(mBIH.bpp));
     757               4 :         memcpy(&mBIH.compression, mRawBuf + 12, sizeof(mBIH.compression));
     758               4 :         memcpy(&mBIH.image_size, mRawBuf + 16, sizeof(mBIH.image_size));
     759               4 :         memcpy(&mBIH.xppm, mRawBuf + 20, sizeof(mBIH.xppm));
     760               4 :         memcpy(&mBIH.yppm, mRawBuf + 24, sizeof(mBIH.yppm));
     761               4 :         memcpy(&mBIH.colors, mRawBuf + 28, sizeof(mBIH.colors));
     762               4 :         memcpy(&mBIH.important_colors, mRawBuf + 32, sizeof(mBIH.important_colors));
     763                 :     }
     764                 : 
     765                 :     // Convert endianness
     766               4 :     mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
     767               4 :     mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
     768               4 :     mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
     769               4 :     mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
     770                 : 
     771               4 :     mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
     772               4 :     mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
     773               4 :     mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
     774               4 :     mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
     775               4 :     mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
     776               4 :     mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
     777               4 : }
     778                 : 
     779                 : } // namespace image
     780            4392 : } // namespace mozilla

Generated by: LCOV version 1.7