Bug 458202 - Speed up event handling, r+sr=jst

This commit is contained in:
Olli Pettay 2008-10-08 14:35:29 +03:00
parent 960a26406e
commit 256070b717
11 changed files with 122 additions and 59 deletions

View File

@ -105,6 +105,7 @@ class nsIUGenCategory;
class nsIWidget; class nsIWidget;
class nsIDragSession; class nsIDragSession;
class nsPIDOMWindow; class nsPIDOMWindow;
class nsPIDOMEventTarget;
#ifdef MOZ_XTF #ifdef MOZ_XTF
class nsIXTFService; class nsIXTFService;
#endif #endif
@ -1338,6 +1339,10 @@ public:
static nsIInterfaceRequestor* GetSameOriginChecker(); static nsIInterfaceRequestor* GetSameOriginChecker();
static nsIThreadJSContextStack* ThreadJSContextStack()
{
return sThreadJSContextStack;
}
private: private:
static PRBool InitializeEventTable(); static PRBool InitializeEventTable();
@ -1434,12 +1439,11 @@ public:
~nsCxPusher(); // Calls Pop(); ~nsCxPusher(); // Calls Pop();
// Returns PR_FALSE if something erroneous happened. // Returns PR_FALSE if something erroneous happened.
PRBool Push(nsISupports *aCurrentTarget); PRBool Push(nsPIDOMEventTarget *aCurrentTarget);
PRBool Push(JSContext *cx); PRBool Push(JSContext *cx);
void Pop(); void Pop();
private: private:
nsCOMPtr<nsIJSContextStack> mStack;
nsCOMPtr<nsIScriptContext> mScx; nsCOMPtr<nsIScriptContext> mScx;
PRBool mScriptIsRunning; PRBool mScriptIsRunning;
}; };

View File

