image/decoders/nsJPEGDecoder.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "ImageLogging.h"
     8 #include "nsJPEGDecoder.h"
     9 #include "Orientation.h"
    10 #include "EXIF.h"
    12 #include "nsIInputStream.h"
    14 #include "nspr.h"
    15 #include "nsCRT.h"
    16 #include "gfxColor.h"
    18 #include "jerror.h"
    20 #include "gfxPlatform.h"
    22 extern "C" {
    23 #include "iccjpeg.h"
    24 }
    26 #if defined(IS_BIG_ENDIAN)
    27 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_XRGB
    28 #else
    29 #define MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB JCS_EXT_BGRX
    30 #endif
    32 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width);
    34 namespace mozilla {
    35 namespace image {
    37 #if defined(PR_LOGGING)
    38 static PRLogModuleInfo *
    39 GetJPEGLog()
    40 {
    41   static PRLogModuleInfo *sJPEGLog;
    42   if (!sJPEGLog)
    43     sJPEGLog = PR_NewLogModule("JPEGDecoder");
    44   return sJPEGLog;
    45 }
    47 static PRLogModuleInfo *
    48 GetJPEGDecoderAccountingLog()
    49 {
    50   static PRLogModuleInfo *sJPEGDecoderAccountingLog;
    51   if (!sJPEGDecoderAccountingLog)
    52     sJPEGDecoderAccountingLog = PR_NewLogModule("JPEGDecoderAccounting");
    53   return sJPEGDecoderAccountingLog;
    54 }
    55 #else
    56 #define GetJPEGLog()
    57 #define GetJPEGDecoderAccountingLog()
    58 #endif
    60 static qcms_profile*
    61 GetICCProfile(struct jpeg_decompress_struct &info)
    62 {
    63   JOCTET* profilebuf;
    64   uint32_t profileLength;
    65   qcms_profile* profile = nullptr;
    67   if (read_icc_profile(&info, &profilebuf, &profileLength)) {
    68     profile = qcms_profile_from_memory(profilebuf, profileLength);
    69     free(profilebuf);
    70   }
    72   return profile;
    73 }
    75 METHODDEF(void) init_source (j_decompress_ptr jd);
    76 METHODDEF(boolean) fill_input_buffer (j_decompress_ptr jd);
    77 METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
    78 METHODDEF(void) term_source (j_decompress_ptr jd);
    79 METHODDEF(void) my_error_exit (j_common_ptr cinfo);
    81 /* Normal JFIF markers can't have more bytes than this. */
    82 #define MAX_JPEG_MARKER_LENGTH  (((uint32_t)1 << 16) - 1)
    85 nsJPEGDecoder::nsJPEGDecoder(RasterImage& aImage, Decoder::DecodeStyle aDecodeStyle)
    86  : Decoder(aImage)
    87  , mDecodeStyle(aDecodeStyle)
    88 {
    89   mState = JPEG_HEADER;
    90   mReading = true;
    91   mImageData = nullptr;
    93   mBytesToSkip = 0;
    94   memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
    95   memset(&mSourceMgr, 0, sizeof(mSourceMgr));
    96   mInfo.client_data = (void*)this;
    98   mSegment = nullptr;
    99   mSegmentLen = 0;
   101   mBackBuffer = nullptr;
   102   mBackBufferLen = mBackBufferSize = mBackBufferUnreadLen = 0;
   104   mInProfile = nullptr;
   105   mTransform = nullptr;
   107   mCMSMode = 0;
   109   PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   110          ("nsJPEGDecoder::nsJPEGDecoder: Creating JPEG decoder %p",
   111           this));
   112 }
   114 nsJPEGDecoder::~nsJPEGDecoder()
   115 {
   116   // Step 8: Release JPEG decompression object
   117   mInfo.src = nullptr;
   118   jpeg_destroy_decompress(&mInfo);
   120   PR_FREEIF(mBackBuffer);
   121   if (mTransform)
   122     qcms_transform_release(mTransform);
   123   if (mInProfile)
   124     qcms_profile_release(mInProfile);
   126   PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   127          ("nsJPEGDecoder::~nsJPEGDecoder: Destroying JPEG decoder %p",
   128           this));
   129 }
   131 Telemetry::ID
   132 nsJPEGDecoder::SpeedHistogram()
   133 {
   134   return Telemetry::IMAGE_DECODE_SPEED_JPEG;
   135 }
   137 void
   138 nsJPEGDecoder::InitInternal()
   139 {
   140   mCMSMode = gfxPlatform::GetCMSMode();
   141   if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
   142     mCMSMode = eCMSMode_Off;
   144   /* We set up the normal JPEG error routines, then override error_exit. */
   145   mInfo.err = jpeg_std_error(&mErr.pub);
   146   /*   mInfo.err = jpeg_std_error(&mErr.pub); */
   147   mErr.pub.error_exit = my_error_exit;
   148   /* Establish the setjmp return context for my_error_exit to use. */
   149   if (setjmp(mErr.setjmp_buffer)) {
   150     /* If we get here, the JPEG code has signaled an error.
   151      * We need to clean up the JPEG object, close the input file, and return.
   152      */
   153     PostDecoderError(NS_ERROR_FAILURE);
   154     return;
   155   }
   157   /* Step 1: allocate and initialize JPEG decompression object */
   158   jpeg_create_decompress(&mInfo);
   159   /* Set the source manager */
   160   mInfo.src = &mSourceMgr;
   162   /* Step 2: specify data source (eg, a file) */
   164   /* Setup callback functions. */
   165   mSourceMgr.init_source = init_source;
   166   mSourceMgr.fill_input_buffer = fill_input_buffer;
   167   mSourceMgr.skip_input_data = skip_input_data;
   168   mSourceMgr.resync_to_restart = jpeg_resync_to_restart;
   169   mSourceMgr.term_source = term_source;
   171   /* Record app markers for ICC data */
   172   for (uint32_t m = 0; m < 16; m++)
   173     jpeg_save_markers(&mInfo, JPEG_APP0 + m, 0xFFFF);
   174 }
   176 void
   177 nsJPEGDecoder::FinishInternal()
   178 {
   179   /* If we're not in any sort of error case, flush the decoder.
   180    *
   181    * XXXbholley - It seems wrong that this should be necessary, but at the
   182    * moment I'm just folding the contents of Flush() into Close() so that
   183    * we can get rid of it.
   184    *
   185    * XXX(seth): It'd be great to get rid of this. For now, we treat this as a
   186    * write to a synchronous decoder, which means that this must be called only
   187    * on the main thread. (That's asserted in Decoder::Finish and
   188    * Decoder::FinishSharedDecoder.)
   189    */
   190   if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
   191       (mState != JPEG_ERROR) &&
   192       !IsSizeDecode())
   193     this->Write(nullptr, 0, DECODE_SYNC);
   194 }
   196 void
   197 nsJPEGDecoder::WriteInternal(const char *aBuffer, uint32_t aCount, DecodeStrategy)
   198 {
   199   mSegment = (const JOCTET *)aBuffer;
   200   mSegmentLen = aCount;
   202   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
   204   /* Return here if there is a fatal error within libjpeg. */
   205   nsresult error_code;
   206   // This cast to nsresult makes sense because setjmp() returns whatever we
   207   // passed to longjmp(), which was actually an nsresult.
   208   if ((error_code = (nsresult)setjmp(mErr.setjmp_buffer)) != NS_OK) {
   209     if (error_code == NS_ERROR_FAILURE) {
   210       PostDataError();
   211       /* Error due to corrupt stream - return NS_OK and consume silently
   212          so that libpr0n doesn't throw away a partial image load */
   213       mState = JPEG_SINK_NON_JPEG_TRAILER;
   214       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   215              ("} (setjmp returned NS_ERROR_FAILURE)"));
   216       return;
   217     } else {
   218       /* Error due to reasons external to the stream (probably out of
   219          memory) - let libpr0n attempt to clean up, even though
   220          mozilla is seconds away from falling flat on its face. */
   221       PostDecoderError(error_code);
   222       mState = JPEG_ERROR;
   223       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   224              ("} (setjmp returned an error)"));
   225       return;
   226     }
   227   }
   229   PR_LOG(GetJPEGLog(), PR_LOG_DEBUG,
   230          ("[this=%p] nsJPEGDecoder::Write -- processing JPEG data\n", this));
   232   switch (mState) {
   233   case JPEG_HEADER:
   234   {
   235     LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_HEADER case");
   237     /* Step 3: read file parameters with jpeg_read_header() */
   238     if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED) {
   239       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   240              ("} (JPEG_SUSPENDED)"));
   241       return; /* I/O suspension */
   242     }
   244     int sampleSize = mImage.GetRequestedSampleSize();
   245     if (sampleSize > 0) {
   246       mInfo.scale_num = 1;
   247       mInfo.scale_denom = sampleSize;
   248     }
   250     /* Used to set up image size so arrays can be allocated */
   251     jpeg_calc_output_dimensions(&mInfo);
   253     // Post our size to the superclass
   254     PostSize(mInfo.output_width, mInfo.output_height, ReadOrientationFromEXIF());
   255     if (HasError()) {
   256       // Setting the size led to an error.
   257       mState = JPEG_ERROR;
   258       return;
   259     }
   261     /* If we're doing a size decode, we're done. */
   262     if (IsSizeDecode())
   263       return;
   265     /* We're doing a full decode. */
   266     if (mCMSMode != eCMSMode_Off &&
   267         (mInProfile = GetICCProfile(mInfo)) != nullptr) {
   268       uint32_t profileSpace = qcms_profile_get_color_space(mInProfile);
   269       bool mismatch = false;
   271 #ifdef DEBUG_tor
   272       fprintf(stderr, "JPEG profileSpace: 0x%08X\n", profileSpace);
   273 #endif
   274       switch (mInfo.jpeg_color_space) {
   275       case JCS_GRAYSCALE:
   276         if (profileSpace == icSigRgbData)
   277           mInfo.out_color_space = JCS_RGB;
   278         else if (profileSpace != icSigGrayData)
   279           mismatch = true;
   280         break;
   281       case JCS_RGB:
   282         if (profileSpace != icSigRgbData)
   283           mismatch =  true;
   284         break;
   285       case JCS_YCbCr:
   286         if (profileSpace == icSigRgbData)
   287           mInfo.out_color_space = JCS_RGB;
   288         else
   289 	  // qcms doesn't support ycbcr
   290           mismatch = true;
   291         break;
   292       case JCS_CMYK:
   293       case JCS_YCCK:
   294 	  // qcms doesn't support cmyk
   295           mismatch = true;
   296         break;
   297       default:
   298         mState = JPEG_ERROR;
   299         PostDataError();
   300         PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   301                ("} (unknown colorpsace (1))"));
   302         return;
   303       }
   305       if (!mismatch) {
   306         qcms_data_type type;
   307         switch (mInfo.out_color_space) {
   308         case JCS_GRAYSCALE:
   309           type = QCMS_DATA_GRAY_8;
   310           break;
   311         case JCS_RGB:
   312           type = QCMS_DATA_RGB_8;
   313           break;
   314         default:
   315           mState = JPEG_ERROR;
   316           PostDataError();
   317           PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   318                  ("} (unknown colorpsace (2))"));
   319           return;
   320         }
   321 #if 0
   322         /* We don't currently support CMYK profiles. The following
   323          * code dealt with lcms types. Add something like this
   324          * back when we gain support for CMYK.
   325          */
   326         /* Adobe Photoshop writes YCCK/CMYK files with inverted data */
   327         if (mInfo.out_color_space == JCS_CMYK)
   328           type |= FLAVOR_SH(mInfo.saw_Adobe_marker ? 1 : 0);
   329 #endif
   331         if (gfxPlatform::GetCMSOutputProfile()) {
   333           /* Calculate rendering intent. */
   334           int intent = gfxPlatform::GetRenderingIntent();
   335           if (intent == -1)
   336               intent = qcms_profile_get_rendering_intent(mInProfile);
   338           /* Create the color management transform. */
   339           mTransform = qcms_transform_create(mInProfile,
   340                                           type,
   341                                           gfxPlatform::GetCMSOutputProfile(),
   342                                           QCMS_DATA_RGB_8,
   343                                           (qcms_intent)intent);
   344         }
   345       } else {
   346 #ifdef DEBUG_tor
   347         fprintf(stderr, "ICM profile colorspace mismatch\n");
   348 #endif
   349       }
   350     }
   352     if (!mTransform) {
   353       switch (mInfo.jpeg_color_space) {
   354       case JCS_GRAYSCALE:
   355       case JCS_RGB:
   356       case JCS_YCbCr:
   357         // if we're not color managing we can decode directly to
   358         // MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB
   359         if (mCMSMode != eCMSMode_All) {
   360             mInfo.out_color_space = MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB;
   361             mInfo.out_color_components = 4;
   362         } else {
   363             mInfo.out_color_space = JCS_RGB;
   364         }
   365         break;
   366       case JCS_CMYK:
   367       case JCS_YCCK:
   368         /* libjpeg can convert from YCCK to CMYK, but not to RGB */
   369         mInfo.out_color_space = JCS_CMYK;
   370         break;
   371       default:
   372         mState = JPEG_ERROR;
   373         PostDataError();
   374         PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   375                ("} (unknown colorpsace (3))"));
   376         return;
   377         break;
   378       }
   379     }
   381     /*
   382      * Don't allocate a giant and superfluous memory buffer
   383      * when not doing a progressive decode.
   384      */
   385     mInfo.buffered_image = mDecodeStyle == PROGRESSIVE && jpeg_has_multiple_scans(&mInfo);
   387     if (!mImageData) {
   388       mState = JPEG_ERROR;
   389       PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
   390       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   391              ("} (could not initialize image frame)"));
   392       return;
   393     }
   395     PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   396            ("        JPEGDecoderAccounting: nsJPEGDecoder::Write -- created image frame with %ux%u pixels",
   397             mInfo.output_width, mInfo.output_height));
   399     mState = JPEG_START_DECOMPRESS;
   400   }
   402   case JPEG_START_DECOMPRESS:
   403   {
   404     LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- entering JPEG_START_DECOMPRESS case");
   405     /* Step 4: set parameters for decompression */
   407     /* FIXME -- Should reset dct_method and dither mode
   408      * for final pass of progressive JPEG
   409      */
   410     mInfo.dct_method =  JDCT_ISLOW;
   411     mInfo.dither_mode = JDITHER_FS;
   412     mInfo.do_fancy_upsampling = TRUE;
   413     mInfo.enable_2pass_quant = FALSE;
   414     mInfo.do_block_smoothing = TRUE;
   416     /* Step 5: Start decompressor */
   417     if (jpeg_start_decompress(&mInfo) == FALSE) {
   418       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   419              ("} (I/O suspension after jpeg_start_decompress())"));
   420       return; /* I/O suspension */
   421     }
   424     /* If this is a progressive JPEG ... */
   425     mState = mInfo.buffered_image ? JPEG_DECOMPRESS_PROGRESSIVE : JPEG_DECOMPRESS_SEQUENTIAL;
   426   }
   428   case JPEG_DECOMPRESS_SEQUENTIAL:
   429   {
   430     if (mState == JPEG_DECOMPRESS_SEQUENTIAL)
   431     {
   432       LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_SEQUENTIAL case");
   434       bool suspend;
   435       OutputScanlines(&suspend);
   437       if (suspend) {
   438         PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   439                ("} (I/O suspension after OutputScanlines() - SEQUENTIAL)"));
   440         return; /* I/O suspension */
   441       }
   443       /* If we've completed image output ... */
   444       NS_ASSERTION(mInfo.output_scanline == mInfo.output_height, "We didn't process all of the data!");
   445       mState = JPEG_DONE;
   446     }
   447   }
   449   case JPEG_DECOMPRESS_PROGRESSIVE:
   450   {
   451     if (mState == JPEG_DECOMPRESS_PROGRESSIVE)
   452     {
   453       LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::Write -- JPEG_DECOMPRESS_PROGRESSIVE case");
   455       int status;
   456       do {
   457         status = jpeg_consume_input(&mInfo);
   458       } while ((status != JPEG_SUSPENDED) &&
   459                (status != JPEG_REACHED_EOI));
   461       for (;;) {
   462         if (mInfo.output_scanline == 0) {
   463           int scan = mInfo.input_scan_number;
   465           /* if we haven't displayed anything yet (output_scan_number==0)
   466              and we have enough data for a complete scan, force output
   467              of the last full scan */
   468           if ((mInfo.output_scan_number == 0) &&
   469               (scan > 1) &&
   470               (status != JPEG_REACHED_EOI))
   471             scan--;
   473           if (!jpeg_start_output(&mInfo, scan)) {
   474             PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   475                    ("} (I/O suspension after jpeg_start_output() - PROGRESSIVE)"));
   476             return; /* I/O suspension */
   477           }
   478         }
   480         if (mInfo.output_scanline == 0xffffff)
   481           mInfo.output_scanline = 0;
   483         bool suspend;
   484         OutputScanlines(&suspend);
   486         if (suspend) {
   487           if (mInfo.output_scanline == 0) {
   488             /* didn't manage to read any lines - flag so we don't call
   489                jpeg_start_output() multiple times for the same scan */
   490             mInfo.output_scanline = 0xffffff;
   491           }
   492           PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   493                  ("} (I/O suspension after OutputScanlines() - PROGRESSIVE)"));
   494           return; /* I/O suspension */
   495         }
   497         if (mInfo.output_scanline == mInfo.output_height)
   498         {
   499           if (!jpeg_finish_output(&mInfo)) {
   500             PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   501                    ("} (I/O suspension after jpeg_finish_output() - PROGRESSIVE)"));
   502             return; /* I/O suspension */
   503           }
   505           if (jpeg_input_complete(&mInfo) &&
   506               (mInfo.input_scan_number == mInfo.output_scan_number))
   507             break;
   509           mInfo.output_scanline = 0;
   510         }
   511       }
   513       mState = JPEG_DONE;
   514     }
   515   }
   517   case JPEG_DONE:
   518   {
   519     LOG_SCOPE(GetJPEGLog(), "nsJPEGDecoder::ProcessData -- entering JPEG_DONE case");
   521     /* Step 7: Finish decompression */
   523     if (jpeg_finish_decompress(&mInfo) == FALSE) {
   524       PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   525              ("} (I/O suspension after jpeg_finish_decompress() - DONE)"));
   526       return; /* I/O suspension */
   527     }
   529     mState = JPEG_SINK_NON_JPEG_TRAILER;
   531     /* we're done dude */
   532     break;
   533   }
   534   case JPEG_SINK_NON_JPEG_TRAILER:
   535     PR_LOG(GetJPEGLog(), PR_LOG_DEBUG,
   536            ("[this=%p] nsJPEGDecoder::ProcessData -- entering JPEG_SINK_NON_JPEG_TRAILER case\n", this));
   538     break;
   540   case JPEG_ERROR:
   541     NS_ABORT_IF_FALSE(0, "Should always return immediately after error and not re-enter decoder");
   542   }
   544   PR_LOG(GetJPEGDecoderAccountingLog(), PR_LOG_DEBUG,
   545          ("} (end of function)"));
   546   return;
   547 }
   549 Orientation
   550 nsJPEGDecoder::ReadOrientationFromEXIF()
   551 {
   552   jpeg_saved_marker_ptr marker;
   554   // Locate the APP1 marker, where EXIF data is stored, in the marker list.
   555   for (marker = mInfo.marker_list ; marker != nullptr ; marker = marker->next) {
   556     if (marker->marker == JPEG_APP0 + 1) 
   557       break;
   558   }
   560   // If we're at the end of the list, there's no EXIF data.
   561   if (!marker)
   562     return Orientation();
   564   // Extract the orientation information.
   565   EXIFData exif = EXIFParser::Parse(marker->data,
   566                                     static_cast<uint32_t>(marker->data_length));
   567   return exif.orientation;
   568 }
   570 void
   571 nsJPEGDecoder::NotifyDone()
   572 {
   573   PostFrameStop(FrameBlender::kFrameOpaque);
   574   PostDecodeDone();
   575 }
   577 void
   578 nsJPEGDecoder::OutputScanlines(bool* suspend)
   579 {
   580   *suspend = false;
   582   const uint32_t top = mInfo.output_scanline;
   584   while ((mInfo.output_scanline < mInfo.output_height)) {
   585       /* Use the Cairo image buffer as scanline buffer */
   586       uint32_t *imageRow = ((uint32_t*)mImageData) +
   587                            (mInfo.output_scanline * mInfo.output_width);
   589       if (mInfo.out_color_space == MOZ_JCS_EXT_NATIVE_ENDIAN_XRGB) {
   590         /* Special case: scanline will be directly converted into packed ARGB */
   591         if (jpeg_read_scanlines(&mInfo, (JSAMPARRAY)&imageRow, 1) != 1) {
   592           *suspend = true; /* suspend */
   593           break;
   594         }
   595         continue; /* all done for this row! */
   596       }
   598       JSAMPROW sampleRow = (JSAMPROW)imageRow;
   599       if (mInfo.output_components == 3) {
   600         /* Put the pixels at end of row to enable in-place expansion */
   601         sampleRow += mInfo.output_width;
   602       }
   604       /* Request one scanline.  Returns 0 or 1 scanlines. */    
   605       if (jpeg_read_scanlines(&mInfo, &sampleRow, 1) != 1) {
   606         *suspend = true; /* suspend */
   607         break;
   608       }
   610       if (mTransform) {
   611         JSAMPROW source = sampleRow;
   612         if (mInfo.out_color_space == JCS_GRAYSCALE) {
   613           /* Convert from the 1byte grey pixels at begin of row 
   614              to the 3byte RGB byte pixels at 'end' of row */
   615           sampleRow += mInfo.output_width;
   616         }
   617         qcms_transform_data(mTransform, source, sampleRow, mInfo.output_width);
   618         /* Move 3byte RGB data to end of row */
   619         if (mInfo.out_color_space == JCS_CMYK) {
   620           memmove(sampleRow + mInfo.output_width,
   621                   sampleRow,
   622                   3 * mInfo.output_width);
   623           sampleRow += mInfo.output_width;
   624         }
   625       } else {
   626         if (mInfo.out_color_space == JCS_CMYK) {
   627           /* Convert from CMYK to RGB */
   628           /* We cannot convert directly to Cairo, as the CMSRGBTransform may wants to do a RGB transform... */
   629           /* Would be better to have platform CMSenabled transformation from CMYK to (A)RGB... */
   630           cmyk_convert_rgb((JSAMPROW)imageRow, mInfo.output_width);
   631           sampleRow += mInfo.output_width;
   632         }
   633         if (mCMSMode == eCMSMode_All) {
   634           /* No embedded ICC profile - treat as sRGB */
   635           qcms_transform *transform = gfxPlatform::GetCMSRGBTransform();
   636           if (transform) {
   637             qcms_transform_data(transform, sampleRow, sampleRow, mInfo.output_width);
   638           }
   639         }
   640       }
   642       // counter for while() loops below
   643       uint32_t idx = mInfo.output_width;
   645       // copy as bytes until source pointer is 32-bit-aligned
   646       for (; (NS_PTR_TO_UINT32(sampleRow) & 0x3) && idx; --idx) {
   647         *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
   648         sampleRow += 3;
   649       }
   651       // copy pixels in blocks of 4
   652       while (idx >= 4) {
   653         GFX_BLOCK_RGB_TO_FRGB(sampleRow, imageRow);
   654         idx       -=  4;
   655         sampleRow += 12;
   656         imageRow  +=  4;
   657       }
   659       // copy remaining pixel(s)
   660       while (idx--) {
   661         // 32-bit read of final pixel will exceed buffer, so read bytes
   662         *imageRow++ = gfxPackedPixel(0xFF, sampleRow[0], sampleRow[1], sampleRow[2]);
   663         sampleRow += 3;
   664       }
   665   }
   667   if (top != mInfo.output_scanline) {
   668       nsIntRect r(0, top, mInfo.output_width, mInfo.output_scanline-top);
   669       PostInvalidation(r);
   670   }
   672 }
   675 /* Override the standard error method in the IJG JPEG decoder code. */
   676 METHODDEF(void)
   677 my_error_exit (j_common_ptr cinfo)
   678 {
   679   decoder_error_mgr *err = (decoder_error_mgr *) cinfo->err;
   681   /* Convert error to a browser error code */
   682   nsresult error_code = err->pub.msg_code == JERR_OUT_OF_MEMORY
   683                       ? NS_ERROR_OUT_OF_MEMORY
   684                       : NS_ERROR_FAILURE;
   686 #ifdef DEBUG
   687   char buffer[JMSG_LENGTH_MAX];
   689   /* Create the message */
   690   (*err->pub.format_message) (cinfo, buffer);
   692   fprintf(stderr, "JPEG decoding error:\n%s\n", buffer);
   693 #endif
   695   /* Return control to the setjmp point.  We pass an nsresult masquerading as
   696    * an int, which works because the setjmp() caller casts it back. */
   697   longjmp(err->setjmp_buffer, static_cast<int>(error_code));
   698 }
   700 /******************************************************************************/
   701 /*-----------------------------------------------------------------------------
   702  * This is the callback routine from the IJG JPEG library used to supply new
   703  * data to the decompressor when its input buffer is exhausted.  It juggles
   704  * multiple buffers in an attempt to avoid unnecessary copying of input data.
   705  *
   706  * (A simpler scheme is possible: It's much easier to use only a single
   707  * buffer; when fill_input_buffer() is called, move any unconsumed data
   708  * (beyond the current pointer/count) down to the beginning of this buffer and
   709  * then load new data into the remaining buffer space.  This approach requires
   710  * a little more data copying but is far easier to get right.)
   711  *
   712  * At any one time, the JPEG decompressor is either reading from the necko
   713  * input buffer, which is volatile across top-level calls to the IJG library,
   714  * or the "backtrack" buffer.  The backtrack buffer contains the remaining
   715  * unconsumed data from the necko buffer after parsing was suspended due
   716  * to insufficient data in some previous call to the IJG library.
   717  *
   718  * When suspending, the decompressor will back up to a convenient restart
   719  * point (typically the start of the current MCU). The variables
   720  * next_input_byte & bytes_in_buffer indicate where the restart point will be
   721  * if the current call returns FALSE.  Data beyond this point must be
   722  * rescanned after resumption, so it must be preserved in case the decompressor
   723  * decides to backtrack.
   724  *
   725  * Returns:
   726  *  TRUE if additional data is available, FALSE if no data present and
   727  *   the JPEG library should therefore suspend processing of input stream
   728  *---------------------------------------------------------------------------*/
   730 /******************************************************************************/
   731 /* data source manager method                                                 */
   732 /******************************************************************************/
   735 /******************************************************************************/
   736 /* data source manager method 
   737         Initialize source.  This is called by jpeg_read_header() before any
   738         data is actually read.  May leave
   739         bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
   740         will occur immediately).
   741 */
   742 METHODDEF(void)
   743 init_source (j_decompress_ptr jd)
   744 {
   745 }
   747 /******************************************************************************/
   748 /* data source manager method
   749         Skip num_bytes worth of data.  The buffer pointer and count should
   750         be advanced over num_bytes input bytes, refilling the buffer as
   751         needed.  This is used to skip over a potentially large amount of
   752         uninteresting data (such as an APPn marker).  In some applications
   753         it may be possible to optimize away the reading of the skipped data,
   754         but it's not clear that being smart is worth much trouble; large
   755         skips are uncommon.  bytes_in_buffer may be zero on return.
   756         A zero or negative skip count should be treated as a no-op.
   757 */
   758 METHODDEF(void)
   759 skip_input_data (j_decompress_ptr jd, long num_bytes)
   760 {
   761   struct jpeg_source_mgr *src = jd->src;
   762   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
   764   if (num_bytes > (long)src->bytes_in_buffer) {
   765     /*
   766      * Can't skip it all right now until we get more data from
   767      * network stream. Set things up so that fill_input_buffer
   768      * will skip remaining amount.
   769      */
   770     decoder->mBytesToSkip = (size_t)num_bytes - src->bytes_in_buffer;
   771     src->next_input_byte += src->bytes_in_buffer;
   772     src->bytes_in_buffer = 0;
   774   } else {
   775     /* Simple case. Just advance buffer pointer */
   777     src->bytes_in_buffer -= (size_t)num_bytes;
   778     src->next_input_byte += num_bytes;
   779   }
   780 }
   783 /******************************************************************************/
   784 /* data source manager method
   785         This is called whenever bytes_in_buffer has reached zero and more
   786         data is wanted.  In typical applications, it should read fresh data
   787         into the buffer (ignoring the current state of next_input_byte and
   788         bytes_in_buffer), reset the pointer & count to the start of the
   789         buffer, and return TRUE indicating that the buffer has been reloaded.
   790         It is not necessary to fill the buffer entirely, only to obtain at
   791         least one more byte.  bytes_in_buffer MUST be set to a positive value
   792         if TRUE is returned.  A FALSE return should only be used when I/O
   793         suspension is desired.
   794 */
   795 METHODDEF(boolean)
   796 fill_input_buffer (j_decompress_ptr jd)
   797 {
   798   struct jpeg_source_mgr *src = jd->src;
   799   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
   801   if (decoder->mReading) {
   802     const JOCTET *new_buffer = decoder->mSegment;
   803     uint32_t new_buflen = decoder->mSegmentLen;
   805     if (!new_buffer || new_buflen == 0)
   806       return false; /* suspend */
   808     decoder->mSegmentLen = 0;
   810     if (decoder->mBytesToSkip) {
   811       if (decoder->mBytesToSkip < new_buflen) {
   812         /* All done skipping bytes; Return what's left. */
   813         new_buffer += decoder->mBytesToSkip;
   814         new_buflen -= decoder->mBytesToSkip;
   815         decoder->mBytesToSkip = 0;
   816       } else {
   817         /* Still need to skip some more data in the future */
   818         decoder->mBytesToSkip -= (size_t)new_buflen;
   819         return false; /* suspend */
   820       }
   821     }
   823       decoder->mBackBufferUnreadLen = src->bytes_in_buffer;
   825     src->next_input_byte = new_buffer;
   826     src->bytes_in_buffer = (size_t)new_buflen;
   827     decoder->mReading = false;
   829     return true;
   830   }
   832   if (src->next_input_byte != decoder->mSegment) {
   833     /* Backtrack data has been permanently consumed. */
   834     decoder->mBackBufferUnreadLen = 0;
   835     decoder->mBackBufferLen = 0;
   836   }
   838   /* Save remainder of netlib buffer in backtrack buffer */
   839   const uint32_t new_backtrack_buflen = src->bytes_in_buffer + decoder->mBackBufferLen;
   841   /* Make sure backtrack buffer is big enough to hold new data. */
   842   if (decoder->mBackBufferSize < new_backtrack_buflen) {
   843     /* Check for malformed MARKER segment lengths, before allocating space for it */
   844     if (new_backtrack_buflen > MAX_JPEG_MARKER_LENGTH) {
   845       my_error_exit((j_common_ptr)(&decoder->mInfo));
   846     }
   848     /* Round up to multiple of 256 bytes. */
   849     const size_t roundup_buflen = ((new_backtrack_buflen + 255) >> 8) << 8;
   850     JOCTET *buf = (JOCTET *)PR_REALLOC(decoder->mBackBuffer, roundup_buflen);
   851     /* Check for OOM */
   852     if (!buf) {
   853       decoder->mInfo.err->msg_code = JERR_OUT_OF_MEMORY;
   854       my_error_exit((j_common_ptr)(&decoder->mInfo));
   855     }
   856     decoder->mBackBuffer = buf;
   857     decoder->mBackBufferSize = roundup_buflen;
   858   }
   860   /* Copy remainder of netlib segment into backtrack buffer. */
   861   memmove(decoder->mBackBuffer + decoder->mBackBufferLen,
   862           src->next_input_byte,
   863           src->bytes_in_buffer);
   865   /* Point to start of data to be rescanned. */
   866   src->next_input_byte = decoder->mBackBuffer + decoder->mBackBufferLen - decoder->mBackBufferUnreadLen;
   867   src->bytes_in_buffer += decoder->mBackBufferUnreadLen;
   868   decoder->mBackBufferLen = (size_t)new_backtrack_buflen;
   869   decoder->mReading = true;
   871   return false;
   872 }
   874 /******************************************************************************/
   875 /* data source manager method */
   876 /*
   877  * Terminate source --- called by jpeg_finish_decompress() after all
   878  * data has been read to clean up JPEG source manager. NOT called by 
   879  * jpeg_abort() or jpeg_destroy().
   880  */
   881 METHODDEF(void)
   882 term_source (j_decompress_ptr jd)
   883 {
   884   nsJPEGDecoder *decoder = (nsJPEGDecoder *)(jd->client_data);
   886   // This function shouldn't be called if we ran into an error we didn't
   887   // recover from.
   888   NS_ABORT_IF_FALSE(decoder->mState != JPEG_ERROR,
   889                     "Calling term_source on a JPEG with mState == JPEG_ERROR!");
   891   // Notify using a helper method to get around protectedness issues.
   892   decoder->NotifyDone();
   893 }
   895 } // namespace image
   896 } // namespace mozilla
   899 /**************** Inverted CMYK -> RGB conversion **************/
   900 /*
   901  * Input is (Inverted) CMYK stored as 4 bytes per pixel.
   902  * Output is RGB stored as 3 bytes per pixel.
   903  * @param row Points to row buffer containing the CMYK bytes for each pixel in the row.
   904  * @param width Number of pixels in the row.
   905  */
   906 static void cmyk_convert_rgb(JSAMPROW row, JDIMENSION width)
   907 {
   908   /* Work from end to front to shrink from 4 bytes per pixel to 3 */
   909   JSAMPROW in = row + width*4;
   910   JSAMPROW out = in;
   912   for (uint32_t i = width; i > 0; i--) {
   913     in -= 4;
   914     out -= 3;
   916     // Source is 'Inverted CMYK', output is RGB.
   917     // See: http://www.easyrgb.com/math.php?MATH=M12#text12
   918     // Or:  http://www.ilkeratalay.com/colorspacesfaq.php#rgb
   920     // From CMYK to CMY
   921     // C = ( C * ( 1 - K ) + K )
   922     // M = ( M * ( 1 - K ) + K )
   923     // Y = ( Y * ( 1 - K ) + K )
   925     // From Inverted CMYK to CMY is thus:
   926     // C = ( (1-iC) * (1 - (1-iK)) + (1-iK) ) => 1 - iC*iK
   927     // Same for M and Y
   929     // Convert from CMY (0..1) to RGB (0..1)
   930     // R = 1 - C => 1 - (1 - iC*iK) => iC*iK
   931     // G = 1 - M => 1 - (1 - iM*iK) => iM*iK
   932     // B = 1 - Y => 1 - (1 - iY*iK) => iY*iK
   934     // Convert from Inverted CMYK (0..255) to RGB (0..255)
   935     const uint32_t iC = in[0];
   936     const uint32_t iM = in[1];
   937     const uint32_t iY = in[2];
   938     const uint32_t iK = in[3];
   939     out[0] = iC*iK/255;   // Red
   940     out[1] = iM*iK/255;   // Green
   941     out[2] = iY*iK/255;   // Blue
   942   }
   943 }

mercurial