Bug 1180798 - Pass event names in nsIEventListenerChangeListener r=smaug

This commit is contained in:
Lorien Hu 2015-07-17 11:07:37 -04:00
parent dfc1421bdb
commit f16760445c
5 changed files with 143 additions and 32 deletions

View File

@ -398,7 +398,8 @@ EventListenerManager::AddEventListenerInternal(
}
if (mIsMainThreadELM && mTarget) {
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
aTypeAtom);
}
}
@ -518,7 +519,8 @@ EventListenerManager::RemoveEventListenerInternal(
mTarget->EventListenerRemoved(aUserType);
}
if (mIsMainThreadELM && mTarget) {
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget,
aUserType);
}
if (!deviceType
@ -654,7 +656,7 @@ EventListenerManager::SetEventHandlerInternal(
mTarget->EventListenerAdded(aName);
}
if (mIsMainThreadELM && mTarget) {
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget, aName);
}
}
@ -784,7 +786,7 @@ EventListenerManager::RemoveEventHandler(nsIAtom* aName,
mTarget->EventListenerRemoved(aName);
}
if (mIsMainThreadELM && mTarget) {
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget, aName);
}
}
}

View File

@ -23,6 +23,44 @@ namespace mozilla {
using namespace dom;
/******************************************************************************
* mozilla::EventListenerChange
******************************************************************************/
NS_IMPL_ISUPPORTS(EventListenerChange, nsIEventListenerChange)
EventListenerChange::~EventListenerChange()
{
}
EventListenerChange::EventListenerChange(dom::EventTarget* aTarget) :
mTarget(aTarget)
{
mChangedListenerNames = nsArrayBase::Create();
}
void
EventListenerChange::AddChangedListenerName(nsIAtom* aEventName)
{
mChangedListenerNames->AppendElement(aEventName, false);
}
NS_IMETHODIMP
EventListenerChange::GetTarget(nsIDOMEventTarget** aTarget)
{
NS_ENSURE_ARG_POINTER(aTarget);
NS_ADDREF(*aTarget = mTarget);
return NS_OK;
}
NS_IMETHODIMP
EventListenerChange::GetChangedListenerNames(nsIArray** aEventNames)
{
NS_ENSURE_ARG_POINTER(aEventNames);
NS_ADDREF(*aEventNames = mChangedListenerNames);
return NS_OK;
}
/******************************************************************************
* mozilla::EventListenerInfo
******************************************************************************/
@ -323,7 +361,8 @@ EventListenerService::RemoveListenerChangeListener(nsIListenerChangeListener* aL
};
void
EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget)
EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget,
nsIAtom* aName)
{
MOZ_ASSERT(NS_IsMainThread());
if (mChangeListeners.IsEmpty()) {
@ -337,10 +376,13 @@ EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarg
NS_DispatchToCurrentThread(runnable);
}
if (!mPendingListenerChangesSet.Get(aTarget)) {
mPendingListenerChanges->AppendElement(aTarget, false);
mPendingListenerChangesSet.Put(aTarget, true);
nsRefPtr<EventListenerChange> changes = mPendingListenerChangesSet.Get(aTarget);
if (!changes) {
changes = new EventListenerChange(aTarget);
mPendingListenerChanges->AppendElement(changes, false);
mPendingListenerChangesSet.Put(aTarget, changes);
}
changes->AddChangedListenerName(aName);
}
void

View File

@ -16,6 +16,7 @@
#include "nsString.h"
#include "nsTObserverArray.h"
#include "nsDataHashtable.h"
#include "nsGkAtoms.h"
class nsIMutableArray;
@ -27,6 +28,23 @@ class EventTarget;
template<typename T>
class Maybe;
class EventListenerChange final : public nsIEventListenerChange
{
public:
explicit EventListenerChange(dom::EventTarget* aTarget);
void AddChangedListenerName(nsIAtom* aEventName);
NS_DECL_ISUPPORTS
NS_DECL_NSIEVENTLISTENERCHANGE
protected:
virtual ~EventListenerChange();
nsCOMPtr<dom::EventTarget> mTarget;
nsCOMPtr<nsIMutableArray> mChangedListenerNames;
};
class EventListenerInfo final : public nsIEventListenerInfo
{
public:
@ -70,19 +88,21 @@ public:
NS_DECL_ISUPPORTS
NS_DECL_NSIEVENTLISTENERSERVICE
static void NotifyAboutMainThreadListenerChange(dom::EventTarget* aTarget)
static void NotifyAboutMainThreadListenerChange(dom::EventTarget* aTarget,
nsIAtom* aName)
{
if (sInstance) {
sInstance->NotifyAboutMainThreadListenerChangeInternal(aTarget);
sInstance->NotifyAboutMainThreadListenerChangeInternal(aTarget, aName);
}
}
void NotifyPendingChanges();
private:
void NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget);
void NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget,
nsIAtom* aName);
nsTObserverArray<nsCOMPtr<nsIListenerChangeListener>> mChangeListeners;
nsCOMPtr<nsIMutableArray> mPendingListenerChanges;
nsDataHashtable<nsISupportsHashKey, bool> mPendingListenerChangesSet;
nsDataHashtable<nsISupportsHashKey, nsRefPtr<EventListenerChange>> mPendingListenerChangesSet;
static EventListenerService* sInstance;
};

