Bug 1305926 - Custom event targets for Dispatcher API (r=ehsan)
authorBill McCloskey <billm@mozilla.com>
Fri, 28 Oct 2016 15:57:50 -0700
changeset 896475 dcd436e553ed85cadb6538ca4f4382610a7bcd5f
parent 896474 5b16c69a1b81c1e1c101c67639bcf489f0d8cdcb
child 896598 c97615bbeb94b0ffe5132bece933061ee5eaecf7
push id155501
push userashiue@mozilla.com
push dateFri, 18 Nov 2016 03:26:06 +0000
treeherdertry@c775a1cfc96e [default view] [failures only]
reviewersehsan
bugs1305926
milestone53.0a1
Bug 1305926 - Custom event targets for Dispatcher API (r=ehsan) MozReview-Commit-ID: 9FXq1BRXwku
dom/base/Dispatcher.cpp
dom/base/Dispatcher.h
dom/base/DocGroup.cpp
dom/base/nsDocument.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIDocument.h
--- a/dom/base/Dispatcher.cpp
+++ b/dom/base/Dispatcher.cpp
@@ -11,8 +11,82 @@ using namespace mozilla;
 
 nsresult
 DispatcherTrait::Dispatch(const char* aName,
                           TaskCategory aCategory,
                           already_AddRefed<nsIRunnable>&& aRunnable)
 {
   return NS_DispatchToMainThread(Move(aRunnable));
 }
+
+already_AddRefed<nsIEventTarget>
+DispatcherTrait::CreateEventTarget(const char* aName,
+                                   TaskCategory aCategory)
+{
+  nsCOMPtr<nsIEventTarget> main = do_GetMainThread();
+  return main.forget();
+}
+
+namespace {
+
+class DispatcherEventTarget final : public nsIEventTarget
+{
+  RefPtr<dom::Dispatcher> mDispatcher;
+  const char* mName;
+  TaskCategory mCategory;
+
+public:
+  DispatcherEventTarget(dom::Dispatcher* aDispatcher,
+                        const char* aName,
+                        TaskCategory aCategory)
+   : mDispatcher(aDispatcher)
+   , mName(aName)
+   , mCategory(aCategory)
+  {}
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIEVENTTARGET
+
+  dom::Dispatcher* Dispatcher() const { return mDispatcher; }
+
+private:
+  virtual ~DispatcherEventTarget() {}
+};
+
+} // namespace
+
+NS_IMPL_ISUPPORTS(DispatcherEventTarget, nsIEventTarget)
+
+NS_IMETHODIMP
+DispatcherEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags)
+{
+  return Dispatch(do_AddRef(aRunnable), aFlags);
+}
+
+NS_IMETHODIMP
+DispatcherEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags)
+{
+  if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+  return mDispatcher->Dispatch(mName, mCategory, Move(aRunnable));
+}
+
+NS_IMETHODIMP
+DispatcherEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+DispatcherEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
+{
+  *aIsOnCurrentThread = NS_IsMainThread();
+  return NS_OK;
+}
+
+already_AddRefed<nsIEventTarget>
+Dispatcher::CreateEventTarget(const char* aName, TaskCategory aCategory)
+{
+  RefPtr<DispatcherEventTarget> target =
+    new DispatcherEventTarget(this, aName, aCategory);
+  return target.forget();
+}
--- a/dom/base/Dispatcher.h
+++ b/dom/base/Dispatcher.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Dispatcher_h
 #define mozilla_dom_Dispatcher_h
 
 #include "mozilla/AlreadyAddRefed.h"
 #include "nsISupports.h"
 
