Bug 1116733 (Part 2) - Remove DecodeStrategy and frame allocation handling outside of Decoder. r=tn
authorSeth Fowler <seth@mozilla.com>
Thu, 08 Jan 2015 00:04:31 -0800
changeset 248559 b4cdc04f65550567f05b881bc4a89224a751b8c9
parent 248558 c96ef32cd8a5852e04e7e3924dd52cd48c709433
child 248560 25d6527235cabab1a0e25e3dd6126120e39e3dde
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1116733
milestone37.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 1116733 (Part 2) - Remove DecodeStrategy and frame allocation handling outside of Decoder. r=tn
image/decoders/nsBMPDecoder.cpp
image/decoders/nsBMPDecoder.h
image/decoders/nsGIFDecoder2.cpp
image/decoders/nsGIFDecoder2.h
image/decoders/nsICODecoder.cpp
image/decoders/nsICODecoder.h
image/decoders/nsIconDecoder.cpp
image/decoders/nsIconDecoder.h
image/decoders/nsJPEGDecoder.cpp
image/decoders/nsJPEGDecoder.h
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
image/src/DecodePool.cpp
image/src/DecodePool.h
image/src/Decoder.cpp
image/src/Decoder.h
image/src/RasterImage.cpp
image/src/RasterImage.h
--- a/image/decoders/nsBMPDecoder.cpp
+++ b/image/decoders/nsBMPDecoder.cpp
@@ -194,18 +194,17 @@ nsBMPDecoder::CalcBitShift()
     // blue
     calcBitmask(mBitFields.blue, begin, length);
     mBitFields.blueRightShift = begin;
     mBitFields.blueLeftShift = 8 - length;
     return NS_OK;
 }
 
 void
-nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
-                            DecodeStrategy)
+nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
   // aCount=0 means EOF, mCurLine=0 means we're past end of image
   if (!aCount || !mCurLine) {
       return;
   }
 
--- a/image/decoders/nsBMPDecoder.h
+++ b/image/decoders/nsBMPDecoder.h
@@ -45,18 +45,18 @@ public:
 
     // Obtains the size of the compressed image resource
     int32_t GetCompressedImageSize() const;
 
     // Obtains whether or not a BMP file had alpha data in its 4th byte
     // for 32BPP bitmaps.  Only use after the bitmap has been processed.
     bool HasAlphaData() const;
 
-    virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-                               DecodeStrategy aStrategy) MOZ_OVERRIDE;
+    virtual void WriteInternal(const char* aBuffer,
+                               uint32_t aCount) MOZ_OVERRIDE;
     virtual void FinishInternal() MOZ_OVERRIDE;
 
 private:
 
     /// Calculates the red-, green- and blueshift in mBitFields using
     /// the bitmasks from mBitFields
     NS_METHOD CalcBitShift();
 
--- a/image/decoders/nsGIFDecoder2.cpp
+++ b/image/decoders/nsGIFDecoder2.cpp
@@ -562,18 +562,17 @@ ConvertColormap(uint32_t* aColormap, uin
   // NB: can't use 32-bit reads, they might read off the end of the buffer
   while (c--) {
     from -= 3;
     *--to = gfxPackedPixel(0xFF, from[0], from[1], from[2]);
   }
 }
 
 void
-nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy)
+nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
   // These variables changed names; renaming would make a much bigger patch :(
   const uint8_t* buf = (const uint8_t*)aBuffer;
   uint32_t len = aCount;
 
   const uint8_t* q = buf;
--- a/image/decoders/nsGIFDecoder2.h
+++ b/image/decoders/nsGIFDecoder2.h
@@ -21,18 +21,17 @@ class RasterImage;
 
 class nsGIFDecoder2 : public Decoder
 {
 public:
 
   explicit nsGIFDecoder2(RasterImage& aImage);
   ~nsGIFDecoder2();
 
-  virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy aStrategy) MOZ_OVERRIDE;
+  virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
   virtual void FinishInternal() MOZ_OVERRIDE;
   virtual Telemetry::ID SpeedHistogram() MOZ_OVERRIDE;
 
 private:
   // These functions will be called when the decoder has a decoded row,
   // frame size information, etc.
 
   void      BeginGIF();
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -209,24 +209,23 @@ nsICODecoder::SetHotSpotIfCursor()
   if (!mIsCursor) {
     return;
   }
 
   mImageMetadata.SetHotspot(mDirEntry.mXHotspot, mDirEntry.mYHotspot);
 }
 
 void
-nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
-                            DecodeStrategy aStrategy)
+nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
   if (!aCount) {
     if (mContainedDecoder) {
-      WriteToContainedDecoder(aBuffer, aCount, aStrategy);
+      WriteToContainedDecoder(aBuffer, aCount);
     }
     return;
   }
 
   while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
     if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
       if ((*aBuffer != 1) && (*aBuffer != 2)) {
         PostDataError();
@@ -341,25 +340,25 @@ nsICODecoder::WriteInternal(const char* 
     mIsPNG = !memcmp(mSignature, nsPNGDecoder::pngSignatureBytes,
                      PNGSIGNATURESIZE);
     if (mIsPNG) {
       mContainedDecoder = new nsPNGDecoder(mImage);
       mContainedDecoder->SetSizeDecode(IsSizeDecode());
       mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
                                            mColormap, mColormapSize,
                                            Move(mRefForContainedDecoder));
-      if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE, aStrategy)) {
+      if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE)) {
         return;
       }
     }
   }
 
   // If we have a PNG, let the PNG decoder do all of the rest of the work
   if (mIsPNG && mContainedDecoder && mPos >= mImageOffset + PNGSIGNATURESIZE) {
-    if (!WriteToContainedDecoder(aBuffer, aCount, aStrategy)) {
+    if (!WriteToContainedDecoder(aBuffer, aCount)) {
       return;
     }
 
     if (!HasSize() && mContainedDecoder->HasSize()) {
       PostSize(mContainedDecoder->GetImageMetadata().GetWidth(),
                mContainedDecoder->GetImageMetadata().GetHeight());
     }
 
@@ -428,18 +427,17 @@ nsICODecoder::WriteInternal(const char* 
     // The ICO format when containing a BMP does not include the 14 byte
     // bitmap file header. To use the code of the BMP decoder we need to
     // generate this header ourselves and feed it to the BMP decoder.
     int8_t bfhBuffer[BMPFILEHEADERSIZE];
     if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
       PostDataError();
       return;
     }
-    if (!WriteToContainedDecoder((const char*)bfhBuffer, sizeof(bfhBuffer),
-                                  aStrategy)) {
+    if (!WriteToContainedDecoder((const char*)bfhBuffer, sizeof(bfhBuffer))) {
       return;
     }
 
     // Setup the cursor hot spot if one is present
     SetHotSpotIfCursor();
 
     // Fix the ICO height from the BIH.
     // Fix the height on the BIH to be /2 so our BMP decoder will understand.
@@ -450,17 +448,17 @@ nsICODecoder::WriteInternal(const char* 
 
     // Fix the ICO width from the BIH.
     if (!FixBitmapWidth(reinterpret_cast<int8_t*>(mBIHraw))) {
       PostDataError();
       return;
     }
 
     // Write out the BMP's bitmap info header
-    if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw), aStrategy)) {
+    if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw))) {
       return;
     }
 
     PostSize(mContainedDecoder->GetImageMetadata().GetWidth(),
              mContainedDecoder->GetImageMetadata().GetHeight());
 
     // We have the size. If we're doing a size decode, we got what
     // we came for.
@@ -500,17 +498,17 @@ nsICODecoder::WriteInternal(const char* 
     if (mPos >= bmpDataOffset && mPos < bmpDataEnd) {
 
       // Figure out how much data the BMP decoder wants
       uint32_t toFeed = bmpDataEnd - mPos;
       if (toFeed > aCount) {
         toFeed = aCount;
       }
 
-      if (!WriteToContainedDecoder(aBuffer, toFeed, aStrategy)) {
+      if (!WriteToContainedDecoder(aBuffer, toFeed)) {
         return;
       }
 
       mPos += toFeed;
       aCount -= toFeed;
       aBuffer += toFeed;
     }
 
@@ -589,20 +587,19 @@ nsICODecoder::WriteInternal(const char* 
             PostHasTransparency();
         }
       }
     }
   }
 }
 
 bool
-nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount,
-                                      DecodeStrategy aStrategy)
+nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount)
 {
-  mContainedDecoder->Write(aBuffer, aCount, aStrategy);
+  mContainedDecoder->Write(aBuffer, aCount);
   mProgress |= mContainedDecoder->TakeProgress();
   mInvalidRect.Union(mContainedDecoder->TakeInvalidRect());
   if (mContainedDecoder->HasDataError()) {
     mDataError = mContainedDecoder->HasDataError();
   }
   if (mContainedDecoder->HasDecoderError()) {
     PostDecoderError(mContainedDecoder->GetDecoderError());
   }
--- a/image/decoders/nsICODecoder.h
+++ b/image/decoders/nsICODecoder.h
@@ -33,27 +33,27 @@ public:
   }
 
   // Obtains the height of the icon directory entry
   uint32_t GetRealHeight() const
   {
     return mDirEntry.mHeight == 0 ? 256 : mDirEntry.mHeight;
   }
 
-  virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy aStrategy) MOZ_OVERRIDE;
+  virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
   virtual void FinishInternal() MOZ_OVERRIDE;
+  virtual nsresult AllocateFrame() MOZ_OVERRIDE;
+
+protected:
   virtual bool NeedsNewFrame() const MOZ_OVERRIDE;
-  virtual nsresult AllocateFrame() MOZ_OVERRIDE;
 
 private:
   // Writes to the contained decoder and sets the appropriate errors
   // Returns true if there are no errors.
-  bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount,
-                               DecodeStrategy aStrategy);
+  bool WriteToContainedDecoder(const char* aBuffer, uint32_t aCount);
 
   // Processes a single dir entry of the icon resource
   void ProcessDirEntry(IconDirEntry& aTarget);
   // Sets the hotspot property of if we have a cursor
   void SetHotSpotIfCursor();
   // Creates a bitmap file header buffer, returns true if successful
   bool FillBitmapFileHeaderBuffer(int8_t *bfh);
   // Fixes the ICO height to match that of the BIH.
--- a/image/decoders/nsIconDecoder.cpp
+++ b/image/decoders/nsIconDecoder.cpp
@@ -24,18 +24,17 @@ nsIconDecoder::nsIconDecoder(RasterImage
 {
   // Nothing to do
 }
 
 nsIconDecoder::~nsIconDecoder()
 { }
 
 void
-nsIconDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy)
+nsIconDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
   // We put this here to avoid errors about crossing initialization with case
   // jumps on linux.
   uint32_t bytesToRead = 0;
 
   // Loop until the input data is gone
