Bug 505385 - Part 18: Reduce number of notifications - START_REQUEST/START_CONTAINER -> SIZE_AVAILABLE, remove START_DECODE and START_FRAME. Rename remaining ones for clarity. r=joe
authorJosh Matthews <josh@joshmatthews.net>
Thu, 11 Oct 2012 21:34:24 -0400
changeset 110163 d35c748b03b0f222767442747c7eab9fa911e9e4
parent 110162 b4ec385f733b9e2e04eea14b418a9ab2aea5b673
child 110164 510e593b160b077392085b73c849654a1aa76ac1
child 110169 2adc0ce03dba4ba6548c1a0673a4c9e4d18b473a
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersjoe
bugs505385
milestone19.0a1
Bug 505385 - Part 18: Reduce number of notifications - START_REQUEST/START_CONTAINER -> SIZE_AVAILABLE, remove START_DECODE and START_FRAME. Rename remaining ones for clarity. r=joe
content/base/src/nsImageLoadingContent.cpp
content/html/document/src/ImageDocument.cpp
content/svg/content/src/nsSVGFilters.cpp
image/public/imgIDecoderObserver.idl
image/public/imgINotificationObserver.idl
image/public/imgIScriptedNotificationObserver.idl
image/src/Decoder.cpp
image/src/ScriptedNotificationObserver.cpp
image/src/imgRequestProxy.cpp
image/src/imgRequestProxy.h
image/src/imgStatusTracker.cpp
image/src/imgStatusTracker.h
image/test/mochitest/imgutils.js
image/test/mochitest/test_animSVGImage.html
image/test/unit/async_load_tests.js
image/test/unit/image_load_helpers.js
layout/generic/nsBulletFrame.cpp
layout/generic/nsImageFrame.cpp
layout/generic/nsImageFrame.h
layout/style/ImageLoader.cpp
layout/svg/nsSVGImageFrame.cpp
layout/xul/base/src/nsImageBoxFrame.cpp
layout/xul/base/src/tree/src/nsTreeImageListener.cpp
toolkit/system/gnome/nsAlertsIconListener.cpp
widget/cocoa/nsMenuItemIconX.mm
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -129,37 +129,35 @@ NS_IMETHODIMP
 nsImageLoadingContent::Notify(imgIRequest* aRequest,
                               int32_t aType,
                               const nsIntRect* aData)
 {
   if (aType == imgINotificationObserver::IS_ANIMATED) {
     return OnImageIsAnimated(aRequest);
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     // We should definitely have a request here
     NS_ABORT_IF_FALSE(aRequest, "no request?");
 
     NS_PRECONDITION(aRequest == mCurrentRequest || aRequest == mPendingRequest,
                     "Unknown request");
   }
 
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
-  if (aType != imgINotificationObserver::FRAME_CHANGED) {
-    LOOP_OVER_OBSERVERS(Notify(aRequest, aType, aData));
-  }
+  LOOP_OVER_OBSERVERS(Notify(aRequest, aType, aData));
 
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Have to check for state changes here, since we might have been in
     // the LOADING state before.
     UpdateImageState(true);
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     uint32_t reqStatus;
     aRequest->GetImageStatus(&reqStatus);
     nsresult status =
         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     return OnStopRequest(aRequest, status);
   }
 
   return NS_OK;
--- a/content/html/document/src/ImageDocument.cpp
+++ b/content/html/document/src/ImageDocument.cpp
@@ -503,23 +503,23 @@ ImageDocument::ToggleImageSize()
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
     return OnStartContainer(aRequest, image);
   }
 
-  if (aType == imgINotificationObserver::STOP_DECODE) {
+  if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     if (mImageContent) {
       // Update the background-color of the image only after the
       // image has been decoded to prevent flashes of just the
       // background-color.
       mImageContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
                              NS_LITERAL_STRING("decoded"), true);
     }
   }
@@ -528,17 +528,17 @@ ImageDocument::Notify(imgIRequest* aRequ
     // mImageContent can be null if the document is already destroyed
     if (mImageContent) {
       // Remove any decoded-related styling when the image is unloaded.
       mImageContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class,
                                true);
     }
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     uint32_t reqStatus;
     aRequest->GetImageStatus(&reqStatus);
     nsresult status =
         reqStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     return OnStopRequest(aRequest, status);
   }
 
   return NS_OK;
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -5758,27 +5758,27 @@ nsSVGFEImageElement::GetStringInfo()
 //----------------------------------------------------------------------
 // imgINotificationObserver methods
 
 NS_IMETHODIMP
 nsSVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
 {
   nsresult rv = nsImageLoadingContent::Notify(aRequest, aType, aData);
 
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Request a decode
     nsCOMPtr<imgIContainer> container;
     aRequest->GetImage(getter_AddRefs(container));
     NS_ABORT_IF_FALSE(container, "who sent the notification then?");
     container->StartDecoding();
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST ||
-      aType == imgINotificationObserver::FRAME_CHANGED ||
-      aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE ||
+      aType == imgINotificationObserver::FRAME_UPDATE ||
+      aType == imgINotificationObserver::SIZE_AVAILABLE) {
     Invalidate();
   }
 
   return rv;
 }
 
 //----------------------------------------------------------------------
 // helper methods
--- a/image/public/imgIDecoderObserver.idl
+++ b/image/public/imgIDecoderObserver.idl
@@ -38,17 +38,17 @@ interface imgIContainer;
  * all, some, or none of the notifications may fire before the call returns.
  *
  * This interface will be cleaned up in bug 505385.
  *
  * @author Stuart Parmenter <pavlov@netscape.com>
  * @version 0.1
  * @see imagelib2
  */