@ -2691,7 +2691,7 @@ IsContextOnStack(nsIJSContextStack *aStack, JSContext *aContext)
} }
PRBool PRBool
nsCxPusher::Push(nsISupports *aCurrentTarget) nsCxPusher::Push(nsPIDOMEventTarget *aCurrentTarget)
{ {
if (mScx) { if (mScx) {
NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!"); NS_ERROR("Whaaa! No double pushing with nsCxPusher::Push()!");
@ -2699,10 +2699,9 @@ nsCxPusher::Push(nsISupports *aCurrentTarget)
return PR_FALSE; return PR_FALSE;
} }
nsCOMPtr<nsPIDOMEventTarget> eventTarget = do_QueryInterface(aCurrentTarget); NS_ENSURE_TRUE(aCurrentTarget, PR_FALSE);
NS_ENSURE_TRUE(eventTarget, PR_FALSE);
nsCOMPtr<nsIScriptContext> scx; nsCOMPtr<nsIScriptContext> scx;
nsresult rv = eventTarget->GetContextForEventHandlers(getter_AddRefs(scx)); nsresult rv = aCurrentTarget->GetContextForEventHandlers(getter_AddRefs(scx));
NS_ENSURE_SUCCESS(rv, PR_FALSE); NS_ENSURE_SUCCESS(rv, PR_FALSE);
JSContext* cx = nsnull; JSContext* cx = nsnull;
@ -2735,18 +2734,15 @@ nsCxPusher::Push(JSContext *cx)
return PR_TRUE; return PR_TRUE;
} }
if (!mStack) { nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
mStack = do_GetService(kJSStackContractID); if (stack) {
} if (IsContextOnStack(stack, cx)) {
if (mStack) {
if (IsContextOnStack(mStack, cx)) {
// If the context is on the stack, that means that a script // If the context is on the stack, that means that a script
// is running at the moment in the context. // is running at the moment in the context.
mScriptIsRunning = PR_TRUE; mScriptIsRunning = PR_TRUE;
} }
mStack->Push(cx); stack->Push(cx);
} }
} }
return PR_TRUE; return PR_TRUE;
@ -2755,7 +2751,8 @@ nsCxPusher::Push(JSContext *cx)
void void
nsCxPusher::Pop() nsCxPusher::Pop()
{ {
if (!mScx || !mStack) { nsIThreadJSContextStack* stack = nsContentUtils::ThreadJSContextStack();
if (!mScx || !stack) {
mScx = nsnull; mScx = nsnull;
NS_ASSERTION(!mScriptIsRunning, "Huh, this can't be happening, " NS_ASSERTION(!mScriptIsRunning, "Huh, this can't be happening, "
@ -2765,7 +2762,7 @@ nsCxPusher::Pop()
} }
JSContext *unused; JSContext *unused;
mStack->Pop(&unused); stack->Pop(&unused);
if (!mScriptIsRunning) { if (!mScriptIsRunning) {
// No JS is running in the context, but executing the event handler might have // No JS is running in the context, but executing the event handler might have

View File

@ -5996,7 +5996,8 @@ nsDocument::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
// Load events must not propagate to |window| object, see bug 335251. // Load events must not propagate to |window| object, see bug 335251.
if (aVisitor.mEvent->message != NS_LOAD) { if (aVisitor.mEvent->message != NS_LOAD) {
aVisitor.mParentTarget = GetWindow(); nsCOMPtr<nsPIDOMEventTarget> parentTarget = do_QueryInterface(GetWindow());
aVisitor.mParentTarget = parentTarget;
} }
return NS_OK; return NS_OK;
} }

View File

@ -132,13 +132,15 @@ public:
nsEventStatus aEventStatus = nsEventStatus_eIgnore) nsEventStatus aEventStatus = nsEventStatus_eIgnore)
: nsEventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus), : nsEventChainVisitor(aPresContext, aEvent, aDOMEvent, aEventStatus),
mCanHandle(PR_TRUE), mForceContentDispatch(PR_FALSE), mCanHandle(PR_TRUE), mForceContentDispatch(PR_FALSE),
mRelatedTargetIsInAnon(PR_FALSE) {} mRelatedTargetIsInAnon(PR_FALSE), mWantsWillHandleEvent(PR_FALSE),
mParentTarget(nsnull), mEventTargetAtParent(nsnull) {}
void Reset() { void Reset() {
mItemFlags = 0; mItemFlags = 0;
mItemData = nsnull; mItemData = nsnull;
mCanHandle = PR_TRUE; mCanHandle = PR_TRUE;
mForceContentDispatch = PR_FALSE; mForceContentDispatch = PR_FALSE;
mWantsWillHandleEvent = PR_FALSE;
mParentTarget = nsnull; mParentTarget = nsnull;
mEventTargetAtParent = nsnull; mEventTargetAtParent = nsnull;
} }
@ -164,16 +166,23 @@ public:
*/ */
PRPackedBool mRelatedTargetIsInAnon; PRPackedBool mRelatedTargetIsInAnon;
/**
* Whether or not nsPIDOMEventTarget::WillHandleEvent will be
* called. Default is PR_FALSE;
*/
PRPackedBool mWantsWillHandleEvent;
/** /**
* Parent item in the event target chain. * Parent item in the event target chain.
*/ */
nsCOMPtr<nsISupports> mParentTarget; nsPIDOMEventTarget* mParentTarget;
/** /**
* If the event needs to be retargeted, this is the event target, * If the event needs to be retargeted, this is the event target,
* which should be used when the event is handled at mParentTarget. * which should be used when the event is handled at mParentTarget.
*/ */
nsCOMPtr<nsISupports> mEventTargetAtParent; nsPIDOMEventTarget* mEventTargetAtParent;
}; };
class nsEventChainPostVisitor : public nsEventChainVisitor { class nsEventChainPostVisitor : public nsEventChainVisitor {

View File

@ -47,13 +47,14 @@ class nsIScriptContext;
class nsIDOMEventTarget; class nsIDOMEventTarget;
class nsIDOMEventGroup; class nsIDOMEventGroup;
class nsIAtom; class nsIAtom;
class nsPIDOMEventTarget;
/* /*
* Event listener manager interface. * Event listener manager interface.
*/ */
#define NS_IEVENTLISTENERMANAGER_IID \ #define NS_IEVENTLISTENERMANAGER_IID \
{ 0x0056ac6b, 0xc25b, 0x4fbb, \ { 0x0cdf1660, 0x3ac1, 0x4b84, \
{ 0x92, 0x98, 0x8d, 0xce, 0x53, 0x6e } } { 0xa9, 0x35, 0xc0, 0xc0, 0xe5, 0x5d, 0x73, 0xca } }
class nsIEventListenerManager : public nsISupports { class nsIEventListenerManager : public nsISupports {
@ -138,7 +139,7 @@ public:
NS_IMETHOD HandleEvent(nsPresContext* aPresContext, NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent, nsEvent* aEvent,
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
nsISupports* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aFlags, PRUint32 aFlags,
nsEventStatus* aEventStatus) = 0; nsEventStatus* aEventStatus) = 0;

View File

@ -94,7 +94,8 @@ public:
virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) = 0; virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor) = 0;
/** /**
* Called just before possible event handlers on this object will be called. * If nsEventChainPreVisitor.mWantsWillHandleEvent is set PR_TRUE,
* called just before possible event handlers on this object will be called.
*/ */
virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor) virtual nsresult WillHandleEvent(nsEventChainPostVisitor& aVisitor)
{ {

View File

@ -40,27 +40,28 @@
#include "nsPIDOMEventTarget.h" #include "nsPIDOMEventTarget.h"
#include "nsPresContext.h" #include "nsPresContext.h"
#include "nsIPrivateDOMEvent.h" #include "nsIPrivateDOMEvent.h"
#include "nsIEventListenerManager.h" #include "nsEventListenerManager.h"
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsMutationEvent.h" #include "nsMutationEvent.h"
#include NEW_H #include NEW_H
#include "nsFixedSizeAllocator.h" #include "nsFixedSizeAllocator.h"
#define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0) #define NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH (1 << 0)
#define NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT (1 << 1)
// nsEventTargetChainItem represents a single item in the event target chain. // nsEventTargetChainItem represents a single item in the event target chain.
class nsEventTargetChainItem class nsEventTargetChainItem
{ {
private: private:
nsEventTargetChainItem(nsISupports* aTarget, nsEventTargetChainItem(nsPIDOMEventTarget* aTarget,
nsEventTargetChainItem* aChild = nsnull); nsEventTargetChainItem* aChild = nsnull);
void Destroy(nsFixedSizeAllocator* aAllocator); void Destroy(nsFixedSizeAllocator* aAllocator);
public: public:
static nsEventTargetChainItem* Create(nsFixedSizeAllocator* aAllocator, static nsEventTargetChainItem* Create(nsFixedSizeAllocator* aAllocator,
nsISupports* aTarget, nsPIDOMEventTarget* aTarget,
nsEventTargetChainItem* aChild = nsnull) nsEventTargetChainItem* aChild = nsnull)
{ {
void* place = aAllocator->Alloc(sizeof(nsEventTargetChainItem)); void* place = aAllocator->Alloc(sizeof(nsEventTargetChainItem));
@ -88,12 +89,13 @@ public:
return mNewTarget; return mNewTarget;
} }
void SetNewTarget(nsISupports* aNewTarget) void SetNewTarget(nsPIDOMEventTarget* aNewTarget)
{ {
mNewTarget = aNewTarget; mNewTarget = aNewTarget;
} }
void SetForceContentDispatch(PRBool aForce) { void SetForceContentDispatch(PRBool aForce)
{
if (aForce) { if (aForce) {
mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH; mFlags |= NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH;
} else { } else {
@ -101,10 +103,26 @@ public:
} }
} }
PRBool ForceContentDispatch() { PRBool ForceContentDispatch()
{
return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH); return !!(mFlags & NS_TARGET_CHAIN_FORCE_CONTENT_DISPATCH);
} }
void SetWantsWillHandleEvent(PRBool aWants)
{
if (aWants) {
mFlags |= NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
} else {
mFlags &= ~NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT;
}
}
PRBool WantsWillHandleEvent()
{
return !!(mFlags & NS_TARGET_CHAIN_WANTS_WILL_HANDLE_EVENT);
}
nsPIDOMEventTarget* CurrentTarget() nsPIDOMEventTarget* CurrentTarget()
{ {
return mTarget; return mTarget;
@ -118,7 +136,8 @@ public:
*/ */
nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, nsresult HandleEventTargetChain(nsEventChainPostVisitor& aVisitor,
PRUint32 aFlags, PRUint32 aFlags,
nsDispatchingCallback* aCallback); nsDispatchingCallback* aCallback,
PRBool aMayHaveNewListenerManagers);
/** /**
* Resets aVisitor object and calls PreHandleEvent. * Resets aVisitor object and calls PreHandleEvent.
@ -131,7 +150,8 @@ public:
* manager, this method sets the .currentTarget to the CurrentTarget() * manager, this method sets the .currentTarget to the CurrentTarget()
* and calls nsIEventListenerManager::HandleEvent(). * and calls nsIEventListenerManager::HandleEvent().
*/ */
nsresult HandleEvent(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags); nsresult HandleEvent(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags,
PRBool aMayHaveNewListenerManagers);
/** /**
* Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent. * Copies mItemFlags and mItemData to aVisitor and calls PostHandleEvent.
@ -146,19 +166,16 @@ public:
PRUint16 mItemFlags; PRUint16 mItemFlags;
nsCOMPtr<nsISupports> mItemData; nsCOMPtr<nsISupports> mItemData;
// Event retargeting must happen whenever mNewTarget is non-null. // Event retargeting must happen whenever mNewTarget is non-null.
nsCOMPtr<nsISupports> mNewTarget; nsCOMPtr<nsPIDOMEventTarget> mNewTarget;
// Cache mTarget's event listener manager. // Cache mTarget's event listener manager.
nsCOMPtr<nsIEventListenerManager> mManager; nsCOMPtr<nsIEventListenerManager> mManager;
}; };
nsEventTargetChainItem::nsEventTargetChainItem(nsISupports* aTarget, nsEventTargetChainItem::nsEventTargetChainItem(nsPIDOMEventTarget* aTarget,
nsEventTargetChainItem* aChild) nsEventTargetChainItem* aChild)
: mChild(aChild), mParent(nsnull), mFlags(0), mItemFlags(0) : mChild(aChild), mParent(nsnull), mFlags(0), mItemFlags(0)
{ {
nsCOMPtr<nsPIDOMEventTarget> t = do_QueryInterface(aTarget); mTarget = aTarget->GetTargetForEventTargetChain();
if (t) {
mTarget = t->GetTargetForEventTargetChain();
}
if (mChild) { if (mChild) {
mChild->mParent = this; mChild->mParent = this;
} }
@ -186,6 +203,7 @@ nsEventTargetChainItem::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
aVisitor.Reset(); aVisitor.Reset();
nsresult rv = mTarget->PreHandleEvent(aVisitor); nsresult rv = mTarget->PreHandleEvent(aVisitor);
SetForceContentDispatch(aVisitor.mForceContentDispatch); SetForceContentDispatch(aVisitor.mForceContentDispatch);
SetWantsWillHandleEvent(aVisitor.mWantsWillHandleEvent);
mItemFlags = aVisitor.mItemFlags; mItemFlags = aVisitor.mItemFlags;
mItemData = aVisitor.mItemData; mItemData = aVisitor.mItemData;
return rv; return rv;
@ -193,21 +211,28 @@ nsEventTargetChainItem::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
nsresult nsresult
nsEventTargetChainItem::HandleEvent(nsEventChainPostVisitor& aVisitor, nsEventTargetChainItem::HandleEvent(nsEventChainPostVisitor& aVisitor,
PRUint32 aFlags) PRUint32 aFlags,
PRBool aMayHaveNewListenerManagers)
{ {
mTarget->WillHandleEvent(aVisitor); if (WantsWillHandleEvent()) {
mTarget->WillHandleEvent(aVisitor);
}
if (aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) { if (aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH) {
return NS_OK; return NS_OK;
} }
if (!mManager) { if (!mManager) {
if (!aMayHaveNewListenerManagers) {
return NS_OK;
}
mTarget->GetListenerManager(PR_FALSE, getter_AddRefs(mManager)); mTarget->GetListenerManager(PR_FALSE, getter_AddRefs(mManager));
} }
if (mManager) { if (mManager) {
aVisitor.mEvent->currentTarget = CurrentTarget()->GetTargetForDOMEvent(); nsPIDOMEventTarget* currentTarget = CurrentTarget()->GetTargetForDOMEvent();
aVisitor.mEvent->currentTarget = currentTarget;
if (aVisitor.mEvent->currentTarget) { if (aVisitor.mEvent->currentTarget) {
mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent, mManager->HandleEvent(aVisitor.mPresContext, aVisitor.mEvent,
&aVisitor.mDOMEvent, &aVisitor.mDOMEvent,
aVisitor.mEvent->currentTarget, aFlags, currentTarget, aFlags,
&aVisitor.mEventStatus); &aVisitor.mEventStatus);
aVisitor.mEvent->currentTarget = nsnull; aVisitor.mEvent->currentTarget = nsnull;
} }
@ -226,8 +251,10 @@ nsEventTargetChainItem::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
nsresult nsresult
nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags, nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor, PRUint32 aFlags,
nsDispatchingCallback* aCallback) nsDispatchingCallback* aCallback,
PRBool aMayHaveNewListenerManagers)
{ {
PRUint32 createdELMs = nsEventListenerManager::sCreatedCount;
// Save the target so that it can be restored later. // Save the target so that it can be restored later.
nsCOMPtr<nsISupports> firstTarget = aVisitor.mEvent->target; nsCOMPtr<nsISupports> firstTarget = aVisitor.mEvent->target;
@ -239,7 +266,9 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
if ((!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) || if ((!(aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) ||
item->ForceContentDispatch()) && item->ForceContentDispatch()) &&
!(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) { !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
item->HandleEvent(aVisitor, aFlags & NS_EVENT_CAPTURE_MASK); item->HandleEvent(aVisitor, aFlags & NS_EVENT_CAPTURE_MASK,
aMayHaveNewListenerManagers ||
createdELMs != nsEventListenerManager::sCreatedCount);
} }
if (item->GetNewTarget()) { if (item->GetNewTarget()) {
@ -266,7 +295,9 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
// FIXME Should use aFlags & NS_EVENT_BUBBLE_MASK because capture phase // FIXME Should use aFlags & NS_EVENT_BUBBLE_MASK because capture phase
// event listeners should not be fired. But it breaks at least // event listeners should not be fired. But it breaks at least
// <xul:dialog>'s buttons. Bug 235441. // <xul:dialog>'s buttons. Bug 235441.
item->HandleEvent(aVisitor, aFlags); item->HandleEvent(aVisitor, aFlags,
aMayHaveNewListenerManagers ||
createdELMs != nsEventListenerManager::sCreatedCount);
} }
if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) { if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
item->PostHandleEvent(aVisitor); item->PostHandleEvent(aVisitor);
@ -289,7 +320,8 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
(!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) || (!(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) ||
aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) && aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) &&
!(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) { !(aVisitor.mEvent->flags & NS_EVENT_FLAG_STOP_DISPATCH)) {
item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK); item->HandleEvent(aVisitor, aFlags & NS_EVENT_BUBBLE_MASK,
createdELMs != nsEventListenerManager::sCreatedCount);
} }
if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) { if (aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) {
item->PostHandleEvent(aVisitor); item->PostHandleEvent(aVisitor);
@ -318,7 +350,8 @@ nsEventTargetChainItem::HandleEventTargetChain(nsEventChainPostVisitor& aVisitor
// Setting back the target which was used also for default event group. // Setting back the target which was used also for default event group.
aVisitor.mEvent->target = firstTarget; aVisitor.mEvent->target = firstTarget;
HandleEventTargetChain(aVisitor, aFlags | NS_EVENT_FLAG_SYSTEM_EVENT, HandleEventTargetChain(aVisitor, aFlags | NS_EVENT_FLAG_SYSTEM_EVENT,
aCallback); aCallback,
createdELMs != nsEventListenerManager::sCreatedCount);
} }
return NS_OK; return NS_OK;
@ -378,6 +411,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
NS_ENSURE_TRUE(!NS_IS_EVENT_IN_DISPATCH(aEvent), NS_ENSURE_TRUE(!NS_IS_EVENT_IN_DISPATCH(aEvent),
NS_ERROR_ILLEGAL_VALUE); NS_ERROR_ILLEGAL_VALUE);
nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(aTarget);
#ifdef DEBUG #ifdef DEBUG
if (aDOMEvent) { if (aDOMEvent) {
nsCOMPtr<nsIPrivateDOMEvent> privEvt(do_QueryInterface(aDOMEvent)); nsCOMPtr<nsIPrivateDOMEvent> privEvt(do_QueryInterface(aDOMEvent));
@ -401,7 +435,7 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
// Create the event target chain item for the event target. // Create the event target chain item for the event target.
nsEventTargetChainItem* targetEtci = nsEventTargetChainItem* targetEtci =
nsEventTargetChainItem::Create(pool.GetPool(), aTarget); nsEventTargetChainItem::Create(pool.GetPool(), target);
NS_ENSURE_TRUE(targetEtci, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(targetEtci, NS_ERROR_OUT_OF_MEMORY);
if (!targetEtci->IsValid()) { if (!targetEtci->IsValid()) {
nsEventTargetChainItem::Destroy(pool.GetPool(), targetEtci); nsEventTargetChainItem::Destroy(pool.GetPool(), targetEtci);
@ -438,7 +472,8 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
if (preVisitor.mCanHandle) { if (preVisitor.mCanHandle) {
// At least the original target can handle the event. // At least the original target can handle the event.
// Setting the retarget to the |target| simplifies retargeting code. // Setting the retarget to the |target| simplifies retargeting code.
targetEtci->SetNewTarget(aEvent->target); nsCOMPtr<nsPIDOMEventTarget> t = do_QueryInterface(aEvent->target);
targetEtci->SetNewTarget(t);
nsEventTargetChainItem* topEtci = targetEtci; nsEventTargetChainItem* topEtci = targetEtci;
while (preVisitor.mParentTarget) { while (preVisitor.mParentTarget) {
nsEventTargetChainItem* parentEtci = nsEventTargetChainItem* parentEtci =
@ -476,7 +511,8 @@ nsEventDispatcher::Dispatch(nsISupports* aTarget,
rv = topEtci->HandleEventTargetChain(postVisitor, rv = topEtci->HandleEventTargetChain(postVisitor,
NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_BUBBLE |
NS_EVENT_FLAG_CAPTURE, NS_EVENT_FLAG_CAPTURE,
aCallback); aCallback,
PR_TRUE);
preVisitor.mEventStatus = postVisitor.mEventStatus; preVisitor.mEventStatus = postVisitor.mEventStatus;
// If the DOM event was created during event flow. // If the DOM event was created during event flow.

View File

@ -339,6 +339,7 @@ nsIDOMEventGroup* gDOM2EventGroup = nsnull;
nsDataHashtable<nsISupportsHashKey, PRUint32>* gEventIdTable = nsnull; nsDataHashtable<nsISupportsHashKey, PRUint32>* gEventIdTable = nsnull;
PRUint32 nsEventListenerManager::mInstanceCount = 0; PRUint32 nsEventListenerManager::mInstanceCount = 0;
PRUint32 nsEventListenerManager::sCreatedCount = 0;
nsEventListenerManager::nsEventListenerManager() : nsEventListenerManager::nsEventListenerManager() :
mTarget(nsnull), mTarget(nsnull),
@ -346,6 +347,7 @@ nsEventListenerManager::nsEventListenerManager() :
mNoListenerForEvent(NS_EVENT_TYPE_NULL) mNoListenerForEvent(NS_EVENT_TYPE_NULL)
{ {
++mInstanceCount; ++mInstanceCount;
++sCreatedCount;
} }
nsEventListenerManager::~nsEventListenerManager() nsEventListenerManager::~nsEventListenerManager()
@ -1072,10 +1074,7 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
} }
} }
// nsCxPusher will push and pop (automatically) the current cx onto the if (NS_SUCCEEDED(result)) {
// context stack
nsCxPusher pusher;
if (NS_SUCCEEDED(result) && pusher.Push(aCurrentTarget)) {
// nsIDOMEvent::currentTarget is set in nsEventDispatcher. // nsIDOMEvent::currentTarget is set in nsEventDispatcher.
result = aListener->HandleEvent(aDOMEvent); result = aListener->HandleEvent(aDOMEvent);
} }
@ -1095,7 +1094,7 @@ static const EventDispatchData* sLatestEventDispData = nsnull;
nsresult nsresult
nsEventListenerManager::HandleEvent(nsPresContext* aPresContext, nsEventListenerManager::HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent, nsIDOMEvent** aDOMEvent, nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
nsISupports* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aFlags, PRUint32 aFlags,
nsEventStatus* aEventStatus) nsEventStatus* aEventStatus)
{ {
@ -1155,6 +1154,10 @@ found:
nsAutoTObserverArray<nsListenerStruct, 2>::EndLimitedIterator iter(mListeners); nsAutoTObserverArray<nsListenerStruct, 2>::EndLimitedIterator iter(mListeners);
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent)); nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
PRBool hasListener = PR_FALSE; PRBool hasListener = PR_FALSE;
// nsCxPusher will push and pop (automatically) the current cx onto the
// context stack
nsCxPusher pusher;
PRBool didPush = PR_FALSE;
while (iter.HasMore()) { while (iter.HasMore()) {
nsListenerStruct* ls = &iter.GetNext(); nsListenerStruct* ls = &iter.GetNext();
PRBool useTypeInterface = PRBool useTypeInterface =
@ -1178,9 +1181,14 @@ found:
if (*aDOMEvent) { if (*aDOMEvent) {
nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener; nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener;
if (useTypeInterface) { if (useTypeInterface) {
if (didPush) {
didPush = PR_FALSE;
pusher.Pop();
}
DispatchToInterface(*aDOMEvent, ls->mListener, DispatchToInterface(*aDOMEvent, ls->mListener,
dispData->method, *typeData->iid); dispData->method, *typeData->iid);
} else if (useGenericInterface) { } else if (useGenericInterface &&
(didPush || (didPush = pusher.Push(aCurrentTarget)))) {
HandleEventSubType(ls, ls->mListener, *aDOMEvent, HandleEventSubType(ls, ls->mListener, *aDOMEvent,
aCurrentTarget, aFlags); aCurrentTarget, aFlags);
} }

View File

@ -52,6 +52,7 @@ class nsIAtom;
class nsIWidget; class nsIWidget;
struct nsPoint; struct nsPoint;
struct EventTypeData; struct EventTypeData;
class nsEventTargetChainItem;
typedef struct { typedef struct {
nsRefPtr<nsIDOMEventListener> mListener; nsRefPtr<nsIDOMEventListener> mListener;
@ -113,7 +114,7 @@ public:
NS_IMETHOD HandleEvent(nsPresContext* aPresContext, NS_IMETHOD HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent, nsEvent* aEvent,
nsIDOMEvent** aDOMEvent, nsIDOMEvent** aDOMEvent,
nsISupports* aCurrentTarget, nsPIDOMEventTarget* aCurrentTarget,
PRUint32 aFlags, PRUint32 aFlags,
nsEventStatus* aEventStatus); nsEventStatus* aEventStatus);
@ -202,6 +203,9 @@ protected:
static PRUint32 mInstanceCount; static PRUint32 mInstanceCount;
static jsval sAddListenerID; static jsval sAddListenerID;
friend class nsEventTargetChainItem;
static PRUint32 sCreatedCount;
}; };
#endif // nsEventListenerManager_h__ #endif // nsEventListenerManager_h__

View File

@ -5129,7 +5129,8 @@ nsEventStateManager::SendFocusBlur(nsPresContext* aPresContext,
return NS_OK; return NS_OK;
} }
if (pusher.Push(window)) { nsCOMPtr<nsPIDOMEventTarget> target = do_QueryInterface(window);
if (pusher.Push(target)) {
nsEventDispatcher::Dispatch(window, gLastFocusedPresContextWeak, &event, nsEventDispatcher::Dispatch(window, gLastFocusedPresContextWeak, &event,
nsnull, &status); nsnull, &status);

View File

@ -808,6 +808,7 @@ nsHTMLFormElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
nsresult nsresult
nsHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor) nsHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{ {
aVisitor.mWantsWillHandleEvent = PR_TRUE;
if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) { if (aVisitor.mEvent->originalTarget == static_cast<nsIContent*>(this)) {
PRUint32 msg = aVisitor.mEvent->message; PRUint32 msg = aVisitor.mEvent->message;
if (msg == NS_FORM_SUBMIT) { if (msg == NS_FORM_SUBMIT) {