Bug 666446, Part 1/10 - Add method to imgIContainer for notification of refresh driver events. [r=dholbert,joe][sr=mats]
authorScott Johnson <sjohnson@mozilla.com>
Wed, 09 Nov 2011 13:39:15 -0800
changeset 82096 b8cf152adb605f22ab4d44eb83918cc2058dc40b
parent 82095 698e6ec3467e8257c65bbc6bf5bf7bcb6f85bbe1
child 82097 3f8fbd2c0aa8cfa799e369dbed135cfccf441347
push id114
push userffxbld
push dateFri, 09 Mar 2012 01:01:18 +0000
treeherdermozilla-release@c081ebf13261 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert, joe, mats
bugs666446
milestone11.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 666446, Part 1/10 - Add method to imgIContainer for notification of refresh driver events. [r=dholbert,joe][sr=mats]
content/base/src/nsImageLoadingContent.cpp
content/base/src/nsStubImageDecoderObserver.cpp
image/public/imgIContainer.idl
image/public/imgIDecoderObserver.idl
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/VectorImage.cpp
image/src/VectorImage.h
image/src/imgRequest.cpp
image/src/imgRequestProxy.cpp
image/src/imgRequestProxy.h
image/src/imgStatusTracker.cpp
image/src/imgStatusTracker.h
layout/generic/nsImageFrame.cpp
toolkit/system/gnome/nsAlertsIconListener.cpp
widget/src/cocoa/nsMenuItemIconX.mm
--- a/content/base/src/nsImageLoadingContent.cpp
+++ b/content/base/src/nsImageLoadingContent.cpp
@@ -368,16 +368,22 @@ nsImageLoadingContent::OnStopRequest(img
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
   LOOP_OVER_OBSERVERS(OnStopRequest(aRequest, aLastPart));
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsImageLoadingContent::OnDiscard(imgIRequest *aRequest)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
   LOOP_OVER_OBSERVERS(OnDiscard(aRequest));
 
   return NS_OK;
 }
--- a/content/base/src/nsStubImageDecoderObserver.cpp
+++ b/content/base/src/nsStubImageDecoderObserver.cpp
@@ -102,13 +102,19 @@ nsStubImageDecoderObserver::OnStopReques
 
 NS_IMETHODIMP 
 nsStubImageDecoderObserver::OnDiscard(imgIRequest *aRequest)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsStubImageDecoderObserver::OnImageIsAnimated(imgIRequest *aRequest)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsStubImageDecoderObserver::FrameChanged(imgIContainer *aContainer,
                                          const nsIntRect *aDirtyRect)
 {
     return NS_OK;
 }
--- a/image/public/imgIContainer.idl
+++ b/image/public/imgIContainer.idl
@@ -58,40 +58,47 @@ interface imgIDecoderObserver;
 namespace mozilla {
 namespace layers {
 class LayerManager;
 class ImageContainer;
 }
 }
 
 class nsIFrame;
+
+namespace mozilla {
+class TimeStamp;
+}
+
 %}
 
 [ptr] native gfxImageSurface(gfxImageSurface);
 [ptr] native gfxASurface(gfxASurface);
 native gfxImageFormat(gfxASurface::gfxImageFormat);
 [ptr] native gfxContext(gfxContext);
 [ref] native gfxMatrix(gfxMatrix);
 [ref] native gfxRect(gfxRect);
 native gfxGraphicsFilter(gfxPattern::GraphicsFilter);
 [ref] native nsIntRect(nsIntRect);
 [ref] native nsIntSize(nsIntSize);
 [ptr] native nsIFrame(nsIFrame);
 [ptr] native ImageContainer(mozilla::layers::ImageContainer);
 [ptr] native LayerManager(mozilla::layers::LayerManager);
+[ref] native TimeStamp(mozilla::TimeStamp);
+
 
 /**
  * imgIContainer is the interface that represents an image. It allows
  * access to frames as Thebes surfaces, and permits users to extract subregions
  * as other imgIContainers. It also allows drawing of images on to Thebes
  * contexts.
  *
  * Internally, imgIContainer also manages animation of images.
  */
