зеркало из https://github.com/mozilla/gecko-dev.git
Bug 807226 part 2. Change event handlers to store WebIDL callback functions. r=smaug
This commit is contained in:
Родитель
bec7132f7d
Коммит
beb6a36d0f
|
@ -525,7 +525,7 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
|||
JSContext* aCx,
|
||||
JSObject* aScopeObject,
|
||||
nsIAtom* aName,
|
||||
JSObject *aHandler,
|
||||
const nsEventHandler& aHandler,
|
||||
bool aPermitUntrustedEvents,
|
||||
nsListenerStruct **aListenerStruct)
|
||||
{
|
||||
|
@ -551,8 +551,9 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
|||
// If we don't have a script context, we're setting an event handler from
|
||||
// a component or other odd scope. Ask XPConnect if it can make us an
|
||||
// nsIDOMEventListener.
|
||||
MOZ_ASSERT(aHandler.HasEventHandler());
|
||||
rv = nsContentUtils::XPConnect()->WrapJS(aCx,
|
||||
aHandler,
|
||||
aHandler.Ptr()->Callable(),
|
||||
NS_GET_IID(nsIDOMEventListener),
|
||||
getter_AddRefs(listener));
|
||||
}
|
||||
|
@ -574,9 +575,10 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
|||
if (scriptListener) {
|
||||
scriptListener->SetHandler(aHandler);
|
||||
} else {
|
||||
MOZ_ASSERT(aHandler.HasEventHandler());
|
||||
nsCOMPtr<nsIDOMEventListener> listener;
|
||||
rv = nsContentUtils::XPConnect()->WrapJS(aCx,
|
||||
aHandler,
|
||||
aHandler.Ptr()->Callable(),
|
||||
NS_GET_IID(nsIDOMEventListener),
|
||||
getter_AddRefs(listener));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -587,7 +589,7 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
|||
|
||||
if (NS_SUCCEEDED(rv) && ls) {
|
||||
// Set flag to indicate possible need for compilation later
|
||||
ls->mHandlerIsString = !aHandler;
|
||||
ls->mHandlerIsString = !aHandler.HasEventHandler();
|
||||
if (aPermitUntrustedEvents) {
|
||||
ls->mFlags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
|
||||
}
|
||||
|
@ -708,7 +710,7 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
|
|||
JSObject* scope = global->GetGlobalJSObject();
|
||||
|
||||
nsListenerStruct *ls;
|
||||
rv = SetEventHandlerInternal(context, nullptr, scope, aName, nullptr,
|
||||
rv = SetEventHandlerInternal(context, nullptr, scope, aName, nsEventHandler(),
|
||||
aPermitUntrustedEvents, &ls);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
@ -745,11 +747,14 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
|
|||
nsresult result = NS_OK;
|
||||
|
||||
nsIJSEventListener *listener = aListenerStruct->GetJSListener();
|
||||
NS_ASSERTION(!listener->GetHandler(), "What is there to compile?");
|
||||
NS_ASSERTION(!listener->GetHandler().HasEventHandler(),
|
||||
"What is there to compile?");
|
||||
|
||||
nsIScriptContext *context = listener->GetEventContext();
|
||||
nsScriptObjectHolder<JSObject> handler(context);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win; // Will end up non-null if mTarget is a window
|
||||
|
||||
if (aListenerStruct->mHandlerIsString) {
|
||||
// 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
|
||||
|
@ -799,7 +804,7 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
|
|||
if (content) {
|
||||
doc = content->OwnerDoc();
|
||||
} else {
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget);
|
||||
win = do_QueryInterface(mTarget);
|
||||
if (win) {
|
||||
doc = do_QueryInterface(win->GetExtantDocument());
|
||||
}
|
||||
|
@ -849,7 +854,46 @@ nsEventListenerManager::CompileEventHandlerInternal(nsListenerStruct *aListenerS
|
|||
nsScriptObjectHolder<JSObject> boundHandler(context);
|
||||
context->BindCompiledEventHandler(mTarget, listener->GetEventScope(),
|
||||
handler.get(), boundHandler);
|
||||
listener->SetHandler(boundHandler.get());
|
||||
if (listener->EventName() == nsGkAtoms::onerror && win) {
|
||||
bool ok;
|
||||
JSAutoRequest ar(context->GetNativeContext());
|
||||
nsRefPtr<OnErrorEventHandlerNonNull> handlerCallback =
|
||||
new OnErrorEventHandlerNonNull(context->GetNativeContext(),
|
||||
listener->GetEventScope(),
|
||||
boundHandler.get(), &ok);
|
||||
if (!ok) {
|
||||
// JS_WrapObject failed, which means OOM allocating the JSObject.
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
listener->SetHandler(handlerCallback);
|
||||
} else if (listener->EventName() == nsGkAtoms::onbeforeunload) {
|
||||
// XXXbz Should we really do the special beforeunload handler on
|
||||
// non-Window objects? Per spec, we shouldn't even be compiling the
|
||||
// beforeunload content attribute on random elements! See bug 807226.
|
||||
bool ok;
|
||||
JSAutoRequest ar(context->GetNativeContext());
|
||||
nsRefPtr<BeforeUnloadEventHandlerNonNull> handlerCallback =
|
||||
new BeforeUnloadEventHandlerNonNull(context->GetNativeContext(),
|
||||
listener->GetEventScope(),
|
||||
boundHandler.get(), &ok);
|
||||
if (!ok) {
|
||||
// JS_WrapObject failed, which means OOM allocating the JSObject.
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
listener->SetHandler(handlerCallback);
|
||||
} else {
|
||||
bool ok;
|
||||
JSAutoRequest ar(context->GetNativeContext());
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(context->GetNativeContext(),
|
||||
listener->GetEventScope(),
|
||||
boundHandler.get(), &ok);
|
||||
if (!ok) {
|
||||
// JS_WrapObject failed, which means OOM allocating the JSObject.
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
listener->SetHandler(handlerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1153,28 +1197,49 @@ nsEventListenerManager::SetEventHandlerToJsval(nsIAtom* aEventName,
|
|||
const jsval& v,
|
||||
bool aExpectScriptContext)
|
||||
{
|
||||
JSObject *handler;
|
||||
JSObject *callable;
|
||||
if (JSVAL_IS_PRIMITIVE(v) ||
|
||||
!JS_ObjectIsCallable(cx, handler = JSVAL_TO_OBJECT(v))) {
|
||||
!JS_ObjectIsCallable(cx, callable = JSVAL_TO_OBJECT(v))) {
|
||||
RemoveEventHandler(aEventName);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now ensure that we're working in the compartment of aScope from now on.
|
||||
JSAutoCompartment ac(cx, aScope);
|
||||
|
||||
// Rewrap the handler into the new compartment, if needed.
|
||||
jsval tempVal = v;
|
||||
if (!JS_WrapValue(cx, &tempVal)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
nsEventHandler handler;
|
||||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mTarget);
|
||||
if (aEventName == nsGkAtoms::onerror && win) {
|
||||
bool ok;
|
||||
nsRefPtr<OnErrorEventHandlerNonNull> handlerCallback =
|
||||
new OnErrorEventHandlerNonNull(cx, aScope, callable, &ok);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
handler.SetHandler(handlerCallback);
|
||||
} else if (aEventName == nsGkAtoms::onbeforeunload) {
|
||||
MOZ_ASSERT(win,
|
||||
"Should not have onbeforeunload handlers on non-Window objects");
|
||||
bool ok;
|
||||
nsRefPtr<BeforeUnloadEventHandlerNonNull> handlerCallback =
|
||||
new BeforeUnloadEventHandlerNonNull(cx, aScope, callable, &ok);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
handler.SetHandler(handlerCallback);
|
||||
} else {
|
||||
bool ok;
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(cx, aScope, callable, &ok);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
handler.SetHandler(handlerCallback);
|
||||
}
|
||||
handler = &tempVal.toObject();
|
||||
|
||||
// We might not have a script context, e.g. if we're setting a listener
|
||||
// on a dead Window.
|
||||
nsIScriptContext *context = nsJSUtils::GetStaticScriptContext(aScope);
|
||||
NS_ENSURE_TRUE(context || !aExpectScriptContext, NS_ERROR_FAILURE);
|
||||
|
||||
JSAutoCompartment ac(cx, aScope);
|
||||
JSObject *scope = ::JS_GetGlobalForObject(cx, aScope);
|
||||
// Untrusted events are always permitted for non-chrome script
|
||||
// handlers.
|
||||
|
@ -1201,7 +1266,12 @@ nsEventListenerManager::GetEventHandler(nsIAtom *aEventName, jsval *vp)
|
|||
CompileEventHandlerInternal(ls, true, nullptr);
|
||||
}
|
||||
|
||||
*vp = OBJECT_TO_JSVAL(listener->GetHandler());
|
||||
const nsEventHandler& handler = listener->GetHandler();
|
||||
if (handler.HasEventHandler()) {
|
||||
*vp = OBJECT_TO_JSVAL(handler.Ptr()->Callable());
|
||||
} else {
|
||||
*vp = JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
|
@ -1228,7 +1298,9 @@ nsEventListenerManager::MarkForCC()
|
|||
const nsListenerStruct& ls = mListeners.ElementAt(i);
|
||||
nsIJSEventListener* jsl = ls.GetJSListener();
|
||||
if (jsl) {
|
||||
xpc_UnmarkGrayObject(jsl->GetHandler());
|
||||
if (jsl->GetHandler().HasEventHandler()) {
|
||||
xpc_UnmarkGrayObject(jsl->GetHandler().Ptr()->Callable());
|
||||
}
|
||||
xpc_UnmarkGrayObject(jsl->GetEventScope());
|
||||
} else if (ls.mListenerType == eWrappedJSListener) {
|
||||
xpc_TryUnmarkWrappedGrayObject(ls.mListener);
|
||||
|
|
|
@ -261,16 +261,16 @@ protected:
|
|||
nsListenerStruct* FindEventHandler(uint32_t 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.
|
||||
* Set the "inline" event listener for aName to aHandler. aHandler may be
|
||||
* have no actual handler set 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 SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
JSContext* aCx,
|
||||
JSObject* aScopeGlobal,
|
||||
nsIAtom* aName,
|
||||
JSObject *aHandler,
|
||||
const nsEventHandler& aHandler,
|
||||
bool aPermitUntrustedEvents,
|
||||
nsListenerStruct **aListenerStruct);
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ nsEventListenerInfo::GetJSVal(JSContext* aCx, mozilla::Maybe<JSAutoCompartment>&
|
|||
|
||||
nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
|
||||
if (jsl) {
|
||||
JSObject *handler = jsl->GetHandler();
|
||||
JSObject *handler = jsl->GetHandler().Ptr()->Callable();
|
||||
if (handler) {
|
||||
aAc.construct(aCx, handler);
|
||||
*aJSVal = OBJECT_TO_JSVAL(handler);
|
||||
|
|
|
@ -45,8 +45,10 @@
|
|||
#include "nsXBLSerialize.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/EventHandlerBinding.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID,
|
||||
NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
|
||||
|
@ -294,11 +296,22 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventTarget* aTarget,
|
|||
handler.get(), boundHandler);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool ok;
|
||||
JSAutoRequest ar(boundContext->GetNativeContext());
|
||||
nsRefPtr<EventHandlerNonNull> handlerCallback =
|
||||
new EventHandlerNonNull(boundContext->GetNativeContext(),
|
||||
scope, boundHandler.get(), &ok);
|
||||
if (!ok) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsEventHandler eventHandler(handlerCallback);
|
||||
|
||||
// Execute it.
|
||||
nsCOMPtr<nsIJSEventListener> eventListener;
|
||||
rv = NS_NewJSEventListener(boundContext, scope,
|
||||
scriptTarget, onEventAtom,
|
||||
boundHandler.get(),
|
||||
eventHandler,
|
||||
getter_AddRefs(eventListener));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
|
|
@ -10,13 +10,150 @@
|
|||
#include "jsapi.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
|
||||
class nsIAtom;
|
||||
#include "nsIAtom.h"
|
||||
#include "mozilla/dom/EventHandlerBinding.h"
|
||||
|
||||
#define NS_IJSEVENTLISTENER_IID \
|
||||
{ 0x92f9212b, 0xa6aa, 0x4867, \
|
||||
{ 0x93, 0x8a, 0x56, 0xbe, 0x17, 0x67, 0x4f, 0xd4 } }
|
||||
|
||||
class nsEventHandler
|
||||
{
|
||||
public:
|
||||
typedef mozilla::dom::EventHandlerNonNull EventHandlerNonNull;
|
||||
typedef mozilla::dom::BeforeUnloadEventHandlerNonNull
|
||||
BeforeUnloadEventHandlerNonNull;
|
||||
typedef mozilla::dom::OnErrorEventHandlerNonNull OnErrorEventHandlerNonNull;
|
||||
typedef mozilla::dom::CallbackFunction CallbackFunction;
|
||||
|
||||
enum HandlerType {
|
||||
eUnset = 0,
|
||||
eNormal = 0x1,
|
||||
eOnError = 0x2,
|
||||
eOnBeforeUnload = 0x3,
|
||||
eTypeBits = 0x3
|
||||
};
|
||||
|
||||
nsEventHandler() :
|
||||
mBits(0)
|
||||
{}
|
||||
|
||||
nsEventHandler(EventHandlerNonNull* aHandler)
|
||||
{
|
||||
Assign(aHandler, eNormal);
|
||||
}
|
||||
|
||||
nsEventHandler(OnErrorEventHandlerNonNull* aHandler)
|
||||
{
|
||||
Assign(aHandler, eOnError);
|
||||
}
|
||||
|
||||
nsEventHandler(BeforeUnloadEventHandlerNonNull* aHandler)
|
||||
{
|
||||
Assign(aHandler, eOnBeforeUnload);
|
||||
}
|
||||
|
||||
nsEventHandler(const nsEventHandler& aOther)
|
||||
{
|
||||
if (aOther.HasEventHandler()) {
|
||||
// Have to make sure we take our own ref
|
||||
Assign(aOther.Ptr(), aOther.Type());
|
||||
} else {
|
||||
mBits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~nsEventHandler()
|
||||
{
|
||||
ReleaseHandler();
|
||||
}
|
||||
|
||||
HandlerType Type() const {
|
||||
return HandlerType(mBits & eTypeBits);
|
||||
}
|
||||
|
||||
bool HasEventHandler() const
|
||||
{
|
||||
return !!Ptr();
|
||||
}
|
||||
|
||||
void SetHandler(const nsEventHandler& aHandler)
|
||||
{
|
||||
if (aHandler.HasEventHandler()) {
|
||||
ReleaseHandler();
|
||||
Assign(aHandler.Ptr(), aHandler.Type());
|
||||
} else {
|
||||
ForgetHandler();
|
||||
}
|
||||
}
|
||||
|
||||
EventHandlerNonNull* EventHandler() const
|
||||
{
|
||||
MOZ_ASSERT(Type() == eNormal && Ptr());
|
||||
return reinterpret_cast<EventHandlerNonNull*>(Ptr());
|
||||
}
|
||||
|
||||
void SetHandler(EventHandlerNonNull* aHandler)
|
||||
{
|
||||
ReleaseHandler();
|
||||
Assign(aHandler, eNormal);
|
||||
}
|
||||
|
||||
BeforeUnloadEventHandlerNonNull* BeforeUnloadEventHandler() const
|
||||
{
|
||||
MOZ_ASSERT(Type() == eOnBeforeUnload);
|
||||
return reinterpret_cast<BeforeUnloadEventHandlerNonNull*>(Ptr());
|
||||
}
|
||||
|
||||
void SetHandler(BeforeUnloadEventHandlerNonNull* aHandler)
|
||||
{
|
||||
ReleaseHandler();
|
||||
Assign(aHandler, eOnBeforeUnload);
|
||||
}
|
||||
|
||||
OnErrorEventHandlerNonNull* OnErrorEventHandler() const
|
||||
{
|
||||
MOZ_ASSERT(Type() == eOnError);
|
||||
return reinterpret_cast<OnErrorEventHandlerNonNull*>(Ptr());
|
||||
}
|
||||
|
||||
void SetHandler(OnErrorEventHandlerNonNull* aHandler)
|
||||
{
|
||||
ReleaseHandler();
|
||||
Assign(aHandler, eOnError);
|
||||
}
|
||||
|
||||
CallbackFunction* Ptr() const
|
||||
{
|
||||
// Have to cast eTypeBits so we don't have to worry about
|
||||
// promotion issues after the bitflip.
|
||||
return reinterpret_cast<CallbackFunction*>(mBits & ~uintptr_t(eTypeBits));
|
||||
}
|
||||
|
||||
void ForgetHandler()
|
||||
{
|
||||
ReleaseHandler();
|
||||
mBits = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(const nsEventHandler&) MOZ_DELETE;
|
||||
|
||||
void ReleaseHandler()
|
||||
{
|
||||
nsISupports* ptr = Ptr();
|
||||
NS_IF_RELEASE(ptr);
|
||||
}
|
||||
|
||||
void Assign(nsISupports* aHandler, HandlerType aType) {
|
||||
MOZ_ASSERT(aHandler, "Must have handler");
|
||||
NS_ADDREF(aHandler);
|
||||
mBits = uintptr_t(aHandler) | uintptr_t(aType);
|
||||
}
|
||||
|
||||
uintptr_t mBits;
|
||||
};
|
||||
|
||||
// Implemented by script event listeners. Used to retrieve the
|
||||
// script object corresponding to the event target and the handler itself.
|
||||
// (Note this interface is now used to store script objects for all
|
||||
|
@ -30,8 +167,10 @@ public:
|
|||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IJSEVENTLISTENER_IID)
|
||||
|
||||
nsIJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
|
||||
nsISupports *aTarget, JSObject *aHandler)
|
||||
: mContext(aContext), mScopeObject(aScopeObject), mHandler(aHandler)
|
||||
nsISupports *aTarget, nsIAtom* aType,
|
||||
const nsEventHandler& aHandler)
|
||||
: mContext(aContext), mScopeObject(aScopeObject), mEventName(aType),
|
||||
mHandler(aHandler)
|
||||
{
|
||||
nsCOMPtr<nsISupports> base = do_QueryInterface(aTarget);
|
||||
mTarget = base.get();
|
||||
|
@ -57,21 +196,35 @@ public:
|
|||
return xpc_UnmarkGrayObject(mScopeObject);
|
||||
}
|
||||
|
||||
JSObject *GetHandler() const
|
||||
const nsEventHandler& GetHandler() const
|
||||
{
|
||||
return xpc_UnmarkGrayObject(mHandler);
|
||||
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(JSObject *aHandler) = 0;
|
||||
nsIAtom* EventName() const
|
||||
{
|
||||
return mEventName;
|
||||
}
|
||||
|
||||
// Set a handler for this event listener. The handler must already
|
||||
// be bound to the right target.
|
||||
void SetHandler(const nsEventHandler& aHandler)
|
||||
{
|
||||
mHandler.SetHandler(aHandler);
|
||||
}
|
||||
void SetHandler(mozilla::dom::EventHandlerNonNull* aHandler)
|
||||
{
|
||||
mHandler.SetHandler(aHandler);
|
||||
}
|
||||
void SetHandler(mozilla::dom::BeforeUnloadEventHandlerNonNull* aHandler)
|
||||
{
|
||||
mHandler.SetHandler(aHandler);
|
||||
}
|
||||
void SetHandler(mozilla::dom::OnErrorEventHandlerNonNull* aHandler)
|
||||
{
|
||||
mHandler.SetHandler(aHandler);
|
||||
}
|
||||
|
||||
// Among the sub-classes that inherit (directly or indirectly) from nsINode,
|
||||
// measurement of the following members may be added later if DMD finds it is
|
||||
// worthwhile:
|
||||
// - nsIJSEventListener: mEventName
|
||||
//
|
||||
virtual size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
{
|
||||
return 0;
|
||||
|
@ -82,8 +235,10 @@ public:
|
|||
// - mTarget
|
||||
//
|
||||
// The following members are not measured:
|
||||
// - mScopeObject, mHandler: because they're measured by the JS memory
|
||||
// - mScopeObject: because they're measured by the JS memory
|
||||
// reporters
|
||||
// - mHandler: may be shared with others
|
||||
// - mEventName: shared with others
|
||||
}
|
||||
|
||||
virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
|
@ -99,7 +254,8 @@ protected:
|
|||
nsCOMPtr<nsIScriptContext> mContext;
|
||||
JSObject* mScopeObject;
|
||||
nsISupports* mTarget;
|
||||
JSObject *mHandler;
|
||||
nsCOMPtr<nsIAtom> mEventName;
|
||||
nsEventHandler mHandler;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
|
||||
|
@ -107,7 +263,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
|
|||
/* factory function. aHandler must already be bound to aTarget */
|
||||
nsresult NS_NewJSEventListener(nsIScriptContext *aContext,
|
||||
JSObject* aScopeObject, nsISupports* aTarget,
|
||||
nsIAtom* aType, JSObject* aHandler,
|
||||
nsIAtom* aType, const nsEventHandler& aHandler,
|
||||
nsIJSEventListener **aReturn);
|
||||
|
||||
#endif // nsIJSEventListener_h__
|
||||
|
|
|
@ -78,6 +78,12 @@ public:
|
|||
return mCallable;
|
||||
}
|
||||
|
||||
bool HasGrayCallable() const
|
||||
{
|
||||
// Play it safe in case this gets called after unlink.
|
||||
return mCallable && xpc_IsGrayGCThing(mCallable);
|
||||
}
|
||||
|
||||
protected:
|
||||
void DropCallback()
|
||||
{
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
static EventListenerCounter sEventListenerCounter;
|
||||
#endif
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
/*
|
||||
* nsJSEventListener implementation
|
||||
*/
|
||||
|
@ -45,9 +47,8 @@ nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
|
|||
JSObject* aScopeObject,
|
||||
nsISupports *aTarget,
|
||||
nsIAtom* aType,
|
||||
JSObject *aHandler)
|
||||
: nsIJSEventListener(aContext, aScopeObject, aTarget, aHandler),
|
||||
mEventName(aType)
|
||||
const nsEventHandler& aHandler)
|
||||
: nsIJSEventListener(aContext, aScopeObject, aTarget, aType, aHandler)
|
||||
{
|
||||
// aScopeObject is the inner window's JS object, which we need to lock
|
||||
// until we are done with it.
|
||||
|
@ -70,6 +71,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
|
|||
tmp->mScopeObject = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
|
||||
}
|
||||
tmp->mHandler.ForgetHandler();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSEventListener)
|
||||
if (MOZ_UNLIKELY(cb.WantDebugInfo()) && tmp->mEventName) {
|
||||
|
@ -82,12 +84,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsJSEventListener)
|
|||
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsJSEventListener, tmp->mRefCnt.get())
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mContext)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mHandler.Ptr())
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsJSEventListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScopeObject)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mHandler)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsJSEventListener)
|
||||
|
@ -131,7 +133,8 @@ nsJSEventListener::IsBlackForCC()
|
|||
{
|
||||
if (mContext &&
|
||||
(!mScopeObject || !xpc_IsGrayGCThing(mScopeObject)) &&
|
||||
(!mHandler || !xpc_IsGrayGCThing(mHandler))) {
|
||||
(!mHandler.HasEventHandler() ||
|
||||
!mHandler.Ptr()->HasGrayCallable())) {
|
||||
nsIScriptGlobalObject* sgo =
|
||||
static_cast<nsJSContext*>(mContext.get())->GetCachedGlobalObject();
|
||||
return sgo && sgo->IsBlackForCC();
|
||||
|
@ -143,7 +146,7 @@ nsresult
|
|||
nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTarget);
|
||||
if (!target || !mContext || !mHandler)
|
||||
if (!target || !mContext || !mHandler.HasEventHandler())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv;
|
||||
|
@ -208,9 +211,9 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
|||
#endif
|
||||
nsCOMPtr<nsIVariant> vrv;
|
||||
xpc_UnmarkGrayObject(mScopeObject);
|
||||
xpc_UnmarkGrayObject(mHandler);
|
||||
rv = mContext->CallEventHandler(mTarget, mScopeObject, mHandler, iargv,
|
||||
getter_AddRefs(vrv));
|
||||
rv = mContext->CallEventHandler(mTarget, mScopeObject,
|
||||
mHandler.Ptr()->Callable(),
|
||||
iargv, getter_AddRefs(vrv));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
uint16_t dataType = nsIDataType::VTYPE_VOID;
|
||||
|
@ -257,18 +260,6 @@ nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
|||
return rv;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsJSEventListener::SetHandler(JSObject *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
|
||||
*/
|
||||
|
@ -276,7 +267,8 @@ nsJSEventListener::SetHandler(JSObject *aHandler)
|
|||
nsresult
|
||||
NS_NewJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
|
||||
nsISupports*aTarget, nsIAtom* aEventType,
|
||||
JSObject* aHandler, nsIJSEventListener** aReturn)
|
||||
const nsEventHandler& aHandler,
|
||||
nsIJSEventListener** aReturn)
|
||||
{
|
||||
NS_ENSURE_ARG(aEventType);
|
||||
nsJSEventListener* it =
|
||||
|
|
|
@ -21,7 +21,8 @@ class nsJSEventListener : public nsIJSEventListener
|
|||
{
|
||||
public:
|
||||
nsJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
|
||||
nsISupports* aTarget, nsIAtom* aType, JSObject* aHandler);
|
||||
nsISupports* aTarget, nsIAtom* aType,
|
||||
const nsEventHandler& aHandler);
|
||||
virtual ~nsJSEventListener();
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
@ -30,7 +31,6 @@ public:
|
|||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
// nsIJSEventListener
|
||||
virtual void SetHandler(JSObject *aHandler);
|
||||
|
||||
virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
{
|
||||
|
@ -41,8 +41,6 @@ public:
|
|||
|
||||
protected:
|
||||
bool IsBlackForCC();
|
||||
|
||||
nsCOMPtr<nsIAtom> mEventName;
|
||||
};
|
||||
|
||||
#endif //nsJSEventListener_h__
|
||||
|
|
|
@ -15,5 +15,9 @@ callback EventHandlerNonNull = any (Event event);
|
|||
typedef EventHandlerNonNull? EventHandler;
|
||||
|
||||
[TreatNonCallableAsNull]
|
||||
callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column);
|
||||
callback BeforeUnloadEventHandlerNonNull = DOMString? (Event event);
|
||||
typedef BeforeUnloadEventHandlerNonNull? BeforeUnloadEventHandler;
|
||||
|
||||
[TreatNonCallableAsNull]
|
||||
callback OnErrorEventHandlerNonNull = boolean ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column);
|
||||
typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
|
||||
|
|
Загрузка…
Ссылка в новой задаче