Bug 659350 part 5. The guts of the change to move from storing inline event handlers on the JSObject to storing them in the event listener manager directly, so we can easily set/read them via IDL.

The changes here are as follows:
1) nsIJSEventListener now stores the handler.  This is guaranteed to be already bound properly, if needed, before being set in the nsIJSEventListener.
2) The old classinfo glue to deal with on* properties is gone.
3) IDL-based methods for on* properties have been added.
This commit is contained in:
Boris Zbarsky 2011-08-24 15:49:25 -04:00
parent d189b7ba20
commit 1c9abe2f8d
35 changed files with 881 additions and 932 deletions

View File

@ -48,6 +48,7 @@
#include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT #include "nsIProgrammingLanguage.h" // for ::JAVASCRIPT
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsDOMString.h" #include "nsDOMString.h"
#include "jspubtd.h"
class nsIContent; class nsIContent;
class nsIDocument; class nsIDocument;
@ -280,8 +281,8 @@ private:
// IID for the nsINode interface // IID for the nsINode interface
#define NS_INODE_IID \ #define NS_INODE_IID \
{ 0xc7abbb40, 0x2571, 0x4d12, \ { 0xcdab747e, 0xa58f, 0x4b96, \
{ 0x8f, 0x89, 0x0d, 0x4f, 0x55, 0xc0, 0x92, 0xf6 } } { 0x8b, 0xae, 0x9d, 0x53, 0xe0, 0xa7, 0x8a, 0x74 } }
/** /**
* An internal interface that abstracts some DOMNode-related parts that both * An internal interface that abstracts some DOMNode-related parts that both
@ -1366,6 +1367,18 @@ protected:
nsresult doInsertChildAt(nsIContent* aKid, PRUint32 aIndex, nsresult doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
PRBool aNotify, nsAttrAndChildArray& aChildArray); PRBool aNotify, nsAttrAndChildArray& aChildArray);
/* Event stuff that documents and elements share. This needs to be
NS_IMETHOD because some subclasses implement DOM methods with
this exact name and signature and then the calling convention
needs to match. */
#define EVENT(name_, id_, type_, struct_) \
NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp); \
NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v);
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef EVENT
nsCOMPtr<nsINodeInfo> mNodeInfo; nsCOMPtr<nsINodeInfo> mNodeInfo;
nsINode* mParent; nsINode* mParent;

View File

@ -1702,6 +1702,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver) NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers)
NS_OFFSET_AND_INTERFACE_TABLE_END NS_OFFSET_AND_INTERFACE_TABLE_END
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument) NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
@ -8472,3 +8473,14 @@ nsDocument::SizeOf() const
return size; return size;
} }
#define EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsDocument::GetOn##name_(JSContext *cx, jsval *vp) { \
return nsINode::GetOn##name_(cx, vp); \
} \
NS_IMETHODIMP nsDocument::SetOn##name_(JSContext *cx, const jsval &v) { \
return nsINode::SetOn##name_(cx, v); \
}
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef EVENT

View File

@ -98,6 +98,7 @@
#include "imgIRequest.h" #include "imgIRequest.h"
#include "nsIDOMDOMImplementation.h" #include "nsIDOMDOMImplementation.h"
#include "nsIDOMTouchEvent.h" #include "nsIDOMTouchEvent.h"
#include "nsIInlineEventHandlers.h"
#include "nsDataHashtable.h" #include "nsDataHashtable.h"
#include "TimeStamp.h" #include "TimeStamp.h"
@ -492,7 +493,8 @@ class nsDocument : public nsIDocument,
public nsIRadioGroupContainer, public nsIRadioGroupContainer,
public nsIApplicationCacheContainer, public nsIApplicationCacheContainer,
public nsStubMutationObserver, public nsStubMutationObserver,
public nsIDOMDocumentTouch public nsIDOMDocumentTouch,
public nsIInlineEventHandlers
{ {
public: public:
typedef mozilla::dom::Element Element; typedef mozilla::dom::Element Element;
@ -787,6 +789,9 @@ public:
// nsIDOMDocumentTouch // nsIDOMDocumentTouch
NS_DECL_NSIDOMDOCUMENTTOUCH NS_DECL_NSIDOMDOCUMENTTOUCH
// nsIInlineEventHandlers
NS_DECL_NSIINLINEEVENTHANDLERS
virtual nsresult Init(); virtual nsresult Init();
virtual void AddXMLEventsContent(nsIContent * aXMLEventsElement); virtual void AddXMLEventsContent(nsIContent * aXMLEventsElement);

View File

@ -147,6 +147,8 @@
#include "nsSVGFeatures.h" #include "nsSVGFeatures.h"
#include "nsDOMMemoryReporter.h" #include "nsDOMMemoryReporter.h"
#include "xpcpublic.h"
using namespace mozilla::dom; using namespace mozilla::dom;
namespace css = mozilla::css; namespace css = mozilla::css;
@ -2160,6 +2162,17 @@ NS_INTERFACE_MAP_END_AGGREGATED(mElement)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTouchEventReceiverTearoff) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTouchEventReceiverTearoff)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTouchEventReceiverTearoff) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTouchEventReceiverTearoff)
//----------------------------------------------------------------------
NS_IMPL_CYCLE_COLLECTION_1(nsInlineEventHandlersTearoff, mElement)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsInlineEventHandlersTearoff)
NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
NS_INTERFACE_MAP_END_AGGREGATED(mElement)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsInlineEventHandlersTearoff)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsInlineEventHandlersTearoff)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
nsGenericElement::nsDOMSlots::nsDOMSlots() nsGenericElement::nsDOMSlots::nsDOMSlots()
: nsINode::nsSlots(), : nsINode::nsSlots(),
@ -4278,6 +4291,8 @@ NS_INTERFACE_MAP_BEGIN(nsGenericElement)
new nsNode3Tearoff(this)) new nsNode3Tearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsITouchEventReceiver, NS_INTERFACE_MAP_ENTRY_TEAROFF(nsITouchEventReceiver,
new nsTouchEventReceiverTearoff(this)) new nsTouchEventReceiverTearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIInlineEventHandlers,
new nsInlineEventHandlersTearoff(this))
// nsNodeSH::PreCreate() depends on the identity pointer being the // nsNodeSH::PreCreate() depends on the identity pointer being the
// same as nsINode (which nsIContent inherits), so if you change the // same as nsINode (which nsIContent inherits), so if you change the
// below line, make sure nsNodeSH::PreCreate() still does the right // below line, make sure nsNodeSH::PreCreate() still does the right
@ -5398,3 +5413,30 @@ nsGenericElement::SizeOf() const
return size; return size;
} }
#define EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, jsval *vp) { \
nsEventListenerManager *elm = GetListenerManager(PR_FALSE); \
if (elm) { \
elm->GetJSEventListener(nsGkAtoms::on##name_, vp); \
} else { \
*vp = JSVAL_NULL; \
} \
return NS_OK; \
} \
NS_IMETHODIMP nsINode::SetOn##name_(JSContext *cx, const jsval &v) { \
nsEventListenerManager *elm = GetListenerManager(PR_TRUE); \
if (!elm) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
\
JSObject *obj = GetWrapper(); \
if (!obj) { \
/* Just silently do nothing */ \
return NS_OK; \
} \
return elm->SetJSEventListenerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
}
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef EVENT

View File

@ -65,6 +65,7 @@
#include "nsContentList.h" #include "nsContentList.h"
#include "nsDOMClassInfoID.h" // DOMCI_DATA #include "nsDOMClassInfoID.h" // DOMCI_DATA
#include "nsIDOMTouchEvent.h" #include "nsIDOMTouchEvent.h"
#include "nsIInlineEventHandlers.h"
#ifdef MOZ_SMIL #ifdef MOZ_SMIL
#include "nsISMILAttr.h" #include "nsISMILAttr.h"
@ -226,6 +227,7 @@ private:
// Forward declare to allow being a friend // Forward declare to allow being a friend
class nsNSElementTearoff; class nsNSElementTearoff;
class nsTouchEventReceiverTearoff; class nsTouchEventReceiverTearoff;
class nsInlineEventHandlersTearoff;
/** /**
* A generic base class for DOM elements, implementing many nsIContent, * A generic base class for DOM elements, implementing many nsIContent,
@ -239,6 +241,7 @@ public:
friend class nsNSElementTearoff; friend class nsNSElementTearoff;
friend class nsTouchEventReceiverTearoff; friend class nsTouchEventReceiverTearoff;
friend class nsInlineEventHandlersTearoff;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -1066,7 +1069,7 @@ class nsTouchEventReceiverTearoff : public nsITouchEventReceiver
public: public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSITOUCHEVENTRECEIVER NS_FORWARD_NSITOUCHEVENTRECEIVER(mElement->)
NS_DECL_CYCLE_COLLECTION_CLASS(nsTouchEventReceiverTearoff) NS_DECL_CYCLE_COLLECTION_CLASS(nsTouchEventReceiverTearoff)
@ -1078,6 +1081,26 @@ private:
nsRefPtr<nsGenericElement> mElement; nsRefPtr<nsGenericElement> mElement;
}; };
/**
* Tearoff class to implement nsIInlineEventHandlers
*/
class nsInlineEventHandlersTearoff : public nsIInlineEventHandlers
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_FORWARD_NSIINLINEEVENTHANDLERS(mElement->)
NS_DECL_CYCLE_COLLECTION_CLASS(nsInlineEventHandlersTearoff)
nsInlineEventHandlersTearoff(nsGenericElement *aElement) : mElement(aElement)
{
}
private:
nsRefPtr<nsGenericElement> mElement;
};
#define NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE \ #define NS_ELEMENT_INTERFACE_TABLE_TO_MAP_SEGUE \
rv = nsGenericElement::QueryInterface(aIID, aInstancePtr); \ rv = nsGenericElement::QueryInterface(aIID, aInstancePtr); \
if (NS_SUCCEEDED(rv)) \ if (NS_SUCCEEDED(rv)) \

View File

