|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 */ |
|
8 |
|
9 #ifndef nsDocLoader_h__ |
|
10 #define nsDocLoader_h__ |
|
11 |
|
12 #include "nsIDocumentLoader.h" |
|
13 #include "nsIWebProgress.h" |
|
14 #include "nsIWebProgressListener.h" |
|
15 #include "nsIRequestObserver.h" |
|
16 #include "nsWeakReference.h" |
|
17 #include "nsILoadGroup.h" |
|
18 #include "nsCOMArray.h" |
|
19 #include "nsTObserverArray.h" |
|
20 #include "nsVoidArray.h" |
|
21 #include "nsString.h" |
|
22 #include "nsIChannel.h" |
|
23 #include "nsIProgressEventSink.h" |
|
24 #include "nsIInterfaceRequestor.h" |
|
25 #include "nsIInterfaceRequestorUtils.h" |
|
26 #include "nsIChannelEventSink.h" |
|
27 #include "nsISecurityEventSink.h" |
|
28 #include "nsISupportsPriority.h" |
|
29 #include "nsCOMPtr.h" |
|
30 #include "pldhash.h" |
|
31 #include "nsAutoPtr.h" |
|
32 |
|
33 #include "mozilla/LinkedList.h" |
|
34 |
|
35 struct nsListenerInfo; |
|
36 |
|
37 /**************************************************************************** |
|
38 * nsDocLoader implementation... |
|
39 ****************************************************************************/ |
|
40 |
|
41 #define NS_THIS_DOCLOADER_IMPL_CID \ |
|
42 { /* b4ec8387-98aa-4c08-93b6-6d23069c06f2 */ \ |
|
43 0xb4ec8387, \ |
|
44 0x98aa, \ |
|
45 0x4c08, \ |
|
46 {0x93, 0xb6, 0x6d, 0x23, 0x06, 0x9c, 0x06, 0xf2} \ |
|
47 } |
|
48 |
|
49 class nsDocLoader : public nsIDocumentLoader, |
|
50 public nsIRequestObserver, |
|
51 public nsSupportsWeakReference, |
|
52 public nsIProgressEventSink, |
|
53 public nsIWebProgress, |
|
54 public nsIInterfaceRequestor, |
|
55 public nsIChannelEventSink, |
|
56 public nsISecurityEventSink, |
|
57 public nsISupportsPriority |
|
58 { |
|
59 public: |
|
60 NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_DOCLOADER_IMPL_CID) |
|
61 |
|
62 nsDocLoader(); |
|
63 |
|
64 virtual nsresult Init(); |
|
65 |
|
66 static already_AddRefed<nsDocLoader> GetAsDocLoader(nsISupports* aSupports); |
|
67 // Needed to deal with ambiguous inheritance from nsISupports... |
|
68 static nsISupports* GetAsSupports(nsDocLoader* aDocLoader) { |
|
69 return static_cast<nsIDocumentLoader*>(aDocLoader); |
|
70 } |
|
71 |
|
72 // Add aDocLoader as a child to the docloader service. |
|
73 static nsresult AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader); |
|
74 |
|
75 NS_DECL_ISUPPORTS |
|
76 NS_DECL_NSIDOCUMENTLOADER |
|
77 |
|
78 // nsIProgressEventSink |
|
79 NS_DECL_NSIPROGRESSEVENTSINK |
|
80 |
|
81 NS_DECL_NSISECURITYEVENTSINK |
|
82 |
|
83 // nsIRequestObserver methods: (for observing the load group) |
|
84 NS_DECL_NSIREQUESTOBSERVER |
|
85 NS_DECL_NSIWEBPROGRESS |
|
86 |
|
87 NS_DECL_NSIINTERFACEREQUESTOR |
|
88 NS_DECL_NSICHANNELEVENTSINK |
|
89 NS_DECL_NSISUPPORTSPRIORITY |
|
90 |
|
91 // Implementation specific methods... |
|
92 |
|
93 // Remove aChild from our childlist. This nulls out the child's mParent |
|
94 // pointer. |
|
95 nsresult RemoveChildLoader(nsDocLoader *aChild); |
|
96 // Add aChild to our child list. This will set aChild's mParent pointer to |
|
97 // |this|. |
|
98 nsresult AddChildLoader(nsDocLoader* aChild); |
|
99 nsDocLoader* GetParent() const { return mParent; } |
|
100 |
|
101 protected: |
|
102 virtual ~nsDocLoader(); |
|
103 |
|
104 virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader); |
|
105 |
|
106 bool IsBusy(); |
|
107 |
|
108 void Destroy(); |
|
109 virtual void DestroyChildren(); |
|
110 |
|
111 nsIDocumentLoader* ChildAt(int32_t i) { |
|
112 return mChildList.SafeElementAt(i, nullptr); |
|
113 } |
|
114 |
|
115 void FireOnProgressChange(nsDocLoader* aLoadInitiator, |
|
116 nsIRequest *request, |
|
117 int64_t aProgress, |
|
118 int64_t aProgressMax, |
|
119 int64_t aProgressDelta, |
|
120 int64_t aTotalProgress, |
|
121 int64_t aMaxTotalProgress); |
|
122 |
|
123 // This should be at least 2 long since we'll generally always |
|
124 // have the current page and the global docloader on the ancestor |
|
125 // list. But to deal with frames it's better to make it a bit |
|
126 // longer, and it's always a stack temporary so there's no real |
|
127 // reason not to. |
|
128 typedef nsAutoTArray<nsRefPtr<nsDocLoader>, 8> WebProgressList; |
|
129 void GatherAncestorWebProgresses(WebProgressList& aList); |
|
130 |
|
131 void FireOnStateChange(nsIWebProgress *aProgress, |
|
132 nsIRequest* request, |
|
133 int32_t aStateFlags, |
|
134 nsresult aStatus); |
|
135 |
|
136 // The guts of FireOnStateChange, but does not call itself on our ancestors. |
|
137 // The arguments that are const are const so that we can detect cases when |
|
138 // DoFireOnStateChange wants to propagate changes to the next web progress |
|
139 // at compile time. The ones that are not, are references so that such |
|
140 // changes can be propagated. |
|
141 void DoFireOnStateChange(nsIWebProgress * const aProgress, |
|
142 nsIRequest* const request, |
|
143 int32_t &aStateFlags, |
|
144 const nsresult aStatus); |
|
145 |
|
146 void FireOnStatusChange(nsIWebProgress *aWebProgress, |
|
147 nsIRequest *aRequest, |
|
148 nsresult aStatus, |
|
149 const char16_t* aMessage); |
|
150 |
|
151 void FireOnLocationChange(nsIWebProgress* aWebProgress, |
|
152 nsIRequest* aRequest, |
|
153 nsIURI *aUri, |
|
154 uint32_t aFlags); |
|
155 |
|
156 bool RefreshAttempted(nsIWebProgress* aWebProgress, |
|
157 nsIURI *aURI, |
|
158 int32_t aDelay, |
|
159 bool aSameURI); |
|
160 |
|
161 // this function is overridden by the docshell, it is provided so that we |
|
162 // can pass more information about redirect state (the normal OnStateChange |
|
163 // doesn't get the new channel). |
|
164 // @param aRedirectFlags The flags being sent to OnStateChange that |
|
165 // indicate the type of redirect. |
|
166 // @param aStateFlags The channel flags normally sent to OnStateChange. |
|
167 virtual void OnRedirectStateChange(nsIChannel* aOldChannel, |
|
168 nsIChannel* aNewChannel, |
|
169 uint32_t aRedirectFlags, |
|
170 uint32_t aStateFlags) {} |
|
171 |
|
172 void doStartDocumentLoad(); |
|
173 void doStartURLLoad(nsIRequest *request); |
|
174 void doStopURLLoad(nsIRequest *request, nsresult aStatus); |
|
175 void doStopDocumentLoad(nsIRequest *request, nsresult aStatus); |
|
176 |
|
177 // Inform a parent docloader that aChild is about to call its onload |
|
178 // handler. |
|
179 bool ChildEnteringOnload(nsIDocumentLoader* aChild) { |
|
180 // It's ok if we're already in the list -- we'll just be in there twice |
|
181 // and then the RemoveObject calls from ChildDoneWithOnload will remove |
|
182 // us. |
|
183 return mChildrenInOnload.AppendObject(aChild); |
|
184 } |
|
185 |
|
186 // Inform a parent docloader that aChild is done calling its onload |
|
187 // handler. |
|
188 void ChildDoneWithOnload(nsIDocumentLoader* aChild) { |
|
189 mChildrenInOnload.RemoveObject(aChild); |
|
190 DocLoaderIsEmpty(true); |
|
191 } |
|
192 |
|
193 protected: |
|
194 struct nsStatusInfo : public mozilla::LinkedListElement<nsStatusInfo> |
|
195 { |
|
196 nsString mStatusMessage; |
|
197 nsresult mStatusCode; |
|
198 // Weak mRequest is ok; we'll be told if it decides to go away. |
|
199 nsIRequest * const mRequest; |
|
200 |
|
201 nsStatusInfo(nsIRequest* aRequest) : |
|
202 mRequest(aRequest) |
|
203 { |
|
204 MOZ_COUNT_CTOR(nsStatusInfo); |
|
205 } |
|
206 ~nsStatusInfo() |
|
207 { |
|
208 MOZ_COUNT_DTOR(nsStatusInfo); |
|
209 } |
|
210 }; |
|
211 |
|
212 struct nsRequestInfo : public PLDHashEntryHdr |
|
213 { |
|
214 nsRequestInfo(const void* key) |
|
215 : mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(false) |
|
216 , mLastStatus(nullptr) |
|
217 { |
|
218 MOZ_COUNT_CTOR(nsRequestInfo); |
|
219 } |
|
220 |
|
221 ~nsRequestInfo() |
|
222 { |
|
223 MOZ_COUNT_DTOR(nsRequestInfo); |
|
224 } |
|
225 |
|
226 nsIRequest* Request() { |
|
227 return static_cast<nsIRequest*>(const_cast<void*>(mKey)); |
|
228 } |
|
229 |
|
230 const void* mKey; // Must be first for the pldhash stubs to work |
|
231 int64_t mCurrentProgress; |
|
232 int64_t mMaxProgress; |
|
233 bool mUploading; |
|
234 |
|
235 nsAutoPtr<nsStatusInfo> mLastStatus; |
|
236 }; |
|
237 |
|
238 static bool RequestInfoHashInitEntry(PLDHashTable* table, PLDHashEntryHdr* entry, |
|
239 const void* key); |
|
240 static void RequestInfoHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry); |
|
241 |
|
242 // IMPORTANT: The ownership implicit in the following member |
|
243 // variables has been explicitly checked and set using nsCOMPtr |
|
244 // for owning pointers and raw COM interface pointers for weak |
|
245 // (ie, non owning) references. If you add any members to this |
|
246 // class, please make the ownership explicit (pinkerton, scc). |
|
247 |
|
248 nsCOMPtr<nsIRequest> mDocumentRequest; // [OWNER] ???compare with document |
|
249 |
|
250 nsDocLoader* mParent; // [WEAK] |
|
251 |
|
252 nsVoidArray mListenerInfoList; |
|
253 |
|
254 nsCOMPtr<nsILoadGroup> mLoadGroup; |
|
255 // We hold weak refs to all our kids |
|
256 nsTObserverArray<nsDocLoader*> mChildList; |
|
257 |
|
258 // The following member variables are related to the new nsIWebProgress |
|
259 // feedback interfaces that travis cooked up. |
|
260 int32_t mProgressStateFlags; |
|
261 |
|
262 int64_t mCurrentSelfProgress; |
|
263 int64_t mMaxSelfProgress; |
|
264 |
|
265 int64_t mCurrentTotalProgress; |
|
266 int64_t mMaxTotalProgress; |
|
267 |
|
268 PLDHashTable mRequestInfoHash; |
|
269 int64_t mCompletedTotalProgress; |
|
270 |
|
271 mozilla::LinkedList<nsStatusInfo> mStatusInfoList; |
|
272 |
|
273 /* |
|
274 * This flag indicates that the loader is loading a document. It is set |
|
275 * from the call to LoadDocument(...) until the OnConnectionsComplete(...) |
|
276 * notification is fired... |
|
277 */ |
|
278 bool mIsLoadingDocument; |
|
279 |
|
280 /* Flag to indicate that we're in the process of restoring a document. */ |
|
281 bool mIsRestoringDocument; |
|
282 |
|
283 /* Flag to indicate that we're in the process of flushing layout |
|
284 under DocLoaderIsEmpty() and should not do another flush. */ |
|
285 bool mDontFlushLayout; |
|
286 |
|
287 /* Flag to indicate whether we should consider ourselves as currently |
|
288 flushing layout for the purposes of IsBusy. For example, if Stop has |
|
289 been called then IsBusy should return false even if we are still |
|
290 flushing. */ |
|
291 bool mIsFlushingLayout; |
|
292 |
|
293 private: |
|
294 // A list of kids that are in the middle of their onload calls and will let |
|
295 // us know once they're done. We don't want to fire onload for "normal" |
|
296 // DocLoaderIsEmpty calls (those coming from requests finishing in our |
|
297 // loadgroup) unless this is empty. |
|
298 nsCOMArray<nsIDocumentLoader> mChildrenInOnload; |
|
299 |
|
300 // DocLoaderIsEmpty should be called whenever the docloader may be empty. |
|
301 // This method is idempotent and does nothing if the docloader is not in |
|
302 // fact empty. This method _does_ make sure that layout is flushed if our |
|
303 // loadgroup has no active requests before checking for "real" emptiness if |
|
304 // aFlushLayout is true. |
|
305 void DocLoaderIsEmpty(bool aFlushLayout); |
|
306 |
|
307 nsListenerInfo *GetListenerInfo(nsIWebProgressListener* aListener); |
|
308 |
|
309 int64_t GetMaxTotalProgress(); |
|
310 |
|
311 nsresult AddRequestInfo(nsIRequest* aRequest); |
|
312 void RemoveRequestInfo(nsIRequest* aRequest); |
|
313 nsRequestInfo *GetRequestInfo(nsIRequest* aRequest); |
|
314 void ClearRequestInfoHash(); |
|
315 int64_t CalculateMaxProgress(); |
|
316 static PLDHashOperator CalcMaxProgressCallback(PLDHashTable* table, |
|
317 PLDHashEntryHdr* hdr, |
|
318 uint32_t number, void* arg); |
|
319 /// void DumpChannelInfo(void); |
|
320 |
|
321 // used to clear our internal progress state between loads... |
|
322 void ClearInternalProgress(); |
|
323 }; |
|
324 |
|
325 NS_DEFINE_STATIC_IID_ACCESSOR(nsDocLoader, NS_THIS_DOCLOADER_IMPL_CID) |
|
326 |
|
327 #endif /* nsDocLoader_h__ */ |