michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef imgRequestProxy_h__ michael@0: #define imgRequestProxy_h__ michael@0: michael@0: #include "mozilla/WeakPtr.h" michael@0: #include "imgIRequest.h" michael@0: #include "nsISecurityInfoProvider.h" michael@0: michael@0: #include "nsILoadGroup.h" michael@0: #include "nsISupportsPriority.h" michael@0: #include "nsITimedChannel.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: michael@0: #include "imgRequest.h" michael@0: michael@0: #define NS_IMGREQUESTPROXY_CID \ michael@0: { /* 20557898-1dd2-11b2-8f65-9c462ee2bc95 */ \ michael@0: 0x20557898, \ michael@0: 0x1dd2, \ michael@0: 0x11b2, \ michael@0: {0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95} \ michael@0: } michael@0: michael@0: class imgINotificationObserver; michael@0: class imgRequestNotifyRunnable; michael@0: class imgStatusNotifyRunnable; michael@0: class nsIntRect; michael@0: class ProxyBehaviour; michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: class Image; michael@0: class ImageURL; michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: class imgRequestProxy : public imgIRequest, michael@0: public nsISupportsPriority, michael@0: public nsISecurityInfoProvider, michael@0: public nsITimedChannel, michael@0: public mozilla::SupportsWeakPtr michael@0: { michael@0: public: michael@0: MOZ_DECLARE_REFCOUNTED_TYPENAME(imgRequestProxy) michael@0: typedef mozilla::image::ImageURL ImageURL; michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_IMGIREQUEST michael@0: NS_DECL_NSIREQUEST michael@0: NS_DECL_NSISUPPORTSPRIORITY michael@0: NS_DECL_NSISECURITYINFOPROVIDER michael@0: // nsITimedChannel declared below michael@0: michael@0: imgRequestProxy(); michael@0: virtual ~imgRequestProxy(); michael@0: michael@0: // Callers to Init or ChangeOwner are required to call NotifyListener after michael@0: // (although not immediately after) doing so. michael@0: nsresult Init(imgRequest* aOwner, michael@0: nsILoadGroup *aLoadGroup, michael@0: ImageURL* aURI, michael@0: imgINotificationObserver *aObserver); michael@0: michael@0: nsresult ChangeOwner(imgRequest *aNewOwner); // this will change mOwner. Do not call this if the previous michael@0: // owner has already sent notifications out! michael@0: michael@0: void AddToLoadGroup(); michael@0: void RemoveFromLoadGroup(bool releaseLoadGroup); michael@0: michael@0: inline bool HasObserver() const { michael@0: return mListener != nullptr; michael@0: } michael@0: michael@0: // Asynchronously notify this proxy's listener of the current state of the michael@0: // image, and, if we have an imgRequest mOwner, any status changes that michael@0: // happen between the time this function is called and the time the michael@0: // notification is scheduled. michael@0: void NotifyListener(); michael@0: michael@0: // Synchronously notify this proxy's listener of the current state of the michael@0: // image. Only use this function if you are currently servicing an michael@0: // asynchronously-called function. michael@0: void SyncNotifyListener(); michael@0: michael@0: // Whether we want notifications from imgStatusTracker to be deferred until michael@0: // an event it has scheduled has been fired. michael@0: bool NotificationsDeferred() const michael@0: { michael@0: return mDeferNotifications; michael@0: } michael@0: void SetNotificationsDeferred(bool aDeferNotifications) michael@0: { michael@0: mDeferNotifications = aDeferNotifications; michael@0: } michael@0: michael@0: // XXXbholley - This eventually gets folded into the new notification API. michael@0: void SetHasImage(); michael@0: michael@0: // Removes all animation consumers that were created with michael@0: // IncrementAnimationConsumers. This is necessary since we need michael@0: // to do it before the proxy itself is destroyed. See michael@0: // imgRequest::RemoveProxy michael@0: void ClearAnimationConsumers(); michael@0: michael@0: virtual nsresult Clone(imgINotificationObserver* aObserver, imgRequestProxy** aClone); michael@0: nsresult GetStaticRequest(imgRequestProxy** aReturn); michael@0: michael@0: nsresult GetURI(ImageURL **aURI); michael@0: michael@0: protected: michael@0: friend class imgStatusTracker; michael@0: friend class imgStatusNotifyRunnable; michael@0: friend class imgRequestNotifyRunnable; michael@0: michael@0: class imgCancelRunnable; michael@0: friend class imgCancelRunnable; michael@0: michael@0: class imgCancelRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: imgCancelRunnable(imgRequestProxy* owner, nsresult status) michael@0: : mOwner(owner), mStatus(status) michael@0: {} michael@0: michael@0: NS_IMETHOD Run() { michael@0: mOwner->DoCancel(mStatus); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: nsRefPtr mOwner; michael@0: nsresult mStatus; michael@0: }; michael@0: michael@0: // The following notification functions are protected to ensure that (friend michael@0: // class) imgStatusTracker is the only class allowed to send us michael@0: // notifications. michael@0: michael@0: /* non-virtual imgDecoderObserver methods */ michael@0: void OnStartDecode (); michael@0: void OnStartContainer (); michael@0: void OnFrameUpdate (const nsIntRect * aRect); michael@0: void OnStopFrame (); michael@0: void OnStopDecode (); michael@0: void OnDiscard (); michael@0: void OnUnlockedDraw (); michael@0: void OnImageIsAnimated (); michael@0: michael@0: /* non-virtual sort-of-nsIRequestObserver methods */ michael@0: void OnStartRequest(); michael@0: void OnStopRequest(bool aLastPart); michael@0: michael@0: /* non-virtual imgIOnloadBlocker methods */ michael@0: void BlockOnload(); michael@0: void UnblockOnload(); michael@0: michael@0: /* Finish up canceling ourselves */ michael@0: void DoCancel(nsresult status); michael@0: michael@0: /* Do the proper refcount management to null out mListener */ michael@0: void NullOutListener(); michael@0: michael@0: void DoRemoveFromLoadGroup() { michael@0: RemoveFromLoadGroup(true); michael@0: } michael@0: michael@0: // Return the imgStatusTracker associated with mOwner and/or mImage. It may michael@0: // live either on mOwner or mImage, depending on whether michael@0: // (a) we have an mOwner at all michael@0: // (b) whether mOwner has instantiated its image yet michael@0: already_AddRefed GetStatusTracker() const; michael@0: michael@0: nsITimedChannel* TimedChannel() michael@0: { michael@0: if (!GetOwner()) michael@0: return nullptr; michael@0: return GetOwner()->mTimedChannel; michael@0: } michael@0: michael@0: already_AddRefed GetImage() const; michael@0: bool HasImage() const; michael@0: imgRequest* GetOwner() const; michael@0: michael@0: nsresult PerformClone(imgINotificationObserver* aObserver, michael@0: imgRequestProxy* (aAllocFn)(imgRequestProxy*), michael@0: imgRequestProxy** aClone); michael@0: michael@0: public: michael@0: NS_FORWARD_SAFE_NSITIMEDCHANNEL(TimedChannel()) michael@0: michael@0: protected: michael@0: nsAutoPtr mBehaviour; michael@0: michael@0: private: michael@0: friend class imgCacheValidator; michael@0: friend imgRequestProxy* NewStaticProxy(imgRequestProxy* aThis); michael@0: michael@0: // The URI of our request. michael@0: nsRefPtr mURI; michael@0: michael@0: // mListener is only promised to be a weak ref (see imgILoader.idl), michael@0: // but we actually keep a strong ref to it until we've seen our michael@0: // first OnStopRequest. michael@0: imgINotificationObserver* mListener; michael@0: nsCOMPtr mLoadGroup; michael@0: michael@0: nsLoadFlags mLoadFlags; michael@0: uint32_t mLockCount; michael@0: uint32_t mAnimationConsumers; michael@0: bool mCanceled; michael@0: bool mIsInLoadGroup; michael@0: bool mListenerIsStrongRef; michael@0: bool mDecodeRequested; michael@0: michael@0: // Whether we want to defer our notifications by the non-virtual Observer michael@0: // interfaces as image loads proceed. michael@0: bool mDeferNotifications; michael@0: michael@0: // We only want to send OnStartContainer once for each proxy, but we might michael@0: // get multiple OnStartContainer calls. michael@0: bool mSentStartContainer; michael@0: }; michael@0: michael@0: // Used for static image proxies for which no requests are available, so michael@0: // certain behaviours must be overridden to compensate. michael@0: class imgRequestProxyStatic : public imgRequestProxy michael@0: { michael@0: michael@0: public: michael@0: imgRequestProxyStatic(mozilla::image::Image* aImage, michael@0: nsIPrincipal* aPrincipal); michael@0: michael@0: NS_IMETHOD GetImagePrincipal(nsIPrincipal** aPrincipal) MOZ_OVERRIDE; michael@0: michael@0: using imgRequestProxy::Clone; michael@0: michael@0: virtual nsresult Clone(imgINotificationObserver* aObserver, michael@0: imgRequestProxy** aClone) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: friend imgRequestProxy* NewStaticProxy(imgRequestProxy*); michael@0: michael@0: // Our principal. We have to cache it, rather than accessing the underlying michael@0: // request on-demand, because static proxies don't have an underlying request. michael@0: nsCOMPtr mPrincipal; michael@0: }; michael@0: michael@0: #endif // imgRequestProxy_h__