mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-11 18:24:02 +00:00
Use iterators that deal with observers being removed to iterate the observers array when notifying Bug 340733, r+sr+branch181=sicking
This commit is contained in:
parent
8d743fde46
commit
f552f1c839
@ -631,6 +631,73 @@ nsDOMImplementation::Init(nsIURI* aDocumentURI, nsIURI* aBaseURI,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsDocumentObserverList::PrependElement(nsIDocumentObserver* aObserver)
|
||||||
|
{
|
||||||
|
PRBool prepended = mObservers.InsertElementAt(aObserver, 0);
|
||||||
|
|
||||||
|
// This introduces an inconsistency -- forward iterators will not see the new
|
||||||
|
// element, while backwards ones will. That's kinda inherent in the
|
||||||
|
// different iteration orders, though.
|
||||||
|
if (prepended) {
|
||||||
|
for (Iterator* iter = mIterators; iter; iter = iter->mNext) {
|
||||||
|
iter->mPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prepended;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
nsDocumentObserverList::RemoveElement(nsIDocumentObserver* aElement)
|
||||||
|
{
|
||||||
|
PRInt32 index = mObservers.IndexOf(aElement);
|
||||||
|
if (index == -1) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
PRBool removed =
|
||||||
|
#endif
|
||||||
|
mObservers.RemoveElementAt(index);
|
||||||
|
NS_ASSERTION(removed, "How could we fail to remove by index?");
|
||||||
|
|
||||||
|
for (Iterator* iter = mIterators; iter; iter = iter->mNext) {
|
||||||
|
// If iter->mPosition == index then forward iterators are safe, since in
|
||||||
|
// that case the position is not affected by the removal; all that's
|
||||||
|
// affected is what element is at that position. Backward iterators,
|
||||||
|
// however, need to decrement mPosition in that case.
|
||||||
|
if (iter->mPosition > index ||
|
||||||
|
(iter->mPosition == index && iter->mStep < 0)) {
|
||||||
|
iter->mPosition--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsDocumentObserverList::Clear()
|
||||||
|
{
|
||||||
|
mObservers.Clear();
|
||||||
|
|
||||||
|
// Reset all iterators to a bogus position so they don't return
|
||||||
|
// anything next time they're called.
|
||||||
|
for (Iterator* iter = mIterators; iter; iter = iter->mNext) {
|
||||||
|
iter->mPosition = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsIDocumentObserver*
|
||||||
|
nsDocumentObserverList::Iterator::GetNext()
|
||||||
|
{
|
||||||
|
nsIDocumentObserver* ret =
|
||||||
|
NS_STATIC_CAST(nsIDocumentObserver*,
|
||||||
|
mList.mObservers.SafeElementAt(mPosition));
|
||||||
|
mPosition += mStep;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// =
|
// =
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
@ -826,8 +893,7 @@ nsDocument::Init()
|
|||||||
mBindingManager = bindingManager;
|
mBindingManager = bindingManager;
|
||||||
|
|
||||||
// The binding manager must always be the first observer of the document.
|
// The binding manager must always be the first observer of the document.
|
||||||
// (static cast to the correct interface pointer)
|
mObservers.PrependElement(bindingManager);
|
||||||
mObservers.InsertElementAt(NS_STATIC_CAST(nsIDocumentObserver*, bindingManager), 0);
|
|
||||||
|
|
||||||
mOnloadBlocker = new nsOnloadBlocker();
|
mOnloadBlocker = new nsOnloadBlocker();
|
||||||
NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
|
NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
|
||||||
@ -2113,7 +2179,7 @@ void
|
|||||||
nsDocument::AddObserver(nsIDocumentObserver* aObserver)
|
nsDocument::AddObserver(nsIDocumentObserver* aObserver)
|
||||||
{
|
{
|
||||||
// XXX Make sure the observer isn't already in the list
|
// XXX Make sure the observer isn't already in the list
|
||||||
if (mObservers.IndexOf(aObserver) == -1) {
|
if (!mObservers.Contains(aObserver)) {
|
||||||
mObservers.AppendElement(aObserver);
|
mObservers.AppendElement(aObserver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2129,22 +2195,9 @@ nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
|
|||||||
return mObservers.RemoveElement(aObserver);
|
return mObservers.RemoveElement(aObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (mObservers.IndexOf(aObserver) != -1);
|
return mObservers.Contains(aObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
nsDocument::CopyObserversTo(nsCOMArray<nsIDocumentObserver>& aDestination)
|
|
||||||
{
|
|
||||||
PRInt32 count = mObservers.Count();
|
|
||||||
aDestination.SetCapacity(count);
|
|
||||||
// If we run out of memory, we just won't notify some of the observers.
|
|
||||||
for (PRInt32 i = 0; i < count; ++i) {
|
|
||||||
aDestination.AppendObject(
|
|
||||||
NS_STATIC_CAST(nsIDocumentObserver*,mObservers[i]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsDocument::BeginUpdate(nsUpdateType aUpdateType)
|
nsDocument::BeginUpdate(nsUpdateType aUpdateType)
|
||||||
{
|
{
|
||||||
@ -2325,11 +2378,9 @@ nsDocument::ContentAppended(nsIContent* aContainer,
|
|||||||
// observer list in a forward order
|
// observer list in a forward order
|
||||||
// XXXldb So one should notify the other rather than both being
|
// XXXldb So one should notify the other rather than both being
|
||||||
// registered.
|
// registered.
|
||||||
nsCOMArray<nsIDocumentObserver> observers;
|
NS_DOCUMENT_FORWARD_NOTIFY_OBSERVERS(ContentAppended,
|
||||||
CopyObserversTo(observers);
|
(this, aContainer,
|
||||||
for (PRInt32 i = 0, i_end = observers.Count(); i < i_end; ++i) {
|
aNewIndexInContainer));
|
||||||
observers[i]->ContentAppended(this, aContainer, aNewIndexInContainer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2343,11 +2394,9 @@ nsDocument::ContentInserted(nsIContent* aContainer, nsIContent* aChild,
|
|||||||
// in a forward order
|
// in a forward order
|
||||||
// XXXldb So one should notify the other rather than both being
|
// XXXldb So one should notify the other rather than both being
|
||||||
// registered.
|
// registered.
|
||||||
nsCOMArray<nsIDocumentObserver> observers;
|
NS_DOCUMENT_FORWARD_NOTIFY_OBSERVERS(ContentInserted,
|
||||||
CopyObserversTo(observers);
|
(this, aContainer, aChild,
|
||||||
for (PRInt32 i = 0, i_end = observers.Count(); i < i_end; ++i) {
|
aIndexInContainer));
|
||||||
observers[i]->ContentInserted(this, aContainer, aChild, aIndexInContainer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2361,11 +2410,8 @@ nsDocument::ContentRemoved(nsIContent* aContainer, nsIContent* aChild,
|
|||||||
// observer list in a reverse order
|
// observer list in a reverse order
|
||||||
// XXXldb So one should notify the other rather than both being
|
// XXXldb So one should notify the other rather than both being
|
||||||
// registered.
|
// registered.
|
||||||
nsCOMArray<nsIDocumentObserver> observers;
|
NS_DOCUMENT_NOTIFY_OBSERVERS(ContentRemoved,
|
||||||
CopyObserversTo(observers);
|
(this, aContainer, aChild, aIndexInContainer));
|
||||||
for (PRInt32 i = observers.Count() - 1; i >= 0; --i) {
|
|
||||||
observers[i]->ContentRemoved(this, aContainer, aChild, aIndexInContainer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -262,6 +262,94 @@ private:
|
|||||||
~nsOnloadBlocker() {}
|
~nsOnloadBlocker() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nsDocumentObserverList is the list of nsIDocumentObservers for a document.
|
||||||
|
* It doesn't allow direct reading of the list; all access must take place
|
||||||
|
* through stack-allocated nsDocumentObserverList::ForwardIterator or
|
||||||
|
* nsDocumentObserverList::ReverseIterator objects.
|
||||||
|
*/
|
||||||
|
class nsDocumentObserverList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nsDocumentObserverList() :
|
||||||
|
mIterators(nsnull)
|
||||||
|
{}
|
||||||
|
|
||||||
|
class Iterator;
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
nsIDocumentObserver* GetNext();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Iterator(PRInt32 aStep, nsDocumentObserverList& aList) :
|
||||||
|
mPosition(aStep > 0 ? 0 : aList.mObservers.Count() - 1),
|
||||||
|
mStep(aStep),
|
||||||
|
mList(aList),
|
||||||
|
mNext(aList.mIterators)
|
||||||
|
{
|
||||||
|
NS_ASSERTION(mStep == 1 || mStep == -1, "Invalid step size");
|
||||||
|
aList.mIterators = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Iterator() {
|
||||||
|
NS_ASSERTION(mList.mIterators == this, "Destroyed out of order?");
|
||||||
|
mList.mIterators = mNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend class nsDocumentObserverList;
|
||||||
|
|
||||||
|
// Our current position in mObservers
|
||||||
|
PRInt32 mPosition;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Which direction to move in
|
||||||
|
PRInt32 mStep;
|
||||||
|
|
||||||
|
// The observer array to work with
|
||||||
|
nsDocumentObserverList& mList;
|
||||||
|
|
||||||
|
// Our next iterator.
|
||||||
|
Iterator* mNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ForwardIterator : public Iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ForwardIterator(nsDocumentObserverList& aList) :
|
||||||
|
Iterator(1, aList)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ReverseIterator : public Iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ReverseIterator(nsDocumentObserverList& aList) :
|
||||||
|
Iterator(-1, aList)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
PRBool PrependElement(nsIDocumentObserver* aObserver);
|
||||||
|
|
||||||
|
PRInt32 Contains(nsIDocumentObserver* aPossibleObserver) const {
|
||||||
|
return mObservers.IndexOf(aPossibleObserver) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool AppendElement(nsIDocumentObserver* aElement) {
|
||||||
|
return mObservers.AppendElement(aElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool RemoveElement(nsIDocumentObserver* aElement);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsAutoVoidArray mObservers;
|
||||||
|
Iterator* mIterators;
|
||||||
|
};
|
||||||
|
|
||||||
// Base class for our document implementations.
|
// Base class for our document implementations.
|
||||||
//
|
//
|
||||||
// Note that this class *implements* nsIDOMXMLDocument, but it's not
|
// Note that this class *implements* nsIDOMXMLDocument, but it's not
|
||||||
@ -682,16 +770,23 @@ protected:
|
|||||||
// Dispatch an event to the ScriptGlobalObject for this document
|
// Dispatch an event to the ScriptGlobalObject for this document
|
||||||
void DispatchEventToWindow(nsEvent *aEvent);
|
void DispatchEventToWindow(nsEvent *aEvent);
|
||||||
|
|
||||||
// Copy |mObservers| to an nsCOMArray in preparation so we can notify
|
// NS_DOCUMENT_NOTIFY_OBSERVERS goes backwards for now for backwards compat.
|
||||||
// the list of observers set up at one point in time.
|
// If you change this, update ContentAppended/Inserted/Removed accordingly.
|
||||||
void CopyObserversTo(nsCOMArray<nsIDocumentObserver>& aDestination);
|
|
||||||
|
|
||||||
#define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_) \
|
#define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_) \
|
||||||
do { \
|
do { \
|
||||||
nsCOMArray<nsIDocumentObserver> observers_; \
|
nsDocumentObserverList::ReverseIterator iter_(mObservers); \
|
||||||
CopyObserversTo(observers_); \
|
nsCOMPtr<nsIDocumentObserver> obs_; \
|
||||||
for (PRInt32 i_ = observers_.Count() - 1; i_ >= 0; --i_) { \
|
while ((obs_ = iter_.GetNext())) { \
|
||||||
observers_[i_] -> func_ params_ ; \
|
obs_ -> func_ params_ ; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define NS_DOCUMENT_FORWARD_NOTIFY_OBSERVERS(func_, params_) \
|
||||||
|
do { \
|
||||||
|
nsDocumentObserverList::ForwardIterator iter_(mObservers); \
|
||||||
|
nsCOMPtr<nsIDocumentObserver> obs_; \
|
||||||
|
while ((obs_ = iter_.GetNext())) { \
|
||||||
|
obs_ -> func_ params_ ; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -720,7 +815,7 @@ protected:
|
|||||||
nsCOMArray<nsIStyleSheet> mCatalogSheets;
|
nsCOMArray<nsIStyleSheet> mCatalogSheets;
|
||||||
|
|
||||||
// Basically always has at least 1 entry
|
// Basically always has at least 1 entry
|
||||||
nsAutoVoidArray mObservers;
|
nsDocumentObserverList mObservers;
|
||||||
|
|
||||||
// The document's script global object, the object from which the
|
// The document's script global object, the object from which the
|
||||||
// document can get its script context and scope. This is the
|
// document can get its script context and scope. This is the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user