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 "nsDOMError.h"
#include "nsDOMString.h"
#include "jspubtd.h"
class nsIContent;
class nsIDocument;
@ -280,8 +281,8 @@ private:
// IID for the nsINode interface
#define NS_INODE_IID \
{ 0xc7abbb40, 0x2571, 0x4d12, \
{ 0x8f, 0x89, 0x0d, 0x4f, 0x55, 0xc0, 0x92, 0xf6 } }
{ 0xcdab747e, 0xa58f, 0x4b96, \
{ 0x8b, 0xae, 0x9d, 0x53, 0xe0, 0xa7, 0x8a, 0x74 } }
/**
* An internal interface that abstracts some DOMNode-related parts that both
@ -1366,6 +1367,18 @@ protected:
nsresult doInsertChildAt(nsIContent* aKid, PRUint32 aIndex,
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;
nsINode* mParent;

View File

@ -1702,6 +1702,7 @@ NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentTouch)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsITouchEventReceiver)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIInlineEventHandlers)
NS_OFFSET_AND_INTERFACE_TABLE_END
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
@ -8472,3 +8473,14 @@ nsDocument::SizeOf() const
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 "nsIDOMDOMImplementation.h"
#include "nsIDOMTouchEvent.h"
#include "nsIInlineEventHandlers.h"
#include "nsDataHashtable.h"
#include "TimeStamp.h"
@ -492,7 +493,8 @@ class nsDocument : public nsIDocument,
public nsIRadioGroupContainer,
public nsIApplicationCacheContainer,
public nsStubMutationObserver,
public nsIDOMDocumentTouch
public nsIDOMDocumentTouch,
public nsIInlineEventHandlers
{
public:
typedef mozilla::dom::Element Element;
@ -787,6 +789,9 @@ public:
// nsIDOMDocumentTouch
NS_DECL_NSIDOMDOCUMENTTOUCH
// nsIInlineEventHandlers
NS_DECL_NSIINLINEEVENTHANDLERS
virtual nsresult Init();
virtual void AddXMLEventsContent(nsIContent * aXMLEventsElement);

View File

@ -147,6 +147,8 @@
#include "nsSVGFeatures.h"
#include "nsDOMMemoryReporter.h"
#include "xpcpublic.h"
using namespace mozilla::dom;
namespace css = mozilla::css;
@ -2160,6 +2162,17 @@ NS_INTERFACE_MAP_END_AGGREGATED(mElement)
NS_IMPL_CYCLE_COLLECTING_ADDREF(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()
: nsINode::nsSlots(),
@ -4278,6 +4291,8 @@ NS_INTERFACE_MAP_BEGIN(nsGenericElement)
new nsNode3Tearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsITouchEventReceiver,
new nsTouchEventReceiverTearoff(this))
NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIInlineEventHandlers,
new nsInlineEventHandlersTearoff(this))
// nsNodeSH::PreCreate() depends on the identity pointer being the
// same as nsINode (which nsIContent inherits), so if you change the
// below line, make sure nsNodeSH::PreCreate() still does the right
@ -5398,3 +5413,30 @@ nsGenericElement::SizeOf() const
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 "nsDOMClassInfoID.h" // DOMCI_DATA
#include "nsIDOMTouchEvent.h"
#include "nsIInlineEventHandlers.h"
#ifdef MOZ_SMIL
#include "nsISMILAttr.h"
@ -226,6 +227,7 @@ private:
// Forward declare to allow being a friend
class nsNSElementTearoff;
class nsTouchEventReceiverTearoff;
class nsInlineEventHandlersTearoff;
/**
* A generic base class for DOM elements, implementing many nsIContent,
@ -239,6 +241,7 @@ public:
friend class nsNSElementTearoff;
friend class nsTouchEventReceiverTearoff;
friend class nsInlineEventHandlersTearoff;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -1066,7 +1069,7 @@ class nsTouchEventReceiverTearoff : public nsITouchEventReceiver
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_NSITOUCHEVENTRECEIVER
NS_FORWARD_NSITOUCHEVENTRECEIVER(mElement->)
NS_DECL_CYCLE_COLLECTION_CLASS(nsTouchEventReceiverTearoff)
@ -1078,6 +1081,26 @@ private:
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 \
rv = nsGenericElement::QueryInterface(aIID, aInstancePtr); \
if (NS_SUCCEEDED(rv)) \

View File

@ -81,6 +81,7 @@
#include "nsEventListenerService.h"
#include "nsDOMEvent.h"
#include "nsIContentSecurityPolicy.h"
#include "nsJSEnvironment.h"
using namespace mozilla::dom;
@ -166,7 +167,6 @@ nsEventListenerManager::RemoveAllListeners()
void
nsEventListenerManager::Shutdown()
{
sAddListenerID = JSID_VOID;
nsDOMEvent::Shutdown();
}
@ -377,8 +377,9 @@ nsresult
nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
void *aScopeObject,
nsIAtom* aName,
PRBool aIsString,
PRBool aPermitUntrustedEvents)
JSObject *aHandler,
PRBool aPermitUntrustedEvents,
nsListenerStruct **aListenerStruct)
{
nsresult rv = NS_OK;
PRUint32 eventType = nsContentUtils::GetEventId(aName);
@ -389,22 +390,27 @@ nsEventListenerManager::SetJSEventListener(nsIScriptContext *aContext,
// create and add a new one.
nsCOMPtr<nsIDOMEventListener> scriptListener;
rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
getter_AddRefs(scriptListener));
aHandler, getter_AddRefs(scriptListener));
if (NS_SUCCEEDED(rv)) {
AddEventListener(scriptListener, eventType, aName,
NS_EVENT_FLAG_BUBBLE | NS_PRIV_EVENT_FLAG_SCRIPT);
ls = FindJSEventListener(eventType, aName);
}
} else {
ls->GetJSListener()->SetHandler(aHandler);
}
if (NS_SUCCEEDED(rv) && ls) {
// Set flag to indicate possible need for compilation later
ls->mHandlerIsString = aIsString;
ls->mHandlerIsString = !aHandler;
if (aPermitUntrustedEvents) {
ls->mFlags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
}
*aListenerStruct = ls;
} else {
*aListenerStruct = nsnull;
}
return rv;
@ -516,81 +522,16 @@ nsEventListenerManager::AddScriptEventListener(nsIAtom *aName,
void *scope = global->GetScriptGlobal(aLanguage);
nsListenerStruct *ls;
rv = SetJSEventListener(context, scope, aName, nsnull,
aPermitUntrustedEvents, &ls);
NS_ENSURE_SUCCESS(rv, rv);
if (!aDeferCompilation) {
nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
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 CompileEventHandlerInternal(ls, PR_TRUE, &aBody);
}
return SetJSEventListener(context, scope, aName, aDeferCompilation,
aPermitUntrustedEvents);
return NS_OK;
}
void
@ -606,211 +547,153 @@ nsEventListenerManager::RemoveScriptEventListener(nsIAtom* aName)
}
}
jsid
nsEventListenerManager::sAddListenerID = JSID_VOID;
nsresult
nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext,
void *aScope,
nsIAtom *aName)
nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerStruct,
PRBool aNeedsCxPush,
const nsAString* aBody)
{
// Check that we have access to set an event listener. Prevents
// snooping attacks across domains by setting onkeypress handlers,
// for instance.
// You'd think it'd work just to get the JSContext from aContext,
// 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;
NS_PRECONDITION(aListenerStruct->GetJSListener(),
"Why do we not have a JS listener?");
NS_PRECONDITION(aListenerStruct->mHandlerIsString,
"Why are we compiling a non-string JS listener?");
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;
nsIJSEventListener *listener = aListenerStruct->GetJSListener();
NS_ASSERTION(!listener->GetHandler(), "What is there to compile?");
nsIScriptContext *context = listener->GetEventContext();
nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
do_QueryInterface(aObject);
nsScriptObjectHolder handler(aContext);
do_QueryInterface(mTarget);
nsScriptObjectHolder handler(context);
if (handlerOwner) {
result = handlerOwner->GetCompiledEventHandler(aName,
result = handlerOwner->GetCompiledEventHandler(aListenerStruct->mTypeAtom,
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;
} else {
// Make sure there's nothing in the holder in the failure case
handler.set(nsnull);
}
}
if (aListenerStruct->mHandlerIsString) {
// This should never happen for anything but content
// XXX I don't like that we have to reference content
// from here. The alternative is to store the event handler
// string on the JS object itself.
nsCOMPtr<nsIContent> content = do_QueryInterface(aObject);
NS_ASSERTION(content, "only content should have event handler attributes");
if (content) {
nsAutoString handlerBody;
nsIAtom* attrName = aName;
if (aName == nsGkAtoms::onSVGLoad)
// OK, we didn't find an existing compiled event handler. Flag us
// as not a string so we don't keep trying to compile strings
// which can't be compiled
aListenerStruct->mHandlerIsString = PR_FALSE;
// mTarget may not be an nsIContent if it's a window and we're
// getting an inline event listener forwarded from <html:body> or
// <html:frameset> or <xul:window> or the like.
// XXX I don't like that we have to reference content from
// 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;
else if (aName == nsGkAtoms::onSVGUnload)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGUnload)
attrName = nsGkAtoms::onunload;
else if (aName == nsGkAtoms::onSVGAbort)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGAbort)
attrName = nsGkAtoms::onabort;
else if (aName == nsGkAtoms::onSVGError)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGError)
attrName = nsGkAtoms::onerror;
else if (aName == nsGkAtoms::onSVGResize)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGResize)
attrName = nsGkAtoms::onresize;
else if (aName == nsGkAtoms::onSVGScroll)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGScroll)
attrName = nsGkAtoms::onscroll;
else if (aName == nsGkAtoms::onSVGZoom)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGZoom)
attrName = nsGkAtoms::onzoom;
#ifdef MOZ_SMIL
else if (aName == nsGkAtoms::onbeginEvent)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onbeginEvent)
attrName = nsGkAtoms::onbegin;
else if (aName == nsGkAtoms::onrepeatEvent)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onrepeatEvent)
attrName = nsGkAtoms::onrepeat;
else if (aName == nsGkAtoms::onendEvent)
else if (aListenerStruct->mTypeAtom == nsGkAtoms::onendEvent)
attrName = nsGkAtoms::onend;
#endif // MOZ_SMIL
content->GetAttr(kNameSpaceID_None, attrName, handlerBody);
body = &handlerBody;
}
PRUint32 lineNo = 0;
nsCAutoString url (NS_LITERAL_CSTRING("javascript:alert('TODO: FIXME')"));
nsIDocument* doc = nsnull;
nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentTarget);
if (node) {
doc = node->GetOwnerDoc();
}
if (doc) {
nsIURI *uri = doc->GetDocumentURI();
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;
PRUint32 lineNo = 0;
nsCAutoString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
nsCOMPtr<nsIDocument> doc;
if (content) {
doc = content->GetOwnerDoc();
} else {
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget);
if (win) {
doc = do_QueryInterface(win->GetExtantDocument());
}
}
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;
}
@ -828,34 +711,11 @@ nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct,
// compiled the event handler itself
if ((aListenerStruct->mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) &&
aListenerStruct->mHandlerIsString) {
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(aListener);
if (jslistener) {
// We probably have the atom already.
nsCOMPtr<nsIAtom> atom = aListenerStruct->mTypeAtom;
if (!atom) {
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());
}
}
nsIJSEventListener *jslistener = aListenerStruct->GetJSListener();
result = CompileEventHandlerInternal(aListenerStruct,
jslistener->GetEventContext() !=
aPusher->GetCurrentScriptContext(),
nsnull);
}
if (NS_SUCCEEDED(result)) {
@ -1040,18 +900,10 @@ nsEventListenerManager::GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList)
PRBool systemGroup = !!(ls.mFlags & NS_EVENT_FLAG_SYSTEM_EVENT);
PRBool allowsUntrusted = !!(ls.mFlags & NS_PRIV_EVENT_UNTRUSTED_PERMITTED);
// 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) {
nsCOMPtr<nsIJSEventListener> jslistener = do_QueryInterface(ls.mListener);
if (jslistener) {
CompileEventHandlerInternal(jslistener->GetEventContext(),
jslistener->GetEventScope(),
jslistener->GetEventTarget(),
ls.mTypeAtom,
const_cast<nsListenerStruct*>(&ls),
mTarget,
PR_TRUE);
}
CompileEventHandlerInternal(const_cast<nsListenerStruct*>(&ls),
PR_TRUE, nsnull);
}
const nsDependentSubstring& eventType =
Substring(nsDependentAtomString(ls.mTypeAtom), 2);
@ -1077,3 +929,52 @@ nsEventListenerManager::HasUnloadListeners()
}
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 "nsTObserverArray.h"
#include "nsGUIEvent.h"
#include "nsIJSEventListener.h"
class nsIDOMEvent;
class nsIAtom;
@ -60,13 +61,19 @@ class nsEventTargetChainItem;
class nsPIDOMWindow;
class nsCxPusher;
class nsIEventListenerInfo;
class nsIDocument;
typedef struct {
nsRefPtr<nsIDOMEventListener> mListener;
PRUint32 mEventType;
nsCOMPtr<nsIAtom> mTypeAtom;
PRUint16 mFlags;
PRBool mHandlerIsString;
PRPackedBool mHandlerIsString;
nsIJSEventListener* GetJSListener() const {
return (mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) ?
static_cast<nsIJSEventListener *>(mListener.get()) : nsnull;
}
} nsListenerStruct;
/*
@ -102,18 +109,24 @@ public:
void RemoveEventListenerByType(nsIDOMEventListener *aListener,
const nsAString& type,
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,
const nsAString& aFunc,
PRUint32 aLanguage,
PRBool aDeferCompilation,
PRBool aPermitUntrustedEvents);
nsresult RegisterScriptEventListener(nsIScriptContext *aContext,
void *aScopeObject,
nsIAtom* aName);
/**
* Remove the current "inline" event listener for aName.
*/
void RemoveScriptEventListener(nsIAtom *aName);
nsresult CompileScriptEventListener(nsIScriptContext *aContext,
void *aScopeObject,
nsIAtom* aName, PRBool *aDidCompile);
void HandleEvent(nsPresContext* aPresContext,
nsEvent* aEvent,
@ -155,18 +168,46 @@ public:
nsEventStatus* aEventStatus,
nsCxPusher* aPusher);
/**
* Tells the event listener manager that its target (which owns it) is
* no longer using it (and could go away).
*/
void Disconnect();
/**
* Allows us to quickly determine if we have mutation listeners registered.
*/
PRBool HasMutationListeners();
/**
* Allows us to quickly determine whether we have unload or beforeunload
* listeners registered.
*/
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();
/**
* Returns PR_TRUE if there is at least one event listener for aEventName.
*/
PRBool HasListenersFor(const nsAString& aEventName);
/**
* Returns PR_TRUE if there is at least one event listener.
*/
PRBool HasListeners();
/**
* Sets aList to the list of nsIEventListenerInfo objects representing the
* listeners managed by this listener manager.
*/
nsresult GetListenerInfo(nsCOMArray<nsIEventListenerInfo>* aList);
PRUint32 GetIdentifierForEvent(nsIAtom* aEvent);
@ -198,18 +239,49 @@ protected:
nsIDOMEventTarget* aCurrentTarget,
PRUint32 aPhaseFlags,
nsCxPusher* aPusher);
nsresult CompileEventHandlerInternal(nsIScriptContext *aContext,
void *aScopeObject,
nsISupports *aObject,
nsIAtom *aName,
nsListenerStruct *aListenerStruct,
nsISupports* aCurrentTarget,
PRBool aNeedsCxPush);
/**
* Compile the "inline" event listener for aListenerStruct. The
* body of the listener can be provided in aBody; if this is null we
* will look for it on mTarget.
*/
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);
/**
* 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,
void *aScopeGlobal,
nsIAtom* aName, PRBool aIsString,
PRBool aPermitUntrustedEvents);
nsIAtom* aName,
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,
PRUint32 aType,
nsIAtom* aTypeAtom,

View File

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

View File

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

View File

@ -1245,7 +1245,8 @@ nsGenericHTMLElement::GetEventListenerManagerForAttr(PRBool* aDefer)
// 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.
// bail if it does. See similar code in nsHTMLBodyElement and
// nsHTMLFramesetElement
*aDefer = PR_FALSE;
if (document &&
(win = document->GetInnerWindow()) && win->IsInnerWindow()) {

View File

@ -57,6 +57,7 @@
#include "nsIEditorDocShell.h"
#include "nsCOMPtr.h"
#include "nsRuleWalker.h"
#include "jsapi.h"
//----------------------------------------------------------------------
@ -105,6 +106,16 @@ public:
// 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,
nsIAtom* aAttribute,
const nsAString& aValue,
@ -488,3 +499,54 @@ nsHTMLBodyElement::GetAssociatedEditor()
editorDocShell->GetEditor(&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 ***** */
#include "nsHTMLFrameSetElement.h"
#include "jsapi.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet)
@ -347,3 +348,55 @@ nsHTMLFrameSetElement::ParseRowCol(const nsAString & aValue,
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
//----------------------------------------------------------------------
class nsHTMLFrameSetElement : public nsGenericHTMLElement,
public nsIDOMHTMLFrameSetElement
{
@ -96,6 +98,16 @@ public:
// 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
// both here to silence compiler warnings).
nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,

View File

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

View File

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

View File

@ -159,7 +159,6 @@ public:
// nsIScriptEventHandlerOwner
virtual nsresult CompileEventHandler(nsIScriptContext* aContext,
nsISupports* aTarget,
nsIAtom *aName,
const nsAString& aBody,
const char* aURL,
@ -743,7 +742,6 @@ nsScriptEventHandlerOwnerTearoff::GetCompiledEventHandler(
nsresult
nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
nsIScriptContext* aContext,
nsISupports* aTarget,
nsIAtom *aName,
const nsAString& aBody,
const char* aURL,
@ -786,8 +784,6 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
}
else {
// We don't have a prototype, so the passed context is ok.
NS_ASSERTION(aTarget != nsnull, "no prototype and no target?!");
context = aContext;
}
@ -808,12 +804,6 @@ nsScriptEventHandlerOwnerTearoff::CompileEventHandler(
aHandler);
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 =
mElement->FindPrototypeAttribute(kNameSpaceID_None, aName);
if (attr) {

View File

@ -523,7 +523,6 @@ static const char kDOMStringBundleURL[] =
(nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_ADDPROPERTY | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_EQUALITY | \
nsIXPCScriptable::WANT_ENUMERATE | \
@ -788,7 +787,7 @@ static nsDOMClassInfoData sClassInfoData[] = {
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLBaseElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLBodyElement, nsHTMLBodyElementSH,
NS_DEFINE_CLASSINFO_DATA(HTMLBodyElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(HTMLButtonElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
@ -1625,15 +1624,8 @@ jsid nsDOMClassInfo::sURL_id = JSID_VOID;
jsid nsDOMClassInfo::sKeyPath_id = JSID_VOID;
jsid nsDOMClassInfo::sAutoIncrement_id = JSID_VOID;
jsid nsDOMClassInfo::sUnique_id = JSID_VOID;
#define EVENT(name_, id_, type_, struct_) \
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
jsid nsDOMClassInfo::sOnload_id = JSID_VOID;
jsid nsDOMClassInfo::sOnerror_id = JSID_VOID;
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(sAutoIncrement_id, cx, "autoIncrement");
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;
}
@ -2201,6 +2186,7 @@ nsDOMClassInfo::RegisterExternalClasses()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMXPathEvaluator) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMDocumentTouch, \
nsDOMTouchEvent::PrefEnabled())
@ -2211,6 +2197,7 @@ nsDOMClassInfo::RegisterExternalClasses()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \
nsDOMTouchEvent::PrefEnabled())
@ -2268,6 +2255,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMJSWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMStorageIndexedDB,
nsGlobalWindow::HasIndexedDBSupport())
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsIDOMWindowPerformance,
@ -2386,6 +2374,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
nsDOMTouchEvent::PrefEnabled())
DOM_CLASSINFO_MAP_END
@ -2919,6 +2908,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementCSSInlineStyle)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
nsDOMTouchEvent::PrefEnabled())
DOM_CLASSINFO_MAP_END
@ -2969,6 +2959,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMChromeWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageIndexedDB)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(RangeException, nsIDOMRangeException)
@ -3030,6 +3021,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGElement) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement) \
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector) \
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers) \
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver, \
nsDOMTouchEvent::PrefEnabled())
@ -3855,6 +3847,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMStorageIndexedDB)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMModalContentWindow)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(DataContainerEvent, nsIDOMDataContainerEvent)
@ -3966,6 +3959,7 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNSElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMNodeSelector)
DOM_CLASSINFO_MAP_ENTRY(nsIInlineEventHandlers)
DOM_CLASSINFO_MAP_CONDITIONAL_ENTRY(nsITouchEventReceiver,
nsDOMTouchEvent::PrefEnabled())
DOM_CLASSINFO_MAP_END
@ -4888,15 +4882,8 @@ nsDOMClassInfo::ShutDown()
sKeyPath_id = JSID_VOID;
sAutoIncrement_id = JSID_VOID;
sUnique_id = JSID_VOID;
#define EVENT(name_, id_, type_, struct_) \
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
sOnload_id = JSID_VOID;
sOnerror_id = JSID_VOID;
NS_IF_RELEASE(sXPConnect);
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 nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval);
return NS_OK;
}
NS_IMETHODIMP
@ -5523,62 +5510,6 @@ DefineInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID)
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
{
protected:
@ -6756,18 +6687,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
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 (IsReadonlyReplaceable(id) ||
(!(flags & JSRESOLVE_QUALIFIED) && IsWritableReplaceable(id))) {
@ -6890,8 +6809,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
}
JSObject *oldobj = *objp;
rv = nsEventReceiverSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
rv = nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
if (NS_FAILED(rv) || *objp != oldobj) {
// 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)
{
nsNodeSH::PreserveWrapper(GetNative(wrapper, obj));
return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval);
return NS_OK;
}
NS_IMETHODIMP
@ -7311,11 +7230,15 @@ nsNodeSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (id == sOnload_id || id == sOnerror_id) {
// Make sure that this node can't go away while waiting for a
// 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));
}
return nsEventReceiverSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
return nsDOMGenericSH::NewResolve(wrapper, cx, obj, id, flags, objp,
_retval);
}
NS_IMETHODIMP
@ -7372,7 +7295,7 @@ nsNodeSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp,_retval);
return NS_OK;
}
NS_IMETHODIMP
@ -7390,249 +7313,6 @@ nsNodeSH::PreserveWrapper(nsISupports *aNative)
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
NS_IMETHODIMP