+class nsIEventTarget;
 class nsIRunnable;
 
 namespace mozilla {
 namespace dom {
 
 enum class TaskCategory {
   // User input (clicks, keypresses, etc.)
   UI,
@@ -41,23 +42,34 @@ enum class TaskCategory {
 // directly because it inherits from nsISupports.
 class DispatcherTrait {
 public:
   // This method may or may not be safe off of the main thread. For nsIDocument
   // it is safe. For nsIGlobalWindow it is not safe.
   virtual nsresult Dispatch(const char* aName,
                             TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable);
+
+  // This method may or may not be safe off of the main thread. For nsIDocument
+  // it is safe. For nsIGlobalWindow it is not safe. The nsIEventTarget can
+  // always be used off the main thread.
+  virtual already_AddRefed<nsIEventTarget>
+  CreateEventTarget(const char* aName, TaskCategory aCategory);
 };
 
 // Base class for DocGroup and TabGroup.
 class Dispatcher : public nsISupports {
 public:
   // This method is always safe to call off the main thread.
   virtual nsresult Dispatch(const char* aName,
                             TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) = 0;
+
+  // This method is always safe to call off the main thread. The nsIEventTarget
+  // can always be used off the main thread.
+  virtual already_AddRefed<nsIEventTarget>
+  CreateEventTarget(const char* aName, TaskCategory aCategory);
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_Dispatcher_h
--- a/dom/base/DocGroup.cpp
+++ b/dom/base/DocGroup.cpp
@@ -1,16 +1,20 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/TabGroup.h"
 #include "mozilla/Telemetry.h"
-#include "nsIURI.h"
+#include "nsIDocShell.h"
 #include "nsIEffectiveTLDService.h"
-#include "mozilla/StaticPtr.h"
-#include "mozilla/ClearOnShutdown.h"
-#include "nsIDocShell.h"
+#include "nsIURI.h"
 
 namespace mozilla {
 namespace dom {
 
 /* static */ void
 DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
 {
   aKey.Truncate();
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -2895,16 +2895,25 @@ nsIDocument::Dispatch(const char* aName,
 {
   // Note that this method may be called off the main thread.
   if (mDocGroup) {
     return mDocGroup->Dispatch(aName, aCategory, Move(aRunnable));
   }
   return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
 }
 
+already_AddRefed<nsIEventTarget>
+nsIDocument::CreateEventTarget(const char* aName, TaskCategory aCategory)
+{
+  if (mDocGroup) {
+    return mDocGroup->CreateEventTarget(aName, aCategory);
+  }
+  return DispatcherTrait::CreateEventTarget(aName, aCategory);
+}
+
 NS_IMETHODIMP
 nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
 {
   NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
 
   return NS_OK;
 }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -14940,16 +14940,27 @@ nsGlobalWindow::Dispatch(const char* aNa
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (GetDocGroup()) {
     return GetDocGroup()->Dispatch(aName, aCategory, Move(aRunnable));
   }
   return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
 }
 
+already_AddRefed<nsIEventTarget>
+nsGlobalWindow::CreateEventTarget(const char* aName,
+                                  TaskCategory aCategory)
+{
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+  if (GetDocGroup()) {
+    return GetDocGroup()->CreateEventTarget(aName, aCategory);
+  }
+  return DispatcherTrait::CreateEventTarget(aName, aCategory);
+}
+
 nsGlobalWindow::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
   nsGlobalWindow* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
   MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 
   MOZ_ASSERT(aWindow);
   nsGlobalWindow* topWindow = aWindow->GetScriptableTopInternal();
   if (!topWindow) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -1718,16 +1718,19 @@ private:
   mozilla::dom::TabGroup* TabGroupOuter();
 
 public:
   // Dispatch a runnable related to the global.
   virtual nsresult Dispatch(const char* aName,
                             mozilla::dom::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
+  virtual already_AddRefed<nsIEventTarget>
+  CreateEventTarget(const char* aName, mozilla::dom::TaskCategory aCategory) override;
+
 protected:
   // These members are only used on outer window objects. Make sure
   // you never set any of these on an inner object!
   bool                          mFullScreen : 1;
   bool                          mFullscreenMode : 1;
   bool                          mIsClosed : 1;
   bool                          mInClose : 1;
   // mHavePendingClose means we've got a termination function set to
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -2867,16 +2867,20 @@ public:
   virtual void ScheduleIntersectionObserverNotification() = 0;
   virtual void NotifyIntersectionObservers() = 0;
 
   // Dispatch a runnable related to the document.
   virtual nsresult Dispatch(const char* aName,
                             mozilla::dom::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
+  virtual already_AddRefed<nsIEventTarget>
+  CreateEventTarget(const char* aName,
+                    mozilla::dom::TaskCategory aCategory) override;
+
 protected:
   bool GetUseCounter(mozilla::UseCounter aUseCounter)
   {
     return mUseCounters[aUseCounter];
   }
 
   void SetChildDocumentUseCounter(mozilla::UseCounter aUseCounter)
   {