imgRequestProxy.h (9294B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_image_imgRequestProxy_h 8 #define mozilla_image_imgRequestProxy_h 9 10 #include "imgIRequest.h" 11 12 #include "nsIPrincipal.h" 13 #include "nsISupportsPriority.h" 14 #include "nsITimedChannel.h" 15 #include "nsCOMPtr.h" 16 #include "nsThreadUtils.h" 17 #include "mozilla/PreloaderBase.h" 18 #include "mozilla/TimeStamp.h" 19 #include "mozilla/UniquePtr.h" 20 #include "mozilla/gfx/Rect.h" 21 22 #include "IProgressObserver.h" 23 24 #define NS_IMGREQUESTPROXY_CID \ 25 {/* 20557898-1dd2-11b2-8f65-9c462ee2bc95 */ \ 26 0x20557898, \ 27 0x1dd2, \ 28 0x11b2, \ 29 {0x8f, 0x65, 0x9c, 0x46, 0x2e, 0xe2, 0xbc, 0x95}} 30 31 class imgCacheValidator; 32 class imgINotificationObserver; 33 class imgRequest; 34 class imgStatusNotifyRunnable; 35 class ProxyBehaviour; 36 37 namespace mozilla { 38 namespace image { 39 class Image; 40 class ProgressTracker; 41 } // namespace image 42 } // namespace mozilla 43 44 class imgRequestProxy : public mozilla::PreloaderBase, 45 public imgIRequest, 46 public mozilla::image::IProgressObserver, 47 public nsISupportsPriority, 48 public nsITimedChannel { 49 protected: 50 virtual ~imgRequestProxy(); 51 52 public: 53 typedef mozilla::dom::Document Document; 54 typedef mozilla::image::Image Image; 55 typedef mozilla::image::ProgressTracker ProgressTracker; 56 57 NS_INLINE_DECL_STATIC_IID(NS_IMGREQUESTPROXY_CID) 58 MOZ_DECLARE_REFCOUNTED_TYPENAME(imgRequestProxy) 59 NS_DECL_ISUPPORTS 60 NS_DECL_IMGIREQUEST 61 NS_DECL_NSIREQUEST 62 NS_DECL_NSISUPPORTSPRIORITY 63 // nsITimedChannel declared below 64 65 imgRequestProxy(); 66 67 // Callers to Init or ChangeOwner are required to call NotifyListener after 68 // (although not immediately after) doing so. 69 nsresult Init(imgRequest* aOwner, nsILoadGroup* aLoadGroup, nsIURI* aURI, 70 imgINotificationObserver* aObserver); 71 72 nsresult ChangeOwner(imgRequest* aNewOwner); // this will change mOwner. 73 // Do not call this if the 74 // previous owner has already 75 // sent notifications out! 76 77 // Add the request to the load group, if any. This should only be called once 78 // during initialization. 79 void AddToLoadGroup(); 80 81 inline bool HasObserver() const { return mListener != nullptr; } 82 83 // Asynchronously notify this proxy's listener of the current state of the 84 // image, and, if we have an imgRequest mOwner, any status changes that 85 // happen between the time this function is called and the time the 86 // notification is scheduled. 87 void NotifyListener(); 88 89 // Synchronously notify this proxy's listener of the current state of the 90 // image. Only use this function if you are currently servicing an 91 // asynchronously-called function. 92 void SyncNotifyListener(); 93 94 // imgINotificationObserver methods: 95 virtual void Notify(int32_t aType, 96 const mozilla::gfx::IntRect* aRect = nullptr) override; 97 virtual void OnLoadComplete(bool aLastPart) override; 98 99 // Other, internal-only methods: 100 virtual void SetHasImage() override; 101 102 // Whether we want notifications from ProgressTracker to be deferred until 103 // an event it has scheduled has been fired and/or validation is complete. 104 virtual bool NotificationsDeferred() const override { 105 return IsValidating() || mPendingNotify; 106 } 107 virtual void MarkPendingNotify() override { mPendingNotify = true; } 108 virtual void ClearPendingNotify() override { mPendingNotify = false; } 109 bool IsValidating() const { return mValidating; } 110 void MarkValidating(); 111 void ClearValidating(); 112 113 // Flags this image load as not cancelable temporarily. This is needed so that 114 // stylesheets can be shared across documents properly, see bug 1800979. 115 void SetCancelable(bool); 116 117 // Removes all animation consumers that were created with 118 // IncrementAnimationConsumers. This is necessary since we need 119 // to do it before the proxy itself is destroyed. See 120 // imgRequest::RemoveProxy 121 void ClearAnimationConsumers(); 122 123 nsresult SyncClone(imgINotificationObserver* aObserver, 124 Document* aLoadingDocument, imgRequestProxy** aClone); 125 nsresult Clone(imgINotificationObserver* aObserver, 126 Document* aLoadingDocument, imgRequestProxy** aClone); 127 already_AddRefed<imgRequestProxy> GetStaticRequest( 128 Document* aLoadingDocument); 129 130 imgRequest* GetOwner() const; 131 132 struct LCPTimings { 133 bool AreSet() const { return mLoadTime.isSome() && mRenderTime.isSome(); } 134 135 void Reset() { 136 mLoadTime = mozilla::Nothing(); 137 mRenderTime = mozilla::Nothing(); 138 } 139 140 mozilla::Maybe<mozilla::TimeStamp> mLoadTime; 141 mozilla::Maybe<mozilla::TimeStamp> mRenderTime; 142 143 void Set(const mozilla::TimeStamp& aLoadTime, 144 const mozilla::TimeStamp& aRenderTime) { 145 mLoadTime = Some(aLoadTime); 146 mRenderTime = Some(aRenderTime); 147 } 148 }; 149 150 LCPTimings& GetLCPTimings() { return mLCPTimings; } 151 152 const LCPTimings& GetLCPTimings() const { return mLCPTimings; } 153 154 protected: 155 friend class mozilla::image::ProgressTracker; 156 friend class imgStatusNotifyRunnable; 157 158 class imgCancelRunnable; 159 friend class imgCancelRunnable; 160 161 class imgCancelRunnable : public mozilla::Runnable { 162 public: 163 imgCancelRunnable(imgRequestProxy* owner, nsresult status) 164 : Runnable("imgCancelRunnable"), mOwner(owner), mStatus(status) {} 165 166 NS_IMETHOD Run() override { 167 mOwner->DoCancel(mStatus); 168 return NS_OK; 169 } 170 171 private: 172 RefPtr<imgRequestProxy> mOwner; 173 nsresult mStatus; 174 }; 175 176 /* Remove from and forget the load group. */ 177 void RemoveFromLoadGroup(); 178 179 /* Remove from the load group and re-add as a background request. */ 180 void MoveToBackgroundInLoadGroup(); 181 182 /* Finish up canceling ourselves */ 183 void DoCancel(nsresult status); 184 185 /* Do the proper refcount management to null out mListener */ 186 void NullOutListener(); 187 188 // Return the ProgressTracker associated with mOwner and/or mImage. It may 189 // live either on mOwner or mImage, depending on whether 190 // (a) we have an mOwner at all 191 // (b) whether mOwner has instantiated its image yet 192 already_AddRefed<ProgressTracker> GetProgressTracker() const; 193 194 nsITimedChannel* TimedChannel(); 195 196 already_AddRefed<Image> GetImage() const; 197 bool HasImage() const; 198 imgCacheValidator* GetValidator() const; 199 200 nsresult PerformClone(imgINotificationObserver* aObserver, 201 Document* aLoadingDocument, bool aSyncNotify, 202 imgRequestProxy** aClone); 203 204 virtual imgRequestProxy* NewClonedProxy(); 205 206 public: 207 NS_FORWARD_SAFE_NSITIMEDCHANNEL(TimedChannel()) 208 209 protected: 210 mozilla::UniquePtr<ProxyBehaviour> mBehaviour; 211 212 private: 213 friend class imgCacheValidator; 214 215 void AddToOwner(); 216 void RemoveFromOwner(nsresult aStatus); 217 218 nsresult DispatchWithTargetIfAvailable(already_AddRefed<nsIRunnable> aEvent); 219 220 // The URI of our request. 221 nsCOMPtr<nsIURI> mURI; 222 223 LCPTimings mLCPTimings; 224 // mListener is only promised to be a weak ref (see imgILoader.idl), 225 // but we actually keep a strong ref to it until we've seen our 226 // first OnStopRequest. 227 imgINotificationObserver* MOZ_UNSAFE_REF( 228 "Observers must call Cancel() or " 229 "CancelAndForgetObserver() before " 230 "they are destroyed") mListener; 231 232 nsCOMPtr<nsILoadGroup> mLoadGroup; 233 234 nsLoadFlags mLoadFlags; 235 uint32_t mLockCount; 236 uint32_t mAnimationConsumers; 237 bool mCancelable : 1; 238 bool mCanceled : 1; 239 bool mIsInLoadGroup : 1; 240 bool mForceDispatchLoadGroup : 1; 241 bool mListenerIsStrongRef : 1; 242 bool mDecodeRequested : 1; 243 244 // Whether we want to defer our notifications by the non-virtual Observer 245 // interfaces as image loads proceed. 246 bool mPendingNotify : 1; 247 bool mValidating : 1; 248 }; 249 250 inline nsISupports* ToSupports(imgRequestProxy* p) { 251 return NS_ISUPPORTS_CAST(imgIRequest*, p); 252 } 253 254 // Used for static image proxies for which no requests are available, so 255 // certain behaviours must be overridden to compensate. 256 class imgRequestProxyStatic : public imgRequestProxy { 257 public: 258 imgRequestProxyStatic(Image* aImage, nsIPrincipal* aImagePrincipal, 259 nsIPrincipal* aTriggeringPrincipal, 260 bool hadCrossOriginRedirects); 261 262 NS_IMETHOD GetImagePrincipal(nsIPrincipal** aPrincipal) override; 263 NS_IMETHOD GetTriggeringPrincipal(nsIPrincipal** aPrincipal) override; 264 265 NS_IMETHOD GetHadCrossOriginRedirects( 266 bool* aHadCrossOriginRedirects) override; 267 268 protected: 269 imgRequestProxy* NewClonedProxy() override; 270 271 // Our principal. We have to cache it, rather than accessing the underlying 272 // request on-demand, because static proxies don't have an underlying request. 273 const nsCOMPtr<nsIPrincipal> mImagePrincipal; 274 const nsCOMPtr<nsIPrincipal> mTriggeringPrincipal; 275 const bool mHadCrossOriginRedirects; 276 }; 277 278 #endif // mozilla_image_imgRequestProxy_h