1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 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/. */
7 #include "AbortSignal.h"
9 #include "mozilla/dom/Event.h"
10 #include "mozilla/dom/EventBinding.h"
11 #include "mozilla/dom/AbortSignalBinding.h"
12 #include "mozilla/RefPtr.h"
14 namespace mozilla::dom
{
17 // ----------------------------------------------------------------------------
19 AbortSignalImpl::AbortSignalImpl(bool aAborted
) : mAborted(aAborted
) {}
21 bool AbortSignalImpl::Aborted() const { return mAborted
; }
23 // https://dom.spec.whatwg.org/#abortsignal-signal-abort steps 1-4
24 void AbortSignalImpl::SignalAbort() {
34 // When there are multiple followers, the follower removal algorithm
35 // https://dom.spec.whatwg.org/#abortsignal-remove could be invoked in an
36 // earlier algorithm to remove a later algorithm, so |mFollowers| must be a
37 // |nsTObserverArray| to defend against mutation.
38 for (RefPtr
<AbortFollower
> follower
: mFollowers
.ForwardRange()) {
39 MOZ_ASSERT(follower
->mFollowingSignal
== this);
40 follower
->RunAbortAlgorithm();
44 // Clear follower->signal links, then clear signal->follower links.
45 for (AbortFollower
* follower
: mFollowers
.ForwardRange()) {
46 follower
->mFollowingSignal
= nullptr;
51 /* static */ void AbortSignalImpl::Traverse(
52 AbortSignalImpl
* aSignal
, nsCycleCollectionTraversalCallback
& cb
) {
53 // To be filled in shortly.
57 // ----------------------------------------------------------------------------
59 NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignal
)
61 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AbortSignal
,
63 AbortSignalImpl::Traverse(static_cast<AbortSignalImpl
*>(tmp
), cb
);
64 AbortFollower::Traverse(static_cast<AbortFollower
*>(tmp
), cb
);
65 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
67 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AbortSignal
,
69 AbortSignalImpl::Unlink(static_cast<AbortSignalImpl
*>(tmp
));
70 AbortFollower::Unlink(static_cast<AbortFollower
*>(tmp
));
71 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
73 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortSignal
)
74 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper
)
76 NS_IMPL_ADDREF_INHERITED(AbortSignal
, DOMEventTargetHelper
)
77 NS_IMPL_RELEASE_INHERITED(AbortSignal
, DOMEventTargetHelper
)
79 AbortSignal::AbortSignal(nsIGlobalObject
* aGlobalObject
, bool aAborted
)
80 : DOMEventTargetHelper(aGlobalObject
), AbortSignalImpl(aAborted
) {}
82 JSObject
* AbortSignal::WrapObject(JSContext
* aCx
,
83 JS::Handle
<JSObject
*> aGivenProto
) {
84 return AbortSignal_Binding::Wrap(aCx
, this, aGivenProto
);
87 already_AddRefed
<AbortSignal
> AbortSignal::Abort(GlobalObject
& aGlobal
) {
88 nsCOMPtr
<nsIGlobalObject
> global
= do_QueryInterface(aGlobal
.GetAsSupports());
89 RefPtr
<AbortSignal
> abortSignal
= new AbortSignal(global
, true);
90 return abortSignal
.forget();
93 // https://dom.spec.whatwg.org/#abortsignal-signal-abort
94 void AbortSignal::SignalAbort() {
96 AbortSignalImpl::SignalAbort();
100 init
.mBubbles
= false;
101 init
.mCancelable
= false;
103 RefPtr
<Event
> event
= Event::Constructor(this, u
"abort"_ns
, init
);
104 event
->SetTrusted(true);
106 DispatchEvent(*event
);
110 // ----------------------------------------------------------------------------
112 AbortFollower::~AbortFollower() { Unfollow(); }
114 // https://dom.spec.whatwg.org/#abortsignal-add
115 void AbortFollower::Follow(AbortSignalImpl
* aSignal
) {
117 if (aSignal
->mAborted
) {
121 MOZ_DIAGNOSTIC_ASSERT(aSignal
);
126 mFollowingSignal
= aSignal
;
127 MOZ_ASSERT(!aSignal
->mFollowers
.Contains(this));
128 aSignal
->mFollowers
.AppendElement(this);
131 // https://dom.spec.whatwg.org/#abortsignal-remove
132 void AbortFollower::Unfollow() {
133 if (mFollowingSignal
) {
134 // |Unfollow| is called by cycle-collection unlink code that runs in no
135 // guaranteed order. So we can't, symmetric with |Follow| above, assert
136 // that |this| will be found in |mFollowingSignal->mFollowers|.
137 mFollowingSignal
->mFollowers
.RemoveElement(this);
138 mFollowingSignal
= nullptr;
142 bool AbortFollower::IsFollowing() const { return !!mFollowingSignal
; }
144 /* static */ void AbortFollower::Traverse(
145 AbortFollower
* aFollower
, nsCycleCollectionTraversalCallback
& cb
) {
146 ImplCycleCollectionTraverse(cb
, aFollower
->mFollowingSignal
,
147 "mFollowingSignal", 0);
150 } // namespace mozilla::dom