Backed out 4 changesets (bug 1948254) for causing build bustages @ NavigateEvent.h

Backed out changeset 14269121caf3 (bug 1948254)
Backed out changeset e327d067c6a0 (bug 1948254)
Backed out changeset d13b8e53fb78 (bug 1948254)
Backed out changeset 3c4be02a9115 (bug 1948254)
This commit is contained in:
Alexandru Marc
2025-03-14 21:42:35 +02:00
parent ee7ab56773
commit e4fca80d91
33 changed files with 126 additions and 1623 deletions

View File

@@ -607,15 +607,15 @@ bool WindowContext::HasValidHistoryActivation() const {
}
// https://html.spec.whatwg.org/multipage/interaction.html#consume-history-action-user-activation
void WindowContext::ConsumeHistoryActivation() {
bool WindowContext::ConsumeHistoryActivation() {
MOZ_ASSERT(IsInProcess());
if (!HasValidHistoryActivation()) {
return;
return false;
}
mHistoryActivation = mUserGestureStart;
return;
return true;
}
bool WindowContext::GetTransientUserGestureActivationModifiers(

View File

@@ -229,8 +229,9 @@ class WindowContext : public nsISupports, public nsWrapperCache {
// Return true if its corresponding window has history activation.
bool HasValidHistoryActivation() const;
// Consume the history-action user activation.
void ConsumeHistoryActivation();
// Return true if the corresponding window has valid history activation
// and the history activation had been consumed successfully.
bool ConsumeHistoryActivation();
bool GetTransientUserGestureActivationModifiers(
UserActivation::Modifiers* aModifiers);

View File

@@ -11353,20 +11353,6 @@ nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
} // end of same-origin check
// https://html.spec.whatwg.org/#shared-history-push/replace-state-steps
// Step 8
if (nsCOMPtr<nsPIDOMWindowInner> window = document->GetInnerWindow()) {
if (RefPtr<Navigation> navigation = window->Navigation();
navigation &&
navigation->FirePushReplaceReloadNavigateEvent(
aReplace ? NavigationType::Replace : NavigationType::Push, newURI,
/* aIsSameDocument */ true, /* aUserInvolvement */ Nothing(),
/* aSourceElement */ nullptr, /* aFormDataEntryList */ Nothing(),
/* aNavigationAPIState */ nullptr, scContainer)) {
return NS_OK;
}
}
// Step 8: call "URL and history update steps"
rv = UpdateURLAndHistory(document, newURI, scContainer,
aReplace ? NavigationHistoryBehavior::Replace

View File

@@ -106,7 +106,7 @@ interface nsIDocShell : nsIDocShellTreeItem
* Do either a history.pushState() or history.replaceState() operation,
* depending on the value of aReplace.
*/
[implicit_jscontext, can_run_script]
[implicit_jscontext]
void addState(in jsval aData, in AString aTitle,
in AString aURL, in boolean aReplace);

View File

@@ -365,7 +365,7 @@ nsresult FormData::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
return NS_OK;
}
already_AddRefed<FormData> FormData::Clone() const {
already_AddRefed<FormData> FormData::Clone() {
RefPtr<FormData> formData = new FormData(*this);
return formData.forget();
}

View File

@@ -56,7 +56,7 @@ class FormData final : public nsISupports,
NotNull<const Encoding*> aEncoding = UTF_8_ENCODING,
Element* aSubmitter = nullptr);
already_AddRefed<FormData> Clone() const;
already_AddRefed<FormData> Clone();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FormData)

View File

@@ -50,14 +50,10 @@ class nsHistory final : public nsISupports, public nsWrapperCache {
mozilla::ErrorResult& aRv);
void Back(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv);
void Forward(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
void PushState(JSContext* aCx, JS::Handle<JS::Value> aData,
const nsAString& aTitle, const nsAString& aUrl,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT
void ReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
const nsAString& aTitle, const nsAString& aUrl,
mozilla::dom::CallerType aCallerType,
@@ -66,7 +62,6 @@ class nsHistory final : public nsISupports, public nsWrapperCache {
protected:
virtual ~nsHistory();
MOZ_CAN_RUN_SCRIPT
void PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
const nsAString& aTitle, const nsAString& aUrl,
mozilla::dom::CallerType aCallerType,

View File

@@ -27,7 +27,6 @@
#include <type_traits>
#include "js/Value.h"
#include "mozilla/CycleCollectedUniquePtr.h"
#include "mozilla/RootedOwningNonNull.h"
#include "mozilla/RootedRefPtr.h"
@@ -88,6 +87,12 @@ inline std::enable_if_t<is_dom_dictionary<T>, void> ImplCycleCollectionTraverse(
aDictionary.TraverseForCC(aCallback, aFlags);
}
template <typename T>
inline std::enable_if_t<is_dom_dictionary<T>, void> ImplCycleCollectionUnlink(
UniquePtr<T>& aDictionary) {
aDictionary.reset();
}
template <typename T>
inline std::enable_if_t<is_dom_dictionary<T>, void> ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback, UniquePtr<T>& aDictionary,

View File

@@ -19267,15 +19267,6 @@ class CGBindingRoot(CGThing):
for d in dictionaries:
addPrefHeadersForDictionary(bindingHeaders, d)
try:
if CGDictionary.dictionaryNeedsCycleCollection(d):
bindingDeclareHeaders["nsCycleCollectionParticipant.h"] = True
except CycleCollectionUnsupported:
# We have some member that we don't know how to CC. Don't output
# our cycle collection overloads, so attempts to CC us will fail to
# compile instead of misbehaving.
pass
for d in descriptors:
interface = d.interface
addPrefHeaderForObject(bindingHeaders, interface)

View File

@@ -4,302 +4,16 @@
* 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/. */
#include "nsGlobalWindowInner.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/dom/AbortController.h"
#include "mozilla/dom/NavigateEvent.h"
#include "mozilla/dom/NavigateEventBinding.h"
#include "mozilla/dom/Navigation.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED_WITH_JS_MEMBERS(NavigateEvent, Event,
(mDestination, mSignal,
mFormData, mSourceElement,
mNavigationHandlerList,
mAbortController),
(mInfo))
NS_IMPL_ADDREF_INHERITED(NavigateEvent, Event)
NS_IMPL_RELEASE_INHERITED(NavigateEvent, Event)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NavigateEvent)
NS_INTERFACE_MAP_END_INHERITING(Event)
JSObject* NavigateEvent::WrapObjectInternal(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return NavigateEvent_Binding::Wrap(aCx, this, aGivenProto);
}
/* static */
already_AddRefed<NavigateEvent> NavigateEvent::Constructor(
const GlobalObject& aGlobal, const nsAString& aType,
const NavigateEventInit& aEventInitDict) {
nsCOMPtr<mozilla::dom::EventTarget> eventTarget =
do_QueryInterface(aGlobal.GetAsSupports());
return Constructor(eventTarget, aType, aEventInitDict);
return {};
}
/* static */
already_AddRefed<NavigateEvent> NavigateEvent::Constructor(
EventTarget* aEventTarget, const nsAString& aType,
const NavigateEventInit& aEventInitDict) {
RefPtr<NavigateEvent> event = new NavigateEvent(aEventTarget);
bool trusted = event->Init(aEventTarget);
event->InitEvent(
aType, aEventInitDict.mBubbles ? CanBubble::eYes : CanBubble::eNo,
aEventInitDict.mCancelable ? Cancelable::eYes : Cancelable::eNo,
aEventInitDict.mComposed ? Composed::eYes : Composed::eNo);
event->InitNavigateEvent(aEventInitDict);
event->SetTrusted(trusted);
return event.forget();
}
/* static */
already_AddRefed<NavigateEvent> NavigateEvent::Constructor(
EventTarget* aEventTarget, const nsAString& aType,
const NavigateEventInit& aEventInitDict,
nsIStructuredCloneContainer* aClassicHistoryAPIState,
AbortController* aAbortController) {
RefPtr<NavigateEvent> event =
Constructor(aEventTarget, aType, aEventInitDict);
event->mAbortController = aAbortController;
MOZ_DIAGNOSTIC_ASSERT(event->mSignal == aAbortController->Signal());
event->mClassicHistoryAPIState = aClassicHistoryAPIState;
return event.forget();
}
NavigationType NavigateEvent::NavigationType() const { return mNavigationType; }
already_AddRefed<NavigationDestination> NavigateEvent::Destination() const {
return do_AddRef(mDestination);
}
bool NavigateEvent::CanIntercept() const { return mCanIntercept; }
bool NavigateEvent::UserInitiated() const { return mUserInitiated; }
bool NavigateEvent::HashChange() const { return mHashChange; }
AbortSignal* NavigateEvent::Signal() const { return mSignal; }
already_AddRefed<FormData> NavigateEvent::GetFormData() const {
return do_AddRef(mFormData);
}
void NavigateEvent::GetDownloadRequest(nsAString& aDownloadRequest) const {
aDownloadRequest = mDownloadRequest;
}
void NavigateEvent::GetInfo(JSContext* aCx,
JS::MutableHandle<JS::Value> aInfo) const {
aInfo.set(mInfo);
}
bool NavigateEvent::HasUAVisualTransition() const {
return mHasUAVisualTransition;
}
Element* NavigateEvent::GetSourceElement() const { return mSourceElement; }
void NavigateEvent::Intercept(const NavigationInterceptOptions& aOptions,
ErrorResult& aRv) {
// This will be implemented in Bug 1897439.
}
void NavigateEvent::Scroll(ErrorResult& aRv) {
// This will be implemented in Bug 1897439.
}
NavigateEvent::NavigateEvent(EventTarget* aOwner)
: Event(aOwner, nullptr, nullptr) {
mozilla::HoldJSObjects(this);
}
NavigateEvent::~NavigateEvent() { DropJSObjects(this); }
void NavigateEvent::InitNavigateEvent(const NavigateEventInit& aEventInitDict) {
mNavigationType = aEventInitDict.mNavigationType;
mDestination = aEventInitDict.mDestination;
mCanIntercept = aEventInitDict.mCanIntercept;
mUserInitiated = aEventInitDict.mUserInitiated;
mHashChange = aEventInitDict.mHashChange;
mSignal = aEventInitDict.mSignal;
mFormData = aEventInitDict.mFormData;
mDownloadRequest = aEventInitDict.mDownloadRequest;
mInfo = aEventInitDict.mInfo;
mHasUAVisualTransition = aEventInitDict.mHasUAVisualTransition;
mSourceElement = aEventInitDict.mSourceElement;
}
void NavigateEvent::SetCanIntercept(bool aCanIntercept) {
mCanIntercept = aCanIntercept;
}
enum NavigateEvent::InterceptionState NavigateEvent::InterceptionState() const {
return mInterceptionState;
}
void NavigateEvent::SetInterceptionState(
enum InterceptionState aInterceptionState) {
mInterceptionState = aInterceptionState;
}
nsIStructuredCloneContainer* NavigateEvent::ClassicHistoryAPIState() const {
return mClassicHistoryAPIState;
}
nsTArray<RefPtr<NavigationInterceptHandler>>&
NavigateEvent::NavigationHandlerList() {
return mNavigationHandlerList;
}
// https://html.spec.whatwg.org/#navigateevent-finish
void NavigateEvent::Finish(bool aDidFulfill) {
switch (mInterceptionState) {
// Step 1
case InterceptionState::Intercepted:
case InterceptionState::Finished:
MOZ_DIAGNOSTIC_ASSERT(false);
break;
// Step 2
case InterceptionState::None:
return;
default:
break;
}
// Step 3
PotentiallyResetFocus();
// Step 4
if (aDidFulfill) {
PotentiallyProcessScrollBehavior();
}
// Step 5
mInterceptionState = InterceptionState::Finished;
}
// https://html.spec.whatwg.org/#potentially-reset-the-focus
void NavigateEvent::PotentiallyResetFocus() {
// Step 1
MOZ_DIAGNOSTIC_ASSERT(mInterceptionState == InterceptionState::Committed ||
mInterceptionState == InterceptionState::Scrolled);
// Step 2
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetParentObject());
// If we don't have a window here, there's not much we can do. This could
// potentially happen in a chrome context, and in the end it's just better to
// be sure and null check.
if (NS_WARN_IF(!window)) {
return;
}
Navigation* navigation = window->Navigation();
// Step 3
bool focusChanged = navigation->FocusedChangedDuringOngoingNavigation();
// Step 4
navigation->SetFocusedChangedDuringOngoingNavigation(false);
// Step 5
if (focusChanged) {
return;
}
// Step 6
if (mFocusResetBehavior &&
*mFocusResetBehavior == NavigationFocusReset::Manual) {
return;
}
// Step 7
Document* document = window->GetExtantDoc();
// If we don't have a document here, there's not much we can do.
if (NS_WARN_IF(!document)) {
return;
}
// Step 8
Element* focusTarget = document->GetDocumentElement();
if (focusTarget) {
focusTarget =
focusTarget->GetAutofocusDelegate(mozilla::IsFocusableFlags(0));
}
// Step 9
if (!focusTarget) {
focusTarget = document->GetBody();
}
// Step 10
if (!focusTarget) {
focusTarget = document->GetDocumentElement();
}
// The remaining steps will be implemented in Bug 1948253.
// Step 11: Run the focusing steps for focusTarget, with document's viewport
// as the fallback target.
// Step 12: Move the sequential focus navigation starting point to
// focusTarget.
}
// https://html.spec.whatwg.org/#potentially-process-scroll-behavior
void NavigateEvent::PotentiallyProcessScrollBehavior() {
// Step 1
MOZ_DIAGNOSTIC_ASSERT(mInterceptionState == InterceptionState::Committed ||
mInterceptionState == InterceptionState::Scrolled);
// Step 2
if (mInterceptionState == InterceptionState::Scrolled) {
return;
}
// Step 3
if (mScrollBehavior && *mScrollBehavior == NavigationScrollBehavior::Manual) {
return;
}
// Process 4
ProcessScrollBehavior();
}
// https://html.spec.whatwg.org/#process-scroll-behavior
void NavigateEvent::ProcessScrollBehavior() {
// Step 1
MOZ_DIAGNOSTIC_ASSERT(mInterceptionState == InterceptionState::Committed);
// Step 2
mInterceptionState = InterceptionState::Scrolled;
switch (mNavigationType) {
// Step 3
case NavigationType::Traverse:
case NavigationType::Reload:
// Restore scroll position data given event's relevant global object's
// navigable's active session history entry.
// The remaining steps will be implemented in Bug 1948249.
return;
default:
// Step 4
break;
}
// The remaining steps will be implemented in Bug 1948249.
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetParentObject());
// Step 4.1
/* Document* document = */ Unused << window->GetExtantDoc();
}
} // namespace mozilla::dom