-[scriptable, uuid(dad8093d-384b-4923-b83c-351c4e5f9dce)]
+[scriptable, uuid(0089cf0c-210c-4b44-9ab0-8099b32bcf64)]
 interface imgIDecoderObserver : imgIContainerObserver
 {
   /**
    * Load notification.
    *
    * called at the same time that nsIRequestObserver::onStartRequest would be
    * (used only for observers of imgIRequest objects, which are nsIRequests,
    * not imgIDecoder objects)
@@ -72,23 +72,16 @@ interface imgIDecoderObserver : imgICont
    * called, the size has been set on the container and STATUS_SIZE_AVAILABLE
    * has been set on the associated imgRequest.
    */
   void onStartContainer();
 
   /**
    * Decode notification.
    *
-   * called when each frame is created.
-   */
-  void onStartFrame();
-
-  /**
-   * Decode notification.
-   *
    * called when there is more to paint.
    */
   [noscript] void onDataAvailable([const] in nsIntRect aRect);
 
   /**
    * Decode notification.
    *
    * called when a frame is finished decoding.
--- a/image/public/imgINotificationObserver.idl
+++ b/image/public/imgINotificationObserver.idl
@@ -9,25 +9,21 @@
 interface imgIRequest;
 
 %{C++
 #include "nsRect.h"
 %}
 
 [ptr] native nsIntRect(nsIntRect);
 
-[scriptable, builtinclass, uuid(9c606ef4-a8e9-45c0-9721-9d6171227ca5)]
+[scriptable, builtinclass, uuid(90b3d21c-317d-4d96-93c0-12add64a26bf)]
 interface imgINotificationObserver : nsISupports
 {
-  const long START_REQUEST = 1;
-  const long START_CONTAINER = 2;
-  const long START_FRAME = 3;
-  const long DATA_AVAILABLE = 4;
-  const long STOP_FRAME = 5;
-  const long STOP_DECODE = 7;
-  const long DISCARD = 8;
-  const long IS_ANIMATED = 9;
-  const long FRAME_CHANGED = 10;
-  const long STOP_REQUEST = 11;
-  const long START_DECODE = 12;
+  const long SIZE_AVAILABLE = 1;
+  const long FRAME_UPDATE = 2;
+  const long FRAME_COMPLETE = 3;
+  const long LOAD_COMPLETE = 4;
+  const long DECODE_COMPLETE = 5;
+  const long DISCARD = 6;
+  const long IS_ANIMATED = 7;
 
   [noscript] void notify(in imgIRequest aProxy, in long aType, [const] in nsIntRect aRect);
 };
--- a/image/public/imgIScriptedNotificationObserver.idl
+++ b/image/public/imgIScriptedNotificationObserver.idl
@@ -3,23 +3,19 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface imgIRequest;
 
-[scriptable, uuid(c5a58b5f-cd1f-4c47-a5ed-5013e0b53e95)]
+[scriptable, uuid(10be55b3-2029-41a7-a975-538efed250ed)]
 interface imgIScriptedNotificationObserver : nsISupports
 {
-  void startRequest(in imgIRequest aRequest);
-  void startContainer(in imgIRequest aRequest);
-  void startFrame(in imgIRequest aRequest);
-  void startDecode(in imgIRequest aRequest);
-  void dataAvailable(in imgIRequest aRequest);
-  void stopFrame(in imgIRequest aRequest);
-  void stopDecode(in imgIRequest aRequest);
-  void stopRequest(in imgIRequest aRequest);
+  void sizeAvailable(in imgIRequest aRequest);
+  void frameUpdate(in imgIRequest aRequest);
+  void frameComplete(in imgIRequest aRequest);
+  void loadComplete(in imgIRequest aRequest);
+  void decodeComplete(in imgIRequest aRequest);
   void discard(in imgIRequest aRequest);
   void isAnimated(in imgIRequest aRequest);
-  void frameChanged(in imgIRequest aRequest);
 };
--- a/image/src/Decoder.cpp
+++ b/image/src/Decoder.cpp
@@ -215,20 +215,16 @@ Decoder::PostFrameStart()
   mFrameCount++;
   mInFrame = true;
 
   // Decoder implementations should only call this method if they successfully
   // appended the frame to the image. So mFrameCount should always match that
   // reported by the Image.
   NS_ABORT_IF_FALSE(mFrameCount == mImage.GetNumFrames(),
                     "Decoder frame count doesn't match image's!");
-
-  // Fire notification
-  if (mObserver)
-    mObserver->OnStartFrame();
 }
 
 void
 Decoder::PostFrameStop()
 {
   // We should be mid-frame
   NS_ABORT_IF_FALSE(mInFrame, "Stopping frame when we didn't start one!");
 
--- a/image/src/ScriptedNotificationObserver.cpp
+++ b/image/src/ScriptedNotificationObserver.cpp
@@ -26,32 +26,24 @@ ScriptedNotificationObserver::ScriptedNo
 {
 }
 
 NS_IMETHODIMP
 ScriptedNotificationObserver::Notify(imgIRequest* aRequest,
                                      int32_t aType,
                                      const nsIntRect* /*aUnused*/)
 {
-  if (aType == imgINotificationObserver::START_REQUEST)
-    return mInner->StartRequest(aRequest);
-  if (aType == imgINotificationObserver::START_CONTAINER)
-    return mInner->StartContainer(aRequest);
-  if (aType == imgINotificationObserver::START_FRAME)
-    return mInner->StartFrame(aRequest);
-  if (aType == imgINotificationObserver::START_DECODE)
-    return mInner->StartDecode(aRequest);
-  if (aType == imgINotificationObserver::DATA_AVAILABLE)
-    return mInner->DataAvailable(aRequest);
-  if (aType == imgINotificationObserver::STOP_FRAME)
-    return mInner->StopFrame(aRequest);
-  if (aType == imgINotificationObserver::STOP_DECODE)
-    return mInner->StopDecode(aRequest);
-  if (aType == imgINotificationObserver::STOP_REQUEST)
-    return mInner->StopRequest(aRequest);
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE)
+    return mInner->SizeAvailable(aRequest);
+  if (aType == imgINotificationObserver::FRAME_UPDATE)
+    return mInner->FrameUpdate(aRequest);
+  if (aType == imgINotificationObserver::FRAME_COMPLETE)
+    return mInner->FrameComplete(aRequest);
+  if (aType == imgINotificationObserver::DECODE_COMPLETE)
+    return mInner->DecodeComplete(aRequest);
+  if (aType == imgINotificationObserver::LOAD_COMPLETE)
+    return mInner->LoadComplete(aRequest);
   if (aType == imgINotificationObserver::DISCARD)
     return mInner->Discard(aRequest);
   if (aType == imgINotificationObserver::IS_ANIMATED)
     return mInner->IsAnimated(aRequest);