@ -81,6 +81,7 @@
#include "nsEventListenerService.h" #include "nsEventListenerService.h"
#include "nsDOMEvent.h" #include "nsDOMEvent.h"
#include "nsIContentSecurityPolicy.h" #include "nsIContentSecurityPolicy.h"
#include "nsJSEnvironment.h"
using namespace mozilla::dom; using namespace mozilla::dom;
@ -166,7 +167,6 @@ nsEventListenerManager::RemoveAllListeners()
void void
nsEventListenerManager::Shutdown() nsEventListenerManager::Shutdown()
{ {
sAddListenerID = JSID_VOID;
nsDOMEvent::Shutdown(); nsDOMEvent::Shutdown();
} }
@ -377,8 +377,9 @@ nsresult
nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext, nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
void *aScopeObject, void *aScopeObject,
nsIAtom* aName, nsIAtom* aName,
PRBool aIsString, JSObject *aHandler,
PRBool aPermitUntrustedEvents) PRBool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct)
{ {
nsresult rv = NS_OK; nsresult rv = NS_OK;
PRUint32 eventType = nsContentUtils::GetEventId(aName); PRUint32 eventType = nsContentUtils::GetEventId(aName);
@ -389,22 +390,27 @@ nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
// create and add a new one. // create and add a new one.
nsCOMPtr<nsIDOMEventListener> scriptListener; nsCOMPtr<nsIDOMEventListener> scriptListener;
rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName, rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
getter_AddRefs(scriptListener)); aHandler, getter_AddRefs(scriptListener));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
AddEventListener(scriptListener, eventType, aName, AddEventListener(scriptListener, eventType, aName,
NS_EVENT_FLAG_BUBBLE | NS_PRIV_EVENT_FLAG_SCRIPT); NS_EVENT_FLAG_BUBBLE | NS_PRIV_EVENT_FLAG_SCRIPT);
ls = FindJSEventListener(eventType, aName); ls = FindJSEventListener(eventType, aName);
} }
} else {
ls->GetJSListener()->SetHandler(aHandler);
} }
if (NS_SUCCEEDED(rv) && ls) { if (NS_SUCCEEDED(rv) && ls) {
// Set flag to indicate possible need for compilation later // Set flag to indicate possible need for compilation later
ls->mHandlerIsString = aIsString; ls->mHandlerIsString = !aHandler;
if (aPermitUntrustedEvents) { if (aPermitUntrustedEvents) {
ls->mFlags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED; ls->mFlags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
} }
*aListenerStruct = ls;
} else {
*aListenerStruct = nsnull;
} }
return rv; return rv;
@ -516,81 +522,16 @@ nsEventListenerManager::AddScriptEventListener(nsIAtom *aName,
void *scope = global->GetScriptGlobal(aLanguage); void *scope = global->GetScriptGlobal(aLanguage);
nsListenerStruct *ls;
rv = SetJSEventListener(context, scope, aName, nsnull,
aPermitUntrustedEvents, &ls);
NS_ENSURE_SUCCESS(rv, rv);
if (!aDeferCompilation) { if (!aDeferCompilation) {
nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner = return CompileEventHandlerInternal(ls, PR_TRUE, &aBody);
do_QueryInterface(mTarget);
nsScriptObjectHolder handler(context);
PRBool done = PR_FALSE;
if (handlerOwner) {
rv = handlerOwner->GetCompiledEventHandler(aName, handler);
if (NS_SUCCEEDED(rv) && handler) {
rv = context->BindCompiledEventHandler(mTarget, scope, aName, handler);
if (NS_FAILED(rv))
return rv;
done = PR_TRUE;
}
}
if (!done) {
PRUint32 lineNo = 0;
nsCAutoString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
if (doc) {
nsIURI *uri = doc->GetDocumentURI();
if (uri) {
uri->GetSpec(url);
lineNo = 1;
}
}
if (handlerOwner) {
// Always let the handler owner compile the event handler, as
// it may want to use a special context or scope object.
rv = handlerOwner->CompileEventHandler(context, mTarget, aName,
aBody, url.get(), lineNo, handler);
}
else {
PRInt32 nameSpace = kNameSpaceID_Unknown;
if (node && node->IsNodeOfType(nsINode::eCONTENT)) {
nsIContent* content = static_cast<nsIContent*>(node.get());
nameSpace = content->GetNameSpaceID();
}
else if (doc) {
Element* root = doc->GetRootElement();
if (root)
nameSpace = root->GetNameSpaceID();
}
PRUint32 argCount;
const char **argNames;
nsContentUtils::GetEventArgNames(nameSpace, aName, &argCount,
&argNames);
nsCxPusher pusher;
if (!pusher.Push((JSContext*)context->GetNativeContext())) {
return NS_ERROR_FAILURE;
}
rv = context->CompileEventHandler(aName, argCount, argNames,
aBody,
url.get(), lineNo,
SCRIPTVERSION_DEFAULT, // for now?
handler);
if (rv == NS_ERROR_ILLEGAL_VALUE) {
NS_WARNING("Probably a syntax error in the event handler!");
return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
}
NS_ENSURE_SUCCESS(rv, rv);
// And bind it.
rv = context->BindCompiledEventHandler(mTarget, scope,
aName, handler);
}
if (NS_FAILED(rv)) return rv;
}
} }
return SetJSEventListener(context, scope, aName, aDeferCompilation, return NS_OK;
aPermitUntrustedEvents);
} }
void void
@ -606,211 +547,153 @@ nsEventListenerManager::RemoveScriptEventListener(nsIAtom* aName)
} }
} }
jsid
nsEventListenerManager::sAddListenerID = JSID_VOID;
nsresult nsresult
nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext, nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
void *aScope, PRBool aNeedsCxPush,
nsIAtom *aName) const nsAString* aBody)
{ {
// Check that we have access to set an event listener. Prevents NS_PRECONDITION(aListenerStruct->GetJSListener(),
// snooping attacks across domains by setting onkeypress handlers, "Why do we not have a JS listener?");
// for instance. NS_PRECONDITION(aListenerStruct->mHandlerIsString,
// You'd think it'd work just to get the JSContext from aContext, "Why are we compiling a non-string JS listener?");
// but that's actually the JSContext whose private object parents
// the object in mTarget.
nsresult rv;
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
if (NS_FAILED(rv))
return rv;
JSContext *cx;
if (NS_FAILED(rv = stack->Peek(&cx)))
return rv;
if (cx) {
if (sAddListenerID == JSID_VOID) {
JSAutoRequest ar(cx);
sAddListenerID =
INTERNED_STRING_TO_JSID(cx, ::JS_InternString(cx, "addEventListener"));
}
if (aContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) {
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
jsval v;
rv = nsContentUtils::WrapNative(cx, (JSObject *)aScope, mTarget, &v,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
rv = nsContentUtils::GetSecurityManager()->
CheckPropertyAccess(cx, JSVAL_TO_OBJECT(v),
"EventTarget",
sAddListenerID,
nsIXPCSecurityManager::ACCESS_SET_PROPERTY);
if (NS_FAILED(rv)) {
// XXX set pending exception on the native call context?
return rv;
}
} else {
NS_WARNING("Skipping CheckPropertyAccess for non JS language");
}
}
// Untrusted events are always permitted for non-chrome script
// handlers.
return SetJSEventListener(aContext, aScope, aName, PR_FALSE,
!nsContentUtils::IsCallerChrome());
}
nsresult
nsEventListenerManager::CompileScriptEventListener(nsIScriptContext *aContext,
void *aScope,
nsIAtom *aName,
PRBool *aDidCompile)
{
nsresult rv = NS_OK;
*aDidCompile = PR_FALSE;
PRUint32 eventType = nsContentUtils::GetEventId(aName);
nsListenerStruct* ls = FindJSEventListener(eventType, aName);
if (!ls) {
//nothing to compile
return NS_OK;
}
if (ls->mHandlerIsString) {
rv = CompileEventHandlerInternal(aContext, aScope, mTarget, aName,
ls, /*XXX fixme*/nsnull, PR_TRUE);
}
// Set *aDidCompile to true even if we didn't really compile
// anything right now, if we get here it means that this event
// handler has been compiled at some point, that's good enough for
// us.
*aDidCompile = PR_TRUE;
return rv;
}
nsresult
nsEventListenerManager::CompileEventHandlerInternal(nsIScriptContext *aContext,
void *aScope,
nsISupports *aObject,
nsIAtom *aName,
nsListenerStruct *aListenerStruct,
nsISupports* aCurrentTarget,
PRBool aNeedsCxPush)
{
nsresult result = NS_OK; nsresult result = NS_OK;
nsIJSEventListener *listener = aListenerStruct->GetJSListener();
NS_ASSERTION(!listener->GetHandler(), "What is there to compile?");
nsIScriptContext *context = listener->GetEventContext();
nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner = nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
do_QueryInterface(aObject); do_QueryInterface(mTarget);
nsScriptObjectHolder handler(aContext); nsScriptObjectHolder handler(context);
if (handlerOwner) { if (handlerOwner) {
result = handlerOwner->GetCompiledEventHandler(aName, result = handlerOwner->GetCompiledEventHandler(aListenerStruct->mTypeAtom,
handler); handler);
if (NS_SUCCEEDED(result) && handler) { if (NS_SUCCEEDED(result) && handler) {
// XXXmarkh - why do we bind here, but not after compilation below?
result = aContext->BindCompiledEventHandler(aObject, aScope, aName, handler);
aListenerStruct->mHandlerIsString = PR_FALSE; aListenerStruct->mHandlerIsString = PR_FALSE;
} else {
// Make sure there's nothing in the holder in the failure case
handler.set(nsnull);
} }
} }
if (aListenerStruct->mHandlerIsString) { if (aListenerStruct->mHandlerIsString) {
// This should never happen for anything but content // OK, we didn't find an existing compiled event handler. Flag us
// XXX I don't like that we have to reference content // as not a string so we don't keep trying to compile strings
// from here. The alternative is to store the event handler // which can't be compiled
// string on the JS object itself. aListenerStruct->mHandlerIsString = PR_FALSE;
nsCOMPtr<nsIContent> content = do_QueryInterface(aObject);
NS_ASSERTION(content, "only content should have event handler attributes"); // mTarget may not be an nsIContent if it's a window and we're
if (content) { // getting an inline event listener forwarded from <html:body> or
nsAutoString handlerBody; // <html:frameset> or <xul:window> or the like.
nsIAtom* attrName = aName; // XXX I don't like that we have to reference content from
if (aName == nsGkAtoms::onSVGLoad) // here. The alternative is to store the event handler string on
// the nsIJSEventListener itself, and that still doesn't address
// the arg names issue.
nsCOMPtr<nsIContent> content = do_QueryInterface(mTarget);
nsAutoString handlerBody;
const nsAString* body = aBody;
if (content && !aBody) {
nsIAtom* attrName = aListenerStruct->mTypeAtom;
if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGLoad)
attrName = nsGkAtoms::onload; attrName = nsGkAtoms::onload;
else if (aName == nsGkAtoms::onSVGUnload) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGUnload)
attrName = nsGkAtoms::onunload; attrName = nsGkAtoms::onunload;
else if (aName == nsGkAtoms::onSVGAbort) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGAbort)
attrName = nsGkAtoms::onabort; attrName = nsGkAtoms::onabort;
else if (aName == nsGkAtoms::onSVGError) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGError)
attrName = nsGkAtoms::onerror; attrName = nsGkAtoms::onerror;
else if (aName == nsGkAtoms::onSVGResize) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGResize)
attrName = nsGkAtoms::onresize; attrName = nsGkAtoms::onresize;
else if (aName == nsGkAtoms::onSVGScroll) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGScroll)
attrName = nsGkAtoms::onscroll; attrName = nsGkAtoms::onscroll;
else if (aName == nsGkAtoms::onSVGZoom) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGZoom)
attrName = nsGkAtoms::onzoom; attrName = nsGkAtoms::onzoom;
#ifdef MOZ_SMIL #ifdef MOZ_SMIL
else if (aName == nsGkAtoms::onbeginEvent) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onbeginEvent)
attrName = nsGkAtoms::onbegin; attrName = nsGkAtoms::onbegin;
else if (aName == nsGkAtoms::onrepeatEvent) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onrepeatEvent)
attrName = nsGkAtoms::onrepeat; attrName = nsGkAtoms::onrepeat;
else if (aName == nsGkAtoms::onendEvent) else if (aListenerStruct->mTypeAtom == nsGkAtoms::onendEvent)
attrName = nsGkAtoms::onend; attrName = nsGkAtoms::onend;
#endif // MOZ_SMIL #endif // MOZ_SMIL
content->GetAttr(kNameSpaceID_None, attrName, handlerBody); content->GetAttr(kNameSpaceID_None, attrName, handlerBody);
body = &handlerBody;
}
PRUint32 lineNo = 0; PRUint32 lineNo = 0;
nsCAutoString url (NS_LITERAL_CSTRING("javascript:alert('TODO: FIXME')")); nsCAutoString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
nsIDocument* doc = nsnull; nsCOMPtr<nsIDocument> doc;
nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentTarget); if (content) {
if (node) { doc = content->GetOwnerDoc();
doc = node->GetOwnerDoc(); } else {
} nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget);
if (doc) { if (win) {
nsIURI *uri = doc->GetDocumentURI(); doc = do_QueryInterface(win->GetExtantDocument());
if (uri) {
uri->GetSpec(url);
lineNo = 1;
}
}
nsCxPusher pusher;
if (aNeedsCxPush &&
!pusher.Push((JSContext*)aContext->GetNativeContext())) {
return NS_ERROR_FAILURE;
}
if (handlerOwner) {
// Always let the handler owner compile the event
// handler, as it may want to use a special
// context or scope object.
result = handlerOwner->CompileEventHandler(aContext, aObject, aName,
handlerBody,
url.get(), lineNo,
handler);
}
else {
PRUint32 argCount;
const char **argNames;
nsContentUtils::GetEventArgNames(content->GetNameSpaceID(), aName,
&argCount, &argNames);
result = aContext->CompileEventHandler(aName,
argCount, argNames,
handlerBody,
url.get(), lineNo,
SCRIPTVERSION_DEFAULT, // for now?
handler);
NS_ENSURE_SUCCESS(result, result);
// And bind it.
result = aContext->BindCompiledEventHandler(aObject, aScope,
aName, handler);
NS_ENSURE_SUCCESS(result, result);
}
if (NS_SUCCEEDED(result)) {
aListenerStruct->mHandlerIsString = PR_FALSE;
} }
} }
if (doc) {
nsIURI *uri = doc->GetDocumentURI();
if (uri) {
uri->GetSpec(url);
lineNo = 1;
}
}
nsCxPusher pusher;
if (aNeedsCxPush &&
!pusher.Push((JSContext*)context->GetNativeContext())) {
return NS_ERROR_FAILURE;
}
if (handlerOwner) {
// Always let the handler owner compile the event
// handler, as it may want to use a special
// context or scope object.
result = handlerOwner->CompileEventHandler(context,
aListenerStruct->mTypeAtom,
*body,
url.get(), lineNo,
handler);
} else {
PRUint32 argCount;
const char **argNames;
// If no content, then just use kNameSpaceID_None for the
// namespace ID. In practice, it doesn't matter since SVG is
// the only thing with weird arg names and SVG doesn't map event
// listeners to the window.
nsContentUtils::GetEventArgNames(content ?
content->GetNameSpaceID() :
kNameSpaceID_None,
aListenerStruct->mTypeAtom,
&argCount, &argNames);
result = context->CompileEventHandler(aListenerStruct->mTypeAtom,
argCount, argNames,
*body,
url.get(), lineNo,
SCRIPTVERSION_DEFAULT, // for now?
handler);
if (result == NS_ERROR_ILLEGAL_VALUE) {
NS_WARNING("Probably a syntax error in the event handler!");
return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
}
NS_ENSURE_SUCCESS(result, result);
}
} }
if (handler) {
// Bind it
nsScriptObjectHolder boundHandler(context);
context->BindCompiledEventHandler(mTarget, listener->GetEventScope(),
handler, boundHandler);
listener->SetHandler(boundHandler);
}
return result; return result;
} }
@ -828,34 +711,11 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
// compiled the event handler itself // compiled the event handler itself
if ((aListenerStruct->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && if ((aListenerStruct->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) &&
aListenerStruct->mHandlerIsString) { aListenerStruct->mHandlerIsString) {
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListener); nsIJSEventListener *jslistener = aListenerStruct->GetJSListener();
if (jslistener) { result = CompileEventHandlerInternal(aListenerStruct,
// We probably have the atom already. jslistener->GetEventContext() !=
nsCOMPtr<nsIAtom> atom = aListenerStruct->mTypeAtom; aPusher->GetCurrentScriptContext(),
if (!atom) { nsnull);
nsAutoString eventString;
if (NS_SUCCEEDED(aDOMEvent->GetType(eventString))) {
atom = do_GetAtom(NS_LITERAL_STRING("on") + eventString);
}
}
if (atom) {
#ifdef DEBUG
nsAutoString type;
aDOMEvent->GetType(type);
nsCOMPtr<nsIAtom> eventAtom = do_GetAtom(NS_LITERAL_STRING("on") + type);
NS_ASSERTION(eventAtom == atom, "Something wrong with event atoms!");
#endif
result = CompileEventHandlerInternal(jslistener->GetEventContext(),
jslistener->GetEventScope(),
jslistener->GetEventTarget(),
atom, aListenerStruct,
aCurrentTarget,
!jslistener->GetEventContext() ||
jslistener->GetEventContext() !=
aPusher->GetCurrentScriptContext());
}
}
} }
if (NS_SUCCEEDED(result)) { if (NS_SUCCEEDED(result)) {
@ -1040,18 +900,10 @@ nsEventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
PRBool systemGroup = !!(ls.mFlags & NS_EVENT_FLAG_SYSTEM_EVENT); PRBool systemGroup = !!(ls.mFlags & NS_EVENT_FLAG_SYSTEM_EVENT);
PRBool allowsUntrusted = !!(ls.mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED); PRBool allowsUntrusted = !!(ls.mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED);
// If this is a script handler and we haven't yet // If this is a script handler and we haven't yet
// compiled the event handler itself // compiled the event handler itself go ahead and compile it
if ((ls.mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && ls.mHandlerIsString) { if ((ls.mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && ls.mHandlerIsString) {
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(ls.mListener); CompileEventHandlerInternal(const_cast<nsListenerStruct*>(&ls),
if (jslistener) { PR_TRUE, nsnull);
CompileEventHandlerInternal(jslistener->GetEventContext(),
jslistener->GetEventScope(),
jslistener->GetEventTarget(),
ls.mTypeAtom,
const_cast<nsListenerStruct*>(&ls),
mTarget,
PR_TRUE);
}
} }
const nsDependentSubstring& eventType = const nsDependentSubstring& eventType =
Substring(nsDependentAtomString(ls.mTypeAtom), 2); Substring(nsDependentAtomString(ls.mTypeAtom), 2);
@ -1077,3 +929,52 @@ nsEventListenerManager::HasUnloadListeners()
} }
return PR_FALSE; return PR_FALSE;
} }
nsresult
nsEventListenerManager::SetJSEventListenerToJsval(nsIAtom *aEventName,
JSContext *cx,
JSObject* aScope,
const jsval & v)
{
JSObject *handler;
if (JSVAL_IS_PRIMITIVE(v) ||
!JS_ObjectIsCallable(cx, handler = JSVAL_TO_OBJECT(v))) {
RemoveScriptEventListener(aEventName);
return NS_OK;
}
nsIScriptContext *context = nsJSUtils::GetStaticScriptContext(cx, aScope);
JSObject *scope = ::JS_GetGlobalForObject(cx, aScope);
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetJSEventListener(context, scope, aEventName, handler,
!nsContentUtils::IsCallerChrome(), &ignored);
}
void
nsEventListenerManager::GetJSEventListener(nsIAtom *aEventName, jsval *vp)
{
PRUint32 eventType = nsContentUtils::GetEventId(aEventName);
nsListenerStruct* ls = FindJSEventListener(eventType, aEventName);
*vp = JSVAL_NULL;
if (!ls) {
return;
}
nsIJSEventListener *listener = ls->GetJSListener();
if (listener->GetEventContext()->GetScriptTypeID() !=
nsIProgrammingLanguage::JAVASCRIPT) {
// Not JS, so no point doing anything with it.
return;
}
if (ls->mHandlerIsString) {
CompileEventHandlerInternal(ls, PR_TRUE, nsnull);
}
*vp = OBJECT_TO_JSVAL(static_cast<JSObject*>(listener->GetHandler()));
}

