Bug 807226 part 7. Move creation of our event handlers out to the relevant API methods. r=smaug

Note that once we switch all these guys to WebIDL bindings they'll
automatically get the callback objects passed in from binding code.
This commit is contained in:
Boris Zbarsky 2012-11-09 08:00:25 -08:00
Родитель 3e87d4c861
Коммит 4e328798b1
6 изменённых файлов: 221 добавлений и 75 удалений

Просмотреть файл

@ -2018,10 +2018,13 @@ nsINode::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
NS_IMETHODIMP nsINode::GetOn##name_(JSContext *cx, jsval *vp) { \
nsEventListenerManager *elm = GetListenerManager(false); \
if (elm) { \
elm->GetEventHandler(nsGkAtoms::on##name_, vp); \
} else { \
*vp = JSVAL_NULL; \
EventHandlerNonNull* h = elm->GetEventHandler(nsGkAtoms::on##name_); \
if (h) { \
*vp = JS::ObjectValue(*h->Callable()); \
return NS_OK; \
} \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsINode::SetOn##name_(JSContext *cx, const jsval &v) { \
@ -2035,8 +2038,18 @@ nsINode::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
/* Just silently do nothing */ \
return NS_OK; \
} \
return elm->SetEventHandlerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
}
nsRefPtr<EventHandlerNonNull> handler; \
JSObject *callable; \
if (v.isObject() && \
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
bool ok; \
handler = new EventHandlerNonNull(cx, obj, callable, &ok); \
if (!ok) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} \
return elm->SetEventHandler(nsGkAtoms::on##name_, handler); \
}
#define TOUCH_EVENT EVENT
#define DOCUMENT_ONLY_EVENT EVENT
#include "nsEventNameList.h"

Просмотреть файл

@ -15,6 +15,9 @@
#include "nsDOMEvent.h"
#include "mozilla/Likely.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMEventTargetHelper)
@ -231,14 +234,24 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
JSContext* aCx,
const JS::Value& aValue)
{
nsEventListenerManager* elm = GetListenerManager(true);
JSObject* obj = GetWrapper();
if (!obj) {
return NS_OK;
}
return elm->SetEventHandlerToJsval(aType, aCx, obj, aValue);
nsRefPtr<EventHandlerNonNull> handler;
JSObject* callable;
if (aValue.isObject() &&
JS_ObjectIsCallable(aCx, callable = &aValue.toObject())) {
bool ok;
handler = new EventHandlerNonNull(aCx, obj, callable, &ok);
if (!ok) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
ErrorResult rv;
SetEventHandler(aType, handler, rv);
return rv.ErrorCode();
}
void
@ -246,11 +259,11 @@ nsDOMEventTargetHelper::GetEventHandler(nsIAtom* aType,
JSContext* aCx,
JS::Value* aValue)
{
*aValue = JSVAL_NULL;
nsEventListenerManager* elm = GetListenerManager(false);
if (elm) {
elm->GetEventHandler(aType, aValue);
EventHandlerNonNull* handler = GetEventHandler(aType);
if (handler) {
*aValue = JS::ObjectValue(*handler->Callable());
} else {
*aValue = JS::NullValue();
}
}

Просмотреть файл

@ -92,9 +92,20 @@ public:
nsresult SetEventHandler(nsIAtom* aType,
JSContext* aCx,
const JS::Value& aValue);
void SetEventHandler(nsIAtom* aType,
mozilla::dom::EventHandlerNonNull* aHandler,
mozilla::ErrorResult& rv)
{
rv = GetListenerManager(true)->SetEventHandler(aType, aHandler);
}
void GetEventHandler(nsIAtom* aType,
JSContext* aCx,
JS::Value* aValue);
mozilla::dom::EventHandlerNonNull* GetEventHandler(nsIAtom* aType)
{
nsEventListenerManager* elm = GetListenerManager(false);
return elm ? elm->GetEventHandler(aType) : nullptr;
}
nsresult CheckInnerWindowCorrectness()
{
@ -162,9 +173,7 @@ private:
mozilla::dom::EventHandlerNonNull* aCallback, \
ErrorResult& aRv) \
{ \
JSObject* callback = aCallback ? aCallback->Callable() : nullptr; \
aRv = SetEventHandler(nsGkAtoms::on##_event, aCx, \
JS::ObjectOrNullValue(callback)); \
SetEventHandler(nsGkAtoms::on##_event, aCallback, aRv); \
}
/* Use this macro to declare functions that forward the behavior of this

Просмотреть файл

@ -1161,65 +1161,62 @@ nsEventListenerManager::HasUnloadListeners()
}
nsresult
nsEventListenerManager::SetEventHandlerToJsval(nsIAtom* aEventName,
JSContext* cx,
JSObject* aScope,
const jsval& v)
nsEventListenerManager::SetEventHandler(nsIAtom* aEventName,
EventHandlerNonNull* aHandler)
{
JSObject *callable;
if (JSVAL_IS_PRIMITIVE(v) ||
!JS_ObjectIsCallable(cx, callable = JSVAL_TO_OBJECT(v))) {
if (!aHandler) {
RemoveEventHandler(aEventName);
return NS_OK;
}
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);
}
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, nullptr, aEventName, handler,
return SetEventHandlerInternal(nullptr, nullptr, aEventName,
nsEventHandler(aHandler),
!nsContentUtils::IsCallerChrome(), &ignored);
}
void
nsEventListenerManager::GetEventHandler(nsIAtom *aEventName, jsval *vp)
nsresult
nsEventListenerManager::SetEventHandler(OnErrorEventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(nsGkAtoms::onerror);
return NS_OK;
}
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, nullptr, nsGkAtoms::onerror,
nsEventHandler(aHandler),
!nsContentUtils::IsCallerChrome(), &ignored);
}
nsresult
nsEventListenerManager::SetEventHandler(BeforeUnloadEventHandlerNonNull* aHandler)
{
if (!aHandler) {
RemoveEventHandler(nsGkAtoms::onbeforeunload);
return NS_OK;
}
// Untrusted events are always permitted for non-chrome script
// handlers.
nsListenerStruct *ignored;
return SetEventHandlerInternal(nullptr, nullptr, nsGkAtoms::onbeforeunload,
nsEventHandler(aHandler),
!nsContentUtils::IsCallerChrome(), &ignored);
}
const nsEventHandler*
nsEventListenerManager::GetEventHandlerInternal(nsIAtom *aEventName)
{
uint32_t eventType = nsContentUtils::GetEventId(aEventName);
nsListenerStruct* ls = FindEventHandler(eventType, aEventName);
*vp = JSVAL_NULL;
if (!ls) {
return;
return nullptr;
}
nsIJSEventListener *listener = ls->GetJSListener();
@ -1230,10 +1227,10 @@ nsEventListenerManager::GetEventHandler(nsIAtom *aEventName, jsval *vp)
const nsEventHandler& handler = listener->GetHandler();
if (handler.HasEventHandler()) {
*vp = OBJECT_TO_JSVAL(handler.Ptr()->Callable());
} else {
*vp = JS::NullValue();
return &handler;
}
return nullptr;
}
size_t

Просмотреть файл

@ -281,21 +281,47 @@ protected:
public:
/**
* Set the "inline" event listener for aEventName to |v|. This
* might actually remove the event listener, depending on the value
* of |v|. Note that on entry to this function cx and aScope might
* not be in the same compartment, though cx and v are guaranteed to
* be in the same compartment.
* Set the "inline" event listener for aEventName to aHandler. If
* aHandler is null, this will actually remove the event listener
*/
nsresult SetEventHandlerToJsval(nsIAtom* aEventName, JSContext* cx,
JSObject* aScope, const jsval& v);
nsresult SetEventHandler(nsIAtom* aEventName,
mozilla::dom::EventHandlerNonNull* aHandler);
nsresult SetEventHandler(mozilla::dom::OnErrorEventHandlerNonNull* aHandler);
nsresult SetEventHandler(mozilla::dom::BeforeUnloadEventHandlerNonNull* aHandler);
/**
* Get the value of the "inline" event listener for aEventName.
* This may cause lazy compilation if the listener is uncompiled.
*
* Note: It's the caller's responsibility to make sure to call the right one
* of these methods. In particular, "onerror" events use
* OnErrorEventHandlerNonNull for some event targets and EventHandlerNonNull
* for others.
*/
void GetEventHandler(nsIAtom *aEventName, jsval *vp);
mozilla::dom::EventHandlerNonNull* GetEventHandler(nsIAtom *aEventName)
{
const nsEventHandler* handler = GetEventHandlerInternal(aEventName);
return handler ? handler->EventHandler() : nullptr;
}
mozilla::dom::OnErrorEventHandlerNonNull* GetOnErrorEventHandler()
{
const nsEventHandler* handler = GetEventHandlerInternal(nsGkAtoms::onerror);
return handler ? handler->OnErrorEventHandler() : nullptr;
}
mozilla::dom::BeforeUnloadEventHandlerNonNull* GetOnBeforeUnloadEventHandler()
{
const nsEventHandler* handler =
GetEventHandlerInternal(nsGkAtoms::onbeforeunload);
return handler ? handler->BeforeUnloadEventHandler() : nullptr;
}
protected:
/**
* Helper method for implementing the various Get*EventHandler above. Will
* return null if we don't have an event handler for this event name.
*/
const nsEventHandler* GetEventHandlerInternal(nsIAtom* aEventName);
void AddEventListener(nsIDOMEventListener *aListener,
uint32_t aType,
nsIAtom* aTypeAtom,

Просмотреть файл

@ -11192,10 +11192,13 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
jsval *vp) { \
nsEventListenerManager *elm = GetListenerManager(false); \
if (elm) { \
elm->GetEventHandler(nsGkAtoms::on##name_, vp); \
} else { \
*vp = JSVAL_NULL; \
EventHandlerNonNull* h = elm->GetEventHandler(nsGkAtoms::on##name_); \
if (h) { \
*vp = JS::ObjectValue(*h->Callable()); \
return NS_OK; \
} \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
@ -11209,7 +11212,92 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
if (!obj) { \
return NS_ERROR_UNEXPECTED; \
} \
return elm->SetEventHandlerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
nsRefPtr<EventHandlerNonNull> handler; \
JSObject *callable; \
if (v.isObject() && \
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
bool ok; \
handler = new EventHandlerNonNull(cx, obj, callable, &ok); \
if (!ok) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} \
return elm->SetEventHandler(nsGkAtoms::on##name_, handler); \
}
#define ERROR_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
jsval *vp) { \
nsEventListenerManager *elm = GetListenerManager(false); \
if (elm) { \
OnErrorEventHandlerNonNull* h = elm->GetOnErrorEventHandler(); \
if (h) { \
*vp = JS::ObjectValue(*h->Callable()); \
return NS_OK; \
} \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsEventListenerManager *elm = GetListenerManager(true); \
if (!elm) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
\
JSObject *obj = mJSObject; \
if (!obj) { \
return NS_ERROR_UNEXPECTED; \
} \
nsRefPtr<OnErrorEventHandlerNonNull> handler; \
JSObject *callable; \
if (v.isObject() && \
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
bool ok; \
handler = new OnErrorEventHandlerNonNull(cx, obj, callable, &ok); \
if (!ok) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} \
return elm->SetEventHandler(handler); \
}
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_) \
NS_IMETHODIMP nsGlobalWindow::GetOn##name_(JSContext *cx, \
jsval *vp) { \
nsEventListenerManager *elm = GetListenerManager(false); \
if (elm) { \
BeforeUnloadEventHandlerNonNull* h = \
elm->GetOnBeforeUnloadEventHandler(); \
if (h) { \
*vp = JS::ObjectValue(*h->Callable()); \
return NS_OK; \
} \
} \
*vp = JSVAL_NULL; \
return NS_OK; \
} \
NS_IMETHODIMP nsGlobalWindow::SetOn##name_(JSContext *cx, \
const jsval &v) { \
nsEventListenerManager *elm = GetListenerManager(true); \
if (!elm) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
\
JSObject *obj = mJSObject; \
if (!obj) { \
return NS_ERROR_UNEXPECTED; \
} \
nsRefPtr<BeforeUnloadEventHandlerNonNull> handler; \
JSObject *callable; \
if (v.isObject() && \
JS_ObjectIsCallable(cx, callable = &v.toObject())) { \
bool ok; \
handler = new BeforeUnloadEventHandlerNonNull(cx, obj, callable, &ok); \
if (!ok) { \
return NS_ERROR_OUT_OF_MEMORY; \
} \
} \
return elm->SetEventHandler(handler); \
}
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT