Bug 812602. Don't decode jpegs progressively when we have all the data. r=joe
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Sun, 18 Nov 2012 20:18:52 -0500
changeset 113650 3d6eb774184a64a83ca682a98f8d9cc2081ee86b
parent 113649 e10975ff4a070889dc8ed763de51f2f94ef6bbd5
child 113651 77c8bc0e550a2a7696ee479a109525b025123d2d
push id18283
push userjmuizelaar@mozilla.com
push dateMon, 19 Nov 2012 01:32:16 +0000
treeherdermozilla-inbound@3d6eb774184a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe
bugs812602
milestone19.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 812602. Don't decode jpegs progressively when we have all the data. r=joe Decoding progressively is slower because we duplicate work like color conversion and color correction for each outputted scan. We already suppress paints when have all of the data, so we shouldn't do this extra work.
image/decoders/nsJPEGDecoder.cpp
image/decoders/nsJPEGDecoder.h
image/src/Decoder.h
image/src/RasterImage.cpp
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -77,18 +77,19 @@ METHODDEF(boolean) fill_input_buffer (j_
 METHODDEF(void) skip_input_data (j_decompress_ptr jd, long num_bytes);
 METHODDEF(void) term_source (j_decompress_ptr jd);
 METHODDEF(void) my_error_exit (j_common_ptr cinfo);
 
 /* Normal JFIF markers can't have more bytes than this. */
 #define MAX_JPEG_MARKER_LENGTH  (((uint32_t)1 << 16) - 1)
 
 
-nsJPEGDecoder::nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
+nsJPEGDecoder::nsJPEGDecoder(RasterImage& aImage, imgIDecoderObserver* aObserver, Decoder::DecodeStyle aDecodeStyle)
  : Decoder(aImage, aObserver)
+ , mDecodeStyle(aDecodeStyle)
 {
   mState = JPEG_HEADER;
   mReading = true;
   mImageData = nullptr;
 
   mBytesToSkip = 0;
   memset(&mInfo, 0, sizeof(jpeg_decompress_struct));
   memset(&mSourceMgr, 0, sizeof(mSourceMgr));
@@ -360,19 +361,19 @@ nsJPEGDecoder::WriteInternal(const char 
                ("} (unknown colorpsace (3))"));
         return;
         break;
       }
     }
 
     /*
      * Don't allocate a giant and superfluous memory buffer
-     * when the image is a sequential JPEG.
+     * when not doing a progressive decode.
      */
-    mInfo.buffered_image = jpeg_has_multiple_scans(&mInfo);
+    mInfo.buffered_image = mDecodeStyle == PROGRESSIVE && jpeg_has_multiple_scans(&mInfo);
 
     /* Used to set up image size so arrays can be allocated */
     jpeg_calc_output_dimensions(&mInfo);
 
     uint32_t imagelength;
     if (NS_FAILED(mImage.EnsureFrame(0, 0, 0, mInfo.image_width, mInfo.image_height,
                                      gfxASurface::ImageFormatRGB24,
                                      &mImageData, &imagelength))) {
--- a/image/decoders/nsJPEGDecoder.h
+++ b/image/decoders/nsJPEGDecoder.h
@@ -47,17 +47,17 @@ typedef enum {
     JPEG_ERROR    
 } jstate;
 
 class RasterImage;
 
 class nsJPEGDecoder : public Decoder
 {
 public:
-  nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver);
+  nsJPEGDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver, Decoder::DecodeStyle aDecodeStyle);
   virtual ~nsJPEGDecoder();
 
   virtual void InitInternal();
   virtual void WriteInternal(const char* aBuffer, uint32_t aCount);
   virtual void FinishInternal();
 
   virtual Telemetry::ID SpeedHistogram();
   void NotifyDone();
@@ -86,15 +86,17 @@ public:
   JOCTET  *mProfile;
   uint32_t mProfileLength;
 
   qcms_profile *mInProfile;
   qcms_transform *mTransform;
 
   bool mReading;
 
+  const Decoder::DecodeStyle mDecodeStyle;
+
   uint32_t mCMSMode;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // nsJPEGDecoder_h__
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -115,16 +115,22 @@ public:
 
   // flags.  Keep these in sync with imgIContainer.idl.
   // SetDecodeFlags must be called before Init(), otherwise
   // default flags are assumed.
   enum {
     DECODER_NO_PREMULTIPLY_ALPHA = 0x2,     // imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA
     DECODER_NO_COLORSPACE_CONVERSION = 0x4  // imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION
   };
+
+  enum DecodeStyle {
+      PROGRESSIVE, // produce intermediate frames representing the partial state of the image
+      SEQUENTIAL // decode to final image immediately
+  };
+
   void SetDecodeFlags(uint32_t aFlags) { mDecodeFlags = aFlags; }
   uint32_t GetDecodeFlags() { return mDecodeFlags; }
 
   // Use HistogramCount as an invalid Histogram ID
   virtual Telemetry::ID SpeedHistogram() { return Telemetry::HistogramCount; }
 
 protected:
 
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -2517,17 +2517,21 @@ RasterImage::InitDecoder(bool aDoSizeDec
   switch (type) {
     case eDecoderType_png:
       mDecoder = new nsPNGDecoder(*this, observer);
       break;
     case eDecoderType_gif:
       mDecoder = new nsGIFDecoder2(*this, observer);
       break;
     case eDecoderType_jpeg:
-      mDecoder = new nsJPEGDecoder(*this, observer);
+      // If we have all the data we don't want to waste cpu time doing
+      // a progressive decode
+      mDecoder = new nsJPEGDecoder(*this, observer,
+                                   mHasBeenDecoded ? Decoder::DecodeStyle::SEQUENTIAL :
+                                                     Decoder::DecodeStyle::PROGRESSIVE);
       break;
     case eDecoderType_bmp:
       mDecoder = new nsBMPDecoder(*this, observer);
       break;
     case eDecoderType_ico:
       mDecoder = new nsICODecoder(*this, observer);
       break;
     case eDecoderType_icon: