Bug 1379688 part 2. Make the EventTarget interface constructible. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Mon, 20 Nov 2017 13:59:22 -0500
changeset 444504 312db92828f8ac8af5391d5a9533821e6eb758a8
parent 444503 55753b766fd5a588742ac73c6b88a55c0021d2f2
child 444505 11c2b95991519b35c04214060b2a2168f32cdad2
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1379688
milestone59.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 1379688 part 2. Make the EventTarget interface constructible. r=smaug MozReview-Commit-ID: 4xrSSqXna7F
dom/bindings/Bindings.conf
dom/events/ConstructibleEventTarget.cpp
dom/events/ConstructibleEventTarget.h
dom/events/DOMEventTargetHelper.h
dom/events/EventTarget.cpp
dom/events/EventTarget.h
dom/events/moz.build
dom/webidl/EventTarget.webidl
testing/web-platform/meta/dom/events/EventTarget-constructible.any.js.ini
testing/web-platform/meta/dom/interfaces.html.ini
testing/web-platform/tests/eventsource/interfaces.html
testing/web-platform/tests/interfaces/dedicated-workers.idl
testing/web-platform/tests/service-workers/service-worker/resources/interfaces-idls.js
testing/web-platform/tests/webrtc/RTCPeerConnection-idl.html
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -312,17 +312,16 @@ DOMInterfaces = {
 
 'EventTarget': {
     # When we get rid of hasXPConnectImpls, we can get rid of the
     # couldBeDOMBinding stuff in GetOrCreateDOMReflector.
     #
     # We can also get rid of the UnwrapArg bits in
     # the dom QueryInterface (in BindingUtils.cpp) at that point.
     'hasXPConnectImpls': True,
-    'concrete': False,
     'jsImplParent': 'mozilla::DOMEventTargetHelper',
 },
 
 'Exception': {
     'headerFile': 'mozilla/dom/DOMException.h',
     'binaryNames': {
         'message': 'messageMoz',
     },
new file mode 100644
--- /dev/null
+++ b/dom/events/ConstructibleEventTarget.cpp
@@ -0,0 +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/ConstructibleEventTarget.h"
+#include "mozilla/dom/EventTargetBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+JSObject*
+ConstructibleEventTarget::WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto)
+{
+  return EventTargetBinding::Wrap(cx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/events/ConstructibleEventTarget.h
@@ -0,0 +1,35 @@
+/* -*- 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/. */
+
+#ifndef mozilla_dom_ConstructibleEventTarget_h_
+#define mozilla_dom_ConstructibleEventTarget_h_
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "js/RootingAPI.h"
+
+namespace mozilla {
+namespace dom {
+
+class ConstructibleEventTarget : public DOMEventTargetHelper
+{
+public:
+  // Not worrying about isupports and cycle collection here.  This does mean
+  // ConstructibleEventTarget will show up in CC and refcount logs as a
+  // DOMEventTargetHelper, but that's probably OK.
+
+  explicit ConstructibleEventTarget(nsIGlobalObject* aGlobalObject)
+    : DOMEventTargetHelper(aGlobalObject)
+  {
+  }
+
+  virtual JSObject* WrapObject(JSContext* cx,
+			       JS::Handle<JSObject*> aGivenProto) override;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ConstructibleEventTarget_h_
--- a/dom/events/DOMEventTargetHelper.h
+++ b/dom/events/DOMEventTargetHelper.h
@@ -138,20 +138,17 @@ public:
   nsPIDOMWindowInner* GetWindowIfCurrent() const;
   // Returns the document associated with this event target, if that document is
   // the current document of its browsing context.  Will return null otherwise.
   nsIDocument* GetDocumentIfCurrent() const;
   void BindToOwner(nsIGlobalObject* aOwner);
   void BindToOwner(nsPIDOMWindowInner* aOwner);
   void BindToOwner(DOMEventTargetHelper* aOther);
   virtual void DisconnectFromOwner();
-  nsIGlobalObject* GetParentObject() const
-  {
-    return GetOwnerGlobal();
-  }
+  using EventTarget::GetParentObject;
   virtual nsIGlobalObject* GetOwnerGlobal() const override
   {
     nsCOMPtr<nsIGlobalObject> parentObject = do_QueryReferent(mParentObject);
     return parentObject;
   }
   bool HasOrHasHadOwner() { return mHasOrHasHadOwnerWindow; }
 
   virtual void EventListenerAdded(nsAtom* aType) override;
--- a/dom/events/EventTarget.cpp
+++ b/dom/events/EventTarget.cpp
@@ -2,21 +2,36 @@
 /* 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/EventListenerManager.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/EventTargetBinding.h"
+#include "mozilla/dom/ConstructibleEventTarget.h"
+#include "nsIGlobalObject.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
+/* static */
+already_AddRefed<EventTarget>
+EventTarget::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+  RefPtr<EventTarget> target = new ConstructibleEventTarget(global);
+  return target.forget();
+}
+
 void
 EventTarget::RemoveEventListener(const nsAString& aType,
                                  EventListener* aListener,
                                  const EventListenerOptionsOrBoolean& aOptions,
                                  ErrorResult& aRv)
 {
   EventListenerManager* elm = GetExistingListenerManager();
   if (elm) {
--- a/dom/events/EventTarget.h
+++ b/dom/events/EventTarget.h
@@ -23,45 +23,53 @@ class EventListenerManager;
 
 namespace dom {
 
 class AddEventListenerOptionsOrBoolean;
 class Event;
 class EventListener;
 class EventListenerOptionsOrBoolean;
 class EventHandlerNonNull;
+class GlobalObject;
 
 template <class T> struct Nullable;
 
 // IID for the dom::EventTarget interface
 #define NS_EVENTTARGET_IID \
 { 0xde651c36, 0x0053, 0x4c67, \
   { 0xb1, 0x3d, 0x67, 0xb9, 0x40, 0xfc, 0x82, 0xe4 } }
 
 class EventTarget : public nsIDOMEventTarget,
                     public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_EVENTTARGET_IID)
 
   // WebIDL API
+  static already_AddRefed<EventTarget> Constructor(const GlobalObject& aGlobal,
+                                                   ErrorResult& aRv);
   using nsIDOMEventTarget::AddEventListener;
   using nsIDOMEventTarget::RemoveEventListener;
   using nsIDOMEventTarget::DispatchEvent;
   virtual void AddEventListener(const nsAString& aType,
                                 EventListener* aCallback,
                                 const AddEventListenerOptionsOrBoolean& aOptions,
                                 const Nullable<bool>& aWantsUntrusted,
                                 ErrorResult& aRv) = 0;
   virtual void RemoveEventListener(const nsAString& aType,
                                    EventListener* aCallback,
                                    const EventListenerOptionsOrBoolean& aOptions,
                                    ErrorResult& aRv);
   bool DispatchEvent(Event& aEvent, CallerType aCallerType, ErrorResult& aRv);
 
+  nsIGlobalObject* GetParentObject() const
+  {
+    return GetOwnerGlobal();
+  }
+
   // Note, this takes the type in onfoo form!
   EventHandlerNonNull* GetEventHandler(const nsAString& aType)
   {
     RefPtr<nsAtom> type = NS_Atomize(aType);
     return GetEventHandler(type, EmptyString());
   }
 
   // Note, this takes the type in onfoo form!
--- a/dom/events/moz.build
+++ b/dom/events/moz.build
@@ -40,16 +40,17 @@ EXPORTS.mozilla += [
 ]
 
 EXPORTS.mozilla.dom += [
     'AnimationEvent.h',
     'BeforeUnloadEvent.h',
     'ClipboardEvent.h',
     'CommandEvent.h',
     'CompositionEvent.h',
+    'ConstructibleEventTarget.h',
     'CustomEvent.h',
     'DataTransfer.h',
     'DataTransferItem.h',
     'DataTransferItemList.h',
     'DeviceMotionEvent.h',
     'DragEvent.h',
     'Event.h',
     'EventTarget.h',
@@ -82,16 +83,17 @@ if CONFIG['MOZ_WEBSPEECH']:
 
 UNIFIED_SOURCES += [
     'AnimationEvent.cpp',
     'AsyncEventDispatcher.cpp',
     'BeforeUnloadEvent.cpp',
     'ClipboardEvent.cpp',
     'CommandEvent.cpp',
     'CompositionEvent.cpp',
+    'ConstructibleEventTarget.cpp',
     'ContentEventHandler.cpp',
     'CustomEvent.cpp',
     'DataTransfer.cpp',
     'DataTransferItem.cpp',
     'DataTransferItemList.cpp',
     'DeviceMotionEvent.cpp',
     'DOMEventTargetHelper.cpp',
     'DragEvent.cpp',
--- a/dom/webidl/EventTarget.webidl
+++ b/dom/webidl/EventTarget.webidl
@@ -18,17 +18,18 @@ dictionary EventListenerOptions {
   boolean mozSystemGroup = false;
 };
 
 dictionary AddEventListenerOptions : EventListenerOptions {
   boolean passive = false;
   boolean once = false;
 };
 
-[Exposed=(Window,Worker,WorkerDebugger,System)]
+[Constructor,
+ Exposed=(Window,Worker,WorkerDebugger,System)]
 interface EventTarget {
   /* Passing null for wantsUntrusted means "default behavior", which
      differs in content and chrome.  In content that default boolean
      value is true, while in chrome the default boolean value is
      false. */
   [Throws]
   void addEventListener(DOMString type,
                         EventListener? listener,
deleted file mode 100644
--- a/testing/web-platform/meta/dom/events/EventTarget-constructible.any.js.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[EventTarget-constructible.any.html]
-  type: testharness
-  [A constructed EventTarget can be used as expected]
-    expected: FAIL
-
-  [EventTarget can be subclassed]
-    expected: FAIL
-
-
-[EventTarget-constructible.any.worker.html]
-  type: testharness
-  [A constructed EventTarget can be used as expected]
-    expected: FAIL
-
-  [EventTarget can be subclassed]
-    expected: FAIL
-
--- a/testing/web-platform/meta/dom/interfaces.html.ini
+++ b/testing/web-platform/meta/dom/interfaces.html.ini
@@ -17,58 +17,19 @@
     bug: 931884
 
   [Element interface: element must inherit property "assignedSlot" with the proper type (48)]
     expected: FAIL
 
   [Text interface: document.createTextNode("abc") must inherit property "assignedSlot" with the proper type (2)]
     expected: FAIL
 
-  [EventTarget must be primary interface of new EventTarget()]
-    expected: FAIL
-
-  [Stringification of new EventTarget()]
-    expected: FAIL
-
-  [EventTarget interface: new EventTarget() must inherit property "addEventListener" with the proper type (0)]
-    expected: FAIL
-
-  [EventTarget interface: calling addEventListener(DOMString,EventListener,[object Object\],[object Object\]) on new EventTarget() with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [EventTarget interface: new EventTarget() must inherit property "removeEventListener" with the proper type (1)]
-    expected: FAIL
-
-  [EventTarget interface: calling removeEventListener(DOMString,EventListener,[object Object\],[object Object\]) on new EventTarget() with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [EventTarget interface: new EventTarget() must inherit property "dispatchEvent" with the proper type (2)]
-    expected: FAIL
-
-  [EventTarget interface: calling dispatchEvent(Event) on new EventTarget() with too few arguments must throw TypeError]
-    expected: FAIL
-
   [AbortSignal interface: new AbortController().signal must inherit property "onabort" with the proper type (1)]
     expected: FAIL
 
-  [EventTarget interface: new EventTarget() must inherit property "addEventListener(DOMString, EventListener, [object Object\],[object Object\])" with the proper type]
-    expected: FAIL
-
-  [EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object\],[object Object\]) on new EventTarget() with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [EventTarget interface: new EventTarget() must inherit property "removeEventListener(DOMString, EventListener, [object Object\],[object Object\])" with the proper type]
-    expected: FAIL
-
-  [EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object\],[object Object\]) on new EventTarget() with too few arguments must throw TypeError]
-    expected: FAIL
-
-  [EventTarget interface: new EventTarget() must inherit property "dispatchEvent(Event)" with the proper type]
-    expected: FAIL
-
   [AbortSignal interface: new AbortController().signal must inherit property "onabort" with the proper type]
     expected: FAIL
 
   [Document interface: new Document() must inherit property "origin" with the proper type]
     expected: FAIL
 
   [Document interface: xmlDoc must inherit property "origin" with the proper type]
     expected: FAIL
--- a/testing/web-platform/tests/eventsource/interfaces.html
+++ b/testing/web-platform/tests/eventsource/interfaces.html
@@ -4,17 +4,17 @@
 <script src=/resources/testharnessreport.js></script>
 <script src=/resources/WebIDLParser.js></script>
 <script src=/resources/idlharness.js></script>
 
 <h1>EventSource IDL tests</h1>
 <div id=log></div>
 
 <script type=text/plain>
-[Exposed=(Window,Worker)]
+[Constructor(), Exposed=(Window,Worker)]
 interface EventTarget {
   void addEventListener(DOMString type, EventListener? listener, optional (AddEventListenerOptions or boolean) options);
   void removeEventListener(DOMString type, EventListener? listener, optional (EventListenerOptions or boolean) options);
   boolean dispatchEvent(Event event);
 };
 callback interface EventListener {
   void handleEvent(Event event);
 };
--- a/testing/web-platform/tests/interfaces/dedicated-workers.idl
+++ b/testing/web-platform/tests/interfaces/dedicated-workers.idl
@@ -1,12 +1,12 @@
 // -----------------------------------------------------------------------------
 // DOM
 // -----------------------------------------------------------------------------
-[Exposed=(Window,Worker)]
+[Constructor(), Exposed=(Window,Worker)]
 interface EventTarget {
   void addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);
   void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
   boolean dispatchEvent(Event event);
 };
 
 callback interface EventListener {
   void handleEvent(Event event);
--- a/testing/web-platform/tests/service-workers/service-worker/resources/interfaces-idls.js
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/interfaces-idls.js
@@ -88,17 +88,17 @@ interface ServiceWorkerRegistration : Ev
 
   [NewObject] Promise<void> update();
   [NewObject] Promise<boolean> unregister();
 
   // event
   attribute EventHandler onupdatefound;
 };
 
-[Exposed=(Window,Worker)]
+[Constructor(), Exposed=(Window,Worker)]
 interface EventTarget {
   void addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);
   void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
   boolean dispatchEvent(Event event);
 };
 
 [SecureContext, Exposed=(Window,Worker)]
 interface NavigationPreloadManager {
--- a/testing/web-platform/tests/webrtc/RTCPeerConnection-idl.html
+++ b/testing/web-platform/tests/webrtc/RTCPeerConnection-idl.html
@@ -13,16 +13,17 @@
 <div id='log'></div>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script src=/resources/WebIDLParser.js></script>
 <script src=/resources/idlharness.js></script>
 
 <!-- The IDL is copied from the 22 September 2015 editors' draft. -->
 <script type="text/plain">
+[Constructor()]
 interface EventTarget {
     // Only a dummy definition is needed here.
 };
 [ Constructor (optional RTCConfiguration configuration)]
 interface RTCPeerConnection : EventTarget  {
     Promise<RTCSessionDescription> createOffer (optional RTCOfferOptions options);
     Promise<RTCSessionDescription> createAnswer (optional RTCAnswerOptions options);
     Promise<void>                  setLocalDescription (RTCSessionDescription description);