diff --git a/xpcom/ds/nsObserverList.cpp b/xpcom/ds/nsObserverList.cpp index 9e5e77d8863c..742ed53fd0e2 100644 --- a/xpcom/ds/nsObserverList.cpp +++ b/xpcom/ds/nsObserverList.cpp @@ -26,6 +26,8 @@ #include "nsObserverList.h" #include "nsString.h" #include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsIWeakReference.h" #define NS_AUTOLOCK(__monitor) nsAutoLock __lock(__monitor) @@ -33,6 +35,114 @@ static NS_DEFINE_CID(kObserverListCID, NS_OBSERVERLIST_CID); +class nsObserverListEnumerator : public nsIBidirectionalEnumerator + { + public: + nsObserverListEnumerator( nsISupportsArray* ); + + NS_DECL_ISUPPORTS + NS_DECL_NSIENUMERATOR + NS_DECL_NSIBIDIRECTIONALENUMERATOR + + private: + PRUint32 GetTargetArraySize() const; + nsresult MoveToIndex( PRUint32 ); + + private: + nsCOMPtr mTargetArray; + PRUint32 mCurrentItemIndex; + }; + +NS_IMPL_ISUPPORTS2(nsObserverListEnumerator, nsIBidirectionalEnumerator, nsIEnumerator) + +nsObserverListEnumerator::nsObserverListEnumerator( nsISupportsArray* anArray ) + : mRefCnt(0), + mTargetArray(anArray), + mCurrentItemIndex(0) + { + // nothing else to do here + } + +PRUint32 +nsObserverListEnumerator::GetTargetArraySize() const + { + PRUint32 array_size = 0; + mTargetArray->Count(&array_size); + return array_size; + } + +nsresult +nsObserverListEnumerator::MoveToIndex( PRUint32 aNewIndex ) + { + nsresult status; + if ( aNewIndex < GetTargetArraySize() ) + { + mCurrentItemIndex = aNewIndex; + status = NS_OK; + } + else + status = NS_ERROR_FAILURE; // array bounds violation + + return status; + } + + +NS_IMETHODIMP +nsObserverListEnumerator::First() + { + NS_ASSERTION(mTargetArray, "must enumerate over an non-null list"); + + return MoveToIndex(0); + } + +NS_IMETHODIMP +nsObserverListEnumerator::Last() + { + NS_ASSERTION(mTargetArray, "must enumerate over an non-null list"); + + return MoveToIndex(GetTargetArraySize()-1); + } + +NS_IMETHODIMP +nsObserverListEnumerator::Prev() + { + NS_ASSERTION(mTargetArray, "must enumerate over an non-null list"); + + return MoveToIndex(mCurrentItemIndex-1); + } + +NS_IMETHODIMP +nsObserverListEnumerator::Next() + { + NS_ASSERTION(mTargetArray, "must enumerate over an non-null list"); + + return MoveToIndex(mCurrentItemIndex+1); + } + +NS_IMETHODIMP +nsObserverListEnumerator::CurrentItem( nsISupports** aItemPtr ) + { + NS_ASSERTION(mTargetArray, "must enumerate over an non-null list"); + NS_ASSERTION(aItemPtr, "must supply a place to put the result"); + + nsWeakPtr weakPtr = getter_AddRefs(NS_REINTERPRET_CAST(nsIWeakReference*, mTargetArray->ElementAt(mCurrentItemIndex))); + + if ( !aItemPtr || !weakPtr ) + return NS_ERROR_NULL_POINTER; + + return weakPtr->QueryReferent(NS_GET_IID(nsIObserver), aItemPtr); + } + +NS_IMETHODIMP +nsObserverListEnumerator::IsDone() + { + NS_ASSERTION(mTargetArray, "must enumerate over an non-null list"); + + return (mCurrentItemIndex == (GetTargetArraySize()-1)) ? NS_OK : NS_ENUMERATOR_FALSE; + } + + + //////////////////////////////////////////////////////////////////////////////// // nsObserverList Implementation @@ -87,8 +197,14 @@ nsresult nsObserverList::AddObserver(nsIObserver** anObserver) if (NS_FAILED(rv)) return rv; } +#if NS_WEAK_OBSERVERS + nsWeakPtr observer_ref = getter_AddRefs(NS_GetWeakReference(*anObserver)); + if(observer_ref) { + inserted = mObserverList->AppendElement(observer_ref); +#else if(*anObserver) { - inserted = mObserverList->AppendElement(*anObserver); + inserted = mObserverList->AppendElement(*anObserver); +#endif return inserted ? NS_OK : NS_ERROR_FAILURE; } @@ -110,8 +226,14 @@ nsresult nsObserverList::RemoveObserver(nsIObserver** anObserver) return NS_ERROR_FAILURE; } +#if NS_WEAK_OBSERVERS + nsWeakPtr observer_ref = getter_AddRefs(NS_GetWeakReference(*anObserver)); + if(observer_ref) { + removed = mObserverList->RemoveElement(observer_ref); +#else if(*anObserver) { - removed = mObserverList->RemoveElement(*anObserver); + removed = mObserverList->RemoveElement(*anObserver); +#endif return removed ? NS_OK : NS_ERROR_FAILURE; } @@ -131,7 +253,15 @@ NS_IMETHODIMP nsObserverList::EnumerateObserverList(nsIEnumerator** anEnumerator if(!mObserverList) { return NS_ERROR_FAILURE; } - - return mObserverList->Enumerate(anEnumerator); + +#if NS_WEAK_OBSERVERS + nsCOMPtr enumerator = new nsObserverListEnumerator(mObserverList); + if ( !enumerator ) + return NS_ERROR_OUT_OF_MEMORY; + + return CallQueryInterface(enumerator, anEnumerator); +#else + return mObserverList->Enumerate(anEnumerator); +#endif }