Navigation.h (13236B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_Navigation_h___ 8 #define mozilla_dom_Navigation_h___ 9 10 #include "mozilla/AlreadyAddRefed.h" 11 #include "mozilla/DOMEventTargetHelper.h" 12 #include "mozilla/Maybe.h" 13 #include "mozilla/RefPtr.h" 14 #include "mozilla/dom/NavigateEvent.h" 15 #include "mozilla/dom/NavigationBinding.h" 16 #include "nsHashtablesFwd.h" 17 #include "nsStringFwd.h" 18 19 class nsIDHashKey; 20 21 namespace mozilla::dom { 22 23 class FormData; 24 class NavigationActivation; 25 class NavigationDestination; 26 class NavigationHistoryEntry; 27 struct NavigationNavigateOptions; 28 struct NavigationOptions; 29 class NavigationTransition; 30 struct NavigationUpdateCurrentEntryOptions; 31 struct NavigationReloadOptions; 32 struct NavigationResult; 33 34 class SessionHistoryInfo; 35 36 // https://html.spec.whatwg.org/#navigation-api-method-tracker 37 struct NavigationAPIMethodTracker final : public nsISupports { 38 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 39 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(NavigationAPIMethodTracker) 40 41 NavigationAPIMethodTracker(Navigation* aNavigationObject, 42 const Maybe<nsID> aKey, const JS::Value& aInfo, 43 nsIStructuredCloneContainer* aSerializedState, 44 NavigationHistoryEntry* aCommittedToEntry, 45 Promise* aCommittedPromise, 46 Promise* aFinishedPromise, bool aPending = false); 47 48 // Mark this tracker as no longer pending (promoted to ongoing). 49 void MarkAsNotPending() { mPending = false; } 50 51 void CleanUp(); 52 void NotifyAboutCommittedToEntry(NavigationHistoryEntry* aNHE); 53 void ResolveFinishedPromise(); 54 void RejectFinishedPromise(JS::Handle<JS::Value> aException); 55 void CreateResult(JSContext* aCx, NavigationResult& aResult); 56 void SetSerializedState(nsIStructuredCloneContainer* aSerializedState) { 57 mSerializedState = aSerializedState; 58 } 59 60 Promise* CommittedPromise() { return mCommittedPromise; } 61 Promise* FinishedPromise() { return mFinishedPromise; } 62 63 RefPtr<Navigation> mNavigationObject; 64 Maybe<nsID> mKey; 65 JS::Heap<JS::Value> mInfo; 66 67 private: 68 ~NavigationAPIMethodTracker(); 69 70 bool mPending; 71 RefPtr<nsIStructuredCloneContainer> mSerializedState; 72 RefPtr<NavigationHistoryEntry> mCommittedToEntry; 73 RefPtr<Promise> mCommittedPromise; 74 RefPtr<Promise> mFinishedPromise; 75 }; 76 77 class Navigation final : public DOMEventTargetHelper { 78 public: 79 NS_DECL_ISUPPORTS_INHERITED 80 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Navigation, DOMEventTargetHelper) 81 82 explicit Navigation(nsPIDOMWindowInner* aWindow); 83 84 bool IsNavigation() const override { return true; } 85 86 NS_IMPL_FROMEVENTTARGET_HELPER(Navigation, IsNavigation()) 87 88 using EventTarget::EventListenerAdded; 89 virtual void EventListenerAdded(nsAtom* aType) override; 90 using EventTarget::EventListenerRemoved; 91 virtual void EventListenerRemoved(nsAtom* aType) override; 92 93 // Navigation.webidl 94 void Entries(nsTArray<RefPtr<NavigationHistoryEntry>>& aResult) const; 95 already_AddRefed<NavigationHistoryEntry> GetCurrentEntry() const; 96 MOZ_CAN_RUN_SCRIPT 97 void UpdateCurrentEntry(JSContext* aCx, 98 const NavigationUpdateCurrentEntryOptions& aOptions, 99 ErrorResult& aRv); 100 NavigationTransition* GetTransition() const; 101 NavigationActivation* GetActivation() const; 102 103 bool CanGoBack() { 104 return !HasEntriesAndEventsDisabled() && mCurrentEntryIndex && 105 *mCurrentEntryIndex != 0; 106 } 107 bool CanGoForward() { 108 return !HasEntriesAndEventsDisabled() && mCurrentEntryIndex && 109 *mCurrentEntryIndex != mEntries.Length() - 1; 110 } 111 112 void Navigate(JSContext* aCx, const nsAString& aUrl, 113 const NavigationNavigateOptions& aOptions, 114 NavigationResult& aResult); 115 116 MOZ_CAN_RUN_SCRIPT void Reload(JSContext* aCx, 117 const NavigationReloadOptions& aOptions, 118 NavigationResult& aResult); 119 120 void TraverseTo(JSContext* aCx, const nsAString& aKey, 121 const NavigationOptions& aOptions, NavigationResult& aResult); 122 void Back(JSContext* aCx, const NavigationOptions& aOptions, 123 NavigationResult& aResult); 124 void Forward(JSContext* aCx, const NavigationOptions& aOptions, 125 NavigationResult& aResult); 126 127 IMPL_EVENT_HANDLER(navigate); 128 IMPL_EVENT_HANDLER(navigatesuccess); 129 IMPL_EVENT_HANDLER(navigateerror); 130 IMPL_EVENT_HANDLER(currententrychange); 131 132 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#initialize-the-navigation-api-entries-for-a-new-document 133 void InitializeHistoryEntries( 134 mozilla::Span<const SessionHistoryInfo> aNewSHInfos, 135 const SessionHistoryInfo* aInitialSHInfo); 136 137 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#update-the-navigation-api-entries-for-reactivation 138 MOZ_CAN_RUN_SCRIPT 139 void UpdateForReactivation(SessionHistoryInfo* aReactivatedEntry); 140 141 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation 142 void UpdateEntriesForSameDocumentNavigation( 143 SessionHistoryInfo* aDestinationSHE, NavigationType aNavigationType); 144 145 JSObject* WrapObject(JSContext* aCx, 146 JS::Handle<JSObject*> aGivenProto) override; 147 148 // The Navigation API is only enabled if both SessionHistoryInParent and 149 // the dom.navigation.webidl.enabled pref are set. 150 static bool IsAPIEnabled(JSContext* /* unused */ = nullptr, 151 JSObject* /* unused */ = nullptr); 152 153 // Wrapper algorithms for firing the navigate event. 154 // https://html.spec.whatwg.org/#navigate-event-firing 155 156 MOZ_CAN_RUN_SCRIPT bool FireTraverseNavigateEvent( 157 JSContext* aCx, const SessionHistoryInfo& aDestinationSessionHistoryInfo, 158 Maybe<UserNavigationInvolvement> aUserInvolvement); 159 160 MOZ_CAN_RUN_SCRIPT bool FirePushReplaceReloadNavigateEvent( 161 JSContext* aCx, NavigationType aNavigationType, nsIURI* aDestinationURL, 162 bool aIsSameDocument, Maybe<UserNavigationInvolvement> aUserInvolvement, 163 Element* aSourceElement, FormData* aFormDataEntryList, 164 nsIStructuredCloneContainer* aNavigationAPIState, 165 nsIStructuredCloneContainer* aClassicHistoryAPIState, 166 NavigationAPIMethodTracker* aApiMethodTrackerForNavigateOrReload = 167 nullptr); 168 169 MOZ_CAN_RUN_SCRIPT bool FireDownloadRequestNavigateEvent( 170 JSContext* aCx, nsIURI* aDestinationURL, 171 UserNavigationInvolvement aUserInvolvement, Element* aSourceElement, 172 const nsAString& aFilename); 173 174 bool FocusedChangedDuringOngoingNavigation() const; 175 void SetFocusedChangedDuringOngoingNavigation( 176 bool aFocusChangedDuringOngoingNavigation); 177 178 bool HasOngoingNavigateEvent() const; 179 180 MOZ_CAN_RUN_SCRIPT 181 void InnerInformAboutAbortingNavigation(JSContext* aCx); 182 183 MOZ_CAN_RUN_SCRIPT 184 void AbortOngoingNavigation( 185 JSContext* aCx, JS::Handle<JS::Value> aError = JS::UndefinedHandleValue); 186 187 MOZ_CAN_RUN_SCRIPT 188 void AbortNavigateEvent(JSContext* aCx, NavigateEvent* aEvent, 189 JS::Handle<JS::Value> aReason); 190 191 MOZ_CAN_RUN_SCRIPT 192 void InformAboutChildNavigableDestruction(JSContext* aCx); 193 194 void CreateNavigationActivationFrom( 195 SessionHistoryInfo* aPreviousEntryForActivation, 196 NavigationType aNavigationType); 197 198 void SetSerializedStateIntoOngoingAPIMethodTracker( 199 nsIStructuredCloneContainer* aSerializedState); 200 201 private: 202 friend struct NavigationAPIMethodTracker; 203 friend struct NavigationWaitForAllScope; 204 using UpcomingTraverseAPIMethodTrackers = 205 nsTHashMap<nsIDHashKey, RefPtr<NavigationAPIMethodTracker>>; 206 207 ~Navigation() = default; 208 209 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#has-entries-and-events-disabled 210 bool HasEntriesAndEventsDisabled() const; 211 212 MOZ_CAN_RUN_SCRIPT 213 nsresult FireEvent(const nsAString& aName); 214 215 MOZ_CAN_RUN_SCRIPT 216 nsresult FireErrorEvent(const nsAString& aName, 217 const ErrorEventInit& aEventInitDict); 218 219 // https://html.spec.whatwg.org/#inner-navigate-event-firing-algorithm 220 MOZ_CAN_RUN_SCRIPT bool InnerFireNavigateEvent( 221 JSContext* aCx, NavigationType aNavigationType, 222 NavigationDestination* aDestination, 223 UserNavigationInvolvement aUserInvolvement, Element* aSourceElement, 224 FormData* aFormDataEntryList, 225 nsIStructuredCloneContainer* aClassicHistoryAPIState, 226 const nsAString& aDownloadRequestFilename, 227 NavigationAPIMethodTracker* aNavigationAPIMethodTracker = nullptr); 228 229 NavigationHistoryEntry* FindNavigationHistoryEntry( 230 const SessionHistoryInfo& aSessionHistoryInfo) const; 231 232 RefPtr<NavigationAPIMethodTracker> SetUpNavigateReloadAPIMethodTracker( 233 JS::Handle<JS::Value> aInfo, 234 nsIStructuredCloneContainer* aSerializedState); 235 236 RefPtr<NavigationAPIMethodTracker> AddUpcomingTraverseAPIMethodTracker( 237 const nsID& aKey, JS::Handle<JS::Value> aInfo); 238 239 void SetEarlyErrorResult(JSContext* aCx, NavigationResult& aResult, 240 ErrorResult&& aRv) const; 241 242 void SetEarlyStateErrorResult(JSContext* aCx, NavigationResult& aResult, 243 const nsACString& aMessage) const; 244 245 bool CheckIfDocumentIsFullyActiveAndMaybeSetEarlyErrorResult( 246 JSContext* aCx, const Document* aDocument, 247 NavigationResult& aResult) const; 248 249 bool CheckDocumentUnloadCounterAndMaybeSetEarlyErrorResult( 250 JSContext* aCx, const Document* aDocument, 251 NavigationResult& aResult) const; 252 253 already_AddRefed<nsIStructuredCloneContainer> 254 CreateSerializedStateAndMaybeSetEarlyErrorResult( 255 JSContext* aCx, const JS::Value& aState, NavigationResult& aResult) const; 256 257 static void CleanUp(NavigationAPIMethodTracker* aNavigationAPIMethodTracker); 258 259 void SetCurrentEntryIndex(const SessionHistoryInfo* aTargetInfo); 260 261 Document* GetAssociatedDocument() const; 262 263 // Update the state managing if we need to dispatch the traverse event or not. 264 void UpdateNeedsTraverse(); 265 266 void LogHistory() const; 267 268 void PerformNavigationTraversal(JSContext* aCx, const nsID& aKey, 269 const NavigationOptions& aOptions, 270 NavigationResult& aResult); 271 272 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-entry-list 273 nsTArray<RefPtr<NavigationHistoryEntry>> mEntries; 274 275 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-current-entry 276 Maybe<uint64_t> mCurrentEntryIndex; 277 278 // https://html.spec.whatwg.org/#ongoing-navigation-tracking:navigateevent-2 279 RefPtr<NavigateEvent> mOngoingNavigateEvent; 280 281 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#focus-changed-during-ongoing-navigation 282 bool mFocusChangedDuringOngoingNavigation = false; 283 284 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#suppress-normal-scroll-restoration-during-ongoing-navigation 285 bool mSuppressNormalScrollRestorationDuringOngoingNavigation = false; 286 287 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#ongoing-api-method-tracker 288 RefPtr<NavigationAPIMethodTracker> mOngoingAPIMethodTracker; 289 290 // https://html.spec.whatwg.org/multipage/nav-history-apis.html#upcoming-traverse-api-method-trackers 291 UpcomingTraverseAPIMethodTrackers mUpcomingTraverseAPIMethodTrackers; 292 293 // https://html.spec.whatwg.org/#concept-navigation-transition 294 RefPtr<NavigationTransition> mTransition; 295 296 // https://html.spec.whatwg.org/#navigation-activation 297 RefPtr<NavigationActivation> mActivation; 298 }; 299 300 inline Navigation* EventTarget::GetAsNavigation() { 301 return IsNavigation() ? AsNavigation() : nullptr; 302 } 303 inline const Navigation* EventTarget::GetAsNavigation() const { 304 return IsNavigation() ? AsNavigation() : nullptr; 305 } 306 inline Navigation* EventTarget::AsNavigation() { 307 MOZ_DIAGNOSTIC_ASSERT(IsNavigation()); 308 return static_cast<Navigation*>(this); 309 } 310 inline const Navigation* EventTarget::AsNavigation() const { 311 MOZ_DIAGNOSTIC_ASSERT(IsNavigation()); 312 return static_cast<const Navigation*>(this); 313 } 314 315 } // namespace mozilla::dom 316 317 template <> 318 struct fmt::formatter<mozilla::dom::NavigationType, char> 319 : public formatter<nsLiteralCString> { 320 template <typename FmtContext> 321 constexpr auto format(const mozilla::dom::NavigationType& aNavigationType, 322 FmtContext& aCtx) const { 323 return formatter<nsLiteralCString>::format( 324 mozilla::dom::GetEnumString(aNavigationType), aCtx); 325 } 326 }; 327 328 template <> 329 struct fmt::formatter<mozilla::dom::NavigationHistoryBehavior, char> 330 : public formatter<nsLiteralCString> { 331 template <typename FmtContext> 332 constexpr auto format( 333 const mozilla::dom::NavigationHistoryBehavior& aNavigationHistoryBehavior, 334 FmtContext& aCtx) const { 335 return formatter<nsLiteralCString>::format( 336 mozilla::dom::GetEnumString(aNavigationHistoryBehavior), aCtx); 337 } 338 }; 339 340 #endif // mozilla_dom_Navigation_h___