LCOV - code coverage report
Current view: directory - image/encoders/bmp - nsBMPEncoder.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 319 207 64.9 %
Date: 2012-06-02 Functions: 32 24 75.0 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is an implementation of a bitmap encoder.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Brian R. Bondy <netzen@gmail.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsCRT.h"
      39                 : #include "EndianMacros.h"
      40                 : #include "nsBMPEncoder.h"
      41                 : #include "prmem.h"
      42                 : #include "prprf.h"
      43                 : #include "nsString.h"
      44                 : #include "nsStreamUtils.h"
      45                 : #include "nsAutoPtr.h"
      46                 : 
      47                 : using namespace mozilla;
      48                 : 
      49              24 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsBMPEncoder, imgIEncoder, nsIInputStream, nsIAsyncInputStream)
      50                 : 
      51               4 : nsBMPEncoder::nsBMPEncoder() : mImageBufferStart(nsnull), 
      52                 :                                mImageBufferCurr(0),
      53                 :                                mImageBufferSize(0), 
      54                 :                                mImageBufferReadPoint(0), 
      55                 :                                mFinished(false),
      56                 :                                mCallback(nsnull), 
      57                 :                                mCallbackTarget(nsnull), 
      58               4 :                                mNotifyThreshold(0)
      59                 : {
      60               4 : }
      61                 : 
      62               8 : nsBMPEncoder::~nsBMPEncoder()
      63                 : {
      64               4 :   if (mImageBufferStart) {
      65               4 :     moz_free(mImageBufferStart);
      66               4 :     mImageBufferStart = nsnull;
      67               4 :     mImageBufferCurr = nsnull;
      68                 :   }
      69               4 : }
      70                 : 
      71                 : // nsBMPEncoder::InitFromData
      72                 : //
      73                 : // One output option is supported: bpp=<bpp_value>
      74                 : // bpp specifies the bits per pixel to use where bpp_value can be 24 or 32
      75               4 : NS_IMETHODIMP nsBMPEncoder::InitFromData(const PRUint8* aData,
      76                 :                                          PRUint32 aLength, // (unused,
      77                 :                                                            // req'd by JS)
      78                 :                                          PRUint32 aWidth,
      79                 :                                          PRUint32 aHeight,
      80                 :                                          PRUint32 aStride,
      81                 :                                          PRUint32 aInputFormat,
      82                 :                                          const nsAString& aOutputOptions)
      83                 : {
      84                 :   // validate input format
      85               4 :   if (aInputFormat != INPUT_FORMAT_RGB &&
      86                 :       aInputFormat != INPUT_FORMAT_RGBA &&
      87                 :       aInputFormat != INPUT_FORMAT_HOSTARGB) {
      88               0 :     return NS_ERROR_INVALID_ARG;
      89                 :   }
      90                 : 
      91                 :   // Stride is the padded width of each row, so it better be longer
      92               4 :   if ((aInputFormat == INPUT_FORMAT_RGB &&
      93                 :        aStride < aWidth * 3) ||
      94                 :       ((aInputFormat == INPUT_FORMAT_RGBA || aInputFormat == INPUT_FORMAT_HOSTARGB) &&
      95                 :        aStride < aWidth * 4)) {
      96               0 :       NS_WARNING("Invalid stride for InitFromData");
      97               0 :       return NS_ERROR_INVALID_ARG;
      98                 :   }
      99                 : 
     100                 :   nsresult rv;
     101               4 :   rv = StartImageEncode(aWidth, aHeight, aInputFormat, aOutputOptions);
     102               4 :   if (NS_FAILED(rv)) {
     103               0 :     return rv;
     104                 :   }
     105                 : 
     106                 :   rv = AddImageFrame(aData, aLength, aWidth, aHeight, aStride,
     107               4 :                      aInputFormat, aOutputOptions);
     108               4 :   if (NS_FAILED(rv)) {
     109               0 :     return rv;
     110                 :   }
     111                 : 
     112               4 :   rv = EndImageEncode();
     113               4 :   return rv;
     114                 : }
     115                 : 
     116                 : // Just a helper method to make it explicit in calculations that we are dealing
     117                 : // with bytes and not bits
     118                 : static inline PRUint32
     119            4052 : BytesPerPixel(PRUint32 aBPP)
     120                 : {
     121            4052 :   return aBPP / 8;
     122                 : }
     123                 : 
     124                 : // Calculates the number of padding bytes that are needed per row of image data
     125                 : static inline PRUint32
     126             104 : PaddingBytes(PRUint32 aBPP, PRUint32 aWidth)
     127                 : {
     128             104 :   PRUint32 rowSize = aWidth * BytesPerPixel(aBPP);
     129             104 :   PRUint8 paddingSize = 0;
     130             104 :   if(rowSize % 4) {
     131               0 :     paddingSize = (4 - (rowSize % 4));
     132                 :   }
     133             104 :   return paddingSize;
     134                 : }
     135                 : 
     136                 : // See ::InitFromData for other info.
     137               4 : NS_IMETHODIMP nsBMPEncoder::StartImageEncode(PRUint32 aWidth,
     138                 :                                              PRUint32 aHeight,
     139                 :                                              PRUint32 aInputFormat,
     140                 :                                              const nsAString& aOutputOptions)
     141                 : {
     142                 :   // can't initialize more than once
     143               4 :   if (mImageBufferStart || mImageBufferCurr) {
     144               0 :     return NS_ERROR_ALREADY_INITIALIZED;
     145                 :   }
     146                 : 
     147                 :   // validate input format
     148               4 :   if (aInputFormat != INPUT_FORMAT_RGB &&
     149                 :       aInputFormat != INPUT_FORMAT_RGBA &&
     150                 :       aInputFormat != INPUT_FORMAT_HOSTARGB) {
     151               0 :     return NS_ERROR_INVALID_ARG;
     152                 :   }
     153                 : 
     154                 :   // parse and check any provided output options
     155                 :   PRUint32 bpp;
     156               4 :   nsresult rv = ParseOptions(aOutputOptions, &bpp);
     157               4 :   if (NS_FAILED(rv)) {
     158               0 :     return rv;
     159                 :   }
     160                 : 
     161               4 :   InitFileHeader(bpp, aWidth, aHeight);
     162               4 :   InitInfoHeader(bpp, aWidth, aHeight);
     163                 : 
     164               4 :   mImageBufferSize = mBMPFileHeader.filesize;
     165               4 :   mImageBufferStart = static_cast<PRUint8*>(moz_malloc(mImageBufferSize));
     166               4 :   if (!mImageBufferStart) {
     167               0 :     return NS_ERROR_OUT_OF_MEMORY;
     168                 :   }
     169               4 :   mImageBufferCurr = mImageBufferStart;
     170                 : 
     171               4 :   EncodeFileHeader();
     172               4 :   EncodeInfoHeader();
     173                 : 
     174               4 :   return NS_OK;
     175                 : }
     176                 : 
     177                 : // Returns the number of bytes in the image buffer used.
     178                 : // For a BMP file, this is all bytes in the buffer.
     179               4 : NS_IMETHODIMP nsBMPEncoder::GetImageBufferUsed(PRUint32 *aOutputSize)
     180                 : {
     181               4 :   NS_ENSURE_ARG_POINTER(aOutputSize);
     182               4 :   *aOutputSize = mImageBufferSize;
     183               4 :   return NS_OK;
     184                 : }
     185                 : 
     186                 : // Returns a pointer to the start of the image buffer
     187               4 : NS_IMETHODIMP nsBMPEncoder::GetImageBuffer(char **aOutputBuffer)
     188                 : {
     189               4 :   NS_ENSURE_ARG_POINTER(aOutputBuffer);
     190               4 :   *aOutputBuffer = reinterpret_cast<char*>(mImageBufferStart);
     191               4 :   return NS_OK;
     192                 : }
     193                 : 
     194               4 : NS_IMETHODIMP nsBMPEncoder::AddImageFrame(const PRUint8* aData,
     195                 :                                           PRUint32 aLength, // (unused,
     196                 :                                                             // req'd by JS)
     197                 :                                           PRUint32 aWidth,
     198                 :                                           PRUint32 aHeight,
     199                 :                                           PRUint32 aStride,
     200                 :                                           PRUint32 aInputFormat,
     201                 :                                           const nsAString& aFrameOptions)
     202                 : {
     203                 :   // must be initialized
     204               4 :   if (!mImageBufferStart || !mImageBufferCurr) {
     205               0 :     return NS_ERROR_NOT_INITIALIZED;
     206                 :   }
     207                 : 
     208                 :   // validate input format
     209               4 :   if (aInputFormat != INPUT_FORMAT_RGB &&
     210                 :       aInputFormat != INPUT_FORMAT_RGBA &&
     211                 :       aInputFormat != INPUT_FORMAT_HOSTARGB) {
     212               0 :     return NS_ERROR_INVALID_ARG;
     213                 :   }
     214                 : 
     215               4 :   static fallible_t fallible = fallible_t();
     216                 :   nsAutoArrayPtr<PRUint8> row(new (fallible) 
     217                 :                               PRUint8[mBMPInfoHeader.width * 
     218              12 :                               BytesPerPixel(mBMPInfoHeader.bpp)]);
     219               4 :   if (!row) {
     220               0 :     return NS_ERROR_OUT_OF_MEMORY;
     221                 :   }
     222                 : 
     223                 :   // write each row: if we add more input formats, we may want to
     224                 :   // generalize the conversions
     225               4 :   if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
     226                 :     // BMP requires RGBA with post-multiplied alpha, so we need to convert
     227             100 :     for (PRInt32 y = mBMPInfoHeader.height - 1; y >= 0 ; y --) {
     228              96 :       ConvertHostARGBRow(&aData[y * aStride], row, mBMPInfoHeader.width);
     229              96 :       if(mBMPInfoHeader.bpp == 24) {
     230              48 :         EncodeImageDataRow24(row);
     231                 :       } else {
     232              48 :         EncodeImageDataRow32(row);
     233                 :       }
     234                 :     }
     235               0 :   } else if (aInputFormat == INPUT_FORMAT_RGBA) {
     236                 :     // RBGA, but we need to strip the alpha
     237               0 :     for (PRInt32 y = 0; y < mBMPInfoHeader.height; y ++) {
     238               0 :       StripAlpha(&aData[y * aStride], row, mBMPInfoHeader.width);
     239               0 :       if (mBMPInfoHeader.bpp == 24) {
     240               0 :         EncodeImageDataRow24(row);
     241                 :       } else {
     242               0 :         EncodeImageDataRow32(row);
     243                 :       }
     244                 :     }
     245               0 :   } else if (aInputFormat == INPUT_FORMAT_RGB) {
     246                 :     // simple RBG(A), no conversion needed
     247               0 :     for (PRInt32 y = 0; y < mBMPInfoHeader.height; y ++) {
     248               0 :       if (mBMPInfoHeader.bpp == 24) {
     249               0 :         EncodeImageDataRow24(&aData[y * aStride]);
     250                 :       } else { 
     251               0 :         EncodeImageDataRow32(&aData[y * aStride]);
     252                 :       }
     253                 :     }
     254                 :   } else {
     255               0 :     NS_NOTREACHED("Bad format type");
     256               0 :     return NS_ERROR_INVALID_ARG;
     257                 :   }
     258                 : 
     259               4 :   return NS_OK;
     260                 : }
     261                 : 
     262                 : 
     263               4 : NS_IMETHODIMP nsBMPEncoder::EndImageEncode()
     264                 : {
     265                 :   // must be initialized
     266               4 :   if (!mImageBufferStart || !mImageBufferCurr) {
     267               0 :     return NS_ERROR_NOT_INITIALIZED;
     268                 :   }
     269                 : 
     270               4 :   mFinished = true;
     271               4 :   NotifyListener();
     272                 : 
     273                 :   // if output callback can't get enough memory, it will free our buffer
     274               4 :   if (!mImageBufferStart || !mImageBufferCurr) {
     275               0 :     return NS_ERROR_OUT_OF_MEMORY;
     276                 :   }
     277                 : 
     278               4 :   return NS_OK;
     279                 : }
     280                 : 
     281                 : 
     282                 : // Parses the encoder options and sets the bits per pixel to use
     283                 : // See InitFromData for a description of the parse options
     284                 : nsresult
     285               4 : nsBMPEncoder::ParseOptions(const nsAString& aOptions, PRUint32* bpp)
     286                 : {
     287                 :   // If no parsing options just use the default of 24BPP
     288               4 :   if (aOptions.Length() == 0) {
     289               0 :     if (bpp) {
     290               0 :       *bpp = 24;
     291                 :     }
     292               0 :     return NS_OK;
     293                 :   }
     294                 : 
     295                 :   // Parse the input string into a set of name/value pairs.
     296                 :   // From a format like: name=value;bpp=<bpp_value>;name=value
     297                 :   // to format: [0] = name=value, [1] = bpp=<bpp_value>, [2] = name=value
     298               8 :   nsTArray<nsCString> nameValuePairs;
     299               4 :   if (!ParseString(NS_ConvertUTF16toUTF8(aOptions), ';', nameValuePairs)) {
     300               0 :     return NS_ERROR_INVALID_ARG;
     301                 :   }
     302                 : 
     303                 :   // For each name/value pair in the set
     304               8 :   for (PRUint32 i = 0; i < nameValuePairs.Length(); ++i) {
     305                 : 
     306                 :     // Split the name value pair [0] = name, [1] = value
     307               8 :     nsTArray<nsCString> nameValuePair;
     308               4 :     if (!ParseString(nameValuePairs[i], '=', nameValuePair)) {
     309               0 :       return NS_ERROR_INVALID_ARG;
     310                 :     }
     311               4 :     if (nameValuePair.Length() != 2) {
     312               0 :       return NS_ERROR_INVALID_ARG;
     313                 :     }
     314                 : 
     315                 :     // Parse the bpp portion of the string name=value;bpp=<bpp_value>;name=value
     316               4 :     if (nameValuePair[0].Equals("bpp", nsCaseInsensitiveCStringComparator())) {
     317               4 :       if (nameValuePair[1].Equals("24")) {
     318               2 :         *bpp = 24;
     319               2 :       } else if (nameValuePair[1].Equals("32")) {
     320               2 :         *bpp = 32;
     321                 :       } else {
     322               0 :         return NS_ERROR_INVALID_ARG;
     323                 :       }
     324                 :     }
     325                 :   }
     326                 : 
     327               4 :   return NS_OK;
     328                 : }
     329                 : 
     330               0 : NS_IMETHODIMP nsBMPEncoder::Close()
     331                 : {
     332               0 :   if (mImageBufferStart) {
     333               0 :     moz_free(mImageBufferStart);
     334               0 :     mImageBufferStart = nsnull;
     335               0 :     mImageBufferSize = 0;
     336               0 :     mImageBufferReadPoint = 0;
     337               0 :     mImageBufferCurr = nsnull;
     338                 :   }
     339                 : 
     340               0 :   return NS_OK;
     341                 : }
     342                 : 
     343                 : // Obtains the available bytes to read
     344               0 : NS_IMETHODIMP nsBMPEncoder::Available(PRUint32 *_retval)
     345                 : {
     346               0 :   if (!mImageBufferStart || !mImageBufferCurr) {
     347               0 :     return NS_BASE_STREAM_CLOSED;
     348                 :   }
     349                 : 
     350               0 :   *_retval = GetCurrentImageBufferOffset() - mImageBufferReadPoint;
     351               0 :   return NS_OK;
     352                 : }
     353                 : 
     354                 : // [noscript] Reads bytes which are available
     355               0 : NS_IMETHODIMP nsBMPEncoder::Read(char * aBuf, PRUint32 aCount,
     356                 :                                  PRUint32 *_retval)
     357                 : {
     358               0 :   return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
     359                 : }
     360                 : 
     361                 : // [noscript] Reads segments
     362               0 : NS_IMETHODIMP nsBMPEncoder::ReadSegments(nsWriteSegmentFun aWriter,
     363                 :                                          void *aClosure, PRUint32 aCount,
     364                 :                                          PRUint32 *_retval)
     365                 : {
     366               0 :   PRUint32 maxCount = GetCurrentImageBufferOffset() - mImageBufferReadPoint;
     367               0 :   if (maxCount == 0) {
     368               0 :     *_retval = 0;
     369               0 :     return mFinished ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
     370                 :   }
     371                 : 
     372               0 :   if (aCount > maxCount) {
     373               0 :     aCount = maxCount;
     374                 :   }
     375                 :   nsresult rv = aWriter(this, aClosure,
     376                 :                         reinterpret_cast<const char*>(mImageBufferStart + 
     377                 :                                                       mImageBufferReadPoint),
     378               0 :                         0, aCount, _retval);
     379               0 :   if (NS_SUCCEEDED(rv)) {
     380               0 :     NS_ASSERTION(*_retval <= aCount, "bad write count");
     381               0 :     mImageBufferReadPoint += *_retval;
     382                 :   }
     383                 :   // errors returned from the writer end here!
     384               0 :   return NS_OK;
     385                 : }
     386                 : 
     387                 : NS_IMETHODIMP 
     388               0 : nsBMPEncoder::IsNonBlocking(bool *_retval)
     389                 : {
     390               0 :   *_retval = true;
     391               0 :   return NS_OK;
     392                 : }
     393                 : 
     394                 : NS_IMETHODIMP 
     395               0 : nsBMPEncoder::AsyncWait(nsIInputStreamCallback *aCallback,
     396                 :                         PRUint32 aFlags,
     397                 :                         PRUint32 aRequestedCount,
     398                 :                         nsIEventTarget *aTarget)
     399                 : {
     400               0 :   if (aFlags != 0) {
     401               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     402                 :   }
     403                 : 
     404               0 :   if (mCallback || mCallbackTarget) {
     405               0 :     return NS_ERROR_UNEXPECTED;
     406                 :   }
     407                 : 
     408               0 :   mCallbackTarget = aTarget;
     409                 :   // 0 means "any number of bytes except 0"
     410               0 :   mNotifyThreshold = aRequestedCount;
     411               0 :   if (!aRequestedCount) {
     412               0 :     mNotifyThreshold = 1024; // We don't want to notify incessantly
     413                 :   }
     414                 : 
     415                 :   // We set the callback absolutely last, because NotifyListener uses it to
     416                 :   // determine if someone needs to be notified.  If we don't set it last,
     417                 :   // NotifyListener might try to fire off a notification to a null target
     418                 :   // which will generally cause non-threadsafe objects to be used off the main thread
     419               0 :   mCallback = aCallback;
     420                 : 
     421                 :   // What we are being asked for may be present already
     422               0 :   NotifyListener();
     423               0 :   return NS_OK;
     424                 : }
     425                 : 
     426               0 : NS_IMETHODIMP nsBMPEncoder::CloseWithStatus(nsresult aStatus)
     427                 : {
     428               0 :   return Close();
     429                 : }
     430                 : 
     431                 : // nsBMPEncoder::ConvertHostARGBRow
     432                 : //
     433                 : //    Our colors are stored with premultiplied alphas, but we need
     434                 : //    an output with no alpha in machine-independent byte order.
     435                 : //
     436                 : void
     437              96 : nsBMPEncoder::ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest,
     438                 :                                  PRUint32 aPixelWidth)
     439                 : {
     440              96 :   int bytes = BytesPerPixel(mBMPInfoHeader.bpp);
     441                 : 
     442              96 :   if (mBMPInfoHeader.bpp == 32) {
     443            1328 :     for (PRUint32 x = 0; x < aPixelWidth; x++) {
     444            1280 :       const PRUint32& pixelIn = ((const PRUint32*)(aSrc))[x];
     445            1280 :       PRUint8 *pixelOut = &aDest[x * bytes];
     446                 : 
     447            1280 :       pixelOut[0] = (pixelIn & 0x00ff0000) >> 16;
     448            1280 :       pixelOut[1] = (pixelIn & 0x0000ff00) >>  8;
     449            1280 :       pixelOut[2] = (pixelIn & 0x000000ff) >>  0;
     450            1280 :       pixelOut[3] = (pixelIn & 0xff000000) >> 24;
     451                 :     }
     452                 :   } else {
     453            1328 :     for (PRUint32 x = 0; x < aPixelWidth; x++) {
     454            1280 :       const PRUint32& pixelIn = ((const PRUint32*)(aSrc))[x];
     455            1280 :       PRUint8 *pixelOut = &aDest[x * bytes];
     456                 : 
     457            1280 :       pixelOut[0] = (pixelIn & 0xff0000) >> 16;
     458            1280 :       pixelOut[1] = (pixelIn & 0x00ff00) >>  8;
     459            1280 :       pixelOut[2] = (pixelIn & 0x0000ff) >>  0;
     460                 :     }
     461                 :   }
     462              96 : }
     463                 : 
     464                 : // nsBMPEncoder::StripAlpha
     465                 : //
     466                 : //    Input is RGBA, output is RGB
     467                 : void
     468               0 : nsBMPEncoder::StripAlpha(const PRUint8* aSrc, PRUint8* aDest,
     469                 :                          PRUint32 aPixelWidth)
     470                 : {
     471               0 :   for (PRUint32 x = 0; x < aPixelWidth; x ++) {
     472               0 :     const PRUint8* pixelIn = &aSrc[x * 4];
     473               0 :     PRUint8* pixelOut = &aDest[x * 3];
     474               0 :     pixelOut[0] = pixelIn[0];
     475               0 :     pixelOut[1] = pixelIn[1];
     476               0 :     pixelOut[2] = pixelIn[2];
     477                 :   }
     478               0 : }
     479                 : 
     480                 : void
     481               4 : nsBMPEncoder::NotifyListener()
     482                 : {
     483               4 :   if (mCallback &&
     484               0 :       (GetCurrentImageBufferOffset() - mImageBufferReadPoint >= 
     485               4 :        mNotifyThreshold || mFinished)) {
     486               0 :     nsCOMPtr<nsIInputStreamCallback> callback;
     487               0 :     if (mCallbackTarget) {
     488               0 :       NS_NewInputStreamReadyEvent(getter_AddRefs(callback),
     489                 :                                   mCallback,
     490               0 :                                   mCallbackTarget);
     491                 :     } else {
     492               0 :       callback = mCallback;
     493                 :     }
     494                 : 
     495               0 :     NS_ASSERTION(callback, "Shouldn't fail to make the callback");
     496                 :     // Null the callback first because OnInputStreamReady could
     497                 :     // reenter AsyncWait
     498               0 :     mCallback = nsnull;
     499               0 :     mCallbackTarget = nsnull;
     500               0 :     mNotifyThreshold = 0;
     501                 : 
     502               0 :     callback->OnInputStreamReady(this);
     503                 :   }
     504               4 : }
     505                 : 
     506                 : // Initializes the BMP file header mBMPFileHeader to the passed in values
     507                 : void 
     508               4 : nsBMPEncoder::InitFileHeader(PRUint32 aBPP, PRUint32 aWidth, PRUint32 aHeight)
     509                 : {
     510               4 :   memset(&mBMPFileHeader, 0, sizeof(mBMPFileHeader));
     511               4 :   mBMPFileHeader.signature[0] = 'B';
     512               4 :   mBMPFileHeader.signature[1] = 'M';
     513                 :   
     514               4 :   mBMPFileHeader.dataoffset = WIN_HEADER_LENGTH;
     515                 : 
     516                 :   // The color table is present only if BPP is <= 8
     517               4 :   if (aBPP <= 8) {
     518               0 :     PRUint32 numColors = 1 << aBPP;
     519               0 :     mBMPFileHeader.dataoffset += 4 * numColors;
     520               0 :     mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + aWidth * aHeight;
     521                 :   } else {
     522                 :     mBMPFileHeader.filesize = mBMPFileHeader.dataoffset + (aWidth * 
     523               8 :                               BytesPerPixel(aBPP) + PaddingBytes(aBPP, aWidth)) *
     524              12 :                               aHeight;
     525                 :   }
     526                 : 
     527               4 :   mBMPFileHeader.reserved = 0;
     528               4 :   mBMPFileHeader.bihsize = WIN_BIH_LENGTH;
     529               4 : }
     530                 : 
     531                 : // Initializes the bitmap info header mBMPInfoHeader to the passed in values
     532                 : void 
     533               4 : nsBMPEncoder::InitInfoHeader(PRUint32 aBPP, PRUint32 aWidth, PRUint32 aHeight)
     534                 : {
     535               4 :   memset(&mBMPInfoHeader, 0, sizeof(mBMPInfoHeader));
     536               4 :   mBMPInfoHeader.bpp =  aBPP;
     537               4 :   mBMPInfoHeader.planes = 1;
     538               4 :   mBMPInfoHeader.colors = 0;
     539               4 :   mBMPInfoHeader.important_colors = 0;
     540               4 :   mBMPInfoHeader.width = aWidth;
     541               4 :   mBMPInfoHeader.height = aHeight;
     542               4 :   mBMPInfoHeader.compression = 0;
     543               4 :   if (aBPP <= 8) {
     544               0 :     mBMPInfoHeader.image_size = aWidth * aHeight;
     545                 :   } else {
     546               4 :     mBMPInfoHeader.image_size = (aWidth * BytesPerPixel(aBPP) + 
     547               4 :                                  PaddingBytes(aBPP, aWidth)) * aHeight;
     548                 :   }
     549               4 :   mBMPInfoHeader.xppm = 0;
     550               4 :   mBMPInfoHeader.yppm = 0;
     551               4 : }
     552                 : 
     553                 : // Encodes the BMP file header mBMPFileHeader
     554                 : void 
     555               4 : nsBMPEncoder::EncodeFileHeader() 
     556                 : {  
     557               4 :   mozilla::image::BMPFILEHEADER littleEndianBFH = mBMPFileHeader;
     558               4 :   littleEndianBFH.filesize = NATIVE32_TO_LITTLE(littleEndianBFH.filesize);
     559               4 :   littleEndianBFH.reserved = NATIVE32_TO_LITTLE(littleEndianBFH.reserved);
     560               4 :   littleEndianBFH.dataoffset= NATIVE32_TO_LITTLE(littleEndianBFH.dataoffset);
     561               4 :   littleEndianBFH.bihsize = NATIVE32_TO_LITTLE(littleEndianBFH.bihsize);
     562                 : 
     563                 :   memcpy(mImageBufferCurr, &littleEndianBFH.signature, 
     564               4 :          sizeof(littleEndianBFH.signature));
     565               4 :   mImageBufferCurr += sizeof(littleEndianBFH.signature);
     566                 :   memcpy(mImageBufferCurr, &littleEndianBFH.filesize, 
     567               4 :          sizeof(littleEndianBFH.filesize));
     568               4 :   mImageBufferCurr += sizeof(littleEndianBFH.filesize);
     569                 :   memcpy(mImageBufferCurr, &littleEndianBFH.reserved, 
     570               4 :          sizeof(littleEndianBFH.reserved));
     571               4 :   mImageBufferCurr += sizeof(littleEndianBFH.reserved);
     572                 :   memcpy(mImageBufferCurr, &littleEndianBFH.dataoffset, 
     573               4 :          sizeof(littleEndianBFH.dataoffset));
     574               4 :   mImageBufferCurr += sizeof(littleEndianBFH.dataoffset);
     575                 :   memcpy(mImageBufferCurr, &littleEndianBFH.bihsize, 
     576               4 :          sizeof(littleEndianBFH.bihsize));
     577               4 :   mImageBufferCurr += sizeof(littleEndianBFH.bihsize);
     578               4 : }
     579                 : 
     580                 : // Encodes the BMP infor header mBMPInfoHeader
     581                 : void 
     582               4 : nsBMPEncoder::EncodeInfoHeader()
     583                 : {
     584               4 :   mozilla::image::BMPINFOHEADER littleEndianmBIH = mBMPInfoHeader;
     585               4 :   littleEndianmBIH.width =  NATIVE32_TO_LITTLE(littleEndianmBIH.width);
     586               4 :   littleEndianmBIH.height = NATIVE32_TO_LITTLE(littleEndianmBIH.height); 
     587               4 :   littleEndianmBIH.planes = NATIVE16_TO_LITTLE(littleEndianmBIH.planes);
     588               4 :   littleEndianmBIH.bpp = NATIVE16_TO_LITTLE(littleEndianmBIH.bpp);
     589                 :   littleEndianmBIH.compression = NATIVE32_TO_LITTLE(
     590               4 :                                  littleEndianmBIH.compression);
     591                 :   littleEndianmBIH.image_size = NATIVE32_TO_LITTLE(
     592               4 :                                 littleEndianmBIH.image_size);
     593               4 :   littleEndianmBIH.xppm = NATIVE32_TO_LITTLE(littleEndianmBIH.xppm);
     594               4 :   littleEndianmBIH.yppm = NATIVE32_TO_LITTLE(littleEndianmBIH.yppm);
     595               4 :   littleEndianmBIH.colors = NATIVE32_TO_LITTLE(littleEndianmBIH.colors);
     596                 :   littleEndianmBIH.important_colors = NATIVE32_TO_LITTLE(
     597               4 :                                       littleEndianmBIH.important_colors);
     598                 : 
     599               4 :   if (mBMPFileHeader.bihsize == 12) { // OS/2 Bitmap
     600               0 :     memcpy(mImageBufferCurr, &littleEndianmBIH.width, 2);
     601               0 :     mImageBufferCurr += 2; // Uint16 in OS/2 BMPs
     602               0 :     memcpy(mImageBufferCurr, &littleEndianmBIH.height, 2);
     603               0 :     mImageBufferCurr += 2; // Uint16 in OS/2 BMPs
     604                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.planes, 
     605               0 :            sizeof(littleEndianmBIH.planes));
     606               0 :     mImageBufferCurr += sizeof(littleEndianmBIH.planes);
     607                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.bpp, 
     608               0 :            sizeof(littleEndianmBIH.bpp));
     609               0 :     mImageBufferCurr += sizeof(littleEndianmBIH.bpp);
     610                 :   }
     611                 :   else {
     612                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.width, 
     613               4 :            sizeof(littleEndianmBIH.width));
     614               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.width);
     615                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.height, 
     616               4 :            sizeof(littleEndianmBIH.height));
     617               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.height);
     618                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.planes, 
     619               4 :            sizeof(littleEndianmBIH.planes));
     620               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.planes);
     621                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.bpp, 
     622               4 :            sizeof(littleEndianmBIH.bpp));
     623               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.bpp);
     624                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.compression, 
     625               4 :            sizeof(littleEndianmBIH.compression));
     626               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.compression);
     627                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.image_size, 
     628               4 :            sizeof(littleEndianmBIH.image_size));
     629               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.image_size);
     630                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.xppm, 
     631               4 :            sizeof(littleEndianmBIH.xppm));
     632               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.xppm);
     633                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.yppm, 
     634               4 :            sizeof(littleEndianmBIH.yppm));
     635               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.yppm);
     636                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.colors, 
     637               4 :            sizeof(littleEndianmBIH.colors));
     638               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.colors);
     639                 :     memcpy(mImageBufferCurr, &littleEndianmBIH.important_colors, 
     640               4 :            sizeof(littleEndianmBIH.important_colors));
     641               4 :     mImageBufferCurr += sizeof(littleEndianmBIH.important_colors);
     642                 :   }
     643               4 : }
     644                 : 
     645                 : // Sets a pixel in the image buffer that doesn't have alpha data
     646                 : static inline void 
     647            1280 :   SetPixel24(PRUint8*& imageBufferCurr, PRUint8 aRed, PRUint8 aGreen, 
     648                 :   PRUint8 aBlue)
     649                 : {
     650            1280 :   *imageBufferCurr = aBlue;
     651            1280 :   *(imageBufferCurr + 1) = aGreen;
     652            1280 :   *(imageBufferCurr + 2) = aRed;
     653            1280 : }
     654                 : 
     655                 : // Sets a pixel in the image buffer with alpha data
     656                 : static inline void 
     657            1280 : SetPixel32(PRUint8*& imageBufferCurr, PRUint8 aRed, PRUint8 aGreen, 
     658                 :            PRUint8 aBlue, PRUint8 aAlpha = 0xFF)
     659                 : {
     660            1280 :   *imageBufferCurr = aBlue;
     661            1280 :   *(imageBufferCurr + 1) = aGreen;
     662            1280 :   *(imageBufferCurr + 2) = aRed;
     663            1280 :   *(imageBufferCurr + 3) = aAlpha;
     664            1280 : }
     665                 : 
     666                 : // Encodes a row of image data which does not have alpha data
     667                 : void 
     668              48 : nsBMPEncoder::EncodeImageDataRow24(const PRUint8* aData)
     669                 : {
     670            1328 :   for (PRInt32 x = 0; x < mBMPInfoHeader.width; x ++) {
     671            1280 :     PRUint32 pos = x * BytesPerPixel(mBMPInfoHeader.bpp);
     672            1280 :     SetPixel24(mImageBufferCurr, aData[pos], aData[pos + 1], aData[pos + 2]);
     673            1280 :     mImageBufferCurr += BytesPerPixel(mBMPInfoHeader.bpp);
     674                 :   }
     675                 :   
     676              96 :   for (PRUint32 x = 0; x < PaddingBytes(mBMPInfoHeader.bpp, 
     677              48 :                                         mBMPInfoHeader.width); x ++) {
     678               0 :     *mImageBufferCurr++ = 0;
     679                 :   }
     680              48 : }
     681                 : 
     682                 : // Encodes a row of image data which does have alpha data
     683                 : void 
     684              48 : nsBMPEncoder::EncodeImageDataRow32(const PRUint8* aData)
     685                 : {
     686            1328 :   for (PRInt32 x = 0; x < mBMPInfoHeader.width; x ++) {
     687            1280 :     PRUint32 pos = x * BytesPerPixel(mBMPInfoHeader.bpp);
     688            2560 :     SetPixel32(mImageBufferCurr, aData[pos], aData[pos + 1], 
     689            3840 :                aData[pos + 2], aData[pos + 3]);
     690            1280 :     mImageBufferCurr += 4;
     691                 :   }
     692                 : 
     693              96 :   for (PRUint32 x = 0; x < PaddingBytes(mBMPInfoHeader.bpp, 
     694              48 :                                         mBMPInfoHeader.width); x ++) {
     695               0 :     *mImageBufferCurr++ = 0;
     696                 :   }
     697              48 : }

Generated by: LCOV version 1.7