View File

@ -50,6 +50,7 @@
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsTObserverArray.h" #include "nsTObserverArray.h"
#include "nsGUIEvent.h" #include "nsGUIEvent.h"
#include "nsIJSEventListener.h"
class nsIDOMEvent; class nsIDOMEvent;
class nsIAtom; class nsIAtom;
@ -60,13 +61,19 @@ class nsEventTargetChainItem;
class nsPIDOMWindow; class nsPIDOMWindow;
class nsCxPusher; class nsCxPusher;
class nsIEventListenerInfo; class nsIEventListenerInfo;
class nsIDocument;
typedef struct { typedef struct {
nsRefPtr<nsIDOMEventListener> mListener; nsRefPtr<nsIDOMEventListener> mListener;
PRUint32 mEventType; PRUint32 mEventType;
nsCOMPtr<nsIAtom> mTypeAtom; nsCOMPtr<nsIAtom> mTypeAtom;
PRUint16 mFlags; PRUint16 mFlags;
PRBool mHandlerIsString; PRPackedBool mHandlerIsString;
nsIJSEventListener* GetJSListener() const {
return (mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) ?
static_cast<nsIJSEventListener *>(mListener.get()) : nsnull;
}
} nsListenerStruct; } nsListenerStruct;
/* /*
@ -102,18 +109,24 @@ public:
void RemoveEventListenerByType(nsIDOMEventListener *aListener, void RemoveEventListenerByType(nsIDOMEventListener *aListener,
const nsAString& type, const nsAString& type,
PRInt32 aFlags); PRInt32 aFlags);
/**
* Sets the current "inline" event listener for aName to be a
* function compiled from aFunc if !aDeferCompilation. If
* aDeferCompilation, then we assume that we can get the string from
* mTarget later and compile lazily.
*/
// XXXbz does that play correctly with nodes being adopted across
// documents? Need to double-check the spec here.
nsresult AddScriptEventListener(nsIAtom *aName, nsresult AddScriptEventListener(nsIAtom *aName,
const nsAString& aFunc, const nsAString& aFunc,
PRUint32 aLanguage, PRUint32 aLanguage,
PRBool aDeferCompilation, PRBool aDeferCompilation,
PRBool aPermitUntrustedEvents); PRBool aPermitUntrustedEvents);
nsresult RegisterScriptEventListener(nsIScriptContext *aContext, /**
void *aScopeObject, * Remove the current "inline" event listener for aName.
nsIAtom* aName); */
void RemoveScriptEventListener(nsIAtom *aName); void RemoveScriptEventListener(nsIAtom *aName);
nsresult CompileScriptEventListener(nsIScriptContext *aContext,
void *aScopeObject,
nsIAtom* aName, PRBool *aDidCompile);
void HandleEvent(nsPresContext* aPresContext, void HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent, nsEvent* aEvent,
@ -155,18 +168,46 @@ public:
nsEventStatus* aEventStatus, nsEventStatus* aEventStatus,
nsCxPusher* aPusher); nsCxPusher* aPusher);
/**
* Tells the event listener manager that its target (which owns it) is
* no longer using it (and could go away).
*/
void Disconnect(); void Disconnect();
/**
* Allows us to quickly determine if we have mutation listeners registered.
*/
PRBool HasMutationListeners(); PRBool HasMutationListeners();
/**
* Allows us to quickly determine whether we have unload or beforeunload
* listeners registered.
*/
PRBool HasUnloadListeners(); PRBool HasUnloadListeners();
/**
* Returns the mutation bits depending on which mutation listeners are
* registered to this listener manager.
* @note If a listener is an nsIDOMMutationListener, all possible mutation
* event bits are returned. All bits are also returned if one of the
* event listeners is registered to handle DOMSubtreeModified events.
*/
PRUint32 MutationListenerBits(); PRUint32 MutationListenerBits();
/**
* Returns PR_TRUE if there is at least one event listener for aEventName.
*/
PRBool HasListenersFor(const nsAString& aEventName); PRBool HasListenersFor(const nsAString& aEventName);
/**
* Returns PR_TRUE if there is at least one event listener.
*/
PRBool HasListeners(); PRBool HasListeners();
/**
* Sets aList to the list of nsIEventListenerInfo objects representing the
* listeners managed by this listener manager.
*/
nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList); nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
PRUint32 GetIdentifierForEvent(nsIAtom* aEvent); PRUint32 GetIdentifierForEvent(nsIAtom* aEvent);
@ -198,18 +239,49 @@ protected:
nsIDOMEventTarget* aCurrentTarget, nsIDOMEventTarget* aCurrentTarget,
PRUint32 aPhaseFlags, PRUint32 aPhaseFlags,
nsCxPusher* aPusher); nsCxPusher* aPusher);
nsresult CompileEventHandlerInternal(nsIScriptContext *aContext,
void *aScopeObject, /**
nsISupports *aObject, * Compile the "inline" event listener for aListenerStruct. The
nsIAtom *aName, * body of the listener can be provided in aBody; if this is null we
nsListenerStruct *aListenerStruct, * will look for it on mTarget.
nsISupports* aCurrentTarget, */
PRBool aNeedsCxPush); nsresult CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
PRBool aNeedsCxPush,
const nsAString* aBody);
/**
* Find the nsListenerStruct for the "inline" event listener for aTypeAtom.
*/
nsListenerStruct* FindJSEventListener(PRUint32 aEventType, nsIAtom* aTypeAtom); nsListenerStruct* FindJSEventListener(PRUint32 aEventType, nsIAtom* aTypeAtom);
/**
* Set the "inline" event listener for aName to aHandler. aHandler
* may be null to indicate that we should lazily get and compile the
* string for this listener. The nsListenerStruct that results, if
* any, is returned in aListenerStruct.
*/
nsresult SetJSEventListener(nsIScriptContext *aContext, nsresult SetJSEventListener(nsIScriptContext *aContext,
void *aScopeGlobal, void *aScopeGlobal,
nsIAtom* aName, PRBool aIsString, nsIAtom* aName,
PRBool aPermitUntrustedEvents); JSObject *aHandler,
PRBool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct);
public:
/**
* Set the "inline" event listener for aEventName to |v|. This
* might actually remove the event listener, depending on the value
* of |v|.
*/
nsresult SetJSEventListenerToJsval(nsIAtom *aEventName, JSContext *cx,
JSObject *aScope, const jsval &v);
/**
* Get the value of the "inline" event listener for aEventName.
* This may cause lazy compilation if the listener is uncompiled.
*/
void GetJSEventListener(nsIAtom *aEventName, jsval *vp);
protected:
void AddEventListener(nsIDOMEventListener *aListener, void AddEventListener(nsIDOMEventListener *aListener,
PRUint32 aType, PRUint32 aType,
nsIAtom* aTypeAtom, nsIAtom* aTypeAtom,

View File

@ -112,8 +112,9 @@ nsEventListenerInfo::GetJSVal(jsval* aJSVal)
nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener); nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
if (jsl) { if (jsl) {
nsresult rv = jsl->GetJSVal(mType, aJSVal); void *handler = jsl->GetHandler();
if (NS_SUCCEEDED(rv)) { if (handler) {
*aJSVal = OBJECT_TO_JSVAL(static_cast<JSObject*>(handler));
return PR_TRUE; return PR_TRUE;
} }
} }

View File

@ -47,8 +47,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=379120
var transformedDocument = processor.transformToDocument (originalDoc); var transformedDocument = processor.transformToDocument (originalDoc);
is(transformedDocument.documentElement.getAttribute("onload"), is(transformedDocument.documentElement.getAttribute("onload"),
"var i = 1"); "var i = 1");
ok(transformedDocument.documentElement.onload === undefined, ok(transformedDocument.documentElement.onload === null,
"Shouldn't have onload handler"); "Shouldn't have onload handler",
"got " + repr(transformedDocument.documentElement.onload) +
", expected null");;
</script> </script>
</pre> </pre>
</body> </body>

View File

@ -1245,7 +1245,8 @@ nsGenericHTMLElement::GetEventListenerManagerForAttr(PRBool* aDefer)
// FIXME (https://bugzilla.mozilla.org/show_bug.cgi?id=431767) // FIXME (https://bugzilla.mozilla.org/show_bug.cgi?id=431767)
// nsDocument::GetInnerWindow can return an outer window in some cases, // nsDocument::GetInnerWindow can return an outer window in some cases,
// we don't want to stick an event listener on an outer window, so // we don't want to stick an event listener on an outer window, so
// bail if it does. // bail if it does. See similar code in nsHTMLBodyElement and
// nsHTMLFramesetElement
*aDefer = PR_FALSE; *aDefer = PR_FALSE;
if (document && if (document &&
(win = document->GetInnerWindow()) && win->IsInnerWindow()) { (win = document->GetInnerWindow()) && win->IsInnerWindow()) {

View File

@ -57,6 +57,7 @@
#include "nsIEditorDocShell.h" #include "nsIEditorDocShell.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsRuleWalker.h" #include "nsRuleWalker.h"
#include "jsapi.h"
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@ -105,6 +106,16 @@ public:
// nsIDOMHTMLBodyElement // nsIDOMHTMLBodyElement
NS_DECL_NSIDOMHTMLBODYELEMENT NS_DECL_NSIDOMHTMLBODYELEMENT
// Event listener stuff; we need to declare only the ones we need to
// forward to window that don't come from nsIDOMHTMLBodyElement.
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp); \
NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v);
#include "nsEventNameList.h"
#undef FORWARDED_EVENT
#undef EVENT
virtual PRBool ParseAttribute(PRInt32 aNamespaceID, virtual PRBool ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute, nsIAtom* aAttribute,
const nsAString& aValue, const nsAString& aValue,
@ -488,3 +499,54 @@ nsHTMLBodyElement::GetAssociatedEditor()
editorDocShell->GetEditor(&editor); editorDocShell->GetEditor(&editor);
return editor; return editor;
} }
// Event listener stuff
// FIXME (https://bugzilla.mozilla.org/show_bug.cgi?id=431767)
// nsDocument::GetInnerWindow can return an outer window in some
// cases. We don't want to stick an event listener on an outer
// window, so bail if it does. See also similar code in
// nsGenericHTMLElement::GetEventListenerManagerForAttr.
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsHTMLBodyElement::GetOn##name_(JSContext *cx, \
jsval *vp) { \
/* XXXbz note to self: add tests for this! */ \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
nsCOMPtr<nsIInlineEventHandlers> ev = do_QueryInterface(win); \
return ev->GetOn##name_(cx, vp); \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsHTMLBodyElement::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
nsCOMPtr<nsIInlineEventHandlers> ev = do_QueryInterface(win); \
return ev->SetOn##name_(cx, v); \
} \
return NS_OK; \
}
#define WINDOW_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsHTMLBodyElement::GetOn##name_(JSContext *cx, \
jsval *vp) { \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
return win->GetOn##name_(cx, vp); \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsHTMLBodyElement::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
return win->SetOn##name_(cx, v); \
} \
return NS_OK; \
}
#include "nsEventNameList.h"
#undef WINDOW_EVENT
#undef FORWARDED_EVENT
#undef EVENT

