diff --git a/content/smil/nsSMILTimedElement.cpp b/content/smil/nsSMILTimedElement.cpp index 2c44022d6db..4e0c29c9a12 100644 --- a/content/smil/nsSMILTimedElement.cpp +++ b/content/smil/nsSMILTimedElement.cpp @@ -126,6 +126,7 @@ nsSMILTimedElement::nsSMILTimedElement() mSimpleDur.SetIndefinite(); mMin.SetMillis(0L); mMax.SetIndefinite(); + mTimeDependents.Init(); } void @@ -840,23 +841,11 @@ nsSMILTimedElement::UnsetFillMode() void nsSMILTimedElement::AddDependent(nsSMILTimeValueSpec& aDependent) { - // Insert the dependent so that the array remains sorted. - // We could use InsertElementSorted but we want to ensure that we don't end up - // with duplicate entries. - PRUint32 index; - PRBool found = mTimeDependents.GreatestIndexLtEq(&aDependent, - nsDefaultComparator(), - &index); - // There's probably no harm in attempting to register a dependent - // nsSMILTimeValueSpec twice (as long as we don't add it to the array twice) - // but we're not expecting it to happen. - NS_ABORT_IF_FALSE(!found, + // nsSMILTimeValueSpec twice, but we're not expecting it to happen. + NS_ABORT_IF_FALSE(!mTimeDependents.GetEntry(&aDependent), "nsSMILTimeValueSpec is already registered as a dependency"); - if (found) - return; - - mTimeDependents.InsertElementAt(index, &aDependent); + mTimeDependents.PutEntry(&aDependent); if (mCurrentInterval.IsSet()) { // Not necessary to call SyncPauseTime here as we're dealing with @@ -866,9 +855,9 @@ nsSMILTimedElement::AddDependent(nsSMILTimeValueSpec& aDependent) } void -nsSMILTimedElement::RemoveDependent(const nsSMILTimeValueSpec& aDependent) +nsSMILTimedElement::RemoveDependent(nsSMILTimeValueSpec& aDependent) { - mTimeDependents.RemoveElementSorted(&aDependent); + mTimeDependents.RemoveEntry(&aDependent); } PRBool @@ -1544,13 +1533,8 @@ nsSMILTimedElement::NotifyNewInterval() container->SyncPauseTime(); } - PRUint32 count = mTimeDependents.Length(); - for (PRUint32 i = 0; i < count; ++i) { - nsSMILTimeValueSpec* spec = mTimeDependents[i]; - NS_ABORT_IF_FALSE(spec, - "null nsSMILTimeValueSpec in list of time dependents"); - spec->HandleNewInterval(mCurrentInterval, container); - } + NotifyTimeDependentsParams params = { &mCurrentInterval, container }; + mTimeDependents.EnumerateEntries(NotifyNewIntervalCallback, ¶ms); } void @@ -1565,25 +1549,14 @@ nsSMILTimedElement::NotifyChangedInterval() container->SyncPauseTime(); } - PRUint32 count = mTimeDependents.Length(); - for (PRUint32 i = 0; i < count; ++i) { - nsSMILTimeValueSpec* spec = mTimeDependents[i]; - NS_ABORT_IF_FALSE(spec, - "null nsSMILTimeValueSpec in list of time dependents"); - spec->HandleChangedInterval(mCurrentInterval, container); - } + NotifyTimeDependentsParams params = { &mCurrentInterval, container }; + mTimeDependents.EnumerateEntries(NotifyChangedIntervalCallback, ¶ms); } void nsSMILTimedElement::NotifyDeletedInterval() { - PRUint32 count = mTimeDependents.Length(); - for (PRUint32 i = 0; i < count; ++i) { - nsSMILTimeValueSpec* spec = mTimeDependents[i]; - NS_ABORT_IF_FALSE(spec, - "null nsSMILTimeValueSpec in list of time dependents"); - spec->HandleDeletedInterval(); - } + mTimeDependents.EnumerateEntries(NotifyDeletedIntervalCallback, nsnull); } const nsSMILInstanceTime* @@ -1606,3 +1579,59 @@ nsSMILTimedElement::GetEffectiveBeginInstance() const return nsnull; } } + +//---------------------------------------------------------------------- +// Hashtable callback functions + +/* static */ PR_CALLBACK PLDHashOperator +nsSMILTimedElement::NotifyNewIntervalCallback(TimeValueSpecPtrKey* aKey, + void* aData) +{ + NotifyTimeDependentsParams* params = + static_cast(aData); + SanityCheckTimeDependentCallbackArgs(aKey, params, PR_TRUE); + + nsSMILTimeValueSpec* spec = aKey->GetKey(); + spec->HandleNewInterval(*params->mCurrentInterval, params->mTimeContainer); + return PL_DHASH_NEXT; +} + +/* static */ PR_CALLBACK PLDHashOperator +nsSMILTimedElement::NotifyChangedIntervalCallback(TimeValueSpecPtrKey* aKey, + void* aData) +{ + NotifyTimeDependentsParams* params = + static_cast(aData); + SanityCheckTimeDependentCallbackArgs(aKey, params, PR_TRUE); + + nsSMILTimeValueSpec* spec = aKey->GetKey(); + spec->HandleChangedInterval(*params->mCurrentInterval, + params->mTimeContainer); + return PL_DHASH_NEXT; +} + +/* static */ PR_CALLBACK PLDHashOperator +nsSMILTimedElement::NotifyDeletedIntervalCallback(TimeValueSpecPtrKey* aKey, + void* /* unused */) +{ + SanityCheckTimeDependentCallbackArgs(aKey, nsnull, PR_FALSE); + + nsSMILTimeValueSpec* spec = aKey->GetKey(); + spec->HandleDeletedInterval(); + return PL_DHASH_NEXT; +} + +/* static */ void +nsSMILTimedElement::SanityCheckTimeDependentCallbackArgs( + TimeValueSpecPtrKey* aKey, + NotifyTimeDependentsParams* aParams, + PRBool aExpectingParams) +{ + NS_ABORT_IF_FALSE(aKey, "Null hash key for time container hash table"); + NS_ABORT_IF_FALSE(aKey->GetKey(), + "null nsSMILTimeValueSpec in set of time dependents"); + if (aExpectingParams) { + NS_ABORT_IF_FALSE(aParams, "null data ptr while enumerating hashtable"); + NS_ABORT_IF_FALSE(aParams->mCurrentInterval, "null current-interval ptr"); + } +} diff --git a/content/smil/nsSMILTimedElement.h b/content/smil/nsSMILTimedElement.h index 25b7165ecdd..6dbf42e2651 100644 --- a/content/smil/nsSMILTimedElement.h +++ b/content/smil/nsSMILTimedElement.h @@ -45,6 +45,8 @@ #include "nsSMILRepeatCount.h" #include "nsSMILTypes.h" #include "nsTArray.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" #include "nsAutoPtr.h" #include "nsAttrValue.h" @@ -271,7 +273,7 @@ public: * * @param aDependent The nsSMILTimeValueSpec object to unregister. */ - void RemoveDependent(const nsSMILTimeValueSpec& aDependent); + void RemoveDependent(nsSMILTimeValueSpec& aDependent); /** * Determines if this timed element is dependent on the given timed element's @@ -312,6 +314,8 @@ protected: // Typedefs typedef nsTArray > TimeValueSpecList; typedef nsTArray > InstanceTimeList; + typedef nsPtrHashKey TimeValueSpecPtrKey; + typedef nsTHashtable TimeValueSpecHashSet; // Helper classes class InstanceTimeComparator { @@ -322,6 +326,11 @@ protected: const nsSMILInstanceTime* aElem2) const; }; + struct NotifyTimeDependentsParams { + nsSMILInterval* mCurrentInterval; + nsSMILTimeContainer* mTimeContainer; + }; + // // Implementation helpers // @@ -404,6 +413,17 @@ protected: void NotifyDeletedInterval(); const nsSMILInstanceTime* GetEffectiveBeginInstance() const; + // Hashtable callback methods + PR_STATIC_CALLBACK(PLDHashOperator) NotifyNewIntervalCallback( + TimeValueSpecPtrKey* aKey, void* aData); + PR_STATIC_CALLBACK(PLDHashOperator) NotifyChangedIntervalCallback( + TimeValueSpecPtrKey* aKey, void* aData); + PR_STATIC_CALLBACK(PLDHashOperator) NotifyDeletedIntervalCallback( + TimeValueSpecPtrKey* aKey, void* /* unused */); + static inline void SanityCheckTimeDependentCallbackArgs( + TimeValueSpecPtrKey* aKey, NotifyTimeDependentsParams* aParams, + PRBool aExpectingParams); + // // Members // @@ -456,16 +476,12 @@ protected: nsSMILMilestone mPrevRegisteredMilestone; static const nsSMILMilestone sMaxMilestone; - // List of dependent time value specs to be notified when creating, updating, + // Set of dependent time value specs to be notified when creating, updating, // or deleting the current interval. // // [weak] The nsSMILTimeValueSpec objects register themselves and unregister // on destruction. Likewise, we notify them when we are destroyed. - // - // To avoid worst-case O(n^2) performance when many time dependents want to - // unregister, we keep these arrays sorted so we have worst case O(n*logn) for - // add and remove. - nsTArray mTimeDependents; + TimeValueSpecHashSet mTimeDependents; /** * The state of the element in its life-cycle. These states are based on the