summaryrefslogtreecommitdiffstats
path: root/dom/smil/SMILTimeContainer.h
blob: 62ea7ad2c4e7e718412eb92863191b01b9468567 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/* -*- 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_SMILTIMECONTAINER_H_
#define DOM_SMIL_SMILTIMECONTAINER_H_

#include "mozilla/dom/SVGAnimationElement.h"
#include "mozilla/SMILMilestone.h"
#include "mozilla/SMILTypes.h"
#include "nscore.h"
#include "nsTPriorityQueue.h"

namespace mozilla {

class SMILTimeValue;

//----------------------------------------------------------------------
// SMILTimeContainer
//
// Common base class for a time base that can be paused, resumed, and sampled.
//
class SMILTimeContainer {
 public:
  SMILTimeContainer();
  virtual ~SMILTimeContainer();

  /*
   * Pause request types.
   */
  enum {
    PAUSE_BEGIN = 1,     // Paused because timeline has yet to begin.
    PAUSE_SCRIPT = 2,    // Paused by script.
    PAUSE_PAGEHIDE = 4,  // Paused because our doc is hidden.
    PAUSE_USERPREF = 8,  // Paused because animations are disabled in prefs.
    PAUSE_IMAGE = 16     // Paused becuase we're in an image that's suspended.
  };

  /*
   * Cause the time container to record its begin time.
   */
  void Begin();

  /*
   * Pause this time container
   *
   * @param aType The source of the pause request. Successive calls to Pause
   * with the same aType will be ignored. The container will remain paused until
   * each call to Pause of a given aType has been matched by at least one call
   * to Resume with the same aType.
   */
  virtual void Pause(uint32_t aType);

  /*
   * Resume this time container
   *
   * param @aType The source of the resume request. Clears the pause flag for
   * this particular type of pause request. When all pause flags have been
   * cleared the time container will be resumed.
   */
  virtual void Resume(uint32_t aType);

  /**
   * Returns true if this time container is paused by the specified type.
   * Note that the time container may also be paused by other types; this method
   * does not test if aType is the exclusive pause source.
   *
   * @param @aType The pause source to test for.
   * @return true if this container is paused by aType.
   */
  bool IsPausedByType(uint32_t aType) const { return mPauseState & aType; }

  /**
   * Returns true if this time container is paused.
   * Generally you should test for a specific type of pausing using
   * IsPausedByType.
   *
   * @return true if this container is paused, false otherwise.
   */
  bool IsPaused() const { return mPauseState != 0; }

  /*
   * Return the time elapsed since this time container's begin time (expressed
   * in parent time) minus any accumulated offset from pausing.
   */
  SMILTime GetCurrentTimeAsSMILTime() const;

  /*
   * Seek the document timeline to the specified time.
   *
   * @param aSeekTo The time to seek to, expressed in this time container's time
   * base (i.e. the same units as GetCurrentTime).
   */
  void SetCurrentTime(SMILTime aSeekTo);

  /*
   * Return the current time for the parent time container if any.
   */
  virtual SMILTime GetParentTime() const;

  /*
   * Convert container time to parent time.
   *
   * @param   aContainerTime The container time to convert.
   * @return  The equivalent parent time or indefinite if the container is
   *          paused and the time is in the future.
   */
  SMILTimeValue ContainerToParentTime(SMILTime aContainerTime) const;

  /*
   * Convert from parent time to container time.
   *
   * @param   aParentTime The parent time to convert.
   * @return  The equivalent container time or indefinite if the container is
   *          paused and aParentTime is after the time when the pause began.
   */
  SMILTimeValue ParentToContainerTime(SMILTime aParentTime) const;

  /*
   * If the container is paused, causes the pause time to be updated to the
   * current parent time. This should be called before updating
   * cross-container dependencies that will call ContainerToParentTime in order
   * to provide more intuitive results.
   */
  void SyncPauseTime();

  /*
   * Updates the current time of this time container and calls DoSample to
   * perform any sample-operations.
   */
  void Sample();

  /*
   * Return if this time container should be sampled or can be skipped.
   *
   * This is most useful as an optimisation for skipping time containers that
   * don't require a sample.
   */
  bool NeedsSample() const { return !mPauseState || mNeedsPauseSample; }

  /*
   * Indicates if the elements of this time container need to be rewound.
   * This occurs during a backwards seek.
   */
  bool NeedsRewind() const { return mNeedsRewind; }
  void ClearNeedsRewind() { mNeedsRewind = false; }

  /*
   * Indicates the time container is currently processing a SetCurrentTime
   * request and appropriate seek behaviour should be applied by child elements
   * (e.g. not firing time events).
   */
  bool IsSeeking() const { return mIsSeeking; }
  void MarkSeekFinished() { mIsSeeking = false; }

  /*
   * Sets the parent time container.
   *
   * The callee still retains ownership of the time container.
   */
  nsresult SetParent(SMILTimeContainer* aParent);

  /*
   * Registers an element for a sample at the given time.
   *
   * @param   aMilestone  The milestone to register in container time.
   * @param   aElement    The timebase element that needs a sample at
   *                      aMilestone.
   */
  void AddMilestone(const SMILMilestone& aMilestone,
                    mozilla::dom::SVGAnimationElement& aElement);

  /*
   * Resets the list of milestones.
   */
  void ClearMilestones();

  /*
   * Returns the next significant transition from amongst the registered
   * milestones.
   *
   * @param[out] aNextMilestone The next milestone with time in parent time.
   *
   * @return true if there exists another milestone, false otherwise in
   * which case aNextMilestone will be unmodified.
   */
  bool GetNextMilestoneInParentTime(SMILMilestone& aNextMilestone) const;

  using AnimElemArray = nsTArray<RefPtr<dom::SVGAnimationElement>>;

  /*
   * Removes and returns the timebase elements from the start of the list of
   * timebase elements that match the given time.
   *
   * @param      aMilestone  The milestone time to match in parent time. This
   *                         must be <= GetNextMilestoneInParentTime.
   * @param[out] aMatchedElements The array to which matching elements will be
   *                              appended.
   * @return true if one or more elements match, false otherwise.
   */
  bool PopMilestoneElementsAtMilestone(const SMILMilestone& aMilestone,
                                       AnimElemArray& aMatchedElements);

  // Cycle-collection support
  void Traverse(nsCycleCollectionTraversalCallback* aCallback);
  void Unlink();

 protected:
  /*
   * Per-sample operations to be performed whenever Sample() is called and
   * NeedsSample() is true. Called after updating mCurrentTime;
   */
  virtual void DoSample() {}

  /*
   * Adding and removing child containers is not implemented in the base class
   * because not all subclasses need this.
   */

  /*
   * Adds a child time container.
   */
  virtual nsresult AddChild(SMILTimeContainer& aChild) {
    return NS_ERROR_FAILURE;
  }

  /*
   * Removes a child time container.
   */
  virtual void RemoveChild(SMILTimeContainer& aChild) {}

  /*
   * Implementation helper to update the current time.
   */
  void UpdateCurrentTime();

  /*
   * Implementation helper to notify timed elements with dependencies that the
   * container time has changed with respect to the document time.
   */
  void NotifyTimeChange();

  // The parent time container, if any
  SMILTimeContainer* mParent;

  // The current time established at the last call to Sample()
  SMILTime mCurrentTime;

  // The number of milliseconds for which the container has been paused
  // (excluding the current pause interval if the container is currently
  // paused).
  //
  //  Current time = parent time - mParentOffset
  //
  SMILTime mParentOffset;

  // The timestamp in parent time when the container was paused
  SMILTime mPauseStart;

  // Whether or not a pause sample is required
  bool mNeedsPauseSample;

  bool mNeedsRewind;  // Backwards seek performed
  bool mIsSeeking;    // Currently in the middle of a seek operation

#ifdef DEBUG
  bool mHoldingEntries;  // True if there's a raw pointer to mMilestoneEntries
                         // on the stack.
#endif

  // A bitfield of the pause state for all pause requests
  uint32_t mPauseState;

  struct MilestoneEntry {
    MilestoneEntry(const SMILMilestone& aMilestone,
                   mozilla::dom::SVGAnimationElement& aElement)
        : mMilestone(aMilestone), mTimebase(&aElement) {}

    bool operator<(const MilestoneEntry& aOther) const {
      return mMilestone < aOther.mMilestone;
    }

    SMILMilestone mMilestone;  // In container time.
    RefPtr<mozilla::dom::SVGAnimationElement> mTimebase;
  };

  // Queue of elements with registered milestones. Used to update the model with
  // significant transitions that occur between two samples. Since timed element
  // re-register their milestones when they're sampled this is reset once we've
  // taken care of the milestones before the current sample time but before we
  // actually do the full sample.
  nsTPriorityQueue<MilestoneEntry> mMilestoneEntries;
};

}  // namespace mozilla

#endif  // DOM_SMIL_SMILTIMECONTAINER_H_