View File

@ -36,6 +36,7 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "nsHTMLFrameSetElement.h" #include "nsHTMLFrameSetElement.h"
#include "jsapi.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet) NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
@ -347,3 +348,55 @@ nsHTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
return NS_OK; return NS_OK;
} }
// Event listener stuff
// FIXME (https://bugzilla.mozilla.org/show_bug.cgi?id=431767)
// nsDocument::GetInnerWindow can return an outer window in some
// cases. We don't want to stick an event listener on an outer
// window, so bail if it does. See also similar code in
// nsGenericHTMLElement::GetEventListenerManagerForAttr.
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the shim */
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsHTMLFrameSetElement::GetOn##name_(JSContext *cx, \
jsval *vp) { \
/* XXXbz note to self: add tests for this! */ \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
nsCOMPtr<nsIInlineEventHandlers> ev = do_QueryInterface(win); \
return ev->GetOn##name_(cx, vp); \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsHTMLFrameSetElement::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
nsCOMPtr<nsIInlineEventHandlers> ev = do_QueryInterface(win); \
return ev->SetOn##name_(cx, v); \
} \
return NS_OK; \
}
#define WINDOW_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsHTMLFrameSetElement::GetOn##name_(JSContext *cx, \
jsval *vp) { \
/* XXXbz note to self: add tests for this! */ \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
return win->GetOn##name_(cx, vp); \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsHTMLFrameSetElement::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsPIDOMWindow* win = GetOwnerDoc()->GetInnerWindow(); \
if (win && win->IsInnerWindow()) { \
return win->SetOn##name_(cx, v); \
} \
return NS_OK; \
}
#include "nsEventNameList.h"
#undef WINDOW_EVENT
#undef FORWARDED_EVENT
#undef EVENT

View File

@ -74,6 +74,8 @@ struct nsFramesetSpec {
*/ */
#define NS_MAX_FRAMESET_SPEC_COUNT 16000 #define NS_MAX_FRAMESET_SPEC_COUNT 16000
//----------------------------------------------------------------------
class nsHTMLFrameSetElement : public nsGenericHTMLElement, class nsHTMLFrameSetElement : public nsGenericHTMLElement,
public nsIDOMHTMLFrameSetElement public nsIDOMHTMLFrameSetElement
{ {
@ -96,6 +98,16 @@ public:
// nsIDOMHTMLFrameSetElement // nsIDOMHTMLFrameSetElement
NS_DECL_NSIDOMHTMLFRAMESETELEMENT NS_DECL_NSIDOMHTMLFRAMESETELEMENT
// Event listener stuff; we need to declare only the ones we need to
// forward to window that don't come from nsIDOMHTMLFrameSetElement.
#define EVENT(name_, id_, type_, struct_) /* nothing; handled by the superclass */
#define FORWARDED_EVENT(name_, id_, type_, struct_) \
NS_IMETHOD GetOn##name_(JSContext *cx, jsval *vp); \
NS_IMETHOD SetOn##name_(JSContext *cx, const jsval &v);
#include "nsEventNameList.h"
#undef FORWARDED_EVENT
#undef EVENT
// These override the SetAttr methods in nsGenericHTMLElement (need // These override the SetAttr methods in nsGenericHTMLElement (need
// both here to silence compiler warnings). // both here to silence compiler warnings).
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,

View File

@ -36,7 +36,8 @@ function HTML_TAG(aTagName, aImplClass) {
"nsIDOMNSHTMLElement", "nsIDOMNSHTMLElement",
"nsIDOMElementCSSInlineStyle", "nsIDOMElementCSSInlineStyle",
"nsIDOMNodeSelector", "nsIDOMNodeSelector",
"nsITouchEventReceiver" ]; "nsITouchEventReceiver",
"nsIInlineEventHandlers" ];
// Some interfaces don't appear in classinfo because other interfaces that // Some interfaces don't appear in classinfo because other interfaces that
// inherit from them do. // inherit from them do.

View File

@ -318,17 +318,19 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventTarget* aTarget,
rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, handler); rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, handler);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Temporarily bind it to the bound element // Bind it to the bound element
void *scope = boundGlobal->GetScriptGlobal(stID); void *scope = boundGlobal->GetScriptGlobal(stID);
nsScriptObjectHolder boundHandler(boundContext);
rv = boundContext->BindCompiledEventHandler(scriptTarget, scope, rv = boundContext->BindCompiledEventHandler(scriptTarget, scope,
onEventAtom, handler); handler, boundHandler);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Execute it. // Execute it.
nsCOMPtr<nsIDOMEventListener> eventListener; nsCOMPtr<nsIDOMEventListener> eventListener;
NS_NewJSEventListener(boundContext, scope, rv = NS_NewJSEventListener(boundContext, scope,
scriptTarget, onEventAtom, scriptTarget, onEventAtom,
getter_AddRefs(eventListener)); boundHandler, getter_AddRefs(eventListener));
NS_ENSURE_SUCCESS(rv, rv);
// Handle the event. // Handle the event.
eventListener->HandleEvent(aEvent); eventListener->HandleEvent(aEvent);

View File

