Bug 1361259. P2 - use NewRunnableMethod() to pass event data to the listener function. r=gerald
authorJW Wang <jwwang@mozilla.com>
Fri, 28 Apr 2017 16:28:47 +0800
changeset 355990 b8fe34848ac81980de9f5c5c222abc0005309ffd
parent 355989 c8d5c205eeeeb670d2b626f066b4841d00754ace
child 355991 cf5321dca675249a420ad59b2301a9890f74bd9c
push id31754
push userkwierso@gmail.com
push dateWed, 03 May 2017 00:28:51 +0000
treeherdermozilla-central@5eaf2d70eded [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1361259
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1361259. P2 - use NewRunnableMethod() to pass event data to the listener function. r=gerald 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
dom/media/MediaEventSource.h
--- 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.
  *