View File

@ -292,16 +292,9 @@ public:
static jsid sKeyPath_id;
static jsid sAutoIncrement_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:
static JSPropertyOp sXPCNativeWrapperGetPropertyOp;
static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp;
@ -346,53 +339,6 @@ do_QueryWrapper(JSContext *cx, JSObject *obj, nsresult* error)
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.
class nsEventTargetSH : public nsDOMGenericSH
{
@ -420,10 +366,10 @@ public:
// Window scriptable helper
class nsWindowSH : public nsEventReceiverSH
class nsWindowSH : public nsDOMGenericSH
{
protected:
nsWindowSH(nsDOMClassInfoData *aData) : nsEventReceiverSH(aData)
nsWindowSH(nsDOMClassInfoData *aData) : nsDOMGenericSH(aData)
{
}
@ -451,7 +397,7 @@ public:
NS_IMETHOD GetScriptableFlags(PRUint32 *aFlags)
{
PRUint32 flags;
nsresult rv = nsEventReceiverSH::GetScriptableFlags(&flags);
nsresult rv = nsDOMGenericSH::GetScriptableFlags(&flags);
if (NS_SUCCEEDED(rv)) {
*aFlags = flags | nsIXPCScriptable::WANT_POSTCREATE;
}
@ -548,10 +494,10 @@ public:
// DOM Node helper, this class deals with setting the parent for the
// wrappers
class nsNodeSH : public nsEventReceiverSH
class nsNodeSH : public nsDOMGenericSH
{
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
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(nsIDOMWindowPerformance)
NS_INTERFACE_MAP_ENTRY(nsITouchEventReceiver)
NS_INTERFACE_MAP_ENTRY(nsIInlineEventHandlers)
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Window)
OUTER_WINDOW_ONLY
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
@ -11356,6 +11357,37 @@ NS_IMETHODIMP nsNavigator::GetMozNotification(nsIDOMDesktopNotificationCenter **
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
nsNavigator::SizeOf() const
{

View File

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

View File

@ -40,47 +40,55 @@
#include "nsIScriptContext.h"
#include "jsapi.h"
#include "nsIDOMEventListener.h"
class nsIScriptObjectOwner;
class nsIDOMEventListener;
class nsIAtom;
#define NS_IJSEVENTLISTENER_IID \
{ 0x08ca15c4, 0x1c2d, 0x449e, \
{ 0x9e, 0x88, 0xaa, 0x8b, 0xbf, 0x00, 0xf7, 0x63 } }
{ 0xb88fb066, 0xe9f8, 0x45d0, \
{ 0x92, 0x9a, 0x7d, 0xa8, 0x4c, 0x1f, 0xb5, 0xbc } }
// 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
// script languages, so is no longer JS specific)
class nsIJSEventListener : public nsISupports
class nsIJSEventListener : public nsIDOMEventListener
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSEVENTLISTENER_IID)
nsIJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports *aTarget)
nsISupports *aTarget, void *aHandler)
: mContext(aContext), mScopeObject(aScopeObject),
mTarget(do_QueryInterface(aTarget))
mTarget(do_QueryInterface(aTarget)), mHandler(aHandler)
{
}
nsIScriptContext *GetEventContext()
nsIScriptContext *GetEventContext() const
{
return mContext;
}
nsISupports *GetEventTarget()
nsISupports *GetEventTarget() const
{
return mTarget;
}
void *GetEventScope()
void *GetEventScope() const
{
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:
virtual ~nsIJSEventListener()
@ -89,13 +97,15 @@ protected:
nsCOMPtr<nsIScriptContext> mContext;
void *mScopeObject;
nsCOMPtr<nsISupports> mTarget;
void *mHandler;
};
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,
void *aScopeObject, nsISupports *aObject,
nsIAtom* aType, nsIDOMEventListener **aReturn);
void *aScopeObject, nsISupports *aTarget,
nsIAtom* aType, void *aHandler,
nsIDOMEventListener **aReturn);
#endif // nsIJSEventListener_h__

