dom/smil/nsSMILTimedElement.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:de0f3457f3ec
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef NS_SMILTIMEDELEMENT_H_
7 #define NS_SMILTIMEDELEMENT_H_
8
9 #include "nsSMILInterval.h"
10 #include "nsSMILInstanceTime.h"
11 #include "nsSMILMilestone.h"
12 #include "nsSMILTimeValueSpec.h"
13 #include "nsSMILRepeatCount.h"
14 #include "nsSMILTypes.h"
15 #include "nsTArray.h"
16 #include "nsTHashtable.h"
17 #include "nsHashKeys.h"
18 #include "nsAutoPtr.h"
19 #include "nsAttrValue.h"
20
21 class nsSMILAnimationFunction;
22 class nsSMILTimeContainer;
23 class nsSMILTimeValue;
24 class nsIAtom;
25
26 namespace mozilla {
27 namespace dom {
28 class SVGAnimationElement;
29 }
30 }
31
32 //----------------------------------------------------------------------
33 // nsSMILTimedElement
34
35 class nsSMILTimedElement
36 {
37 public:
38 nsSMILTimedElement();
39 ~nsSMILTimedElement();
40
41 typedef mozilla::dom::Element Element;
42
43 /*
44 * Sets the owning animation element which this class uses to convert between
45 * container times and to register timebase elements.
46 */
47 void SetAnimationElement(mozilla::dom::SVGAnimationElement* aElement);
48
49 /*
50 * Returns the time container with which this timed element is associated or
51 * nullptr if it is not associated with a time container.
52 */
53 nsSMILTimeContainer* GetTimeContainer();
54
55 /*
56 * Returns the element targeted by the animation element. Needed for
57 * registering event listeners against the appropriate element.
58 */
59 mozilla::dom::Element* GetTargetElement();
60
61 /**
62 * Methods for supporting the nsIDOMElementTimeControl interface.
63 */
64
65 /*
66 * Adds a new begin instance time at the current container time plus or minus
67 * the specified offset.
68 *
69 * @param aOffsetSeconds A real number specifying the number of seconds to add
70 * to the current container time.
71 * @return NS_OK if the operation succeeeded, or an error code otherwise.
72 */
73 nsresult BeginElementAt(double aOffsetSeconds);
74
75 /*
76 * Adds a new end instance time at the current container time plus or minus
77 * the specified offset.
78 *
79 * @param aOffsetSeconds A real number specifying the number of seconds to add
80 * to the current container time.
81 * @return NS_OK if the operation succeeeded, or an error code otherwise.
82 */
83 nsresult EndElementAt(double aOffsetSeconds);
84
85 /**
86 * Methods for supporting the nsSVGAnimationElement interface.
87 */
88
89 /**
90 * According to SVG 1.1 SE this returns
91 *
92 * the begin time, in seconds, for this animation element's current
93 * interval, if it exists, regardless of whether the interval has begun yet.
94 *
95 * @return the start time as defined above in milliseconds or an unresolved
96 * time if there is no current interval.
97 */
98 nsSMILTimeValue GetStartTime() const;
99
100 /**
101 * Returns the simple duration of this element.
102 *
103 * @return the simple duration in milliseconds or INDEFINITE.
104 */
105 nsSMILTimeValue GetSimpleDuration() const
106 {
107 return mSimpleDur;
108 }
109
110 /**
111 * Methods for supporting hyperlinking
112 */
113
114 /**
115 * Internal SMIL methods
116 */
117
118 /**
119 * Returns the time to seek the document to when this element is targetted by
120 * a hyperlink.
121 *
122 * The behavior is defined here:
123 * http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
124 *
125 * It is very similar to GetStartTime() with the exception that when the
126 * element is not active, the begin time of the *first* interval is returned.
127 *
128 * @return the time to seek the documen to in milliseconds or an unresolved
129 * time if there is no resolved interval.
130 */
131 nsSMILTimeValue GetHyperlinkTime() const;
132
133 /**
134 * Adds an instance time object this element's list of instance times.
135 * These instance times are used when creating intervals.
136 *
137 * This method is typically called by an nsSMILTimeValueSpec.
138 *
139 * @param aInstanceTime The time to add, expressed in container time.
140 * @param aIsBegin true if the time to be added represents a begin
141 * time or false if it represents an end time.
142 */
143 void AddInstanceTime(nsSMILInstanceTime* aInstanceTime, bool aIsBegin);
144
145 /**
146 * Requests this element update the given instance time.
147 *
148 * This method is typically called by a child nsSMILTimeValueSpec.
149 *
150 * @param aInstanceTime The instance time to update.
151 * @param aUpdatedTime The time to update aInstanceTime with.
152 * @param aDependentTime The instance time upon which aInstanceTime should be
153 * based.
154 * @param aIsBegin true if the time to be updated represents a begin
155 * instance time or false if it represents an end
156 * instance time.
157 */
158 void UpdateInstanceTime(nsSMILInstanceTime* aInstanceTime,
159 nsSMILTimeValue& aUpdatedTime,
160 bool aIsBegin);
161
162 /**
163 * Removes an instance time object from this element's list of instance times.
164 *
165 * This method is typically called by a child nsSMILTimeValueSpec.
166 *
167 * @param aInstanceTime The instance time to remove.
168 * @param aIsBegin true if the time to be removed represents a begin
169 * time or false if it represents an end time.
170 */
171 void RemoveInstanceTime(nsSMILInstanceTime* aInstanceTime, bool aIsBegin);
172
173 /**
174 * Removes all the instance times associated with the given
175 * nsSMILTimeValueSpec object. Used when an ID assignment changes and hence
176 * all the previously associated instance times become invalid.
177 *
178 * @param aSpec The nsSMILTimeValueSpec object whose created
179 * nsSMILInstanceTime's should be removed.
180 * @param aIsBegin true if the times to be removed represent begin
181 * times or false if they are end times.
182 */
183 void RemoveInstanceTimesForCreator(const nsSMILTimeValueSpec* aSpec,
184 bool aIsBegin);
185
186 /**
187 * Sets the object that will be called by this timed element each time it is
188 * sampled.
189 *
190 * In Schmitz's model it is possible to associate several time clients with
191 * a timed element but for now we only allow one.
192 *
193 * @param aClient The time client to associate. Any previous time client
194 * will be disassociated and no longer sampled. Setting this
195 * to nullptr will simply disassociate the previous client, if
196 * any.
197 */
198 void SetTimeClient(nsSMILAnimationFunction* aClient);
199
200 /**
201 * Samples the object at the given container time. Timing intervals are
202 * updated and if this element is active at the given time the associated time
203 * client will be sampled with the appropriate simple time.
204 *
205 * @param aContainerTime The container time at which to sample.
206 */
207 void SampleAt(nsSMILTime aContainerTime);
208
209 /**
210 * Performs a special sample for the end of an interval. Such a sample should
211 * only advance the timed element (and any dependent elements) to the waiting
212 * or postactive state. It should not cause a transition to the active state.
213 * Transition to the active state is only performed on a regular SampleAt.
214 *
215 * This allows all interval ends at a given time to be processed first and
216 * hence the new interval can be established based on full information of the
217 * available instance times.
218 *
219 * @param aContainerTime The container time at which to sample.
220 */
221 void SampleEndAt(nsSMILTime aContainerTime);
222
223 /**
224 * Informs the timed element that its time container has changed time
225 * relative to document time. The timed element therefore needs to update its
226 * dependent elements (which may belong to a different time container) so they
227 * can re-resolve their times.
228 */
229 void HandleContainerTimeChange();
230
231 /**
232 * Resets this timed element's accumulated times and intervals back to start
233 * up state.
234 *
235 * This is used for backwards seeking where rather than accumulating
236 * historical timing state and winding it back, we reset the element and seek
237 * forwards.
238 */
239 void Rewind();
240
241 /**
242 * Attempts to set an attribute on this timed element.
243 *
244 * @param aAttribute The name of the attribute to set. The namespace of this
245 * attribute is not specified as it is checked by the host
246 * element. Only attributes in the namespace defined for
247 * SMIL attributes in the host language are passed to the
248 * timed element.
249 * @param aValue The attribute value.
250 * @param aResult The nsAttrValue object that may be used for storing the
251 * parsed result.
252 * @param aContextNode The element to use for context when resolving
253 * references to other elements.
254 * @param[out] aParseResult The result of parsing the attribute. Will be set
255 * to NS_OK if parsing is successful.
256 *
257 * @return true if the given attribute is a timing attribute, false
258 * otherwise.
259 */
260 bool SetAttr(nsIAtom* aAttribute, const nsAString& aValue,
261 nsAttrValue& aResult, Element* aContextNode,
262 nsresult* aParseResult = nullptr);
263
264 /**
265 * Attempts to unset an attribute on this timed element.
266 *
267 * @param aAttribute The name of the attribute to set. As with SetAttr the
268 * namespace of the attribute is not specified (see
269 * SetAttr).
270 *
271 * @return true if the given attribute is a timing attribute, false
272 * otherwise.
273 */
274 bool UnsetAttr(nsIAtom* aAttribute);
275
276 /**
277 * Adds a syncbase dependency to the list of dependents that will be notified
278 * when this timed element creates, deletes, or updates its current interval.
279 *
280 * @param aDependent The nsSMILTimeValueSpec object to notify. A raw pointer
281 * to this object will be stored. Therefore it is necessary
282 * for the object to be explicitly unregistered (with
283 * RemoveDependent) when it is destroyed.
284 */
285 void AddDependent(nsSMILTimeValueSpec& aDependent);
286
287 /**
288 * Removes a syncbase dependency from the list of dependents that are notified
289 * when the current interval is modified.
290 *
291 * @param aDependent The nsSMILTimeValueSpec object to unregister.
292 */
293 void RemoveDependent(nsSMILTimeValueSpec& aDependent);
294
295 /**
296 * Determines if this timed element is dependent on the given timed element's
297 * begin time for the interval currently in effect. Whilst the element is in
298 * the active state this is the current interval and in the postactive or
299 * waiting state this is the previous interval if one exists. In all other
300 * cases the element is not considered a time dependent of any other element.
301 *
302 * @param aOther The potential syncbase element.
303 * @return true if this timed element's begin time for the currently
304 * effective interval is directly or indirectly derived from aOther, false
305 * otherwise.
306 */
307 bool IsTimeDependent(const nsSMILTimedElement& aOther) const;
308
309 /**
310 * Called when the timed element has been bound to the document so that
311 * references from this timed element to other elements can be resolved.
312 *
313 * @param aContextNode The node which provides the necessary context for
314 * resolving references. This is typically the element in
315 * the host language that owns this timed element. Should
316 * not be null.
317 */
318 void BindToTree(nsIContent* aContextNode);
319
320 /**
321 * Called when the target of the animation has changed so that event
322 * registrations can be updated.
323 */
324 void HandleTargetElementChange(mozilla::dom::Element* aNewTarget);
325
326 /**
327 * Called when the timed element has been removed from a document so that
328 * references to other elements can be broken.
329 */
330 void DissolveReferences() { Unlink(); }
331
332 // Cycle collection
333 void Traverse(nsCycleCollectionTraversalCallback* aCallback);
334 void Unlink();
335
336 typedef bool (*RemovalTestFunction)(nsSMILInstanceTime* aInstance);
337
338 protected:
339 // Typedefs
340 typedef nsTArray<nsAutoPtr<nsSMILTimeValueSpec> > TimeValueSpecList;
341 typedef nsTArray<nsRefPtr<nsSMILInstanceTime> > InstanceTimeList;
342 typedef nsTArray<nsAutoPtr<nsSMILInterval> > IntervalList;
343 typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
344 typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
345
346 // Helper classes
347 class InstanceTimeComparator {
348 public:
349 bool Equals(const nsSMILInstanceTime* aElem1,
350 const nsSMILInstanceTime* aElem2) const;
351 bool LessThan(const nsSMILInstanceTime* aElem1,
352 const nsSMILInstanceTime* aElem2) const;
353 };
354
355 struct NotifyTimeDependentsParams {
356 nsSMILTimedElement* mTimedElement;
357 nsSMILTimeContainer* mTimeContainer;
358 };
359
360 // Templated helper functions
361 template <class TestFunctor>
362 void RemoveInstanceTimes(InstanceTimeList& aArray, TestFunctor& aTest);
363
364 //
365 // Implementation helpers
366 //
367
368 nsresult SetBeginSpec(const nsAString& aBeginSpec,
369 Element* aContextNode,
370 RemovalTestFunction aRemove);
371 nsresult SetEndSpec(const nsAString& aEndSpec,
372 Element* aContextNode,
373 RemovalTestFunction aRemove);
374 nsresult SetSimpleDuration(const nsAString& aDurSpec);
375 nsresult SetMin(const nsAString& aMinSpec);
376 nsresult SetMax(const nsAString& aMaxSpec);
377 nsresult SetRestart(const nsAString& aRestartSpec);
378 nsresult SetRepeatCount(const nsAString& aRepeatCountSpec);
379 nsresult SetRepeatDur(const nsAString& aRepeatDurSpec);
380 nsresult SetFillMode(const nsAString& aFillModeSpec);
381
382 void UnsetBeginSpec(RemovalTestFunction aRemove);
383 void UnsetEndSpec(RemovalTestFunction aRemove);
384 void UnsetSimpleDuration();
385 void UnsetMin();
386 void UnsetMax();
387 void UnsetRestart();
388 void UnsetRepeatCount();
389 void UnsetRepeatDur();
390 void UnsetFillMode();
391
392 nsresult SetBeginOrEndSpec(const nsAString& aSpec,
393 Element* aContextNode,
394 bool aIsBegin,
395 RemovalTestFunction aRemove);
396 void ClearSpecs(TimeValueSpecList& aSpecs,
397 InstanceTimeList& aInstances,
398 RemovalTestFunction aRemove);
399 void ClearIntervals();
400 void DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly);
401
402 /**
403 * Helper function to check for an early end and, if necessary, update the
404 * current interval accordingly.
405 *
406 * See SMIL 3.0, section 5.4.5, Element life cycle, "Active Time - Playing an
407 * interval" for a description of ending early.
408 *
409 * @param aSampleTime The current sample time. Early ends should only be
410 * applied at the last possible moment (i.e. if they are at
411 * or before the current sample time) and only if the
412 * current interval is not already ending.
413 * @return true if the end time of the current interval was updated,
414 * false otherwise.
415 */
416 bool ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime);
417
418 /**
419 * Clears certain state in response to the element restarting.
420 *
421 * This state is described in SMIL 3.0, section 5.4.3, Resetting element state
422 */
423 void Reset();
424
425 /**
426 * Completes a seek operation by sending appropriate events and, in the case
427 * of a backwards seek, updating the state of timing information that was
428 * previously considered historical.
429 */
430 void DoPostSeek();
431
432 /**
433 * Unmarks instance times that were previously preserved because they were
434 * considered important historical milestones but are no longer such because
435 * a backwards seek has been performed.
436 */
437 void UnpreserveInstanceTimes(InstanceTimeList& aList);
438
439 /**
440 * Helper function to iterate through this element's accumulated timing
441 * information (specifically old nsSMILIntervals and nsSMILTimeInstanceTimes)
442 * and discard items that are no longer needed or exceed some threshold of
443 * accumulated state.
444 */
445 void FilterHistory();
446
447 // Helper functions for FilterHistory to clear old nsSMILIntervals and
448 // nsSMILInstanceTimes respectively.
449 void FilterIntervals();
450 void FilterInstanceTimes(InstanceTimeList& aList);
451
452 /**
453 * Calculates the next acceptable interval for this element after the
454 * specified interval, or, if no previous interval is specified, it will be
455 * the first interval with an end time after t=0.
456 *
457 * @see SMILANIM 3.6.8
458 *
459 * @param aPrevInterval The previous interval used. If supplied, the first
460 * interval that begins after aPrevInterval will be
461 * returned. May be nullptr.
462 * @param aReplacedInterval The interval that is being updated (if any). This
463 * used to ensure we don't return interval endpoints
464 * that are dependent on themselves. May be nullptr.
465 * @param aFixedBeginTime The time to use for the start of the interval. This
466 * is used when only the endpoint of the interval
467 * should be updated such as when the animation is in
468 * the ACTIVE state. May be nullptr.
469 * @param[out] aResult The next interval. Will be unchanged if no suitable
470 * interval was found (in which case false will be
471 * returned).
472 * @return true if a suitable interval was found, false otherwise.
473 */
474 bool GetNextInterval(const nsSMILInterval* aPrevInterval,
475 const nsSMILInterval* aReplacedInterval,
476 const nsSMILInstanceTime* aFixedBeginTime,
477 nsSMILInterval& aResult) const;
478 nsSMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
479 const nsSMILTimeValue& aBase,
480 int32_t& aPosition) const;
481 nsSMILInstanceTime* GetNextGreaterOrEqual(const InstanceTimeList& aList,
482 const nsSMILTimeValue& aBase,
483 int32_t& aPosition) const;
484 nsSMILTimeValue CalcActiveEnd(const nsSMILTimeValue& aBegin,
485 const nsSMILTimeValue& aEnd) const;
486 nsSMILTimeValue GetRepeatDuration() const;
487 nsSMILTimeValue ApplyMinAndMax(const nsSMILTimeValue& aDuration) const;
488 nsSMILTime ActiveTimeToSimpleTime(nsSMILTime aActiveTime,
489 uint32_t& aRepeatIteration);
490 nsSMILInstanceTime* CheckForEarlyEnd(
491 const nsSMILTimeValue& aContainerTime) const;
492 void UpdateCurrentInterval(bool aForceChangeNotice = false);
493 void SampleSimpleTime(nsSMILTime aActiveTime);
494 void SampleFillValue();
495 nsresult AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
496 double aOffsetSeconds, bool aIsBegin);
497 void RegisterMilestone();
498 bool GetNextMilestone(nsSMILMilestone& aNextMilestone) const;
499
500 // Notification methods. Note that these notifications can result in nested
501 // calls to this same object. Therefore,
502 // (i) we should not perform notification until this object is in
503 // a consistent state to receive callbacks, and
504 // (ii) after calling these methods we must assume that the state of the
505 // element may have changed.
506 void NotifyNewInterval();
507 void NotifyChangedInterval(nsSMILInterval* aInterval,
508 bool aBeginObjectChanged,
509 bool aEndObjectChanged);
510
511 void FireTimeEventAsync(uint32_t aMsg, int32_t aDetail);
512 const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
513 const nsSMILInterval* GetPreviousInterval() const;
514 bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
515 bool HasClientInFillRange() const;
516 bool EndHasEventConditions() const;
517 bool AreEndTimesDependentOn(
518 const nsSMILInstanceTime* aBase) const;
519
520 // Reset the current interval by first passing ownership to a temporary
521 // variable so that if Unlink() results in us receiving a callback,
522 // mCurrentInterval will be nullptr and we will be in a consistent state.
523 void ResetCurrentInterval()
524 {
525 if (mCurrentInterval) {
526 // Transfer ownership to temp var. (This sets mCurrentInterval to null.)
527 nsAutoPtr<nsSMILInterval> interval(mCurrentInterval);
528 interval->Unlink();
529 }
530 }
531
532 // Hashtable callback methods
533 static PLDHashOperator NotifyNewIntervalCallback(
534 TimeValueSpecPtrKey* aKey, void* aData);
535
536 //
537 // Members
538 //
539 mozilla::dom::SVGAnimationElement* mAnimationElement; // [weak] won't outlive
540 // owner
541 TimeValueSpecList mBeginSpecs; // [strong]
542 TimeValueSpecList mEndSpecs; // [strong]
543
544 nsSMILTimeValue mSimpleDur;
545
546 nsSMILRepeatCount mRepeatCount;
547 nsSMILTimeValue mRepeatDur;
548
549 nsSMILTimeValue mMin;
550 nsSMILTimeValue mMax;
551
552 enum nsSMILFillMode
553 {
554 FILL_REMOVE,
555 FILL_FREEZE
556 };
557 nsSMILFillMode mFillMode;
558 static nsAttrValue::EnumTable sFillModeTable[];
559
560 enum nsSMILRestartMode
561 {
562 RESTART_ALWAYS,
563 RESTART_WHENNOTACTIVE,
564 RESTART_NEVER
565 };
566 nsSMILRestartMode mRestartMode;
567 static nsAttrValue::EnumTable sRestartModeTable[];
568
569 InstanceTimeList mBeginInstances;
570 InstanceTimeList mEndInstances;
571 uint32_t mInstanceSerialIndex;
572
573 nsSMILAnimationFunction* mClient;
574 nsAutoPtr<nsSMILInterval> mCurrentInterval;
575 IntervalList mOldIntervals;
576 uint32_t mCurrentRepeatIteration;
577 nsSMILMilestone mPrevRegisteredMilestone;
578 static const nsSMILMilestone sMaxMilestone;
579 static const uint8_t sMaxNumIntervals;
580 static const uint8_t sMaxNumInstanceTimes;
581
582 // Set of dependent time value specs to be notified when establishing a new
583 // current interval. Change notifications and delete notifications are handled
584 // by the interval.
585 //
586 // [weak] The nsSMILTimeValueSpec objects register themselves and unregister
587 // on destruction. Likewise, we notify them when we are destroyed.
588 TimeValueSpecHashSet mTimeDependents;
589
590 /**
591 * The state of the element in its life-cycle. These states are based on the
592 * element life-cycle described in SMILANIM 3.6.8
593 */
594 enum nsSMILElementState
595 {
596 STATE_STARTUP,
597 STATE_WAITING,
598 STATE_ACTIVE,
599 STATE_POSTACTIVE
600 };
601 nsSMILElementState mElementState;
602
603 enum nsSMILSeekState
604 {
605 SEEK_NOT_SEEKING,
606 SEEK_FORWARD_FROM_ACTIVE,
607 SEEK_FORWARD_FROM_INACTIVE,
608 SEEK_BACKWARD_FROM_ACTIVE,
609 SEEK_BACKWARD_FROM_INACTIVE
610 };
611 nsSMILSeekState mSeekState;
612
613 // Used to batch updates to the timing model
614 class AutoIntervalUpdateBatcher;
615 bool mDeferIntervalUpdates;
616 bool mDoDeferredUpdate; // Set if an update to the current interval was
617 // requested while mDeferIntervalUpdates was set
618
619 // Stack-based helper class to call UpdateCurrentInterval when it is destroyed
620 class AutoIntervalUpdater;
621
622 // Recursion depth checking
623 uint8_t mDeleteCount;
624 uint8_t mUpdateIntervalRecursionDepth;
625 static const uint8_t sMaxUpdateIntervalRecursionDepth;
626 };
627
628 #endif // NS_SMILTIMEDELEMENT_H_

mercurial