Bug 865377. Give EventTarget a chrome-only getter that returns its global. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 30 May 2013 17:46:39 -0400
changeset 133498 a6de622f95744e724e08f448a6489ee272ad5463
parent 133497 d921692be88fb0f5876b216956c7c814917347f1
child 133499 eb910ddfc5bbf8878667dfaa1da494cf73017a49
push id28781
push userbzbarsky@mozilla.com
push dateThu, 30 May 2013 21:48:08 +0000
treeherdermozilla-inbound@a3f8d2127f2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs865377
milestone24.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 865377. Give EventTarget a chrome-only getter that returns its global. r=smaug The idea is that you then do things like t.dispatchEvent(new t.ownerGlobal.Event("something")).
content/base/public/nsINode.h
content/base/src/nsINode.cpp
content/events/public/EventTarget.h
content/events/src/nsDOMEventTargetHelper.h
dom/base/nsGlobalWindow.h
dom/base/nsPIDOMWindow.h
dom/base/nsPIWindowRoot.h
dom/base/nsWindowRoot.cpp
dom/base/nsWindowRoot.h
dom/bindings/Bindings.conf
dom/webidl/EventTarget.webidl
dom/workers/EventTarget.h
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -807,16 +807,17 @@ public:
   using mozilla::dom::EventTarget::RemoveEventListener;
   using nsIDOMEventTarget::AddEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 nsIDOMEventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
   using nsIDOMEventTarget::AddSystemEventListener;
+  virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE;
 
   /**
    * Adds a mutation observer to be notified when this node, or any of its
    * descendants, are modified. The node will hold a weak reference to the
    * observer, which means that it is the responsibility of the observer to
    * remove itself in case it dies before the node.  If an observer is added
    * while observers are being notified, it may also be notified.  In general,
    * adding observers while inside a notification is not a good idea.  An
--- a/content/base/src/nsINode.cpp
+++ b/content/base/src/nsINode.cpp
@@ -99,16 +99,17 @@
 #include "nsCSSRuleProcessor.h"
 #include "nsCSSParser.h"
 #include "HTMLLegendElement.h"
 #include "nsWrapperCacheInlines.h"
 #include "WrapperFactory.h"
 #include "DocumentType.h"
 #include <algorithm>
 #include "nsDOMEvent.h"
+#include "nsGlobalWindow.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 nsINode::nsSlots::~nsSlots()
 {
   if (mChildNodes) {
     mChildNodes->DropReference();
@@ -1158,16 +1159,24 @@ nsINode::GetListenerManager(bool aCreate
 }
 
 nsIScriptContext*
 nsINode::GetContextForEventHandlers(nsresult* aRv)
 {
   return nsContentUtils::GetContextForEventHandlers(this, aRv);
 }
 
+nsIDOMWindow*
+nsINode::GetOwnerGlobal()
+{
+  bool dummy;
+  return nsPIDOMWindow::GetOuterFromCurrentInner(
+    static_cast<nsGlobalWindow*>(OwnerDoc()->GetScriptHandlingObject(dummy)));
+}
+
 bool
 nsINode::UnoptimizableCCNode() const
 {
   const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS |
                                       NODE_IS_IN_ANONYMOUS_SUBTREE |
                                       NODE_IS_NATIVE_ANONYMOUS_ROOT |
                                       NODE_MAY_BE_IN_BINDING_MNGR |
                                       NODE_IS_INSERTION_PARENT);
--- a/content/events/public/EventTarget.h
+++ b/content/events/public/EventTarget.h
@@ -9,16 +9,17 @@
 #include "nsIDOMEventTarget.h"
 #include "nsWrapperCache.h"
 #include "nsIDOMEventListener.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/Nullable.h"
 #include "nsIAtom.h"
 
 class nsDOMEvent;
+class nsIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class EventListener;
 class EventHandlerNonNull;
 
 // IID for the dom::EventTarget interface
@@ -59,16 +60,21 @@ public:
     nsCOMPtr<nsIAtom> type = do_GetAtom(aType);
     return SetEventHandler(type, aHandler, rv);
   }
 
   // Note, for an event 'foo' aType will be 'onfoo'.
   virtual void EventListenerAdded(nsIAtom* aType) {}
   virtual void EventListenerRemoved(nsIAtom* aType) {}
 
+  // Returns an outer window that corresponds to the inner window this event
+  // target is associated with.  Will return null if the inner window is not the
+  // current inner or if there is no window around at all.
+  virtual nsIDOMWindow* GetOwnerGlobal() = 0;
+
 protected:
   EventHandlerNonNull* GetEventHandler(nsIAtom* aType);
   void SetEventHandler(nsIAtom* aType, EventHandlerNonNull* aHandler,
                        ErrorResult& rv);
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(EventTarget, NS_EVENTTARGET_IID)
 
--- a/content/events/src/nsDOMEventTargetHelper.h
+++ b/content/events/src/nsDOMEventTargetHelper.h
@@ -90,16 +90,20 @@ public:
   nsresult SetEventHandler(nsIAtom* aType,
                            JSContext* aCx,
                            const JS::Value& aValue);
   using mozilla::dom::EventTarget::SetEventHandler;
   void GetEventHandler(nsIAtom* aType,
                        JSContext* aCx,
                        JS::Value* aValue);
   using mozilla::dom::EventTarget::GetEventHandler;
+  virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE
+  {
+    return nsPIDOMWindow::GetOuterFromCurrentInner(GetOwner());
+  }
 
   nsresult CheckInnerWindowCorrectness()
   {
     NS_ENSURE_STATE(!mHasOrHasHadOwnerWindow || mOwnerWindow);
     if (mOwnerWindow) {
       NS_ASSERTION(mOwnerWindow->IsInnerWindow(), "Should have inner window here!\n");
       nsPIDOMWindow* outer = mOwnerWindow->GetOuterWindow();
       if (!outer || outer->GetCurrentInnerWindow() != mOwnerWindow) {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -387,16 +387,24 @@ public:
   // nsIDOMEventTarget
   NS_DECL_NSIDOMEVENTTARGET
   using mozilla::dom::EventTarget::RemoveEventListener;
   virtual void AddEventListener(const nsAString& aType,
                                 nsIDOMEventListener* aListener,
                                 bool aUseCapture,
                                 const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                 mozilla::ErrorResult& aRv) MOZ_OVERRIDE;
+  virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE
+  {
+    if (IsOuterWindow()) {
+      return this;
+    }
+
+    return GetOuterFromCurrentInner(this);
+  }
 
   // nsITouchEventReceiver
   NS_DECL_NSITOUCHEVENTRECEIVER
 
   // nsIInlineEventHandlers
   NS_DECL_NSIINLINEEVENTHANDLERS
 
   // nsPIDOMWindow
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -53,18 +53,18 @@ class nsPIWindowRoot;
 
 namespace mozilla {
 namespace dom {
 class AudioContext;
 }
 }
 
 #define NS_PIDOMWINDOW_IID \
-{ 0x7202842a, 0x0e24, 0x46dc, \
-  { 0xb2, 0x25, 0xd2, 0x9d, 0x28, 0xda, 0x87, 0xd8 } }
+{ 0xc7f20d00, 0xed38, 0x4d60, \
+ { 0x90, 0xf6, 0x3e, 0xde, 0x7b, 0x71, 0xc3, 0xb3 } }
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -640,16 +640,32 @@ public:
    * Like nsIDOMWindow::Open, except that we don't navigate to the given URL.
    */
   virtual nsresult
   OpenNoNavigate(const nsAString& aUrl, const nsAString& aName,
                  const nsAString& aOptions, nsIDOMWindow **_retval) = 0;
 
   void AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
 
+  // Given an inner window, return its outer if the inner is the current inner.
+  // Otherwise (argument null or not an inner or not current) return null.
+  static nsPIDOMWindow* GetOuterFromCurrentInner(nsPIDOMWindow* aInner)
+  {
+    if (!aInner) {
+      return nullptr;
+    }
+
+    nsPIDOMWindow* outer = aInner->GetOuterWindow();
+    if (!outer || outer->GetCurrentInnerWindow() != aInner) {
+      return nullptr;
+    }
+
+    return outer;
+  }
+
   // WebIDL-ish APIs
   nsPerformance* GetPerformance();
 
 protected:
   // The nsPIDOMWindow constructor. The aOuterWindow argument should
   // be null if and only if the created window itself is an outer
   // window. In all other cases aOuterWindow should be the outer
   // window for the inner window that is being created.
--- a/dom/base/nsPIWindowRoot.h
+++ b/dom/base/nsPIWindowRoot.h
@@ -10,20 +10,19 @@
 #include "nsISupports.h"
 #include "mozilla/dom/EventTarget.h"
 
 class nsPIDOMWindow;
 class nsIControllers;
 class nsIController;
 struct JSContext;
 
-// 426C1B56-E38A-435E-B291-BE1557F2A0A2
 #define NS_IWINDOWROOT_IID \
-{ 0xc89780f2, 0x8905, 0x417f, \
-  { 0xa6, 0x62, 0xf6, 0xc, 0xa6, 0xd7, 0xc, 0x91 } }
+{ 0x3f71f50c, 0xa7e0, 0x43bc, \
+ { 0xac, 0x25, 0x4d, 0xbb, 0x88, 0x7b, 0x21, 0x09 } }
 
 class nsPIWindowRoot : public mozilla::dom::EventTarget
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID)
 
   virtual nsPIDOMWindow* GetWindow()=0;
 
