LCOV - code coverage report
Current view: directory - image/decoders - nsJPEGDecoder.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 341 184 54.0 %
Date: 2012-06-02 Functions: 20 16 80.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Stuart Parmenter <stuart@mozilla.com>
      25                 :  *   Federico Mena-Quintero <federico@novell.com>
      26                 :  *   Bobby Holley <bobbyholley@gmail.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include "nsJPEGDecoder.h"
      43                 : #include "ImageLogging.h"
      44                 : 
      45                 : #include "imgIContainerObserver.h"
      46                 : 
      47                 : #include "nsIInputStream.h"
      48                 : 
      49                 : #include "nspr.h"
      50                 : #include "nsCRT.h"
      51                 : #include "gfxColor.h"
      52                 : 
      53                 : #include "jerror.h"
      54                 : 
      55                 : #include "gfxPlatform.h"
      56                 : 
      57                 : extern "C" {
      58                 : #include "iccjpeg.h"
      59                 : 
      60                 : /* Colorspace conversion (copied from jpegint.h) */
      61                 : struct jpeg_color_deconverter {
      62                 :   JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
      63                 :   JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
      64                 :                                 JSAMPIMAGE input_buf, JDIMENSION input_row,
      65                 :                                 JSAMPARRAY output_buf, int num_rows));
      66                 : };
      67                 : 
      68                 : METHODDEF(void)
      69                 : ycc_rgb_convert_argb (j_decompress_ptr cinfo,
      70                 :                  JSAMPIMAGE input_buf, JDIMENSION input_row,
      71                 :                  JSAMPARRAY output_buf, int num_rows);
      72                 : }
      73                 : 
      74                 : static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
      75                 : 
      76                 : namespace mozilla {
      77                 : namespace image {
      78                 : 
      79                 : #if defined(PR_LOGGING)
      80            1464 : PRLogModuleInfo *gJPEGlog = PR_NewLogModule("JPEGDecoder");
      81            1464 : static PRLogModuleInfo *gJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
      82                 : #else
      83                 : #define gJPEGlog
      84                 : #define gJPEGDecoderAccountingLog
      85                 : #endif
      86                 : 
      87                 : static qcms_profile*
      88               5 : GetICCProfile(struct jpeg_decompress_struct &info)
      89                 : {
      90                 :   JOCTET* profilebuf;
      91                 :   PRUint32 profileLength;
      92               5 :   qcms_profile* profile = nsnull;
      93                 : 
      94               5 :   if (read_icc_profile(&info, &profilebuf, &profileLength)) {
      95               0 :     profile = qcms_profile_from_memory(profilebuf, profileLength);
      96               0 :     free(profilebuf);
      97                 :   }
      98                 : 
      99               5 :   return profile;
     100                 : }
     101                 : 
     102                 : METHODDEF(void) init_source (j_decompress_ptr jd);
     103                 : METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
     104                 : METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
     105                 : METHODDEF(void) term_source (j_decompress_ptr jd);
     106                 : METHODDEF(void) my_error_exit (j_common_ptr cinfo);
     107                 : 
     108                 : /* Normal JFIF markers can't have more bytes than this. */
     109                 : #define MAX_JPEG_MARKER_LENGTH  (((PRUint32)1 << 16) - 1)
     110                 : 
     111                 : 
     112               5 : nsJPEGDecoder::nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
     113               5 :  : Decoder(aImage, aObserver)
     114                 : {
     115               5 :   mState = JPEG_HEADER;
     116               5 :   mReading = true;
     117               5 :   mImageData = nsnull;
     118                 : 
     119               5 :   mBytesToSkip = 0;
     120               5 :   memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
     121               5 :   memset(&mSourceMgr, 0, sizeof(mSourceMgr));
     122               5 :   mInfo.client_data = (void*)this;
     123                 : 
     124               5 :   mSegment = nsnull;
     125               5 :   mSegmentLen = 0;
     126                 : 
     127               5 :   mBackBuffer = nsnull;
     128               5 :   mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
     129                 : 
     130               5 :   mInProfile = nsnull;
     131               5 :   mTransform = nsnull;
     132                 : 
     133               5 :   mCMSMode = 0;
     134                 : 
     135               5 :   PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     136                 :          ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
     137                 :           this));
     138               5 : }
     139                 : 
     140              15 : nsJPEGDecoder::~nsJPEGDecoder()
     141                 : {
     142                 :   // Step 8: Release JPEG decompression object
     143               5 :   mInfo.src = nsnull;
     144               5 :   jpeg_destroy_decompress(&mInfo);
     145                 : 
     146               5 :   PR_FREEIF(mBackBuffer);
     147               5 :   if (mTransform)
     148               0 :     qcms_transform_release(mTransform);
     149               5 :   if (mInProfile)
     150               0 :     qcms_profile_release(mInProfile);
     151                 : 
     152               5 :   PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     153                 :          ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
     154                 :           this));
     155              20 : }
     156                 : 
     157                 : Telemetry::ID
     158               0 : nsJPEGDecoder::SpeedHistogram()
     159                 : {
     160               0 :   return Telemetry::IMAGE_DECODE_SPEED_JPEG;
     161                 : }
     162                 : 
     163                 : void
     164               5 : nsJPEGDecoder::InitInternal()
     165                 : {
     166               5 :   mCMSMode = gfxPlatform::GetCMSMode();
     167               5 :   if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
     168               0 :     mCMSMode = eCMSMode_Off;
     169                 : 
     170                 :   /* We set up the normal JPEG error routines, then override error_exit. */
     171               5 :   mInfo.err = jpeg_std_error(&mErr.pub);
     172                 :   /*   mInfo.err = jpeg_std_error(&mErr.pub); */
     173               5 :   mErr.pub.error_exit = my_error_exit;
     174                 :   /* Establish the setjmp return context for my_error_exit to use. */
     175               5 :   if (setjmp(mErr.setjmp_buffer)) {
     176                 :     /* If we get here, the JPEG code has signaled an error.
     177                 :      * We need to clean up the JPEG object, close the input file, and return.
     178                 :      */
     179               0 :     PostDecoderError(NS_ERROR_FAILURE);
     180               0 :     return;
     181                 :   }
     182                 : 
     183                 :   /* Step 1: allocate and initialize JPEG decompression object */
     184               5 :   jpeg_create_decompress(&mInfo);
     185                 :   /* Set the source manager */
     186               5 :   mInfo.src = &mSourceMgr;
     187                 : 
     188                 :   /* Step 2: specify data source (eg, a file) */
     189                 : 
     190                 :   /* Setup callback functions. */
     191               5 :   mSourceMgr.init_source = init_source;
     192               5 :   mSourceMgr.fill_input_buffer = fill_input_buffer;
     193               5 :   mSourceMgr.skip_input_data = skip_input_data;
     194               5 :   mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
     195               5 :   mSourceMgr.term_source = term_source;
     196                 : 
     197                 :   /* Record app markers for ICC data */
     198              85 :   for (PRUint32 m = 0; m < 16; m++)
     199              80 :     jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
     200                 : }
     201                 : 
     202                 : void
     203               5 : nsJPEGDecoder::FinishInternal()
     204                 : {
     205                 :   /* If we're not in any sort of error case, flush the decoder.
     206                 :    *
     207                 :    * XXXbholley - It seems wrong that this should be necessary, but at the
     208                 :    * moment I'm just folding the contents of Flush() into Close() so that
     209                 :    * we can get rid of it.
     210                 :    */
     211               5 :   if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
     212                 :       (mState != JPEG_ERROR) &&
     213               0 :       !IsSizeDecode())
     214               0 :     this->Write(nsnull, 0);
     215               5 : }
     216                 : 
     217                 : void
     218               8 : nsJPEGDecoder::WriteInternal(const char *aBuffer, PRUint32 aCount)
     219                 : {
     220               8 :   mSegment = (const JOCTET *)aBuffer;
     221               8 :   mSegmentLen = aCount;
     222                 : 
     223               8 :   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
     224                 : 
     225                 :   /* Return here if there is a fatal error within libjpeg. */
     226                 :   nsresult error_code;
     227               8 :   if ((error_code = setjmp(mErr.setjmp_buffer)) != 0) {
     228               0 :     if (error_code == NS_ERROR_FAILURE) {
     229               0 :       PostDataError();
     230                 :       /* Error due to corrupt stream - return NS_OK and consume silently
     231                 :          so that libpr0n doesn't throw away a partial image load */
     232               0 :       mState = JPEG_SINK_NON_JPEG_TRAILER;
     233               0 :       PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     234                 :              ("} (setjmp returned NS_ERROR_FAILURE)"));
     235               0 :       return;
     236                 :     } else {
     237                 :       /* Error due to reasons external to the stream (probably out of
     238                 :          memory) - let libpr0n attempt to clean up, even though
     239                 :          mozilla is seconds away from falling flat on its face. */
     240               0 :       PostDecoderError(error_code);
     241               0 :       mState = JPEG_ERROR;
     242               0 :       PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     243                 :              ("} (setjmp returned an error)"));
     244               0 :       return;
     245                 :     }
     246                 :   }
     247                 : 
     248               8 :   PR_LOG(gJPEGlog, PR_LOG_DEBUG,
     249                 :          ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
     250                 : 
     251               8 :   switch (mState) {
     252                 :   case JPEG_HEADER:
     253                 :   {
     254              12 :     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
     255                 : 
     256                 :     /* Step 3: read file parameters with jpeg_read_header() */
     257               6 :     if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
     258               1 :       PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     259                 :              ("} (JPEG_SUSPENDED)"));
     260                 :       return; /* I/O suspension */
     261                 :     }
     262                 : 
     263                 :     // Post our size to the superclass
     264               5 :     PostSize(mInfo.image_width, mInfo.image_height);
     265               5 :     if (HasError()) {
     266                 :       // Setting the size lead to an error; this can happen when for example
     267                 :       // a multipart channel sends an image of a different size.
     268               0 :       mState = JPEG_ERROR;
     269                 :       return;
     270                 :     }
     271                 : 
     272                 :     /* If we're doing a size decode, we're done. */
     273               5 :     if (IsSizeDecode())
     274                 :       return;
     275                 : 
     276                 :     /* We're doing a full decode. */
     277              10 :     if (mCMSMode != eCMSMode_Off &&
     278               5 :         (mInProfile = GetICCProfile(mInfo)) != nsnull) {
     279               0 :       PRUint32 profileSpace = qcms_profile_get_color_space(mInProfile);
     280               0 :       bool mismatch = false;
     281                 : 
     282                 : #ifdef DEBUG_tor
     283                 :       fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
     284                 : #endif
     285               0 :       switch (mInfo.jpeg_color_space) {
     286                 :       case JCS_GRAYSCALE:
     287               0 :         if (profileSpace == icSigRgbData)
     288               0 :           mInfo.out_color_space = JCS_RGB;
     289               0 :         else if (profileSpace != icSigGrayData)
     290               0 :           mismatch = true;
     291               0 :         break;
     292                 :       case JCS_RGB:
     293               0 :         if (profileSpace != icSigRgbData)
     294               0 :           mismatch =  true;
     295               0 :         break;
     296                 :       case JCS_YCbCr:
     297               0 :         if (profileSpace == icSigRgbData)
     298               0 :           mInfo.out_color_space = JCS_RGB;
     299                 :         else
     300                 :           // qcms doesn't support ycbcr
     301               0 :           mismatch = true;
     302               0 :         break;
     303                 :       case JCS_CMYK:
     304                 :       case JCS_YCCK:
     305                 :           // qcms doesn't support cmyk
     306               0 :           mismatch = true;
     307               0 :         break;
     308                 :       default:
     309               0 :         mState = JPEG_ERROR;
     310               0 :         PostDataError();
     311               0 :         PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     312                 :                ("} (unknown colorpsace (1))"));
     313                 :         return;
     314                 :       }
     315                 : 
     316               0 :       if (!mismatch) {
     317                 :         qcms_data_type type;
     318               0 :         switch (mInfo.out_color_space) {
     319                 :         case JCS_GRAYSCALE:
     320               0 :           type = QCMS_DATA_GRAY_8;
     321               0 :           break;
     322                 :         case JCS_RGB:
     323               0 :           type = QCMS_DATA_RGB_8;
     324               0 :           break;
     325                 :         default:
     326               0 :           mState = JPEG_ERROR;
     327               0 :           PostDataError();
     328               0 :           PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     329                 :                  ("} (unknown colorpsace (2))"));
     330                 :           return;
     331                 :         }
     332                 : #if 0
     333                 :         /* We don't currently support CMYK profiles. The following
     334                 :          * code dealt with lcms types. Add something like this
     335                 :          * back when we gain support for CMYK.
     336                 :          */
     337                 :         /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
     338                 :         if (mInfo.out_color_space == JCS_CMYK)
     339                 :           type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
     340                 : #endif
     341                 : 
     342               0 :         if (gfxPlatform::GetCMSOutputProfile()) {
     343                 : 
     344                 :           /* Calculate rendering intent. */
     345               0 :           int intent = gfxPlatform::GetRenderingIntent();
     346               0 :           if (intent == -1)
     347               0 :               intent = qcms_profile_get_rendering_intent(mInProfile);
     348                 : 
     349                 :           /* Create the color management transform. */
     350                 :           mTransform = qcms_transform_create(mInProfile,
     351                 :                                           type,
     352                 :                                           gfxPlatform::GetCMSOutputProfile(),
     353                 :                                           QCMS_DATA_RGB_8,
     354               0 :                                           (qcms_intent)intent);
     355                 :         }
     356                 :       } else {
     357                 : #ifdef DEBUG_tor
     358                 :         fprintf(stderr, "ICM profile colorspace mismatch\n");
     359                 : #endif
     360                 :       }
     361                 :     }
     362                 : 
     363               5 :     if (!mTransform) {
     364               5 :       switch (mInfo.jpeg_color_space) {
     365                 :       case JCS_GRAYSCALE:
     366                 :       case JCS_RGB:
     367                 :       case JCS_YCbCr:
     368               5 :         mInfo.out_color_space = JCS_RGB;
     369               5 :         break;
     370                 :       case JCS_CMYK:
     371                 :       case JCS_YCCK:
     372                 :         /* libjpeg can convert from YCCK to CMYK, but not to RGB */
     373               0 :         mInfo.out_color_space = JCS_CMYK;
     374               0 :         break;
     375                 :       default:
     376               0 :         mState = JPEG_ERROR;
     377               0 :         PostDataError();
     378               0 :         PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     379                 :                ("} (unknown colorpsace (3))"));
     380                 :         return;
     381                 :         break;
     382                 :       }
     383                 :     }
     384                 : 
     385                 :     /*
     386                 :      * Don't allocate a giant and superfluous memory buffer
     387                 :      * when the image is a sequential JPEG.
     388                 :      */
     389               5 :     mInfo.buffered_image = jpeg_has_multiple_scans(&mInfo);
     390                 : 
     391                 :     /* Used to set up image size so arrays can be allocated */
     392               5 :     jpeg_calc_output_dimensions(&mInfo);
     393                 : 
     394                 :     PRUint32 imagelength;
     395               5 :     if (NS_FAILED(mImage.EnsureFrame(0, 0, 0, mInfo.image_width, mInfo.image_height,
     396                 :                                      gfxASurface::ImageFormatRGB24,
     397                 :                                      &mImageData, &imagelength))) {
     398               0 :       mState = JPEG_ERROR;
     399               0 :       PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
     400               0 :       PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     401                 :              ("} (could not initialize image frame)"));
     402                 :       return;
     403                 :     }
     404                 : 
     405               5 :     PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     406                 :            ("        JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
     407                 :             mInfo.image_width, mInfo.image_height));
     408                 : 
     409                 :     // Tell the superclass we're starting a frame
     410               5 :     PostFrameStart();
     411                 : 
     412              11 :     mState = JPEG_START_DECOMPRESS;
     413                 :   }
     414                 : 
     415                 :   case JPEG_START_DECOMPRESS:
     416                 :   {
     417              10 :     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
     418                 :     /* Step 4: set parameters for decompression */
     419                 : 
     420                 :     /* FIXME -- Should reset dct_method and dither mode
     421                 :      * for final pass of progressive JPEG
     422                 :      */
     423               5 :     mInfo.dct_method =  JDCT_ISLOW;
     424               5 :     mInfo.dither_mode = JDITHER_FS;
     425               5 :     mInfo.do_fancy_upsampling = TRUE;
     426               5 :     mInfo.enable_2pass_quant = FALSE;
     427               5 :     mInfo.do_block_smoothing = TRUE;
     428                 : 
     429                 :     /* Step 5: Start decompressor */
     430               5 :     if (jpeg_start_decompress(&mInfo) == FALSE) {
     431               0 :       PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     432                 :              ("} (I/O suspension after jpeg_start_decompress())"));
     433                 :       return; /* I/O suspension */
     434                 :     }
     435                 : 
     436                 :     /* Force to use our YCbCr to Packed RGB converter when possible */
     437               5 :     if (!mTransform && (mCMSMode != eCMSMode_All) &&
     438                 :         mInfo.jpeg_color_space == JCS_YCbCr && mInfo.out_color_space == JCS_RGB) {
     439                 :       /* Special case for the most common case: transform from YCbCr direct into packed ARGB */
     440               5 :       mInfo.out_color_components = 4; /* Packed ARGB pixels are always 4 bytes...*/
     441               5 :       mInfo.cconvert->color_convert = ycc_rgb_convert_argb;
     442                 :     }
     443                 : 
     444                 :     /* If this is a progressive JPEG ... */
     445              10 :     mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
     446                 :   }
     447                 : 
     448                 :   case JPEG_DECOMPRESS_SEQUENTIAL:
     449                 :   {
     450               7 :     if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
     451                 :     {
     452              14 :       LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
     453                 :       
     454                 :       bool suspend;
     455               7 :       OutputScanlines(&suspend);
     456                 :       
     457               7 :       if (suspend) {
     458               2 :         PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     459                 :                ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
     460                 :         return; /* I/O suspension */
     461                 :       }
     462                 :       
     463                 :       /* If we've completed image output ... */
     464               5 :       NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
     465              12 :       mState = JPEG_DONE;
     466                 :     }
     467                 :   }
     468                 : 
     469                 :   case JPEG_DECOMPRESS_PROGRESSIVE:
     470                 :   {
     471               5 :     if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
     472                 :     {
     473               0 :       LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
     474                 : 
     475                 :       int status;
     476               0 :       do {
     477               0 :         status = jpeg_consume_input(&mInfo);
     478                 :       } while ((status != JPEG_SUSPENDED) &&
     479                 :                (status != JPEG_REACHED_EOI));
     480                 : 
     481               0 :       for (;;) {
     482               0 :         if (mInfo.output_scanline == 0) {
     483               0 :           int scan = mInfo.input_scan_number;
     484                 : 
     485                 :           /* if we haven't displayed anything yet (output_scan_number==0)
     486                 :              and we have enough data for a complete scan, force output
     487                 :              of the last full scan */
     488               0 :           if ((mInfo.output_scan_number == 0) &&
     489                 :               (scan > 1) &&
     490                 :               (status != JPEG_REACHED_EOI))
     491               0 :             scan--;
     492                 : 
     493               0 :           if (!jpeg_start_output(&mInfo, scan)) {
     494               0 :             PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     495                 :                    ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
     496                 :             return; /* I/O suspension */
     497                 :           }
     498                 :         }
     499                 : 
     500               0 :         if (mInfo.output_scanline == 0xffffff)
     501               0 :           mInfo.output_scanline = 0;
     502                 : 
     503                 :         bool suspend;
     504               0 :         OutputScanlines(&suspend);
     505                 : 
     506               0 :         if (suspend) {
     507               0 :           if (mInfo.output_scanline == 0) {
     508                 :             /* didn't manage to read any lines - flag so we don't call
     509                 :                jpeg_start_output() multiple times for the same scan */
     510               0 :             mInfo.output_scanline = 0xffffff;
     511                 :           }
     512               0 :           PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     513                 :                  ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
     514                 :           return; /* I/O suspension */
     515                 :         }
     516                 : 
     517               0 :         if (mInfo.output_scanline == mInfo.output_height)
     518                 :         {
     519               0 :           if (!jpeg_finish_output(&mInfo)) {
     520               0 :             PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     521                 :                    ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
     522                 :             return; /* I/O suspension */
     523                 :           }
     524                 : 
     525               0 :           if (jpeg_input_complete(&mInfo) &&
     526                 :               (mInfo.input_scan_number == mInfo.output_scan_number))
     527                 :             break;
     528                 : 
     529               0 :           mInfo.output_scanline = 0;
     530                 :         }
     531                 :       }
     532                 : 
     533               0 :       mState = JPEG_DONE;
     534                 :     }
     535                 :   }
     536                 : 
     537                 :   case JPEG_DONE:
     538                 :   {
     539              10 :     LOG_SCOPE(gJPEGlog, "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
     540                 : 
     541                 :     /* Step 7: Finish decompression */
     542                 : 
     543               5 :     if (jpeg_finish_decompress(&mInfo) == FALSE) {
     544               0 :       PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     545                 :              ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
     546                 :       return; /* I/O suspension */
     547                 :     }
     548                 : 
     549               5 :     mState = JPEG_SINK_NON_JPEG_TRAILER;
     550                 : 
     551                 :     /* we're done dude */
     552               5 :     break;
     553                 :   }
     554                 :   case JPEG_SINK_NON_JPEG_TRAILER:
     555               0 :     PR_LOG(gJPEGlog, PR_LOG_DEBUG,
     556                 :            ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
     557                 : 
     558               0 :     break;
     559                 : 
     560                 :   case JPEG_ERROR:
     561               0 :     NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
     562                 :   }
     563                 : 
     564               5 :   PR_LOG(gJPEGDecoderAccountingLog, PR_LOG_DEBUG,
     565                 :          ("} (end of function)"));
     566               5 :   return;
     567                 : }
     568                 : 
     569                 : void
     570               5 : nsJPEGDecoder::NotifyDone()
     571                 : {
     572               5 :   PostFrameStop();
     573               5 :   PostDecodeDone();
     574               5 : }
     575                 : 
     576                 : void
     577               7 : nsJPEGDecoder::OutputScanlines(bool* suspend)
     578                 : {
     579               7 :   *suspend = false;
     580                 : 
     581               7 :   const PRUint32 top = mInfo.output_scanline;
     582                 : 
     583             245 :   while ((mInfo.output_scanline < mInfo.output_height)) {
     584                 :       /* Use the Cairo image buffer as scanline buffer */
     585                 :       PRUint32 *imageRow = ((PRUint32*)mImageData) +
     586             233 :                            (mInfo.output_scanline * mInfo.output_width);
     587                 : 
     588             233 :       if (mInfo.cconvert->color_convert == ycc_rgb_convert_argb) {
     589                 :         /* Special case: scanline will be directly converted into packed ARGB */
     590             233 :         if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
     591               2 :           *suspend = true; /* suspend */
     592               2 :           break;
     593                 :         }
     594             231 :         continue; /* all done for this row! */
     595                 :       }
     596                 : 
     597               0 :       JSAMPROW sampleRow = (JSAMPROW)imageRow;
     598               0 :       if (mInfo.output_components == 3) {
     599                 :         /* Put the pixels at end of row to enable in-place expansion */
     600               0 :         sampleRow += mInfo.output_width;
     601                 :       }
     602                 : 
     603                 :       /* Request one scanline.  Returns 0 or 1 scanlines. */    
     604               0 :       if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
     605               0 :         *suspend = true; /* suspend */
     606               0 :         break;
     607                 :       }
     608                 : 
     609               0 :       if (mTransform) {
     610               0 :         JSAMPROW source = sampleRow;
     611               0 :         if (mInfo.out_color_space == JCS_GRAYSCALE) {
     612                 :           /* Convert from the 1byte grey pixels at begin of row 
     613                 :              to the 3byte RGB byte pixels at 'end' of row */
     614               0 :           sampleRow += mInfo.output_width;
     615                 :         }
     616               0 :         qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
     617                 :         /* Move 3byte RGB data to end of row */
     618               0 :         if (mInfo.out_color_space == JCS_CMYK) {
     619               0 :           memmove(sampleRow + mInfo.output_width,
     620                 :                   sampleRow,
     621               0 :                   3 * mInfo.output_width);
     622               0 :           sampleRow += mInfo.output_width;
     623                 :         }
     624                 :       } else {
     625               0 :         if (mInfo.out_color_space == JCS_CMYK) {
     626                 :           /* Convert from CMYK to RGB */
     627                 :           /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
     628                 :           /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
     629               0 :           cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
     630               0 :           sampleRow += mInfo.output_width;
     631                 :         }
     632               0 :         if (mCMSMode == eCMSMode_All) {
     633                 :           /* No embedded ICC profile - treat as sRGB */
     634               0 :           qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
     635               0 :           if (transform) {
     636               0 :             qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
     637                 :           }
     638                 :         }
     639                 :       }
     640                 : 
     641                 :       // counter for while() loops below
     642               0 :       PRUint32 idx = mInfo.output_width;
     643                 : 
     644                 :       // copy as bytes until source pointer is 32-bit-aligned
     645               0 :       for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
     646               0 :         *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
     647               0 :         sampleRow += 3;
     648                 :       }
     649                 : 
     650                 :       // copy pixels in blocks of 4
     651               0 :       while (idx >= 4) {
     652               0 :         GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
     653               0 :         idx       -=  4;
     654               0 :         sampleRow += 12;
     655               0 :         imageRow  +=  4;
     656                 :       }
     657                 : 
     658                 :       // copy remaining pixel(s)
     659               0 :       while (idx--) {
     660                 :         // 32-bit read of final pixel will exceed buffer, so read bytes
     661               0 :         *imageRow++ = GFX_PACKED_PIXEL(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
     662               0 :         sampleRow += 3;
     663                 :       }
     664                 :   }
     665                 : 
     666               7 :   if (top != mInfo.output_scanline) {
     667               6 :       nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
     668               6 :       PostInvalidation(r);
     669                 :   }
     670                 : 
     671               7 : }
     672                 : 
     673                 : 
     674                 : /* Override the standard error method in the IJG JPEG decoder code. */
     675                 : METHODDEF(void)
     676               0 : my_error_exit (j_common_ptr cinfo)
     677                 : {
     678               0 :   decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
     679                 : 
     680                 :   /* Convert error to a browser error code */
     681                 :   nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
     682                 :                       ? NS_ERROR_OUT_OF_MEMORY
     683               0 :                       : NS_ERROR_FAILURE;
     684                 : 
     685                 : #ifdef DEBUG
     686                 :   char buffer[JMSG_LENGTH_MAX];
     687                 : 
     688                 :   /* Create the message */
     689               0 :   (*err->pub.format_message) (cinfo, buffer);
     690                 : 
     691               0 :   fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
     692                 : #endif
     693                 : 
     694                 :   /* Return control to the setjmp point. */
     695               0 :   longjmp(err->setjmp_buffer, error_code);
     696                 : }
     697                 : 
     698                 : /******************************************************************************/
     699                 : /*-----------------------------------------------------------------------------
     700                 :  * This is the callback routine from the IJG JPEG library used to supply new
     701                 :  * data to the decompressor when its input buffer is exhausted.  It juggles
     702                 :  * multiple buffers in an attempt to avoid unnecessary copying of input data.
     703                 :  *
     704                 :  * (A simpler scheme is possible: It's much easier to use only a single
     705                 :  * buffer; when fill_input_buffer() is called, move any unconsumed data
     706                 :  * (beyond the current pointer/count) down to the beginning of this buffer and
     707                 :  * then load new data into the remaining buffer space.  This approach requires
     708                 :  * a little more data copying but is far easier to get right.)
     709                 :  *
     710                 :  * At any one time, the JPEG decompressor is either reading from the necko
     711                 :  * input buffer, which is volatile across top-level calls to the IJG library,
     712                 :  * or the "backtrack" buffer.  The backtrack buffer contains the remaining
     713                 :  * unconsumed data from the necko buffer after parsing was suspended due
     714                 :  * to insufficient data in some previous call to the IJG library.
     715                 :  *
     716                 :  * When suspending, the decompressor will back up to a convenient restart
     717                 :  * point (typically the start of the current MCU). The variables
     718                 :  * next_input_byte & bytes_in_buffer indicate where the restart point will be
     719                 :  * if the current call returns FALSE.  Data beyond this point must be
     720                 :  * rescanned after resumption, so it must be preserved in case the decompressor
     721                 :  * decides to backtrack.
     722                 :  *
     723                 :  * Returns:
     724                 :  *  TRUE if additional data is available, FALSE if no data present and
     725                 :  *   the JPEG library should therefore suspend processing of input stream
     726                 :  *---------------------------------------------------------------------------*/
     727                 : 
     728                 : /******************************************************************************/
     729                 : /* data source manager method                                                 */
     730                 : /******************************************************************************/
     731                 : 
     732                 : 
     733                 : /******************************************************************************/
     734                 : /* data source manager method 
     735                 :         Initialize source.  This is called by jpeg_read_header() before any
     736                 :         data is actually read.  May leave
     737                 :         bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
     738                 :         will occur immediately).
     739                 : */
     740                 : METHODDEF(void)
     741               5 : init_source (j_decompress_ptr jd)
     742                 : {
     743               5 : }
     744                 : 
     745                 : /******************************************************************************/
     746                 : /* data source manager method
     747                 :         Skip num_bytes worth of data.  The buffer pointer and count should
     748                 :         be advanced over num_bytes input bytes, refilling the buffer as
     749                 :         needed.  This is used to skip over a potentially large amount of
     750                 :         uninteresting data (such as an APPn marker).  In some applications
     751                 :         it may be possible to optimize away the reading of the skipped data,
     752                 :         but it's not clear that being smart is worth much trouble; large
     753                 :         skips are uncommon.  bytes_in_buffer may be zero on return.
     754                 :         A zero or negative skip count should be treated as a no-op.
     755                 : */
     756                 : METHODDEF(void)
     757               3 : skip_input_data (j_decompress_ptr jd, long num_bytes)
     758                 : {
     759               3 :   struct jpeg_source_mgr *src = jd->src;
     760               3 :   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
     761                 : 
     762               3 :   if (num_bytes > (long)src->bytes_in_buffer) {
     763                 :     /*
     764                 :      * Can't skip it all right now until we get more data from
     765                 :      * network stream. Set things up so that fill_input_buffer
     766                 :      * will skip remaining amount.
     767                 :      */
     768               0 :     decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
     769               0 :     src->next_input_byte += src->bytes_in_buffer;
     770               0 :     src->bytes_in_buffer = 0;
     771                 : 
     772                 :   } else {
     773                 :     /* Simple case. Just advance buffer pointer */
     774                 : 
     775               3 :     src->bytes_in_buffer -= (size_t)num_bytes;
     776               3 :     src->next_input_byte += num_bytes;
     777                 :   }
     778               3 : }
     779                 : 
     780                 : 
     781                 : /******************************************************************************/
     782                 : /* data source manager method
     783                 :         This is called whenever bytes_in_buffer has reached zero and more
     784                 :         data is wanted.  In typical applications, it should read fresh data
     785                 :         into the buffer (ignoring the current state of next_input_byte and
     786                 :         bytes_in_buffer), reset the pointer & count to the start of the
     787                 :         buffer, and return TRUE indicating that the buffer has been reloaded.
     788                 :         It is not necessary to fill the buffer entirely, only to obtain at
     789                 :         least one more byte.  bytes_in_buffer MUST be set to a positive value
     790                 :         if TRUE is returned.  A FALSE return should only be used when I/O
     791                 :         suspension is desired.
     792                 : */
     793                 : METHODDEF(boolean)
     794              11 : fill_input_buffer (j_decompress_ptr jd)
     795                 : {
     796              11 :   struct jpeg_source_mgr *src = jd->src;
     797              11 :   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
     798                 : 
     799              11 :   if (decoder->mReading) {
     800               8 :     const JOCTET *new_buffer = decoder->mSegment;
     801               8 :     PRUint32 new_buflen = decoder->mSegmentLen;
     802                 :   
     803               8 :     if (!new_buffer || new_buflen == 0)
     804               0 :       return false; /* suspend */
     805                 : 
     806               8 :     decoder->mSegmentLen = 0;
     807                 : 
     808               8 :     if (decoder->mBytesToSkip) {
     809               0 :       if (decoder->mBytesToSkip < new_buflen) {
     810                 :         /* All done skipping bytes; Return what's left. */
     811               0 :         new_buffer += decoder->mBytesToSkip;
     812               0 :         new_buflen -= decoder->mBytesToSkip;
     813               0 :         decoder->mBytesToSkip = 0;
     814                 :       } else {
     815                 :         /* Still need to skip some more data in the future */
     816               0 :         decoder->mBytesToSkip -= (size_t)new_buflen;
     817               0 :         return false; /* suspend */
     818                 :       }
     819                 :     }
     820                 : 
     821               8 :       decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
     822                 : 
     823               8 :     src->next_input_byte = new_buffer;
     824               8 :     src->bytes_in_buffer = (size_t)new_buflen;
     825               8 :     decoder->mReading = false;
     826                 : 
     827               8 :     return true;
     828                 :   }
     829                 : 
     830               3 :   if (src->next_input_byte != decoder->mSegment) {
     831                 :     /* Backtrack data has been permanently consumed. */
     832               3 :     decoder->mBackBufferUnreadLen = 0;
     833               3 :     decoder->mBackBufferLen = 0;
     834                 :   }
     835                 : 
     836                 :   /* Save remainder of netlib buffer in backtrack buffer */
     837               3 :   const PRUint32 new_backtrack_buflen = src->bytes_in_buffer + decoder->mBackBufferLen;
     838                 :  
     839                 :   /* Make sure backtrack buffer is big enough to hold new data. */
     840               3 :   if (decoder->mBackBufferSize < new_backtrack_buflen) {
     841                 :     /* Check for malformed MARKER segment lengths, before allocating space for it */
     842               2 :     if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
     843               0 :       my_error_exit((j_common_ptr)(&decoder->mInfo));
     844                 :     }
     845                 : 
     846                 :     /* Round up to multiple of 256 bytes. */
     847               2 :     const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
     848               2 :     JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen);
     849                 :     /* Check for OOM */
     850               2 :     if (!buf) {
     851               0 :       decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
     852               0 :       my_error_exit((j_common_ptr)(&decoder->mInfo));
     853                 :     }
     854               2 :     decoder->mBackBuffer = buf;
     855               2 :     decoder->mBackBufferSize = roundup_buflen;
     856                 :   }
     857                 : 
     858                 :   /* Copy remainder of netlib segment into backtrack buffer. */
     859               3 :   memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
     860                 :           src->next_input_byte,
     861               6 :           src->bytes_in_buffer);
     862                 : 
     863                 :   /* Point to start of data to be rescanned. */
     864               3 :   src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen - decoder->mBackBufferUnreadLen;
     865               3 :   src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
     866               3 :   decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
     867               3 :   decoder->mReading = true;
     868                 : 
     869               3 :   return false;
     870                 : }
     871                 : 
     872                 : /******************************************************************************/
     873                 : /* data source manager method */
     874                 : /*
     875                 :  * Terminate source --- called by jpeg_finish_decompress() after all
     876                 :  * data has been read to clean up JPEG source manager. NOT called by 
     877                 :  * jpeg_abort() or jpeg_destroy().
     878                 :  */
     879                 : METHODDEF(void)
     880               5 : term_source (j_decompress_ptr jd)
     881                 : {
     882               5 :   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
     883                 : 
     884                 :   // This function shouldn't be called if we ran into an error we didn't
     885                 :   // recover from.
     886               5 :   NS_ABORT_IF_FALSE(decoder->mState != JPEG_ERROR,
     887                 :                     "Calling term_source on a JPEG with mState == JPEG_ERROR!");
     888                 : 
     889                 :   // Notify using a helper method to get around protectedness issues.
     890               5 :   decoder->NotifyDone();
     891               5 : }
     892                 : 
     893                 : } // namespace image
     894                 : } // namespace mozilla
     895                 : 
     896                 : 
     897                 : /**************** YCbCr -> Cairo's RGB24/ARGB32 conversion: most common case **************/
     898                 : 
     899                 : /*
     900                 :  * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
     901                 :  * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
     902                 :  * The conversion equations to be implemented are therefore
     903                 :  *      R = Y                + 1.40200 * Cr
     904                 :  *      G = Y - 0.34414 * Cb - 0.71414 * Cr
     905                 :  *      B = Y + 1.77200 * Cb
     906                 :  * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
     907                 :  * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
     908                 :  *
     909                 :  * To avoid floating-point arithmetic, we represent the fractional constants
     910                 :  * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
     911                 :  * the products by 2^16, with appropriate rounding, to get the correct answer.
     912                 :  * Notice that Y, being an integral input, does not contribute any fraction
     913                 :  * so it need not participate in the rounding.
     914                 :  *
     915                 :  * For even more speed, we avoid doing any multiplications in the inner loop
     916                 :  * by precalculating the constants times Cb and Cr for all possible values.
     917                 :  * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
     918                 :  * for 12-bit samples it is still acceptable.  It's not very reasonable for
     919                 :  * 16-bit samples, but if you want lossless storage you shouldn't be changing
     920                 :  * colorspace anyway.
     921                 :  * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
     922                 :  * values for the G calculation are left scaled up, since we must add them
     923                 :  * together before rounding.
     924                 :  */
     925                 : 
     926                 : #define SCALEBITS       16      /* speediest right-shift on some machines */
     927                 : 
     928                 : /* Use static tables for color processing. */
     929                 : /* Four tables, each 256 entries of 4 bytes totals 4K which is not bad... */
     930                 : 
     931                 : const int Cr_r_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
     932                 :        -0xb3,       -0xb2,       -0xb1,       -0xaf,       -0xae,       -0xac,
     933                 :        -0xab,       -0xaa,       -0xa8,       -0xa7,       -0xa5,       -0xa4,
     934                 :        -0xa3,       -0xa1,       -0xa0,       -0x9e,       -0x9d,       -0x9c,
     935                 :        -0x9a,       -0x99,       -0x97,       -0x96,       -0x95,       -0x93,
     936                 :        -0x92,       -0x90,       -0x8f,       -0x8e,       -0x8c,       -0x8b,
     937                 :        -0x89,       -0x88,       -0x87,       -0x85,       -0x84,       -0x82,
     938                 :        -0x81,       -0x80,       -0x7e,       -0x7d,       -0x7b,       -0x7a,
     939                 :        -0x79,       -0x77,       -0x76,       -0x74,       -0x73,       -0x72,
     940                 :        -0x70,       -0x6f,       -0x6d,       -0x6c,       -0x6b,       -0x69,
     941                 :        -0x68,       -0x66,       -0x65,       -0x64,       -0x62,       -0x61,
     942                 :        -0x5f,       -0x5e,       -0x5d,       -0x5b,       -0x5a,       -0x58,
     943                 :        -0x57,       -0x56,       -0x54,       -0x53,       -0x51,       -0x50,
     944                 :        -0x4f,       -0x4d,       -0x4c,       -0x4a,       -0x49,       -0x48,
     945                 :        -0x46,       -0x45,       -0x43,       -0x42,       -0x40,       -0x3f,
     946                 :        -0x3e,       -0x3c,       -0x3b,       -0x39,       -0x38,       -0x37,
     947                 :        -0x35,       -0x34,       -0x32,       -0x31,       -0x30,       -0x2e,
     948                 :        -0x2d,       -0x2b,       -0x2a,       -0x29,       -0x27,       -0x26,
     949                 :        -0x24,       -0x23,       -0x22,       -0x20,       -0x1f,       -0x1d,
     950                 :        -0x1c,       -0x1b,       -0x19,       -0x18,       -0x16,       -0x15,
     951                 :        -0x14,       -0x12,       -0x11,       -0x0f,       -0x0e,       -0x0d,
     952                 :        -0x0b,       -0x0a,       -0x08,       -0x07,       -0x06,       -0x04,
     953                 :        -0x03,       -0x01,        0x00,        0x01,        0x03,        0x04,
     954                 :         0x06,        0x07,        0x08,        0x0a,        0x0b,        0x0d,
     955                 :         0x0e,        0x0f,        0x11,        0x12,        0x14,        0x15,
     956                 :         0x16,        0x18,        0x19,        0x1b,        0x1c,        0x1d,
     957                 :         0x1f,        0x20,        0x22,        0x23,        0x24,        0x26,
     958                 :         0x27,        0x29,        0x2a,        0x2b,        0x2d,        0x2e,
     959                 :         0x30,        0x31,        0x32,        0x34,        0x35,        0x37,
     960                 :         0x38,        0x39,        0x3b,        0x3c,        0x3e,        0x3f,
     961                 :         0x40,        0x42,        0x43,        0x45,        0x46,        0x48,
     962                 :         0x49,        0x4a,        0x4c,        0x4d,        0x4f,        0x50,
     963                 :         0x51,        0x53,        0x54,        0x56,        0x57,        0x58,
     964                 :         0x5a,        0x5b,        0x5d,        0x5e,        0x5f,        0x61,
     965                 :         0x62,        0x64,        0x65,        0x66,        0x68,        0x69,
     966                 :         0x6b,        0x6c,        0x6d,        0x6f,        0x70,        0x72,
     967                 :         0x73,        0x74,        0x76,        0x77,        0x79,        0x7a,
     968                 :         0x7b,        0x7d,        0x7e,        0x80,        0x81,        0x82,
     969                 :         0x84,        0x85,        0x87,        0x88,        0x89,        0x8b,
     970                 :         0x8c,        0x8e,        0x8f,        0x90,        0x92,        0x93,
     971                 :         0x95,        0x96,        0x97,        0x99,        0x9a,        0x9c,
     972                 :         0x9d,        0x9e,        0xa0,        0xa1,        0xa3,        0xa4,
     973                 :         0xa5,        0xa7,        0xa8,        0xaa,        0xab,        0xac,
     974                 :         0xae,        0xaf,        0xb1,        0xb2,
     975                 :   };
     976                 : 
     977                 : const int Cb_b_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
     978                 :        -0xe3,       -0xe1,       -0xdf,       -0xde,       -0xdc,       -0xda,
     979                 :        -0xd8,       -0xd6,       -0xd5,       -0xd3,       -0xd1,       -0xcf,
     980                 :        -0xce,       -0xcc,       -0xca,       -0xc8,       -0xc6,       -0xc5,
     981                 :        -0xc3,       -0xc1,       -0xbf,       -0xbe,       -0xbc,       -0xba,
     982                 :        -0xb8,       -0xb7,       -0xb5,       -0xb3,       -0xb1,       -0xaf,
     983                 :        -0xae,       -0xac,       -0xaa,       -0xa8,       -0xa7,       -0xa5,
     984                 :        -0xa3,       -0xa1,       -0x9f,       -0x9e,       -0x9c,       -0x9a,
     985                 :        -0x98,       -0x97,       -0x95,       -0x93,       -0x91,       -0x90,
     986                 :        -0x8e,       -0x8c,       -0x8a,       -0x88,       -0x87,       -0x85,
     987                 :        -0x83,       -0x81,       -0x80,       -0x7e,       -0x7c,       -0x7a,
     988                 :        -0x78,       -0x77,       -0x75,       -0x73,       -0x71,       -0x70,
     989                 :        -0x6e,       -0x6c,       -0x6a,       -0x69,       -0x67,       -0x65,
     990                 :        -0x63,       -0x61,       -0x60,       -0x5e,       -0x5c,       -0x5a,
     991                 :        -0x59,       -0x57,       -0x55,       -0x53,       -0x52,       -0x50,
     992                 :        -0x4e,       -0x4c,       -0x4a,       -0x49,       -0x47,       -0x45,
     993                 :        -0x43,       -0x42,       -0x40,       -0x3e,       -0x3c,       -0x3a,
     994                 :        -0x39,       -0x37,       -0x35,       -0x33,       -0x32,       -0x30,
     995                 :        -0x2e,       -0x2c,       -0x2b,       -0x29,       -0x27,       -0x25,
     996                 :        -0x23,       -0x22,       -0x20,       -0x1e,       -0x1c,       -0x1b,
     997                 :        -0x19,       -0x17,       -0x15,       -0x13,       -0x12,       -0x10,
     998                 :        -0x0e,       -0x0c,       -0x0b,       -0x09,       -0x07,       -0x05,
     999                 :        -0x04,       -0x02,        0x00,        0x02,        0x04,        0x05,
    1000                 :         0x07,        0x09,        0x0b,        0x0c,        0x0e,        0x10,
    1001                 :         0x12,        0x13,        0x15,        0x17,        0x19,        0x1b,
    1002                 :         0x1c,        0x1e,        0x20,        0x22,        0x23,        0x25,
    1003                 :         0x27,        0x29,        0x2b,        0x2c,        0x2e,        0x30,
    1004                 :         0x32,        0x33,        0x35,        0x37,        0x39,        0x3a,
    1005                 :         0x3c,        0x3e,        0x40,        0x42,        0x43,        0x45,
    1006                 :         0x47,        0x49,        0x4a,        0x4c,        0x4e,        0x50,
    1007                 :         0x52,        0x53,        0x55,        0x57,        0x59,        0x5a,
    1008                 :         0x5c,        0x5e,        0x60,        0x61,        0x63,        0x65,
    1009                 :         0x67,        0x69,        0x6a,        0x6c,        0x6e,        0x70,
    1010                 :         0x71,        0x73,        0x75,        0x77,        0x78,        0x7a,
    1011                 :         0x7c,        0x7e,        0x80,        0x81,        0x83,        0x85,
    1012                 :         0x87,        0x88,        0x8a,        0x8c,        0x8e,        0x90,
    1013                 :         0x91,        0x93,        0x95,        0x97,        0x98,        0x9a,
    1014                 :         0x9c,        0x9e,        0x9f,        0xa1,        0xa3,        0xa5,
    1015                 :         0xa7,        0xa8,        0xaa,        0xac,        0xae,        0xaf,
    1016                 :         0xb1,        0xb3,        0xb5,        0xb7,        0xb8,        0xba,
    1017                 :         0xbc,        0xbe,        0xbf,        0xc1,        0xc3,        0xc5,
    1018                 :         0xc6,        0xc8,        0xca,        0xcc,        0xce,        0xcf,
    1019                 :         0xd1,        0xd3,        0xd5,        0xd6,        0xd8,        0xda,
    1020                 :         0xdc,        0xde,        0xdf,        0xe1,
    1021                 :   };
    1022                 : 
    1023                 : const int Cr_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
    1024                 :     0x5b6900,    0x5ab22e,    0x59fb5c,    0x59448a,    0x588db8,    0x57d6e6,
    1025                 :     0x572014,    0x566942,    0x55b270,    0x54fb9e,    0x5444cc,    0x538dfa,
    1026                 :     0x52d728,    0x522056,    0x516984,    0x50b2b2,    0x4ffbe0,    0x4f450e,
    1027                 :     0x4e8e3c,    0x4dd76a,    0x4d2098,    0x4c69c6,    0x4bb2f4,    0x4afc22,
    1028                 :     0x4a4550,    0x498e7e,    0x48d7ac,    0x4820da,    0x476a08,    0x46b336,
    1029                 :     0x45fc64,    0x454592,    0x448ec0,    0x43d7ee,    0x43211c,    0x426a4a,
    1030                 :     0x41b378,    0x40fca6,    0x4045d4,    0x3f8f02,    0x3ed830,    0x3e215e,
    1031                 :     0x3d6a8c,    0x3cb3ba,    0x3bfce8,    0x3b4616,    0x3a8f44,    0x39d872,
    1032                 :     0x3921a0,    0x386ace,    0x37b3fc,    0x36fd2a,    0x364658,    0x358f86,
    1033                 :     0x34d8b4,    0x3421e2,    0x336b10,    0x32b43e,    0x31fd6c,    0x31469a,
    1034                 :     0x308fc8,    0x2fd8f6,    0x2f2224,    0x2e6b52,    0x2db480,    0x2cfdae,
    1035                 :     0x2c46dc,    0x2b900a,    0x2ad938,    0x2a2266,    0x296b94,    0x28b4c2,
    1036                 :     0x27fdf0,    0x27471e,    0x26904c,    0x25d97a,    0x2522a8,    0x246bd6,
    1037                 :     0x23b504,    0x22fe32,    0x224760,    0x21908e,    0x20d9bc,    0x2022ea,
    1038                 :     0x1f6c18,    0x1eb546,    0x1dfe74,    0x1d47a2,    0x1c90d0,    0x1bd9fe,
    1039                 :     0x1b232c,    0x1a6c5a,    0x19b588,    0x18feb6,    0x1847e4,    0x179112,
    1040                 :     0x16da40,    0x16236e,    0x156c9c,    0x14b5ca,    0x13fef8,    0x134826,
    1041                 :     0x129154,    0x11da82,    0x1123b0,    0x106cde,    0x0fb60c,    0x0eff3a,
    1042                 :     0x0e4868,    0x0d9196,    0x0cdac4,    0x0c23f2,    0x0b6d20,    0x0ab64e,
    1043                 :     0x09ff7c,    0x0948aa,    0x0891d8,    0x07db06,    0x072434,    0x066d62,
    1044                 :     0x05b690,    0x04ffbe,    0x0448ec,    0x03921a,    0x02db48,    0x022476,
    1045                 :     0x016da4,    0x00b6d2,    0x000000,   -0x00b6d2,   -0x016da4,   -0x022476,
    1046                 :    -0x02db48,   -0x03921a,   -0x0448ec,   -0x04ffbe,   -0x05b690,   -0x066d62,
    1047                 :    -0x072434,   -0x07db06,   -0x0891d8,   -0x0948aa,   -0x09ff7c,   -0x0ab64e,
    1048                 :    -0x0b6d20,   -0x0c23f2,   -0x0cdac4,   -0x0d9196,   -0x0e4868,   -0x0eff3a,
    1049                 :    -0x0fb60c,   -0x106cde,   -0x1123b0,   -0x11da82,   -0x129154,   -0x134826,
    1050                 :    -0x13fef8,   -0x14b5ca,   -0x156c9c,   -0x16236e,   -0x16da40,   -0x179112,
    1051                 :    -0x1847e4,   -0x18feb6,   -0x19b588,   -0x1a6c5a,   -0x1b232c,   -0x1bd9fe,
    1052                 :    -0x1c90d0,   -0x1d47a2,   -0x1dfe74,   -0x1eb546,   -0x1f6c18,   -0x2022ea,
    1053                 :    -0x20d9bc,   -0x21908e,   -0x224760,   -0x22fe32,   -0x23b504,   -0x246bd6,
    1054                 :    -0x2522a8,   -0x25d97a,   -0x26904c,   -0x27471e,   -0x27fdf0,   -0x28b4c2,
    1055                 :    -0x296b94,   -0x2a2266,   -0x2ad938,   -0x2b900a,   -0x2c46dc,   -0x2cfdae,
    1056                 :    -0x2db480,   -0x2e6b52,   -0x2f2224,   -0x2fd8f6,   -0x308fc8,   -0x31469a,
    1057                 :    -0x31fd6c,   -0x32b43e,   -0x336b10,   -0x3421e2,   -0x34d8b4,   -0x358f86,
    1058                 :    -0x364658,   -0x36fd2a,   -0x37b3fc,   -0x386ace,   -0x3921a0,   -0x39d872,
    1059                 :    -0x3a8f44,   -0x3b4616,   -0x3bfce8,   -0x3cb3ba,   -0x3d6a8c,   -0x3e215e,
    1060                 :    -0x3ed830,   -0x3f8f02,   -0x4045d4,   -0x40fca6,   -0x41b378,   -0x426a4a,
    1061                 :    -0x43211c,   -0x43d7ee,   -0x448ec0,   -0x454592,   -0x45fc64,   -0x46b336,
    1062                 :    -0x476a08,   -0x4820da,   -0x48d7ac,   -0x498e7e,   -0x4a4550,   -0x4afc22,
    1063                 :    -0x4bb2f4,   -0x4c69c6,   -0x4d2098,   -0x4dd76a,   -0x4e8e3c,   -0x4f450e,
    1064                 :    -0x4ffbe0,   -0x50b2b2,   -0x516984,   -0x522056,   -0x52d728,   -0x538dfa,
    1065                 :    -0x5444cc,   -0x54fb9e,   -0x55b270,   -0x566942,   -0x572014,   -0x57d6e6,
    1066                 :    -0x588db8,   -0x59448a,   -0x59fb5c,   -0x5ab22e,
    1067                 :  };
    1068                 : 
    1069                 : const int Cb_g_tab[(MAXJSAMPLE+1) * sizeof(int)] ={
    1070                 :     0x2c8d00,    0x2c34e6,    0x2bdccc,    0x2b84b2,    0x2b2c98,    0x2ad47e,
    1071                 :     0x2a7c64,    0x2a244a,    0x29cc30,    0x297416,    0x291bfc,    0x28c3e2,
    1072                 :     0x286bc8,    0x2813ae,    0x27bb94,    0x27637a,    0x270b60,    0x26b346,
    1073                 :     0x265b2c,    0x260312,    0x25aaf8,    0x2552de,    0x24fac4,    0x24a2aa,
    1074                 :     0x244a90,    0x23f276,    0x239a5c,    0x234242,    0x22ea28,    0x22920e,
    1075                 :     0x2239f4,    0x21e1da,    0x2189c0,    0x2131a6,    0x20d98c,    0x208172,
    1076                 :     0x202958,    0x1fd13e,    0x1f7924,    0x1f210a,    0x1ec8f0,    0x1e70d6,
    1077                 :     0x1e18bc,    0x1dc0a2,    0x1d6888,    0x1d106e,    0x1cb854,    0x1c603a,
    1078                 :     0x1c0820,    0x1bb006,    0x1b57ec,    0x1affd2,    0x1aa7b8,    0x1a4f9e,
    1079                 :     0x19f784,    0x199f6a,    0x194750,    0x18ef36,    0x18971c,    0x183f02,
    1080                 :     0x17e6e8,    0x178ece,    0x1736b4,    0x16de9a,    0x168680,    0x162e66,
    1081                 :     0x15d64c,    0x157e32,    0x152618,    0x14cdfe,    0x1475e4,    0x141dca,
    1082                 :     0x13c5b0,    0x136d96,    0x13157c,    0x12bd62,    0x126548,    0x120d2e,
    1083                 :     0x11b514,    0x115cfa,    0x1104e0,    0x10acc6,    0x1054ac,    0x0ffc92,
    1084                 :     0x0fa478,    0x0f4c5e,    0x0ef444,    0x0e9c2a,    0x0e4410,    0x0debf6,
    1085                 :     0x0d93dc,    0x0d3bc2,    0x0ce3a8,    0x0c8b8e,    0x0c3374,    0x0bdb5a,
    1086                 :     0x0b8340,    0x0b2b26,    0x0ad30c,    0x0a7af2,    0x0a22d8,    0x09cabe,
    1087                 :     0x0972a4,    0x091a8a,    0x08c270,    0x086a56,    0x08123c,    0x07ba22,
    1088                 :     0x076208,    0x0709ee,    0x06b1d4,    0x0659ba,    0x0601a0,    0x05a986,
    1089                 :     0x05516c,    0x04f952,    0x04a138,    0x04491e,    0x03f104,    0x0398ea,
    1090                 :     0x0340d0,    0x02e8b6,    0x02909c,    0x023882,    0x01e068,    0x01884e,
    1091                 :     0x013034,    0x00d81a,    0x008000,    0x0027e6,   -0x003034,   -0x00884e,
    1092                 :    -0x00e068,   -0x013882,   -0x01909c,   -0x01e8b6,   -0x0240d0,   -0x0298ea,
    1093                 :    -0x02f104,   -0x03491e,   -0x03a138,   -0x03f952,   -0x04516c,   -0x04a986,
    1094                 :    -0x0501a0,   -0x0559ba,   -0x05b1d4,   -0x0609ee,   -0x066208,   -0x06ba22,
    1095                 :    -0x07123c,   -0x076a56,   -0x07c270,   -0x081a8a,   -0x0872a4,   -0x08cabe,
    1096                 :    -0x0922d8,   -0x097af2,   -0x09d30c,   -0x0a2b26,   -0x0a8340,   -0x0adb5a,
    1097                 :    -0x0b3374,   -0x0b8b8e,   -0x0be3a8,   -0x0c3bc2,   -0x0c93dc,   -0x0cebf6,
    1098                 :    -0x0d4410,   -0x0d9c2a,   -0x0df444,   -0x0e4c5e,   -0x0ea478,   -0x0efc92,
    1099                 :    -0x0f54ac,   -0x0facc6,   -0x1004e0,   -0x105cfa,   -0x10b514,   -0x110d2e,
    1100                 :    -0x116548,   -0x11bd62,   -0x12157c,   -0x126d96,   -0x12c5b0,   -0x131dca,
    1101                 :    -0x1375e4,   -0x13cdfe,   -0x142618,   -0x147e32,   -0x14d64c,   -0x152e66,
    1102                 :    -0x158680,   -0x15de9a,   -0x1636b4,   -0x168ece,   -0x16e6e8,   -0x173f02,
    1103                 :    -0x17971c,   -0x17ef36,   -0x184750,   -0x189f6a,   -0x18f784,   -0x194f9e,
    1104                 :    -0x19a7b8,   -0x19ffd2,   -0x1a57ec,   -0x1ab006,   -0x1b0820,   -0x1b603a,
    1105                 :    -0x1bb854,   -0x1c106e,   -0x1c6888,   -0x1cc0a2,   -0x1d18bc,   -0x1d70d6,
    1106                 :    -0x1dc8f0,   -0x1e210a,   -0x1e7924,   -0x1ed13e,   -0x1f2958,   -0x1f8172,
    1107                 :    -0x1fd98c,   -0x2031a6,   -0x2089c0,   -0x20e1da,   -0x2139f4,   -0x21920e,
    1108                 :    -0x21ea28,   -0x224242,   -0x229a5c,   -0x22f276,   -0x234a90,   -0x23a2aa,
    1109                 :    -0x23fac4,   -0x2452de,   -0x24aaf8,   -0x250312,   -0x255b2c,   -0x25b346,
    1110                 :    -0x260b60,   -0x26637a,   -0x26bb94,   -0x2713ae,   -0x276bc8,   -0x27c3e2,
    1111                 :    -0x281bfc,   -0x287416,   -0x28cc30,   -0x29244a,   -0x297c64,   -0x29d47e,
    1112                 :    -0x2a2c98,   -0x2a84b2,   -0x2adccc,   -0x2b34e6,
    1113                 :  };
    1114                 : 
    1115                 : 
    1116                 : /* We assume that right shift corresponds to signed division by 2 with
    1117                 :  * rounding towards minus infinity.  This is correct for typical "arithmetic
    1118                 :  * shift" instructions that shift in copies of the sign bit.  But some
    1119                 :  * C compilers implement >> with an unsigned shift.  For these machines you
    1120                 :  * must define RIGHT_SHIFT_IS_UNSIGNED.
    1121                 :  * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
    1122                 :  * It is only applied with constant shift counts.  SHIFT_TEMPS must be
    1123                 :  * included in the variables of any routine using RIGHT_SHIFT.
    1124                 :  */
    1125                 : 
    1126                 : #ifdef RIGHT_SHIFT_IS_UNSIGNED
    1127                 : #define SHIFT_TEMPS     INT32 shift_temp;
    1128                 : #define RIGHT_SHIFT(x,shft)  \
    1129                 :         ((shift_temp = (x)) < 0 ? \
    1130                 :          (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
    1131                 :          (shift_temp >> (shft)))
    1132                 : #else
    1133                 : #define SHIFT_TEMPS
    1134                 : #define RIGHT_SHIFT(x,shft)     ((x) >> (shft))
    1135                 : #endif
    1136                 : 
    1137                 : 
    1138                 : METHODDEF(void)
    1139             231 : ycc_rgb_convert_argb (j_decompress_ptr cinfo,
    1140                 :                  JSAMPIMAGE input_buf, JDIMENSION input_row,
    1141                 :                  JSAMPARRAY output_buf, int num_rows)
    1142                 : {
    1143             231 :   JDIMENSION num_cols = cinfo->output_width;
    1144             231 :   JSAMPLE * range_limit = cinfo->sample_range_limit;
    1145                 : 
    1146                 :   SHIFT_TEMPS
    1147                 : 
    1148                 :   /* This is used if we don't have SSE2 */
    1149                 : 
    1150             693 :   while (--num_rows >= 0) {
    1151             231 :     JSAMPROW inptr0 = input_buf[0][input_row];
    1152             231 :     JSAMPROW inptr1 = input_buf[1][input_row];
    1153             231 :     JSAMPROW inptr2 = input_buf[2][input_row];
    1154             231 :     input_row++;
    1155             231 :     PRUint32 *outptr = (PRUint32 *) *output_buf++;
    1156            3255 :     for (JDIMENSION col = 0; col < num_cols; col++) {
    1157            3024 :       int y  = GETJSAMPLE(inptr0[col]);
    1158            3024 :       int cb = GETJSAMPLE(inptr1[col]);
    1159            3024 :       int cr = GETJSAMPLE(inptr2[col]);
    1160            3024 :       JSAMPLE * range_limit_y = range_limit + y;
    1161                 :       /* Range-limiting is essential due to noise introduced by DCT losses. */
    1162            3024 :       outptr[col] = 0xFF000000 |
    1163            3024 :                     ( range_limit_y[Cr_r_tab[cr]] << 16 ) |
    1164            3024 :                     ( range_limit_y[((int) RIGHT_SHIFT(Cb_g_tab[cb] + Cr_g_tab[cr], SCALEBITS))] << 8 ) |
    1165            6048 :                     ( range_limit_y[Cb_b_tab[cb]] );
    1166                 :     }
    1167                 :   }
    1168             231 : }
    1169                 : 
    1170                 : 
    1171                 : /**************** Inverted CMYK -> RGB conversion **************/
    1172                 : /*
    1173                 :  * Input is (Inverted) CMYK stored as 4 bytes per pixel.
    1174                 :  * Output is RGB stored as 3 bytes per pixel.
    1175                 :  * @param row Points to row buffer containing the CMYK bytes for each pixel in the row.
    1176                 :  * @param width Number of pixels in the row.
    1177                 :  */
    1178               0 : static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
    1179                 : {
    1180                 :   /* Work from end to front to shrink from 4 bytes per pixel to 3 */
    1181               0 :   JSAMPROW in = row + width*4;
    1182               0 :   JSAMPROW out = in;
    1183                 : 
    1184               0 :   for (PRUint32 i = width; i > 0; i--) {
    1185               0 :     in -= 4;
    1186               0 :     out -= 3;
    1187                 : 
    1188                 :     // Source is 'Inverted CMYK', output is RGB.
    1189                 :     // See: http://www.easyrgb.com/math.php?MATH=M12#text12
    1190                 :     // Or:  http://www.ilkeratalay.com/colorspacesfaq.php#rgb
    1191                 : 
    1192                 :     // From CMYK to CMY
    1193                 :     // C = ( C * ( 1 - K ) + K )
    1194                 :     // M = ( M * ( 1 - K ) + K )
    1195                 :     // Y = ( Y * ( 1 - K ) + K )
    1196                 : 
    1197                 :     // From Inverted CMYK to CMY is thus:
    1198                 :     // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
    1199                 :     // Same for M and Y
    1200                 : 
    1201                 :     // Convert from CMY (0..1) to RGB (0..1)
    1202                 :     // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
    1203                 :     // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
    1204                 :     // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
    1205                 :   
    1206                 :     // Convert from Inverted CMYK (0..255) to RGB (0..255)
    1207               0 :     const PRUint32 iC = in[0];
    1208               0 :     const PRUint32 iM = in[1];
    1209               0 :     const PRUint32 iY = in[2];
    1210               0 :     const PRUint32 iK = in[3];
    1211               0 :     out[0] = iC*iK/255;   // Red
    1212               0 :     out[1] = iM*iK/255;   // Green
    1213               0 :     out[2] = iY*iK/255;   // Blue
    1214                 :   }
    1215            4392 : }

Generated by: LCOV version 1.7