@ -159,7 +159,6 @@ public:
// nsIScriptEventHandlerOwner // nsIScriptEventHandlerOwner
virtual nsresult CompileEventHandler(nsIScriptContext* aContext, virtual nsresult CompileEventHandler(nsIScriptContext* aContext,
nsISupports* aTarget,
nsIAtom *aName, nsIAtom *aName,
const nsAString& aBody, const nsAString& aBody,
const char* aURL, const char* aURL,
@ -743,7 +742,6 @@ nsScriptEventHandlerOwnerTearoff::GetCompiledEventHandler(
nsresult nsresult
nsScriptEventHandlerOwnerTearoff::CompileEventHandler( nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
nsIScriptContext* aContext, nsIScriptContext* aContext,
nsISupports* aTarget,
nsIAtom *aName, nsIAtom *aName,
const nsAString& aBody, const nsAString& aBody,
const char* aURL, const char* aURL,
@ -786,8 +784,6 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED); NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
} }
else { else {
// We don't have a prototype, so the passed context is ok.
NS_ASSERTION(aTarget != nsnull, "no prototype and no target?!");
context = aContext; context = aContext;
} }
@ -808,12 +804,6 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
aHandler); aHandler);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// XXX: Shouldn't this use context and not aContext?
// XXXmarkh - is GetNativeGlobal() the correct scope?
rv = aContext->BindCompiledEventHandler(aTarget, aContext->GetNativeGlobal(),
aName, aHandler);
if (NS_FAILED(rv)) return rv;
nsXULPrototypeAttribute *attr = nsXULPrototypeAttribute *attr =
mElement->FindPrototypeAttribute(kNameSpaceID_None, aName); mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
if (attr) { if (attr) {

View File

@ -523,7 +523,6 @@ static const char kDOMStringBundleURL[] =
(nsIXPCScriptable::WANT_GETPROPERTY | \ (nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \ nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_PRECREATE | \ nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_ADDPROPERTY | \
nsIXPCScriptable::WANT_FINALIZE | \ nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_EQUALITY | \ nsIXPCScriptable::WANT_EQUALITY | \
nsIXPCScriptable::WANT_ENUMERATE | \ nsIXPCScriptable::WANT_ENUMERATE | \
@ -788,7 +787,7 @@ static nsDOMClassInfoData sClassInfoData[] = {
ELEMENT_SCRIPTABLE_FLAGS) ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLBaseElement, nsElementSH, NS_DEFINE_CLASSINFO_DATA(HTMLBaseElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS) ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLBodyElement, nsHTMLBodyElementSH, NS_DEFINE_CLASSINFO_DATA(HTMLBodyElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS) ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLButtonElement, nsElementSH, NS_DEFINE_CLASSINFO_DATA(HTMLButtonElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS) ELEMENT_SCRIPTABLE_FLAGS)
@ -1625,15 +1624,8 @@ jsid nsDOMClassInfo::sURL_id = JSID_VOID;
jsid nsDOMClassInfo::sKeyPath_id = JSID_VOID; jsid nsDOMClassInfo::sKeyPath_id = JSID_VOID;
jsid nsDOMClassInfo::sAutoIncrement_id = JSID_VOID; jsid nsDOMClassInfo::sAutoIncrement_id = JSID_VOID;
jsid nsDOMClassInfo::sUnique_id = JSID_VOID; jsid nsDOMClassInfo::sUnique_id = JSID_VOID;
jsid nsDOMClassInfo::sOnload_id = JSID_VOID;
#define EVENT(name_, id_, type_, struct_) \ jsid nsDOMClassInfo::sOnerror_id = JSID_VOID;
jsid nsDOMClassInfo::sOn##name_##_id = JSID_VOID;
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef WINDOW_ONLY_EVENT
#undef EVENT
static const JSClass *sObjectClass = nsnull; static const JSClass *sObjectClass = nsnull;
@ -1895,16 +1887,9 @@ nsDOMClassInfo::DefineStaticJSVals(JSContext *cx)
SET_JSID_TO_STRING(sKeyPath_id, cx, "keyPath"); SET_JSID_TO_STRING(sKeyPath_id, cx, "keyPath");
SET_JSID_TO_STRING(sAutoIncrement_id, cx, "autoIncrement"); SET_JSID_TO_STRING(sAutoIncrement_id, cx, "autoIncrement");
SET_JSID_TO_STRING(sUnique_id, cx, "unique"); SET_JSID_TO_STRING(sUnique_id, cx, "unique");
SET_JSID_TO_STRING(sOnload_id, cx, "onload");
SET_JSID_TO_STRING(sOnerror_id, cx, "onerror");
#define EVENT(name_, id_, type_, struct_) \
SET_JSID_TO_STRING(sOn##name_##_id, cx, "on" #name_);
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef WINDOW_ONLY_EVENT
#undef EVENT
return NS_OK; return NS_OK;
} }
@ -2201,6 +2186,7 @@ nsDOMClassInfo::RegisterExternalClasses()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathEvaluator) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathEvaluator) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMDocumentTouch, \ DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMDocumentTouch, \
nsDOMTouchEvent::PrefEnabled()) nsDOMTouchEvent::PrefEnabled())
@ -2211,6 +2197,7 @@ nsDOMClassInfo::RegisterExternalClasses()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \ DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \
nsDOMTouchEvent::PrefEnabled()) nsDOMTouchEvent::PrefEnabled())
@ -2268,6 +2255,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow) DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow) DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMStorageIndexedDB, DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMStorageIndexedDB,
nsGlobalWindow::HasIndexedDBSupport()) nsGlobalWindow::HasIndexedDBSupport())
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMWindowPerformance, DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMWindowPerformance,
@ -2386,6 +2374,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
nsDOMTouchEvent::PrefEnabled()) nsDOMTouchEvent::PrefEnabled())
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END
@ -2919,6 +2908,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementCSSInlineStyle) DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementCSSInlineStyle)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
nsDOMTouchEvent::PrefEnabled()) nsDOMTouchEvent::PrefEnabled())
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END
@ -2969,6 +2959,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow) DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageIndexedDB) DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageIndexedDB)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(RangeException, nsIDOMRangeException) DOM_CLASSINFO_MAP_BEGIN(RangeException, nsIDOMRangeException)
@ -3030,6 +3021,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \ DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \ DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \
nsDOMTouchEvent::PrefEnabled()) nsDOMTouchEvent::PrefEnabled())
@ -3855,6 +3847,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageIndexedDB) DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageIndexedDB)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow) DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DataContainerEvent, nsIDOMDataContainerEvent) DOM_CLASSINFO_MAP_BEGIN(DataContainerEvent, nsIDOMDataContainerEvent)
@ -3966,6 +3959,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
nsDOMTouchEvent::PrefEnabled()) nsDOMTouchEvent::PrefEnabled())
DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_END
@ -4888,15 +4882,8 @@ nsDOMClassInfo::ShutDown()
sKeyPath_id = JSID_VOID; sKeyPath_id = JSID_VOID;
sAutoIncrement_id = JSID_VOID; sAutoIncrement_id = JSID_VOID;
sUnique_id = JSID_VOID; sUnique_id = JSID_VOID;
sOnload_id = JSID_VOID;
#define EVENT(name_, id_, type_, struct_) \ sOnerror_id = JSID_VOID;
sOn##name_##_id = JSID_VOID;
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef WINDOW_ONLY_EVENT
#undef EVENT
NS_IF_RELEASE(sXPConnect); NS_IF_RELEASE(sXPConnect);
NS_IF_RELEASE(sSecMan); NS_IF_RELEASE(sSecMan);
@ -5327,7 +5314,7 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
} }
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval); return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -5523,62 +5510,6 @@ DefineInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsHTMLBodyElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext
*cx, JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval)
{
if (id == sOnhashchange_id) {
// Special handling so |"onhashchange" in document.body| returns true.
if (!JS_DefinePropertyById(cx, obj, id, JSVAL_VOID,
nsnull, nsnull, JSPROP_ENUMERATE)) {
*_retval = PR_FALSE;
return NS_ERROR_FAILURE;
}
*objp = obj;
return NS_OK;
}
return nsElementSH::NewResolve(wrapper, cx, obj, id, flags, objp, _retval);
}
NS_IMETHODIMP
nsHTMLBodyElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
jsval *vp, PRBool *_retval)
{
if (id == sOnhashchange_id) {
// Forward the request to the Window.
if (!JS_GetPropertyById(cx, JS_GetGlobalForObject(cx, obj), id, vp)) {
*_retval = PR_FALSE;
return NS_ERROR_FAILURE;
}
return NS_OK;
}
return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval);
}
NS_IMETHODIMP
nsHTMLBodyElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj,
jsid id, jsval *vp, PRBool *_retval)
{
if (id == sOnhashchange_id) {
// Forward the request to the Window.
if (!JS_SetPropertyById(cx, JS_GetGlobalForObject(cx, obj), id, vp)) {
*_retval = PR_FALSE;
return NS_ERROR_FAILURE;
}
return NS_OK;
}
return nsElementSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
}
class nsDOMConstructor : public nsIDOMDOMConstructor class nsDOMConstructor : public nsIDOMDOMConstructor
{ {
protected: protected:
@ -6756,18 +6687,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_OK; return NS_OK;
} }
if (id == sOnhashchange_id) {
// Special handling so |"onhashchange" in window| returns true
if (!JS_DefinePropertyById(cx, obj, id, JSVAL_VOID,
nsnull, nsnull, JSPROP_ENUMERATE)) {
*_retval = PR_FALSE;
return NS_ERROR_FAILURE;
}
*objp = obj;
return NS_OK;
}
if (flags & JSRESOLVE_ASSIGNING) { if (flags & JSRESOLVE_ASSIGNING) {
if (IsReadonlyReplaceable(id) || if (IsReadonlyReplaceable(id) ||
(!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) { (!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) {
@ -6890,8 +6809,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
} }
JSObject *oldobj = *objp; JSObject *oldobj = *objp;
rv = nsEventReceiverSH::NewResolve(wrapper, cx, obj, id, flags, objp, rv = nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval); _retval);
if (NS_FAILED(rv) || *objp != oldobj) { if (NS_FAILED(rv) || *objp != oldobj) {
// Something went wrong, or the property got resolved. Return. // Something went wrong, or the property got resolved. Return.
@ -7295,7 +7214,7 @@ nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval) JSObject *obj, jsid id, jsval *vp, PRBool *_retval)
{ {
nsNodeSH::PreserveWrapper(GetNative(wrapper, obj)); nsNodeSH::PreserveWrapper(GetNative(wrapper, obj));
return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval); return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -7311,11 +7230,15 @@ nsNodeSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (id == sOnload_id || id == sOnerror_id) { if (id == sOnload_id || id == sOnerror_id) {
// Make sure that this node can't go away while waiting for a // Make sure that this node can't go away while waiting for a
// network load that could fire an event handler. // network load that could fire an event handler.
// XXXbz won't this fail if the listener is added using
// addEventListener? On the other hand, even if I comment this
// code out I can't seem to reproduce the bug it was trying to
// fix....
nsNodeSH::PreserveWrapper(GetNative(wrapper, obj)); nsNodeSH::PreserveWrapper(GetNative(wrapper, obj));
} }
return nsEventReceiverSH::NewResolve(wrapper, cx, obj, id, flags, objp, return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval); _retval);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -7372,7 +7295,7 @@ nsNodeSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_ERROR_DOM_NOT_SUPPORTED_ERR; return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
} }
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp,_retval); return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -7390,249 +7313,6 @@ nsNodeSH::PreserveWrapper(nsISupports *aNative)
nsContentUtils::PreserveWrapper(aNative, node); nsContentUtils::PreserveWrapper(aNative, node);
} }
// EventReceiver helper
// static
PRBool
nsEventReceiverSH::ReallyIsEventName(jsid id, jschar aFirstChar)
{
// I wonder if this is faster than using a hash...
switch (aFirstChar) {
case 'a' :
return (id == sOnabort_id ||
id == sOnafterscriptexecute_id ||
id == sOnafterprint_id);
case 'b' :
return (id == sOnbeforeunload_id ||
id == sOnbeforescriptexecute_id ||
id == sOnblur_id ||
id == sOnbeforeprint_id);
case 'c' :
return (id == sOnchange_id ||
id == sOnclick_id ||
id == sOncontextmenu_id ||
id == sOncopy_id ||
id == sOncut_id ||
id == sOncanplay_id ||
id == sOncanplaythrough_id);
case 'd' :
return (id == sOndblclick_id ||
id == sOndrag_id ||
id == sOndragend_id ||
id == sOndragenter_id ||
id == sOndragleave_id ||
id == sOndragover_id ||
id == sOndragstart_id ||
id == sOndrop_id ||
id == sOndurationchange_id ||
id == sOndeviceorientation_id ||
id == sOndevicemotion_id );
case 'e' :
return (id == sOnerror_id ||
id == sOnemptied_id ||
id == sOnended_id);
case 'f' :
return id == sOnfocus_id;
case 'h' :
return id == sOnhashchange_id;
case 'i' :
return (id == sOninput_id ||
id == sOninvalid_id);
case 'k' :
return (id == sOnkeydown_id ||
id == sOnkeypress_id ||
id == sOnkeyup_id);
case 'l' :
return (id == sOnload_id ||
id == sOnloadeddata_id ||
id == sOnloadedmetadata_id ||
id == sOnloadstart_id);
case 'm' :
return (id == sOnmousemove_id ||
id == sOnmouseout_id ||
id == sOnmouseover_id ||
id == sOnmouseup_id ||
id == sOnmousedown_id ||
id == sOnmessage_id);
case 'p' :
return (id == sOnpageshow_id ||
id == sOnpagehide_id ||
id == sOnpaste_id ||
id == sOnpopstate_id ||
id == sOnpause_id ||
id == sOnplay_id ||
id == sOnplaying_id ||
id == sOnprogress_id);
case 'r' :
return (id == sOnreadystatechange_id ||
id == sOnreset_id ||
id == sOnresize_id ||
id == sOnratechange_id);
case 's' :
return (id == sOnscroll_id ||
id == sOnshow_id ||
id == sOnselect_id ||
id == sOnsubmit_id ||
id == sOnseeked_id ||
id == sOnseeking_id ||
id == sOnstalled_id ||
id == sOnsuspend_id);
case 't':
return id == sOntimeupdate_id ||
(nsDOMTouchEvent::PrefEnabled() &&
(id == sOntouchstart_id ||
id == sOntouchend_id ||
id == sOntouchmove_id ||
id == sOntouchenter_id ||
id == sOntouchleave_id ||
id == sOntouchcancel_id));
case 'u' :
return id == sOnunload_id;
case 'v':
return id == sOnvolumechange_id;
case 'w':
return id == sOnwaiting_id;
}
return PR_FALSE;
}
nsresult
nsEventReceiverSH::RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj,
jsid id, PRBool compile,
PRBool remove,
PRBool *did_define)
{
NS_PRECONDITION(!compile || !remove,
"Can't both compile and remove at the same time");
*did_define = PR_FALSE;
if (!IsEventName(id)) {
return NS_OK;
}
if (ObjectIsNativeWrapper(cx, obj)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsIScriptContext *script_cx = nsJSUtils::GetStaticScriptContext(cx, obj);
NS_ENSURE_TRUE(script_cx, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMEventTarget> target =
do_QueryWrappedNative(wrapper, obj);
if (!target) {
// Doesn't do events
NS_WARNING("Doesn't QI to nsIDOMEventTarget?");
return NS_OK;
}
nsEventListenerManager* manager = target->GetListenerManager(PR_TRUE);
NS_ENSURE_TRUE(manager, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIAtom> atom(do_GetAtom(nsDependentJSString(id)));
NS_ENSURE_TRUE(atom, NS_ERROR_OUT_OF_MEMORY);
JSObject *scope = ::JS_GetGlobalForObject(cx, obj);
if (compile) {
nsresult rv = manager->CompileScriptEventListener(script_cx, scope,
atom, did_define);
NS_ENSURE_SUCCESS(rv, rv);
} else if (remove) {
manager->RemoveScriptEventListener(atom);
} else {
manager->RegisterScriptEventListener(script_cx, scope, atom);
}
return NS_SUCCESS_I_DID_SOMETHING;
}
NS_IMETHODIMP
nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
PRUint32 flags, JSObject **objp, PRBool *_retval)
{
if (!JSID_IS_STRING(id)) {
return NS_OK;
}
if (flags & JSRESOLVE_ASSIGNING) {
if (!IsEventName(id)) {
// Bail out. We don't care about this assignment.
return NS_OK;
}
// If we're assigning to an on* property, just resolve to null for
// now; the assignment will then set the right value. Only do this
// in the case where the property isn't already defined on the
// object's prototype chain though.
JSAutoRequest ar(cx);
JSObject *proto = ::JS_GetPrototype(cx, obj);
PRBool ok = PR_TRUE;
JSBool hasProp = JS_FALSE;
if (!proto || ((ok = ::JS_HasPropertyById(cx, proto, id, &hasProp)) &&
!hasProp)) {
// Make sure the flags here match those in
// nsJSContext::BindCompiledEventHandler
if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_NULL, nsnull, nsnull,
JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
return NS_ERROR_FAILURE;
}
*objp = obj;
return NS_OK;
}
return ok ? NS_OK : NS_ERROR_FAILURE;
}
if (id == sAddEventListener_id) {
return NS_OK;
}
PRBool did_define = PR_FALSE;
nsresult rv = RegisterCompileHandler(wrapper, cx, obj, id, PR_TRUE, PR_FALSE,
&did_define);
NS_ENSURE_SUCCESS(rv, rv);
if (did_define) {
*objp = obj;
}
return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
}
NS_IMETHODIMP
nsEventReceiverSH::SetProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
jsval *vp, PRBool *_retval)
{
JSAutoRequest ar(cx);
if ((::JS_TypeOfValue(cx, *vp) != JSTYPE_FUNCTION && !JSVAL_IS_NULL(*vp)) ||
!JSID_IS_STRING(id) || id == sAddEventListener_id) {
return NS_OK;
}
PRBool did_compile; // Ignored here.
return RegisterCompileHandler(wrapper, cx, obj, id, PR_FALSE,
JSVAL_IS_NULL(*vp), &did_compile);
}
NS_IMETHODIMP
nsEventReceiverSH::AddProperty(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
jsval *vp, PRBool *_retval)
{
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
}
// EventTarget helper // EventTarget helper
NS_IMETHODIMP NS_IMETHODIMP

