mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 524674, nsIEventListenerService: tracking of dynamically added and removed event listeners, r=masayuki
This commit is contained in:
parent
d632609013
commit
5532b3f7f9
@ -379,6 +379,10 @@ EventListenerManager::AddEventListenerInternal(
|
||||
if (aTypeAtom && mTarget) {
|
||||
mTarget->EventListenerAdded(aTypeAtom);
|
||||
}
|
||||
|
||||
if (mIsMainThreadELM && mTarget) {
|
||||
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@ -496,6 +500,9 @@ EventListenerManager::RemoveEventListenerInternal(
|
||||
if (mTarget && aUserType) {
|
||||
mTarget->EventListenerRemoved(aUserType);
|
||||
}
|
||||
if (mIsMainThreadELM && mTarget) {
|
||||
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
|
||||
}
|
||||
|
||||
if (!deviceType
|
||||
#ifdef MOZ_B2G
|
||||
@ -629,6 +636,9 @@ EventListenerManager::SetEventHandlerInternal(
|
||||
mTarget->EventListenerRemoved(aName);
|
||||
mTarget->EventListenerAdded(aName);
|
||||
}
|
||||
if (mIsMainThreadELM && mTarget) {
|
||||
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// Set flag to indicate possible need for compilation later
|
||||
@ -756,6 +766,9 @@ EventListenerManager::RemoveEventHandler(nsIAtom* aName,
|
||||
if (mTarget && aName) {
|
||||
mTarget->EventListenerRemoved(aName);
|
||||
}
|
||||
if (mIsMainThreadELM && mTarget) {
|
||||
EventListenerService::NotifyAboutMainThreadListenerChange(mTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -127,6 +129,21 @@ EventListenerInfo::ToSource(nsAString& aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
EventListenerService*
|
||||
EventListenerService::sInstance = nullptr;
|
||||
|
||||
EventListenerService::EventListenerService()
|
||||
{
|
||||
MOZ_ASSERT(!sInstance);
|
||||
sInstance = this;
|
||||
}
|
||||
|
||||
EventListenerService::~EventListenerService()
|
||||
{
|
||||
MOZ_ASSERT(sInstance == this);
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
EventListenerService::GetListenerInfoFor(nsIDOMEventTarget* aEventTarget,
|
||||
uint32_t* aCount,
|
||||
@ -288,6 +305,58 @@ EventListenerService::RemoveListenerForAllEvents(nsIDOMEventTarget* aTarget,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
EventListenerService::AddListenerChangeListener(nsIListenerChangeListener* aListener)
|
||||
{
|
||||
if (!mChangeListeners.Contains(aListener)) {
|
||||
mChangeListeners.AppendElement(aListener);
|
||||
}
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
EventListenerService::RemoveListenerChangeListener(nsIListenerChangeListener* aListener)
|
||||
{
|
||||
mChangeListeners.RemoveElement(aListener);
|
||||
return NS_OK;
|
||||
};
|
||||
|
||||
void
|
||||
EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mChangeListeners.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mPendingListenerChanges) {
|
||||
mPendingListenerChanges = nsArrayBase::Create();
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableMethod(this,
|
||||
&EventListenerService::NotifyPendingChanges);
|
||||
NS_DispatchToCurrentThread(runnable);
|
||||
}
|
||||
|
||||
if (!mPendingListenerChangesSet.Get(aTarget)) {
|
||||
mPendingListenerChanges->AppendElement(aTarget, false);
|
||||
mPendingListenerChangesSet.Put(aTarget, true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventListenerService::NotifyPendingChanges()
|
||||
{
|
||||
nsCOMPtr<nsIMutableArray> changes;
|
||||
mPendingListenerChanges.swap(changes);
|
||||
mPendingListenerChangesSet.Clear();
|
||||
|
||||
nsTObserverArray<nsCOMPtr<nsIListenerChangeListener>>::EndLimitedIterator
|
||||
iter(mChangeListeners);
|
||||
while (iter.HasMore()) {
|
||||
nsCOMPtr<nsIListenerChangeListener> listener = iter.GetNext();
|
||||
listener->ListenersChanged(changes);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
nsresult
|
||||
|
@ -13,8 +13,15 @@
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIEventListenerService.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
class nsIMutableArray;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class EventTarget;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Maybe;
|
||||
@ -56,10 +63,27 @@ protected:
|
||||
|
||||
class EventListenerService final : public nsIEventListenerService
|
||||
{
|
||||
~EventListenerService() {}
|
||||
~EventListenerService();
|
||||
public:
|
||||
EventListenerService();
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIEVENTLISTENERSERVICE
|
||||
|
||||
static void NotifyAboutMainThreadListenerChange(dom::EventTarget* aTarget)
|
||||
{
|
||||
if (sInstance) {
|
||||
sInstance->NotifyAboutMainThreadListenerChangeInternal(aTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyPendingChanges();
|
||||
private:
|
||||
void NotifyAboutMainThreadListenerChangeInternal(dom::EventTarget* aTarget);
|
||||
nsTObserverArray<nsCOMPtr<nsIListenerChangeListener>> mChangeListeners;
|
||||
nsCOMPtr<nsIMutableArray> mPendingListenerChanges;
|
||||
nsDataHashtable<nsISupportsHashKey, bool> mPendingListenerChangesSet;
|
||||
|
||||
static EventListenerService* sInstance;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -7,6 +7,13 @@
|
||||
|
||||
interface nsIDOMEventListener;
|
||||
interface nsIDOMEventTarget;
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, function, uuid(8d5b5a6b-dec0-473d-86c4-591801dfaac1)]
|
||||
interface nsIListenerChangeListener : nsISupports
|
||||
{
|
||||
void listenersChanged(in nsIArray aEventTargets);
|
||||
};
|
||||
|
||||
/**
|
||||
* An instance of this interface describes how an event listener
|
||||
@ -39,7 +46,7 @@ interface nsIEventListenerInfo : nsISupports
|
||||
AString toSource();
|
||||
};
|
||||
|
||||
[scriptable, uuid(f6964bfb-dabe-4cab-9733-be0ee2bf8171)]
|
||||
[scriptable, uuid(77aab5f7-213d-4db4-9f22-e46dfb774f15)]
|
||||
interface nsIEventListenerService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -96,5 +103,8 @@ interface nsIEventListenerService : nsISupports
|
||||
in nsIDOMEventListener listener,
|
||||
[optional] in boolean aUseCapture,
|
||||
[optional] in boolean aSystemEventGroup);
|
||||
|
||||
void addListenerChangeListener(in nsIListenerChangeListener aListener);
|
||||
void removeListenerChangeListener(in nsIListenerChangeListener aListener);
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@ support-files =
|
||||
[test_bug336682_2.xul]
|
||||
[test_bug368835.html]
|
||||
[test_bug415498.xul]
|
||||
[test_bug524674.xul]
|
||||
[test_bug586961.xul]
|
||||
[test_bug591249.xul]
|
||||
[test_bug602962.xul]
|
||||
|
106
dom/events/test/test_bug524674.xul
Normal file
106
dom/events/test/test_bug524674.xul
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=524674
|
||||
-->
|
||||
<window title="Mozilla Bug 524674"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=524674"
|
||||
target="_blank">Mozilla Bug 524674</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/** Test for Bug 524674 **/
|
||||
|
||||
var els = Components.classes["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Components.interfaces.nsIEventListenerService);
|
||||
|
||||
function dummyListener() {}
|
||||
|
||||
var runningTest = null;
|
||||
var d = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
// Test also double removals and such.
|
||||
var tests = [
|
||||
function() {
|
||||
els.addListenerChangeListener(changeListener);
|
||||
d.addEventListener("foo", dummyListener);
|
||||
d.addEventListener("foo", dummyListener);
|
||||
xhr.addEventListener("foo", dummyListener);
|
||||
tests[0] = [d, xhr];
|
||||
},
|
||||
function() {
|
||||
d.onclick = dummyListener;
|
||||
d.onclick = dummyListener;
|
||||
xhr.onload = dummyListener;
|
||||
tests[0] = [d, xhr];
|
||||
},
|
||||
function() {
|
||||
d.onclick = function() {};
|
||||
tests[0] = [d];
|
||||
},
|
||||
function() {
|
||||
d.removeEventListener("foo", dummyListener);
|
||||
d.removeEventListener("foo", dummyListener);
|
||||
xhr.removeEventListener("foo", dummyListener);
|
||||
tests[0] = [d, xhr];
|
||||
},
|
||||
function() {
|
||||
d.onclick = null;
|
||||
d.onclick = null;
|
||||
xhr.onload = null;
|
||||
tests[0] = [d, xhr];
|
||||
},
|
||||
function() {
|
||||
els.removeListenerChangeListener(changeListener);
|
||||
// Check that once we've removed the change listener, it isn't called anymore.
|
||||
d.addEventListener("foo", dummyListener);
|
||||
xhr.addEventListener("foo", dummyListener);
|
||||
SimpleTest.executeSoon(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
SimpleTest.executeSoon(tests[0]);
|
||||
|
||||
function changeListener(array) {
|
||||
if (typeof tests[0] == "function") {
|
||||
return;
|
||||
}
|
||||
var expectedEventTargets = tests[0];
|
||||
var e = array.enumerate();
|
||||
var i = 0;
|
||||
while (e.hasMoreElements()) {
|
||||
var current = e.getNext();
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
is(expectedEventTargets.length, i, "Should have got notification for all the changes.");
|
||||
tests.shift();
|
||||
|
||||
ok(tests.length);
|
||||
SimpleTest.executeSoon(tests[0]);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
Loading…
Reference in New Issue
Block a user