--- a/image/decoders/nsIconDecoder.h
+++ b/image/decoders/nsIconDecoder.h
@@ -36,18 +36,17 @@ class RasterImage;
 
 class nsIconDecoder : public Decoder
 {
 public:
 
   explicit nsIconDecoder(RasterImage& aImage);
   virtual ~nsIconDecoder();
 
-  virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy aStrategy) MOZ_OVERRIDE;
+  virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
 
   uint8_t mWidth;
   uint8_t mHeight;
   uint32_t mPixBytesRead;
   uint32_t mState;
 };
 
 enum {
--- a/image/decoders/nsJPEGDecoder.cpp
+++ b/image/decoders/nsJPEGDecoder.cpp
@@ -185,18 +185,17 @@ nsJPEGDecoder::FinishInternal()
   if ((mState != JPEG_DONE && mState != JPEG_SINK_NON_JPEG_TRAILER) &&
       (mState != JPEG_ERROR) &&
       !IsSizeDecode()) {
     mState = JPEG_DONE;
   }
 }
 
 void
-nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy)
+nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   mSegment = (const JOCTET*)aBuffer;
   mSegmentLen = aCount;
 
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
   // Return here if there is a fatal error within libjpeg.
   nsresult error_code;
--- a/image/decoders/nsJPEGDecoder.h
+++ b/image/decoders/nsJPEGDecoder.h
@@ -51,18 +51,17 @@ struct Orientation;
 
 class nsJPEGDecoder : public Decoder
 {
 public:
   nsJPEGDecoder(RasterImage& aImage, Decoder::DecodeStyle aDecodeStyle);
   virtual ~nsJPEGDecoder();
 
   virtual void InitInternal() MOZ_OVERRIDE;
-  virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy aStrategy) MOZ_OVERRIDE;
+  virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
   virtual void FinishInternal() MOZ_OVERRIDE;
 
   virtual Telemetry::ID SpeedHistogram() MOZ_OVERRIDE;
   void NotifyDone();
 
 protected:
   Orientation ReadOrientationFromEXIF();
   void OutputScanlines(bool* suspend);
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -308,18 +308,17 @@ nsPNGDecoder::InitInternal()
   png_set_progressive_read_fn(mPNG, static_cast<png_voidp>(this),
                               nsPNGDecoder::info_callback,
                               nsPNGDecoder::row_callback,
                               nsPNGDecoder::end_callback);
 
 }
 
 void
-nsPNGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount,
-                            DecodeStrategy)
+nsPNGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
 {
   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
 
   // If we only want width/height, we don't need to go through libpng
   if (IsSizeDecode()) {
 
     // Are we done?
     if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -23,18 +23,17 @@ class RasterImage;
 
 class nsPNGDecoder : public Decoder
 {
 public:
   explicit nsPNGDecoder(RasterImage& aImage);
   virtual ~nsPNGDecoder();
 
   virtual void InitInternal() MOZ_OVERRIDE;
-  virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-                             DecodeStrategy aStrategy) MOZ_OVERRIDE;
+  virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
   virtual Telemetry::ID SpeedHistogram() MOZ_OVERRIDE;
 
   void CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
                    int32_t width, int32_t height,
                    gfx::SurfaceFormat format);
   void EndImageFrame();
 
   // Check if PNG is valid ICO (32bpp RGBA)
--- a/image/src/DecodePool.cpp
+++ b/image/src/DecodePool.cpp
@@ -61,59 +61,16 @@ public:
 private:
   explicit NotifyProgressWorker(RasterImage* aImage)
     : mImage(aImage)
   { }
 
   nsRefPtr<RasterImage> mImage;
 };
 
-class FrameNeededWorker : public nsRunnable
-{
-public:
-  /**
-   * Called when an off-main-thread decoder needs a new frame to be allocated on
-   * the main thread.
-   *
-   * After allocating the new frame, the worker will call RequestDecode to
-   * continue decoding.
-   */
-  static void Dispatch(RasterImage* aImage)
-  {
-    nsCOMPtr<nsIRunnable> worker = new FrameNeededWorker(aImage);
-    NS_DispatchToMainThread(worker);
-  }
-
-  NS_IMETHOD Run() MOZ_OVERRIDE
-  {
-    ReentrantMonitorAutoEnter lock(mImage->mDecodingMonitor);
-    nsresult rv = NS_OK;
-
-    // If we got a synchronous decode in the mean time, we don't need to do
-    // anything.
-    if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
-      rv = mImage->mDecoder->AllocateFrame();
-    }
-
-    if (NS_SUCCEEDED(rv) && mImage->mDecoder) {
-      // By definition, we're not done decoding, so enqueue us for more decoding.
-      DecodePool::Singleton()->RequestDecode(mImage);
-    }
-
-    return NS_OK;
-  }
-
-private:
-  explicit FrameNeededWorker(RasterImage* aImage)
-    : mImage(aImage)
-  { }
-
-  nsRefPtr<RasterImage> mImage;
-};
-
 class DecodeWorker : public nsRunnable
 {
 public:
   explicit DecodeWorker(RasterImage* aImage)
     : mImage(aImage)
   { }
 
   NS_IMETHOD Run() MOZ_OVERRIDE
@@ -127,51 +84,39 @@ public:
     }
 
     // If someone came along and synchronously decoded us, there's nothing for us to do.
     if (!mImage->mDecoder || mImage->IsDecodeFinished()) {
       NotifyProgressWorker::Dispatch(mImage);
       return NS_OK;
     }
 