View File

@ -292,16 +292,9 @@ public:
static jsid sKeyPath_id; static jsid sKeyPath_id;
static jsid sAutoIncrement_id; static jsid sAutoIncrement_id;
static jsid sUnique_id; static jsid sUnique_id;
static jsid sOnload_id;
static jsid sOnerror_id;
#define EVENT(name_, id_, type_, struct_) \
static jsid sOn##name_##_id;
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef WINDOW_ONLY_EVENT
#undef EVENT
protected: protected:
static JSPropertyOp sXPCNativeWrapperGetPropertyOp; static JSPropertyOp sXPCNativeWrapperGetPropertyOp;
static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp; static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp;
@ -346,53 +339,6 @@ do_QueryWrapper(JSContext *cx, JSObject *obj, nsresult* error)
typedef nsDOMClassInfo nsDOMGenericSH; typedef nsDOMClassInfo nsDOMGenericSH;
// EventProp scriptable helper, this class should be the base class of
// all objects that should support things like
// obj.onclick=function{...}
class nsEventReceiverSH : public nsDOMGenericSH
{
protected:
nsEventReceiverSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
{
}
virtual ~nsEventReceiverSH()
{
}
static PRBool ReallyIsEventName(jsid id, jschar aFirstChar);
static inline PRBool IsEventName(jsid id)
{
NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!");
const jschar *str = ::JS_GetInternedStringChars(JSID_TO_STRING(id));
if (str[0] == 'o' && str[1] == 'n') {
return ReallyIsEventName(id, str[2]);
}
return PR_FALSE;
}
nsresult RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper,
JSContext *cx, JSObject *obj, jsid id,
PRBool compile, PRBool remove,
PRBool *did_define);
public:
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval);
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp,
PRBool *_retval);
NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
};
// Simpler than nsEventReceiverSH
// Makes sure that the wrapper is preserved if new properties are added. // Makes sure that the wrapper is preserved if new properties are added.
class nsEventTargetSH : public nsDOMGenericSH class nsEventTargetSH : public nsDOMGenericSH
{ {
@ -420,10 +366,10 @@ public:
// Window scriptable helper // Window scriptable helper
class nsWindowSH : public nsEventReceiverSH class nsWindowSH : public nsDOMGenericSH
{ {
protected: protected:
nsWindowSH(nsDOMClassInfoData *aData) : nsEventReceiverSH(aData) nsWindowSH(nsDOMClassInfoData *aData) : nsDOMGenericSH(aData)
{ {
} }
@ -451,7 +397,7 @@ public:
NS_IMETHOD GetScriptableFlags(PRUint32 *aFlags) NS_IMETHOD GetScriptableFlags(PRUint32 *aFlags)
{ {
PRUint32 flags; PRUint32 flags;
nsresult rv = nsEventReceiverSH::GetScriptableFlags(&flags); nsresult rv = nsDOMGenericSH::GetScriptableFlags(&flags);
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
*aFlags = flags | nsIXPCScriptable::WANT_POSTCREATE; *aFlags = flags | nsIXPCScriptable::WANT_POSTCREATE;
} }
@ -548,10 +494,10 @@ public:
// DOM Node helper, this class deals with setting the parent for the // DOM Node helper, this class deals with setting the parent for the
// wrappers // wrappers
class nsNodeSH : public nsEventReceiverSH class nsNodeSH : public nsDOMGenericSH
{ {
protected: protected:
nsNodeSH(nsDOMClassInfoData* aData) : nsEventReceiverSH(aData) nsNodeSH(nsDOMClassInfoData* aData) : nsDOMGenericSH(aData)
{ {
} }
@ -946,38 +892,6 @@ public:
}; };
// HTMLBodyElement helper
class nsHTMLBodyElementSH : public nsElementSH
{
protected:
nsHTMLBodyElementSH(nsDOMClassInfoData* aData) : nsElementSH(aData)
{
}
virtual ~nsHTMLBodyElementSH()
{
}
public:
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
JSObject **objp, PRBool *_retval);
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp,
PRBool *_retval);
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
{
return new nsHTMLBodyElementSH(aData);
}
};
// HTMLFormElement helper // HTMLFormElement helper
class nsHTMLFormElementSH : public nsElementSH class nsHTMLFormElementSH : public nsElementSH

View File

@ -1367,6 +1367,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindow)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance) NS_INTERFACE_MAP_ENTRY(nsIDOMWindowPerformance)
NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver) NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
OUTER_WINDOW_ONLY OUTER_WINDOW_ONLY
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@ -11356,6 +11357,37 @@ NS_IMETHODIMP nsNavigator::GetMozNotification(nsIDOMDesktopNotificationCenter **
return NS_OK; return NS_OK;
} }
#define EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
jsval *vp) { \
nsEventListenerManager *elm = GetListenerManager(PR_FALSE); \
if (elm) { \
elm->GetJSEventListener(nsGkAtoms::on##name_, vp); \
} else { \
*vp = JSVAL_NULL; \
} \
return NS_OK; \
} \
NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsEventListenerManager *elm = GetListenerManager(PR_TRUE); \
if (!elm) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
\
JSObject *obj = mJSObject; \
if (!obj) { \
return NS_ERROR_UNEXPECTED; \
} \
return elm->SetJSEventListenerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
}
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT
#include "nsEventNameList.h"
#undef TOUCH_EVENT
#undef WINDOW_ONLY_EVENT
#undef EVENT
PRInt64 PRInt64
nsNavigator::SizeOf() const nsNavigator::SizeOf() const
{ {

View File

@ -104,6 +104,7 @@
#include "nsFrameMessageManager.h" #include "nsFrameMessageManager.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "nsIDOMTouchEvent.h" #include "nsIDOMTouchEvent.h"
#include "nsIInlineEventHandlers.h"
// JS includes // JS includes
#include "jsapi.h" #include "jsapi.h"
@ -280,7 +281,8 @@ class nsGlobalWindow : public nsPIDOMWindow,
public nsWrapperCache, public nsWrapperCache,
public PRCListStr, public PRCListStr,
public nsIDOMWindowPerformance, public nsIDOMWindowPerformance,
public nsITouchEventReceiver public nsITouchEventReceiver,
public nsIInlineEventHandlers
{ {
public: public:
friend class nsDOMMozURLProperty; friend class nsDOMMozURLProperty;
@ -335,6 +337,9 @@ public:
// nsITouchEventReceiver // nsITouchEventReceiver
NS_DECL_NSITOUCHEVENTRECEIVER NS_DECL_NSITOUCHEVENTRECEIVER
// nsIInlineEventHandlers
NS_DECL_NSIINLINEEVENTHANDLERS
// nsPIDOMWindow // nsPIDOMWindow
virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot(); virtual NS_HIDDEN_(nsPIDOMWindow*) GetPrivateRoot();
virtual NS_HIDDEN_(void) ActivateOrDeactivate(PRBool aActivate); virtual NS_HIDDEN_(void) ActivateOrDeactivate(PRBool aActivate);

View File

@ -40,47 +40,55 @@
#include "nsIScriptContext.h" #include "nsIScriptContext.h"
#include "jsapi.h" #include "jsapi.h"
#include "nsIDOMEventListener.h"
class nsIScriptObjectOwner; class nsIScriptObjectOwner;
class nsIDOMEventListener;
class nsIAtom; class nsIAtom;
#define NS_IJSEVENTLISTENER_IID \ #define NS_IJSEVENTLISTENER_IID \
{ 0x08ca15c4, 0x1c2d, 0x449e, \ { 0xb88fb066, 0xe9f8, 0x45d0, \
{ 0x9e, 0x88, 0xaa, 0x8b, 0xbf, 0x00, 0xf7, 0x63 } } { 0x92, 0x9a, 0x7d, 0xa8, 0x4c, 0x1f, 0xb5, 0xbc } }
// Implemented by script event listeners. Used to retrieve the // Implemented by script event listeners. Used to retrieve the
// script object corresponding to the event target. // script object corresponding to the event target and the handler itself.
// (Note this interface is now used to store script objects for all // (Note this interface is now used to store script objects for all
// script languages, so is no longer JS specific) // script languages, so is no longer JS specific)
class nsIJSEventListener : public nsISupports class nsIJSEventListener : public nsIDOMEventListener
{ {
public: public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSEVENTLISTENER_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSEVENTLISTENER_IID)
nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject, nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports *aTarget) nsISupports *aTarget, void *aHandler)
: mContext(aContext), mScopeObject(aScopeObject), : mContext(aContext), mScopeObject(aScopeObject),
mTarget(do_QueryInterface(aTarget)) mTarget(do_QueryInterface(aTarget)), mHandler(aHandler)
{ {
} }
nsIScriptContext *GetEventContext() nsIScriptContext *GetEventContext() const
{ {
return mContext; return mContext;
} }
nsISupports *GetEventTarget() nsISupports *GetEventTarget() const
{ {
return mTarget; return mTarget;
} }
void *GetEventScope() void *GetEventScope() const
{ {
return mScopeObject; return mScopeObject;
} }
virtual nsresult GetJSVal(const nsAString& aEventName, jsval* aJSVal) = 0; void *GetHandler() const
{
return mHandler;
}
// Set a handler for this event listener. Must not be called if
// there is already a handler! The handler must already be bound to
// the right target.
virtual void SetHandler(void *aHandler) = 0;
protected: protected:
virtual ~nsIJSEventListener() virtual ~nsIJSEventListener()
@ -89,13 +97,15 @@ protected:
nsCOMPtr<nsIScriptContext> mContext; nsCOMPtr<nsIScriptContext> mContext;
void *mScopeObject; void *mScopeObject;
nsCOMPtr<nsISupports> mTarget; nsCOMPtr<nsISupports> mTarget;
void *mHandler;
}; };
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID) NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
/* factory function */ /* factory function. aHandler must already be bound to aTarget */
nsresult NS_NewJSEventListener(nsIScriptContext *aContext, nsresult NS_NewJSEventListener(nsIScriptContext *aContext,
void *aScopeObject, nsISupports *aObject, void *aScopeObject, nsISupports *aTarget,
nsIAtom* aType, nsIDOMEventListener **aReturn); nsIAtom* aType, void *aHandler,
nsIDOMEventListener **aReturn);
#endif // nsIJSEventListener_h__ #endif // nsIJSEventListener_h__

View File