View File

@@ -7,136 +7,56 @@
#ifndef mozilla_dom_NavigateEvent_h___
#define mozilla_dom_NavigateEvent_h___
#include "js/RootingAPI.h"
#include "js/Value.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/AbortController.h"
#include "js/TypeDecls.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/NavigateEventBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "mozilla/dom/NavigationBinding.h"
namespace mozilla::dom {
class AbortController;
class AbortSignal;
class FormData;
class NavigationDestination;
struct NavigationInterceptOptions;
enum class NavigationType : uint8_t;
// https://html.spec.whatwg.org/#the-navigateevent-interface
class NavigateEvent final : public Event {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(NavigateEvent, Event)
virtual JSObject* WrapObjectInternal(
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
NS_INLINE_DECL_REFCOUNTING_INHERITED(NavigateEvent, Event)
static already_AddRefed<NavigateEvent> Constructor(
const GlobalObject& aGlobal, const nsAString& aType,
const NavigateEventInit& aEventInitDict);
static already_AddRefed<NavigateEvent> Constructor(
EventTarget* aEventTarget, const nsAString& aType,
const NavigateEventInit& aEventInitDict);
enum NavigationType NavigationType() const { return {}; }
static already_AddRefed<NavigateEvent> Constructor(
EventTarget* aEventTarget, const nsAString& aType,
const NavigateEventInit& aEventInitDict,
nsIStructuredCloneContainer* aClassicHistoryAPIState,
AbortController* aAbortController);
already_AddRefed<NavigationDestination> Destination() const { return {}; }
NavigationType NavigationType() const;
bool CanIntercept() const { return {}; }
already_AddRefed<NavigationDestination> Destination() const;
bool UserInitiated() const { return {}; }
bool CanIntercept() const;
bool HashChange() const { return {}; }
bool UserInitiated() const;
already_AddRefed<AbortSignal> Signal() const { return {}; }
bool HashChange() const;
already_AddRefed<FormData> GetFormData() const { return {}; }
AbortSignal* Signal() const;
void GetDownloadRequest(nsString& aRetVal) const {}
already_AddRefed<FormData> GetFormData() const;
void GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aRetVal) const {}
void GetDownloadRequest(nsAString& aDownloadRequest) const;
bool HasUAVisualTransition() const { return {}; }
void GetInfo(JSContext* aCx, JS::MutableHandle<JS::Value> aInfo) const;
void Intercept(const NavigationInterceptOptions& aOptions, ErrorResult& aRv) {
}
bool HasUAVisualTransition() const;
void Scroll(ErrorResult& aRv) {}
Element* GetSourceElement() const;
void Intercept(const NavigationInterceptOptions& aOptions, ErrorResult& aRv);
void Scroll(ErrorResult& aRv);
void InitNavigateEvent(const NavigateEventInit& aEventInitDict);
void SetCanIntercept(bool aCanIntercept);
enum class InterceptionState : uint8_t {
None,
Intercepted,
Committed,
Scrolled,
Finished
};
InterceptionState InterceptionState() const;
void SetInterceptionState(enum InterceptionState aInterceptionState);
nsIStructuredCloneContainer* ClassicHistoryAPIState() const;
nsTArray<RefPtr<NavigationInterceptHandler>>& NavigationHandlerList();
void Finish(bool aDidFulfill);
bool IsTrusted() const { return {}; }
private:
void PotentiallyResetFocus();
void PotentiallyProcessScrollBehavior();
void ProcessScrollBehavior();
explicit NavigateEvent(EventTarget* aOwner);
~NavigateEvent();
enum NavigationType mNavigationType {};
RefPtr<NavigationDestination> mDestination;
bool mCanIntercept = false;
bool mUserInitiated = false;
bool mHashChange = false;
RefPtr<AbortSignal> mSignal;
RefPtr<FormData> mFormData;
nsString mDownloadRequest;
JS::Heap<JS::Value> mInfo;
bool mHasUAVisualTransition = false;
RefPtr<Element> mSourceElement;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-navigateevent-interface:navigateevent-2
enum InterceptionState mInterceptionState = InterceptionState::None;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-navigateevent-interface:navigateevent-3
nsTArray<RefPtr<NavigationInterceptHandler>> mNavigationHandlerList;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-navigateevent-interface:navigateevent-4
Maybe<NavigationFocusReset> mFocusResetBehavior;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-navigateevent-interface:navigateevent-5
Maybe<NavigationScrollBehavior> mScrollBehavior;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-navigateevent-interface:navigateevent-6
RefPtr<AbortController> mAbortController;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#the-navigateevent-interface:navigateevent-7
nsCOMPtr<nsIStructuredCloneContainer> mClassicHistoryAPIState;
~NavigateEvent() = default;
};
} // namespace mozilla::dom

View File