@@ -32,13 +31,14 @@ public:
   virtual void SetPopupNode(nsIDOMNode* aNode) = 0;
 
   virtual nsresult GetControllerForCommand(const char *aCommand,
                                            nsIController** aResult) = 0;
   virtual nsresult GetControllers(nsIControllers** aResult) = 0;
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) = 0;
   virtual mozilla::dom::EventTarget* GetParentTarget() = 0;
+  virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsPIWindowRoot, NS_IWINDOWROOT_IID)
 
 #endif // nsPIWindowRoot_h__
--- a/dom/base/nsWindowRoot.cpp
+++ b/dom/base/nsWindowRoot.cpp
@@ -174,16 +174,22 @@ nsWindowRoot::PreHandleEvent(nsEventChai
 }
 
 nsresult
 nsWindowRoot::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
   return NS_OK;
 }
 
+nsIDOMWindow*
+nsWindowRoot::GetOwnerGlobal()
+{
+  return GetWindow();
+}
+
 nsPIDOMWindow*
 nsWindowRoot::GetWindow()
 {
   return mWindow;
 }
 
 nsresult
 nsWindowRoot::GetControllers(nsIControllers** aResult)
--- a/dom/base/nsWindowRoot.h
+++ b/dom/base/nsWindowRoot.h
@@ -45,16 +45,17 @@ public:
   virtual nsIDOMNode* GetPopupNode();
   virtual void SetPopupNode(nsIDOMNode* aNode);
 
   virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget)
   {
     mParent = aTarget;
   }
   virtual mozilla::dom::EventTarget* GetParentTarget() { return mParent; }
+  virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE;
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsWindowRoot,
                                                          nsIDOMEventTarget)
 
 protected:
   // Members
   nsPIDOMWindow* mWindow; // [Weak]. The window will hold on to us and let go when it dies.
   nsRefPtr<nsEventListenerManager> mListenerManager; // [Strong]. We own the manager, which owns event listeners attached
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1208,16 +1208,27 @@ DOMInterfaces = {
     'implicitJSContext': [ 'constructor' ]
 },
 
 'WheelEvent': {
     'headerFile': 'DOMWheelEvent.h',
     'nativeType': 'mozilla::dom::DOMWheelEvent',
 },
 
+'WindowProxy': [
+{
+    'nativeType': 'nsIDOMWindow',
+    'concrete': False
+},
+{
+    # We need a worker descriptor for WindowProxy because EventTarget exists in
+    # workers.  But it's an external interface, so it'll just map to JSObject*.
+    'workers': True
+}],
+
 'XMLHttpRequest': [
 {
     'nativeType': 'nsXMLHttpRequest',
     'implicitJSContext': [ 'constructor', ],
     'resultNotAddRefed': [ 'upload', 'responseXML' ]
 },
 {
     'workers': True,
@@ -1611,14 +1622,13 @@ addExternalIface('SVGAnimatedNumber')
 addExternalIface('SVGAnimatedString')
 addExternalIface('SVGLength')
 addExternalIface('SVGNumber')
 addExternalIface('TouchList', headerFile='nsIDOMTouchEvent.h')
 addExternalIface('URI', nativeType='nsIURI', headerFile='nsIURI.h',
                  notflattened=True)
 addExternalIface('UserDataHandler')
 addExternalIface('Window')
-addExternalIface('WindowProxy', nativeType='nsIDOMWindow')
 addExternalIface('XPathResult', nativeType='nsISupports')
 addExternalIface('XPathExpression')
 addExternalIface('XPathNSResolver')
 addExternalIface('XULCommandDispatcher')
 addExternalIface('DataTransfer', notflattened=True)
--- a/dom/webidl/EventTarget.webidl
+++ b/dom/webidl/EventTarget.webidl
@@ -32,8 +32,16 @@ interface EventTarget {
 // implement on* properties.
 partial interface EventTarget {
   [ChromeOnly, Throws]
   void setEventHandler(DOMString type, EventHandler handler);
 
   [ChromeOnly]
   EventHandler getEventHandler(DOMString type);
 };
+
+// Mozilla extension to make firing events on event targets from
+// chrome easier.  This returns the window which can be used to create
+// events to fire at this EventTarget, or null if there isn't one.
+partial interface EventTarget {
+  [ChromeOnly]
+  readonly attribute WindowProxy? ownerGlobal;
+};
--- a/dom/workers/EventTarget.h
+++ b/dom/workers/EventTarget.h
@@ -69,13 +69,19 @@ public:
   {
     rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   }
 
   JSObject* GetEventHandler(JSContext*, const nsAString& aType)
   {
     return nullptr;
   }
+
+  JSObject* GetOwnerGlobal() const
+  {
+    // We have no windows
+    return nullptr;
+  }
 };
 
 END_WORKERS_NAMESPACE
 
 #endif // mozilla_dom_workers_eventtarget_h__