mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 807226 part 4. Allow event handlers to have a null nsIScriptContext if they won't have to compile from a string. r=smaug
This commit is contained in:
parent
d15bb45f3e
commit
2daa94afcd
@ -2035,8 +2035,7 @@ nsINode::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
||||
/* Just silently do nothing */ \
|
||||
return NS_OK; \
|
||||
} \
|
||||
return elm->SetEventHandlerToJsval(nsGkAtoms::on##name_, cx, obj, v, \
|
||||
true); \
|
||||
return elm->SetEventHandlerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
|
||||
}
|
||||
#define TOUCH_EVENT EVENT
|
||||
#define DOCUMENT_ONLY_EVENT EVENT
|
||||
|
@ -238,8 +238,7 @@ nsDOMEventTargetHelper::SetEventHandler(nsIAtom* aType,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return elm->SetEventHandlerToJsval(aType, aCx, obj, aValue,
|
||||
HasOrHasHadOwner());
|
||||
return elm->SetEventHandlerToJsval(aType, aCx, obj, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -522,14 +522,14 @@ nsEventListenerManager::FindEventHandler(uint32_t aEventType,
|
||||
|
||||
nsresult
|
||||
nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
JSContext* aCx,
|
||||
JSObject* aScopeObject,
|
||||
nsIAtom* aName,
|
||||
const nsEventHandler& aHandler,
|
||||
bool aPermitUntrustedEvents,
|
||||
nsListenerStruct **aListenerStruct)
|
||||
{
|
||||
NS_ASSERTION(aContext || aCx, "Must have one or the other!");
|
||||
NS_ASSERTION(aContext || aHandler.HasEventHandler(),
|
||||
"Must have one or the other!");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
uint32_t eventType = nsContentUtils::GetEventId(aName);
|
||||
@ -538,53 +538,23 @@ nsEventListenerManager::SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
if (!ls) {
|
||||
// If we didn't find a script listener or no listeners existed
|
||||
// create and add a new one.
|
||||
const uint32_t flags = NS_EVENT_FLAG_BUBBLE |
|
||||
(aContext ? NS_PRIV_EVENT_FLAG_SCRIPT : 0);
|
||||
nsCOMPtr<nsIDOMEventListener> listener;
|
||||
const uint32_t flags = NS_EVENT_FLAG_BUBBLE | NS_PRIV_EVENT_FLAG_SCRIPT;
|
||||
|
||||
if (aContext) {
|
||||
nsCOMPtr<nsIJSEventListener> scriptListener;
|
||||
rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
|
||||
aHandler, getter_AddRefs(scriptListener));
|
||||
listener = scriptListener.forget();
|
||||
} else {
|
||||
// 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.Ptr()->Callable(),
|
||||
NS_GET_IID(nsIDOMEventListener),
|
||||
getter_AddRefs(listener));
|
||||
}
|
||||
nsCOMPtr<nsIJSEventListener> scriptListener;
|
||||
rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName,
|
||||
aHandler, getter_AddRefs(scriptListener));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
AddEventListener(listener, eventType, aName, flags, true);
|
||||
AddEventListener(scriptListener, eventType, aName, flags, true);
|
||||
|
||||
ls = FindEventHandler(eventType, aName);
|
||||
}
|
||||
} else {
|
||||
// Don't mix 'real' JS event handlers and 'fake' JS event handlers.
|
||||
nsIJSEventListener* scriptListener = ls->GetJSListener();
|
||||
MOZ_ASSERT(scriptListener,
|
||||
"How can we have an event handler with no nsIJSEventListener?");
|
||||
|
||||
if ((!aContext && scriptListener) ||
|
||||
(aContext && !scriptListener)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (scriptListener) {
|
||||
scriptListener->SetHandler(aHandler);
|
||||
} else {
|
||||
MOZ_ASSERT(aHandler.HasEventHandler());
|
||||
nsCOMPtr<nsIDOMEventListener> listener;
|
||||
rv = nsContentUtils::XPConnect()->WrapJS(aCx,
|
||||
aHandler.Ptr()->Callable(),
|
||||
NS_GET_IID(nsIDOMEventListener),
|
||||
getter_AddRefs(listener));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
ls->mListener = listener.forget();
|
||||
}
|
||||
}
|
||||
scriptListener->SetHandler(aHandler, aContext, aScopeObject);
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv) && ls) {
|
||||
@ -710,7 +680,7 @@ nsEventListenerManager::SetEventHandler(nsIAtom *aName,
|
||||
JSObject* scope = global->GetGlobalJSObject();
|
||||
|
||||
nsListenerStruct *ls;
|
||||
rv = SetEventHandlerInternal(context, nullptr, scope, aName, nsEventHandler(),
|
||||
rv = SetEventHandlerInternal(context, scope, aName, nsEventHandler(),
|
||||
aPermitUntrustedEvents, &ls);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -1194,8 +1164,7 @@ nsresult
|
||||
nsEventListenerManager::SetEventHandlerToJsval(nsIAtom* aEventName,
|
||||
JSContext* cx,
|
||||
JSObject* aScope,
|
||||
const jsval& v,
|
||||
bool aExpectScriptContext)
|
||||
const jsval& v)
|
||||
{
|
||||
JSObject *callable;
|
||||
if (JSVAL_IS_PRIMITIVE(v) ||
|
||||
@ -1234,17 +1203,12 @@ nsEventListenerManager::SetEventHandlerToJsval(nsIAtom* aEventName,
|
||||
handler.SetHandler(handlerCallback);
|
||||
}
|
||||
|
||||
// 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.
|
||||
nsListenerStruct *ignored;
|
||||
return SetEventHandlerInternal(context, cx, scope, aEventName, handler,
|
||||
return SetEventHandlerInternal(nullptr, scope, aEventName, handler,
|
||||
!nsContentUtils::IsCallerChrome(), &ignored);
|
||||
}
|
||||
|
||||
|
@ -263,11 +263,11 @@ protected:
|
||||
/**
|
||||
* 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.
|
||||
* compile the string for this listener, but in that case aContext must be
|
||||
* non-null. Otherwise, aContext is allowed to be null. The nsListenerStruct
|
||||
* that results, if any, is returned in aListenerStruct.
|
||||
*/
|
||||
nsresult SetEventHandlerInternal(nsIScriptContext *aContext,
|
||||
JSContext* aCx,
|
||||
JSObject* aScopeGlobal,
|
||||
nsIAtom* aName,
|
||||
const nsEventHandler& aHandler,
|
||||
@ -284,12 +284,10 @@ public:
|
||||
* 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. If aExpectScriptContext is false,
|
||||
* not finding an nsIScriptContext does not cause failure.
|
||||
* be in the same compartment.
|
||||
*/
|
||||
nsresult SetEventHandlerToJsval(nsIAtom* aEventName, JSContext* cx,
|
||||
JSObject* aScope, const jsval& v,
|
||||
bool aExpectScriptContext);
|
||||
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.
|
||||
|
@ -309,7 +309,7 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventTarget* aTarget,
|
||||
|
||||
// Execute it.
|
||||
nsCOMPtr<nsIJSEventListener> eventListener;
|
||||
rv = NS_NewJSEventListener(boundContext, scope,
|
||||
rv = NS_NewJSEventListener(nullptr, scope,
|
||||
scriptTarget, onEventAtom,
|
||||
eventHandler,
|
||||
getter_AddRefs(eventListener));
|
||||
|
@ -11209,8 +11209,7 @@ nsGlobalWindow::DisableNetworkEvent(uint32_t aType)
|
||||
if (!obj) { \
|
||||
return NS_ERROR_UNEXPECTED; \
|
||||
} \
|
||||
return elm->SetEventHandlerToJsval(nsGkAtoms::on##name_, cx, obj, v, \
|
||||
true); \
|
||||
return elm->SetEventHandlerToJsval(nsGkAtoms::on##name_, cx, obj, v); \
|
||||
}
|
||||
#define WINDOW_ONLY_EVENT EVENT
|
||||
#define TOUCH_EVENT EVENT
|
||||
|
@ -176,6 +176,7 @@ public:
|
||||
mTarget = base.get();
|
||||
}
|
||||
|
||||
// Can return null if we already have a handler.
|
||||
nsIScriptContext *GetEventContext() const
|
||||
{
|
||||
return mContext;
|
||||
@ -208,9 +209,12 @@ public:
|
||||
|
||||
// Set a handler for this event listener. The handler must already
|
||||
// be bound to the right target.
|
||||
void SetHandler(const nsEventHandler& aHandler)
|
||||
void SetHandler(const nsEventHandler& aHandler, nsIScriptContext* aContext,
|
||||
JSObject* aScopeObject)
|
||||
{
|
||||
mHandler.SetHandler(aHandler);
|
||||
mContext = aContext;
|
||||
mScopeObject = aScopeObject;
|
||||
}
|
||||
void SetHandler(mozilla::dom::EventHandlerNonNull* aHandler)
|
||||
{
|
||||
@ -260,7 +264,9 @@ protected:
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIJSEventListener, NS_IJSEVENTLISTENER_IID)
|
||||
|
||||
/* factory function. aHandler must already be bound to aTarget */
|
||||
/* factory function. aHandler must already be bound to aTarget.
|
||||
aContext is allowed to be null if aHandler is already set up.
|
||||
*/
|
||||
nsresult NS_NewJSEventListener(nsIScriptContext *aContext,
|
||||
JSObject* aScopeObject, nsISupports* aTarget,
|
||||
nsIAtom* aType, const nsEventHandler& aHandler,
|
||||
|
@ -55,21 +55,21 @@ nsJSEventListener::nsJSEventListener(nsIScriptContext *aContext,
|
||||
{
|
||||
// aScopeObject is the inner window's JS object, which we need to lock
|
||||
// until we are done with it.
|
||||
NS_ASSERTION(aScopeObject && aContext,
|
||||
NS_ASSERTION(aScopeObject,
|
||||
"EventListener with no context or scope?");
|
||||
NS_HOLD_JS_OBJECTS(this, nsJSEventListener);
|
||||
}
|
||||
|
||||
nsJSEventListener::~nsJSEventListener()
|
||||
{
|
||||
if (mContext) {
|
||||
if (mScopeObject) {
|
||||
NS_DROP_JS_OBJECTS(this, nsJSEventListener);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(nsJSEventListener)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsJSEventListener)
|
||||
if (tmp->mContext) {
|
||||
if (tmp->mScopeObject) {
|
||||
NS_DROP_JS_OBJECTS(tmp, nsJSEventListener);
|
||||
tmp->mScopeObject = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mContext)
|
||||
@ -134,10 +134,15 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsJSEventListener)
|
||||
bool
|
||||
nsJSEventListener::IsBlackForCC()
|
||||
{
|
||||
if (mContext &&
|
||||
(!mScopeObject || !xpc_IsGrayGCThing(mScopeObject)) &&
|
||||
// We can claim to be black if all the things we reference are
|
||||
// effectively black already.
|
||||
if ((!mScopeObject || !xpc_IsGrayGCThing(mScopeObject)) &&
|
||||
(!mHandler.HasEventHandler() ||
|
||||
!mHandler.Ptr()->HasGrayCallable())) {
|
||||
if (!mContext) {
|
||||
// Well, we certainly won't be marking it, so move on!
|
||||
return true;
|
||||
}
|
||||
nsIScriptGlobalObject* sgo =
|
||||
static_cast<nsJSContext*>(mContext.get())->GetCachedGlobalObject();
|
||||
return sgo && sgo->IsBlackForCC();
|
||||
@ -149,7 +154,7 @@ nsresult
|
||||
nsJSEventListener::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mTarget);
|
||||
if (!target || !mContext || !mHandler.HasEventHandler())
|
||||
if (!target || !mHandler.HasEventHandler())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mHandler.Type() == nsEventHandler::eOnError) {
|
||||
@ -256,6 +261,8 @@ NS_NewJSEventListener(nsIScriptContext* aContext, JSObject* aScopeObject,
|
||||
const nsEventHandler& aHandler,
|
||||
nsIJSEventListener** aReturn)
|
||||
{
|
||||
MOZ_ASSERT(aContext || aHandler.HasEventHandler(),
|
||||
"Must have a handler if we don't have an nsIScriptContext");
|
||||
NS_ENSURE_ARG(aEventType);
|
||||
nsJSEventListener* it =
|
||||
new nsJSEventListener(aContext, aScopeObject, aTarget, aEventType,
|
||||
|
Loading…
Reference in New Issue
Block a user