image/encoders/bmp/nsBMPEncoder.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial