Bug 1361259. P2 - use NewRunnableMethod() to pass event data to the listener function.
Note this breaks the MediaEventSource::CopyEvent2 gtest since there is always
one copy or move when storing the event data in the runnable created by
NewRunnableMethod() even when the listener function takes no arguments at all.
We will fix it later.
MozReview-Commit-ID: J9T63yxXko2
--- a/dom/media/MediaEventSource.h
+++ b/dom/media/MediaEventSource.h
@@ -229,53 +229,74 @@ protected:
* Stored by MediaEventSource to send notifications to the listener.
* Since virtual methods can not be templated, this class is specialized
* to provide different Dispatch() overloads depending on EventPassMode.
*/
template <EventPassMode Mode, typename... As>
class Listener : public ListenerBase
{
public:
- virtual void Dispatch(const As&... aEvents) = 0;
-};
+ template <typename... Ts>
+ void Dispatch(Ts&&... aEvents)
+ {
+ DispatchTask(NewRunnableMethod<typename Decay<Ts>::Type&&...>(
+ this, &Listener::Apply, Forward<Ts>(aEvents)...));
+ }
-template <typename... As>
-class Listener<EventPassMode::Move, As...> : public ListenerBase
-{
-public:
- virtual void Dispatch(As... aEvents) = 0;
+private:
+ virtual void DispatchTask(already_AddRefed<nsIRunnable> aTask) = 0;
+ virtual void Apply(As&&... aEvents) = 0;
};
/**
* Store the registered target thread and function so it knows where and to
* whom to send the event data.
*/
-template <typename Target, typename Function, EventPassMode, typename... As>
-class ListenerImpl : public Listener<EventPassMode::Copy, As...> {
+template <typename Target, typename Function, EventPassMode Mode, typename... As>
+class ListenerImpl : public Listener<Mode, As...>
+{
public:
ListenerImpl(Target* aTarget, const Function& aFunction)
- : mHelper(this, aTarget, aFunction) {}
- void Dispatch(const As&... aEvents) override {
- mHelper.Dispatch(aEvents...);
+ : mTarget(aTarget)
+ , mFunction(aFunction)
+ {
}
+
private:
- ListenerHelper<Target, Function> mHelper;
-};
+ void DispatchTask(already_AddRefed<nsIRunnable> aTask) override
+ {
+ EventTarget<Target>::Dispatch(mTarget.get(), Move(aTask));
+ }
+
+ // |F| takes one or more arguments.
+ template <typename F>
+ typename EnableIf<TakeArgs<F>::value, void>::Type
+ ApplyImpl(const F& aFunc, As&&... aEvents)
+ {
+ aFunc(Move(aEvents)...);
+ }
-template <typename Target, typename Function, typename... As>
-class ListenerImpl<Target, Function, EventPassMode::Move, As...>
- : public Listener<EventPassMode::Move, As...> {
-public:
- ListenerImpl(Target* aTarget, const Function& aFunction)
- : mHelper(this, aTarget, aFunction) {}
- void Dispatch(As... aEvents) override {
- mHelper.Dispatch(Move(aEvents)...);
+ // |F| takes no arguments. Don't bother passing aEvent.
+ template <typename F>
+ typename EnableIf<!TakeArgs<F>::value, void>::Type
+ ApplyImpl(const F& aFunc, As&&... aEvents)
+ {
+ aFunc();
}
-private:
- ListenerHelper<Target, Function> mHelper;
+
+ void Apply(As&&... aEvents) override
+ {
+ // Don't call the listener if it is disconnected.
+ if (!RevocableToken::IsRevoked()) {
+ ApplyImpl(mFunction, Move(aEvents)...);
+ }
+ }
+
+ const RefPtr<Target> mTarget;
+ Function mFunction;
};
/**
* Select EventPassMode based on ListenerPolicy.
*
* @Copy Selected when ListenerPolicy is NonExclusive because each listener
* must get a copy.
*