-[scriptable, uuid(239dfa70-2285-4d63-99cd-e9b7ff9555c7)]
+[scriptable, uuid(8c82b89f-f90c-4a31-a544-6e1f759673d4)]
 interface imgIContainer : nsISupports
 {
   /**
    * The width of the container rectangle.  In the case of any error,
    * zero is returned, and an exception will be thrown.
    */
   readonly attribute PRInt32 width;
 
@@ -274,16 +281,23 @@ interface imgIContainer : nsISupports
     *
     * Upon instantiation images have a lock count of zero. It is an error to
     * call this method without first having made a matching lockImage() call.
     * In other words, the lock count is not allowed to be negative.
     */
   void unlockImage();
 
   /**
+    * Indicates that this imgIContainer has been triggered to update
+    * its internal animation state. Likely this should only be called
+    * from within nsImageFrame or objects of similar type.
+    */
+  [notxpcom] void requestRefresh([const] in TimeStamp aTime);
+
+  /**
    * Animation mode Constants
    *   0 = normal
    *   1 = don't animate
    *   2 = loop once
    */
   const short kNormalAnimMode   = 0;
   const short kDontAnimMode     = 1;
   const short kLoopOnceAnimMode = 2;
--- a/image/public/imgIDecoderObserver.idl
+++ b/image/public/imgIDecoderObserver.idl
@@ -54,17 +54,17 @@ interface imgIContainer;
  * observing imgIRequest objects.  In the former case, aRequest is
  * always null.
  *
  * We make the distinction here between "load" and "decode" notifications. Load
  * notifications are fired as the image is loaded from the network or
  * filesystem. Decode notifications are fired as the image is decoded. If an
  * image is decoded on load and not visibly discarded, decode notifications are
  * nested logically inside load notifications as one might expect. However, with
- * decode-on-draw, the set of decode notifications can come completely _after_
+ * decode-on-draw, the set of decode notifications can imgRcome completely _after_
  * the load notifications, and can come multiple times if the image is
  * discardable. Moreover, they can be interleaved in various ways. In general,
  * any presumed ordering between load and decode notifications should not be
  * relied upon.
  *
  * Decode notifications may or may not be synchronous, depending on the
  * situation. If imgIDecoder::FLAG_SYNC_DECODE is passed to a function that
  * triggers a decode, all notifications that can be generated from the currently
@@ -72,17 +72,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(9f6bfbee-9e04-43a0-b8f6-2159973efec8)]
+[scriptable, uuid(2e5fa0c4-57f8-4d16-bda3-1daeba9caa34)]
 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)
@@ -130,16 +130,22 @@ interface imgIDecoderObserver : imgICont
   void onStopFrame(in imgIRequest aRequest, in unsigned long aFrame);
 
   /**
    * Do not implement this. It is useless and going away.
    */
   void onStopContainer(in imgIRequest aRequest, in imgIContainer aContainer);
 
   /**
+   * Notification for when an image is known to be animated. This should be
+   * fired at the earliest possible time.
+   */
+  void onImageIsAnimated(in imgIRequest aRequest);
+
+  /**
    * In theory a decode notification, but currently a load notification.
    *
    * Ideally this would be called when the decode is complete. Unfortunately,
    * this is currently the only way to signal decoding errors to consumers,
    * and the only decoding errors that consumers care about (indeed, the only
    * ones that they're prepared to hear about) are failures to instantiate the
    * decoder (<img src="foo.html"> for example). Thus, currently this is just
    * a companion to onStopDecode to signal success or failure. This will be
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -311,16 +311,24 @@ RasterImage::Init(imgIDecoderObserver *a
 
   // Mark us as initialized
   mInitialized = true;
 
   return NS_OK;
 }
 
 //******************************************************************************
+/* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */
+NS_IMETHODIMP_(void)
+RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime)
+{
+  // TODO: Implement me as part of b666446
+}
+
+//******************************************************************************
 /* [noscript] imgIContainer extractFrame(PRUint32 aWhichFrame,
  *                                       [const] in nsIntRect aRegion,
  *                                       in PRUint32 aFlags); */
 NS_IMETHODIMP
 RasterImage::ExtractFrame(PRUint32 aWhichFrame,
                           const nsIntRect &aRegion,
                           PRUint32 aFlags,
                           imgIContainer **_retval)
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -183,16 +183,17 @@ public:
   NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
   NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
   NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
   NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
   NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
   NS_SCRIPTABLE NS_IMETHOD LockImage(void);
   NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
   NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