@ -72,10 +72,9 @@ public:
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal, NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
NS_ISCRIPTCONTEXTPRINCIPAL_IID) NS_ISCRIPTCONTEXTPRINCIPAL_IID)
// a7139c0e-962c-44b6-bec3-e4166bfe84eb
#define NS_ISCRIPTCONTEXT_IID \ #define NS_ISCRIPTCONTEXT_IID \
{ 0xa7139c0e, 0x962c, 0x44b6, \ { 0xad76079b, 0xd408, 0x4159, \
{ 0xbe, 0xc3, 0xe4, 0x16, 0x6b, 0xfe, 0x84, 0xeb } } {0xb7, 0x3f, 0x41, 0x08, 0x77, 0xff, 0x9b, 0x47 } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't /* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */ know what language we have is a little silly... */
@ -233,41 +232,30 @@ public:
nsIArray *argv, nsIVariant **rval) = 0; nsIArray *argv, nsIVariant **rval) = 0;
/** /**
* Bind an already-compiled event handler function to a name in the given * Bind an already-compiled event handler function to the given
* scope object. The same restrictions on aName (lowercase ASCII, not too * target. Scripting languages with static scoping must re-bind the
* long) applies here as for CompileEventHandler. Scripting languages with * scope chain for aHandler to begin (after the activation scope for
* static scoping must re-bind the scope chain for aHandler to begin (after * aHandler itself, typically) with aTarget's scope.
* the activation scope for aHandler itself, typically) with aTarget's scope.
* *
* Logically, this 'bind' operation is more of a 'copy' - it simply * The result of the bind operation is a new handler object, with
* stashes/associates the event handler function with the event target, so * principals now set and scope set as above. This is returned in
* it can be fetched later with GetBoundEventHandler(). * aBoundHandler. When this function is called, aBoundHandler is
* expected to not be holding an object.
* *
* @param aTarget an object telling the scope in which to bind the compiled * @param aTarget an object telling the scope in which to bind the compiled
* event handler function. The context will presumably associate * event handler function. The context will presumably associate
* this nsISupports with a native script object. * this nsISupports with a native script object.
* @param aName an nsIAtom pointer naming the function; it must be lowercase * @param aScope the scope in which the script object for aTarget should be
* and ASCII, and should not be longer than 63 chars. This bound on * looked for.
* length is enforced only by assertions, so caveat caller! * @param aHandler the function object to bind, created by an earlier call to
* @param aHandler the function object to name, created by an earlier call to
* CompileEventHandler * CompileEventHandler
* @return NS_OK if the function was successfully bound to the name * @param aBoundHandler [out] the result of the bind operation.
* * @return NS_OK if the function was successfully bound
* XXXmarkh - fold this in with SetProperty? Exactly the same concept!
*/ */
virtual nsresult BindCompiledEventHandler(nsISupports* aTarget, void *aScope, virtual nsresult BindCompiledEventHandler(nsISupports* aTarget,
nsIAtom* aName, void *aScope,
void* aHandler) = 0; void* aHandler,
nsScriptObjectHolder& aBoundHandler) = 0;
/**
* Lookup a previously bound event handler for the specified target. This
* will return an object equivilent to the one passed to
* BindCompiledEventHandler (although the pointer may not be the same).
*
*/
virtual nsresult GetBoundEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
nsScriptObjectHolder &aHandler) = 0;
/** /**
* Compile a function that isn't used as an event handler. * Compile a function that isn't used as an event handler.

View File

@ -94,9 +94,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptObjectOwner,
class nsIAtom; class nsIAtom;
#define NS_ISCRIPTEVENTHANDLEROWNER_IID \ #define NS_ISCRIPTEVENTHANDLEROWNER_IID \
{ /* 2ad54ae0-a839-11d3-ba97-00104ba02d3d */ \ { 0x1e2be5d2, 0x381a, 0x46dc, \
0x2ad54ae0, 0xa839, 0x11d3, \ { 0xae, 0x97, 0xa5, 0x5f, 0x45, 0xfd, 0x36, 0x63 } }
{0xba, 0x97, 0x00, 0x10, 0x4b, 0xa0, 0x2d, 0x3d} }
/** /**
* Associate a compiled event handler with its target object, which owns it * Associate a compiled event handler with its target object, which owns it
@ -110,19 +109,17 @@ public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTEVENTHANDLEROWNER_IID) NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTEVENTHANDLEROWNER_IID)
/** /**
* Compile the specified event handler, and bind it to aTarget using * Compile the specified event handler. This does NOT bind it to
* aContext. * anything. That's the caller's responsibility.
* *
* @param aContext the context to use when creating event handler * @param aContext the context to use when creating event handler
* @param aTarget the object to which to bind the event handler
* @param aName the name of the handler * @param aName the name of the handler
* @param aBody the handler script body * @param aBody the handler script body
* @param aURL the URL or filename for error messages * @param aURL the URL or filename for error messages
* @param aLineNo the starting line number of the script for error messages * @param aLineNo the starting line number of the script for error messages
* @param aHandler the holder for the compiled, bound handler object * @param aHandler the holder for the compiled handler object
*/ */
virtual nsresult CompileEventHandler(nsIScriptContext* aContext, virtual nsresult CompileEventHandler(nsIScriptContext* aContext,
nsISupports* aTarget,
nsIAtom *aName, nsIAtom *aName,
const nsAString& aBody, const nsAString& aBody,
const char* aURL, const char* aURL,

View File

@ -1935,13 +1935,12 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
nsresult nsresult
nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope, nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom *aName, void *aHandler,
void *aHandler) nsScriptObjectHolder& aBoundHandler)
{ {
NS_ENSURE_ARG(aHandler); NS_ENSURE_ARG(aHandler);
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED); NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
NS_PRECONDITION(!aBoundHandler, "Shouldn't already have a bound handler!");
NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
JSAutoRequest ar(mContext); JSAutoRequest ar(mContext);
@ -1970,14 +1969,6 @@ nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
// Push our JSContext on our thread's context stack, in case native code
// called from JS calls back into JS via XPConnect.
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
return NS_ERROR_FAILURE;
}
// Make sure the handler function is parented by its event target object // Make sure the handler function is parented by its event target object
if (funobj) { // && ::JS_GetParent(mContext, funobj) != target) { if (funobj) { // && ::JS_GetParent(mContext, funobj) != target) {
funobj = ::JS_CloneFunctionObject(mContext, funobj, target); funobj = ::JS_CloneFunctionObject(mContext, funobj, target);
@ -1985,57 +1976,11 @@ nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
rv = NS_ERROR_OUT_OF_MEMORY; rv = NS_ERROR_OUT_OF_MEMORY;
} }
if (NS_SUCCEEDED(rv) && aBoundHandler.set(funobj);
// Make sure the flags here match those in nsEventReceiverSH::NewResolve
!::JS_DefineProperty(mContext, target, nsAtomCString(aName).get(),
OBJECT_TO_JSVAL(funobj), nsnull, nsnull,
JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
ReportPendingException();
rv = NS_ERROR_FAILURE;
}
// XXXmarkh - ideally we should assert that the wrapped native is now
// "long lived" - how to do that?
if (NS_FAILED(stack->Pop(nsnull)) && NS_SUCCEEDED(rv)) {
rv = NS_ERROR_FAILURE;
}
return rv; return rv;
} }
nsresult
nsJSContext::GetBoundEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
nsScriptObjectHolder &aHandler)
{
NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
JSAutoRequest ar(mContext);
JSObject *obj = nsnull;
nsresult rv = JSObjectFromInterface(aTarget, aScope, &obj);
NS_ENSURE_SUCCESS(rv, rv);
JSAutoEnterCompartment ac;
if (!ac.enter(mContext, obj)) {
return NS_ERROR_FAILURE;
}
jsval funval;
if (!JS_LookupProperty(mContext, obj,
nsAtomCString(aName).get(), &funval))
return NS_ERROR_FAILURE;
if (JS_TypeOfValue(mContext, funval) != JSTYPE_FUNCTION) {
NS_WARNING("Event handler object not a function");
aHandler.drop();
return NS_OK;
}
NS_ASSERTION(aHandler.getScriptTypeID()==JAVASCRIPT,
"Expecting JS script object holder");
return aHandler.set(JSVAL_TO_OBJECT(funval));
}
// serialization // serialization
nsresult nsresult
nsJSContext::Serialize(nsIObjectOutputStream* aStream, void *aScriptObject) nsJSContext::Serialize(nsIObjectOutputStream* aStream, void *aScriptObject)

View File