View File

@ -9,10 +9,21 @@ interface nsIDOMEventListener;
interface nsIDOMEventTarget;
interface nsIArray;
[scriptable, function, uuid(8d5b5a6b-dec0-473d-86c4-591801dfaac1)]
/**
* Contains an event target along with an array of nsIAtom in form "oneventname"
* representing changed event listener names.
*/
[scriptable, uuid(07222b02-da12-4cf4-b2f7-761da007a8d8)]
interface nsIEventListenerChange : nsISupports
{
readonly attribute nsIDOMEventTarget target;
readonly attribute nsIArray changedListenerNames;
};
[scriptable, function, uuid(aa7c95f6-d3b5-44b3-9597-1d9f19b9c5f2)]
interface nsIListenerChangeListener : nsISupports
{
void listenersChanged(in nsIArray aEventTargets);
void listenersChanged(in nsIArray aEventListenerChanges);
};
/**

View File

@ -22,6 +22,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=524674
var els = Components.classes["@mozilla.org/eventlistenerservice;1"]
.getService(Components.interfaces.nsIEventListenerService);
const Ci = Components.interfaces;
function dummyListener() {}
var runningTest = null;
@ -35,29 +37,49 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=524674
d.addEventListener("foo", dummyListener);
d.addEventListener("foo", dummyListener);
xhr.addEventListener("foo", dummyListener);
tests[0] = [d, xhr];
tests[0] = [{target: d, listeners: ["onfoo"]},
{target: xhr, listeners: ["onfoo"]}];
},
function() {
d.addEventListener("bar", dummyListener);
d.addEventListener("baz", dummyListener);
xhr.addEventListener("bar", dummyListener);
xhr.addEventListener("baz", dummyListener);
tests[0] = [{target: d, listeners: ["onbaz", "onbar"]},
{target: xhr, listeners: ["onbaz", "onbar"]}];
},
function() {
d.onclick = dummyListener;
d.onclick = dummyListener;
xhr.onload = dummyListener;
tests[0] = [d, xhr];
tests[0] = [{target: d, listeners: ["onclick"]},
{target: xhr, listeners: ["onload"]}];
},
function() {
d.onclick = function() {};
tests[0] = [d];
tests[0] = [{target: d, listeners: ["onclick"]}];
},
function() {
d.removeEventListener("foo", dummyListener);
d.removeEventListener("foo", dummyListener);
xhr.removeEventListener("foo", dummyListener);
tests[0] = [d, xhr];
tests[0] = [{target: d, listeners: ["onfoo"]},
{target: xhr, listeners: ["onfoo"]}];
},
function() {
d.removeEventListener("bar", dummyListener);
d.removeEventListener("baz", dummyListener);
xhr.removeEventListener("bar", dummyListener);
xhr.removeEventListener("baz", dummyListener);
tests[0] = [{target: d, listeners: ["onbar", "onbaz"]},
{target: xhr, listeners: ["onbar", "onbaz"]}];
},
function() {
d.onclick = null;
d.onclick = null;
xhr.onload = null;
tests[0] = [d, xhr];
tests[0] = [{target: d, listeners: ["onclick"]},
{target: xhr, listeners: ["onload"]}];
},
function() {
els.removeListenerChangeListener(changeListener);
@ -76,29 +98,43 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=524674
if (typeof tests[0] == "function") {
return;
}
var expectedEventTargets = tests[0];
var e = array.enumerate();
var expectedEventChanges = tests[0];
var eventChanges = array.enumerate();
var i = 0;
while (e.hasMoreElements()) {
while (eventChanges.hasMoreElements() && i < expectedEventChanges.length) {
var current;
try {
current = e.getNext();
current = eventChanges.getNext().QueryInterface(Ci.nsIEventListenerChange);
var expected = expectedEventChanges[i];
if (current.target == expected.target) {
// expected.target.listeners should be a subset of
// current.changedListenerNames if all expected listener changes were
// sent. We may get random other event listener changes here too, not
// just the one from the test.
is(current.target, expected.target, current.target + " = " + expected.target);
var eNames = current.changedListenerNames.enumerate();
var listeners = [];
while (eNames.hasMoreElements()) {
var listenerName = eNames.getNext().QueryInterface(Ci.nsIAtom).toString();
listeners.push(listenerName);
}
var matchAll = expected.listeners.every(function(val)
{ return listeners.indexOf(val) >= 0; });
if (!matchAll)
return;
++i;
}
} catch(ex) {
continue;
}
var expected = expectedEventTargets[i];
if (current == expected) {
is(current, expected, current + " = " + expected);
// We may get random other event listener changes here too, not just the one from the
// test.
++i
}
}
if (expectedEventTargets.length != i) {
if (expectedEventChanges.length != i) {
return;
}
is(expectedEventTargets.length, i, "Should have got notification for all the changes.");
is(expectedEventChanges.length, i, "Should have got notification for all the changes.");
tests.shift();
ok(tests.length);