diff --git a/content/base/src/nsImageLoadingContent.cpp b/content/base/src/nsImageLoadingContent.cpp index 36b87bcf8e64..ca8c3ef4cc17 100644 --- a/content/base/src/nsImageLoadingContent.cpp +++ b/content/base/src/nsImageLoadingContent.cpp @@ -372,6 +372,12 @@ nsImageLoadingContent::OnStopRequest(imgIRequest* aRequest, bool aLastPart) return NS_OK; } +NS_IMETHODIMP +nsImageLoadingContent::OnImageIsAnimated(imgIRequest *aRequest) +{ + return NS_OK; +} + NS_IMETHODIMP nsImageLoadingContent::OnDiscard(imgIRequest *aRequest) { diff --git a/content/base/src/nsStubImageDecoderObserver.cpp b/content/base/src/nsStubImageDecoderObserver.cpp index 398cdeb49de8..74f8aeea16e3 100644 --- a/content/base/src/nsStubImageDecoderObserver.cpp +++ b/content/base/src/nsStubImageDecoderObserver.cpp @@ -106,6 +106,12 @@ 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) diff --git a/image/public/imgIContainer.idl b/image/public/imgIContainer.idl index b19d3e945152..43d41b3dd23a 100644 --- a/image/public/imgIContainer.idl +++ b/image/public/imgIContainer.idl @@ -63,6 +63,11 @@ class ImageContainer; } class nsIFrame; + +namespace mozilla { +class TimeStamp; +} + %} [ptr] native gfxImageSurface(gfxImageSurface); @@ -77,6 +82,8 @@ native gfxGraphicsFilter(gfxPattern::GraphicsFilter); [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 @@ -86,7 +93,7 @@ native gfxGraphicsFilter(gfxPattern::GraphicsFilter); * * Internally, imgIContainer also manages animation of images. */ -[scriptable, uuid(239dfa70-2285-4d63-99cd-e9b7ff9555c7)] +[scriptable, uuid(8c82b89f-f90c-4a31-a544-6e1f759673d4)] interface imgIContainer : nsISupports { /** @@ -278,6 +285,13 @@ interface imgIContainer : nsISupports */ 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 diff --git a/image/public/imgIDecoderObserver.idl b/image/public/imgIDecoderObserver.idl index ae555249375d..bed7cf6fc41f 100644 --- a/image/public/imgIDecoderObserver.idl +++ b/image/public/imgIDecoderObserver.idl @@ -59,7 +59,7 @@ interface imgIContainer; * 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 @@ -77,7 +77,7 @@ interface imgIContainer; * @version 0.1 * @see imagelib2 */ -[scriptable, uuid(9f6bfbee-9e04-43a0-b8f6-2159973efec8)] +[scriptable, uuid(2e5fa0c4-57f8-4d16-bda3-1daeba9caa34)] interface imgIDecoderObserver : imgIContainerObserver { /** @@ -134,6 +134,12 @@ interface imgIDecoderObserver : imgIContainerObserver */ 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. * diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 4037950a0088..e0da77c4e940 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -315,6 +315,14 @@ RasterImage::Init(imgIDecoderObserver *aObserver, 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, diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index e22a5b3caa2b..ea9afe36c4ce 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -188,6 +188,7 @@ public: 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); diff --git a/image/src/VectorImage.cpp b/image/src/VectorImage.cpp index c6ca627c91eb..181300cb1411 100644 --- a/image/src/VectorImage.cpp +++ b/image/src/VectorImage.cpp @@ -172,7 +172,6 @@ SVGDrawingCallback::operator()(gfxContext* aContext, gfxContextMatrixAutoSaveRestore contextMatrixRestorer(aContext); aContext->Multiply(gfxMatrix(aTransform).Invert()); - nsPresContext* presContext = presShell->GetPresContext(); NS_ABORT_IF_FALSE(presContext, "pres shell w/out pres context"); @@ -330,6 +329,14 @@ VectorImage::GetWidth(PRInt32* aWidth) 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 diff --git a/image/src/VectorImage.h b/image/src/VectorImage.h index 9fe294caa503..516156ea0016 100644 --- a/image/src/VectorImage.h +++ b/image/src/VectorImage.h @@ -42,6 +42,7 @@ #include "Image.h" #include "nsIStreamListener.h" #include "nsWeakReference.h" +#include "mozilla/TimeStamp.h" class imgIDecoderObserver; @@ -81,6 +82,7 @@ public: 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); diff --git a/image/src/imgRequest.cpp b/image/src/imgRequest.cpp index 7b5181e64c29..ba0f379162b0 100644 --- a/image/src/imgRequest.cpp +++ b/image/src/imgRequest.cpp @@ -796,6 +796,20 @@ NS_IMETHODIMP imgRequest::OnDiscard(imgIRequest *aRequest) 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::ForwardIterator iter(mObservers); + while (iter.HasMore()) { + mImage->GetStatusTracker().SendImageIsAnimated(iter.GetNext()); + } + + return NS_OK; +} + /** nsIRequestObserver methods **/ /* void onStartRequest (in nsIRequest request, in nsISupports ctxt); */ diff --git a/image/src/imgRequestProxy.cpp b/image/src/imgRequestProxy.cpp index 00d2e11c308d..dc23c1f70177 100644 --- a/image/src/imgRequestProxy.cpp +++ b/image/src/imgRequestProxy.cpp @@ -709,6 +709,16 @@ void imgRequestProxy::OnDiscard() } } +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 kungFuDeathGrip(mListener); + mListener->OnImageIsAnimated(this); + } +} + void imgRequestProxy::OnStartRequest() { #ifdef PR_LOGGING diff --git a/image/src/imgRequestProxy.h b/image/src/imgRequestProxy.h index 2e3efdfd5137..b90dea4e621f 100644 --- a/image/src/imgRequestProxy.h +++ b/image/src/imgRequestProxy.h @@ -168,14 +168,15 @@ protected: // 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, diff --git a/image/src/imgStatusTracker.cpp b/image/src/imgStatusTracker.cpp index 652f3be9c7c6..b9149e58eb4e 100644 --- a/image/src/imgStatusTracker.cpp +++ b/image/src/imgStatusTracker.cpp @@ -254,6 +254,14 @@ imgStatusTracker::SyncNotify(imgRequestProxy* proxy) 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 @@ -451,6 +459,24 @@ imgStatusTracker::RecordDiscard() 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) { diff --git a/image/src/imgStatusTracker.h b/image/src/imgStatusTracker.h index f429329e3f29..7224eaba3034 100644 --- a/image/src/imgStatusTracker.h +++ b/image/src/imgStatusTracker.h @@ -159,6 +159,8 @@ public: 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, diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 5046a1e6ee0e..78f39f1ab558 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -1953,6 +1953,12 @@ nsImageFrame::IconLoad::OnStopDecode(imgIRequest *aRequest, return NS_OK; } +NS_IMETHODIMP +nsImageFrame::IconLoad::OnImageIsAnimated(imgIRequest *aRequest) +{ + return NS_OK; +} + NS_IMETHODIMP nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest, bool aIsLastPart) diff --git a/toolkit/system/gnome/nsAlertsIconListener.cpp b/toolkit/system/gnome/nsAlertsIconListener.cpp index 905147028e7f..8cf8c575d16c 100644 --- a/toolkit/system/gnome/nsAlertsIconListener.cpp +++ b/toolkit/system/gnome/nsAlertsIconListener.cpp @@ -175,6 +175,12 @@ nsAlertsIconListener::OnDiscard(imgIRequest *aRequest) return NS_OK; } +NS_IMETHODIMP +nsAlertsIconListener::OnImageIsAnimated(imgIRequest *aRequest) +{ + return NS_OK; +} + NS_IMETHODIMP nsAlertsIconListener::OnStopFrame(imgIRequest* aRequest, PRUint32 aFrame) diff --git a/widget/src/cocoa/nsMenuItemIconX.mm b/widget/src/cocoa/nsMenuItemIconX.mm index c12a37fb38ec..b84bd5c0895a 100644 --- a/widget/src/cocoa/nsMenuItemIconX.mm +++ b/widget/src/cocoa/nsMenuItemIconX.mm @@ -559,3 +559,9 @@ nsMenuItemIconX::OnDiscard(imgIRequest* aRequest) { return NS_OK; } + +NS_IMETHODIMP +nsMenuItemIconX::OnImageIsAnimated(imgIRequest* aRequest) +{ + return NS_OK; +}