+  NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
   // END NS_DECL_IMGICONTAINER
 
   RasterImage(imgStatusTracker* aStatusTracker = nsnull);
   virtual ~RasterImage();
 
   virtual nsresult StartAnimation();
   virtual nsresult StopAnimation();
 
--- a/image/src/VectorImage.cpp
+++ b/image/src/VectorImage.cpp
@@ -167,17 +167,16 @@ SVGDrawingCallback::operator()(gfxContex
   // Clip to aFillRect so that we don't paint outside.
   aContext->NewPath();
   aContext->Rectangle(aFillRect);
   aContext->Clip();
 
   gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext);
   aContext->Multiply(gfxMatrix(aTransform).Invert());
 
-
   nsPresContext* presContext = presShell->GetPresContext();
   NS_ABORT_IF_FALSE(presContext, "pres shell w/out pres context");
 
   nsRect svgRect(presContext->DevPixelsToAppUnits(mViewport.x),
                  presContext->DevPixelsToAppUnits(mViewport.y),
                  presContext->DevPixelsToAppUnits(mViewport.width),
                  presContext->DevPixelsToAppUnits(mViewport.height));
 
@@ -326,16 +325,24 @@ VectorImage::GetWidth(PRInt32* aWidth)
     *aWidth = 0;
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
 //******************************************************************************
