SMILAnimationController.h (6715B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef DOM_SMIL_SMILANIMATIONCONTROLLER_H_ 8 #define DOM_SMIL_SMILANIMATIONCONTROLLER_H_ 9 10 #include "mozilla/SMILCompositorTable.h" 11 #include "mozilla/SMILMilestone.h" 12 #include "mozilla/SMILTimeContainer.h" 13 #include "mozilla/UniquePtr.h" 14 #include "nsCOMPtr.h" 15 #include "nsHashKeys.h" 16 #include "nsTArray.h" 17 #include "nsTHashtable.h" 18 19 class nsRefreshDriver; 20 21 namespace mozilla { 22 struct SMILTargetIdentifier; 23 namespace dom { 24 class Element; 25 class SVGAnimationElement; 26 } // namespace dom 27 28 //---------------------------------------------------------------------- 29 // SMILAnimationController 30 // 31 // The animation controller maintains the animation timer and determines the 32 // sample times and sample rate for all SMIL animations in a document. There is 33 // at most one animation controller per document so that frame-rate tuning can 34 // be performed at a document-level. 35 // 36 // The animation controller can contain many child time containers (timed 37 // document root objects) which may correspond to SVG document fragments within 38 // a compound document. These time containers can be paused individually or 39 // here, at the document level. 40 // 41 class SMILAnimationController final : public SMILTimeContainer { 42 public: 43 explicit SMILAnimationController(mozilla::dom::Document* aDoc); 44 45 NS_INLINE_DECL_REFCOUNTING(SMILAnimationController) 46 47 // Clears mDocument pointer. (Called by our mozilla::dom::Document when it's 48 // going away) 49 void Disconnect(); 50 51 // SMILContainer 52 void Pause(uint32_t aType) override; 53 void Resume(uint32_t aType) override; 54 SMILTime GetParentTime() const override; 55 56 // Returns mDocument's refresh driver, if it's got one. 57 nsRefreshDriver* GetRefreshDriver(); 58 void WillRefresh(mozilla::TimeStamp aTime); 59 60 // Methods for registering and enumerating animation elements 61 void RegisterAnimationElement( 62 mozilla::dom::SVGAnimationElement* aAnimationElement); 63 void UnregisterAnimationElement( 64 mozilla::dom::SVGAnimationElement* aAnimationElement); 65 66 // Methods for resampling all animations 67 // (A resample performs the same operations as a sample but doesn't advance 68 // the current time and doesn't check if the container is paused) 69 // This will flush pending style changes for the document. 70 void Resample() { DoSample(false); } 71 72 void SetResampleNeeded() { 73 if (!mRunningSample && !mResampleNeeded) { 74 FlagDocumentNeedsFlush(); 75 mResampleNeeded = true; 76 } 77 } 78 79 // This will flush pending style changes for the document. 80 void FlushResampleRequests() { 81 if (!mResampleNeeded) return; 82 83 Resample(); 84 } 85 86 // Methods for handling page transitions 87 void OnPageShow(); 88 void OnPageHide(); 89 90 // Methods for supporting cycle-collection 91 void Traverse(nsCycleCollectionTraversalCallback* aCallback); 92 void Unlink(); 93 94 // Helper to check if we have any animation elements at all 95 bool HasRegisteredAnimations() const { 96 return mAnimationElementTable.Count() != 0; 97 } 98 99 bool MightHavePendingStyleUpdates() const { 100 return mMightHavePendingStyleUpdates; 101 } 102 103 void PreTraverse(); 104 void PreTraverseInSubtree(mozilla::dom::Element* aRoot); 105 106 protected: 107 ~SMILAnimationController(); 108 109 // alias declarations 110 using TimeContainerPtrKey = nsPtrHashKey<SMILTimeContainer>; 111 using TimeContainerHashtable = nsTHashtable<TimeContainerPtrKey>; 112 using AnimationElementPtrKey = nsPtrHashKey<dom::SVGAnimationElement>; 113 using AnimationElementHashtable = nsTHashtable<AnimationElementPtrKey>; 114 115 // Methods for controlling whether we're sampling 116 void UpdateSampling(); 117 bool ShouldSample() const; 118 119 // Sample-related callbacks and implementation helpers 120 void DoSample() override; 121 void DoSample(bool aSkipUnchangedContainers); 122 123 void RewindElements(); 124 125 void DoMilestoneSamples(); 126 127 static void SampleTimedElement(mozilla::dom::SVGAnimationElement* aElement, 128 TimeContainerHashtable* aActiveContainers); 129 130 static void AddAnimationToCompositorTable( 131 mozilla::dom::SVGAnimationElement* aElement, 132 SMILCompositorTable* aCompositorTable); 133 134 static bool GetTargetIdentifierForAnimation( 135 mozilla::dom::SVGAnimationElement* aAnimElem, 136 SMILTargetIdentifier& aResult); 137 138 // Methods for adding/removing time containers 139 nsresult AddChild(SMILTimeContainer& aChild) override; 140 void RemoveChild(SMILTimeContainer& aChild) override; 141 142 void FlagDocumentNeedsFlush(); 143 144 // Members 145 146 AnimationElementHashtable mAnimationElementTable; 147 TimeContainerHashtable mChildContainerTable; 148 mozilla::TimeStamp mCurrentSampleTime; 149 mozilla::TimeStamp mStartTime; 150 151 // Average time between samples from the refresh driver. This is used to 152 // detect large unexpected gaps between samples such as can occur when the 153 // computer sleeps. The nature of the SMIL model means that catching up these 154 // large gaps can be expensive as, for example, many events may need to be 155 // dispatched for the intervening time when no samples were received. 156 // 157 // In such cases, we ignore the intervening gap and continue sampling from 158 // when we were expecting the next sample to arrive. 159 // 160 // Note that we only do this for SMIL and not CSS transitions (which doesn't 161 // have so much work to do to catch up) nor scripted animations (which expect 162 // animation time to follow real time). 163 // 164 // This behaviour does not affect pausing (since we're not *expecting* any 165 // samples then) nor seeking (where the SMIL model behaves somewhat 166 // differently such as not dispatching events). 167 SMILTime mAvgTimeBetweenSamples = 0; 168 169 bool mResampleNeeded = false; 170 bool mRunningSample = false; 171 172 // Have we updated animated values without adding them to the restyle tracker? 173 bool mMightHavePendingStyleUpdates = false; 174 175 // Whether we've started sampling. This is only needed because the first 176 // sample is supposed to run sync. 177 bool mIsSampling = false; 178 179 // Store raw ptr to mDocument. It owns the controller, so controller 180 // shouldn't outlive it 181 mozilla::dom::Document* mDocument; 182 183 // Contains compositors used in our last sample. We keep this around 184 // so we can detect when an element/attribute used to be animated, 185 // but isn't anymore for some reason. (e.g. if its <animate> element is 186 // removed or retargeted) 187 UniquePtr<SMILCompositorTable> mLastCompositorTable; 188 }; 189 190 } // namespace mozilla 191 192 #endif // DOM_SMIL_SMILANIMATIONCONTROLLER_H_