View File

@ -72,10 +72,9 @@ public:
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptContextPrincipal,
NS_ISCRIPTCONTEXTPRINCIPAL_IID)
// a7139c0e-962c-44b6-bec3-e4166bfe84eb
#define NS_ISCRIPTCONTEXT_IID \
{ 0xa7139c0e, 0x962c, 0x44b6, \
{ 0xbe, 0xc3, 0xe4, 0x16, 0x6b, 0xfe, 0x84, 0xeb } }
{ 0xad76079b, 0xd408, 0x4159, \
{0xb7, 0x3f, 0x41, 0x08, 0x77, 0xff, 0x9b, 0x47 } }
/* This MUST match JSVERSION_DEFAULT. This version stuff if we don't
know what language we have is a little silly... */
@ -233,41 +232,30 @@ public:
nsIArray *argv, nsIVariant **rval) = 0;
/**
* Bind an already-compiled event handler function to a name in the given
* scope object. The same restrictions on aName (lowercase ASCII, not too
* long) applies here as for CompileEventHandler. Scripting languages with
* static scoping must re-bind the scope chain for aHandler to begin (after
* the activation scope for aHandler itself, typically) with aTarget's scope.
* Bind an already-compiled event handler function to the given
* target. Scripting languages with static scoping must re-bind the
* scope chain for aHandler to begin (after the activation scope for
* aHandler itself, typically) with aTarget's scope.
*
* Logically, this 'bind' operation is more of a 'copy' - it simply
* stashes/associates the event handler function with the event target, so
* it can be fetched later with GetBoundEventHandler().
* The result of the bind operation is a new handler object, with
* principals now set and scope set as above. This is returned in
* 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
* event handler function. The context will presumably associate
* this nsISupports with a native script object.
* @param aName an nsIAtom pointer naming the function; it must be lowercase
* and ASCII, and should not be longer than 63 chars. This bound on
* length is enforced only by assertions, so caveat caller!
* @param aHandler the function object to name, created by an earlier call to
* @param aScope the scope in which the script object for aTarget should be
* looked for.
* @param aHandler the function object to bind, created by an earlier call to
* CompileEventHandler
* @return NS_OK if the function was successfully bound to the name
*
* XXXmarkh - fold this in with SetProperty? Exactly the same concept!
* @param aBoundHandler [out] the result of the bind operation.
* @return NS_OK if the function was successfully bound
*/
virtual nsresult BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom* aName,
void* aHandler) = 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;
virtual nsresult BindCompiledEventHandler(nsISupports* aTarget,
void *aScope,
void* aHandler,
nsScriptObjectHolder& aBoundHandler) = 0;
/**
* 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;
#define NS_ISCRIPTEVENTHANDLEROWNER_IID \
{ /* 2ad54ae0-a839-11d3-ba97-00104ba02d3d */ \
0x2ad54ae0, 0xa839, 0x11d3, \
{0xba, 0x97, 0x00, 0x10, 0x4b, 0xa0, 0x2d, 0x3d} }
{ 0x1e2be5d2, 0x381a, 0x46dc, \
{ 0xae, 0x97, 0xa5, 0x5f, 0x45, 0xfd, 0x36, 0x63 } }
/**
* 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)
/**
* Compile the specified event handler, and bind it to aTarget using
* aContext.
* Compile the specified event handler. This does NOT bind it to
* anything. That's the caller's responsibility.
*
* @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 aBody the handler script body
* @param aURL the URL or filename 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,
nsISupports* aTarget,
nsIAtom *aName,
const nsAString& aBody,
const char* aURL,

View File

@ -1935,13 +1935,12 @@ nsJSContext::CallEventHandler(nsISupports* aTarget, void *aScope, void *aHandler
nsresult
nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
nsIAtom *aName,
void *aHandler)
void *aHandler,
nsScriptObjectHolder& aBoundHandler)
{
NS_ENSURE_ARG(aHandler);
NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
NS_PRECONDITION(!aBoundHandler, "Shouldn't already have a bound handler!");
JSAutoRequest ar(mContext);
@ -1970,14 +1969,6 @@ nsJSContext::BindCompiledEventHandler(nsISupports* aTarget, void *aScope,
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
if (funobj) { // && ::JS_GetParent(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;
}
if (NS_SUCCEEDED(rv) &&
// 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;
}
aBoundHandler.set(funobj);
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
nsresult
nsJSContext::Serialize(nsIObjectOutputStream* aStream, void *aScriptObject)

View File

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

View File

@ -70,7 +70,7 @@ interface nsIDOMMozURLProperty : nsISupports
* @see <http://www.whatwg.org/html/#window>
*/
[scriptable, uuid(972cb379-6bdc-4544-8b46-8d721e12e906)]
[scriptable, uuid(3f5b2af2-604e-4253-8d25-6d3cafc13a69)]
interface nsIDOMWindow : nsISupports
{
// the current browsing context
@ -434,6 +434,34 @@ interface nsIDOMWindow : nsISupports
* Global storage, accessible by domain.
*/
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)]