-  if (aType == imgINotificationObserver::FRAME_CHANGED)
-    return mInner->FrameChanged(aRequest);
   return NS_OK;
 }
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -607,93 +607,60 @@ NS_IMETHODIMP imgRequestProxy::GetHasTra
     *hasData = mOwner->HasTransferredData();
   } else {
     // The safe thing to do is to claim we have data
     *hasData = true;
   }
   return NS_OK;
 }
 
-void imgRequestProxy::FrameChanged(const nsIntRect *dirtyRect)
-{
-  LOG_FUNC(gImgLog, "imgRequestProxy::FrameChanged");
-
-  if (mListener && !mCanceled) {
-    // Hold a ref to the listener while we call it, just in case.
-    nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::FRAME_CHANGED, dirtyRect);
-  }
-}
-
 /** imgIDecoderObserver methods **/
 
-void imgRequestProxy::OnStartDecode()
-{
-  LOG_FUNC(gImgLog, "imgRequestProxy::OnStartDecode");
-
-  if (mListener && !mCanceled) {
-    // Hold a ref to the listener while we call it, just in case.
-    nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::START_DECODE, nullptr);
-  }
-}
-
 void imgRequestProxy::OnStartContainer()
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnStartContainer");
 
   if (mListener && !mCanceled && !mSentStartContainer) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::START_CONTAINER, nullptr);
+    mListener->Notify(this, imgINotificationObserver::SIZE_AVAILABLE, nullptr);
     mSentStartContainer = true;
   }
 }
 
-void imgRequestProxy::OnStartFrame()
-{
-  LOG_FUNC(gImgLog, "imgRequestProxy::OnStartFrame");
-
-  if (mListener && !mCanceled) {
-    // Hold a ref to the listener while we call it, just in case.
-    nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::START_FRAME, nullptr);
-  }
-}
-
-void imgRequestProxy::OnDataAvailable(const nsIntRect * rect)
+void imgRequestProxy::OnFrameUpdate(const nsIntRect * rect)
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::DATA_AVAILABLE, rect);
+    mListener->Notify(this, imgINotificationObserver::FRAME_UPDATE, rect);
   }
 }
 
 void imgRequestProxy::OnStopFrame()
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::STOP_FRAME, nullptr);
+    mListener->Notify(this, imgINotificationObserver::FRAME_COMPLETE, nullptr);
   }
 }
 
 void imgRequestProxy::OnStopDecode()
 {
   LOG_FUNC(gImgLog, "imgRequestProxy::OnStopDecode");
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::STOP_DECODE, nullptr);
+    mListener->Notify(this, imgINotificationObserver::DECODE_COMPLETE, nullptr);
   }
 
   // Multipart needs reset for next OnStartContainer
   if (mOwner && mOwner->GetMultipart())
     mSentStartContainer = false;
 }
 
 void imgRequestProxy::OnDiscard()
@@ -719,24 +686,16 @@ void imgRequestProxy::OnImageIsAnimated(
 
 void imgRequestProxy::OnStartRequest()
 {
 #ifdef PR_LOGGING
   nsAutoCString name;
   GetName(name);
   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get());
 #endif
-
-  // Notify even if mCanceled, since OnStartRequest is guaranteed by the
-  // nsIStreamListener contract so it makes sense to do the same here.
-  if (mListener) {
-    // Hold a ref to the listener while we call it, just in case.
-    nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::START_REQUEST, nullptr);
-  }
 }
 
 void imgRequestProxy::OnStopRequest(bool lastPart)
 {
 #ifdef PR_LOGGING
   nsAutoCString name;
   GetName(name);
   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStopRequest", "name", name.get());
@@ -744,17 +703,17 @@ void imgRequestProxy::OnStopRequest(bool
   // There's all sorts of stuff here that could kill us (the OnStopRequest call
   // on the listener, the removal from the loadgroup, the release of the
   // listener, etc).  Don't let them do it.
   nsCOMPtr<imgIRequest> kungFuDeathGrip(this);
 
   if (mListener) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgINotificationObserver> kungFuDeathGrip(mListener);
-    mListener->Notify(this, imgINotificationObserver::STOP_REQUEST, nullptr);
+    mListener->Notify(this, imgINotificationObserver::LOAD_COMPLETE, nullptr);
   }
 
   // If we're expecting more data from a multipart channel, re-add ourself
   // to the loadgroup so that the document doesn't lose track of the load.
   // If the request is already a background request and there's more data
   // coming, we can just leave the request in the loadgroup as-is.
   if (lastPart || (mLoadFlags & nsIRequest::LOAD_BACKGROUND) == 0) {
     RemoveFromLoadGroup(lastPart);
--- a/image/src/imgRequestProxy.h
+++ b/image/src/imgRequestProxy.h
@@ -127,28 +127,23 @@ protected:
       nsresult mStatus;
   };
 
   // The following notification functions are protected to ensure that (friend
   // class) imgStatusTracker is the only class allowed to send us
   // notifications.
 
   /* non-virtual imgIDecoderObserver methods */
-  void OnStartDecode     ();
   void OnStartContainer  ();
-  void OnStartFrame      ();
-  void OnDataAvailable   (const nsIntRect * aRect);
+  void OnFrameUpdate     (const nsIntRect * aRect);
   void OnStopFrame       ();
   void OnStopDecode      ();
   void OnDiscard         ();
   void OnImageIsAnimated ();
 
-  /* non-virtual imgIContainerObserver methods */
-  void FrameChanged(const nsIntRect *aDirtyRect);
-
   /* non-virtual sort-of-nsIRequestObserver methods */
   void OnStartRequest();
   void OnStopRequest(bool aLastPart);
 
   /* non-virtual imgIOnloadBlocker methods */
   void BlockOnload();
   void UnblockOnload();
 
--- a/image/src/imgStatusTracker.cpp
+++ b/image/src/imgStatusTracker.cpp
@@ -41,30 +41,22 @@ NS_IMETHODIMP imgStatusTrackerObserver::
     mTracker->SendFrameChanged(iter.GetNext(), dirtyRect);
   }
 
   return NS_OK;
 }
 
 /** imgIDecoderObserver methods **/
 
