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