LCOV - code coverage report
Current view: directory - image/encoders/jpeg - nsJPEGEncoder.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 207 95 45.9 %
Date: 2012-06-02 Functions: 25 13 52.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       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 JPEG Encoding code
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Google Inc.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Brett Wilson <brettw@gmail.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsJPEGEncoder.h"
      40                 : #include "prmem.h"
      41                 : #include "prprf.h"
      42                 : #include "nsString.h"
      43                 : #include "nsStreamUtils.h"
      44                 : #include "gfxColor.h"
      45                 : 
      46                 : #include <setjmp.h>
      47                 : #include "jerror.h"
      48                 : 
      49                 : using namespace mozilla;
      50                 : 
      51              93 : NS_IMPL_THREADSAFE_ISUPPORTS3(nsJPEGEncoder, imgIEncoder, nsIInputStream, nsIAsyncInputStream)
      52                 : 
      53                 : // used to pass error info through the JPEG library
      54                 : struct encoder_error_mgr {
      55                 :   jpeg_error_mgr pub;
      56                 :   jmp_buf setjmp_buffer;
      57                 : };
      58                 : 
      59               3 : nsJPEGEncoder::nsJPEGEncoder() : mFinished(false),
      60                 :                                  mImageBuffer(nsnull), mImageBufferSize(0),
      61                 :                                  mImageBufferUsed(0), mImageBufferReadPoint(0),
      62                 :                                  mCallback(nsnull),
      63                 :                                  mCallbackTarget(nsnull), mNotifyThreshold(0),
      64               3 :                                  mReentrantMonitor("nsJPEGEncoder.mReentrantMonitor")
      65                 : {
      66               3 : }
      67                 : 
      68               6 : nsJPEGEncoder::~nsJPEGEncoder()
      69                 : {
      70               3 :   if (mImageBuffer) {
      71               3 :     PR_Free(mImageBuffer);
      72               3 :     mImageBuffer = nsnull;
      73                 :   }
      74               3 : }
      75                 : 
      76                 : 
      77                 : // nsJPEGEncoder::InitFromData
      78                 : //
      79                 : //    One output option is supported: "quality=X" where X is an integer in the
      80                 : //    range 0-100. Higher values for X give better quality.
      81                 : //
      82                 : //    Transparency is always discarded.
      83                 : 
      84               3 : NS_IMETHODIMP nsJPEGEncoder::InitFromData(const PRUint8* aData,
      85                 :                                           PRUint32 aLength, // (unused, req'd by JS)
      86                 :                                           PRUint32 aWidth,
      87                 :                                           PRUint32 aHeight,
      88                 :                                           PRUint32 aStride,
      89                 :                                           PRUint32 aInputFormat,
      90                 :                                           const nsAString& aOutputOptions)
      91                 : {
      92               3 :   NS_ENSURE_ARG(aData);
      93                 : 
      94                 :   // validate input format
      95               3 :   if (aInputFormat != INPUT_FORMAT_RGB &&
      96                 :       aInputFormat != INPUT_FORMAT_RGBA &&
      97                 :       aInputFormat != INPUT_FORMAT_HOSTARGB)
      98               0 :     return NS_ERROR_INVALID_ARG;
      99                 : 
     100                 :   // Stride is the padded width of each row, so it better be longer (I'm afraid
     101                 :   // people will not understand what stride means, so check it well)
     102               3 :   if ((aInputFormat == INPUT_FORMAT_RGB &&
     103                 :        aStride < aWidth * 3) ||
     104                 :       ((aInputFormat == INPUT_FORMAT_RGBA || aInputFormat == INPUT_FORMAT_HOSTARGB) &&
     105                 :        aStride < aWidth * 4)) {
     106               0 :     NS_WARNING("Invalid stride for InitFromData");
     107               0 :     return NS_ERROR_INVALID_ARG;
     108                 :   }
     109                 : 
     110                 :   // can't initialize more than once
     111               3 :   if (mImageBuffer != nsnull)
     112               0 :     return NS_ERROR_ALREADY_INITIALIZED;
     113                 : 
     114                 :   // options: we only have one option so this is easy
     115               3 :   int quality = 92;
     116               3 :   if (aOutputOptions.Length() > 0) {
     117                 :     // have options string
     118               0 :     const nsString qualityPrefix(NS_LITERAL_STRING("quality="));
     119               0 :     if (aOutputOptions.Length() > qualityPrefix.Length()  &&
     120               0 :         StringBeginsWith(aOutputOptions, qualityPrefix)) {
     121                 :       // have quality string
     122                 :       nsCString value = NS_ConvertUTF16toUTF8(Substring(aOutputOptions,
     123               0 :                                                         qualityPrefix.Length()));
     124               0 :       int newquality = -1;
     125               0 :       if (PR_sscanf(value.get(), "%d", &newquality) == 1) {
     126               0 :         if (newquality >= 0 && newquality <= 100) {
     127               0 :           quality = newquality;
     128                 :         } else {
     129               0 :           NS_WARNING("Quality value out of range, should be 0-100, using default");
     130                 :         }
     131                 :       } else {
     132               0 :         NS_WARNING("Quality value invalid, should be integer 0-100, using default");
     133                 :       }
     134                 :     }
     135                 :     else {
     136               0 :       return NS_ERROR_INVALID_ARG;
     137                 :     }
     138                 :   }
     139                 : 
     140                 :   jpeg_compress_struct cinfo;
     141                 : 
     142                 :   // We set up the normal JPEG error routines, then override error_exit.
     143                 :   // This must be done before the call to create_compress
     144                 :   encoder_error_mgr errmgr;
     145               3 :   cinfo.err = jpeg_std_error(&errmgr.pub);
     146               3 :   errmgr.pub.error_exit = errorExit;
     147                 :   // Establish the setjmp return context for my_error_exit to use.
     148               3 :   if (setjmp(errmgr.setjmp_buffer)) {
     149                 :     // If we get here, the JPEG code has signaled an error.
     150                 :     // We need to clean up the JPEG object, close the input file, and return.
     151               0 :     return NS_ERROR_FAILURE;
     152                 :   }
     153                 : 
     154               3 :   jpeg_create_compress(&cinfo);
     155               3 :   cinfo.image_width = aWidth;
     156               3 :   cinfo.image_height = aHeight;
     157               3 :   cinfo.input_components = 3;
     158               3 :   cinfo.in_color_space = JCS_RGB;
     159               3 :   cinfo.data_precision = 8;
     160                 : 
     161               3 :   jpeg_set_defaults(&cinfo);
     162               3 :   jpeg_set_quality(&cinfo, quality, 1); // quality here is 0-100
     163               3 :   if (quality >= 90) {
     164                 :     int i;
     165              33 :     for (i=0; i < MAX_COMPONENTS; i++) {
     166              30 :       cinfo.comp_info[i].h_samp_factor=1;
     167              30 :       cinfo.comp_info[i].v_samp_factor=1;
     168                 :     }
     169                 :   }
     170                 : 
     171                 :   // set up the destination manager
     172                 :   jpeg_destination_mgr destmgr;
     173               3 :   destmgr.init_destination = initDestination;
     174               3 :   destmgr.empty_output_buffer = emptyOutputBuffer;
     175               3 :   destmgr.term_destination = termDestination;
     176               3 :   cinfo.dest = &destmgr;
     177               3 :   cinfo.client_data = this;
     178                 : 
     179               3 :   jpeg_start_compress(&cinfo, 1);
     180                 : 
     181                 :   // feed it the rows
     182               3 :   if (aInputFormat == INPUT_FORMAT_RGB) {
     183               0 :     while (cinfo.next_scanline < cinfo.image_height) {
     184               0 :       const PRUint8* row = &aData[cinfo.next_scanline * aStride];
     185               0 :       jpeg_write_scanlines(&cinfo, const_cast<PRUint8**>(&row), 1);
     186                 :     }
     187               3 :   } else if (aInputFormat == INPUT_FORMAT_RGBA) {
     188               0 :     PRUint8* row = new PRUint8[aWidth * 3];
     189               0 :     while (cinfo.next_scanline < cinfo.image_height) {
     190               0 :       ConvertRGBARow(&aData[cinfo.next_scanline * aStride], row, aWidth);
     191               0 :       jpeg_write_scanlines(&cinfo, &row, 1);
     192                 :     }
     193               0 :     delete[] row;
     194               3 :   } else if (aInputFormat == INPUT_FORMAT_HOSTARGB) {
     195               6 :     PRUint8* row = new PRUint8[aWidth * 3];
     196             150 :     while (cinfo.next_scanline < cinfo.image_height) {
     197             144 :       ConvertHostARGBRow(&aData[cinfo.next_scanline * aStride], row, aWidth);
     198             144 :       jpeg_write_scanlines(&cinfo, &row, 1);
     199                 :     }
     200               3 :     delete[] row;
     201                 :   }
     202                 : 
     203               3 :   jpeg_finish_compress(&cinfo);
     204               3 :   jpeg_destroy_compress(&cinfo);
     205                 : 
     206               3 :   mFinished = true;
     207               3 :   NotifyListener();
     208                 : 
     209                 :   // if output callback can't get enough memory, it will free our buffer
     210               3 :   if (!mImageBuffer)
     211               0 :     return NS_ERROR_OUT_OF_MEMORY;
     212                 : 
     213               3 :   return NS_OK;
     214                 : }
     215                 : 
     216                 : 
     217               0 : NS_IMETHODIMP nsJPEGEncoder::StartImageEncode(PRUint32 aWidth,
     218                 :                                               PRUint32 aHeight,
     219                 :                                               PRUint32 aInputFormat,
     220                 :                                               const nsAString& aOutputOptions)
     221                 : {
     222               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     223                 : }
     224                 : 
     225                 : // Returns the number of bytes in the image buffer used.
     226               0 : NS_IMETHODIMP nsJPEGEncoder::GetImageBufferUsed(PRUint32 *aOutputSize)
     227                 : {
     228               0 :   NS_ENSURE_ARG_POINTER(aOutputSize);
     229               0 :   *aOutputSize = mImageBufferUsed;
     230               0 :   return NS_OK;
     231                 : }
     232                 : 
     233                 : // Returns a pointer to the start of the image buffer
     234               0 : NS_IMETHODIMP nsJPEGEncoder::GetImageBuffer(char **aOutputBuffer)
     235                 : {
     236               0 :   NS_ENSURE_ARG_POINTER(aOutputBuffer);
     237               0 :   *aOutputBuffer = reinterpret_cast<char*>(mImageBuffer);
     238               0 :   return NS_OK;
     239                 : }
     240                 : 
     241               0 : NS_IMETHODIMP nsJPEGEncoder::AddImageFrame(const PRUint8* aData,
     242                 :                                            PRUint32 aLength,
     243                 :                                            PRUint32 aWidth,
     244                 :                                            PRUint32 aHeight,
     245                 :                                            PRUint32 aStride,
     246                 :                                            PRUint32 aFrameFormat,
     247                 :                                            const nsAString& aFrameOptions)
     248                 : {
     249               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     250                 : }
     251                 : 
     252               0 : NS_IMETHODIMP nsJPEGEncoder::EndImageEncode()
     253                 : {
     254               0 :   return NS_ERROR_NOT_IMPLEMENTED;
     255                 : }
     256                 : 
     257                 : 
     258                 : /* void close (); */
     259               0 : NS_IMETHODIMP nsJPEGEncoder::Close()
     260                 : {
     261               0 :   if (mImageBuffer != nsnull) {
     262               0 :     PR_Free(mImageBuffer);
     263               0 :     mImageBuffer = nsnull;
     264               0 :     mImageBufferSize = 0;
     265               0 :     mImageBufferUsed = 0;
     266               0 :     mImageBufferReadPoint = 0;
     267                 :   }
     268               0 :   return NS_OK;
     269                 : }
     270                 : 
     271                 : /* unsigned long available (); */
     272               3 : NS_IMETHODIMP nsJPEGEncoder::Available(PRUint32 *_retval)
     273                 : {
     274               3 :   if (!mImageBuffer)
     275               0 :     return NS_BASE_STREAM_CLOSED;
     276                 : 
     277               3 :   *_retval = mImageBufferUsed - mImageBufferReadPoint;
     278               3 :   return NS_OK;
     279                 : }
     280                 : 
     281                 : /* [noscript] unsigned long read (in charPtr aBuf, in unsigned long aCount); */
     282             565 : NS_IMETHODIMP nsJPEGEncoder::Read(char * aBuf, PRUint32 aCount,
     283                 :                                   PRUint32 *_retval)
     284                 : {
     285             565 :   return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
     286                 : }
     287                 : 
     288                 : /* [noscript] unsigned long readSegments (in nsWriteSegmentFun aWriter, in voidPtr aClosure, in unsigned long aCount); */
     289             565 : NS_IMETHODIMP nsJPEGEncoder::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, PRUint32 aCount, PRUint32 *_retval)
     290                 : {
     291                 :   // Avoid another thread reallocing the buffer underneath us
     292            1130 :   ReentrantMonitorAutoEnter autoEnter(mReentrantMonitor);
     293                 : 
     294             565 :   PRUint32 maxCount = mImageBufferUsed - mImageBufferReadPoint;
     295             565 :   if (maxCount == 0) {
     296               0 :     *_retval = 0;
     297               0 :     return mFinished ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
     298                 :   }
     299                 : 
     300             565 :   if (aCount > maxCount)
     301               0 :     aCount = maxCount;
     302                 :   nsresult rv = aWriter(this, aClosure,
     303                 :                         reinterpret_cast<const char*>(mImageBuffer+mImageBufferReadPoint),
     304             565 :                         0, aCount, _retval);
     305             565 :   if (NS_SUCCEEDED(rv)) {
     306             565 :     NS_ASSERTION(*_retval <= aCount, "bad write count");
     307             565 :     mImageBufferReadPoint += *_retval;
     308                 :   }
     309                 : 
     310                 :   // errors returned from the writer end here!
     311             565 :   return NS_OK;
     312                 : }
     313                 : 
     314                 : /* boolean isNonBlocking (); */
     315               0 : NS_IMETHODIMP nsJPEGEncoder::IsNonBlocking(bool *_retval)
     316                 : {
     317               0 :   *_retval = true;
     318               0 :   return NS_OK;
     319                 : }
     320                 : 
     321               0 : NS_IMETHODIMP nsJPEGEncoder::AsyncWait(nsIInputStreamCallback *aCallback,
     322                 :                                        PRUint32 aFlags,
     323                 :                                        PRUint32 aRequestedCount,
     324                 :                                        nsIEventTarget *aTarget)
     325                 : {
     326               0 :   if (aFlags != 0)
     327               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     328                 : 
     329               0 :   if (mCallback || mCallbackTarget)
     330               0 :     return NS_ERROR_UNEXPECTED;
     331                 : 
     332               0 :   mCallbackTarget = aTarget;
     333                 :   // 0 means "any number of bytes except 0"
     334               0 :   mNotifyThreshold = aRequestedCount;
     335               0 :   if (!aRequestedCount)
     336               0 :     mNotifyThreshold = 1024; // 1 KB seems good.  We don't want to notify incessantly
     337                 : 
     338                 :   // We set the callback absolutely last, because NotifyListener uses it to
     339                 :   // determine if someone needs to be notified.  If we don't set it last,
     340                 :   // NotifyListener might try to fire off a notification to a null target
     341                 :   // which will generally cause non-threadsafe objects to be used off the main thread
     342               0 :   mCallback = aCallback;
     343                 : 
     344                 :   // What we are being asked for may be present already
     345               0 :   NotifyListener();
     346               0 :   return NS_OK;
     347                 : }
     348                 : 
     349               0 : NS_IMETHODIMP nsJPEGEncoder::CloseWithStatus(nsresult aStatus)
     350                 : {
     351               0 :   return Close();
     352                 : }
     353                 : 
     354                 : 
     355                 : 
     356                 : // nsJPEGEncoder::ConvertHostARGBRow
     357                 : //
     358                 : //    Our colors are stored with premultiplied alphas, but we need
     359                 : //    an output with no alpha in machine-independent byte order.
     360                 : //
     361                 : //    See gfx/cairo/cairo/src/cairo-png.c
     362                 : void
     363             144 : nsJPEGEncoder::ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest,
     364                 :                                   PRUint32 aPixelWidth)
     365                 : {
     366            8592 :   for (PRUint32 x = 0; x < aPixelWidth; x++) {
     367            8448 :     const PRUint32& pixelIn = ((const PRUint32*)(aSrc))[x];
     368            8448 :     PRUint8 *pixelOut = &aDest[x * 3];
     369                 : 
     370            8448 :     pixelOut[0] = (pixelIn & 0xff0000) >> 16;
     371            8448 :     pixelOut[1] = (pixelIn & 0x00ff00) >>  8;
     372            8448 :     pixelOut[2] = (pixelIn & 0x0000ff) >>  0;
     373                 :   }
     374             144 : }
     375                 : 
     376                 : /**
     377                 :  * nsJPEGEncoder::ConvertRGBARow
     378                 :  *
     379                 :  * Input is RGBA, output is RGB, so we should alpha-premultiply.
     380                 :  */
     381                 : void
     382               0 : nsJPEGEncoder::ConvertRGBARow(const PRUint8* aSrc, PRUint8* aDest,
     383                 :                               PRUint32 aPixelWidth)
     384                 : {
     385               0 :   for (PRUint32 x = 0; x < aPixelWidth; x++) {
     386               0 :     const PRUint8* pixelIn = &aSrc[x * 4];
     387               0 :     PRUint8* pixelOut = &aDest[x * 3];
     388                 : 
     389               0 :     PRUint8 alpha = pixelIn[3];
     390               0 :     pixelOut[0] = GFX_PREMULTIPLY(pixelIn[0], alpha);
     391               0 :     pixelOut[1] = GFX_PREMULTIPLY(pixelIn[1], alpha);
     392               0 :     pixelOut[2] = GFX_PREMULTIPLY(pixelIn[2], alpha);
     393                 :   }
     394               0 : }
     395                 : 
     396                 : // nsJPEGEncoder::initDestination
     397                 : //
     398                 : //    Initialize destination. This is called by jpeg_start_compress() before
     399                 : //    any data is actually written. It must initialize next_output_byte and
     400                 : //    free_in_buffer. free_in_buffer must be initialized to a positive value.
     401                 : 
     402                 : void // static
     403               3 : nsJPEGEncoder::initDestination(jpeg_compress_struct* cinfo)
     404                 : {
     405               3 :   nsJPEGEncoder* that = static_cast<nsJPEGEncoder*>(cinfo->client_data);
     406               3 :   NS_ASSERTION(! that->mImageBuffer, "Image buffer already initialized");
     407                 : 
     408               3 :   that->mImageBufferSize = 8192;
     409               3 :   that->mImageBuffer = (PRUint8*)PR_Malloc(that->mImageBufferSize);
     410               3 :   that->mImageBufferUsed = 0;
     411                 : 
     412               3 :   cinfo->dest->next_output_byte = that->mImageBuffer;
     413               3 :   cinfo->dest->free_in_buffer = that->mImageBufferSize;
     414               3 : }
     415                 : 
     416                 : 
     417                 : // nsJPEGEncoder::emptyOutputBuffer
     418                 : //
     419                 : //    This is called whenever the buffer has filled (free_in_buffer reaches
     420                 : //    zero).  In typical applications, it should write out the *entire* buffer
     421                 : //    (use the saved start address and buffer length; ignore the current state
     422                 : //    of next_output_byte and free_in_buffer).  Then reset the pointer & count
     423                 : //    to the start of the buffer, and return TRUE indicating that the buffer
     424                 : //    has been dumped.  free_in_buffer must be set to a positive value when
     425                 : //    TRUE is returned.  A FALSE return should only be used when I/O suspension
     426                 : //    is desired (this operating mode is discussed in the next section).
     427                 : 
     428                 : boolean // static
     429               0 : nsJPEGEncoder::emptyOutputBuffer(jpeg_compress_struct* cinfo)
     430                 : {
     431               0 :   nsJPEGEncoder* that = static_cast<nsJPEGEncoder*>(cinfo->client_data);
     432               0 :   NS_ASSERTION(that->mImageBuffer, "No buffer to empty!");
     433                 : 
     434                 :   // When we're reallocing the buffer we need to take the lock to ensure
     435                 :   // that nobody is trying to read from the buffer we are destroying
     436               0 :   ReentrantMonitorAutoEnter autoEnter(that->mReentrantMonitor);
     437                 : 
     438               0 :   that->mImageBufferUsed = that->mImageBufferSize;
     439                 : 
     440                 :   // expand buffer, just double size each time
     441               0 :   that->mImageBufferSize *= 2;
     442                 : 
     443                 :   PRUint8* newBuf = (PRUint8*)PR_Realloc(that->mImageBuffer,
     444               0 :                                          that->mImageBufferSize);
     445               0 :   if (! newBuf) {
     446                 :     // can't resize, just zero (this will keep us from writing more)
     447               0 :     PR_Free(that->mImageBuffer);
     448               0 :     that->mImageBuffer = nsnull;
     449               0 :     that->mImageBufferSize = 0;
     450               0 :     that->mImageBufferUsed = 0;
     451                 : 
     452                 :     // this seems to be the only way to do errors through the JPEG library
     453                 :     longjmp(((encoder_error_mgr*)(cinfo->err))->setjmp_buffer,
     454               0 :             NS_ERROR_OUT_OF_MEMORY);
     455                 :   }
     456               0 :   that->mImageBuffer = newBuf;
     457                 : 
     458               0 :   cinfo->dest->next_output_byte = &that->mImageBuffer[that->mImageBufferUsed];
     459               0 :   cinfo->dest->free_in_buffer = that->mImageBufferSize - that->mImageBufferUsed;
     460               0 :   return 1;
     461                 : }
     462                 : 
     463                 : 
     464                 : // nsJPEGEncoder::termDestination
     465                 : //
     466                 : //    Terminate destination --- called by jpeg_finish_compress() after all data
     467                 : //    has been written.  In most applications, this must flush any data
     468                 : //    remaining in the buffer.  Use either next_output_byte or free_in_buffer
     469                 : //    to determine how much data is in the buffer.
     470                 : 
     471                 : void // static
     472               3 : nsJPEGEncoder::termDestination(jpeg_compress_struct* cinfo)
     473                 : {
     474               3 :   nsJPEGEncoder* that = static_cast<nsJPEGEncoder*>(cinfo->client_data);
     475               3 :   if (! that->mImageBuffer)
     476               0 :     return;
     477               3 :   that->mImageBufferUsed = cinfo->dest->next_output_byte - that->mImageBuffer;
     478               3 :   NS_ASSERTION(that->mImageBufferUsed < that->mImageBufferSize,
     479                 :                "JPEG library busted, got a bad image buffer size");
     480               3 :   that->NotifyListener();
     481                 : }
     482                 : 
     483                 : 
     484                 : // nsJPEGEncoder::errorExit
     485                 : //
     486                 : //    Override the standard error method in the IJG JPEG decoder code. This
     487                 : //    was mostly copied from nsJPEGDecoder.cpp
     488                 : 
     489                 : void // static
     490               0 : nsJPEGEncoder::errorExit(jpeg_common_struct* cinfo)
     491                 : {
     492                 :   nsresult error_code;
     493               0 :   encoder_error_mgr *err = (encoder_error_mgr *) cinfo->err;
     494                 : 
     495                 :   // Convert error to a browser error code
     496               0 :   switch (cinfo->err->msg_code) {
     497                 :     case JERR_OUT_OF_MEMORY:
     498               0 :       error_code = NS_ERROR_OUT_OF_MEMORY;
     499               0 :       break;
     500                 :     default:
     501               0 :       error_code = NS_ERROR_FAILURE;
     502                 :   }
     503                 : 
     504                 :   // Return control to the setjmp point.
     505               0 :   longjmp(err->setjmp_buffer, error_code);
     506                 : }
     507                 : 
     508                 : void
     509               6 : nsJPEGEncoder::NotifyListener()
     510                 : {
     511                 :   // We might call this function on multiple threads (any threads that call
     512                 :   // AsyncWait and any that do encoding) so we lock to avoid notifying the
     513                 :   // listener twice about the same data (which generally leads to a truncated
     514                 :   // image).
     515              12 :   ReentrantMonitorAutoEnter autoEnter(mReentrantMonitor);
     516                 : 
     517               6 :   if (mCallback &&
     518                 :       (mImageBufferUsed - mImageBufferReadPoint >= mNotifyThreshold ||
     519               6 :        mFinished)) {
     520               0 :     nsCOMPtr<nsIInputStreamCallback> callback;
     521               0 :     if (mCallbackTarget) {
     522               0 :       NS_NewInputStreamReadyEvent(getter_AddRefs(callback),
     523                 :                                   mCallback,
     524               0 :                                   mCallbackTarget);
     525                 :     } else {
     526               0 :       callback = mCallback;
     527                 :     }
     528                 : 
     529               0 :     NS_ASSERTION(callback, "Shouldn't fail to make the callback");
     530                 :     // Null the callback first because OnInputStreamReady could reenter
     531                 :     // AsyncWait
     532               0 :     mCallback = nsnull;
     533               0 :     mCallbackTarget = nsnull;
     534               0 :     mNotifyThreshold = 0;
     535                 : 
     536               0 :     callback->OnInputStreamReady(this);
     537                 :   }
     538               6 : }

Generated by: LCOV version 1.7