-/* void onStartDecode (); */
 NS_IMETHODIMP imgStatusTrackerObserver::OnStartDecode()
 {
   LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartDecode");
   NS_ABORT_IF_FALSE(mTracker->GetImage(),
                     "OnStartDecode callback before we've created our image");
 
-  mTracker->RecordStartDecode();
-
-  nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
-  while (iter.HasMore()) {
-    mTracker->SendStartDecode(iter.GetNext());
-  }
-
   if (!mTracker->GetRequest()->GetMultipart()) {
     MOZ_ASSERT(!mTracker->mBlockingOnload);
     mTracker->mBlockingOnload = true;
 
     mTracker->RecordBlockOnload();
 
     nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
     while (iter.HasMore()) {
@@ -100,33 +92,16 @@ NS_IMETHODIMP imgStatusTrackerObserver::
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
   while (iter.HasMore()) {
     mTracker->SendStartContainer(iter.GetNext());
   }
 
   return NS_OK;
 }
 
-/* void onStartFrame (); */
-NS_IMETHODIMP imgStatusTrackerObserver::OnStartFrame()
-{
-  LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnStartFrame");
-  NS_ABORT_IF_FALSE(mTracker->GetImage(),
-                    "OnStartFrame callback before we've created our image");
-
-  mTracker->RecordStartFrame();
-
-  nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mTracker->mConsumers);
-  while (iter.HasMore()) {
-    mTracker->SendStartFrame(iter.GetNext());
-  }
-
-  return NS_OK;
-}
-
 /* [noscript] void onDataAvailable ([const] in nsIntRect rect); */
 NS_IMETHODIMP imgStatusTrackerObserver::OnDataAvailable(const nsIntRect * rect)
 {
   LOG_SCOPE(gImgLog, "imgStatusTrackerObserver::OnDataAvailable");
   NS_ABORT_IF_FALSE(mTracker->GetImage(),
                     "OnDataAvailable callback before we've created our image");
 
   mTracker->RecordDataAvailable();
@@ -415,38 +390,32 @@ imgStatusTracker::SyncNotify(imgRequestP
   // OnStartRequest
   if (mState & stateRequestStarted)
     proxy->OnStartRequest();
 
   // OnStartContainer
   if (mState & stateHasSize)
     proxy->OnStartContainer();
 
-  // OnStartDecode
-  if (mState & stateDecodeStarted)
-    proxy->OnStartDecode();
-
   // BlockOnload
   if (mState & stateBlockingOnload)
     proxy->BlockOnload();
 
   if (mImage) {
     int16_t imageType = mImage->GetType();
-    // Send frame messages (OnStartFrame, OnDataAvailable, OnStopFrame)
+    // Send frame messages (OnDataAvailable, OnStopFrame)
     if (imageType == imgIContainer::TYPE_VECTOR ||
         static_cast<RasterImage*>(mImage)->GetNumFrames() > 0) {
 
-      proxy->OnStartFrame();
-
       // OnDataAvailable
       // XXX - Should only send partial rects here, but that needs to
       // wait until we fix up the observer interface
       nsIntRect r;
       mImage->GetCurrentFrameRect(r);
-      proxy->OnDataAvailable(&r);
+      proxy->OnFrameUpdate(&r);
 
       if (mState & stateFrameStopped)
         proxy->OnStopFrame();
     }
 
     // OnImageIsAnimated
     bool isAnimated = false;
 
@@ -524,35 +493,20 @@ imgStatusTracker::RecordLoaded()
   mImageStatus |= imgIRequest::STATUS_SIZE_AVAILABLE | imgIRequest::STATUS_LOAD_COMPLETE;
   mHadLastPart = true;
 }
 
 void
 imgStatusTracker::RecordDecoded()
 {
   NS_ABORT_IF_FALSE(mImage, "RecordDecoded called before we have an Image");
-  mState |= stateDecodeStarted | stateDecodeStopped | stateFrameStopped;
+  mState |= stateDecodeStopped | stateFrameStopped;
   mImageStatus |= imgIRequest::STATUS_FRAME_COMPLETE | imgIRequest::STATUS_DECODE_COMPLETE;
 }
 
-/* non-virtual imgIDecoderObserver methods */
-void
-imgStatusTracker::RecordStartDecode()
-{
-  NS_ABORT_IF_FALSE(mImage, "RecordStartDecode without an Image");
-  mState |= stateDecodeStarted;
-}
-
-void
-imgStatusTracker::SendStartDecode(imgRequestProxy* aProxy)
-{
-  if (!aProxy->NotificationsDeferred())
-    aProxy->OnStartDecode();
-}
-
 void
 imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
 {
   NS_ABORT_IF_FALSE(mImage,
                     "RecordStartContainer called before we have an Image");
   NS_ABORT_IF_FALSE(mImage == aContainer,
                     "RecordStartContainer called with wrong Image");
   mState |= stateHasSize;
@@ -562,45 +516,30 @@ imgStatusTracker::RecordStartContainer(i
 void
 imgStatusTracker::SendStartContainer(imgRequestProxy* aProxy)
 {
   if (!aProxy->NotificationsDeferred())
     aProxy->OnStartContainer();
 }
 
 void
-imgStatusTracker::RecordStartFrame()
-{
-  NS_ABORT_IF_FALSE(mImage, "RecordStartFrame called before we have an Image");
-  // no bookkeeping necessary here - this is implied by imgIContainer's number
-  // of frames
-}
-
-void
-imgStatusTracker::SendStartFrame(imgRequestProxy* aProxy)
-{
-  if (!aProxy->NotificationsDeferred())
-    aProxy->OnStartFrame();
-}
-
-void
 imgStatusTracker::RecordDataAvailable()
 {
   NS_ABORT_IF_FALSE(mImage,
                     "RecordDataAvailable called before we have an Image");
   // no bookkeeping necessary here - this is implied by imgIContainer's
   // number of frames and frame rect
 }
 
 void
 imgStatusTracker::SendDataAvailable(imgRequestProxy* aProxy,
                                     const nsIntRect* aRect)
 {
   if (!aProxy->NotificationsDeferred())
-    aProxy->OnDataAvailable(aRect);
+    aProxy->OnFrameUpdate(aRect);
 }
 
 
 void
 imgStatusTracker::RecordStopFrame()
 {
   NS_ABORT_IF_FALSE(mImage, "RecordStopFrame called before we have an Image");
   mState |= stateFrameStopped;
@@ -637,17 +576,17 @@ imgStatusTracker::SendStopDecode(imgRequ
 }
 
 void
 imgStatusTracker::RecordDiscard()
 {
   NS_ABORT_IF_FALSE(mImage,
                     "RecordDiscard called before we have an Image");
   // Clear the state bits we no longer deserve.
-  uint32_t stateBitsToClear = stateDecodeStarted | stateDecodeStopped;
+  uint32_t stateBitsToClear = stateDecodeStopped;
   mState &= ~stateBitsToClear;
 
   // Clear the status bits we no longer deserve.
   uint32_t statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE
                                | imgIRequest::STATUS_DECODE_COMPLETE;
   mImageStatus &= ~statusBitsToClear;
 }
 
@@ -686,30 +625,29 @@ imgStatusTracker::RecordFrameChanged(con
   // don't fire while we're recording
 }
 
 void
 imgStatusTracker::SendFrameChanged(imgRequestProxy* aProxy,
                                    const nsIntRect* aDirtyRect)
 {
   if (!aProxy->NotificationsDeferred())
-    aProxy->FrameChanged(aDirtyRect);
+    aProxy->OnFrameUpdate(aDirtyRect);
 }
 
 /* non-virtual sort-of-nsIRequestObserver methods */
 void
 imgStatusTracker::RecordStartRequest()
 {
   // We're starting a new load, so clear any status and state bits indicating
   // load/decode
   mImageStatus &= ~imgIRequest::STATUS_LOAD_PARTIAL;
   mImageStatus &= ~imgIRequest::STATUS_LOAD_COMPLETE;
   mImageStatus &= ~imgIRequest::STATUS_FRAME_COMPLETE;
   mState &= ~stateRequestStarted;
-  mState &= ~stateDecodeStarted;
   mState &= ~stateDecodeStopped;
   mState &= ~stateRequestStopped;
   mState &= ~stateBlockingOnload;
 
   mState |= stateRequestStarted;
 }
 
 void
--- a/image/src/imgStatusTracker.h
+++ b/image/src/imgStatusTracker.h
@@ -27,17 +27,16 @@ class Image;
 #include "nsIRunnable.h"
 #include "nscore.h"
 #include "nsWeakReference.h"
 #include "imgIDecoderObserver.h"
 
 enum {
   stateRequestStarted    = PR_BIT(0),
   stateHasSize           = PR_BIT(1),
-  stateDecodeStarted     = PR_BIT(2),
   stateDecodeStopped     = PR_BIT(3),
   stateFrameStopped      = PR_BIT(4),
   stateRequestStopped    = PR_BIT(5),
   stateBlockingOnload    = PR_BIT(6)
 };
 
 class imgStatusTrackerObserver : public imgIDecoderObserver,
                                  public nsSupportsWeakReference
@@ -144,22 +143,18 @@ public:
   // StartContainer, StopRequest.
   void RecordLoaded();
 
   // Shorthand for recording all the decode notifications: StartDecode,
   // StartFrame, DataAvailable, StopFrame, StopDecode.
   void RecordDecoded();
 
   /* non-virtual imgIDecoderObserver methods */
-  void RecordStartDecode();
-  void SendStartDecode(imgRequestProxy* aProxy);
   void RecordStartContainer(imgIContainer* aContainer);
   void SendStartContainer(imgRequestProxy* aProxy);
-  void RecordStartFrame();
-  void SendStartFrame(imgRequestProxy* aProxy);
   void RecordDataAvailable();
   void SendDataAvailable(imgRequestProxy* aProxy, const nsIntRect* aRect);
   void RecordStopFrame();
   void SendStopFrame(imgRequestProxy* aProxy);
   void RecordStopDecode(nsresult statusg);
   void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus);
   void RecordDiscard();
   void SendDiscard(imgRequestProxy* aProxy);
--- a/image/test/mochitest/imgutils.js
+++ b/image/test/mochitest/imgutils.js
@@ -119,20 +119,16 @@ function getImagePref(pref)
   }
   else
     return null;
 }
 
 // JS implementation of imgIScriptedNotificationObserver with stubs for all of its methods.
 function ImageDecoderObserverStub()
 {
-  this.startRequest = function startRequest(aRequest)     {}
-  this.startDecode = function startDecode(aRequest)       {}
-  this.startContainer = function startContainer(aRequest) {}
-  this.startFrame = function startFrame(aRequest)         {}
-  this.stopFrame = function stopFrame(aRequest)           {}
-  this.stopDecode = function stopDecode(aRequest)         {}
-  this.stopRequest = function stopRequest(aRequest)       {}
-  this.dataAvailable = function dataAvailable(aRequest)   {}
+  this.sizeAvailable = function sizeAvailable(aRequest)   {}
+  this.frameComplete = function frameComplete(aRequest)   {}
+  this.decodeComplete = function decodeComplete(aRequest) {}
+  this.loadComplete = function loadComplete(aRequest)     {}
+  this.frameUpdate = function frameUpdate(aRequest)       {}
   this.discard = function discard(aRequest)               {}
   this.isAnimated = function isAnimated(aRequest)         {}
-  this.frameChanged = function frameChanged(aRequest)     {}
 }
--- a/image/test/mochitest/test_animSVGImage.html
+++ b/image/test/mochitest/test_animSVGImage.html
@@ -86,17 +86,17 @@ function cleanUpAndFinish() {
   gIsTestFinished = true;
 }
 
 function main() {
   takeReferenceSnapshot();
 
   // Create, customize & attach decoder observer
   observer = new ImageDecoderObserverStub();
-  observer.stopFrame = myOnStopFrame;
+  observer.frameComplete = myOnStopFrame;
   gMyDecoderObserver =
     Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
       .createScriptedObserver(observer);
   let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent);
   imgLoadingContent.addObserver(gMyDecoderObserver);
 
   // We want to test the cold loading behavior, so clear cache in case an
   // earlier test got our image in there already.
--- a/image/test/unit/async_load_tests.js
+++ b/image/test/unit/async_load_tests.js
@@ -48,23 +48,20 @@ function checkClone(other_listener, aReq
   var outer = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
                 .createScriptedObserver(listener);
   var clone = aRequest.clone(outer);
 }
 
 // Ensure that all the callbacks were called on aRequest.
 function checkAllCallbacks(listener, aRequest)
 {
-  do_check_neq(listener.state & START_REQUEST, 0);
-  do_check_neq(listener.state & START_DECODE, 0);
-  do_check_neq(listener.state & START_CONTAINER, 0);
-  do_check_neq(listener.state & START_FRAME, 0);
-  do_check_neq(listener.state & STOP_FRAME, 0);
-  do_check_neq(listener.state & STOP_DECODE, 0);
-  do_check_neq(listener.state & STOP_REQUEST, 0);
+  do_check_neq(listener.state & SIZE_AVAILABLE, 0);
+  do_check_neq(listener.state & FRAME_COMPLETE, 0);
+  do_check_neq(listener.state & DECODE_COMPLETE, 0);
+  do_check_neq(listener.state & LOAD_COMPLETE, 0);
   do_check_eq(listener.state, ALL_BITS);
 
   do_test_finished();
 }
 
 function secondLoadDone(oldlistener, aRequest)
 {
   do_test_pending();
@@ -110,20 +107,20 @@ function firstLoadDone(oldlistener, aReq
   do_test_finished();
 }
 
 // Return a closure that allows us to check the stream listener's status when the
 // image starts loading.
 function getChannelLoadImageStartCallback(streamlistener)
 {
   return function channelLoadStart(imglistener, aRequest) {
-    // We must not have received any status before we get this start callback.
+    // We must not have received all status before we get this start callback.
     // If we have, we've broken people's expectations by delaying events from a
     // channel we were given.
-    do_check_eq(streamlistener.requestStatus, 0);
+    do_check_eq(streamlistener.requestStatus & STOP_REQUEST, 0);
 
     checkClone(imglistener, aRequest);
   }
 }
 
 // Return a closure that allows us to check the stream listener's status when the
 // image finishes loading.
 function getChannelLoadImageStopCallback(streamlistener, next)
--- a/image/test/unit/image_load_helpers.js
+++ b/image/test/unit/image_load_helpers.js
@@ -1,83 +1,69 @@
 /*
  * Helper structures to track callbacks from image and channel loads.
  */
 
-// One bit per callback that imageListener below implements. Stored in
-// ImageListener.state.
-// START_REQUEST and STOP_REQUEST are also reused by ChannelListener, and
+// START_REQUEST and STOP_REQUEST are used by ChannelListener, and
 // stored in ChannelListener.requestStatus.
 const START_REQUEST = 0x01;
-const START_DECODE = 0x02;
-const START_CONTAINER = 0x04;
-const START_FRAME = 0x08;
-const STOP_FRAME = 0x10;
-const STOP_DECODE = 0x20;
-const STOP_REQUEST = 0x40;
-const ALL_BITS = START_REQUEST | START_DECODE | START_CONTAINER | START_FRAME |
-                 STOP_FRAME | STOP_DECODE | STOP_REQUEST;
+const STOP_REQUEST = 0x02;
+const DATA_AVAILABLE = 0x04;
+
+// One bit per callback that imageListener below implements. Stored in
+// ImageListener.state.
+const SIZE_AVAILABLE = 0x01;
+const FRAME_UPDATE = 0x02;
+const FRAME_COMPLETE = 0x04;
+const LOAD_COMPLETE = 0x08;
+const DECODE_COMPLETE = 0x10;
+const ALL_BITS = SIZE_AVAILABLE | FRAME_COMPLETE | DECODE_COMPLETE | LOAD_COMPLETE;
 
 // An implementation of imgIDecoderObserver with the ability to call specified
 // functions on onStartRequest and onStopRequest.
 function ImageListener(start_callback, stop_callback)
 {
-  this.startRequest = function onStartRequest(aRequest)
+  this.sizeAvailable = function onSizeAvailable(aRequest)
   {
     do_check_false(this.synchronous);
 
-    this.state |= START_REQUEST;
+    this.state |= SIZE_AVAILABLE;
 
     if (this.start_callback)
       this.start_callback(this, aRequest);
   }
-  this.startDecode = function onStartDecode(aRequest)
-  {
-    do_check_false(this.synchronous);
-
-    this.state |= START_DECODE;
-  }
-  this.startContainer = function onStartContainer(aRequest)
-  {
-    do_check_false(this.synchronous);
-
-    this.state |= START_CONTAINER;
-  }
-  this.startFrame = function onStartFrame(aRequest)
+  this.frameComplete = function onFrameComplete(aRequest)
   {
     do_check_false(this.synchronous);
 
-    this.state |= START_FRAME;
+    this.state |= FRAME_COMPLETE;
   }
-  this.stopFrame = function onStopFrame(aRequest)
+  this.decodeComplete = function onDecodeComplete(aRequest)
   {
     do_check_false(this.synchronous);
 
-    this.state |= STOP_FRAME;
+    this.state |= DECODE_COMPLETE;
   }
-  this.stopDecode = function onStopDecode(aRequest)
-  {
-    do_check_false(this.synchronous);
-
-    this.state |= STOP_DECODE;
-  }
-  this.stopRequest = function onStopRequest(aRequest)
+  this.loadComplete = function onLoadcomplete(aRequest)
   {
     do_check_false(this.synchronous);
 
     // We have to cancel the request when we're done with it to break any
     // reference loops!
     aRequest.cancelAndForgetObserver(0);
 
-    this.state |= STOP_REQUEST;
+    this.state |= LOAD_COMPLETE;
 
     if (this.stop_callback)
       this.stop_callback(this, aRequest);
   }
-  this.dataAvailable = function onDataAvailable(aRequest)
+  this.frameUpdate = function onFrameUpdate(aRequest)
+  {
+  }
+  this.isAnimated = function onIsAnimated()
   {
   }
 
   // Initialize the synchronous flag to true to start. This must be set to
   // false before exiting to the event loop!
   this.synchronous = true;
 
   // A function to call when onStartRequest is called.
@@ -106,16 +92,18 @@ function ChannelListener()
 
     this.requestStatus |= START_REQUEST;
   }
 
   this.onDataAvailable = function onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount)
   {
     if (this.outputListener)
       this.outputListener.onDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
+
+    this.requestStatus |= DATA_AVAILABLE;
   }
 
   this.onStopRequest = function onStopRequest(aRequest, aContext, aStatusCode)
   {
     if (this.outputListener)
       this.outputListener.onStopRequest(aRequest, aContext, aStatusCode);
 
     // If we failed (or were canceled - failure is implied if canceled),
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -1429,24 +1429,23 @@ nsBulletFrame::GetPrefWidth(nsRenderingC
   DISPLAY_PREF_WIDTH(this, metrics.width);
   GetDesiredSize(PresContext(), aRenderingContext, metrics, 1.0f);
   return metrics.width;
 }
 
 NS_IMETHODIMP
 nsBulletFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
     return OnStartContainer(aRequest, image);
   }
 
-  if (aType == imgINotificationObserver::DATA_AVAILABLE ||
-      aType == imgINotificationObserver::FRAME_CHANGED) {
+  if (aType == imgINotificationObserver::FRAME_UPDATE) {
     // The image has changed.
     // Invalidate the entire content area. Maybe it's not optimal but it's simple and
     // always correct, and I'll be a stunned mullet if it ever matters for performance
     InvalidateFrame();
   }
 
   if (aType == imgINotificationObserver::IS_ANIMATED) {
     // Register the image request with the refresh driver now that we know it's
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -135,17 +135,18 @@ NS_NewImageFrame(nsIPresShell* aPresShel
 
 NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame)
 
 
 nsImageFrame::nsImageFrame(nsStyleContext* aContext) :
   ImageFrameSuper(aContext),
   mComputedSize(0, 0),
   mIntrinsicRatio(0, 0),
-  mDisplayingIcon(false)
+  mDisplayingIcon(false),
+  mFirstFrameComplete(false)
 {
   // We assume our size is not constrained and we haven't gotten an
   // initial reflow yet, so don't touch those flags.
   mIntrinsicSize.width.SetCoordValue(0);
   mIntrinsicSize.height.SetCoordValue(0);
 }
 
 nsImageFrame::~nsImageFrame()
@@ -523,40 +524,38 @@ nsImageFrame::ShouldCreateImageFrameFor(
   }
   
   return useSizedBox;
 }
 
 nsresult
 nsImageFrame::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
     return OnStartContainer(aRequest, image);
   }
 
-  if (aType == imgINotificationObserver::DATA_AVAILABLE) {
+  if (aType == imgINotificationObserver::FRAME_UPDATE) {
     return OnDataAvailable(aRequest, aData);
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::FRAME_COMPLETE) {
+    mFirstFrameComplete = true;
+  }
+
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     uint32_t imgStatus;
     aRequest->GetImageStatus(&imgStatus);
     nsresult status =
         imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     return OnStopRequest(aRequest, status);
   }
 
-  if (aType == imgINotificationObserver::FRAME_CHANGED) {
-    nsCOMPtr<imgIContainer> image;
-    aRequest->GetImage(getter_AddRefs(image));
-    return FrameChanged(aRequest, image);
-  }
-
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage)
 {
   if (!aImage) return NS_ERROR_INVALID_ARG;
 
@@ -591,16 +590,22 @@ nsImageFrame::OnStartContainer(imgIReque
 
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnDataAvailable(imgIRequest *aRequest,
                               const nsIntRect *aRect)
 {
+  if (mFirstFrameComplete) {
+    nsCOMPtr<imgIContainer> container;
+    aRequest->GetImage(getter_AddRefs(container));
+    return FrameChanged(aRequest, container);
+  }
+
   // XXX do we need to make sure that the reflow from the
   // OnStartContainer has been processed before we start calling
   // invalidate?
 
   NS_ENSURE_ARG_POINTER(aRect);
 
   if (!(mState & IMAGE_GOTINITIALREFLOW)) {
     // Don't bother to do anything; we have a reflow coming up!
@@ -620,17 +625,17 @@ nsImageFrame::OnDataAvailable(imgIReques
   if (aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
     InvalidateFrame(nsDisplayItem::TYPE_IMAGE);
     InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK);
   } else {
     nsRect invalid = SourceRectToDest(*aRect);
     InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE);
     InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK);
   }
-  
+
   return NS_OK;
 }
 
 nsresult
 nsImageFrame::OnStopRequest(imgIRequest *aRequest,
                             nsresult aStatus)
 {
   // Check what request type we're dealing with
@@ -1971,18 +1976,18 @@ void nsImageFrame::IconLoad::GetPrefs()
 
   mPrefShowPlaceholders =
     Preferences::GetBool("browser.display.show_image_placeholders", true);
 }
 
 NS_IMETHODIMP
 nsImageFrame::IconLoad::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType != imgINotificationObserver::STOP_REQUEST &&
-      aType != imgINotificationObserver::FRAME_CHANGED) {
+  if (aType != imgINotificationObserver::LOAD_COMPLETE &&
+      aType != imgINotificationObserver::FRAME_UPDATE) {
     return NS_OK;
   }
 
   nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
   nsImageFrame *frame;
   while (iter.HasMore()) {
     frame = iter.GetNext();
     frame->InvalidateFrame();
--- a/layout/generic/nsImageFrame.h
+++ b/layout/generic/nsImageFrame.h
@@ -279,16 +279,17 @@ private:
 
   nsCOMPtr<imgINotificationObserver> mListener;
 
   nsSize mComputedSize;
   nsIFrame::IntrinsicSize mIntrinsicSize;
   nsSize mIntrinsicRatio;
 
   bool mDisplayingIcon;
+  bool mFirstFrameComplete;
 
   static nsIIOService* sIOService;
   
   /* loading / broken image icon support */
 
   // XXXbz this should be handled by the prescontext, I think; that
   // way we would have a single iconload per mozilla session instead
   // of one per document...
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -336,31 +336,31 @@ NS_IMPL_RELEASE(ImageLoader)
 NS_INTERFACE_MAP_BEGIN(ImageLoader)
   NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
   NS_INTERFACE_MAP_ENTRY(imgIOnloadBlocker)
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP
 ImageLoader::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
     return OnStartContainer(aRequest, image);
   }
 
   if (aType == imgINotificationObserver::IS_ANIMATED) {
     return OnImageIsAnimated(aRequest);
   }
 
-  if (aType == imgINotificationObserver::STOP_FRAME) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     return OnStopFrame(aRequest);
   }
 
-  if (aType == imgINotificationObserver::FRAME_CHANGED) {
+  if (aType == imgINotificationObserver::FRAME_UPDATE) {
     return FrameChanged(aRequest);
   }
 
   return NS_OK;
 }
 
 nsresult
 ImageLoader::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage)
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -558,28 +558,28 @@ nsSVGImageListener::nsSVGImageListener(n
 }
 
 NS_IMETHODIMP
 nsSVGImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
   if (!mFrame)
     return NS_ERROR_FAILURE;
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame);
   }
 
