michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef NS_SMILANIMATIONCONTROLLER_H_ michael@0: #define NS_SMILANIMATIONCONTROLLER_H_ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsTArray.h" michael@0: #include "nsITimer.h" michael@0: #include "nsTHashtable.h" michael@0: #include "nsHashKeys.h" michael@0: #include "nsSMILTimeContainer.h" michael@0: #include "nsSMILCompositorTable.h" michael@0: #include "nsSMILMilestone.h" michael@0: #include "nsRefreshDriver.h" michael@0: michael@0: struct nsSMILTargetIdentifier; michael@0: class nsIDocument; michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: class SVGAnimationElement; michael@0: } michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // nsSMILAnimationController michael@0: // michael@0: // The animation controller maintains the animation timer and determines the michael@0: // sample times and sample rate for all SMIL animations in a document. There is michael@0: // at most one animation controller per nsDocument so that frame-rate tuning can michael@0: // be performed at a document-level. michael@0: // michael@0: // The animation controller can contain many child time containers (timed michael@0: // document root objects) which may correspond to SVG document fragments within michael@0: // a compound document. These time containers can be paused individually or michael@0: // here, at the document level. michael@0: // michael@0: class nsSMILAnimationController : public nsSMILTimeContainer, michael@0: public nsARefreshObserver michael@0: { michael@0: public: michael@0: nsSMILAnimationController(nsIDocument* aDoc); michael@0: ~nsSMILAnimationController(); michael@0: michael@0: // Clears mDocument pointer. (Called by our nsIDocument when it's going away) michael@0: void Disconnect(); michael@0: michael@0: // nsSMILContainer michael@0: virtual void Pause(uint32_t aType) MOZ_OVERRIDE; michael@0: virtual void Resume(uint32_t aType) MOZ_OVERRIDE; michael@0: virtual nsSMILTime GetParentTime() const MOZ_OVERRIDE; michael@0: michael@0: // nsARefreshObserver michael@0: NS_IMETHOD_(MozExternalRefCountType) AddRef() MOZ_OVERRIDE; michael@0: NS_IMETHOD_(MozExternalRefCountType) Release() MOZ_OVERRIDE; michael@0: michael@0: virtual void WillRefresh(mozilla::TimeStamp aTime) MOZ_OVERRIDE; michael@0: michael@0: // Methods for registering and enumerating animation elements michael@0: void RegisterAnimationElement(mozilla::dom::SVGAnimationElement* aAnimationElement); michael@0: void UnregisterAnimationElement(mozilla::dom::SVGAnimationElement* aAnimationElement); michael@0: michael@0: // Methods for resampling all animations michael@0: // (A resample performs the same operations as a sample but doesn't advance michael@0: // the current time and doesn't check if the container is paused) michael@0: // This will flush pending style changes for the document. michael@0: void Resample() { DoSample(false); } michael@0: michael@0: void SetResampleNeeded() michael@0: { michael@0: if (!mRunningSample) { michael@0: if (!mResampleNeeded) { michael@0: FlagDocumentNeedsFlush(); michael@0: } michael@0: mResampleNeeded = true; michael@0: } michael@0: } michael@0: michael@0: // This will flush pending style changes for the document. michael@0: void FlushResampleRequests() michael@0: { michael@0: if (!mResampleNeeded) michael@0: return; michael@0: michael@0: Resample(); michael@0: } michael@0: michael@0: // Methods for handling page transitions michael@0: void OnPageShow(); michael@0: void OnPageHide(); michael@0: michael@0: // Methods for supporting cycle-collection michael@0: void Traverse(nsCycleCollectionTraversalCallback* aCallback); michael@0: void Unlink(); michael@0: michael@0: // Methods for relaying the availability of the refresh driver michael@0: void NotifyRefreshDriverCreated(nsRefreshDriver* aRefreshDriver); michael@0: void NotifyRefreshDriverDestroying(nsRefreshDriver* aRefreshDriver); michael@0: michael@0: // Helper to check if we have any animation elements at all michael@0: bool HasRegisteredAnimations() michael@0: { return mAnimationElementTable.Count() != 0; } michael@0: michael@0: protected: michael@0: // Typedefs michael@0: typedef nsPtrHashKey TimeContainerPtrKey; michael@0: typedef nsTHashtable TimeContainerHashtable; michael@0: typedef nsPtrHashKey AnimationElementPtrKey; michael@0: typedef nsTHashtable AnimationElementHashtable; michael@0: michael@0: struct SampleTimeContainerParams michael@0: { michael@0: TimeContainerHashtable* mActiveContainers; michael@0: bool mSkipUnchangedContainers; michael@0: }; michael@0: michael@0: struct SampleAnimationParams michael@0: { michael@0: TimeContainerHashtable* mActiveContainers; michael@0: nsSMILCompositorTable* mCompositorTable; michael@0: }; michael@0: michael@0: struct GetMilestoneElementsParams michael@0: { michael@0: nsTArray > mElements; michael@0: nsSMILMilestone mMilestone; michael@0: }; michael@0: michael@0: // Cycle-collection implementation helpers michael@0: static PLDHashOperator CompositorTableEntryTraverse( michael@0: nsSMILCompositor* aCompositor, void* aArg); michael@0: michael@0: // Returns mDocument's refresh driver, if it's got one. michael@0: nsRefreshDriver* GetRefreshDriver(); michael@0: michael@0: // Methods for controlling whether we're sampling michael@0: void StartSampling(nsRefreshDriver* aRefreshDriver); michael@0: void StopSampling(nsRefreshDriver* aRefreshDriver); michael@0: michael@0: // Wrapper for StartSampling that defers if no animations are registered. michael@0: void MaybeStartSampling(nsRefreshDriver* aRefreshDriver); michael@0: michael@0: // Sample-related callbacks and implementation helpers michael@0: virtual void DoSample() MOZ_OVERRIDE; michael@0: void DoSample(bool aSkipUnchangedContainers); michael@0: michael@0: void RewindElements(); michael@0: static PLDHashOperator RewindNeeded( michael@0: TimeContainerPtrKey* aKey, void* aData); michael@0: static PLDHashOperator RewindAnimation( michael@0: AnimationElementPtrKey* aKey, void* aData); michael@0: static PLDHashOperator ClearRewindNeeded( michael@0: TimeContainerPtrKey* aKey, void* aData); michael@0: michael@0: void DoMilestoneSamples(); michael@0: static PLDHashOperator GetNextMilestone( michael@0: TimeContainerPtrKey* aKey, void* aData); michael@0: static PLDHashOperator GetMilestoneElements( michael@0: TimeContainerPtrKey* aKey, void* aData); michael@0: michael@0: static PLDHashOperator SampleTimeContainer( michael@0: TimeContainerPtrKey* aKey, void* aData); michael@0: static PLDHashOperator SampleAnimation( michael@0: AnimationElementPtrKey* aKey, void* aData); michael@0: static void SampleTimedElement(mozilla::dom::SVGAnimationElement* aElement, michael@0: TimeContainerHashtable* aActiveContainers); michael@0: static void AddAnimationToCompositorTable( michael@0: mozilla::dom::SVGAnimationElement* aElement, nsSMILCompositorTable* aCompositorTable); michael@0: static bool GetTargetIdentifierForAnimation( michael@0: mozilla::dom::SVGAnimationElement* aAnimElem, nsSMILTargetIdentifier& aResult); michael@0: michael@0: // Methods for adding/removing time containers michael@0: virtual nsresult AddChild(nsSMILTimeContainer& aChild) MOZ_OVERRIDE; michael@0: virtual void RemoveChild(nsSMILTimeContainer& aChild) MOZ_OVERRIDE; michael@0: michael@0: void FlagDocumentNeedsFlush(); michael@0: michael@0: // Members michael@0: nsAutoRefCnt mRefCnt; michael@0: NS_DECL_OWNINGTHREAD michael@0: michael@0: AnimationElementHashtable mAnimationElementTable; michael@0: TimeContainerHashtable mChildContainerTable; michael@0: mozilla::TimeStamp mCurrentSampleTime; michael@0: mozilla::TimeStamp mStartTime; michael@0: michael@0: // Average time between samples from the refresh driver. This is used to michael@0: // detect large unexpected gaps between samples such as can occur when the michael@0: // computer sleeps. The nature of the SMIL model means that catching up these michael@0: // large gaps can be expensive as, for example, many events may need to be michael@0: // dispatched for the intervening time when no samples were received. michael@0: // michael@0: // In such cases, we ignore the intervening gap and continue sampling from michael@0: // when we were expecting the next sample to arrive. michael@0: // michael@0: // Note that we only do this for SMIL and not CSS transitions (which doesn't michael@0: // have so much work to do to catch up) nor scripted animations (which expect michael@0: // animation time to follow real time). michael@0: // michael@0: // This behaviour does not affect pausing (since we're not *expecting* any michael@0: // samples then) nor seeking (where the SMIL model behaves somewhat michael@0: // differently such as not dispatching events). michael@0: nsSMILTime mAvgTimeBetweenSamples; michael@0: michael@0: bool mResampleNeeded; michael@0: // If we're told to start sampling but there are no animation elements we just michael@0: // record the time, set the following flag, and then wait until we have an michael@0: // animation element. Then we'll reset this flag and actually start sampling. michael@0: bool mDeferredStartSampling; michael@0: bool mRunningSample; michael@0: michael@0: // Are we registered with our document's refresh driver? michael@0: bool mRegisteredWithRefreshDriver; michael@0: michael@0: // Store raw ptr to mDocument. It owns the controller, so controller michael@0: // shouldn't outlive it michael@0: nsIDocument* mDocument; michael@0: michael@0: // Contains compositors used in our last sample. We keep this around michael@0: // so we can detect when an element/attribute used to be animated, michael@0: // but isn't anymore for some reason. (e.g. if its element is michael@0: // removed or retargeted) michael@0: nsAutoPtr mLastCompositorTable; michael@0: }; michael@0: michael@0: #endif // NS_SMILANIMATIONCONTROLLER_H_