michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: */ michael@0: michael@0: #ifndef nsDocLoader_h__ michael@0: #define nsDocLoader_h__ michael@0: michael@0: #include "nsIDocumentLoader.h" michael@0: #include "nsIWebProgress.h" michael@0: #include "nsIWebProgressListener.h" michael@0: #include "nsIRequestObserver.h" michael@0: #include "nsWeakReference.h" michael@0: #include "nsILoadGroup.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsTObserverArray.h" michael@0: #include "nsVoidArray.h" michael@0: #include "nsString.h" michael@0: #include "nsIChannel.h" michael@0: #include "nsIProgressEventSink.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIChannelEventSink.h" michael@0: #include "nsISecurityEventSink.h" michael@0: #include "nsISupportsPriority.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "pldhash.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: #include "mozilla/LinkedList.h" michael@0: michael@0: struct nsListenerInfo; michael@0: michael@0: /**************************************************************************** michael@0: * nsDocLoader implementation... michael@0: ****************************************************************************/ michael@0: michael@0: #define NS_THIS_DOCLOADER_IMPL_CID \ michael@0: { /* b4ec8387-98aa-4c08-93b6-6d23069c06f2 */ \ michael@0: 0xb4ec8387, \ michael@0: 0x98aa, \ michael@0: 0x4c08, \ michael@0: {0x93, 0xb6, 0x6d, 0x23, 0x06, 0x9c, 0x06, 0xf2} \ michael@0: } michael@0: michael@0: class nsDocLoader : public nsIDocumentLoader, michael@0: public nsIRequestObserver, michael@0: public nsSupportsWeakReference, michael@0: public nsIProgressEventSink, michael@0: public nsIWebProgress, michael@0: public nsIInterfaceRequestor, michael@0: public nsIChannelEventSink, michael@0: public nsISecurityEventSink, michael@0: public nsISupportsPriority michael@0: { michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(NS_THIS_DOCLOADER_IMPL_CID) michael@0: michael@0: nsDocLoader(); michael@0: michael@0: virtual nsresult Init(); michael@0: michael@0: static already_AddRefed GetAsDocLoader(nsISupports* aSupports); michael@0: // Needed to deal with ambiguous inheritance from nsISupports... michael@0: static nsISupports* GetAsSupports(nsDocLoader* aDocLoader) { michael@0: return static_cast(aDocLoader); michael@0: } michael@0: michael@0: // Add aDocLoader as a child to the docloader service. michael@0: static nsresult AddDocLoaderAsChildOfRoot(nsDocLoader* aDocLoader); michael@0: michael@0: NS_DECL_ISUPPORTS michael@0: NS_DECL_NSIDOCUMENTLOADER michael@0: michael@0: // nsIProgressEventSink michael@0: NS_DECL_NSIPROGRESSEVENTSINK michael@0: michael@0: NS_DECL_NSISECURITYEVENTSINK michael@0: michael@0: // nsIRequestObserver methods: (for observing the load group) michael@0: NS_DECL_NSIREQUESTOBSERVER michael@0: NS_DECL_NSIWEBPROGRESS michael@0: michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSICHANNELEVENTSINK michael@0: NS_DECL_NSISUPPORTSPRIORITY michael@0: michael@0: // Implementation specific methods... michael@0: michael@0: // Remove aChild from our childlist. This nulls out the child's mParent michael@0: // pointer. michael@0: nsresult RemoveChildLoader(nsDocLoader *aChild); michael@0: // Add aChild to our child list. This will set aChild's mParent pointer to michael@0: // |this|. michael@0: nsresult AddChildLoader(nsDocLoader* aChild); michael@0: nsDocLoader* GetParent() const { return mParent; } michael@0: michael@0: protected: michael@0: virtual ~nsDocLoader(); michael@0: michael@0: virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader); michael@0: michael@0: bool IsBusy(); michael@0: michael@0: void Destroy(); michael@0: virtual void DestroyChildren(); michael@0: michael@0: nsIDocumentLoader* ChildAt(int32_t i) { michael@0: return mChildList.SafeElementAt(i, nullptr); michael@0: } michael@0: michael@0: void FireOnProgressChange(nsDocLoader* aLoadInitiator, michael@0: nsIRequest *request, michael@0: int64_t aProgress, michael@0: int64_t aProgressMax, michael@0: int64_t aProgressDelta, michael@0: int64_t aTotalProgress, michael@0: int64_t aMaxTotalProgress); michael@0: michael@0: // This should be at least 2 long since we'll generally always michael@0: // have the current page and the global docloader on the ancestor michael@0: // list. But to deal with frames it's better to make it a bit michael@0: // longer, and it's always a stack temporary so there's no real michael@0: // reason not to. michael@0: typedef nsAutoTArray, 8> WebProgressList; michael@0: void GatherAncestorWebProgresses(WebProgressList& aList); michael@0: michael@0: void FireOnStateChange(nsIWebProgress *aProgress, michael@0: nsIRequest* request, michael@0: int32_t aStateFlags, michael@0: nsresult aStatus); michael@0: michael@0: // The guts of FireOnStateChange, but does not call itself on our ancestors. michael@0: // The arguments that are const are const so that we can detect cases when michael@0: // DoFireOnStateChange wants to propagate changes to the next web progress michael@0: // at compile time. The ones that are not, are references so that such michael@0: // changes can be propagated. michael@0: void DoFireOnStateChange(nsIWebProgress * const aProgress, michael@0: nsIRequest* const request, michael@0: int32_t &aStateFlags, michael@0: const nsresult aStatus); michael@0: michael@0: void FireOnStatusChange(nsIWebProgress *aWebProgress, michael@0: nsIRequest *aRequest, michael@0: nsresult aStatus, michael@0: const char16_t* aMessage); michael@0: michael@0: void FireOnLocationChange(nsIWebProgress* aWebProgress, michael@0: nsIRequest* aRequest, michael@0: nsIURI *aUri, michael@0: uint32_t aFlags); michael@0: michael@0: bool RefreshAttempted(nsIWebProgress* aWebProgress, michael@0: nsIURI *aURI, michael@0: int32_t aDelay, michael@0: bool aSameURI); michael@0: michael@0: // this function is overridden by the docshell, it is provided so that we michael@0: // can pass more information about redirect state (the normal OnStateChange michael@0: // doesn't get the new channel). michael@0: // @param aRedirectFlags The flags being sent to OnStateChange that michael@0: // indicate the type of redirect. michael@0: // @param aStateFlags The channel flags normally sent to OnStateChange. michael@0: virtual void OnRedirectStateChange(nsIChannel* aOldChannel, michael@0: nsIChannel* aNewChannel, michael@0: uint32_t aRedirectFlags, michael@0: uint32_t aStateFlags) {} michael@0: michael@0: void doStartDocumentLoad(); michael@0: void doStartURLLoad(nsIRequest *request); michael@0: void doStopURLLoad(nsIRequest *request, nsresult aStatus); michael@0: void doStopDocumentLoad(nsIRequest *request, nsresult aStatus); michael@0: michael@0: // Inform a parent docloader that aChild is about to call its onload michael@0: // handler. michael@0: bool ChildEnteringOnload(nsIDocumentLoader* aChild) { michael@0: // It's ok if we're already in the list -- we'll just be in there twice michael@0: // and then the RemoveObject calls from ChildDoneWithOnload will remove michael@0: // us. michael@0: return mChildrenInOnload.AppendObject(aChild); michael@0: } michael@0: michael@0: // Inform a parent docloader that aChild is done calling its onload michael@0: // handler. michael@0: void ChildDoneWithOnload(nsIDocumentLoader* aChild) { michael@0: mChildrenInOnload.RemoveObject(aChild); michael@0: DocLoaderIsEmpty(true); michael@0: } michael@0: michael@0: protected: michael@0: struct nsStatusInfo : public mozilla::LinkedListElement michael@0: { michael@0: nsString mStatusMessage; michael@0: nsresult mStatusCode; michael@0: // Weak mRequest is ok; we'll be told if it decides to go away. michael@0: nsIRequest * const mRequest; michael@0: michael@0: nsStatusInfo(nsIRequest* aRequest) : michael@0: mRequest(aRequest) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStatusInfo); michael@0: } michael@0: ~nsStatusInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStatusInfo); michael@0: } michael@0: }; michael@0: michael@0: struct nsRequestInfo : public PLDHashEntryHdr michael@0: { michael@0: nsRequestInfo(const void* key) michael@0: : mKey(key), mCurrentProgress(0), mMaxProgress(0), mUploading(false) michael@0: , mLastStatus(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(nsRequestInfo); michael@0: } michael@0: michael@0: ~nsRequestInfo() michael@0: { michael@0: MOZ_COUNT_DTOR(nsRequestInfo); michael@0: } michael@0: michael@0: nsIRequest* Request() { michael@0: return static_cast(const_cast(mKey)); michael@0: } michael@0: michael@0: const void* mKey; // Must be first for the pldhash stubs to work michael@0: int64_t mCurrentProgress; michael@0: int64_t mMaxProgress; michael@0: bool mUploading; michael@0: michael@0: nsAutoPtr mLastStatus; michael@0: }; michael@0: michael@0: static bool RequestInfoHashInitEntry(PLDHashTable* table, PLDHashEntryHdr* entry, michael@0: const void* key); michael@0: static void RequestInfoHashClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry); michael@0: michael@0: // IMPORTANT: The ownership implicit in the following member michael@0: // variables has been explicitly checked and set using nsCOMPtr michael@0: // for owning pointers and raw COM interface pointers for weak michael@0: // (ie, non owning) references. If you add any members to this michael@0: // class, please make the ownership explicit (pinkerton, scc). michael@0: michael@0: nsCOMPtr mDocumentRequest; // [OWNER] ???compare with document michael@0: michael@0: nsDocLoader* mParent; // [WEAK] michael@0: michael@0: nsVoidArray mListenerInfoList; michael@0: michael@0: nsCOMPtr mLoadGroup; michael@0: // We hold weak refs to all our kids michael@0: nsTObserverArray mChildList; michael@0: michael@0: // The following member variables are related to the new nsIWebProgress michael@0: // feedback interfaces that travis cooked up. michael@0: int32_t mProgressStateFlags; michael@0: michael@0: int64_t mCurrentSelfProgress; michael@0: int64_t mMaxSelfProgress; michael@0: michael@0: int64_t mCurrentTotalProgress; michael@0: int64_t mMaxTotalProgress; michael@0: michael@0: PLDHashTable mRequestInfoHash; michael@0: int64_t mCompletedTotalProgress; michael@0: michael@0: mozilla::LinkedList mStatusInfoList; michael@0: michael@0: /* michael@0: * This flag indicates that the loader is loading a document. It is set michael@0: * from the call to LoadDocument(...) until the OnConnectionsComplete(...) michael@0: * notification is fired... michael@0: */ michael@0: bool mIsLoadingDocument; michael@0: michael@0: /* Flag to indicate that we're in the process of restoring a document. */ michael@0: bool mIsRestoringDocument; michael@0: michael@0: /* Flag to indicate that we're in the process of flushing layout michael@0: under DocLoaderIsEmpty() and should not do another flush. */ michael@0: bool mDontFlushLayout; michael@0: michael@0: /* Flag to indicate whether we should consider ourselves as currently michael@0: flushing layout for the purposes of IsBusy. For example, if Stop has michael@0: been called then IsBusy should return false even if we are still michael@0: flushing. */ michael@0: bool mIsFlushingLayout; michael@0: michael@0: private: michael@0: // A list of kids that are in the middle of their onload calls and will let michael@0: // us know once they're done. We don't want to fire onload for "normal" michael@0: // DocLoaderIsEmpty calls (those coming from requests finishing in our michael@0: // loadgroup) unless this is empty. michael@0: nsCOMArray mChildrenInOnload; michael@0: michael@0: // DocLoaderIsEmpty should be called whenever the docloader may be empty. michael@0: // This method is idempotent and does nothing if the docloader is not in michael@0: // fact empty. This method _does_ make sure that layout is flushed if our michael@0: // loadgroup has no active requests before checking for "real" emptiness if michael@0: // aFlushLayout is true. michael@0: void DocLoaderIsEmpty(bool aFlushLayout); michael@0: michael@0: nsListenerInfo *GetListenerInfo(nsIWebProgressListener* aListener); michael@0: michael@0: int64_t GetMaxTotalProgress(); michael@0: michael@0: nsresult AddRequestInfo(nsIRequest* aRequest); michael@0: void RemoveRequestInfo(nsIRequest* aRequest); michael@0: nsRequestInfo *GetRequestInfo(nsIRequest* aRequest); michael@0: void ClearRequestInfoHash(); michael@0: int64_t CalculateMaxProgress(); michael@0: static PLDHashOperator CalcMaxProgressCallback(PLDHashTable* table, michael@0: PLDHashEntryHdr* hdr, michael@0: uint32_t number, void* arg); michael@0: /// void DumpChannelInfo(void); michael@0: michael@0: // used to clear our internal progress state between loads... michael@0: void ClearInternalProgress(); michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(nsDocLoader, NS_THIS_DOCLOADER_IMPL_CID) michael@0: michael@0: #endif /* nsDocLoader_h__ */