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