diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index a34c8b027f9..31bf9dc6aeb 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -3931,6 +3931,9 @@ nsDocument::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + nsresult mRet = NS_OK; PRBool externalDOMEvent = PR_FALSE; @@ -3997,6 +4000,10 @@ nsDocument::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, } aDOMEvent = nsnull; } + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return mRet; diff --git a/content/base/src/nsGenericDOMDataNode.cpp b/content/base/src/nsGenericDOMDataNode.cpp index 74d79ab0abe..fa6bfc1a90f 100644 --- a/content/base/src/nsGenericDOMDataNode.cpp +++ b/content/base/src/nsGenericDOMDataNode.cpp @@ -736,6 +736,9 @@ nsGenericDOMDataNode::HandleDOMEvent(nsPresContext* aPresContext, PRUint32 aFlags, nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + nsresult ret = NS_OK; nsIDOMEvent* domEvent = nsnull; @@ -815,6 +818,10 @@ nsGenericDOMDataNode::HandleDOMEvent(nsPresContext* aPresContext, } aDOMEvent = nsnull; + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return ret; diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 88aa1b0d57c..89e500d7886 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -1972,6 +1972,9 @@ nsGenericElement::HandleDOMEvent(nsPresContext* aPresContext, PRUint32 aFlags, nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + nsresult ret = NS_OK; PRBool retarget = PR_FALSE; PRBool externalDOMEvent = PR_FALSE; @@ -2196,6 +2199,10 @@ nsGenericElement::HandleDOMEvent(nsPresContext* aPresContext, aDOMEvent = nsnull; } + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return ret; diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index b4b74b76727..1033bc7a0b2 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -53,6 +53,7 @@ #include "nsMutationEvent.h" #include "nsContentUtils.h" #include "nsIURI.h" +#include "nsIScriptSecurityManager.h" static const char* const sEventNames[] = { "mousedown", "mouseup", "click", "dblclick", "mouseover", @@ -382,7 +383,7 @@ nsDOMEvent::PreventDefault() nsresult nsDOMEvent::SetEventType(const nsAString& aEventTypeArg) { - nsCOMPtr atom= do_GetAtom(NS_LITERAL_STRING("on") + aEventTypeArg); + nsCOMPtr atom = do_GetAtom(NS_LITERAL_STRING("on") + aEventTypeArg); mEvent->message = NS_USER_DEFINED_EVENT; if (mEvent->eventStructType == NS_MOUSE_EVENT) { @@ -473,9 +474,33 @@ nsDOMEvent::SetEventType(const nsAString& aEventTypeArg) NS_IMETHODIMP nsDOMEvent::InitEvent(const nsAString& aEventTypeArg, PRBool aCanBubbleArg, PRBool aCancelableArg) { + // Make sure this event isn't already being dispatched. + NS_ENSURE_TRUE(!NS_IS_EVENT_IN_DISPATCH(mEvent), NS_ERROR_INVALID_ARG); + + if (NS_IS_TRUSTED_EVENT(mEvent)) { + // Ensure the caller is permitted to dispatch trusted DOM events. + + PRBool enabled = PR_FALSE; + nsContentUtils::GetSecurityManager()-> + IsCapabilityEnabled("UniversalBrowserWrite", &enabled); + + if (!enabled) { + SetTrusted(PR_FALSE); + } + } + NS_ENSURE_SUCCESS(SetEventType(aEventTypeArg), NS_ERROR_FAILURE); - mEvent->flags |= aCanBubbleArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_BUBBLE; - mEvent->flags |= aCancelableArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_CANCEL; + + mEvent->flags |= + aCanBubbleArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_BUBBLE; + mEvent->flags |= + aCancelableArg ? NS_EVENT_FLAG_NONE : NS_EVENT_FLAG_CANT_CANCEL; + + // Unset the NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY bit (which is + // set at the end of event dispatch) so that this event can be + // dispatched. + mEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY; + return NS_OK; } diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index aaadc6e99d9..12721fd3214 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -4319,19 +4319,36 @@ nsEventStateManager::DispatchNewEvent(nsISupports* aTarget, nsCOMPtr privEvt(do_QueryInterface(aEvent)); if (privEvt) { + nsEvent * innerEvent; + privEvt->GetInternalNSEvent(&innerEvent); + + NS_ENSURE_TRUE(innerEvent, NS_ERROR_ILLEGAL_VALUE); + + // Make sure this event isn't currently in dispatch. + NS_ENSURE_TRUE(!NS_IS_EVENT_IN_DISPATCH(innerEvent), + NS_ERROR_ILLEGAL_VALUE); + + // And make sure this event wasn't already dispatched w/o being + // re-initialized in between. + NS_ENSURE_TRUE(!(innerEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY), + NS_ERROR_ILLEGAL_VALUE); + + // Mark this event as dispatched now that we're this far along. + NS_MARK_EVENT_DISPATCH_STARTED(innerEvent); + nsCOMPtr eventTarget(do_QueryInterface(aTarget)); privEvt->SetTarget(eventTarget); - //Check security state to determine if dispatcher is trusted - nsIScriptSecurityManager *securityManager = - nsContentUtils::GetSecurityManager(); - PRBool trusted; nsCOMPtr nsevent(do_QueryInterface(privEvt)); nsevent->GetIsTrusted(&trusted); if (!trusted) { + //Check security state to determine if dispatcher is trusted + nsIScriptSecurityManager *securityManager = + nsContentUtils::GetSecurityManager(); + PRBool enabled; nsresult res = securityManager->IsCapabilityEnabled("UniversalBrowserWrite", @@ -4339,45 +4356,45 @@ nsEventStateManager::DispatchNewEvent(nsISupports* aTarget, privEvt->SetTrusted(NS_SUCCEEDED(res) && enabled); } - nsEvent * innerEvent; - privEvt->GetInternalNSEvent(&innerEvent); - - if (innerEvent) { - nsEventStatus status = nsEventStatus_eIgnore; - nsCOMPtr target(do_QueryInterface(aTarget)); + nsEventStatus status = nsEventStatus_eIgnore; + nsCOMPtr target(do_QueryInterface(aTarget)); + if (target) { + ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, + NS_EVENT_FLAG_INIT, &status); + } + else { + nsCOMPtr target(do_QueryInterface(aTarget)); if (target) { - ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, NS_EVENT_FLAG_INIT, &status); + ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, + NS_EVENT_FLAG_INIT, &status); } else { - nsCOMPtr target(do_QueryInterface(aTarget)); + nsCOMPtr target(do_QueryInterface(aTarget)); if (target) { - ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, NS_EVENT_FLAG_INIT, &status); + ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, + NS_EVENT_FLAG_INIT, &status); + + // Dispatch to the system event group. Make sure to clear + // the STOP_DISPATCH flag since this resets for each event + // group per DOM3 Events. + + innerEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH; + ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, + NS_EVENT_FLAG_INIT | + NS_EVENT_FLAG_SYSTEM_EVENT, + &status); } else { - nsCOMPtr target(do_QueryInterface(aTarget)); + nsCOMPtr target(do_QueryInterface(aTarget)); if (target) { - ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, NS_EVENT_FLAG_INIT, &status); - - // Dispatch to the system event group. Make sure to clear the - // STOP_DISPATCH flag since this resets for each event group - // per DOM3 Events. - - innerEvent->flags &= ~NS_EVENT_FLAG_STOP_DISPATCH; - ret = target->HandleDOMEvent(mPresContext, innerEvent, &aEvent, - NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_SYSTEM_EVENT, - &status); - } - else { - nsCOMPtr target(do_QueryInterface(aTarget)); - if (target) { - ret = target->HandleChromeEvent(mPresContext, innerEvent, &aEvent, NS_EVENT_FLAG_INIT, &status); - } + ret = target->HandleChromeEvent(mPresContext, innerEvent, &aEvent, + NS_EVENT_FLAG_INIT, &status); } } } - - *aDefaultActionEnabled = status != nsEventStatus_eConsumeNoDefault; } + + *aDefaultActionEnabled = status != nsEventStatus_eConsumeNoDefault; } return ret; diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 9756077cf05..6a32e5c16ba 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1998,6 +1998,9 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + nsresult ret = NS_OK; PRBool retarget = PR_FALSE; @@ -2031,10 +2034,10 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, } if (aDOMEvent) { if (*aDOMEvent) - externalDOMEvent = PR_TRUE; + externalDOMEvent = PR_TRUE; } else - aDOMEvent = &domEvent; + aDOMEvent = &domEvent; aEvent->flags |= aFlags; aFlags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL); @@ -2077,21 +2080,21 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, // menu), then that breaks. nsCOMPtr privateEvent = do_QueryInterface(domEvent); if (privateEvent) { - nsCOMPtr target(do_QueryInterface(NS_STATIC_CAST(nsIContent *, this))); - privateEvent->SetTarget(target); + nsCOMPtr target(do_QueryInterface(NS_STATIC_CAST(nsIContent *, this))); + privateEvent->SetTarget(target); } else - return NS_ERROR_FAILURE; + return NS_ERROR_FAILURE; // if we are a XUL click, we have the private event set. // now switch to a left mouse click for the duration of the event if (aEvent->message == NS_XUL_CLICK) - aEvent->message = NS_MOUSE_LEFT_CLICK; + aEvent->message = NS_MOUSE_LEFT_CLICK; } } } else if (aEvent->message == NS_IMAGE_LOAD) - return NS_OK; // Don't let these events bubble or be captured. Just allow them + return NS_OK; // Don't let these events bubble or be captured. Just allow them // on the target image. // Find out whether we're anonymous. @@ -2129,60 +2132,62 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, } if (retarget || (parent != GetParent())) { - if (!*aDOMEvent) { - // We haven't made a DOMEvent yet. Force making one now. - nsCOMPtr listenerManager; - if (NS_FAILED(ret = GetListenerManager(getter_AddRefs(listenerManager)))) { - return ret; - } - nsAutoString empty; - if (NS_FAILED(ret = listenerManager->CreateEvent(aPresContext, aEvent, empty, aDOMEvent))) - return ret; - if (!*aDOMEvent) { + // We haven't made a DOMEvent yet. Force making one now. + nsCOMPtr listenerManager; + if (NS_FAILED(ret = GetListenerManager(getter_AddRefs(listenerManager)))) { + return ret; + } + nsAutoString empty; + if (NS_FAILED(ret = listenerManager->CreateEvent(aPresContext, aEvent, empty, aDOMEvent))) + return ret; + + if (!*aDOMEvent) { + return NS_ERROR_FAILURE; + } + } + + nsCOMPtr privateEvent = + do_QueryInterface(*aDOMEvent); + if (!privateEvent) { return NS_ERROR_FAILURE; } - } - nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); - if (!privateEvent) { - return NS_ERROR_FAILURE; - } + (*aDOMEvent)->GetTarget(getter_AddRefs(oldTarget)); - (*aDOMEvent)->GetTarget(getter_AddRefs(oldTarget)); + PRBool hasOriginal; + privateEvent->HasOriginalTarget(&hasOriginal); - PRBool hasOriginal; - privateEvent->HasOriginalTarget(&hasOriginal); + if (!hasOriginal) + privateEvent->SetOriginalTarget(oldTarget); - if (!hasOriginal) - privateEvent->SetOriginalTarget(oldTarget); - - if (retarget) { - nsCOMPtr target = do_QueryInterface(GetParent()); - privateEvent->SetTarget(target); + if (retarget) { + nsCOMPtr target = + do_QueryInterface(GetParent()); + privateEvent->SetTarget(target); } } //Capturing stage evaluation if (NS_EVENT_FLAG_CAPTURE & aFlags) { - //Initiate capturing phase. Special case first call to document - if (parent) { - parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, aFlags & NS_EVENT_CAPTURE_MASK, aEventStatus); - } - else if (doc) { - ret = doc->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, - aFlags & NS_EVENT_CAPTURE_MASK, - aEventStatus); - } + //Initiate capturing phase. Special case first call to document + if (parent) { + parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, aFlags & NS_EVENT_CAPTURE_MASK, aEventStatus); + } + else if (doc) { + ret = doc->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, + aFlags & NS_EVENT_CAPTURE_MASK, + aEventStatus); + } } if (retarget) { - // The event originated beneath us, and we performed a retargeting. - // We need to restore the original target of the event. - nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); - if (privateEvent) - privateEvent->SetTarget(oldTarget); + // The event originated beneath us, and we performed a retargeting. + // We need to restore the original target of the event. + nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); + if (privateEvent) + privateEvent->SetTarget(oldTarget); } //Local handling stage @@ -2194,12 +2199,14 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, } if (retarget) { - // The event originated beneath us, and we need to perform a retargeting. - nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); - if (privateEvent) { - nsCOMPtr parentTarget(do_QueryInterface(GetParent())); - privateEvent->SetTarget(parentTarget); - } + // The event originated beneath us, and we need to perform a + // retargeting. + nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); + if (privateEvent) { + nsCOMPtr parentTarget = + do_QueryInterface(GetParent()); + privateEvent->SetTarget(parentTarget); + } } //Bubbling stage @@ -2207,7 +2214,7 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, if (parent != nsnull) { // We have a parent. Let them field the event. ret = parent->HandleDOMEvent(aPresContext, aEvent, aDOMEvent, - aFlags & NS_EVENT_BUBBLE_MASK, aEventStatus); + aFlags & NS_EVENT_BUBBLE_MASK, aEventStatus); } else if (IsInDoc()) { // We must be the document root. The event should bubble to the @@ -2218,33 +2225,37 @@ nsXULElement::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, } if (retarget) { - // The event originated beneath us, and we performed a retargeting. - // We need to restore the original target of the event. - nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); - if (privateEvent) - privateEvent->SetTarget(oldTarget); + // The event originated beneath us, and we performed a retargeting. + // We need to restore the original target of the event. + nsCOMPtr privateEvent = do_QueryInterface(*aDOMEvent); + if (privateEvent) + privateEvent->SetTarget(oldTarget); } if (NS_EVENT_FLAG_INIT & aFlags) { - // We're leaving the DOM event loop so if we created a DOM event, - // release here. If externalDOMEvent is set the event was passed in - // and we don't own it - if (*aDOMEvent && !externalDOMEvent) { - nsrefcnt rc; - NS_RELEASE2(*aDOMEvent, rc); - if (0 != rc) { - // Okay, so someone in the DOM loop (a listener, JS object) - // still has a ref to the DOM Event but the internal data - // hasn't been malloc'd. Force a copy of the data here so the - // DOM Event is still valid. - nsCOMPtr privateEvent = - do_QueryInterface(*aDOMEvent); - if (privateEvent) { - privateEvent->DuplicatePrivateData(); - } + // We're leaving the DOM event loop so if we created a DOM event, + // release here. If externalDOMEvent is set the event was passed in + // and we don't own it + if (*aDOMEvent && !externalDOMEvent) { + nsrefcnt rc; + NS_RELEASE2(*aDOMEvent, rc); + if (0 != rc) { + // Okay, so someone in the DOM loop (a listener, JS object) + // still has a ref to the DOM Event but the internal data + // hasn't been malloc'd. Force a copy of the data here so the + // DOM Event is still valid. + nsCOMPtr privateEvent = + do_QueryInterface(*aDOMEvent); + if (privateEvent) { + privateEvent->DuplicatePrivateData(); + } + } + aDOMEvent = nsnull; } - aDOMEvent = nsnull; - } + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return ret; diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index 959e73604bc..2634a24442c 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -1201,11 +1201,14 @@ nsXULDocument::ContentRemoved(nsIContent* aContainer, nsresult nsXULDocument::HandleDOMEvent(nsPresContext* aPresContext, - nsEvent* aEvent, - nsIDOMEvent** aDOMEvent, - PRUint32 aFlags, - nsEventStatus* aEventStatus) + nsEvent* aEvent, + nsIDOMEvent** aDOMEvent, + PRUint32 aFlags, + nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + nsresult ret = NS_OK; nsIDOMEvent* domEvent = nsnull; PRBool externalDOMEvent = PR_FALSE; @@ -1266,6 +1269,10 @@ nsXULDocument::HandleDOMEvent(nsPresContext* aPresContext, } } aDOMEvent = nsnull; + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return ret; diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 056cc33873b..4b371f8219c 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -814,6 +814,9 @@ nsGlobalWindow::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + nsresult ret = NS_OK; PRBool externalDOMEvent = PR_FALSE; nsIDOMEvent *domEvent = nsnull; @@ -991,6 +994,10 @@ nsGlobalWindow::HandleDOMEvent(nsPresContext* aPresContext, nsEvent* aEvent, } aDOMEvent = nsnull; } + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } mCurrentEvent = oldEvent; diff --git a/dom/src/base/nsWindowRoot.cpp b/dom/src/base/nsWindowRoot.cpp index c1474d7e2f7..873755b1128 100644 --- a/dom/src/base/nsWindowRoot.cpp +++ b/dom/src/base/nsWindowRoot.cpp @@ -226,10 +226,14 @@ nsWindowRoot::GetSystemEventGroup(nsIDOMEventGroup **aGroup) return NS_ERROR_FAILURE; } -NS_IMETHODIMP nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, - nsEvent* aEvent, nsIDOMEvent** aDOMEvent, PRUint32 aFlags, - nsEventStatus* aEventStatus) +NS_IMETHODIMP +nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, nsEvent* aEvent, + nsIDOMEvent** aDOMEvent, PRUint32 aFlags, + nsEventStatus* aEventStatus) { + // Make sure to tell the event that dispatch has started. + NS_MARK_EVENT_DISPATCH_STARTED(aEvent); + // Prevent the world from going // away until after we've finished handling the event. nsCOMPtr kungFuDeathGrip(mWindow); @@ -252,13 +256,16 @@ NS_IMETHODIMP nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, } if (NS_EVENT_FLAG_INIT & aFlags) { - // We're leaving the DOM event loop so if we created a DOM event, release here. + // We're leaving the DOM event loop so if we created a DOM event, + // release here. if (nsnull != *aDOMEvent) { nsrefcnt rc; NS_RELEASE2(*aDOMEvent, rc); if (0 != rc) { - //Okay, so someone in the DOM loop (a listener, JS object) still has a ref to the DOM Event but - //the internal data hasn't been malloc'd. Force a copy of the data here so the DOM Event is still valid. + // Okay, so someone in the DOM loop (a listener, JS object) + // still has a ref to the DOM Event but the internal data + // hasn't been malloc'd. Force a copy of the data here so the + // DOM Event is still valid. nsIPrivateDOMEvent *privateEvent; if (NS_OK == (*aDOMEvent)->QueryInterface(NS_GET_IID(nsIPrivateDOMEvent), (void**)&privateEvent)) { privateEvent->DuplicatePrivateData(); @@ -267,6 +274,10 @@ NS_IMETHODIMP nsWindowRoot::HandleChromeEvent(nsPresContext* aPresContext, } } aDOMEvent = nsnull; + + // Now that we're done with this event, remove the flag that says + // we're in the process of dispatching this event. + NS_MARK_EVENT_DISPATCH_DONE(aEvent); } return ret; diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index 77d5ccb77f0..7569168321f 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -94,6 +94,9 @@ class nsIURI; #define NS_QUERYCARETRECT_EVENT 28 #define NS_PAGETRANSITION_EVENT 29 +// These flags are sort of a mess. They're sort of shared between event +// listener flags and event flags, but only some of them. You've been +// warned! #define NS_EVENT_FLAG_NONE 0x0000 #define NS_EVENT_FLAG_INIT 0x0001 #define NS_EVENT_FLAG_BUBBLE 0x0002 @@ -106,7 +109,9 @@ class nsIURI; #define NS_EVENT_FLAG_NO_CONTENT_DISPATCH 0x0100 #define NS_EVENT_FLAG_SYSTEM_EVENT 0x0200 #define NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY 0x0400 // @see nsIDOM3Event::stopImmediatePropagation() -#define NS_PRIV_EVENT_UNTRUSTED_PERMITTED 0x0800 +#define NS_EVENT_FLAG_DISPATCHING 0x0800 + +#define NS_PRIV_EVENT_UNTRUSTED_PERMITTED 0x8000 #define NS_EVENT_CAPTURE_MASK (~(NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH)) #define NS_EVENT_BUBBLE_MASK (~(NS_EVENT_FLAG_INIT | NS_EVENT_FLAG_CAPTURE | NS_EVENT_FLAG_NO_CONTENT_DISPATCH)) @@ -971,7 +976,19 @@ enum nsDragDropEventStatus { #define NS_IS_TRUSTED_EVENT(event) \ (((event)->internalAppFlags & NS_APP_EVENT_FLAG_TRUSTED) != 0) +// Mark an event as being dispatching. +#define NS_MARK_EVENT_DISPATCH_STARTED(event) \ + (event)->flags |= NS_EVENT_FLAG_DISPATCHING; +#define NS_IS_EVENT_IN_DISPATCH(event) \ + (((event)->flags & NS_EVENT_FLAG_DISPATCHING) != 0) + +// Mark an event as being done dispatching. +#define NS_MARK_EVENT_DISPATCH_DONE(event) \ + NS_ASSERTION(NS_IS_EVENT_IN_DISPATCH(event), \ + "Event never got marked for dispatch!"); \ + (event)->flags &= ~NS_EVENT_FLAG_DISPATCHING; \ + (event)->flags |= NS_EVENT_FLAG_STOP_DISPATCH_IMMEDIATELY; /* * Virtual key bindings for keyboard events.