@@ -6,99 +6,38 @@
#include "mozilla/dom/Navigation.h"
#include "nsContentUtils.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDocShell.h"
#include "nsGlobalWindowInner.h"
#include "nsIStructuredCloneContainer.h"
#include "nsIXULRuntime.h"
#include "nsNetUtil.h"
#include "nsTHashtable.h"
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/CycleCollectedUniquePtr.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/Logging.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/FeaturePolicy.h"
#include "mozilla/dom/NavigationActivation.h"
#include "mozilla/dom/NavigationCurrentEntryChangeEvent.h"
#include "mozilla/dom/NavigationHistoryEntry.h"
#include "mozilla/dom/NavigationTransition.h"
#include "mozilla/dom/NavigationUtils.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "mozilla/dom/WindowContext.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/NavigationCurrentEntryChangeEvent.h"
#include "mozilla/dom/NavigationHistoryEntry.h"
#include "mozilla/dom/SessionHistoryEntry.h"
#include "nsContentUtils.h"
#include "nsIXULRuntime.h"
#include "nsNetUtil.h"
mozilla::LazyLogModule gNavigationLog("Navigation");
namespace mozilla::dom {
struct NavigationAPIMethodTracker {
RefPtr<Navigation> mNavigationObject;
Maybe<nsID> mKey;
JS::Heap<JS::Value> mInfo;
RefPtr<nsStructuredCloneContainer> mSerializedState;
RefPtr<NavigationHistoryEntry> mCommittedToEntry;
RefPtr<Promise> mFinishedPromise;
};
// This ignore is because the following ImplCycleCollectionTraverse and
// ImplCycleCollectionTrace are being called by the cycle collection machinery
// through a visitor pattern, that fools clangd a bit, since we're not directly
// calling them here but instead they get called from either the overloads for
// UniquePtr or nsTHashtable.
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-function"
#endif // __clang__
static void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& cb,
const NavigationAPIMethodTracker& aField, const char* aName,
uint32_t aFlags) {
const NavigationAPIMethodTracker* tmp = &aField;
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigationObject);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSerializedState);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommittedToEntry);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFinishedPromise);
}
static void ImplCycleCollectionTrace(const TraceCallbacks& aCallbacks,
NavigationAPIMethodTracker& aField,
const char* aName, void* aClosure) {
ImplCycleCollectionTrace(aCallbacks, aField.mInfo, aName, aClosure);
}
#ifdef __clang__
# pragma clang diagnostic pop
#endif // __clang__
NS_IMPL_CYCLE_COLLECTION_INHERITED_WITH_JS_MEMBERS(
Navigation, DOMEventTargetHelper,
(mEntries, mOngoingNavigateEvent, mTransition, mActivation,
mOngoingAPIMethodTracker, mUpcomingNonTraverseAPIMethodTracker,
mUpcomingTraverseAPIMethodTrackers),
(mOngoingAPIMethodTracker, mUpcomingNonTraverseAPIMethodTracker,
mUpcomingTraverseAPIMethodTrackers));
NS_IMPL_CYCLE_COLLECTION_INHERITED(Navigation, DOMEventTargetHelper, mEntries);
NS_IMPL_ADDREF_INHERITED(Navigation, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(Navigation, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Navigation)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
Navigation::Navigation(nsPIDOMWindowInner* aWindow)
: DOMEventTargetHelper(aWindow) {
Navigation::Navigation(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {
MOZ_ASSERT(aWindow);
mozilla::HoldJSObjects(this);
}
Navigation::~Navigation() { mozilla::DropJSObjects(this); }
JSObject* Navigation::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return Navigation_Binding::Wrap(aCx, this, aGivenProto);
@@ -133,7 +72,7 @@ already_AddRefed<NavigationHistoryEntry> Navigation::GetCurrentEntry() const {
return entry.forget();
}
// https://html.spec.whatwg.org/#dom-navigation-updatecurrententry
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigation-updatecurrententry
void Navigation::UpdateCurrentEntry(
JSContext* aCx, const NavigationUpdateCurrentEntryOptions& aOptions,
ErrorResult& aRv) {
@@ -164,20 +103,16 @@ void Navigation::UpdateCurrentEntry(
DispatchEvent(*event);
}
NavigationTransition* Navigation::GetTransition() const { return mTransition; }
NavigationActivation* Navigation::GetActivation() const { return mActivation; }
// https://html.spec.whatwg.org/#has-entries-and-events-disabled
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#has-entries-and-events-disabled
bool Navigation::HasEntriesAndEventsDisabled() const {
Document* doc = GetDocumentIfCurrent();
return !doc || !doc->IsCurrentActiveDocument() ||
Document* doc = mWindow->GetDoc();
return !doc->IsCurrentActiveDocument() ||
(NS_IsAboutBlankAllowQueryAndFragment(doc->GetDocumentURI()) &&
doc->IsInitialDocument()) ||
doc->GetPrincipal()->GetIsNullPrincipal();
}
// https://html.spec.whatwg.org/#initialize-the-navigation-api-entries-for-a-new-document
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#initialize-the-navigation-api-entries-for-a-new-document
void Navigation::InitializeHistoryEntries(
mozilla::Span<const SessionHistoryInfo> aNewSHInfos,
const SessionHistoryInfo* aInitialSHInfo) {
@@ -188,8 +123,8 @@ void Navigation::InitializeHistoryEntries(
}
for (auto i = 0ul; i < aNewSHInfos.Length(); i++) {
mEntries.AppendElement(MakeRefPtr<NavigationHistoryEntry>(
GetOwnerGlobal(), &aNewSHInfos[i], i));
mEntries.AppendElement(
MakeRefPtr<NavigationHistoryEntry>(mWindow, &aNewSHInfos[i], i));
if (aNewSHInfos[i].NavigationKey() == aInitialSHInfo->NavigationKey()) {
mCurrentEntryIndex = Some(i);
}
@@ -204,7 +139,7 @@ void Navigation::InitializeHistoryEntries(
("aInitialSHInfo: %s %s\n", key.ToString().get(), id.ToString().get()));
}
// https://html.spec.whatwg.org/#update-the-navigation-api-entries-for-a-same-document-navigation
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#update-the-navigation-api-entries-for-a-same-document-navigation
void Navigation::UpdateEntriesForSameDocumentNavigation(
SessionHistoryInfo* aDestinationSHE, NavigationType aNavigationType) {
// Step 1.
@@ -239,7 +174,7 @@ void Navigation::UpdateEntriesForSameDocumentNavigation(
disposedEntries.AppendElement(mEntries.PopLastElement());
}
mEntries.AppendElement(MakeRefPtr<NavigationHistoryEntry>(
GetOwnerGlobal(), aDestinationSHE, *mCurrentEntryIndex));
mWindow, aDestinationSHE, *mCurrentEntryIndex));
break;
case NavigationType::Replace:
@@ -247,7 +182,7 @@ void Navigation::UpdateEntriesForSameDocumentNavigation(
disposedEntries.AppendElement(oldCurrentEntry);
aDestinationSHE->NavigationKey() = oldCurrentEntry->Key();
mEntries[*mCurrentEntryIndex] = MakeRefPtr<NavigationHistoryEntry>(
GetOwnerGlobal(), aDestinationSHE, *mCurrentEntryIndex);
mWindow, aDestinationSHE, *mCurrentEntryIndex);
break;
case NavigationType::Reload:
@@ -259,7 +194,7 @@ void Navigation::UpdateEntriesForSameDocumentNavigation(
// Steps 9-12.
{
nsAutoMicroTask mt;
AutoEntryScript aes(GetOwnerGlobal(),
AutoEntryScript aes(mWindow->AsGlobal(),
"UpdateEntriesForSameDocumentNavigation");
ScheduleEventsFromNavigation(aNavigationType, oldCurrentEntry,
@@ -267,7 +202,7 @@ void Navigation::UpdateEntriesForSameDocumentNavigation(
}
}
// https://html.spec.whatwg.org/#update-the-navigation-api-entries-for-reactivation
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#update-the-navigation-api-entries-for-reactivation
void Navigation::UpdateForReactivation(SessionHistoryInfo* aReactivatedEntry) {
// NAV-TODO
}
@@ -324,526 +259,6 @@ void LogEntry(NavigationHistoryEntry* aEntry, uint64_t aIndex, uint64_t aTotal,
} // namespace
// https://html.spec.whatwg.org/#fire-a-traverse-navigate-event
bool Navigation::FireTraverseNavigateEvent(
SessionHistoryInfo* aDestinationSessionHistoryInfo,
Maybe<UserNavigationInvolvement> aUserInvolvement) {
// aDestinationSessionHistoryInfo corresponds to
// https://html.spec.whatwg.org/#fire-navigate-traverse-destinationshe
// To not unnecessarily create an event that's never used, step 1 and step 2
// in #fire-a-traverse-navigate-event have been moved to after step 25 in
// #inner-navigate-event-firing-algorithm in our implementation.
// Step 5
RefPtr<NavigationHistoryEntry> destinationNHE =
FindNavigationHistoryEntry(aDestinationSessionHistoryInfo);
// Step 6.2 and step 7.2
RefPtr<nsStructuredCloneContainer> state =
destinationNHE ? destinationNHE->GetNavigationState() : nullptr;
// Step 8
bool isSameDocument =
ToMaybeRef(
nsDocShell::Cast(nsContentUtils::GetDocShellForEventTarget(this)))
.andThen([](auto& aDocShell) {
return ToMaybeRef(aDocShell.GetLoadingSessionHistoryInfo());
})
.map([aDestinationSessionHistoryInfo](auto& aSessionHistoryInfo) {
return aDestinationSessionHistoryInfo->SharesDocumentWith(
aSessionHistoryInfo.mInfo);
})
.valueOr(false);
// Step 3, step 4, step 6.1, and step 7.1.
RefPtr<NavigationDestination> destination =
MakeAndAddRef<NavigationDestination>(
GetOwnerGlobal(), aDestinationSessionHistoryInfo->GetURI(),
destinationNHE, state, isSameDocument);
// Step 9
return InnerFireNavigateEvent(
NavigationType::Traverse, destination,
aUserInvolvement.valueOr(UserNavigationInvolvement::None),
/* aSourceElement */ nullptr,
/* aFormDataEntryList*/ Nothing(),
/* aClassicHistoryAPIState */ nullptr,
/* aDownloadRequestFilename */ u""_ns);
}
// https://html.spec.whatwg.org/#fire-a-push/replace/reload-navigate-event
bool Navigation::FirePushReplaceReloadNavigateEvent(
NavigationType aNavigationType, nsIURI* aDestinationURL,
bool aIsSameDocument, Maybe<UserNavigationInvolvement> aUserInvolvement,
Element* aSourceElement, Maybe<const FormData&> aFormDataEntryList,
nsStructuredCloneContainer* aNavigationAPIState,
nsIStructuredCloneContainer* aClassicHistoryAPIState) {
// To not unnecessarily create an event that's never used, step 1 and step 2
// in #fire-a-push/replace/reload-navigate-event have been moved to after step
// 25 in #inner-navigate-event-firing-algorithm in our implementation.
// Step 3 to step 7
RefPtr<NavigationDestination> destination =
MakeAndAddRef<NavigationDestination>(GetOwnerGlobal(), aDestinationURL,
/* aEntry */ nullptr,
/* aState */ nullptr,
aIsSameDocument);
// Step 8
return InnerFireNavigateEvent(
aNavigationType, destination,
aUserInvolvement.valueOr(UserNavigationInvolvement::None), aSourceElement,
aFormDataEntryList, aClassicHistoryAPIState,
/* aDownloadRequestFilename */ u""_ns);
}
// https://html.spec.whatwg.org/#fire-a-download-request-navigate-event
bool Navigation::FireDownloadRequestNavigateEvent(
nsIURI* aDestinationURL, UserNavigationInvolvement aUserInvolvement,
Element* aSourceElement, const nsAString& aFilename) {
// To not unnecessarily create an event that's never used, step 1 and step 2
// in #fire-a-download-request-navigate-event have been moved to after step
// 25 in #inner-navigate-event-firing-algorithm in our implementation.
// Step 3 to step 7
RefPtr<NavigationDestination> destination =
MakeAndAddRef<NavigationDestination>(GetOwnerGlobal(), aDestinationURL,
/* aEntry */ nullptr,
/* aState */ nullptr,
/* aIsSameDocument */ false);
// Step 8
return InnerFireNavigateEvent(
NavigationType::Push, destination, aUserInvolvement, aSourceElement,
/* aFormDataEntryList */ Nothing(),
/* aClassicHistoryAPIState */ nullptr, aFilename);
}
// Implementation of this will be done in Bug 1948596.
// https://html.spec.whatwg.org/#can-have-its-url-rewritten
static bool CanBeRewritten(nsIURI* aURI, nsIURI* aOtherURI) { return false; }
static bool HasHistoryActionActivation(
Maybe<nsGlobalWindowInner&> aRelevantGlobalObject) {
return aRelevantGlobalObject
.map([](auto& aRelevantGlobalObject) {
WindowContext* windowContext = aRelevantGlobalObject.GetWindowContext();
return windowContext && windowContext->HasValidHistoryActivation();
})
.valueOr(false);
}
static void ConsumeHistoryActionUserActivation(
Maybe<nsGlobalWindowInner&> aRelevantGlobalObject) {
aRelevantGlobalObject.apply([](auto& aRelevantGlobalObject) {
if (WindowContext* windowContext =
aRelevantGlobalObject.GetWindowContext()) {
windowContext->ConsumeHistoryActivation();
}
});
}
// Implementation of this will be done in Bug 1948593.
static bool HasUAVisualTransition(Maybe<Document&>) { return false; }
static bool EqualsExceptRef(nsIURI* aURI, nsIURI* aOtherURI) {
bool equalsExceptRef = false;
return aURI && aOtherURI &&
NS_SUCCEEDED(aURI->EqualsExceptRef(aOtherURI, &equalsExceptRef));
}
static bool HasIdenticalFragment(nsIURI* aURI, nsIURI* aOtherURI) {
nsAutoCString ref;
if (NS_FAILED(aURI->GetRef(ref))) {
return false;
}
nsAutoCString otherRef;
if (NS_FAILED(aOtherURI->GetRef(otherRef))) {
return false;
}
return ref.Equals(otherRef);
}
nsresult Navigation::FireEvent(const nsAString& aName) {
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
// it doesn't bubble, and it isn't cancelable
event->InitEvent(aName, false, false);
event->SetTrusted(true);
ErrorResult rv;
DispatchEvent(*event, rv);
return rv.StealNSResult();
}
// https://html.spec.whatwg.org/#inner-navigate-event-firing-algorithm
bool Navigation::InnerFireNavigateEvent(
NavigationType aNavigationType, NavigationDestination* aDestination,
UserNavigationInvolvement aUserInvolvement, Element* aSourceElement,
Maybe<const FormData&> aFormDataEntryList,
nsIStructuredCloneContainer* aClassicHistoryAPIState,
const nsAString& aDownloadRequestFilename) {
// Step 1
if (HasEntriesAndEventsDisabled()) {
// Step 1.1 to step 1.3
MOZ_DIAGNOSTIC_ASSERT(!mOngoingAPIMethodTracker);
MOZ_DIAGNOSTIC_ASSERT(!mUpcomingNonTraverseAPIMethodTracker);
MOZ_DIAGNOSTIC_ASSERT(mUpcomingTraverseAPIMethodTrackers.IsEmpty());
// Step 1.4
return true;
}
NavigateEventInit init;
// Step 2
Maybe<nsID> destinationKey;
// Step 3
if (auto* entry = aDestination->GetEntry()) {
destinationKey.emplace(entry->Key());
}
// Step 4
MOZ_DIAGNOSTIC_ASSERT(!destinationKey || destinationKey->Equals(nsID{}));
// Step 5
PromoteUpcomingAPIMethodTrackerToOngoing(std::move(destinationKey));
// Step 6
NavigationAPIMethodTracker* apiMethodTracker = mOngoingAPIMethodTracker.get();
// Step 7
Maybe<BrowsingContext&> navigable =
ToMaybeRef(GetOwnerWindow()).andThen([](auto& aWindow) {
return ToMaybeRef(aWindow.GetBrowsingContext());
});
// Step 8
Document* document =
navigable.map([](auto& aNavigable) { return aNavigable.GetDocument(); })
.valueOr(nullptr);
// Step 9
init.mCanIntercept =
document &&
CanBeRewritten(document->GetDocumentURI(), aDestination->GetURI()) &&
(aDestination->SameDocument() ||
aNavigationType != NavigationType::Traverse);
// Step 10 and step 11
init.mCancelable =
navigable->IsTop() && aDestination->SameDocument() &&
(aUserInvolvement != UserNavigationInvolvement::BrowserUI ||
HasHistoryActionActivation(ToMaybeRef(GetOwnerWindow())));
// Step 13
init.mNavigationType = aNavigationType;
// Step 14
init.mDestination = aDestination;
// Step 15
init.mDownloadRequest = aDownloadRequestFilename;
// Step 16
// init.mInfo = std::move(apiMethodTracker->mInfo);
// Step 17
init.mHasUAVisualTransition =
HasUAVisualTransition(ToMaybeRef(GetDocumentIfCurrent()));
// Step 18
init.mSourceElement = aSourceElement;
// Step 19
RefPtr<AbortController> abortController =
new AbortController(GetOwnerGlobal());
// Step 20
init.mSignal = abortController->Signal();
// step 21
nsCOMPtr<nsIURI> currentURL = document->GetDocumentURI();
// step 22
init.mHashChange = !aClassicHistoryAPIState && aDestination->SameDocument() &&
EqualsExceptRef(aDestination->GetURI(), currentURL) &&
!HasIdenticalFragment(aDestination->GetURI(), currentURL);
// Step 23
init.mUserInitiated = aUserInvolvement != UserNavigationInvolvement::None;
// Step 24
init.mFormData = aFormDataEntryList ? aFormDataEntryList->Clone() : nullptr;
// Step 25
MOZ_DIAGNOSTIC_ASSERT(!mOngoingNavigateEvent);
// We now have everything we need to fully initialize the NavigateEvent, so
// we'll go ahead and create it now. This is done by the spec in step 1 and
// step 2 of #fire-a-traverse-navigate-event,
// #fire-a-push/replace/reload-navigate-event, or
// #fire-a-download-request-navigate-event, but there's no reason to not
// delay it until here.
RefPtr<NavigateEvent> event = NavigateEvent::Constructor(
this, u"navigate"_ns, init, aClassicHistoryAPIState, abortController);
// Step 26
mOngoingNavigateEvent = event;
// Step 27
mFocusChangedDUringOngoingNavigation = false;
// Step 28
mSuppressNormalScrollRestorationDuringOngoingNavigation = false;
// Step 29 and step 30
if (!DispatchEvent(*event, CallerType::NonSystem, IgnoreErrors())) {
// Step 30.1
if (aNavigationType == NavigationType::Traverse) {
ConsumeHistoryActionUserActivation(ToMaybeRef(GetOwnerWindow()));
}
// Step 30.2
if (!abortController->Signal()->Aborted()) {
AbortOngoingNavigation();
}
// Step 30.3
return false;
}
using InterceptionState = enum NavigateEvent::InterceptionState;
// Step 31
bool endResultIsSameDocument =
event->InterceptionState() != InterceptionState::None ||
aDestination->SameDocument();
// Step 32 (and the destructor of this is step 36)
nsAutoMicroTask mt;
// Step 33
if (event->InterceptionState() != InterceptionState::None) {
// Step 33.1
event->SetInterceptionState(InterceptionState::Committed);
// Step 33.2
RefPtr<NavigationHistoryEntry> fromNHE = GetCurrentEntry();
// Step 33.3
MOZ_DIAGNOSTIC_ASSERT(fromNHE);
// Step 33.4
RefPtr<Promise> promise = Promise::CreateInfallible(GetOwnerGlobal());
mTransition = MakeAndAddRef<NavigationTransition>(
GetOwnerGlobal(), aNavigationType, fromNHE, promise);
// Step 33.5
MOZ_ALWAYS_TRUE(promise->SetAnyPromiseIsHandled());
switch (aNavigationType) {
case NavigationType::Traverse:
// Step 33.6
mSuppressNormalScrollRestorationDuringOngoingNavigation = true;
break;
case NavigationType::Push:
case NavigationType::Replace: {
// Step 33.7
nsDocShell* docShell = nsDocShell::Cast(document->GetDocShell());
docShell->UpdateURLAndHistory(
document, aDestination->GetURI(), event->ClassicHistoryAPIState(),
*NavigationUtils::NavigationHistoryBehavior(aNavigationType),
document->GetDocumentURI(), aDestination->SameDocument());
break;
}
default:
break;
}
}
// Step 34
if (endResultIsSameDocument) {
// Step 34.1
AutoTArray<RefPtr<Promise>, 16> promiseList;
// Step 34.2
for (auto& handler : event->NavigationHandlerList().Clone()) {
// Step 34.2.1
promiseList.AppendElement(MOZ_KnownLive(handler)->Call());
}
// Step 34.3
if (promiseList.IsEmpty()) {
promiseList.AppendElement(Promise::CreateResolvedWithUndefined(
GetOwnerGlobal(), IgnoredErrorResult()));
}
// Step 34.4
Promise::WaitForAll(
GetOwnerGlobal(), promiseList,
[self = RefPtr(this), event,
apiMethodTracker](const Span<JS::Heap<JS::Value>>&) {
// Success steps
// Step 1
if (nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(event->GetParentObject());
window && !window->IsFullyActive()) {
return;
}
// Step 2
if (AbortSignal* signal = event->Signal(); signal->Aborted()) {
return;
}
// Step 3
MOZ_DIAGNOSTIC_ASSERT(event == self->mOngoingNavigateEvent);
// Step 4
self->mOngoingNavigateEvent = nullptr;
// Step 5
event->Finish(true);
// Step 6
self->FireEvent(u"navigatesuccess"_ns);
// Step 7
if (apiMethodTracker) {
apiMethodTracker->mFinishedPromise->MaybeResolveWithUndefined();
}
// Step 8
if (self->mTransition) {
self->mTransition->Finished()->MaybeResolveWithUndefined();
}
self->mTransition = nullptr;
},
[self = RefPtr(this), event,
apiMethodTracker](JS::Handle<JS::Value> aRejectionReason) {
// Failure steps
// Step 1
if (nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(event->GetParentObject());
window && !window->IsFullyActive()) {
return;
}
// Step 2
if (AbortSignal* signal = event->Signal(); signal->Aborted()) {
return;
}
// Step 3
MOZ_DIAGNOSTIC_ASSERT(event == self->mOngoingNavigateEvent);
// Step 4
self->mOngoingNavigateEvent = nullptr;
// Step 5
event->Finish(false);
// Step 6 and step 7 will be implemented in Bug 1949499.
// Step 6: Let errorInfo be the result of extracting error
// information from rejectionReason.
// Step 7: Fire an event named navigateerror at navigation using
// ErrorEvent, with additional attributes initialized according to
// errorInfo.
// Step 8
if (apiMethodTracker) {
apiMethodTracker->mFinishedPromise->MaybeReject(aRejectionReason);
}
// Step 9
if (self->mTransition) {
self->mTransition->Finished()->MaybeReject(aRejectionReason);
}
self->mTransition = nullptr;
});
}
// Step 35
if (apiMethodTracker) {
CleanUp(apiMethodTracker);
}
// Step 37 and step 38
return event->InterceptionState() == InterceptionState::None;
}
NavigationHistoryEntry* Navigation::FindNavigationHistoryEntry(
SessionHistoryInfo* aSessionHistoryInfo) const {
for (const auto& navigationHistoryEntry : mEntries) {
if (navigationHistoryEntry->IsSameEntry(aSessionHistoryInfo)) {
return navigationHistoryEntry;
}
}
return nullptr;
}
// https://html.spec.whatwg.org/#promote-an-upcoming-api-method-tracker-to-ongoing
void Navigation::PromoteUpcomingAPIMethodTrackerToOngoing(
Maybe<nsID>&& aDestinationKey) {
MOZ_DIAGNOSTIC_ASSERT(!mOngoingAPIMethodTracker);
if (aDestinationKey) {
MOZ_DIAGNOSTIC_ASSERT(!mUpcomingNonTraverseAPIMethodTracker);
Maybe<NavigationAPIMethodTracker&> tracker(NavigationAPIMethodTracker);
if (auto entry =
mUpcomingTraverseAPIMethodTrackers.Extract(*aDestinationKey)) {
mOngoingAPIMethodTracker = std::move(*entry);
}
return;
}
mOngoingAPIMethodTracker = std::move(mUpcomingNonTraverseAPIMethodTracker);
}
// https://html.spec.whatwg.org/#navigation-api-method-tracker-clean-up
/* static */ void Navigation::CleanUp(
NavigationAPIMethodTracker* aNavigationAPIMethodTracker) {
// Step 1
RefPtr<Navigation> navigation =
aNavigationAPIMethodTracker->mNavigationObject;
// Step 2
if (navigation->mOngoingAPIMethodTracker == aNavigationAPIMethodTracker) {
navigation->mOngoingAPIMethodTracker = nullptr;
return;
}
// Step 3.1
Maybe<nsID> key = aNavigationAPIMethodTracker->mKey;
// Step 3.2
MOZ_DIAGNOSTIC_ASSERT(key);
// Step 3.3
MOZ_DIAGNOSTIC_ASSERT(
navigation->mUpcomingTraverseAPIMethodTrackers.Contains(*key));
navigation->mUpcomingTraverseAPIMethodTrackers.Remove(*key);
}
// https://html.spec.whatwg.org/#abort-the-ongoing-navigation
void Navigation::AbortOngoingNavigation() {}
bool Navigation::FocusedChangedDuringOngoingNavigation() const {
return mFocusChangedDUringOngoingNavigation;
}
void Navigation::SetFocusedChangedDuringOngoingNavigation(
bool aFocusChangedDUringOngoingNavigation) {
mFocusChangedDUringOngoingNavigation = aFocusChangedDUringOngoingNavigation;
}
void Navigation::LogHistory() const {
if (!MOZ_LOG_TEST(gNavigationLog, LogLevel::Debug)) {
return;

View File

@@ -7,25 +7,12 @@
#ifndef mozilla_dom_Navigation_h___
#define mozilla_dom_Navigation_h___
#include "nsHashtablesFwd.h"
#include "nsStringFwd.h"
#include "nsStructuredCloneContainer.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "mozilla/dom/NavigateEvent.h"
#include "mozilla/dom/NavigationBinding.h"
class nsIDHashKey;
namespace mozilla::dom {
class FormData;
class NavigationActivation;
class NavigationDestination;
class NavigationHistoryEntry;
struct NavigationNavigateOptions;
struct NavigationOptions;
@@ -36,13 +23,10 @@ struct NavigationResult;
class SessionHistoryInfo;
struct NavigationAPIMethodTracker;
class Navigation final : public DOMEventTargetHelper {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Navigation,
DOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Navigation, DOMEventTargetHelper)
explicit Navigation(nsPIDOMWindowInner* aWindow);
@@ -53,8 +37,8 @@ class Navigation final : public DOMEventTargetHelper {
void UpdateCurrentEntry(JSContext* aCx,
const NavigationUpdateCurrentEntryOptions& aOptions,
ErrorResult& aRv);
NavigationTransition* GetTransition() const;
NavigationActivation* GetActivation() const;
already_AddRefed<NavigationTransition> GetTransition() { return {}; }
already_AddRefed<NavigationActivation> GetActivation() { return {}; }
bool CanGoBack() {
return !HasEntriesAndEventsDisabled() && mCurrentEntryIndex &&
@@ -105,33 +89,8 @@ class Navigation final : public DOMEventTargetHelper {
static bool IsAPIEnabled(JSContext* /* unused */ = nullptr,
JSObject* /* unused */ = nullptr);
// Wrapper algorithms for firing the navigate event.
// https://html.spec.whatwg.org/#navigate-event-firing
MOZ_CAN_RUN_SCRIPT bool FireTraverseNavigateEvent(
SessionHistoryInfo* aDestinationSessionHistoryInfo,
Maybe<UserNavigationInvolvement> aUserInvolvement);
MOZ_CAN_RUN_SCRIPT bool FirePushReplaceReloadNavigateEvent(
NavigationType aNavigationType, nsIURI* aDestinationURL,
bool aIsSameDocument, Maybe<UserNavigationInvolvement> aUserInvolvement,
Element* aSourceElement, Maybe<const FormData&> aFormDataEntryList,
nsStructuredCloneContainer* aNavigationAPIState,
nsIStructuredCloneContainer* aClassicHistoryAPIState);
MOZ_CAN_RUN_SCRIPT bool FireDownloadRequestNavigateEvent(
nsIURI* aDestinationURL, UserNavigationInvolvement aUserInvolvement,
Element* aSourceElement, const nsAString& aFilename);
bool FocusedChangedDuringOngoingNavigation() const;
void SetFocusedChangedDuringOngoingNavigation(
bool aFocusChangedDUringOngoingNavigation);
private:
using UpcomingTraverseAPIMethodTrackers =
nsTHashMap<nsIDHashKey, UniquePtr<NavigationAPIMethodTracker>>;
~Navigation();
~Navigation() = default;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#has-entries-and-events-disabled
bool HasEntriesAndEventsDisabled() const;
@@ -141,56 +100,13 @@ class Navigation final : public DOMEventTargetHelper {
const RefPtr<NavigationHistoryEntry>& aPreviousEntry,
nsTArray<RefPtr<NavigationHistoryEntry>>&& aDisposedEntries);
nsresult FireEvent(const nsAString& aName);
// https://html.spec.whatwg.org/#inner-navigate-event-firing-algorithm
MOZ_CAN_RUN_SCRIPT bool InnerFireNavigateEvent(
NavigationType aNavigationType, NavigationDestination* aDestination,
UserNavigationInvolvement aUserInvolvement, Element* aSourceElement,
Maybe<const FormData&> aFormDataEntryList,
nsIStructuredCloneContainer* aClassicHistoryAPIState,
const nsAString& aDownloadRequestFilename);
NavigationHistoryEntry* FindNavigationHistoryEntry(
SessionHistoryInfo* aSessionHistoryInfo) const;
void PromoteUpcomingAPIMethodTrackerToOngoing(Maybe<nsID>&& aDestinationKey);
static void CleanUp(NavigationAPIMethodTracker* aNavigationAPIMethodTracker);
void AbortOngoingNavigation();
void LogHistory() const;
nsCOMPtr<nsPIDOMWindowInner> mWindow;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-entry-list
nsTArray<RefPtr<NavigationHistoryEntry>> mEntries;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-current-entry
Maybe<uint64_t> mCurrentEntryIndex;
// https://html.spec.whatwg.org/#ongoing-navigation-tracking:navigateevent-2
RefPtr<NavigateEvent> mOngoingNavigateEvent;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#focus-changed-during-ongoing-navigation
bool mFocusChangedDUringOngoingNavigation = false;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#suppress-normal-scroll-restoration-during-ongoing-navigation
bool mSuppressNormalScrollRestorationDuringOngoingNavigation = false;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#ongoing-api-method-tracker
UniquePtr<NavigationAPIMethodTracker> mOngoingAPIMethodTracker;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#upcoming-non-traverse-api-method-tracker
UniquePtr<NavigationAPIMethodTracker> mUpcomingNonTraverseAPIMethodTracker;
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#upcoming-traverse-api-method-trackers
UpcomingTraverseAPIMethodTrackers mUpcomingTraverseAPIMethodTrackers;
// https://html.spec.whatwg.org/#concept-navigation-transition
RefPtr<NavigationTransition> mTransition;
// https://html.spec.whatwg.org/#navigation-activation
RefPtr<NavigationActivation> mActivation;
};
} // namespace mozilla::dom

View File

@@ -7,7 +7,6 @@
#ifndef mozilla_dom_NavigationActivation_h___
#define mozilla_dom_NavigationActivation_h___
#include "nsISupports.h"
#include "nsWrapperCache.h"
class nsIGlobalObject;

View File

@@ -104,10 +104,4 @@ JSObject* NavigationDestination::WrapObject(JSContext* aCx,
nsIGlobalObject* NavigationDestination::GetParentObject() { return mGlobal; }
NavigationHistoryEntry* NavigationDestination::GetEntry() const {
return mEntry;
}
nsIURI* NavigationDestination::GetURI() const { return mURL; }
} // namespace mozilla::dom

View File

@@ -48,9 +48,6 @@ class NavigationDestination final : public nsISupports, public nsWrapperCache {
JS::Handle<JSObject*> aGivenProto) override;
nsIGlobalObject* GetParentObject();
NavigationHistoryEntry* GetEntry() const;
nsIURI* GetURI() const;
private:
~NavigationDestination() = default;

View File

@@ -15,8 +15,8 @@ extern mozilla::LazyLogModule gNavigationLog;
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_INHERITED(NavigationHistoryEntry,
DOMEventTargetHelper);
NS_IMPL_CYCLE_COLLECTION_INHERITED(NavigationHistoryEntry, DOMEventTargetHelper,
mWindow);
NS_IMPL_ADDREF_INHERITED(NavigationHistoryEntry, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(NavigationHistoryEntry, DOMEventTargetHelper)
@@ -24,22 +24,19 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(NavigationHistoryEntry)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NavigationHistoryEntry::NavigationHistoryEntry(
nsIGlobalObject* aGlobal, const SessionHistoryInfo* aSHInfo, int64_t aIndex)
: DOMEventTargetHelper(aGlobal),
nsPIDOMWindowInner* aWindow, const SessionHistoryInfo* aSHInfo,
int64_t aIndex)
: mWindow(aWindow),
mSHInfo(MakeUnique<SessionHistoryInfo>(*aSHInfo)),
mIndex(aIndex) {}
NavigationHistoryEntry::~NavigationHistoryEntry() = default;
// https://html.spec.whatwg.org/#dom-navigationhistoryentry-url
void NavigationHistoryEntry::GetUrl(nsAString& aResult) const {
if (!HasActiveDocument()) {
if (!GetCurrentDocument()->IsCurrentActiveDocument()) {
return;
}
// HasActiveDocument implies that GetCurrentDocument returns non-null.
MOZ_DIAGNOSTIC_ASSERT(GetCurrentDocument());
if (!SameDocument()) {
auto referrerPolicy = GetCurrentDocument()->ReferrerPolicy();
if (referrerPolicy == ReferrerPolicy::No_referrer ||
@@ -56,9 +53,8 @@ void NavigationHistoryEntry::GetUrl(nsAString& aResult) const {
CopyUTF8toUTF16(uriSpec, aResult);
}
// https://html.spec.whatwg.org/#dom-navigationhistoryentry-key
void NavigationHistoryEntry::GetKey(nsAString& aResult) const {
if (!HasActiveDocument()) {
if (!GetCurrentDocument()->IsCurrentActiveDocument()) {
return;
}
@@ -67,9 +63,8 @@ void NavigationHistoryEntry::GetKey(nsAString& aResult) const {
CopyUTF8toUTF16(Substring(keyString.get() + 1, NSID_LENGTH - 3), aResult);
}
// https://html.spec.whatwg.org/#dom-navigationhistoryentry-id
void NavigationHistoryEntry::GetId(nsAString& aResult) const {
if (!HasActiveDocument()) {
if (!GetCurrentDocument()->IsCurrentActiveDocument()) {
return;
}
@@ -78,30 +73,20 @@ void NavigationHistoryEntry::GetId(nsAString& aResult) const {
CopyUTF8toUTF16(Substring(idString.get() + 1, NSID_LENGTH - 3), aResult);
}
// https://html.spec.whatwg.org/#dom-navigationhistoryentry-index
int64_t NavigationHistoryEntry::Index() const {
MOZ_ASSERT(mSHInfo);
if (!HasActiveDocument()) {
if (!GetCurrentDocument()->IsCurrentActiveDocument()) {
return -1;
}
return mIndex;
}
// https://html.spec.whatwg.org/#dom-navigationhistoryentry-samedocument
bool NavigationHistoryEntry::SameDocument() const {
if (!HasActiveDocument()) {
return false;
}
// HasActiveDocument implies that GetCurrentDocument returns non-null.
MOZ_DIAGNOSTIC_ASSERT(GetCurrentDocument());
MOZ_ASSERT(mSHInfo);
auto* docShell = nsDocShell::Cast(GetCurrentDocument()->GetDocShell());
return docShell && docShell->IsSameDocumentAsActiveEntry(*mSHInfo);
auto* docShell = static_cast<nsDocShell*>(mWindow->GetDocShell());
return docShell->IsSameDocumentAsActiveEntry(*mSHInfo);
}
// https://html.spec.whatwg.org/#dom-navigationhistoryentry-getstate
void NavigationHistoryEntry::GetState(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult,
ErrorResult& aRv) const {
@@ -122,10 +107,8 @@ void NavigationHistoryEntry::GetState(JSContext* aCx,
}
void NavigationHistoryEntry::SetState(nsStructuredCloneContainer* aState) {
if (RefPtr<nsStructuredCloneContainer> state =
mSHInfo->GetNavigationState()) {
state->Copy(*aState);
}
RefPtr<nsStructuredCloneContainer> state = mSHInfo->GetNavigationState();
state->Copy(*aState);
}
bool NavigationHistoryEntry::IsSameEntry(
@@ -144,27 +127,11 @@ JSObject* NavigationHistoryEntry::WrapObject(
}
Document* NavigationHistoryEntry::GetCurrentDocument() const {
return GetDocumentIfCurrent();
}
bool NavigationHistoryEntry::HasActiveDocument() const {
if (auto* document = GetCurrentDocument()) {
return document->IsCurrentActiveDocument();
}
return false;
return mWindow->GetDoc();
}
const nsID& NavigationHistoryEntry::Key() const {
return mSHInfo->NavigationKey();
}
nsStructuredCloneContainer* NavigationHistoryEntry::GetNavigationState() const {
if (!mSHInfo) {
return nullptr;
}
return mSHInfo->GetNavigationState();
}
} // namespace mozilla::dom

View File

@@ -9,21 +9,19 @@
#include "mozilla/DOMEventTargetHelper.h"
class nsIGlobalObject;
class nsStructuredCloneContainer;
namespace mozilla::dom {
class SessionHistoryInfo;
// https://html.spec.whatwg.org/#navigationhistoryentry
class NavigationHistoryEntry final : public DOMEventTargetHelper {
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(NavigationHistoryEntry,
DOMEventTargetHelper)
NavigationHistoryEntry(nsIGlobalObject* aGlobal,
NavigationHistoryEntry(nsPIDOMWindowInner* aWindow,
const SessionHistoryInfo* aSHInfo, int64_t aIndex);
void GetUrl(nsAString& aResult) const;
@@ -47,16 +45,12 @@ class NavigationHistoryEntry final : public DOMEventTargetHelper {
const nsID& Key() const;
nsStructuredCloneContainer* GetNavigationState() const;
private:
~NavigationHistoryEntry();
Document* GetCurrentDocument() const;
bool HasActiveDocument() const;
// https://html.spec.whatwg.org/#nhe-she
nsCOMPtr<nsPIDOMWindowInner> mWindow;
UniquePtr<SessionHistoryInfo> mSHInfo;
int64_t mIndex;
};

View File

@@ -1,25 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 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/. */
#include "mozilla/dom/NavigationBinding.h"
#include "mozilla/dom/NavigationUtils.h"
namespace mozilla::dom {
/* static */ Maybe<NavigationHistoryBehavior>
NavigationUtils::NavigationHistoryBehavior(NavigationType aNavigationType) {
switch (aNavigationType) {
case NavigationType::Push:
return Some(NavigationHistoryBehavior::Push);
case NavigationType::Replace:
return Some(NavigationHistoryBehavior::Replace);
default:
break;
}
return Nothing();
}
} // namespace mozilla::dom

View File

@@ -1,24 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 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_NavigationUtils_h___
#define mozilla_dom_NavigationUtils_h___
#include "mozilla/Maybe.h"
namespace mozilla::dom {
enum class NavigationType : uint8_t;
enum class NavigationHistoryBehavior : uint8_t;
class NavigationUtils {
public:
static Maybe<NavigationHistoryBehavior> NavigationHistoryBehavior(
NavigationType aNavigationType);
};
} // namespace mozilla::dom
#endif // mozilla_dom_NavigationUtils_h___

View File

@@ -13,7 +13,6 @@ EXPORTS.mozilla.dom += [
"NavigationDestination.h",
"NavigationHistoryEntry.h",
"NavigationTransition.h",
"NavigationUtils.h",
"UserNavigationInvolvement.h",
]
@@ -23,7 +22,6 @@ UNIFIED_SOURCES += [
"NavigationDestination.cpp",
"NavigationHistoryEntry.cpp",
"NavigationTransition.cpp",
"NavigationUtils.cpp",
]
FINAL_LIBRARY = "xul"

View File

@@ -42,7 +42,6 @@
#include "nsDebug.h"
#include "nsGlobalWindowInner.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsISupportsImpl.h"
#include "nsJSEnvironment.h"
#include "nsJSPrincipals.h"
#include "nsJSUtils.h"
@@ -219,119 +218,6 @@ already_AddRefed<Promise> Promise::All(
return CreateFromExisting(global, result, aPropagateUserInteraction);
}
struct WaitForAllEmptyTask : public MicroTaskRunnable {
WaitForAllEmptyTask(
nsIGlobalObject* aGlobal,
const std::function<void(const Span<JS::Heap<JS::Value>>&)>& aCallback)
: mGlobal(aGlobal), mCallback(aCallback) {}
private:
virtual void Run(AutoSlowOperation&) override { mCallback({}); }
virtual bool Suppressed() override { return mGlobal->IsInSyncOperation(); }
nsCOMPtr<nsIGlobalObject> mGlobal;
const std::function<void(const Span<JS::Heap<JS::Value>>&)> mCallback;
};
// Initializing WaitForAllResults also performs step 1 and step 2 of
// #wait-for-all.
struct WaitForAllResults {
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WaitForAllResults)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WaitForAllResults)
explicit WaitForAllResults(size_t aSize) : mResult(aSize) {
HoldJSObjects(this);
mResult.EnsureLengthAtLeast(aSize);
}
// Step 1
size_t mFullfilledCount = 0;
// Step 2
bool mRejected = false;
nsTArray<JS::Heap<JS::Value>> mResult;
private:
~WaitForAllResults() { DropJSObjects(this); };
};
NS_IMPL_CYCLE_COLLECTION_WITH_JS_MEMBERS(WaitForAllResults, (), (mResult))
// https://webidl.spec.whatwg.org/#wait-for-all
/* static */
void Promise::WaitForAll(
nsIGlobalObject* aGlobal, const Span<RefPtr<Promise>>& aPromises,
const std::function<void(const Span<JS::Heap<JS::Value>>&)>& aSuccessSteps,
const std::function<void(JS::Handle<JS::Value>)>& aFailureSteps) {
// Step 1 and step 2 are in WaitForAllResults.
// Step 3
const auto& rejectionHandlerSteps =
[aFailureSteps](JSContext* aCx, JS::Handle<JS::Value> aArg,
ErrorResult& aRv,
const RefPtr<WaitForAllResults>& aResult) {
// Step 3.1
if (aResult->mRejected) {
return nullptr;
}
// Step 3.2
aResult->mRejected = true;
// Step 3.3
aFailureSteps(aArg);
return nullptr;
};
// Step 5
const size_t total = aPromises.size();
// Step 6
if (!total) {
CycleCollectedJSContext* context = CycleCollectedJSContext::Get();
if (context) {
RefPtr<MicroTaskRunnable> microTask =
new WaitForAllEmptyTask(aGlobal, aSuccessSteps);
// Step 6.1
context->DispatchToMicroTask(microTask.forget());
}
// Step 6.2
return;
}
// Step 7
size_t index = 0;
// Step 8
// Since we'll be passing an nsTArray to several invocations to
// fulfillmentHandlerSteps we wrap it into a cycle collecting and tracing
// object.
RefPtr result = MakeAndAddRef<WaitForAllResults>(total);
// Step 9
for (const auto& promise : aPromises) {
// Step 9.1 and step 9.2
const auto& fulfillmentHandlerSteps =
[aSuccessSteps, promiseIndex = index](
JSContext* aCx, JS::Handle<JS::Value> aArg, ErrorResult& aRv,
const RefPtr<WaitForAllResults>& aResult)
-> already_AddRefed<Promise> {
// Step 9.2.1
aResult->mResult[promiseIndex].set(aArg.get());
// Step 9.2.2
aResult->mFullfilledCount++;
// Step 9.2.3.
// aResult->mResult.Length() is by definition equals to total.
if (aResult->mFullfilledCount == aResult->mResult.Length()) {
aSuccessSteps(aResult->mResult);
}
return nullptr;
};
// Step 9.4 (and actually also step 4 and step 9.3)
(void)promise->ThenCatchWithCycleCollectedArgs(
fulfillmentHandlerSteps, rejectionHandlerSteps, result);
// Step 9.5
index++;
}
}
static void SettlePromise(Promise* aSettlingPromise, Promise* aCallbackPromise,
ErrorResult& aRv) {
if (!aSettlingPromise) {
@@ -504,11 +390,11 @@ namespace {
class PromiseNativeHandlerShim final : public PromiseNativeHandler {
RefPtr<PromiseNativeHandler> mInner;
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
enum InnerState {
NotCleared,
ClearedFromResolve,
ClearedFromReject,
ClearedFromCC,
enum InnerState{
NotCleared,
ClearedFromResolve,
ClearedFromReject,
ClearedFromCC,
};
InnerState mState = NotCleared;
#endif

View File

@@ -261,12 +261,6 @@ class Promise : public SupportsWeakPtr {
PropagateUserInteraction aPropagateUserInteraction =
eDontPropagateUserInteraction);
static void WaitForAll(
nsIGlobalObject* aGlobal, const Span<RefPtr<Promise>>& aPromises,
const std::function<void(const Span<JS::Heap<JS::Value>>&)>&
aSuccessSteps,
const std::function<void(JS::Handle<JS::Value>)>& aFailureSteps);
template <typename Callback, typename... Args>
using IsHandlerCallback =
std::is_same<already_AddRefed<Promise>,

View File

@@ -21,7 +21,6 @@ interface NavigateEvent : Event {
readonly attribute DOMString? downloadRequest;
readonly attribute any info;
readonly attribute boolean hasUAVisualTransition;
readonly attribute Element? sourceElement;
[Throws] undefined intercept(optional NavigationInterceptOptions options = {});
[Throws] undefined scroll();
@@ -38,7 +37,6 @@ dictionary NavigateEventInit : EventInit {
DOMString? downloadRequest = null;
any info;
boolean hasUAVisualTransition = false;
Element? sourceElement = null;
};
dictionary NavigationInterceptOptions {

View File

@@ -65,7 +65,6 @@ EXPORTS += [
"nsCOMPtr.h",
"nscore.h",
"nsCRTGlue.h",
"nsCycleCollectionContainerParticipant.h",
"nsCycleCollectionNoteChild.h",
"nsCycleCollectionNoteRootCallback.h",
"nsCycleCollectionParticipant.h",

View File

@@ -1,60 +0,0 @@
/* -*- 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 nsCycleCollectionContainerParticipant_h__
#define nsCycleCollectionContainerParticipant_h__
#include <type_traits>
/*
* To be able to implement ImplCycleCollectionIndexedContainer, we need to
* handle const vs non-const. ImplCycleCollectionTrace requires that the the
* value traced is non-const, and historically ImplCycleCollectionTraverse has
* been declared to take either const or non-const values. This poses a problem
* for containers, since it's not possible to define one
* ImplCycleCollectionIndexedContainer for both the const and non-const case
* with a templated parameter for the type contained by the container. The
* reason for this is how overload resolution works when it sees non-generic
* types with different constness. The standard solution for this is to use a
* universal reference, but we can't do this only because suddenly our
* ImplCycleCollectionIndexedContainer would be valid for any type. To make this
* work we need a way to constrain the type and we need it to be a constraint on
* the container type, not the type contained.
*
* This is pretty much the proposal for std::is_specialization_of, but with
* names from the unofficial cycle collector namespace. We use this to be able
* to do partial specialization to overload containers whose contents we wish to
* have participate in cycle collection. `template <typename Container>
* EnableCycleCollectionIf<Container, SomeContainer>` allows us to restrict an
* overload to only happen for a type SomeContainer<T>, which we then can use to
* make sure that an ImplCycleCollectionIndexedContainer overload is for a
* particular container, const or not.
*
* Example:
*
* template <typename Container, typename Callback,
* EnableCycleCollectionIf<Container, nsTHashtable> = nullptr>
* inline void ImplCycleCollectionContainer(Container&& aField,
* Callback&& aCallback) {
* // Implementation goes here
* }
*/
template <typename, template <typename...> typename>
struct ImplCycleCollectionIsContainerT : std::false_type {};
template <template <typename...> typename Container, typename... Args>
struct ImplCycleCollectionIsContainerT<Container<Args...>, Container>
: std::true_type {};
template <typename T, template <typename...> typename Container>
constexpr bool ImplCycleCollectionIsContainer = ImplCycleCollectionIsContainerT<
std::remove_cv_t<std::remove_reference_t<T>>, Container>::value;
template <typename T, template <typename...> typename Container>
using EnableCycleCollectionIf =
typename std::enable_if_t<ImplCycleCollectionIsContainer<T, Container>>*;
#endif // nsCycleCollectionContainerParticipant_h__

View File

@@ -21,8 +21,12 @@
* is a hack and is intentional in order to speed up the comparison inside
* NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED.
*/
#define NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID \
{0xc61eac14, 0x5f7a, 0x4481, {0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5e}}
#define NS_XPCOMCYCLECOLLECTIONPARTICIPANT_IID \
{ \
0xc61eac14, 0x5f7a, 0x4481, { \
0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5e \
} \
}
/**
* Special IID to get at the base nsISupports for a class. Usually this is the
@@ -31,8 +35,12 @@
* to have separate nsCycleCollectionParticipant's for tearoffs or aggregated
* classes.
*/
#define NS_CYCLECOLLECTIONISUPPORTS_IID \
{0xc61eac14, 0x5f7a, 0x4481, {0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5f}}
#define NS_CYCLECOLLECTIONISUPPORTS_IID \
{ \
0xc61eac14, 0x5f7a, 0x4481, { \
0x96, 0x5e, 0x7e, 0xaa, 0x6e, 0xff, 0xa8, 0x5f \
} \
}
namespace mozilla {
enum class CCReason : uint8_t {
@@ -190,109 +198,6 @@ struct TraceCallbackFunc : public TraceCallbacks {
Func mCallback;
};
template <typename T,
typename = std::enable_if_t<
std::is_same_v<
void, decltype(std::declval<TraceCallbacks*>()->Trace(
std::declval<T*>(), std::declval<const char*>(),
std::declval<void*>()))>,
void>>
using TraceableType = T;
/*
* Default implementation for traceable types.
*/
template <typename T>
inline void ImplCycleCollectionTrace(const TraceCallbacks& aCallbacks,
TraceableType<T>& aField,
const char* aName, void* aClosure) {
aCallbacks.Trace(&aField, aName, aClosure);
}
/*
* Default implementations for containers.
*
* To participate either define `ImplCycleCollectionContainer` or
* `ImplCycleCollectionIndexedContainer` for the container type. The latter
* should be chosen when edges should be decorated as an indexed container. Use
* `EnableCycleCollectionIf` from nsCycleCollectionContainerParticipant.h to
* restrict allowed types. For example:
*
* template <typename T>
* struct MyContainer {
* T mT;
* };
*
* template <typename Container, typename Callback,
* EnableCycleCollectionIf<Container, MyContainer> = nullptr>
* inline void ImplCycleCollectionContainer(Container&& aField,
* Callback&& aCallback) {
* aCallback(aField.mT);
* }
*/
template <typename T, typename = void>
struct ImplCycleCollectionNonIndexedContainerT : std::false_type {};
template <typename T>
struct ImplCycleCollectionNonIndexedContainerT<
T,
std::void_t<decltype(ImplCycleCollectionContainer(std::declval<T&>(), 0))>>
: std::true_type {};
template <typename T, typename = void>
struct ImplCycleCollectionIndexedContainerT : std::false_type {};
template <typename T>
struct ImplCycleCollectionIndexedContainerT<
T, std::void_t<decltype(ImplCycleCollectionIndexedContainer(
std::declval<T&>(), 0))>> : std::true_type {};
template <typename T>
constexpr bool ImplCycleCollectionCollectNonIndexedContainer =
ImplCycleCollectionNonIndexedContainerT<T>::value;
template <typename T>
constexpr bool ImplCycleCollectionCollectIndexedContainer =
ImplCycleCollectionIndexedContainerT<T>::value;
template <typename T>
constexpr bool ImplCycleCollectionCollectContainer =
ImplCycleCollectionNonIndexedContainerT<T>::value ||
ImplCycleCollectionIndexedContainerT<T>::value;
template <typename T, typename = std::enable_if_t<
ImplCycleCollectionCollectContainer<T>, void>>
void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
T& aField, const char* aName,
uint32_t aFlags = 0) {
if constexpr (ImplCycleCollectionIndexedContainerT<T>::value) {
aFlags |= CycleCollectionEdgeNameArrayFlag;
ImplCycleCollectionIndexedContainer(aField, [&](auto& aFieldMember) {
ImplCycleCollectionTraverse(aCallback, aFieldMember, aName, aFlags);
});
} else {
ImplCycleCollectionContainer(aField, [&](auto& aFieldMember) {
ImplCycleCollectionTraverse(aCallback, aFieldMember, aName, aFlags);
});
}
}
template <typename T, typename = std::enable_if_t<
ImplCycleCollectionCollectContainer<T>, void>>
void ImplCycleCollectionTrace(const TraceCallbacks& aCallbacks, T& aField,
const char* aName, void* aClosure) {
if constexpr (ImplCycleCollectionIndexedContainerT<T>::value) {
ImplCycleCollectionIndexedContainer(aField, [&](auto& aFieldMember) {
ImplCycleCollectionTrace(aCallbacks, aFieldMember, aName, aClosure);
});
} else {
ImplCycleCollectionContainer(aField, [&](auto& aFieldMember) {
ImplCycleCollectionTrace(aCallbacks, aFieldMember, aName, aClosure);
});
}
}
/**
* Participant implementation classes
*/
@@ -715,7 +620,7 @@ T* DowncastCCParticipant(void* aPtr) {
NS_CYCLE_COLLECTION_CLASSNAME(_base_class)::Trace(s, aCallbacks, aClosure);
#define NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(_field) \
ImplCycleCollectionTrace(aCallbacks, tmp->_field, #_field, aClosure);
aCallbacks.Trace(&tmp->_field, #_field, aClosure);
// NB: The (void)tmp; hack in the TRACE_END macro exists to support
// implementations that don't need to do anything in their Trace method.

View File

@@ -1,29 +0,0 @@
/* -*- 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_CycleCollectedUniquePtr_h__
#define mozilla_CycleCollectedUniquePtr_h__
#include "mozilla/UniquePtr.h"
#include "nsCycleCollectionContainerParticipant.h"
namespace mozilla {
template <typename T>
inline void ImplCycleCollectionUnlink(mozilla::UniquePtr<T>& aField) {
aField.reset();
}
template <typename Container, typename Callback,
EnableCycleCollectionIf<Container, mozilla::UniquePtr> = nullptr>
inline void ImplCycleCollectionContainer(Container&& aField,
Callback&& aCallback) {
if (aField) {
aCallback(*aField);
}
}
} // namespace mozilla
#endif // mozilla_CycleCollectedUniquePtr_h__

View File

@@ -91,7 +91,6 @@ EXPORTS.mozilla += [
"ArrayAlgorithm.h",
"ArrayIterator.h",
"AtomArray.h",
"CycleCollectedUniquePtr.h",
"Dafsa.h",
"IncrementalTokenizer.h",
"Observer.h",

View File

@@ -288,12 +288,6 @@ class nsBaseHashtable
const nsBaseHashtable<KC, DT, UDT, C>&, const char* aName,
uint32_t aFlags);
template <typename KC, typename DT, typename UDT, typename C>
friend inline void ImplCycleCollectionTrace(const TraceCallbacks& aCallbacks,
nsBaseHashtable<KC, DT, UDT, C>&,
const char* aName,
void* aClosure);
public:
typedef typename KeyClass::KeyType KeyType;
typedef nsBaseHashtableET<KeyClass, DataType> EntryType;
@@ -1063,41 +1057,4 @@ inline void ImplCycleCollectionTraverse(
ImplCycleCollectionTraverse(aCallback, aField.GetData(), aName, aFlags);
}
template <class KeyClass, class DataType, class UserDataType, class Converter>
inline void ImplCycleCollectionTrace(
const TraceCallbacks& aCallbacks,
nsBaseHashtable<KeyClass, DataType, UserDataType, Converter>& aField,
const char* aName, void* aClosure) {
ImplCycleCollectionTrace(
aCallbacks,
static_cast<nsTHashtable<nsBaseHashtableET<KeyClass, DataType>>&>(aField),
aName, aClosure);
}
namespace mozilla::detail {
template <typename T, typename = void>
constexpr bool kCanTrace = false;
template <typename T>
constexpr bool
kCanTrace<T, std::void_t<decltype(ImplCycleCollectionTrace(
std::declval<TraceCallbacks>(), std::declval<T&>(),
std::declval<const char*>(), std::declval<void*>()))>> =
true;
} // namespace mozilla::detail
template <typename KeyClass, typename DataType>
inline void ImplCycleCollectionTrace(
const TraceCallbacks& aCallbacks,
nsBaseHashtableET<KeyClass, DataType>& aField, const char* aName,
void* aClosure) {
static_assert(!mozilla::detail::kCanTrace<KeyClass&>,
"Don't use traceable values as KeyClass");
static_assert(mozilla::detail::kCanTrace<DataType&>,
"Can't trace values of type DataType");
ImplCycleCollectionTrace(aCallbacks, *aField.GetModifiableData(), aName,
aClosure);
}
#endif // nsBaseHashtable_h__

View File

@@ -21,3 +21,7 @@ bool IsTwiceTheRequiredBytesRepresentableAsUint32(size_t aCapacity,
using mozilla::CheckedUint32;
return ((CheckedUint32(aCapacity) * aElemSize) * 2).isValid();
}
void ::detail::SetCycleCollectionArrayFlag(uint32_t& aFlags) {
aFlags |= CycleCollectionEdgeNameArrayFlag;
}

View File

@@ -43,7 +43,6 @@ class Heap;
} /* namespace JS */
class nsCycleCollectionTraversalCallback;
struct TraceCallbacks;
class nsRegion;
namespace mozilla::a11y {
@@ -2686,11 +2685,21 @@ inline void ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField) {
aField.Clear();
}
template <typename E, typename Alloc, typename Callback>
inline void ImplCycleCollectionIndexedContainer(nsTArray_Impl<E, Alloc>& aField,
Callback&& aCallback) {
for (auto& value : aField) {
aCallback(value);
namespace detail {
// This is defined in the cpp file to avoid including
// nsCycleCollectionNoteChild.h in this header file.
void SetCycleCollectionArrayFlag(uint32_t& aFlags);
} // namespace detail
template <typename E, typename Alloc>
inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback,
nsTArray_Impl<E, Alloc>& aField, const char* aName, uint32_t aFlags = 0) {
::detail::SetCycleCollectionArrayFlag(aFlags);
size_t length = aField.Length();
E* elements = aField.Elements();
for (size_t i = 0; i < length; ++i) {
ImplCycleCollectionTraverse(aCallback, elements[i], aName, aFlags);
}
}

View File

@@ -25,7 +25,6 @@
#include "mozilla/fallible.h"
#include "nsPointerHashKeys.h"
#include "nsTArrayForwardDeclare.h"
#include "nsCycleCollectionContainerParticipant.h"
template <class EntryType>
class nsTHashtable;
@@ -431,8 +430,8 @@ class MOZ_NEEDS_NO_VTABLE_TYPE nsTHashtable {
};
template <class F>
auto WithEntryHandle(KeyType aKey, F&& aFunc)
-> std::invoke_result_t<F, EntryHandle&&> {
auto WithEntryHandle(KeyType aKey,
F&& aFunc) -> std::invoke_result_t<F, EntryHandle&&> {
return this->mTable.WithEntryHandle(
EntryType::KeyToPointer(aKey),
[&aKey, &aFunc](auto entryHandle) -> decltype(auto) {
@@ -723,21 +722,20 @@ void nsTHashtable<EntryType>::s_ClearEntry(PLDHashTable* aTable,
}
class nsCycleCollectionTraversalCallback;
struct TraceCallbacks;
template <class EntryType>
inline void ImplCycleCollectionUnlink(nsTHashtable<EntryType>& aField) {
aField.Clear();
}
// Function template constrained to types that are (possibly const)
// nsTHashtable.
template <typename Container, typename Callback,
EnableCycleCollectionIf<Container, nsTHashtable> = nullptr>
inline void ImplCycleCollectionContainer(Container&& aField,
Callback&& aCallback) {
for (auto& entry : aField) {
aCallback(entry);
template <class EntryType>
inline void ImplCycleCollectionTraverse(
nsCycleCollectionTraversalCallback& aCallback,
const nsTHashtable<EntryType>& aField, const char* aName,
uint32_t aFlags = 0) {
for (auto iter = aField.ConstIter(); !iter.Done(); iter.Next()) {
const EntryType* entry = iter.Get();
ImplCycleCollectionTraverse(aCallback, *entry, aName, aFlags);
}
}
@@ -878,8 +876,8 @@ class nsTHashtable<nsPtrHashKey<T>>
};
template <class F>
auto WithEntryHandle(KeyType aKey, F aFunc)
-> std::invoke_result_t<F, EntryHandle&&> {
auto WithEntryHandle(KeyType aKey,
F aFunc) -> std::invoke_result_t<F, EntryHandle&&> {
return Base::WithEntryHandle(aKey, [&aFunc](auto entryHandle) {
return aFunc(EntryHandle{std::move(entryHandle)});
});