diff --git a/content/events/public/nsPIDOMEventTarget.h b/content/events/public/nsPIDOMEventTarget.h index 8ea8dd02a4a4..1e07d11a935d 100644 --- a/content/events/public/nsPIDOMEventTarget.h +++ b/content/events/public/nsPIDOMEventTarget.h @@ -47,16 +47,32 @@ class nsEventChainPreVisitor; class nsEventChainPostVisitor; class nsIEventListenerManager; -// 764756cd-8af2-4a25-919d-ca95759a1be1 +// 360fa72e-c709-42cc-9285-1f755ec90376 #define NS_PIDOMEVENTTARGET_IID \ -{ 0x764756cd, 0x8af2, 0x4a25, \ - { 0x91, 0x9d, 0xca, 0x95, 0x75, 0x9a, 0x1b, 0xe1 } } +{ 0x360fa72e, 0xc709, 0x42cc, \ + { 0x92, 0x85, 0x1f, 0x75, 0x5e, 0xc9, 0x03, 0x76 } } class nsPIDOMEventTarget : public nsISupports { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMEVENTTARGET_IID) + /** + * Returns the nsPIDOMEventTarget object which should be used as the target + * of DOMEvents. + * Usually |this| is returned, but for example global object returns + * the outer object. + */ + virtual nsPIDOMEventTarget* GetTargetForDOMEvent() { return this; } + + /** + * Returns the nsPIDOMEventTarget object which should be used as the target + * of the event and when constructing event target chain. + * Usually |this| is returned, but for example global object returns + * the inner object. + */ + virtual nsPIDOMEventTarget* GetTargetForEventTargetChain() { return this; } + /** * Called before the capture phase of the event flow. * This is used to create the event target chain and implementations diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index 138c0b57d611..d459d0df893d 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -170,23 +170,31 @@ NS_METHOD nsDOMEvent::GetType(nsAString& aType) return NS_ERROR_FAILURE; } -NS_METHOD nsDOMEvent::GetTarget(nsIDOMEventTarget** aTarget) +static nsresult +GetDOMEventTarget(nsISupports* aTarget, + nsIDOMEventTarget** aDOMTarget) { - if (mEvent->target) { - return CallQueryInterface(mEvent->target, aTarget); + nsCOMPtr piTarget = do_QueryInterface(aTarget); + nsISupports* realTarget = + piTarget ? piTarget->GetTargetForDOMEvent() : aTarget; + if (realTarget) { + return CallQueryInterface(realTarget, aDOMTarget); } - *aTarget = nsnull; + + *aDOMTarget = nsnull; return NS_OK; } +NS_METHOD +nsDOMEvent::GetTarget(nsIDOMEventTarget** aTarget) +{ + return GetDOMEventTarget(mEvent->target, aTarget); +} + NS_IMETHODIMP nsDOMEvent::GetCurrentTarget(nsIDOMEventTarget** aCurrentTarget) { - if (mEvent->currentTarget) { - return CallQueryInterface(mEvent->currentTarget, aCurrentTarget); - } - *aCurrentTarget = nsnull; - return NS_OK; + return GetDOMEventTarget(mEvent->currentTarget, aCurrentTarget); } // @@ -241,7 +249,7 @@ NS_IMETHODIMP nsDOMEvent::GetOriginalTarget(nsIDOMEventTarget** aOriginalTarget) { if (mEvent->originalTarget) { - return CallQueryInterface(mEvent->originalTarget, aOriginalTarget); + return GetDOMEventTarget(mEvent->originalTarget, aOriginalTarget); } return GetTarget(aOriginalTarget); diff --git a/content/events/src/nsEventDispatcher.cpp b/content/events/src/nsEventDispatcher.cpp index c793d477349f..91171597ba59 100644 --- a/content/events/src/nsEventDispatcher.cpp +++ b/content/events/src/nsEventDispatcher.cpp @@ -111,7 +111,7 @@ public: return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH); } - nsISupports* CurrentTarget() + nsPIDOMEventTarget* CurrentTarget() { return mTarget; } @@ -157,8 +157,12 @@ public: nsEventTargetChainItem::nsEventTargetChainItem(nsISupports* aTarget, nsEventTargetChainItem* aChild) -: mTarget(do_QueryInterface(aTarget)), mChild(aChild), mParent(nsnull), mFlags(0), mItemFlags(0) +: mChild(aChild), mParent(nsnull), mFlags(0), mItemFlags(0) { + nsCOMPtr t = do_QueryInterface(aTarget); + if (t) { + mTarget = t->GetTargetForEventTargetChain(); + } if (mChild) { mChild->mParent = this; } @@ -197,9 +201,8 @@ nsEventTargetChainItem::HandleEvent(nsEventChainPostVisitor& aVisitor, { nsCOMPtr lm; mTarget->GetListenerManager(PR_FALSE, getter_AddRefs(lm)); - - if (lm) { - aVisitor.mEvent->currentTarget = CurrentTarget(); + aVisitor.mEvent->currentTarget = CurrentTarget()->GetTargetForDOMEvent(); + if (lm && aVisitor.mEvent->currentTarget) { lm->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent, &aVisitor.mDOMEvent, aVisitor.mEvent->currentTarget, aFlags, &aVisitor.mEventStatus); @@ -408,11 +411,20 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget, // Make sure that nsIDOMEvent::target and nsIDOMNSEvent::originalTarget // point to the last item in the chain. - // XXX But if the target is already set, use that. This is a hack - // for the 'load', 'beforeunload' and 'unload' events, - // which are dispatched to |window| but have document as their target. if (!aEvent->target) { - aEvent->target = aTarget; + // Note, CurrentTarget() points always to the object returned by + // GetTargetForEventTargetChain(). + aEvent->target = targetEtci->CurrentTarget(); + } else { + // XXX But if the target is already set, use that. This is a hack + // for the 'load', 'beforeunload' and 'unload' events, + // which are dispatched to |window| but have document as their target. + // + // Make sure that the event target points to the right object. + nsCOMPtr t = do_QueryInterface(aEvent->target); + NS_ENSURE_STATE(t); + aEvent->target = t->GetTargetForEventTargetChain(); + NS_ENSURE_STATE(aEvent->target); } aEvent->originalTarget = aEvent->target; diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 4b436879aa97..f74c30b1868f 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -1869,7 +1869,7 @@ nsGlobalWindow::GetGlobalObjectOwner() nsresult nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor) { - FORWARD_TO_INNER(PreHandleEvent, (aVisitor), NS_OK); + NS_PRECONDITION(IsInnerWindow(), "PreHandleEvent is used on outer window!?"); static PRUint32 count = 0; PRUint32 msg = aVisitor.mEvent->message; @@ -1901,7 +1901,7 @@ nsGlobalWindow::PreHandleEvent(nsEventChainPreVisitor& aVisitor) nsresult nsGlobalWindow::PostHandleEvent(nsEventChainPostVisitor& aVisitor) { - FORWARD_TO_INNER(PostHandleEvent, (aVisitor), NS_OK); + NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?"); /* mChromeEventHandler and mContext go dangling in the middle of this function under some circumstances (events that destroy the window) without this addref. */ diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h index a121e1f07fdd..7c0fbb555d97 100644 --- a/dom/src/base/nsGlobalWindow.h +++ b/dom/src/base/nsGlobalWindow.h @@ -308,6 +308,14 @@ public: virtual NS_HIDDEN_(PRBool) WouldReuseInnerWindow(nsIDocument *aNewDocument); + virtual NS_HIDDEN_(nsPIDOMEventTarget*) GetTargetForDOMEvent() + { + return NS_STATIC_CAST(nsPIDOMEventTarget*, GetOuterWindowInternal()); + } + virtual NS_HIDDEN_(nsPIDOMEventTarget*) GetTargetForEventTargetChain() + { + return NS_STATIC_CAST(nsPIDOMEventTarget*, GetCurrentInnerWindowInternal()); + } virtual NS_HIDDEN_(nsresult) PreHandleEvent(nsEventChainPreVisitor& aVisitor); virtual NS_HIDDEN_(nsresult) PostHandleEvent(nsEventChainPostVisitor& aVisitor); virtual NS_HIDDEN_(nsresult) DispatchDOMEvent(nsEvent* aEvent,