+/* [notxpcom] void requestRefresh ([const] in TimeStamp aTime); */
+NS_IMETHODIMP_(void)
+VectorImage::RequestRefresh(const mozilla::TimeStamp& aTime)
+{
+  // TODO: Implement for b666446.
+}
+
+//******************************************************************************
 /* readonly attribute PRInt32 height; */
 NS_IMETHODIMP
 VectorImage::GetHeight(PRInt32* aHeight)
 {
   if (mError || !mIsFullyLoaded) {
     *aHeight = 0;
     return NS_ERROR_FAILURE;
   }
--- a/image/src/VectorImage.h
+++ b/image/src/VectorImage.h
@@ -37,16 +37,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_imagelib_VectorImage_h_
 #define mozilla_imagelib_VectorImage_h_
 
 #include "Image.h"
 #include "nsIStreamListener.h"
 #include "nsWeakReference.h"
+#include "mozilla/TimeStamp.h"
 
 class imgIDecoderObserver;
 
 namespace mozilla {
 namespace layers {
 class LayerManager;
 class ImageContainer;
 }
@@ -76,16 +77,17 @@ public:
   NS_IMETHOD CopyFrame(PRUint32 aWhichFrame, PRUint32 aFlags, gfxImageSurface **_retval NS_OUTPARAM);
   NS_IMETHOD ExtractFrame(PRUint32 aWhichFrame, const nsIntRect & aRect, PRUint32 aFlags, imgIContainer **_retval NS_OUTPARAM);
   NS_IMETHOD Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter, const gfxMatrix & aUserSpaceToImageSpace, const gfxRect & aFill, const nsIntRect & aSubimage, const nsIntSize & aViewportSize, PRUint32 aFlags);
   NS_IMETHOD_(nsIFrame *) GetRootLayoutFrame(void);
   NS_SCRIPTABLE NS_IMETHOD RequestDecode(void);
   NS_SCRIPTABLE NS_IMETHOD LockImage(void);
   NS_SCRIPTABLE NS_IMETHOD UnlockImage(void);
   NS_SCRIPTABLE NS_IMETHOD ResetAnimation(void);
+  NS_IMETHOD_(void) RequestRefresh(const mozilla::TimeStamp& aTime);
   // END NS_DECL_IMGICONTAINER
 
   VectorImage(imgStatusTracker* aStatusTracker = nsnull);
   virtual ~VectorImage();
 
   // Methods inherited from Image
   nsresult Init(imgIDecoderObserver* aObserver,
                 const char* aMimeType,
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -791,16 +791,30 @@ NS_IMETHODIMP imgRequest::OnDiscard(imgI
   nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
   while (iter.HasMore()) {
     mImage->GetStatusTracker().SendDiscard(iter.GetNext());
   }
 
   return NS_OK;
 }
 
+NS_IMETHODIMP imgRequest::OnImageIsAnimated(imgIRequest *aRequest)
+{
+  NS_ABORT_IF_FALSE(mImage,
+                    "OnImageIsAnimated callback before we've created our image");
+  mImage->GetStatusTracker().RecordImageIsAnimated();
+
+  nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mObservers);
+  while (iter.HasMore()) {
+    mImage->GetStatusTracker().SendImageIsAnimated(iter.GetNext());
+  }
+
+  return NS_OK;
+}
+
 /** nsIRequestObserver methods **/
 
 /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */
 NS_IMETHODIMP imgRequest::OnStartRequest(nsIRequest *aRequest, nsISupports *ctxt)
 {
   LOG_SCOPE(gImgLog, "imgRequest::OnStartRequest");
 
   // Figure out if we're multipart
--- a/image/src/imgRequestProxy.cpp
+++ b/image/src/imgRequestProxy.cpp
@@ -704,16 +704,26 @@ void imgRequestProxy::OnDiscard()
 
   if (mListener && !mCanceled) {
     // Hold a ref to the listener while we call it, just in case.
     nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
     mListener->OnDiscard(this);
   }
 }
 
+void imgRequestProxy::OnImageIsAnimated()
+{
+  LOG_FUNC(gImgLog, "imgRequestProxy::OnImageIsAnimated");
+  if (mListener && !mCanceled) {
+    // Hold a ref to the listener while we call it, just in case.
+    nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
+    mListener->OnImageIsAnimated(this);
+  }
+}
+
 void imgRequestProxy::OnStartRequest()
 {
 #ifdef PR_LOGGING
   nsCAutoString name;
   GetName(name);
   LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get());
 #endif
 
--- a/image/src/imgRequestProxy.h
+++ b/image/src/imgRequestProxy.h
@@ -163,24 +163,25 @@ 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(imgIContainer *aContainer);
-  void OnStartFrame    (PRUint32 aFrame);
-  void OnDataAvailable (bool aCurrentFrame, const nsIntRect * aRect);
-  void OnStopFrame     (PRUint32 aFrame);
-  void OnStopContainer (imgIContainer *aContainer);
-  void OnStopDecode    (nsresult status, const PRUnichar *statusArg); 
-  void OnDiscard       ();
+  void OnStartDecode     ();
+  void OnStartContainer  (imgIContainer *aContainer);
+  void OnStartFrame      (PRUint32 aFrame);
+  void OnDataAvailable   (bool aCurrentFrame, const nsIntRect * aRect);
+  void OnStopFrame       (PRUint32 aFrame);
+  void OnStopContainer   (imgIContainer *aContainer);
+  void OnStopDecode      (nsresult status, const PRUnichar *statusArg);
+  void OnDiscard         ();
+  void OnImageIsAnimated ();
 
   /* non-virtual imgIContainerObserver methods */
   void FrameChanged(imgIContainer *aContainer,
                     const nsIntRect *aDirtyRect);
 
   /* non-virtual sort-of-nsIRequestObserver methods */
   void OnStartRequest();
   void OnStopRequest(bool aLastPart);
--- a/image/src/imgStatusTracker.cpp
+++ b/image/src/imgStatusTracker.cpp
@@ -249,16 +249,24 @@ imgStatusTracker::SyncNotify(imgRequestP
       // wait until we fix up the observer interface
       nsIntRect r;
       mImage->GetCurrentFrameRect(r);
       proxy->OnDataAvailable(frame, &r);
 
       if (mState & stateFrameStopped)
         proxy->OnStopFrame(frame);
     }
+
+    // OnImageIsAnimated
+    bool isAnimated = false;
+
+    nsresult rv = mImage->GetAnimated(&isAnimated);
+    if (NS_SUCCEEDED(rv) && isAnimated) {
+      proxy->OnImageIsAnimated();
+    }
   }
 
   // See bug 505385 and imgRequest::OnStopDecode for more information on why we
   // call OnStopContainer based on stateDecodeStopped, and why OnStopDecode is
   // called with OnStopRequest.
   if (mState & stateDecodeStopped) {
     NS_ABORT_IF_FALSE(mImage, "stopped decoding without ever having an image?");
     proxy->OnStopContainer(mImage);
@@ -447,16 +455,34 @@ imgStatusTracker::RecordDiscard()
 
   // Clear the status bits we no longer deserve.
   PRUint32 statusBitsToClear = imgIRequest::STATUS_FRAME_COMPLETE
                                | imgIRequest::STATUS_DECODE_COMPLETE;
   mImageStatus &= ~statusBitsToClear;
 }
 
 void
