Bug 461861, r=mrbkap, sr=jst

--HG--
extra : rebase_source : a5aea484f992785a3d67bb03d7fe074ce4f7f95a
This commit is contained in:
Olli Pettay 2009-05-14 10:03:15 +03:00
parent 35ec9a36b8
commit 61994c29ad
4 changed files with 74 additions and 6 deletions

View File

@ -1490,6 +1490,9 @@ public:
// Returns PR_FALSE if something erroneous happened.
PRBool Push(nsPIDOMEventTarget *aCurrentTarget);
// If nothing has been pushed to stack, this works like Push.
// Otherwise if context will change, Pop and Push will be called.
PRBool RePush(nsPIDOMEventTarget *aCurrentTarget);
// If a null JSContext is passed to Push(), that will cause no
// push to happen and false to be returned.
PRBool Push(JSContext *cx);

View File

@ -2736,6 +2736,34 @@ nsCxPusher::Push(nsPIDOMEventTarget *aCurrentTarget)
return Push(cx);
}
PRBool
nsCxPusher::RePush(nsPIDOMEventTarget *aCurrentTarget)
{
if (!mPushedSomething) {
return Push(aCurrentTarget);
}
if (aCurrentTarget) {
nsresult rv;
nsIScriptContext* scx =
aCurrentTarget->GetContextForEventHandlers(&rv);
if (NS_FAILED(rv)) {
Pop();
return PR_FALSE;
}
// If we have the same script context and native context is still
// alive, no need to Pop/Push.
if (scx && scx == mScx &&
scx->GetNativeContext()) {
return PR_TRUE;
}
}
Pop();
return Push(aCurrentTarget);
}
PRBool
nsCxPusher::Push(JSContext *cx)
{

View File

@ -1082,10 +1082,7 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
}
}
// nsCxPusher will push and pop (automatically) the current cx onto the
// context stack
nsCxPusher pusher;
if (NS_SUCCEEDED(result) && pusher.Push(aCurrentTarget)) {
if (NS_SUCCEEDED(result)) {
// nsIDOMEvent::currentTarget is set in nsEventDispatcher.
result = aListener->HandleEvent(aDOMEvent);
}
@ -1157,6 +1154,7 @@ found:
nsAutoTObserverArray<nsListenerStruct, 2>::EndLimitedIterator iter(mListeners);
nsAutoPopupStatePusher popupStatePusher(nsDOMEvent::GetEventPopupControlState(aEvent));
PRBool hasListener = PR_FALSE;
nsCxPusher pusher;
while (iter.HasMore()) {
nsListenerStruct* ls = &iter.GetNext();
PRBool useTypeInterface =
@ -1180,9 +1178,11 @@ found:
if (*aDOMEvent) {
nsRefPtr<nsIDOMEventListener> kungFuDeathGrip = ls->mListener;
if (useTypeInterface) {
pusher.Pop();
DispatchToInterface(*aDOMEvent, ls->mListener,
dispData->method, *typeData->iid);
} else if (useGenericInterface) {
} else if (useGenericInterface &&
pusher.RePush(aCurrentTarget)) {
HandleEventSubType(ls, ls->mListener, *aDOMEvent,
aCurrentTarget, aFlags);
}

View File

@ -42,6 +42,9 @@
/* Implement global service to track stack of JSContext per thread. */
#include "xpcprivate.h"
#include "XPCWrapper.h"
#include "nsDOMJSUtils.h"
#include "nsIScriptGlobalObject.h"
/***************************************************************************/
@ -113,6 +116,20 @@ XPCJSContextStack::Pop(JSContext * *_retval)
return NS_OK;
}
static nsIPrincipal*
GetPrincipalFromCx(JSContext *cx)
{
nsIScriptContext* scriptContext = GetScriptContextFromJSContext(cx);
if(scriptContext)
{
nsCOMPtr<nsIScriptObjectPrincipal> globalData =
do_QueryInterface(scriptContext->GetGlobalObject());
if(globalData)
return globalData->GetPrincipal();
}
return nsnull;
}
/* void push (in JSContext cx); */
NS_IMETHODIMP
XPCJSContextStack::Push(JSContext * cx)
@ -122,8 +139,28 @@ XPCJSContextStack::Push(JSContext * cx)
if(mStack.Length() > 1)
{
XPCJSContextInfo & e = mStack[mStack.Length() - 2];
if(e.cx && e.cx != cx)
if(e.cx)
{
if(e.cx == cx)
{
nsIScriptSecurityManager* ssm = XPCWrapper::GetSecurityManager();
if(ssm)
{
nsIPrincipal* globalObjectPrincipal =
GetPrincipalFromCx(cx);
if(globalObjectPrincipal)
{
nsIPrincipal* subjectPrincipal = ssm->GetCxSubjectPrincipal(cx);
PRBool equals = PR_FALSE;
globalObjectPrincipal->Equals(subjectPrincipal, &equals);
if(equals)
{
return NS_OK;
}
}
}
}
e.frame = JS_SaveFrameChain(e.cx);
if(JS_GetContextThread(e.cx))