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/. */
6 
7 #include "AbortSignal.h"
8 
9 #include "mozilla/dom/Event.h"
10 #include "mozilla/dom/AbortSignalBinding.h"
11 
12 namespace mozilla {
13 namespace dom {
14 
15 // AbortSignalImpl
16 // ----------------------------------------------------------------------------
17 
AbortSignalImpl(bool aAborted)18 AbortSignalImpl::AbortSignalImpl(bool aAborted) : mAborted(aAborted) {}
19 
Aborted() const20 bool AbortSignalImpl::Aborted() const { return mAborted; }
21 
Abort()22 void AbortSignalImpl::Abort() {
23   if (mAborted) {
24     return;
25   }
26 
27   mAborted = true;
28 
29   // Let's inform the followers.
30   nsTObserverArray<AbortFollower*>::ForwardIterator iter(mFollowers);
31   while (iter.HasMore()) {
32     RefPtr<AbortFollower> follower = iter.GetNext();
33     follower->Abort();
34   }
35 }
36 
AddFollower(AbortFollower * aFollower)37 void AbortSignalImpl::AddFollower(AbortFollower* aFollower) {
38   MOZ_DIAGNOSTIC_ASSERT(aFollower);
39   if (!mFollowers.Contains(aFollower)) {
40     mFollowers.AppendElement(aFollower);
41   }
42 }
43 
RemoveFollower(AbortFollower * aFollower)44 void AbortSignalImpl::RemoveFollower(AbortFollower* aFollower) {
45   MOZ_DIAGNOSTIC_ASSERT(aFollower);
46   mFollowers.RemoveElement(aFollower);
47 }
48 
49 // AbortSignal
50 // ----------------------------------------------------------------------------
51 
52 NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignal)
53 
54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(AbortSignal,
55                                                   DOMEventTargetHelper)
56   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFollowingSignal)
57 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
58 
59 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AbortSignal,
60                                                 DOMEventTargetHelper)
61   tmp->Unfollow();
62 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
63 
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortSignal)64 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortSignal)
65 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
66 
67 NS_IMPL_ADDREF_INHERITED(AbortSignal, DOMEventTargetHelper)
68 NS_IMPL_RELEASE_INHERITED(AbortSignal, DOMEventTargetHelper)
69 
70 AbortSignal::AbortSignal(nsIGlobalObject* aGlobalObject, bool aAborted)
71     : DOMEventTargetHelper(aGlobalObject), AbortSignalImpl(aAborted) {}
72 
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)73 JSObject* AbortSignal::WrapObject(JSContext* aCx,
74                                   JS::Handle<JSObject*> aGivenProto) {
75   return AbortSignal_Binding::Wrap(aCx, this, aGivenProto);
76 }
77 
Abort()78 void AbortSignal::Abort() {
79   AbortSignalImpl::Abort();
80 
81   EventInit init;
82   init.mBubbles = false;
83   init.mCancelable = false;
84 
85   RefPtr<Event> event =
86       Event::Constructor(this, NS_LITERAL_STRING("abort"), init);
87   event->SetTrusted(true);
88 
89   DispatchEvent(*event);
90 }
91 
92 // AbortFollower
93 // ----------------------------------------------------------------------------
94 
~AbortFollower()95 AbortFollower::~AbortFollower() { Unfollow(); }
96 
Follow(AbortSignalImpl * aSignal)97 void AbortFollower::Follow(AbortSignalImpl* aSignal) {
98   MOZ_DIAGNOSTIC_ASSERT(aSignal);
99 
100   Unfollow();
101 
102   mFollowingSignal = aSignal;
103   aSignal->AddFollower(this);
104 }
105 
Unfollow()106 void AbortFollower::Unfollow() {
107   if (mFollowingSignal) {
108     mFollowingSignal->RemoveFollower(this);
109     mFollowingSignal = nullptr;
110   }
111 }
112 
IsFollowing() const113 bool AbortFollower::IsFollowing() const { return !!mFollowingSignal; }
114 
115 }  // namespace dom
116 }  // namespace mozilla
117