Bug 1151309 - Part 1: Block until the previous multipart frame is decoded before processing another. r=tn, a=sledru
authorSeth Fowler <mark.seth.fowler@gmail.com>
Tue, 14 Apr 2015 17:47:56 -0700
changeset 260295 046c97d2eb23
parent 260294 e1fb2a5ab48d
child 260296 0fcbbecc843d
push id741
push userryanvm@gmail.com
push date2015-04-27 20:01 +0000
treeherdermozilla-release@d10817faa571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, sledru
bugs1151309
milestone38.0
Bug 1151309 - Part 1: Block until the previous multipart frame is decoded before processing another. r=tn, a=sledru
image/src/MultipartImage.cpp
--- a/image/src/MultipartImage.cpp
+++ b/image/src/MultipartImage.cpp
@@ -30,71 +30,73 @@ public:
   {
     MOZ_ASSERT(aImage);
     mImage = aImage;
 
     nsRefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
     tracker->AddObserver(this);
   }
 
-  void FinishObservingWithoutNotifying()
+  void BlockUntilDecodedAndFinishObserving()
   {
-    FinishObserving(/* aNotify = */ false);
+    // Use GetFrame() to block until our image finishes decoding.
+    mImage->GetFrame(imgIContainer::FRAME_CURRENT,
+                     imgIContainer::FLAG_SYNC_DECODE);
+
+    FinishObserving();
   }
 
   virtual void Notify(int32_t aType,
                       const nsIntRect* aRect = nullptr) override
   {
     if (!mImage) {
       // We've already finished observing the last image we were given.
       return;
     }
 
     if (aType == imgINotificationObserver::FRAME_COMPLETE) {
-      FinishObserving(/* aNotify = */ true);
+      FinishObserving();
     }
   }
 
   virtual void OnLoadComplete(bool aLastPart) override
   {
     if (!mImage) {
       // We've already finished observing the last image we were given.
       return;
     }
 
     // If there's already an error, we may never get a FRAME_COMPLETE
     // notification, so go ahead and notify our owner right away.
     nsRefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
     if (tracker->GetProgress() & FLAG_HAS_ERROR) {
-      FinishObserving(/* aNotify = */ true);
+      FinishObserving();
     }
   }
 
   // Other notifications are ignored.
   virtual void BlockOnload() override { }
   virtual void UnblockOnload() override { }
   virtual void SetHasImage() override { }
   virtual void OnStartDecode() override { }
   virtual bool NotificationsDeferred() const override { return false; }
   virtual void SetNotificationsDeferred(bool) override { }
 
 private:
   virtual ~NextPartObserver() { }
 
-  void FinishObserving(bool aNotify)
+  void FinishObserving()
   {
     MOZ_ASSERT(mImage);
 
     nsRefPtr<ProgressTracker> tracker = mImage->GetProgressTracker();
     tracker->RemoveObserver(this);
     mImage = nullptr;
 
-    if (aNotify) {
-      mOwner->FinishTransition();
-    }
+    mOwner->FinishTransition();
   }
 
   MultipartImage* mOwner;
   nsRefPtr<Image> mImage;
 };
 
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -125,18 +127,19 @@ NS_IMPL_RELEASE(MultipartImage)
 
 void
 MultipartImage::BeginTransitionToPart(Image* aNextPart)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aNextPart);
 
   if (mNextPart) {
-    NS_WARNING("Decoder not keeping up with multipart image");
-    mNextPartObserver->FinishObservingWithoutNotifying();
+    // Let the decoder catch up so we don't drop frames.
+    mNextPartObserver->BlockUntilDecodedAndFinishObserving();
+    MOZ_ASSERT(!mNextPart);
   }
 
   mNextPart = aNextPart;
 
   // Start observing the next part; we'll complete the transition when
   // NextPartObserver calls FinishTransition.
   mNextPartObserver->BeginObserving(mNextPart);
   mNextPart->RequestDecode();