replaced by .editorconfig # ignore-this-changeset Differential Revision: https://phabricator.services.mozilla.com/D287843
135 lines
4.2 KiB
C++
135 lines
4.2 KiB
C++
/* 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_RequestCallbackManager_h
|
|
#define mozilla_dom_RequestCallbackManager_h
|
|
|
|
#include <limits>
|
|
|
|
#include "mozilla/RefPtr.h"
|
|
#include "nsTArray.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
template <typename RequestCallback>
|
|
struct RequestCallbackEntry {
|
|
RequestCallbackEntry(RequestCallback& aCallback, uint32_t aHandle)
|
|
: mCallback(&aCallback), mHandle(aHandle) {
|
|
LogTaskBase<RequestCallback>::LogDispatch(mCallback);
|
|
}
|
|
|
|
~RequestCallbackEntry() = default;
|
|
|
|
// Comparator operators to allow RemoveElementSorted with an
|
|
// integer argument on arrays of RequestCallback
|
|
bool operator==(uint32_t aHandle) const { return mHandle == aHandle; }
|
|
bool operator<(uint32_t aHandle) const { return mHandle < aHandle; }
|
|
|
|
RefPtr<RequestCallback> mCallback;
|
|
const uint32_t mHandle;
|
|
bool mCancelled = false;
|
|
};
|
|
|
|
template <typename RequestCallback>
|
|
class RequestCallbackManager {
|
|
public:
|
|
RequestCallbackManager() = default;
|
|
~RequestCallbackManager() = default;
|
|
|
|
using CallbackList = nsTArray<RequestCallbackEntry<RequestCallback>>;
|
|
|
|
nsresult Schedule(RequestCallback& aCallback, uint32_t* aHandle) {
|
|
if (mCallbackCounter == std::numeric_limits<uint32_t>::max()) {
|
|
// Can't increment without overflowing; bail out
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
uint32_t newHandle = ++mCallbackCounter;
|
|
|
|
mCallbacks.AppendElement(RequestCallbackEntry(aCallback, newHandle));
|
|
|
|
*aHandle = newHandle;
|
|
return NS_OK;
|
|
}
|
|
|
|
bool Cancel(uint32_t aHandle) {
|
|
// mCallbacks is stored sorted by handle
|
|
if (mCallbacks.RemoveElementSorted(aHandle)) {
|
|
return true;
|
|
}
|
|
for (auto* callbacks : mFiringCallbacksOnStack) {
|
|
auto index = callbacks->mList.BinaryIndexOf(aHandle);
|
|
if (index != CallbackList::NoIndex) {
|
|
callbacks->mList.ElementAt(index).mCancelled = true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool IsEmpty() const { return mCallbacks.IsEmpty(); }
|
|
|
|
// FiringCallbacks takes care of:
|
|
// * Stealing (and thus "freezing") the current callback list, in preparation
|
|
// for firing them.
|
|
// * Registering and unregistering in mFiringCallbacksOnStack, to deal with
|
|
// cancellation of in-flight callbacks in cases like the first callback on
|
|
// the list calling cancelAnimationFrame(secondCallbackId) or so.
|
|
// mList is guaranteed not to reallocate once stolen. Instead if a callback is
|
|
// cancelled mid-firing, the mCancelled bit is set, see Cancel().
|
|
struct MOZ_NON_MEMMOVABLE MOZ_STACK_CLASS FiringCallbacks {
|
|
explicit FiringCallbacks(RequestCallbackManager& aManager)
|
|
: mManager(aManager) {
|
|
mList = std::move(aManager.mCallbacks);
|
|
aManager.mFiringCallbacksOnStack.AppendElement(this);
|
|
}
|
|
|
|
~FiringCallbacks() {
|
|
MOZ_ASSERT(mManager.mFiringCallbacksOnStack.LastElement() == this);
|
|
mManager.mFiringCallbacksOnStack.RemoveLastElement();
|
|
}
|
|
|
|
RequestCallbackManager& mManager;
|
|
CallbackList mList;
|
|
};
|
|
|
|
void Unlink() { mCallbacks.Clear(); }
|
|
|
|
void Traverse(nsCycleCollectionTraversalCallback& aCB) {
|
|
for (auto& i : mCallbacks) {
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(
|
|
aCB, "RequestCallbackManager::mCallbacks[i]");
|
|
aCB.NoteXPCOMChild(i.mCallback);
|
|
}
|
|
}
|
|
|
|
private:
|
|
CallbackList mCallbacks;
|
|
|
|
// The current lists of callbacks that are executing. Used to deal with
|
|
// cancellation within the same frame. Note this is a list to deal reasonably
|
|
// with event loop spinning.
|
|
AutoTArray<FiringCallbacks*, 1> mFiringCallbacksOnStack;
|
|
|
|
// The current frame request callback handle.
|
|
uint32_t mCallbackCounter = 0;
|
|
};
|
|
|
|
template <class RequestCallback>
|
|
inline void ImplCycleCollectionUnlink(
|
|
RequestCallbackManager<RequestCallback>& aField) {
|
|
aField.Unlink();
|
|
}
|
|
|
|
template <class RequestCallback>
|
|
inline void ImplCycleCollectionTraverse(
|
|
nsCycleCollectionTraversalCallback& aCallback,
|
|
RequestCallbackManager<RequestCallback>& aField, const char* aName,
|
|
uint32_t aFlags) {
|
|
aField.Traverse(aCallback);
|
|
}
|
|
|
|
} // namespace mozilla::dom
|
|
|
|
#endif
|