+imgStatusTracker::SendImageIsAnimated(imgRequestProxy* aProxy)
+{
+  if (!aProxy->NotificationsDeferred())
+    aProxy->OnImageIsAnimated();
+}
+
+void
+imgStatusTracker::RecordImageIsAnimated()
+{
+  NS_ABORT_IF_FALSE(mImage,
+                    "RecordImageIsAnimated called before we have an Image");
+  // No bookkeeping necessary here - once decoding is complete, GetAnimated()
+  // will accurately return that this is an animated image. Until that time,
+  // the OnImageIsAnimated notification is the only indication an observer
+  // will have that an image has more than 1 frame.
+}
+
+void
 imgStatusTracker::SendDiscard(imgRequestProxy* aProxy)
 {
   if (!aProxy->NotificationsDeferred())
     aProxy->OnDiscard();
 }
 
 /* non-virtual imgIContainerObserver methods */
 void
--- a/image/src/imgStatusTracker.h
+++ b/image/src/imgStatusTracker.h
@@ -154,16 +154,18 @@ public:
   void RecordStopFrame(PRUint32 aFrame);
   void SendStopFrame(imgRequestProxy* aProxy, PRUint32 aFrame);
   void RecordStopContainer(imgIContainer* aContainer);
   void SendStopContainer(imgRequestProxy* aProxy, imgIContainer* aContainer);
   void RecordStopDecode(nsresult status, const PRUnichar* statusArg);
   void SendStopDecode(imgRequestProxy* aProxy, nsresult aStatus, const PRUnichar* statusArg);
   void RecordDiscard();
   void SendDiscard(imgRequestProxy* aProxy);
+  void RecordImageIsAnimated();
+  void SendImageIsAnimated(imgRequestProxy *aProxy);
 
   /* non-virtual imgIContainerObserver methods */
   void RecordFrameChanged(imgIContainer* aContainer,
                           const nsIntRect* aDirtyRect);
   void SendFrameChanged(imgRequestProxy* aProxy, imgIContainer* aContainer,
                         const nsIntRect* aDirtyRect);
 
   /* non-virtual sort-of-nsIRequestObserver methods */
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1949,16 +1949,22 @@ NS_IMETHODIMP
 nsImageFrame::IconLoad::OnStopDecode(imgIRequest *aRequest,
                                      nsresult status,
                                      const PRUnichar *statusArg)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsImageFrame::IconLoad::OnImageIsAnimated(imgIRequest *aRequest)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest,
                                       bool aIsLastPart)
 {
   nsTObserverArray<nsImageFrame*>::ForwardIterator iter(mIconObservers);
   nsImageFrame *frame;
   while (iter.HasMore()) {
     frame = iter.GetNext();
     frame->Invalidate(frame->GetRect());
--- a/toolkit/system/gnome/nsAlertsIconListener.cpp
+++ b/toolkit/system/gnome/nsAlertsIconListener.cpp
@@ -171,16 +171,22 @@ nsAlertsIconListener::OnStopRequest(imgI
 
 NS_IMETHODIMP
 nsAlertsIconListener::OnDiscard(imgIRequest *aRequest)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsAlertsIconListener::OnImageIsAnimated(imgIRequest *aRequest)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsAlertsIconListener::OnStopFrame(imgIRequest* aRequest,
                                   PRUint32 aFrame)
 {
   if (aRequest != mIconRequest)
     return NS_ERROR_FAILURE;
 
   if (mLoadedFrame)
     return NS_OK; // only use one frame
--- a/widget/src/cocoa/nsMenuItemIconX.mm
+++ b/widget/src/cocoa/nsMenuItemIconX.mm
@@ -554,8 +554,14 @@ nsMenuItemIconX::OnStopRequest(imgIReque
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMenuItemIconX::OnDiscard(imgIRequest* aRequest)
 {
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsMenuItemIconX::OnImageIsAnimated(imgIRequest* aRequest)
+{
+  return NS_OK;
+}