@ -114,11 +114,8 @@ public:
nsIArray *argv, nsIVariant **rv); nsIArray *argv, nsIVariant **rv);
virtual nsresult BindCompiledEventHandler(nsISupports *aTarget, virtual nsresult BindCompiledEventHandler(nsISupports *aTarget,
void *aScope, void *aScope,
nsIAtom *aName, void *aHandler,
void *aHandler); nsScriptObjectHolder& aBoundHandler);
virtual nsresult GetBoundEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
nsScriptObjectHolder &aHandler);
virtual nsresult CompileFunction(void* aTarget, virtual nsresult CompileFunction(void* aTarget,
const nsACString& aName, const nsACString& aName,
PRUint32 aArgCount, PRUint32 aArgCount,

View File

@ -70,7 +70,7 @@ interface nsIDOMMozURLProperty : nsISupports
* @see <http://www.whatwg.org/html/#window> * @see <http://www.whatwg.org/html/#window>
*/ */
[scriptable, uuid(972cb379-6bdc-4544-8b46-8d721e12e906)] [scriptable, uuid(3f5b2af2-604e-4253-8d25-6d3cafc13a69)]
interface nsIDOMWindow : nsISupports interface nsIDOMWindow : nsISupports
{ {
// the current browsing context // the current browsing context
@ -434,6 +434,34 @@ interface nsIDOMWindow : nsISupports
* Global storage, accessible by domain. * Global storage, accessible by domain.
*/ */
readonly attribute nsIDOMStorageList globalStorage; readonly attribute nsIDOMStorageList globalStorage;
/**
* HTML5 event attributes that only apply to windows and <body>/<frameset>
*/
[implicit_jscontext] attribute jsval onafterprint;
[implicit_jscontext] attribute jsval onbeforeprint;
[implicit_jscontext] attribute jsval onbeforeunload;
[implicit_jscontext] attribute jsval onhashchange;
[implicit_jscontext] attribute jsval onmessage;
[implicit_jscontext] attribute jsval onoffline;
[implicit_jscontext] attribute jsval ononline;
[implicit_jscontext] attribute jsval onpopstate;
[implicit_jscontext] attribute jsval onpagehide;
[implicit_jscontext] attribute jsval onpageshow;
// Not supported yet
// [implicit_jscontext] attribute jsval onredo;
[implicit_jscontext] attribute jsval onresize;
// Not supported yet
// [implicit_jscontext] attribute jsval onstorage;
// Not supported yet
// [implicit_jscontext] attribute jsval onundo;
[implicit_jscontext] attribute jsval onunload;
/**
* Non-HTML5 window-specific event attributes
*/
[implicit_jscontext] attribute jsval ondevicemotion;
[implicit_jscontext] attribute jsval ondeviceorientation;
}; };
[scriptable, uuid(2146c906-57f7-486c-a1b4-8cdb57ef577f)] [scriptable, uuid(2146c906-57f7-486c-a1b4-8cdb57ef577f)]

View File

@ -74,6 +74,7 @@ XPIDLSRCS = \
nsIDOMNodeSelector.idl \ nsIDOMNodeSelector.idl \
nsIDOMDOMTokenList.idl \ nsIDOMDOMTokenList.idl \
nsIDOMDOMSettableTokenList.idl \ nsIDOMDOMSettableTokenList.idl \
nsIInlineEventHandlers.idl \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,110 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Boris Zbarsky <bzbarsky@mit.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "domstubs.idl"
%{ C++
#include "jspubtd.h"
%}
[scriptable, uuid(c3cc4504-1eaf-42e9-8b1b-a3020f6d3a28)]
interface nsIInlineEventHandlers : nsISupports
{
[implicit_jscontext] attribute jsval onabort;
[implicit_jscontext] attribute jsval onblur;
[implicit_jscontext] attribute jsval oncanplay;
[implicit_jscontext] attribute jsval oncanplaythrough;
[implicit_jscontext] attribute jsval onchange;
[implicit_jscontext] attribute jsval onclick;
[implicit_jscontext] attribute jsval oncontextmenu;
// Not supported yet
// [implicit_jscontext] attribute jsval oncuechange;
[implicit_jscontext] attribute jsval ondblclick;
[implicit_jscontext] attribute jsval ondrag;
[implicit_jscontext] attribute jsval ondragend;
[implicit_jscontext] attribute jsval ondragenter;
[implicit_jscontext] attribute jsval ondragleave;
[implicit_jscontext] attribute jsval ondragover;
[implicit_jscontext] attribute jsval ondragstart;
[implicit_jscontext] attribute jsval ondrop;
[implicit_jscontext] attribute jsval ondurationchange;
[implicit_jscontext] attribute jsval onemptied;
[implicit_jscontext] attribute jsval onended;
[implicit_jscontext] attribute jsval onerror;
[implicit_jscontext] attribute jsval onfocus;
[implicit_jscontext] attribute jsval oninput;
[implicit_jscontext] attribute jsval oninvalid;
[implicit_jscontext] attribute jsval onkeydown;
[implicit_jscontext] attribute jsval onkeypress;
[implicit_jscontext] attribute jsval onkeyup;
[implicit_jscontext] attribute jsval onload;
[implicit_jscontext] attribute jsval onloadeddata;
[implicit_jscontext] attribute jsval onloadedmetadata;
[implicit_jscontext] attribute jsval onloadstart;
[implicit_jscontext] attribute jsval onmousedown;
[implicit_jscontext] attribute jsval onmousemove;
[implicit_jscontext] attribute jsval onmouseout;
[implicit_jscontext] attribute jsval onmouseover;
[implicit_jscontext] attribute jsval onmouseup;
// Not supported yet
// [implicit_jscontext] attribute jsval onmousewheel;
[implicit_jscontext] attribute jsval onpause;
[implicit_jscontext] attribute jsval onplay;
[implicit_jscontext] attribute jsval onplaying;
[implicit_jscontext] attribute jsval onprogress;
[implicit_jscontext] attribute jsval onratechange;
[implicit_jscontext] attribute jsval onreadystatechange;
[implicit_jscontext] attribute jsval onreset;
[implicit_jscontext] attribute jsval onscroll;
[implicit_jscontext] attribute jsval onseeked;
[implicit_jscontext] attribute jsval onseeking;
[implicit_jscontext] attribute jsval onselect;
[implicit_jscontext] attribute jsval onshow;
[implicit_jscontext] attribute jsval onstalled;
[implicit_jscontext] attribute jsval onsubmit;
[implicit_jscontext] attribute jsval onsuspend;
[implicit_jscontext] attribute jsval ontimeupdate;
[implicit_jscontext] attribute jsval onvolumechange;
[implicit_jscontext] attribute jsval onwaiting;
/**
* Non-HTML5 event attributes
*/
[implicit_jscontext] attribute jsval oncopy;
[implicit_jscontext] attribute jsval oncut;
[implicit_jscontext] attribute jsval onpaste;
[implicit_jscontext] attribute jsval onbeforescriptexecute;
[implicit_jscontext] attribute jsval onafterscriptexecute;
};

View File

@ -90,6 +90,12 @@ interface nsIDOMTouchEvent : nsIDOMUIEvent {
[scriptable, uuid(6d5484f7-92ac-45f8-9388-39b5bad055ce)] [scriptable, uuid(6d5484f7-92ac-45f8-9388-39b5bad055ce)]
interface nsITouchEventReceiver : nsISupports { interface nsITouchEventReceiver : nsISupports {
[implicit_jscontext] attribute jsval ontouchstart;
[implicit_jscontext] attribute jsval ontouchend;
[implicit_jscontext] attribute jsval ontouchmove;
[implicit_jscontext] attribute jsval ontouchenter;
[implicit_jscontext] attribute jsval ontouchleave;
[implicit_jscontext] attribute jsval ontouchcancel;
}; };
[scriptable, uuid(974cff68-6f0b-4520-8523-fa68b2754656)] [scriptable, uuid(974cff68-6f0b-4520-8523-fa68b2754656)]

View File

@ -39,6 +39,10 @@
#include "nsIDOMHTMLElement.idl" #include "nsIDOMHTMLElement.idl"
%{ C++
#include "jspubtd.h"
%}
/** /**
* The nsIDOMHTMLBodyElement interface is the interface to a [X]HTML * The nsIDOMHTMLBodyElement interface is the interface to a [X]HTML
* body element. * body element.
@ -50,7 +54,7 @@
* http://www.whatwg.org/specs/web-apps/current-work/ * http://www.whatwg.org/specs/web-apps/current-work/
*/ */
[scriptable, uuid(87db4ba2-367d-4604-ad36-b97cc09bf3f1)] [scriptable, uuid(9569e420-137a-4c7e-a880-288a81f78308)]
interface nsIDOMHTMLBodyElement : nsIDOMHTMLElement interface nsIDOMHTMLBodyElement : nsIDOMHTMLElement
{ {
attribute DOMString aLink; attribute DOMString aLink;
@ -59,4 +63,23 @@ interface nsIDOMHTMLBodyElement : nsIDOMHTMLElement
attribute DOMString link; attribute DOMString link;
attribute DOMString text; attribute DOMString text;
attribute DOMString vLink; attribute DOMString vLink;
[implicit_jscontext] attribute jsval onafterprint;
[implicit_jscontext] attribute jsval onbeforeprint;
[implicit_jscontext] attribute jsval onbeforeunload;
[implicit_jscontext] attribute jsval onhashchange;
[implicit_jscontext] attribute jsval onmessage;
[implicit_jscontext] attribute jsval onoffline;
[implicit_jscontext] attribute jsval ononline;
[implicit_jscontext] attribute jsval onpagehide;
[implicit_jscontext] attribute jsval onpageshow;
[implicit_jscontext] attribute jsval onpopstate;
// Not supported yet
// [implicit_jscontext] attribute jsval onredo;
[implicit_jscontext] attribute jsval onresize;
// Not supported yet
// [implicit_jscontext] attribute jsval onstorage;
// Not supported yet
// [implicit_jscontext] attribute jsval onundo;
[implicit_jscontext] attribute jsval onunload;
}; };

View File

@ -39,6 +39,10 @@
#include "nsIDOMHTMLElement.idl" #include "nsIDOMHTMLElement.idl"
%{ C++
#include "jspubtd.h"
%}
/** /**
* The nsIDOMHTMLFrameSetElement interface is the interface to a * The nsIDOMHTMLFrameSetElement interface is the interface to a
* [X]HTML frameset element. * [X]HTML frameset element.
@ -50,9 +54,28 @@
* http://www.whatwg.org/specs/web-apps/current-work/ * http://www.whatwg.org/specs/web-apps/current-work/
*/ */
[scriptable, uuid(a827ecd2-472d-4cf7-ae3b-21bca7e5c6aa)] [scriptable, uuid(d6872633-0f1c-4110-bf49-88713a3cad86)]
interface nsIDOMHTMLFrameSetElement : nsIDOMHTMLElement interface nsIDOMHTMLFrameSetElement : nsIDOMHTMLElement
{ {
attribute DOMString cols; attribute DOMString cols;
attribute DOMString rows; attribute DOMString rows;
[implicit_jscontext] attribute jsval onafterprint;
[implicit_jscontext] attribute jsval onbeforeprint;
[implicit_jscontext] attribute jsval onbeforeunload;
[implicit_jscontext] attribute jsval onhashchange;
[implicit_jscontext] attribute jsval onmessage;
[implicit_jscontext] attribute jsval onoffline;
[implicit_jscontext] attribute jsval ononline;
[implicit_jscontext] attribute jsval onpagehide;
[implicit_jscontext] attribute jsval onpageshow;
[implicit_jscontext] attribute jsval onpopstate;
// Not supported yet
// [implicit_jscontext] attribute jsval onredo;
[implicit_jscontext] attribute jsval onresize;
// Not supported yet
// [implicit_jscontext] attribute jsval onstorage;
// Not supported yet
// [implicit_jscontext] attribute jsval onundo;
[implicit_jscontext] attribute jsval onunload;
}; };

View File

@ -75,8 +75,10 @@ static EventListenerCounter sEventListenerCounter;
nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext, nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
void *aScopeObject, void *aScopeObject,
nsISupports *aTarget, nsISupports *aTarget,
nsIAtom* aType) nsIAtom* aType,
: nsIJSEventListener(aContext, aScopeObject, aTarget), mEventName(aType) void *aHandler)
: nsIJSEventListener(aContext, aScopeObject, aTarget, aHandler),
mEventName(aType)
{ {
// aScopeObject is the inner window's JS object, which we need to lock // aScopeObject is the inner window's JS object, which we need to lock
// until we are done with it. // until we are done with it.
@ -85,13 +87,18 @@ nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this, nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener), &NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
aScopeObject, PR_FALSE); aScopeObject, PR_FALSE);
if (aHandler) {
nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
aHandler, PR_TRUE);
}
} }
nsJSEventListener::~nsJSEventListener() nsJSEventListener::~nsJSEventListener()
{ {
if (mContext) if (mContext)
nsContentUtils::DropScriptObjects(mContext->GetScriptTypeID(), this, nsContentUtils::DropScriptObjects(mContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener)); &NS_CYCLE_COLLECTION_NAME(nsJSEventListener));
} }
NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener) NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
@ -118,49 +125,29 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener)
NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(), NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
mScopeObject) mScopeObject)
NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
mHandler)
NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSEventListener) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSEventListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIJSEventListener) NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener) NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSEventListener) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsJSEventListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSEventListener) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSEventListener)
nsresult
nsJSEventListener::GetJSVal(const nsAString& aEventName, jsval* aJSVal)
{
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTarget);
if (target && mContext) {
nsAutoString eventString = NS_LITERAL_STRING("on") + aEventName;
nsCOMPtr<nsIAtom> atomName = do_GetAtom(eventString);
nsScriptObjectHolder funcval(mContext);
nsresult rv = mContext->GetBoundEventHandler(mTarget, mScopeObject,
atomName, funcval);
NS_ENSURE_SUCCESS(rv, rv);
jsval funval =
OBJECT_TO_JSVAL(static_cast<JSObject*>(static_cast<void*>(funcval)));
*aJSVal = funval;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
nsresult nsresult
nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent) nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
{ {
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTarget);
if (!target || !mContext || !mHandler)
return NS_ERROR_FAILURE;
nsresult rv; nsresult rv;
nsCOMPtr<nsIMutableArray> iargv; nsCOMPtr<nsIMutableArray> iargv;
nsScriptObjectHolder funcval(mContext);
rv = mContext->GetBoundEventHandler(mTarget, mScopeObject, mEventName,
funcval);
NS_ENSURE_SUCCESS(rv, rv);
if (!funcval)
return NS_OK;
PRBool handledScriptError = PR_FALSE; PRBool handledScriptError = PR_FALSE;
if (mEventName == nsGkAtoms::onerror) { if (mEventName == nsGkAtoms::onerror) {
nsCOMPtr<nsIPrivateDOMEvent> priv(do_QueryInterface(aEvent)); nsCOMPtr<nsIPrivateDOMEvent> priv(do_QueryInterface(aEvent));
@ -220,7 +207,7 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
"JSEventListener has wrong script context?"); "JSEventListener has wrong script context?");
#endif #endif
nsCOMPtr<nsIVariant> vrv; nsCOMPtr<nsIVariant> vrv;
rv = mContext->CallEventHandler(mTarget, mScopeObject, funcval, iargv, rv = mContext->CallEventHandler(mTarget, mScopeObject, mHandler, iargv,
getter_AddRefs(vrv)); getter_AddRefs(vrv));
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
@ -268,6 +255,18 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
return rv; return rv;
} }
/* virtual */ void
nsJSEventListener::SetHandler(void *aHandler)
{
// Technically we should drop the old mHandler and hold the new
// one... except for JS this is a no-op, and we're really not
// pretending very hard to support anything else. And since we
// can't in fact only drop one script object (we'd have to drop
// mScope too, and then re-hold it), let's just not worry about it
// all.
mHandler = aHandler;
}
/* /*
* Factory functions * Factory functions
*/ */
@ -275,11 +274,12 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
nsresult nsresult
NS_NewJSEventListener(nsIScriptContext *aContext, void *aScopeObject, NS_NewJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports*aTarget, nsIAtom* aEventType, nsISupports*aTarget, nsIAtom* aEventType,
nsIDOMEventListener ** aReturn) void *aHandler, nsIDOMEventListener ** aReturn)
{ {
NS_ENSURE_ARG(aEventType); NS_ENSURE_ARG(aEventType);
nsJSEventListener* it = nsJSEventListener* it =
new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType); new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType,
aHandler);
if (!it) { if (!it) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }

View File

@ -49,12 +49,11 @@
// nsJSEventListener interface // nsJSEventListener interface
// misnamed - JS no longer has exclusive rights over this interface! // misnamed - JS no longer has exclusive rights over this interface!
class nsJSEventListener : public nsIDOMEventListener, class nsJSEventListener : public nsIJSEventListener
public nsIJSEventListener
{ {
public: public:
nsJSEventListener(nsIScriptContext *aContext, void *aScopeObject, nsJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports* aObject, nsIAtom* aType); nsISupports* aTarget, nsIAtom* aType, void *aHandler);
virtual ~nsJSEventListener(); virtual ~nsJSEventListener();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -62,11 +61,10 @@ public:
// nsIDOMEventListener interface // nsIDOMEventListener interface
NS_DECL_NSIDOMEVENTLISTENER NS_DECL_NSIDOMEVENTLISTENER
// nsIJSEventListener interface // nsIJSEventListener
virtual nsresult GetJSVal(const nsAString& aEventName, jsval* aJSVal); virtual void SetHandler(void *aHandler);
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsJSEventListener, NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSEventListener)
nsIDOMEventListener)
protected: protected:
nsCOMPtr<nsIAtom> mEventName; nsCOMPtr<nsIAtom> mEventName;
}; };

View File

@ -30,7 +30,7 @@ with (c) {
is(c.onmouseover, testFunc, "Event handler should have been set on node"); is(c.onmouseover, testFunc, "Event handler should have been set on node");
ok(c.fooExpando === undefined, "Expando should not have been set on node", ok(c.fooExpando === undefined, "Expando should not have been set on node",
"got " + repr(c.fooExpando) + ", expected undefined"); "got " + repr(c.fooExpando) + ", expected undefined");
ok(window.onmouseover === undefined, ok(window.onmouseover === null,
"Event handler should not have been set on window", "Event handler should not have been set on window",
"got " + repr(window.onmouseover) + ", expected undefined"); "got " + repr(window.onmouseover) + ", expected undefined");
is(window.fooExpando, testFunc, "Expando should have been set on window"); is(window.fooExpando, testFunc, "Expando should have been set on window");

View File

@ -29,7 +29,7 @@ SimpleTest.waitForExplicitFinish();
var docFragment = document.createDocumentFragment(); var docFragment = document.createDocumentFragment();
docFragment.foo = "foo"; docFragment.foo = "foo";
docFragment.onclick = clicked; docFragment.addEventListener("click", clicked, false);
var event = document.createEvent('MouseEvent'); var event = document.createEvent('MouseEvent');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false,
false, false, 0, docFragment); false, false, 0, docFragment);