View File

@ -74,6 +74,7 @@ XPIDLSRCS = \
nsIDOMNodeSelector.idl \
nsIDOMDOMTokenList.idl \
nsIDOMDOMSettableTokenList.idl \
nsIInlineEventHandlers.idl \
$(NULL)
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)]
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)]

View File

@ -39,6 +39,10 @@
#include "nsIDOMHTMLElement.idl"
%{ C++
#include "jspubtd.h"
%}
/**
* The nsIDOMHTMLBodyElement interface is the interface to a [X]HTML
* body element.
@ -50,7 +54,7 @@
* 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
{
attribute DOMString aLink;
@ -59,4 +63,23 @@ interface nsIDOMHTMLBodyElement : nsIDOMHTMLElement
attribute DOMString link;
attribute DOMString text;
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"
%{ C++
#include "jspubtd.h"
%}
/**
* The nsIDOMHTMLFrameSetElement interface is the interface to a
* [X]HTML frameset element.
@ -50,9 +54,28 @@
* 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
{
attribute DOMString cols;
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,
void *aScopeObject,
nsISupports *aTarget,
nsIAtom* aType)
: nsIJSEventListener(aContext, aScopeObject, aTarget), mEventName(aType)
nsIAtom* aType,
void *aHandler)
: nsIJSEventListener(aContext, aScopeObject, aTarget, aHandler),
mEventName(aType)
{
// aScopeObject is the inner window's JS object, which we need to lock
// until we are done with it.
@ -85,13 +87,18 @@ nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
aScopeObject, PR_FALSE);
if (aHandler) {
nsContentUtils::HoldScriptObject(aContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener),
aHandler, PR_TRUE);
}
}
nsJSEventListener::~nsJSEventListener()
{
if (mContext)
nsContentUtils::DropScriptObjects(mContext->GetScriptTypeID(), this,
&NS_CYCLE_COLLECTION_NAME(nsJSEventListener));
&NS_CYCLE_COLLECTION_NAME(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_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
mScopeObject)
NS_IMPL_CYCLE_COLLECTION_TRACE_MEMBER_CALLBACK(tmp->mContext->GetScriptTypeID(),
mHandler)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsJSEventListener)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsIJSEventListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(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
nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTarget);
if (!target || !mContext || !mHandler)
return NS_ERROR_FAILURE;
nsresult rv;
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;
if (mEventName == nsGkAtoms::onerror) {
nsCOMPtr<nsIPrivateDOMEvent> priv(do_QueryInterface(aEvent));
@ -220,7 +207,7 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
"JSEventListener has wrong script context?");
#endif
nsCOMPtr<nsIVariant> vrv;
rv = mContext->CallEventHandler(mTarget, mScopeObject, funcval, iargv,
rv = mContext->CallEventHandler(mTarget, mScopeObject, mHandler, iargv,
getter_AddRefs(vrv));
if (NS_SUCCEEDED(rv)) {
@ -268,6 +255,18 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
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
*/
@ -275,11 +274,12 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
nsresult
NS_NewJSEventListener(nsIScriptContext *aContext, void *aScopeObject,
nsISupports*aTarget, nsIAtom* aEventType,
nsIDOMEventListener ** aReturn)
void *aHandler, nsIDOMEventListener ** aReturn)
{
NS_ENSURE_ARG(aEventType);
nsJSEventListener* it =
new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType);
new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType,
aHandler);
if (!it) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

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

View File

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

View File

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