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_SMILTIMECONTAINER_H_
8 #define DOM_SMIL_SMILTIMECONTAINER_H_
9 
10 #include "mozilla/dom/SVGAnimationElement.h"
11 #include "mozilla/SMILMilestone.h"
12 #include "mozilla/SMILTypes.h"
13 #include "nscore.h"
14 #include "nsTPriorityQueue.h"
15 
16 namespace mozilla {
17 
18 class SMILTimeValue;
19 
20 //----------------------------------------------------------------------
21 // SMILTimeContainer
22 //
23 // Common base class for a time base that can be paused, resumed, and sampled.
24 //
25 class SMILTimeContainer {
26  public:
27   SMILTimeContainer();
28   virtual ~SMILTimeContainer();
29 
30   /*
31    * Pause request types.
32    */
33   enum {
34     PAUSE_BEGIN = 1,     // Paused because timeline has yet to begin.
35     PAUSE_SCRIPT = 2,    // Paused by script.
36     PAUSE_PAGEHIDE = 4,  // Paused because our doc is hidden.
37     PAUSE_USERPREF = 8,  // Paused because animations are disabled in prefs.
38     PAUSE_IMAGE = 16     // Paused becuase we're in an image that's suspended.
39   };
40 
41   /*
42    * Cause the time container to record its begin time.
43    */
44   void Begin();
45 
46   /*
47    * Pause this time container
48    *
49    * @param aType The source of the pause request. Successive calls to Pause
50    * with the same aType will be ignored. The container will remain paused until
51    * each call to Pause of a given aType has been matched by at least one call
52    * to Resume with the same aType.
53    */
54   virtual void Pause(uint32_t aType);
55 
56   /*
57    * Resume this time container
58    *
59    * param @aType The source of the resume request. Clears the pause flag for
60    * this particular type of pause request. When all pause flags have been
61    * cleared the time container will be resumed.
62    */
63   virtual void Resume(uint32_t aType);
64 
65   /**
66    * Returns true if this time container is paused by the specified type.
67    * Note that the time container may also be paused by other types; this method
68    * does not test if aType is the exclusive pause source.
69    *
70    * @param @aType The pause source to test for.
71    * @return true if this container is paused by aType.
72    */
IsPausedByType(uint32_t aType)73   bool IsPausedByType(uint32_t aType) const { return mPauseState & aType; }
74 
75   /**
76    * Returns true if this time container is paused.
77    * Generally you should test for a specific type of pausing using
78    * IsPausedByType.
79    *
80    * @return true if this container is paused, false otherwise.
81    */
IsPaused()82   bool IsPaused() const { return mPauseState != 0; }
83 
84   /*
85    * Return the time elapsed since this time container's begin time (expressed
86    * in parent time) minus any accumulated offset from pausing.
87    */
88   SMILTime GetCurrentTimeAsSMILTime() const;
89 
90   /*
91    * Seek the document timeline to the specified time.
92    *
93    * @param aSeekTo The time to seek to, expressed in this time container's time
94    * base (i.e. the same units as GetCurrentTime).
95    */
96   void SetCurrentTime(SMILTime aSeekTo);
97 
98   /*
99    * Return the current time for the parent time container if any.
100    */
101   virtual SMILTime GetParentTime() const;
102 
103   /*
104    * Convert container time to parent time.
105    *
106    * @param   aContainerTime The container time to convert.
107    * @return  The equivalent parent time or indefinite if the container is
108    *          paused and the time is in the future.
109    */
110   SMILTimeValue ContainerToParentTime(SMILTime aContainerTime) const;
111 
112   /*
113    * Convert from parent time to container time.
114    *
115    * @param   aParentTime The parent time to convert.
116    * @return  The equivalent container time or indefinite if the container is
117    *          paused and aParentTime is after the time when the pause began.
118    */
119   SMILTimeValue ParentToContainerTime(SMILTime aParentTime) const;
120 
121   /*
122    * If the container is paused, causes the pause time to be updated to the
123    * current parent time. This should be called before updating
124    * cross-container dependencies that will call ContainerToParentTime in order
125    * to provide more intuitive results.
126    */
127   void SyncPauseTime();
128 
129   /*
130    * Updates the current time of this time container and calls DoSample to
131    * perform any sample-operations.
132    */
133   void Sample();
134 
135   /*
136    * Return if this time container should be sampled or can be skipped.
137    *
138    * This is most useful as an optimisation for skipping time containers that
139    * don't require a sample.
140    */
NeedsSample()141   bool NeedsSample() const { return !mPauseState || mNeedsPauseSample; }
142 
143   /*
144    * Indicates if the elements of this time container need to be rewound.
145    * This occurs during a backwards seek.
146    */
NeedsRewind()147   bool NeedsRewind() const { return mNeedsRewind; }
ClearNeedsRewind()148   void ClearNeedsRewind() { mNeedsRewind = false; }
149 
150   /*
151    * Indicates the time container is currently processing a SetCurrentTime
152    * request and appropriate seek behaviour should be applied by child elements
153    * (e.g. not firing time events).
154    */
IsSeeking()155   bool IsSeeking() const { return mIsSeeking; }
MarkSeekFinished()156   void MarkSeekFinished() { mIsSeeking = false; }
157 
158   /*
159    * Sets the parent time container.
160    *
161    * The callee still retains ownership of the time container.
162    */
163   nsresult SetParent(SMILTimeContainer* aParent);
164 
165   /*
166    * Registers an element for a sample at the given time.
167    *
168    * @param   aMilestone  The milestone to register in container time.
169    * @param   aElement    The timebase element that needs a sample at
170    *                      aMilestone.
171    */
172   void AddMilestone(const SMILMilestone& aMilestone,
173                     mozilla::dom::SVGAnimationElement& aElement);
174 
175   /*
176    * Resets the list of milestones.
177    */
178   void ClearMilestones();
179 
180   /*
181    * Returns the next significant transition from amongst the registered
182    * milestones.
183    *
184    * @param[out] aNextMilestone The next milestone with time in parent time.
185    *
186    * @return true if there exists another milestone, false otherwise in
187    * which case aNextMilestone will be unmodified.
188    */
189   bool GetNextMilestoneInParentTime(SMILMilestone& aNextMilestone) const;
190 
191   using AnimElemArray = nsTArray<RefPtr<dom::SVGAnimationElement>>;
192 
193   /*
194    * Removes and returns the timebase elements from the start of the list of
195    * timebase elements that match the given time.
196    *
197    * @param      aMilestone  The milestone time to match in parent time. This
198    *                         must be <= GetNextMilestoneInParentTime.
199    * @param[out] aMatchedElements The array to which matching elements will be
200    *                              appended.
201    * @return true if one or more elements match, false otherwise.
202    */
203   bool PopMilestoneElementsAtMilestone(const SMILMilestone& aMilestone,
204                                        AnimElemArray& aMatchedElements);
205 
206   // Cycle-collection support
207   void Traverse(nsCycleCollectionTraversalCallback* aCallback);
208   void Unlink();
209 
210  protected:
211   /*
212    * Per-sample operations to be performed whenever Sample() is called and
213    * NeedsSample() is true. Called after updating mCurrentTime;
214    */
DoSample()215   virtual void DoSample() {}
216 
217   /*
218    * Adding and removing child containers is not implemented in the base class
219    * because not all subclasses need this.
220    */
221 
222   /*
223    * Adds a child time container.
224    */
AddChild(SMILTimeContainer & aChild)225   virtual nsresult AddChild(SMILTimeContainer& aChild) {
226     return NS_ERROR_FAILURE;
227   }
228 
229   /*
230    * Removes a child time container.
231    */
RemoveChild(SMILTimeContainer & aChild)232   virtual void RemoveChild(SMILTimeContainer& aChild) {}
233 
234   /*
235    * Implementation helper to update the current time.
236    */
237   void UpdateCurrentTime();
238 
239   /*
240    * Implementation helper to notify timed elements with dependencies that the
241    * container time has changed with respect to the document time.
242    */
243   void NotifyTimeChange();
244 
245   // The parent time container, if any
246   SMILTimeContainer* mParent;
247 
248   // The current time established at the last call to Sample()
249   SMILTime mCurrentTime;
250 
251   // The number of milliseconds for which the container has been paused
252   // (excluding the current pause interval if the container is currently
253   // paused).
254   //
255   //  Current time = parent time - mParentOffset
256   //
257   SMILTime mParentOffset;
258 
259   // The timestamp in parent time when the container was paused
260   SMILTime mPauseStart;
261 
262   // Whether or not a pause sample is required
263   bool mNeedsPauseSample;
264 
265   bool mNeedsRewind;  // Backwards seek performed
266   bool mIsSeeking;    // Currently in the middle of a seek operation
267 
268 #ifdef DEBUG
269   bool mHoldingEntries;  // True if there's a raw pointer to mMilestoneEntries
270                          // on the stack.
271 #endif
272 
273   // A bitfield of the pause state for all pause requests
274   uint32_t mPauseState;
275 
276   struct MilestoneEntry {
MilestoneEntryMilestoneEntry277     MilestoneEntry(const SMILMilestone& aMilestone,
278                    mozilla::dom::SVGAnimationElement& aElement)
279         : mMilestone(aMilestone), mTimebase(&aElement) {}
280 
281     bool operator<(const MilestoneEntry& aOther) const {
282       return mMilestone < aOther.mMilestone;
283     }
284 
285     SMILMilestone mMilestone;  // In container time.
286     RefPtr<mozilla::dom::SVGAnimationElement> mTimebase;
287   };
288 
289   // Queue of elements with registered milestones. Used to update the model with
290   // significant transitions that occur between two samples. Since timed element
291   // re-register their milestones when they're sampled this is reset once we've
292   // taken care of the milestones before the current sample time but before we
293   // actually do the full sample.
294   nsTPriorityQueue<MilestoneEntry> mMilestoneEntries;
295 };
296 
297 }  // namespace mozilla
298 
299 #endif  // DOM_SMIL_SMILTIMECONTAINER_H_
300