Issue #1587 - Part 2: Implement controller follow/unfollow

This commit is contained in:
Moonchild 2020-06-10 21:33:28 +00:00 committed by Roy Tam
commit 7207793622
5 changed files with 202 additions and 8 deletions

View file

@ -12,7 +12,8 @@
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FetchController, mGlobal, mSignal)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FetchController, mGlobal, mSignal,
mFollowingSignal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(FetchController)
NS_IMPL_CYCLE_COLLECTING_RELEASE(FetchController)
@ -97,13 +98,29 @@ FetchController::Abort()
void
FetchController::Follow(FetchSignal& aSignal)
{
// TODO
FetchSignal::Follower::Follow(&aSignal);
}
void
FetchController::Unfollow(FetchSignal& aSignal)
{
// TODO
if (mFollowingSignal != &aSignal) {
return;
}
FetchSignal::Follower::Unfollow();
}
FetchSignal*
FetchController::Following() const
{
return mFollowingSignal;
}
void
FetchController::Aborted()
{
Abort();
}
} // dom namespace

View file

@ -8,6 +8,7 @@
#define mozilla_dom_FetchController_h
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/FetchSignal.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/ErrorResult.h"
@ -16,10 +17,9 @@
namespace mozilla {
namespace dom {
class FetchSignal;
class FetchController final : public nsISupports
, public nsWrapperCache
, public FetchSignal::Follower
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -51,6 +51,13 @@ public:
void
Unfollow(FetchSignal& aSignal);
FetchSignal*
Following() const;
// FetchSignal::Follower
void Aborted() override;
private:
~FetchController() = default;

View file

@ -16,12 +16,12 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(FetchSignal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FetchSignal,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mController)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mController)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FetchSignal,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mController)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mController)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchSignal)
@ -55,6 +55,11 @@ FetchSignal::Abort()
MOZ_ASSERT(!mAborted);
mAborted = true;
// Let's inform the followers.
for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
mFollowers[i]->Aborted();
}
EventInit init;
init.mBubbles = false;
init.mCancelable = false;
@ -65,7 +70,73 @@ FetchSignal::Abort()
Event::Constructor(this, NS_LITERAL_STRING("abort"), init);
event->SetTrusted(true);
DispatchDOMEvent(nullptr, event, nullptr, nullptr);
bool dummy;
DispatchEvent(event, &dummy);
}
void
FetchSignal::AddFollower(FetchSignal::Follower* aFollower)
{
MOZ_DIAGNOSTIC_ASSERT(aFollower);
if (!mFollowers.Contains(aFollower)) {
mFollowers.AppendElement(aFollower);
}
}
void
FetchSignal::RemoveFollower(FetchSignal::Follower* aFollower)
{
MOZ_DIAGNOSTIC_ASSERT(aFollower);
mFollowers.RemoveElement(aFollower);
}
bool
FetchSignal::CanAcceptFollower(FetchSignal::Follower* aFollower) const
{
MOZ_DIAGNOSTIC_ASSERT(aFollower);
if (aFollower == mController) {
return false;
}
FetchSignal* following = mController->Following();
if (!following) {
return true;
}
return following->CanAcceptFollower(aFollower);
}
// FetchSignal::Follower
// ----------------------------------------------------------------------------
FetchSignal::Follower::~Follower()
{
Unfollow();
}
void
FetchSignal::Follower::Follow(FetchSignal* aSignal)
{
MOZ_DIAGNOSTIC_ASSERT(aSignal);
if (!aSignal->CanAcceptFollower(this)) {
return;
}
Unfollow();
mFollowingSignal = aSignal;
aSignal->AddFollower(this);
}
void
FetchSignal::Follower::Unfollow()
{
if (mFollowingSignal) {
mFollowingSignal->RemoveFollower(this);
mFollowingSignal = nullptr;
}
}
} // dom namespace

View file

@ -13,10 +13,29 @@ namespace mozilla {
namespace dom {
class FetchController;
class FetchSignal;
class FetchSignal final : public DOMEventTargetHelper
{
public:
// This class must be implemented by objects who want to follow a FetchSignal.
class Follower
{
public:
virtual void Aborted() = 0;
protected:
virtual ~Follower();
void
Follow(FetchSignal* aSignal);
void
Unfollow();
RefPtr<FetchSignal> mFollowingSignal;
};
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchSignal, DOMEventTargetHelper)
@ -33,11 +52,23 @@ public:
IMPL_EVENT_HANDLER(abort);
void
AddFollower(Follower* aFollower);
void
RemoveFollower(Follower* aFollower);
bool
CanAcceptFollower(Follower* aFollower) const;
private:
~FetchSignal() = default;
RefPtr<FetchController> mController;
// Raw pointers. Follower unregisters itself in the DTOR.
nsTArray<Follower*> mFollowers;
bool mAborted;
};

View file

@ -21,8 +21,76 @@ function testWebIDL() {
next();
}
function testUpdateData() {
var fc = new FetchController();
is(fc.signal.aborted, false, "By default FetchSignal.aborted is false");
fc.abort();
is(fc.signal.aborted, true, "Signal is aborted");
next();
}
function testFollowingOurself() {
// Let's follow ourself
var fc = new FetchController();
fc.follow(fc.signal);
fc.abort();
is(fc.signal.aborted, true, "Signal is aborted");
next();
}
function testFollowingOther() {
// Let's follow another one
var fc1 = new FetchController();
var fc2 = new FetchController();
fc1.follow(fc2.signal);
fc2.abort();
is(fc1.signal.aborted, true, "Signal is aborted");
is(fc2.signal.aborted, true, "Signal is aborted");
next();
}
function testFollowingLoop() {
// fc1 -> fc2 -> fc3 -> fc1
var fc1 = new FetchController();
var fc2 = new FetchController();
var fc3 = new FetchController();
fc1.follow(fc2.signal);
fc2.follow(fc3.signal);
fc3.follow(fc1.signal);
fc3.abort();
is(fc1.signal.aborted, true, "Signal is aborted");
is(fc2.signal.aborted, true, "Signal is aborted");
is(fc3.signal.aborted, true, "Signal is aborted");
next();
}
function testAbortEvent() {
var fc = new FetchController();
fc.signal.onabort = function(e) {
is(e.type, "abort", "Abort received");
next();
}
fc.abort();
}
var steps = [
testWebIDL,
testUpdateData,
testFollowingOurself,
testFollowingOther,
testFollowingLoop,
testAbortEvent,
];
function next() {