diff options
Diffstat (limited to 'image/imgRequestProxy.h')
-rw-r--r-- | image/imgRequestProxy.h | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/image/imgRequestProxy.h b/image/imgRequestProxy.h new file mode 100644 index 0000000000..950c78341c --- /dev/null +++ b/image/imgRequestProxy.h @@ -0,0 +1,263 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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/. */ + +#ifndef mozilla_image_imgRequestProxy_h +#define mozilla_image_imgRequestProxy_h + +#include "imgIRequest.h" + +#include "nsIPrincipal.h" +#include "nsISupportsPriority.h" +#include "nsITimedChannel.h" +#include "nsCOMPtr.h" +#include "nsThreadUtils.h" +#include "mozilla/PreloaderBase.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/gfx/Rect.h" + +#include "IProgressObserver.h" + +#define NS_IMGREQUESTPROXY_CID \ + { /* 20557898-1dd2-11b2-8f65-9c462ee2bc95 */ \ + 0x20557898, 0x1dd2, 0x11b2, { \ + 0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95 \ + } \ + } + +class imgCacheValidator; +class imgINotificationObserver; +class imgRequest; +class imgStatusNotifyRunnable; +class ProxyBehaviour; + +namespace mozilla { +namespace image { +class Image; +class ProgressTracker; +} // namespace image +} // namespace mozilla + +class imgRequestProxy : public mozilla::PreloaderBase, + public imgIRequest, + public mozilla::image::IProgressObserver, + public nsISupportsPriority, + public nsITimedChannel { + protected: + virtual ~imgRequestProxy(); + + public: + typedef mozilla::dom::Document Document; + typedef mozilla::image::Image Image; + typedef mozilla::image::ProgressTracker ProgressTracker; + + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMGREQUESTPROXY_CID) + MOZ_DECLARE_REFCOUNTED_TYPENAME(imgRequestProxy) + NS_DECL_ISUPPORTS + NS_DECL_IMGIREQUEST + NS_DECL_NSIREQUEST + NS_DECL_NSISUPPORTSPRIORITY + // nsITimedChannel declared below + + imgRequestProxy(); + + // Callers to Init or ChangeOwner are required to call NotifyListener after + // (although not immediately after) doing so. + nsresult Init(imgRequest* aOwner, nsILoadGroup* aLoadGroup, + Document* aLoadingDocument, nsIURI* aURI, + imgINotificationObserver* aObserver); + + nsresult ChangeOwner(imgRequest* aNewOwner); // this will change mOwner. + // Do not call this if the + // previous owner has already + // sent notifications out! + + // Add the request to the load group, if any. This should only be called once + // during initialization. + void AddToLoadGroup(); + + inline bool HasObserver() const { return mListener != nullptr; } + + // Asynchronously notify this proxy's listener of the current state of the + // image, and, if we have an imgRequest mOwner, any status changes that + // happen between the time this function is called and the time the + // notification is scheduled. + void NotifyListener(); + + // Synchronously notify this proxy's listener of the current state of the + // image. Only use this function if you are currently servicing an + // asynchronously-called function. + void SyncNotifyListener(); + + // imgINotificationObserver methods: + virtual void Notify(int32_t aType, + const mozilla::gfx::IntRect* aRect = nullptr) override; + virtual void OnLoadComplete(bool aLastPart) override; + + // Other, internal-only methods: + virtual void SetHasImage() override; + + // Whether we want notifications from ProgressTracker to be deferred until + // an event it has scheduled has been fired and/or validation is complete. + virtual bool NotificationsDeferred() const override { + return IsValidating() || mPendingNotify; + } + virtual void MarkPendingNotify() override { mPendingNotify = true; } + virtual void ClearPendingNotify() override { mPendingNotify = false; } + bool IsValidating() const { return mValidating; } + void MarkValidating(); + void ClearValidating(); + + // Flags this image load as not cancelable temporarily. This is needed so that + // stylesheets can be shared across documents properly, see bug 1800979. + void SetCancelable(bool); + + already_AddRefed<nsIEventTarget> GetEventTarget() const override; + + // Removes all animation consumers that were created with + // IncrementAnimationConsumers. This is necessary since we need + // to do it before the proxy itself is destroyed. See + // imgRequest::RemoveProxy + void ClearAnimationConsumers(); + + nsresult SyncClone(imgINotificationObserver* aObserver, + Document* aLoadingDocument, imgRequestProxy** aClone); + nsresult Clone(imgINotificationObserver* aObserver, + Document* aLoadingDocument, imgRequestProxy** aClone); + already_AddRefed<imgRequestProxy> GetStaticRequest( + Document* aLoadingDocument); + + imgRequest* GetOwner() const; + + // PreloaderBase + // We are using the default image loader prioritization for preloads. + virtual void PrioritizeAsPreload() override {} + + protected: + friend class mozilla::image::ProgressTracker; + friend class imgStatusNotifyRunnable; + + class imgCancelRunnable; + friend class imgCancelRunnable; + + class imgCancelRunnable : public mozilla::Runnable { + public: + imgCancelRunnable(imgRequestProxy* owner, nsresult status) + : Runnable("imgCancelRunnable"), mOwner(owner), mStatus(status) {} + + NS_IMETHOD Run() override { + mOwner->DoCancel(mStatus); + return NS_OK; + } + + private: + RefPtr<imgRequestProxy> mOwner; + nsresult mStatus; + }; + + /* Remove from and forget the load group. */ + void RemoveFromLoadGroup(); + + /* Remove from the load group and re-add as a background request. */ + void MoveToBackgroundInLoadGroup(); + + /* Finish up canceling ourselves */ + void DoCancel(nsresult status); + + /* Do the proper refcount management to null out mListener */ + void NullOutListener(); + + // Return the ProgressTracker associated with mOwner and/or mImage. It may + // live either on mOwner or mImage, depending on whether + // (a) we have an mOwner at all + // (b) whether mOwner has instantiated its image yet + already_AddRefed<ProgressTracker> GetProgressTracker() const; + + nsITimedChannel* TimedChannel(); + + already_AddRefed<Image> GetImage() const; + bool HasImage() const; + imgCacheValidator* GetValidator() const; + + nsresult PerformClone(imgINotificationObserver* aObserver, + Document* aLoadingDocument, bool aSyncNotify, + imgRequestProxy** aClone); + + virtual imgRequestProxy* NewClonedProxy(); + + public: + NS_FORWARD_SAFE_NSITIMEDCHANNEL(TimedChannel()) + + protected: + mozilla::UniquePtr<ProxyBehaviour> mBehaviour; + + private: + friend class imgCacheValidator; + + void AddToOwner(Document* aLoadingDocument); + void RemoveFromOwner(nsresult aStatus); + + nsresult DispatchWithTargetIfAvailable(already_AddRefed<nsIRunnable> aEvent); + + // The URI of our request. + nsCOMPtr<nsIURI> mURI; + + // mListener is only promised to be a weak ref (see imgILoader.idl), + // but we actually keep a strong ref to it until we've seen our + // first OnStopRequest. + imgINotificationObserver* MOZ_UNSAFE_REF( + "Observers must call Cancel() or " + "CancelAndForgetObserver() before " + "they are destroyed") mListener; + + nsCOMPtr<nsILoadGroup> mLoadGroup; + nsCOMPtr<nsIEventTarget> mEventTarget; + + nsLoadFlags mLoadFlags; + uint32_t mLockCount; + uint32_t mAnimationConsumers; + bool mCancelable : 1; + bool mCanceled : 1; + bool mIsInLoadGroup : 1; + bool mForceDispatchLoadGroup : 1; + bool mListenerIsStrongRef : 1; + bool mDecodeRequested : 1; + + // Whether we want to defer our notifications by the non-virtual Observer + // interfaces as image loads proceed. + bool mPendingNotify : 1; + bool mValidating : 1; + bool mHadListener : 1; + bool mHadDispatch : 1; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(imgRequestProxy, NS_IMGREQUESTPROXY_CID) + +// Used for static image proxies for which no requests are available, so +// certain behaviours must be overridden to compensate. +class imgRequestProxyStatic : public imgRequestProxy { + public: + imgRequestProxyStatic(Image* aImage, nsIPrincipal* aImagePrincipal, + nsIPrincipal* aTriggeringPrincipal, + bool hadCrossOriginRedirects); + + NS_IMETHOD GetImagePrincipal(nsIPrincipal** aPrincipal) override; + NS_IMETHOD GetTriggeringPrincipal(nsIPrincipal** aPrincipal) override; + + NS_IMETHOD GetHadCrossOriginRedirects( + bool* aHadCrossOriginRedirects) override; + + protected: + imgRequestProxy* NewClonedProxy() override; + + // Our principal. We have to cache it, rather than accessing the underlying + // request on-demand, because static proxies don't have an underlying request. + const nsCOMPtr<nsIPrincipal> mImagePrincipal; + const nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; + const bool mHadCrossOriginRedirects; +}; + +#endif // mozilla_image_imgRequestProxy_h |