-  if (aType == imgINotificationObserver::FRAME_CHANGED) {
+  if (aType == imgINotificationObserver::FRAME_UPDATE) {
     // No new dimensions, so we don't need to call
     // nsSVGUtils::InvalidateAndScheduleBoundsUpdate.
     nsSVGEffects::InvalidateRenderingObservers(mFrame);
     nsSVGUtils::InvalidateBounds(mFrame);
   }
 
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Called once the resource's dimensions have been obtained.
     aRequest->GetImage(getter_AddRefs(mFrame->mImageContainer));
     nsSVGUtils::InvalidateAndScheduleReflowSVG(mFrame);
   }
 
   return NS_OK;
 }
 
--- a/layout/xul/base/src/nsImageBoxFrame.cpp
+++ b/layout/xul/base/src/nsImageBoxFrame.cpp
@@ -575,39 +575,39 @@ nsImageBoxFrame::GetFrameName(nsAString&
 {
   return MakeFrameName(NS_LITERAL_STRING("ImageBox"), aResult);
 }
 #endif
 
 nsresult
 nsImageBoxFrame::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     nsCOMPtr<imgIContainer> image;
     aRequest->GetImage(getter_AddRefs(image));
     return OnStartContainer(aRequest, image);
   }
 
-  if (aType == imgINotificationObserver::STOP_DECODE) {
+  if (aType == imgINotificationObserver::DECODE_COMPLETE) {
     return OnStopDecode(aRequest);
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     uint32_t imgStatus;
     aRequest->GetImageStatus(&imgStatus);
     nsresult status =
         imgStatus & imgIRequest::STATUS_ERROR ? NS_ERROR_FAILURE : NS_OK;
     return OnStopRequest(aRequest, status);
   }
 
   if (aType == imgINotificationObserver::IS_ANIMATED) {
     return OnImageIsAnimated(aRequest);
   }
 
-  if (aType == imgINotificationObserver::FRAME_CHANGED) {
+  if (aType == imgINotificationObserver::FRAME_UPDATE) {
     return FrameChanged(aRequest);
   }
 
   return NS_OK;
 }
 
 nsresult nsImageBoxFrame::OnStartContainer(imgIRequest *request,
                                            imgIContainer *image)
--- a/layout/xul/base/src/tree/src/nsTreeImageListener.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeImageListener.cpp
@@ -24,25 +24,24 @@ nsTreeImageListener::~nsTreeImageListene
 
 NS_IMETHODIMP
 nsTreeImageListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
   if (aType == imgINotificationObserver::IS_ANIMATED) {
     return mTreeFrame ? mTreeFrame->OnImageIsAnimated(aRequest) : NS_OK;
   }
 
-  if (aType == imgINotificationObserver::START_CONTAINER) {
+  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
     // Ensure the animation (if any) is started. Note: There is no
     // corresponding call to Decrement for this. This Increment will be
     // 'cleaned up' by the Request when it is destroyed, but only then.
     aRequest->IncrementAnimationConsumers();
   }
 
-  if (aType == imgINotificationObserver::DATA_AVAILABLE ||
-      aType == imgINotificationObserver::FRAME_CHANGED) {
+  if (aType == imgINotificationObserver::FRAME_UPDATE) {
     Invalidate();
   }
 
   return NS_OK;
 }
 
 void
 nsTreeImageListener::AddCell(int32_t aIndex, nsITreeColumn* aCol)
--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -87,21 +87,21 @@ nsAlertsIconListener::~nsAlertsIconListe
   if (mIconRequest)
     mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
   // Don't dlclose libnotify as it uses atexit().
 }
 
 NS_IMETHODIMP
 nsAlertsIconListener::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     return OnStopRequest(aRequest);
   }
 
-  if (aType == imgINotificationObserver::STOP_FRAME) {
+  if (aType == imgINotificationObserver::FRAME_COMPLETE) {
     return OnStopFrame(aRequest);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsAlertsIconListener::OnStopRequest(imgIRequest* aRequest)
--- a/widget/cocoa/nsMenuItemIconX.mm
+++ b/widget/cocoa/nsMenuItemIconX.mm
@@ -319,21 +319,21 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconU
 
 //
 // imgINotificationObserver
 //
 
 NS_IMETHODIMP
 nsMenuItemIconX::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
 {
-  if (aType == imgINotificationObserver::STOP_FRAME) {
+  if (aType == imgINotificationObserver::FRAME_COMPLETE) {
     return OnStopFrame(aRequest);
   }
 
-  if (aType == imgINotificationObserver::STOP_REQUEST) {
+  if (aType == imgINotificationObserver::LOAD_COMPLETE) {
     if (mIconRequest && mIconRequest == aRequest) {
       mIconRequest->Cancel(NS_BINDING_ABORTED);
       mIconRequest = nullptr;
     }
   }
 
   return NS_OK;
 }