-    // If we're a decode job that's been enqueued since a previous decode that
-    // still needs a new frame, we can't do anything. Wait until the
-    // FrameNeededWorker enqueues another frame.
-    if (mImage->mDecoder->NeedsNewFrame()) {
-      return NS_OK;
-    }
-
     mImage->mDecodeStatus = DecodeStatus::ACTIVE;
 
     size_t oldByteCount = mImage->mDecoder->BytesDecoded();
 
     // Multithreaded decoding can be disabled. If we've done so, we don't want
     // to monopolize the main thread, and will allow a timeout.
     DecodeUntil type = NS_IsMainThread() ? DecodeUntil::TIME
                                          : DecodeUntil::DONE_BYTES;
 
     size_t maxBytes = mImage->mSourceData.Length() -
                       mImage->mDecoder->BytesDecoded();
-    DecodePool::Singleton()->DecodeSomeOfImage(mImage, DecodeStrategy::ASYNC,
-                                               type, maxBytes);
+    DecodePool::Singleton()->DecodeSomeOfImage(mImage, type, maxBytes);
 
     size_t bytesDecoded = mImage->mDecoder->BytesDecoded() - oldByteCount;
 
     mImage->mDecodeStatus = DecodeStatus::WORK_DONE;
 
-    if (mImage->mDecoder && mImage->mDecoder->NeedsNewFrame()) {
-      // The decoder needs a new frame. Enqueue an event to get it; that event
-      // will enqueue another decode request when it's done.
-      FrameNeededWorker::Dispatch(mImage);
-    } else if (mImage->mDecoder &&
-               !mImage->mError &&
-               !mImage->mPendingError &&
-               !mImage->IsDecodeFinished() &&
-               bytesDecoded < maxBytes &&
-               bytesDecoded > 0) {
+    if (mImage->mDecoder &&
+        !mImage->mError &&
+        !mImage->mPendingError &&
+        !mImage->IsDecodeFinished() &&
+        bytesDecoded < maxBytes &&
+        bytesDecoded > 0) {
       // We aren't finished decoding, and we have more data, so add this request
       // to the back of the list.
       DecodePool::Singleton()->RequestDecode(mImage);
     } else {
       // Nothing more for us to do - let everyone know what happened.
       NotifyProgressWorker::Dispatch(mImage);
     }
 
@@ -318,66 +263,56 @@ DecodePool::Observe(nsISupports*, const 
 }
 
 void
 DecodePool::RequestDecode(RasterImage* aImage)
 {
   MOZ_ASSERT(aImage->mDecoder);
   aImage->mDecodingMonitor.AssertCurrentThreadIn();
 
-  // If we're currently waiting on a new frame for this image, we can't do any
-  // decoding.
-  if (!aImage->mDecoder->NeedsNewFrame()) {
-    if (aImage->mDecodeStatus == DecodeStatus::PENDING ||
-        aImage->mDecodeStatus == DecodeStatus::ACTIVE) {
-      // The image is already in our list of images to decode, or currently being
-      // decoded, so we don't have to do anything else.
-      return;
-    }
+  if (aImage->mDecodeStatus == DecodeStatus::PENDING ||
+      aImage->mDecodeStatus == DecodeStatus::ACTIVE) {
+    // The image is already in our list of images to decode, or currently being
+    // decoded, so we don't have to do anything else.
+    return;
+  }
 
-    aImage->mDecodeStatus = DecodeStatus::PENDING;
-    nsCOMPtr<nsIRunnable> worker = new DecodeWorker(aImage);
+  aImage->mDecodeStatus = DecodeStatus::PENDING;
+  nsCOMPtr<nsIRunnable> worker = new DecodeWorker(aImage);
 
-    MutexAutoLock threadPoolLock(mThreadPoolMutex);
-    if (!gfxPrefs::ImageMTDecodingEnabled() || !mThreadPool) {
-      NS_DispatchToMainThread(worker);
-    } else {
-      mThreadPool->Dispatch(worker, nsIEventTarget::DISPATCH_NORMAL);
-    }
+  MutexAutoLock threadPoolLock(mThreadPoolMutex);
+  if (!gfxPrefs::ImageMTDecodingEnabled() || !mThreadPool) {
+    NS_DispatchToMainThread(worker);
+  } else {
+    mThreadPool->Dispatch(worker, nsIEventTarget::DISPATCH_NORMAL);
   }
 }
 
 void
-DecodePool::DecodeABitOf(RasterImage* aImage, DecodeStrategy aStrategy)
+DecodePool::DecodeABitOf(RasterImage* aImage)
 {
   MOZ_ASSERT(NS_IsMainThread());
   aImage->mDecodingMonitor.AssertCurrentThreadIn();
 
   // If the image is waiting for decode work to be notified, go ahead and do that.
   if (aImage->mDecodeStatus == DecodeStatus::WORK_DONE) {
     aImage->FinishedSomeDecoding();
   }
 
-  DecodeSomeOfImage(aImage, aStrategy);
+  DecodeSomeOfImage(aImage);
 
   aImage->FinishedSomeDecoding();
 
-  // If the decoder needs a new frame, enqueue an event to get it; that event
-  // will enqueue another decode request when it's done.
-  if (aImage->mDecoder && aImage->mDecoder->NeedsNewFrame()) {
-    FrameNeededWorker::Dispatch(aImage);
-  } else {
-    // If we aren't yet finished decoding and we have more data in hand, add
-    // this request to the back of the priority list.
-    if (aImage->mDecoder &&
-        !aImage->mError &&
-        !aImage->IsDecodeFinished() &&
-        aImage->mSourceData.Length() > aImage->mDecoder->BytesDecoded()) {
-      RequestDecode(aImage);
-    }
+  // If we aren't yet finished decoding and we have more data in hand, add
+  // this request to the back of the priority list.
+  if (aImage->mDecoder &&
+      !aImage->mError &&
+      !aImage->IsDecodeFinished() &&
+      aImage->mSourceData.Length() > aImage->mDecoder->BytesDecoded()) {
+    RequestDecode(aImage);
   }
 }
 
 /* static */ void
 DecodePool::StopDecoding(RasterImage* aImage)
 {
   aImage->mDecodingMonitor.AssertCurrentThreadIn();
 
@@ -396,38 +331,26 @@ DecodePool::DecodeUntilSizeAvailable(Ras
   if (aImage->mDecodeStatus == DecodeStatus::WORK_DONE) {
     nsresult rv = aImage->FinishedSomeDecoding();
     if (NS_FAILED(rv)) {
       aImage->DoError();
       return rv;
     }
   }
 
-  // We use DecodeStrategy::ASYNC here because we just want to get the size
-  // information here and defer the rest of the work.
-  nsresult rv =
-    DecodeSomeOfImage(aImage, DecodeStrategy::ASYNC, DecodeUntil::SIZE);
+  nsresult rv = DecodeSomeOfImage(aImage, DecodeUntil::SIZE);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  // If the decoder needs a new frame, enqueue an event to get it; that event
-  // will enqueue another decode request when it's done.
-  if (aImage->mDecoder && aImage->mDecoder->NeedsNewFrame()) {
-    FrameNeededWorker::Dispatch(aImage);
-  } else {
-    rv = aImage->FinishedSomeDecoding();
-  }
-
-  return rv;
+  return aImage->FinishedSomeDecoding();
 }
 
 nsresult
 DecodePool::DecodeSomeOfImage(RasterImage* aImage,
-                              DecodeStrategy aStrategy,
                               DecodeUntil aDecodeUntil /* = DecodeUntil::TIME */,
                               uint32_t bytesToDecode /* = 0 */)
 {
   MOZ_ASSERT(aImage->mInitialized, "Worker active for uninitialized container");
   aImage->mDecodingMonitor.AssertCurrentThreadIn();
 
   // If an error is flagged, it probably happened while we were waiting
   // in the event queue.
@@ -442,25 +365,16 @@ DecodePool::DecodeSomeOfImage(RasterImag
   }
 
   // If mDecoded or we don't have a decoder, we must have finished already (for
   // example, a synchronous decode request came while the worker was pending).
   if (!aImage->mDecoder || aImage->mDecoded) {
     return NS_OK;
   }
 
-  if (aImage->mDecoder->NeedsNewFrame()) {
-    if (aStrategy == DecodeStrategy::SYNC) {
-      MOZ_ASSERT(NS_IsMainThread());
-      aImage->mDecoder->AllocateFrame();
-    } else {
-      return NS_OK;
-    }
-  }
-
   nsRefPtr<Decoder> decoderKungFuDeathGrip = aImage->mDecoder;
 
   uint32_t maxBytes;
   if (aImage->mDecoder->IsSizeDecode()) {
     // Decode all available data if we're a size decode; they're cheap, and we
     // want them to be more or less synchronous.
     maxBytes = aImage->mSourceData.Length();
   } else {
@@ -477,26 +391,22 @@ DecodePool::DecodeSomeOfImage(RasterImag
   TimeStamp deadline = TimeStamp::Now() +
                        TimeDuration::FromMilliseconds(gfxPrefs::ImageMemMaxMSBeforeYield());
 
   // We keep decoding chunks until:
   //  * we don't have any data left to decode,
   //  * the decode completes,
   //  * we're an DecodeUntil::SIZE decode and we get the size, or
   //  * we run out of time.
-  // We also try to decode at least one "chunk" if we've allocated a new frame,
-  // even if we have no more data to send to the decoder.
-  while ((aImage->mSourceData.Length() > aImage->mDecoder->BytesDecoded() &&
-          bytesToDecode > 0 &&
-          !aImage->IsDecodeFinished() &&
-          !(aDecodeUntil == DecodeUntil::SIZE && aImage->mHasSize) &&
-          !aImage->mDecoder->NeedsNewFrame()) ||
-         aImage->mDecoder->NeedsToFlushData()) {
+  while (aImage->mSourceData.Length() > aImage->mDecoder->BytesDecoded() &&
+         bytesToDecode > 0 &&
+         !aImage->IsDecodeFinished() &&
+         !(aDecodeUntil == DecodeUntil::SIZE && aImage->mHasSize)) {
     uint32_t chunkSize = min(bytesToDecode, maxBytes);
-    nsresult rv = aImage->DecodeSomeData(chunkSize, aStrategy);
+    nsresult rv = aImage->DecodeSomeData(chunkSize);
     if (NS_FAILED(rv)) {
       aImage->DoError();
       return rv;
     }
 
     bytesToDecode -= chunkSize;
 
     // Yield if we've been decoding for too long. We check this _after_ decoding
--- a/image/src/DecodePool.h
+++ b/image/src/DecodePool.h
@@ -20,32 +20,16 @@
 class nsIThreadPool;
 
 namespace mozilla {
 namespace image {
 
 class Decoder;
 class RasterImage;
 
-MOZ_BEGIN_ENUM_CLASS(DecodeStrategy, uint8_t)
-  // DecodeStrategy::SYNC requests a synchronous decode, which will continue
-  // decoding frames as long as it has more source data. It returns to the
-  // caller only once decoding is complete (or until it needs more source data
-  // before continuing). Because DecodeStrategy::SYNC can involve allocating new
-  // imgFrames, it can only be run on the main thread.
-  SYNC,
-
-  // DecodeStrategy::ASYNC requests an asynchronous decode, which will continue
-  // decoding until it either finishes a frame or runs out of source data.
-  // Because DecodeStrategy::ASYNC does not allocate new imgFrames, it can be
-  // safely run off the main thread. (And hence workers in the decode pool
-  // always use it.)
-  ASYNC
-MOZ_END_ENUM_CLASS(DecodeStrategy)
-
 MOZ_BEGIN_ENUM_CLASS(DecodeStatus, uint8_t)
   INACTIVE,
   PENDING,
   ACTIVE,
   WORK_DONE,
   STOPPED
 MOZ_END_ENUM_CLASS(DecodeStatus)
 
@@ -87,17 +71,17 @@ public:
    * Ask the DecodePool to asynchronously decode this image.
    */
   void RequestDecode(RasterImage* aImage);
 
   /**
    * Decode aImage for a short amount of time, and post the remainder to the
    * queue.
    */
-  void DecodeABitOf(RasterImage* aImage, DecodeStrategy aStrategy);
+  void DecodeABitOf(RasterImage* aImage);
 
   /**
    * Ask the DecodePool to stop decoding this image.  Internally, we also
    * call this function when we finish decoding an image.
    *
    * Since the DecodePool keeps raw pointers to RasterImages, make sure you
    * call this before a RasterImage is destroyed!
    */
@@ -123,17 +107,16 @@ public:
 
   /**
    * Decode some chunks of the given image.  If aDecodeUntil is SIZE,
    * decode until we have the image's size, then stop. If bytesToDecode is
    * non-0, at most bytesToDecode bytes will be decoded. if aDecodeUntil is
    * DONE_BYTES, decode until all bytesToDecode bytes are decoded.
    */
   nsresult DecodeSomeOfImage(RasterImage* aImage,
-                             DecodeStrategy aStrategy,
                              DecodeUntil aDecodeUntil = DecodeUntil::TIME,
                              uint32_t bytesToDecode = 0);
 
 private:
   DecodePool();
   virtual ~DecodePool();
 
   static StaticRefPtr<DecodePool> sSingleton;
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -93,23 +93,21 @@ Decoder::InitSharedDecoder(uint8_t* aIma
   }
 
   // Implementation-specific initialization
   InitInternal();
   mInitialized = true;
 }
 
 void
-Decoder::Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
+Decoder::Write(const char* aBuffer, uint32_t aCount)
 {
   PROFILER_LABEL("ImageDecoder", "Write",
     js::ProfileEntry::Category::GRAPHICS);
 
-  MOZ_ASSERT(NS_IsMainThread() || aStrategy == DecodeStrategy::ASYNC);
-
   // We're strict about decoder errors
   MOZ_ASSERT(!HasDecoderError(),
              "Not allowed to make more decoder calls after error!");
 
   // Begin recording telemetry data.
   TimeStamp start = TimeStamp::Now();
   mChunkCount++;
 
@@ -126,28 +124,33 @@ Decoder::Write(const char* aBuffer, uint
   if (HasDataError())
     return;
 
   if (IsSizeDecode() && HasSize()) {
     // More data came in since we found the size. We have nothing to do here.
     return;
   }
 
-  // Pass the data along to the implementation
-  WriteInternal(aBuffer, aCount, aStrategy);
+  MOZ_ASSERT(!NeedsNewFrame() || HasDataError(),
+             "Should not need a new frame before writing anything");
+  MOZ_ASSERT(!NeedsToFlushData() || HasDataError(),
+             "Should not need to flush data before writing anything");
+
+  // Pass the data along to the implementation.
+  WriteInternal(aBuffer, aCount);
 
   // If we need a new frame to proceed, let's create one and call it again.
   while (NeedsNewFrame() && !HasDataError()) {
     MOZ_ASSERT(!IsSizeDecode(), "Shouldn't need new frame for size decode");
 
     nsresult rv = AllocateFrame();
 
     if (NS_SUCCEEDED(rv)) {
       // Use the data we saved when we asked for a new frame.
-      WriteInternal(nullptr, 0, aStrategy);
+      WriteInternal(nullptr, 0);
     }
 
     mNeedsToFlushData = false;
   }
 
   // Finish telemetry.
   mDecodeTime += (TimeStamp::Now() - start);
 }
@@ -413,17 +416,17 @@ Decoder::SetSizeOnImage()
                  mImageMetadata.GetOrientation());
 }
 
 /*
  * Hook stubs. Override these as necessary in decoder implementations.
  */
 
 void Decoder::InitInternal() { }
-void Decoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) { }
+void Decoder::WriteInternal(const char* aBuffer, uint32_t aCount) { }
 void Decoder::FinishInternal() { }
 
 /*
  * Progress Notifications
  */
 
 void
 Decoder::PostSize(int32_t aWidth,
--- a/image/src/Decoder.h
+++ b/image/src/Decoder.h
@@ -51,17 +51,17 @@ public:
    *
    * @param aBuffer buffer containing the data to be written
    * @param aCount the number of bytes to write
    *
    * Any errors are reported by setting the appropriate state on the decoder.
    *
    * Notifications Sent: TODO
    */
-  void Write(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy);
+  void Write(const char* aBuffer, uint32_t aCount);
 
   /**
    * Informs the decoder that all the data has been written.
    *
    * Notifications Sent: TODO
    */
   void Finish(ShutdownReason aReason);
 
@@ -175,23 +175,18 @@ public:
   // This is called by decoders when they need a new frame. These decoders
   // must then save the data they have been sent but not yet processed and
   // return from WriteInternal. When the new frame is created, WriteInternal
   // will be called again with nullptr and 0 as arguments.
   void NeedNewFrame(uint32_t frameNum, uint32_t x_offset, uint32_t y_offset,
                     uint32_t width, uint32_t height,
                     gfx::SurfaceFormat format,
                     uint8_t palette_depth = 0);
-
   virtual bool NeedsNewFrame() const { return mNeedsNewFrame; }
 
-  // Returns true if we may have stored data that we need to flush now that we
-  // have a new frame to decode into. Callers can use Write() to actually
-  // flush the data; see the documentation for that method.
-  bool NeedsToFlushData() const { return mNeedsToFlushData; }
 
   // Try to allocate a frame as described in mNewFrameData and return the
   // status code from that attempt. Clears mNewFrameData.
   virtual nsresult AllocateFrame();
 
   already_AddRefed<imgFrame> GetCurrentFrame()
   {
     nsRefPtr<imgFrame> frame = mCurrentFrame.get();
@@ -207,18 +202,17 @@ public:
 protected:
   virtual ~Decoder();
 
   /*
    * Internal hooks. Decoder implementations may override these and
    * only these methods.
    */
   virtual void InitInternal();
-  virtual void WriteInternal(const char* aBuffer, uint32_t aCount,
-    DecodeStrategy aStrategy);
+  virtual void WriteInternal(const char* aBuffer, uint32_t aCount);
   virtual void FinishInternal();
 
   /*
    * Progress notifications.
    */
 
   // Called by decoders when they determine the size of the image. Informs
   // the image of its size and sends notifications.
@@ -265,16 +259,21 @@ protected:
   // For animated images, specify the loop count. -1 means loop forever, 0
   // means a single iteration, stopping on the last frame.
   void PostDecodeDone(int32_t aLoopCount = 0);
 
   // Data errors are the fault of the source data, decoder errors are our fault
   void PostDataError();
   void PostDecoderError(nsresult aFailCode);
 
+  // Returns true if we may have stored data that we need to flush now that we
+  // have a new frame to decode into. Callers can use Write() to actually
+  // flush the data; see the documentation for that method.
+  bool NeedsToFlushData() const { return mNeedsToFlushData; }
+
   /**
    * Ensures that a given frame number exists with the given parameters, and
    * returns a RawAccessFrameRef for that frame.
    * It is not possible to create sparse frame arrays; you can only append
    * frames to the current frame array, or if there is only one frame in the
    * array, replace that frame.
    * If a non-paletted frame is desired, pass 0 for aPaletteDepth.
    */
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -1225,17 +1225,17 @@ RasterImage::AddSourceData(const char *a
   if (mDecoded) {
     return NS_OK;
   }
 
   // If we're not storing source data and we've previously gotten the size,
   // write the data directly to the decoder. (If we haven't gotten the size,
   // we'll queue up the data and write it out when we do.)
   if (!StoringSourceData() && mHasSize) {
-    rv = WriteToDecoder(aBuffer, aCount, DecodeStrategy::SYNC);
+    rv = WriteToDecoder(aBuffer, aCount);
     CONTAINER_ENSURE_SUCCESS(rv);
 
     rv = FinishedSomeDecoding();
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
   // Otherwise, we're storing data in the source buffer
   else {
@@ -1633,26 +1633,26 @@ RasterImage::ShutdownDecoder(ShutdownRea
     mSourceData.Clear();
   }
 
   return NS_OK;
 }
 
 // Writes the data to the decoder, updating the total number of bytes written.
 nsresult
-RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
+RasterImage::WriteToDecoder(const char *aBuffer, uint32_t aCount)
 {
   mDecodingMonitor.AssertCurrentThreadIn();
 
   // We should have a decoder
   NS_ABORT_IF_FALSE(mDecoder, "Trying to write to null decoder!");
 
   // Write
   nsRefPtr<Decoder> kungFuDeathGrip = mDecoder;
-  mDecoder->Write(aBuffer, aCount, aStrategy);
+  mDecoder->Write(aBuffer, aCount);
 
   CONTAINER_ENSURE_SUCCESS(mDecoder->GetDecoderError());
 
   return NS_OK;
 }
 
 // This function is called in situations where it's clear that we want the
 // frames in decoded form (Draw, LookupFrame, etc).  If we're completely decoded,
@@ -1712,21 +1712,16 @@ RasterImage::RequestDecodeCore(RequestDe
 
   if (mError)
     return NS_ERROR_FAILURE;
 
   // If we're already decoded, there's nothing to do.
   if (mDecoded)
     return NS_OK;
 
-  // If we're currently waiting for a new frame, we can't do anything until
-  // that frame is allocated.
-  if (mDecoder && mDecoder->NeedsNewFrame())
-    return NS_OK;
-
   // If we have a size decoder open, make sure we get the size
   if (mDecoder && mDecoder->IsSizeDecode()) {
     nsresult rv = DecodePool::Singleton()->DecodeUntilSizeAvailable(this);
     CONTAINER_ENSURE_SUCCESS(rv);
 
     // If we didn't get the size out of the image, we won't until we get more
     // data, so signal that we want a full decode and give up for now.
     if (!mHasSize) {
@@ -1816,17 +1811,17 @@ RasterImage::RequestDecodeCore(RequestDe
 
   // If we can do decoding now, do so.  Small images will decode completely,
   // large images will decode a bit and post themselves to the event loop
   // to finish decoding.
   if (!mDecoded && mHasSourceData && aDecodeType == SYNCHRONOUS_NOTIFY_AND_SOME_DECODE) {
     PROFILER_LABEL_PRINTF("RasterImage", "DecodeABitOf",
       js::ProfileEntry::Category::GRAPHICS, "%s", GetURIString().get());
 
-    DecodePool::Singleton()->DecodeABitOf(this, DecodeStrategy::SYNC);
+    DecodePool::Singleton()->DecodeABitOf(this);
     return NS_OK;
   }
 
   if (!mDecoded) {
     // If we get this far, dispatch the worker. We do this instead of starting
     // any immediate decoding to guarantee that all our decode notifications are
     // dispatched asynchronously, and to ensure we stay responsive.
     DecodePool::Singleton()->RequestDecode(this);
@@ -1884,32 +1879,26 @@ RasterImage::SyncDecode()
     CONTAINER_ENSURE_SUCCESS(rv);
 
     if (mDecoded && mAnim) {
       // We can't redecode animated images, so we'll have to give up.
       return NS_ERROR_NOT_AVAILABLE;
     }
   }
 
-  // If we're currently waiting on a new frame for this image, create it now.
-  if (mDecoder && mDecoder->NeedsNewFrame()) {
-    mDecoder->AllocateFrame();
-  }
-
   // If we don't have a decoder, create one
   if (!mDecoder) {
     rv = InitDecoder(/* aDoSizeDecode = */ false);
     CONTAINER_ENSURE_SUCCESS(rv);
   }
 
   MOZ_ASSERT(mDecoder);
 
   // Write everything we have
-  rv = DecodeSomeData(mSourceData.Length() - mDecoder->BytesDecoded(),
-                      DecodeStrategy::SYNC);
+  rv = DecodeSomeData(mSourceData.Length() - mDecoder->BytesDecoded());
   CONTAINER_ENSURE_SUCCESS(rv);
 
   rv = FinishedSomeDecoding();
   CONTAINER_ENSURE_SUCCESS(rv);
   
   // If our decoder's still open, there's still work to be done.
   if (mDecoder) {
     DecodePool::Singleton()->RequestDecode(this);
@@ -2210,45 +2199,34 @@ RasterImage::RequestDiscard()
     Discard();
   }
 
   return NS_OK;
 }
 
 // Flushes up to aMaxBytes to the decoder.
 nsresult
-RasterImage::DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy)
+RasterImage::DecodeSomeData(size_t aMaxBytes)
 {
   MOZ_ASSERT(mDecoder, "Should have a decoder");
 
   mDecodingMonitor.AssertCurrentThreadIn();
 
-  // First, if we've just been called because we allocated a frame on the main
-  // thread, let the decoder deal with the data it set aside at that time by
-  // passing it a null buffer.
-  if (mDecoder->NeedsToFlushData()) {
-    nsresult rv = WriteToDecoder(nullptr, 0, aStrategy);
-    if (NS_FAILED(rv) || mDecoder->NeedsNewFrame()) {
-      return rv;
-    }
-  }
-
   // If we have nothing else to decode, return.
   if (mDecoder->BytesDecoded() == mSourceData.Length()) {
     return NS_OK;
   }
 
   MOZ_ASSERT(mDecoder->BytesDecoded() < mSourceData.Length());
 
   // write the proper amount of data
   size_t bytesToDecode = min(aMaxBytes,
                              mSourceData.Length() - mDecoder->BytesDecoded());
   return WriteToDecoder(mSourceData.Elements() + mDecoder->BytesDecoded(),
-                        bytesToDecode,
-                        aStrategy);
+                        bytesToDecode);
 
 }
 
 // There are various indicators that tell us we're finished with the decode
 // task at hand and can shut down the decoder.
 //
 // This method may not be called if there is no decoder.
 bool
@@ -2262,23 +2240,16 @@ RasterImage::IsDecodeFinished()
   if (mDecoder->IsSizeDecode()) {
     if (mDecoder->HasSize()) {
       return true;
     }
   } else if (mDecoder->GetDecodeDone()) {
     return true;
   }
 
-  // If the decoder returned because it needed a new frame and we haven't
-  // written to it since then, the decoder may be storing data that it hasn't
-  // decoded yet.
-  if (mDecoder->NeedsNewFrame() || mDecoder->NeedsToFlushData()) {
-    return false;
-  }
-
   // Otherwise, if we have all the source data and wrote all the source data,
   // we're done.
   //
   // (NB - This can be the case even for non-erroneous images because
   // Decoder::GetDecodeDone() might not return true until after we call
   // Decoder::Finish() in ShutdownDecoder())
   if (mHasSourceData && (mDecoder->BytesDecoded() == mSourceData.Length())) {
     return true;
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -421,18 +421,18 @@ private: // data
   bool                       mPendingError:1;
 
   // Decoding
   nsresult RequestDecodeIfNeeded(nsresult aStatus, ShutdownReason aReason,
                                  bool aDone, bool aWasSize);
   nsresult WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify);
   nsresult SyncDecode();
   nsresult InitDecoder(bool aDoSizeDecode);
-  nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount, DecodeStrategy aStrategy);
-  nsresult DecodeSomeData(size_t aMaxBytes, DecodeStrategy aStrategy);
+  nsresult WriteToDecoder(const char *aBuffer, uint32_t aCount);
+  nsresult DecodeSomeData(size_t aMaxBytes);
   bool     IsDecodeFinished();
   TimeStamp mDrawStartTime;
 
   // Initializes ProgressTracker and resets it on RasterImage destruction.
   nsAutoPtr<ProgressTrackerInit> mProgressTrackerInit;
 
   nsresult ShutdownDecoder(ShutdownReason aReason);