diff options
Diffstat (limited to '')
-rw-r--r-- | dom/smil/SMILAnimationController.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/dom/smil/SMILAnimationController.h b/dom/smil/SMILAnimationController.h new file mode 100644 index 0000000000..6bf27e80e6 --- /dev/null +++ b/dom/smil/SMILAnimationController.h @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DOM_SMIL_SMILANIMATIONCONTROLLER_H_ +#define DOM_SMIL_SMILANIMATIONCONTROLLER_H_ + +#include "mozilla/Attributes.h" +#include "mozilla/SMILCompositorTable.h" +#include "mozilla/SMILMilestone.h" +#include "mozilla/SMILTimeContainer.h" +#include "mozilla/UniquePtr.h" +#include "nsCOMPtr.h" +#include "nsTArray.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" +#include "nsRefreshObservers.h" + +class nsRefreshDriver; + +namespace mozilla { +struct SMILTargetIdentifier; +namespace dom { +class Element; +class SVGAnimationElement; +} // namespace dom + +//---------------------------------------------------------------------- +// SMILAnimationController +// +// The animation controller maintains the animation timer and determines the +// sample times and sample rate for all SMIL animations in a document. There is +// at most one animation controller per document so that frame-rate tuning can +// be performed at a document-level. +// +// The animation controller can contain many child time containers (timed +// document root objects) which may correspond to SVG document fragments within +// a compound document. These time containers can be paused individually or +// here, at the document level. +// +class SMILAnimationController final : public SMILTimeContainer, + public nsARefreshObserver { + public: + explicit SMILAnimationController(mozilla::dom::Document* aDoc); + + // Clears mDocument pointer. (Called by our mozilla::dom::Document when it's + // going away) + void Disconnect(); + + // SMILContainer + void Pause(uint32_t aType) override; + void Resume(uint32_t aType) override; + SMILTime GetParentTime() const override; + + // nsARefreshObserver + NS_IMETHOD_(MozExternalRefCountType) AddRef() override; + NS_IMETHOD_(MozExternalRefCountType) Release() override; + + void WillRefresh(mozilla::TimeStamp aTime) override; + + // Methods for registering and enumerating animation elements + void RegisterAnimationElement( + mozilla::dom::SVGAnimationElement* aAnimationElement); + void UnregisterAnimationElement( + mozilla::dom::SVGAnimationElement* aAnimationElement); + + // Methods for resampling all animations + // (A resample performs the same operations as a sample but doesn't advance + // the current time and doesn't check if the container is paused) + // This will flush pending style changes for the document. + void Resample() { DoSample(false); } + + void SetResampleNeeded() { + if (!mRunningSample && !mResampleNeeded) { + FlagDocumentNeedsFlush(); + mResampleNeeded = true; + } + } + + // This will flush pending style changes for the document. + void FlushResampleRequests() { + if (!mResampleNeeded) return; + + Resample(); + } + + // Methods for handling page transitions + void OnPageShow(); + void OnPageHide(); + + // Methods for supporting cycle-collection + void Traverse(nsCycleCollectionTraversalCallback* aCallback); + void Unlink(); + + // Methods for relaying the availability of the refresh driver + void NotifyRefreshDriverCreated(nsRefreshDriver* aRefreshDriver); + void NotifyRefreshDriverDestroying(nsRefreshDriver* aRefreshDriver); + + // Helper to check if we have any animation elements at all + bool HasRegisteredAnimations() const { + return mAnimationElementTable.Count() != 0; + } + + bool MightHavePendingStyleUpdates() const { + return mMightHavePendingStyleUpdates; + } + + bool PreTraverse(); + bool PreTraverseInSubtree(mozilla::dom::Element* aRoot); + + protected: + ~SMILAnimationController(); + + // alias declarations + using TimeContainerPtrKey = nsPtrHashKey<SMILTimeContainer>; + using TimeContainerHashtable = nsTHashtable<TimeContainerPtrKey>; + using AnimationElementPtrKey = nsPtrHashKey<dom::SVGAnimationElement>; + using AnimationElementHashtable = nsTHashtable<AnimationElementPtrKey>; + + // Returns mDocument's refresh driver, if it's got one. + nsRefreshDriver* GetRefreshDriver(); + + // Methods for controlling whether we're sampling + void StartSampling(nsRefreshDriver* aRefreshDriver); + void StopSampling(nsRefreshDriver* aRefreshDriver); + + // Wrapper for StartSampling that defers if no animations are registered. + void MaybeStartSampling(nsRefreshDriver* aRefreshDriver); + + // Sample-related callbacks and implementation helpers + void DoSample() override; + void DoSample(bool aSkipUnchangedContainers); + + void RewindElements(); + + void DoMilestoneSamples(); + + static void SampleTimedElement(mozilla::dom::SVGAnimationElement* aElement, + TimeContainerHashtable* aActiveContainers); + + static void AddAnimationToCompositorTable( + mozilla::dom::SVGAnimationElement* aElement, + SMILCompositorTable* aCompositorTable, bool& aStyleFlushNeeded); + + static bool GetTargetIdentifierForAnimation( + mozilla::dom::SVGAnimationElement* aAnimElem, + SMILTargetIdentifier& aResult); + + // Methods for adding/removing time containers + nsresult AddChild(SMILTimeContainer& aChild) override; + void RemoveChild(SMILTimeContainer& aChild) override; + + void FlagDocumentNeedsFlush(); + + // Members + nsAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD + + AnimationElementHashtable mAnimationElementTable; + TimeContainerHashtable mChildContainerTable; + mozilla::TimeStamp mCurrentSampleTime; + mozilla::TimeStamp mStartTime; + + // Average time between samples from the refresh driver. This is used to + // detect large unexpected gaps between samples such as can occur when the + // computer sleeps. The nature of the SMIL model means that catching up these + // large gaps can be expensive as, for example, many events may need to be + // dispatched for the intervening time when no samples were received. + // + // In such cases, we ignore the intervening gap and continue sampling from + // when we were expecting the next sample to arrive. + // + // Note that we only do this for SMIL and not CSS transitions (which doesn't + // have so much work to do to catch up) nor scripted animations (which expect + // animation time to follow real time). + // + // This behaviour does not affect pausing (since we're not *expecting* any + // samples then) nor seeking (where the SMIL model behaves somewhat + // differently such as not dispatching events). + SMILTime mAvgTimeBetweenSamples; + + bool mResampleNeeded; + // If we're told to start sampling but there are no animation elements we just + // record the time, set the following flag, and then wait until we have an + // animation element. Then we'll reset this flag and actually start sampling. + bool mDeferredStartSampling; + bool mRunningSample; + + // Are we registered with our document's refresh driver? + bool mRegisteredWithRefreshDriver; + + // Have we updated animated values without adding them to the restyle tracker? + bool mMightHavePendingStyleUpdates; + + // Store raw ptr to mDocument. It owns the controller, so controller + // shouldn't outlive it + mozilla::dom::Document* mDocument; + + // Contains compositors used in our last sample. We keep this around + // so we can detect when an element/attribute used to be animated, + // but isn't anymore for some reason. (e.g. if its <animate> element is + // removed or retargeted) + UniquePtr<SMILCompositorTable> mLastCompositorTable; +}; + +} // namespace mozilla + +#endif // DOM_SMIL_SMILANIMATIONCONTROLLER_H_ |