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