/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_CanonicalBrowsingContext_h #define mozilla_dom_CanonicalBrowsingContext_h #include "mozilla/dom/BrowsingContext.h" #include "mozilla/dom/MediaControlKeySource.h" #include "mozilla/dom/BrowsingContextWebProgress.h" #include "mozilla/dom/ProcessIsolation.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/SessionHistoryEntry.h" #include "mozilla/dom/SessionStoreRestoreData.h" #include "mozilla/dom/SessionStoreUtils.h" #include "mozilla/dom/ipc/IdType.h" #include "mozilla/RefPtr.h" #include "mozilla/MozPromise.h" #include "nsCycleCollectionParticipant.h" #include "nsWrapperCache.h" #include "nsTArray.h" #include "nsTHashtable.h" #include "nsHashKeys.h" #include "nsISecureBrowserUI.h" class nsIBrowserDOMWindow; class nsISHistory; class nsIWidget; class nsIPrintSettings; class nsSHistory; class nsBrowserStatusFilter; class nsSecureBrowserUI; class CallerWillNotifyHistoryIndexAndLengthChanges; class nsITimer; namespace mozilla { enum class CallState; namespace embedding { class PrintData; } namespace net { class DocumentLoadListener; } namespace dom { class BrowserParent; class BrowserBridgeParent; class FeaturePolicy; struct LoadURIOptions; class MediaController; struct LoadingSessionHistoryInfo; class SSCacheCopy; class WindowGlobalParent; class SessionStoreFormData; class SessionStoreScrollData; // CanonicalBrowsingContext is a BrowsingContext living in the parent // process, with whatever extra data that a BrowsingContext in the // parent needs. class CanonicalBrowsingContext final : public BrowsingContext { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED( CanonicalBrowsingContext, BrowsingContext) static already_AddRefed Get(uint64_t aId); static CanonicalBrowsingContext* Cast(BrowsingContext* aContext); static const CanonicalBrowsingContext* Cast(const BrowsingContext* aContext); static already_AddRefed Cast( already_AddRefed&& aContext); bool IsOwnedByProcess(uint64_t aProcessId) const { return mProcessId == aProcessId; } bool IsEmbeddedInProcess(uint64_t aProcessId) const { return mEmbedderProcessId == aProcessId; } uint64_t OwnerProcessId() const { return mProcessId; } uint64_t EmbedderProcessId() const { return mEmbedderProcessId; } ContentParent* GetContentParent() const; void GetCurrentRemoteType(nsACString& aRemoteType, ErrorResult& aRv) const; void SetOwnerProcessId(uint64_t aProcessId); // The ID of the BrowsingContext which caused this BrowsingContext to be // opened, or `0` if this is unknown. // Only set for toplevel content BrowsingContexts, and may be from a different // BrowsingContextGroup. uint64_t GetCrossGroupOpenerId() const { return mCrossGroupOpenerId; } void SetCrossGroupOpenerId(uint64_t aOpenerId); void SetCrossGroupOpener(CanonicalBrowsingContext& aCrossGroupOpener, ErrorResult& aRv); void GetWindowGlobals(nsTArray>& aWindows); // The current active WindowGlobal. WindowGlobalParent* GetCurrentWindowGlobal() const; // Same as the methods on `BrowsingContext`, but with the types already cast // to the parent process type. CanonicalBrowsingContext* GetParent() { return Cast(BrowsingContext::GetParent()); } CanonicalBrowsingContext* Top() { return Cast(BrowsingContext::Top()); } WindowGlobalParent* GetParentWindowContext(); WindowGlobalParent* GetTopWindowContext(); already_AddRefed GetParentProcessWidgetContaining(); already_AddRefed GetBrowserDOMWindow(); // Same as `GetParentWindowContext`, but will also cross and // content/chrome boundaries. already_AddRefed GetEmbedderWindowGlobal() const; already_AddRefed GetParentCrossChromeBoundary(); already_AddRefed TopCrossChromeBoundary(); Nullable GetTopChromeWindow(); nsISHistory* GetSessionHistory(); SessionHistoryEntry* GetActiveSessionHistoryEntry(); void SetActiveSessionHistoryEntry(SessionHistoryEntry* aEntry); UniquePtr CreateLoadingSessionHistoryEntryForLoad( nsDocShellLoadState* aLoadState, SessionHistoryEntry* aExistingEntry, nsIChannel* aChannel); UniquePtr ReplaceLoadingSessionHistoryEntryForLoad( LoadingSessionHistoryInfo* aInfo, nsIChannel* aNewChannel); using PrintPromise = MozPromise; MOZ_CAN_RUN_SCRIPT RefPtr Print(nsIPrintSettings*); MOZ_CAN_RUN_SCRIPT already_AddRefed PrintJS(nsIPrintSettings*, ErrorResult&); // Call the given callback on all top-level descendant BrowsingContexts. // Return Callstate::Stop from the callback to stop calling // further children. void CallOnAllTopDescendants( const std::function& aCallback); void SessionHistoryCommit(uint64_t aLoadId, const nsID& aChangeID, uint32_t aLoadType, bool aPersist, bool aCloneEntryChildren, bool aChannelExpired, uint32_t aCacheKey); // Calls the session history listeners' OnHistoryReload, storing the result in // aCanReload. If aCanReload is set to true and we have an active or a loading // entry then aLoadState will be initialized from that entry, and // aReloadActiveEntry will be true if we have an active entry. If aCanReload // is true and aLoadState and aReloadActiveEntry are not set then we should // attempt to reload based on the current document in the docshell. void NotifyOnHistoryReload( bool aForceReload, bool& aCanReload, Maybe>>& aLoadState, Maybe& aReloadActiveEntry); // See BrowsingContext::SetActiveSessionHistoryEntry. void SetActiveSessionHistoryEntry(const Maybe& aPreviousScrollPos, SessionHistoryInfo* aInfo, uint32_t aLoadType, uint32_t aUpdatedCacheKey, const nsID& aChangeID); void ReplaceActiveSessionHistoryEntry(SessionHistoryInfo* aInfo); void RemoveDynEntriesFromActiveSessionHistoryEntry(); void RemoveFromSessionHistory(const nsID& aChangeID); Maybe HistoryGo(int32_t aOffset, uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation, Maybe aContentId); JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; // Dispatches a wheel zoom change to the embedder element. void DispatchWheelZoomChange(bool aIncrease); // This function is used to start the autoplay media which are delayed to // start. If needed, it would also notify the content browsing context which // are related with the canonical browsing content tree to start delayed // autoplay media. void NotifyStartDelayedAutoplayMedia(); // This function is used to mute or unmute all media within a tab. It would // set the media mute property for the top level window and propagate it to // other top level windows in other processes. void NotifyMediaMutedChanged(bool aMuted, ErrorResult& aRv); // Return the number of unique site origins by iterating all given BCs, // including their subtrees. static uint32_t CountSiteOrigins( GlobalObject& aGlobal, const Sequence>& aRoots); // Return true if a private browsing session is active. static bool IsPrivateBrowsingActive(); // This function would propogate the action to its all child browsing contexts // in content processes. void UpdateMediaControlAction(const MediaControlAction& aAction); // Triggers a load in the process using BrowsingContext::LoadURI; void FixupAndLoadURIString(const nsAString& aURI, const LoadURIOptions& aOptions, ErrorResult& aError); void LoadURI(nsIURI* aURI, const LoadURIOptions& aOptions, ErrorResult& aError); void GoBack(const Optional& aCancelContentJSEpoch, bool aRequireUserInteraction, bool aUserActivation); void GoForward(const Optional& aCancelContentJSEpoch, bool aRequireUserInteraction, bool aUserActivation); void GoToIndex(int32_t aIndex, const Optional& aCancelContentJSEpoch, bool aUserActivation); void Reload(uint32_t aReloadFlags); void Stop(uint32_t aStopFlags); // Get the publicly exposed current URI loaded in this BrowsingContext. already_AddRefed GetCurrentURI() const; void SetCurrentRemoteURI(nsIURI* aCurrentRemoteURI); BrowserParent* GetBrowserParent() const; void SetCurrentBrowserParent(BrowserParent* aBrowserParent); // Internal method to change which process a BrowsingContext is being loaded // in. The returned promise will resolve when the process switch is completed. // // A NOT_REMOTE_TYPE aRemoteType argument will perform a process switch into // the parent process, and the method will resolve with a null BrowserParent. using RemotenessPromise = MozPromise, nsresult, false>; RefPtr ChangeRemoteness( const NavigationIsolationOptions& aOptions, uint64_t aPendingSwitchId); // Return a media controller from the top-level browsing context that can // control all media belonging to this browsing context tree. Return nullptr // if the top-level browsing context has been discarded. MediaController* GetMediaController(); bool HasCreatedMediaController() const; // Attempts to start loading the given load state in this BrowsingContext, // without requiring any communication from a docshell. This will handle // computing the right process to load in, and organising handoff to // the right docshell when we get a response. bool LoadInParent(nsDocShellLoadState* aLoadState, bool aSetNavigating); // Attempts to start loading the given load state in this BrowsingContext, // in parallel with a DocumentChannelChild being created in the docshell. // Requires the DocumentChannel to connect with this load for it to // complete successfully. bool AttemptSpeculativeLoadInParent(nsDocShellLoadState* aLoadState); // Get or create a secure browser UI for this BrowsingContext nsISecureBrowserUI* GetSecureBrowserUI(); BrowsingContextWebProgress* GetWebProgress() { return mWebProgress; } // Called when the current URI changes (from an // nsIWebProgressListener::OnLocationChange event, so that we // can update our security UI for the new location, or when the // mixed content/https-only state for our current window is changed. void UpdateSecurityState(); void MaybeAddAsProgressListener(nsIWebProgress* aWebProgress); // Called when a navigation forces us to recreate our browsing // context (for example, when switching in or out of the parent // process). // aNewContext is the newly created BrowsingContext that is replacing // us. void ReplacedBy(CanonicalBrowsingContext* aNewContext, const NavigationIsolationOptions& aRemotenessOptions); bool HasHistoryEntry(nsISHEntry* aEntry); bool HasLoadingHistoryEntry(nsISHEntry* aEntry) { for (const LoadingSessionHistoryEntry& loading : mLoadingEntries) { if (loading.mEntry == aEntry) { return true; } } return false; } void SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry); void AddLoadingSessionHistoryEntry(uint64_t aLoadId, SessionHistoryEntry* aEntry); void GetLoadingSessionHistoryInfoFromParent( Maybe& aLoadingInfo); void HistoryCommitIndexAndLength(); void SynchronizeLayoutHistoryState(); void ResetScalingZoom(); void SetContainerFeaturePolicy(FeaturePolicy* aContainerFeaturePolicy); FeaturePolicy* GetContainerFeaturePolicy() const { return mContainerFeaturePolicy; } void SetRestoreData(SessionStoreRestoreData* aData, ErrorResult& aError); void ClearRestoreState(); MOZ_CAN_RUN_SCRIPT_BOUNDARY void RequestRestoreTabContent( WindowGlobalParent* aWindow); already_AddRefed GetRestorePromise(); nsresult WriteSessionStorageToSessionStore( const nsTArray& aSesssionStorage, uint32_t aEpoch); void UpdateSessionStoreSessionStorage(const std::function& aDone); static void UpdateSessionStoreForStorage(uint64_t aBrowsingContextId); // Called when a BrowserParent for this BrowsingContext has been fully // destroyed (i.e. `ActorDestroy` was called). void BrowserParentDestroyed(BrowserParent* aBrowserParent, bool aAbnormalShutdown); void StartUnloadingHost(uint64_t aChildID); void ClearUnloadingHost(uint64_t aChildID); bool AllowedInBFCache(const Maybe& aChannelId, nsIURI* aNewURI); // Methods for getting and setting the active state for top level // browsing contexts, for the process priority manager. bool IsPriorityActive() const { MOZ_RELEASE_ASSERT(IsTop()); return mPriorityActive; } void SetPriorityActive(bool aIsActive) { MOZ_RELEASE_ASSERT(IsTop()); mPriorityActive = aIsActive; } void SetTouchEventsOverride(dom::TouchEventsOverride, ErrorResult& aRv); void SetTargetTopLevelLinkClicksToBlank(bool aTargetTopLevelLinkClicksToBlank, ErrorResult& aRv); bool IsReplaced() const { return mIsReplaced; } const JS::Heap& PermanentKey() { return mPermanentKey; } void ClearPermanentKey() { mPermanentKey.setNull(); } void MaybeSetPermanentKey(Element* aEmbedder); // When request for page awake, it would increase a count that is used to // prevent whole browsing context tree from being suspended. The request can // be called multiple times. When calling the revoke, it would decrease the // count and once the count reaches to zero, the browsing context tree could // be suspended when the tree is inactive. void AddPageAwakeRequest(); void RemovePageAwakeRequest(); void CloneDocumentTreeInto(CanonicalBrowsingContext* aSource, const nsACString& aRemoteType, embedding::PrintData&& aPrintData); // Returns a Promise which resolves when cloning documents for printing // finished if this browsing context is cloning document tree. RefPtr GetClonePromise() const { return mClonePromise; } bool StartApzAutoscroll(float aAnchorX, float aAnchorY, nsViewID aScrollId, uint32_t aPresShellId); void StopApzAutoscroll(nsViewID aScrollId, uint32_t aPresShellId); void AddFinalDiscardListener(std::function&& aListener); bool ForceAppWindowActive() const { return mForceAppWindowActive; } void SetForceAppWindowActive(bool, ErrorResult&); void RecomputeAppWindowVisibility(); already_AddRefed GetMostRecentLoadingSessionHistoryEntry(); protected: // Called when the browsing context is being discarded. void CanonicalDiscard(); // Called when the browsing context is being attached. void CanonicalAttach(); // Called when the browsing context private mode is changed after // being attached, but before being discarded. void AdjustPrivateBrowsingCount(bool aPrivateBrowsing); using Type = BrowsingContext::Type; CanonicalBrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup, uint64_t aBrowsingContextId, uint64_t aOwnerProcessId, uint64_t aEmbedderProcessId, Type aType, FieldValues&& aInit); private: friend class BrowsingContext; virtual ~CanonicalBrowsingContext(); class PendingRemotenessChange { public: NS_INLINE_DECL_REFCOUNTING(PendingRemotenessChange) PendingRemotenessChange(CanonicalBrowsingContext* aTarget, RemotenessPromise::Private* aPromise, uint64_t aPendingSwitchId, const NavigationIsolationOptions& aOptions); void Cancel(nsresult aRv); private: friend class CanonicalBrowsingContext; ~PendingRemotenessChange(); void ProcessLaunched(); void ProcessReady(); void MaybeFinish(); void Clear(); nsresult FinishTopContent(); nsresult FinishSubframe(); RefPtr mTarget; RefPtr mPromise; RefPtr mContentParent; RefPtr mSpecificGroup; bool mProcessReady = false; bool mWaitingForPrepareToChange = false; uint64_t mPendingSwitchId; NavigationIsolationOptions mOptions; }; struct RestoreState { NS_INLINE_DECL_REFCOUNTING(RestoreState) void ClearData() { mData = nullptr; } void Resolve(); RefPtr mData; RefPtr mPromise; uint32_t mRequests = 0; uint32_t mResolves = 0; private: ~RestoreState() = default; }; friend class net::DocumentLoadListener; // Called when a DocumentLoadListener is created to start a load for // this browsing context. Returns false if a higher priority load is // already in-progress and the new one has been rejected. bool StartDocumentLoad(net::DocumentLoadListener* aLoad); // Called once DocumentLoadListener completes handling a load, and it // is either complete, or handed off to the final channel to deliver // data to the destination docshell. // If aContinueNavigating it set, the reference to the DocumentLoadListener // will be cleared to prevent it being cancelled, however the current load ID // will be preserved until `EndDocumentLoad` is called again. void EndDocumentLoad(bool aContinueNavigating); bool SupportsLoadingInParent(nsDocShellLoadState* aLoadState, uint64_t* aOuterWindowId); void HistoryCommitIndexAndLength( const nsID& aChangeID, const CallerWillNotifyHistoryIndexAndLengthChanges& aProofOfCaller); struct UnloadingHost { uint64_t mChildID; nsTArray> mCallbacks; }; nsTArray::iterator FindUnloadingHost(uint64_t aChildID); // Called when we want to show the subframe crashed UI as our previous browser // has become unloaded for one reason or another. void ShowSubframeCrashedUI(BrowserBridgeParent* aBridge); void MaybeScheduleSessionStoreUpdate(); void CancelSessionStoreUpdate(); void AddPendingDiscard(); void RemovePendingDiscard(); bool ShouldAddEntryForRefresh(const SessionHistoryEntry* aEntry) { return ShouldAddEntryForRefresh(aEntry->Info().GetURI(), aEntry->Info().HasPostData()); } bool ShouldAddEntryForRefresh(nsIURI* aNewURI, bool aHasPostData) { nsCOMPtr currentURI = GetCurrentURI(); return BrowsingContext::ShouldAddEntryForRefresh(currentURI, aNewURI, aHasPostData); } already_AddRefed CreateLoadInfo( SessionHistoryEntry* aEntry); // XXX(farre): Store a ContentParent pointer here rather than mProcessId? // Indicates which process owns the docshell. uint64_t mProcessId; // Indicates which process owns the embedder element. uint64_t mEmbedderProcessId; uint64_t mCrossGroupOpenerId = 0; // This function will make the top window context reset its // "SHEntryHasUserInteraction" cache that prevents documents from repeatedly // setting user interaction on SH entries. Should be called anytime SH // entries are added or replaced. void ResetSHEntryHasUserInteractionCache(); RefPtr mCurrentBrowserParent; nsTArray mUnloadingHosts; // The current URI loaded in this BrowsingContext. This value is only set for // BrowsingContexts loaded in content processes. nsCOMPtr mCurrentRemoteURI; // The current remoteness change which is in a pending state. RefPtr mPendingRemotenessChange; RefPtr mSessionHistory; // Tab media controller is used to control all media existing in the same // browsing context tree, so it would only exist in the top level browsing // context. RefPtr mTabMediaController; RefPtr mCurrentLoad; struct LoadingSessionHistoryEntry { uint64_t mLoadId = 0; RefPtr mEntry; }; nsTArray mLoadingEntries; RefPtr mActiveEntry; RefPtr mSecureBrowserUI; RefPtr mWebProgress; nsCOMPtr mDocShellProgressBridge; RefPtr mStatusFilter; RefPtr mContainerFeaturePolicy; friend class BrowserSessionStore; WeakPtr& GetSessionStoreFormDataRef() { return mFormdata; } WeakPtr& GetSessionStoreScrollDataRef() { return mScroll; } WeakPtr mFormdata; WeakPtr mScroll; RefPtr mRestoreState; nsCOMPtr mSessionStoreSessionStorageUpdateTimer; // If this is a top level context, this is true if our browser ID is marked as // active in the process priority manager. bool mPriorityActive = false; // See CanonicalBrowsingContext.forceAppWindowActive. bool mForceAppWindowActive = false; bool mIsReplaced = false; // A Promise created when cloning documents for printing. RefPtr mClonePromise; JS::Heap mPermanentKey; uint32_t mPendingDiscards = 0; bool mFullyDiscarded = false; nsTArray> mFullyDiscardedListeners; }; } // namespace dom } // namespace mozilla #endif // !defined(mozilla_dom_CanonicalBrowsingContext_h)