Bumping manifests a=b2g-bump
[gecko.git] / dom / smil / nsSMILTimedElement.h
blob812995a1a667362d62b3ae9c1838cf78baa08d02
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/. */
6 #ifndef NS_SMILTIMEDELEMENT_H_
7 #define NS_SMILTIMEDELEMENT_H_
9 #include "mozilla/Move.h"
10 #include "nsSMILInterval.h"
11 #include "nsSMILInstanceTime.h"
12 #include "nsSMILMilestone.h"
13 #include "nsSMILTimeValueSpec.h"
14 #include "nsSMILRepeatCount.h"
15 #include "nsSMILTypes.h"
16 #include "nsTArray.h"
17 #include "nsTHashtable.h"
18 #include "nsHashKeys.h"
19 #include "nsAutoPtr.h"
20 #include "nsAttrValue.h"
22 class nsSMILAnimationFunction;
23 class nsSMILTimeContainer;
24 class nsSMILTimeValue;
25 class nsIAtom;
27 namespace mozilla {
28 namespace dom {
29 class SVGAnimationElement;
33 //----------------------------------------------------------------------
34 // nsSMILTimedElement
36 class nsSMILTimedElement
38 public:
39 nsSMILTimedElement();
40 ~nsSMILTimedElement();
42 typedef mozilla::dom::Element Element;
45 * Sets the owning animation element which this class uses to convert between
46 * container times and to register timebase elements.
48 void SetAnimationElement(mozilla::dom::SVGAnimationElement* aElement);
51 * Returns the time container with which this timed element is associated or
52 * nullptr if it is not associated with a time container.
54 nsSMILTimeContainer* GetTimeContainer();
57 * Returns the element targeted by the animation element. Needed for
58 * registering event listeners against the appropriate element.
60 mozilla::dom::Element* GetTargetElement();
62 /**
63 * Methods for supporting the nsIDOMElementTimeControl interface.
67 * Adds a new begin instance time at the current container time plus or minus
68 * the specified offset.
70 * @param aOffsetSeconds A real number specifying the number of seconds to add
71 * to the current container time.
72 * @return NS_OK if the operation succeeeded, or an error code otherwise.
74 nsresult BeginElementAt(double aOffsetSeconds);
77 * Adds a new end instance time at the current container time plus or minus
78 * the specified offset.
80 * @param aOffsetSeconds A real number specifying the number of seconds to add
81 * to the current container time.
82 * @return NS_OK if the operation succeeeded, or an error code otherwise.
84 nsresult EndElementAt(double aOffsetSeconds);
86 /**
87 * Methods for supporting the nsSVGAnimationElement interface.
90 /**
91 * According to SVG 1.1 SE this returns
93 * the begin time, in seconds, for this animation element's current
94 * interval, if it exists, regardless of whether the interval has begun yet.
96 * @return the start time as defined above in milliseconds or an unresolved
97 * time if there is no current interval.
99 nsSMILTimeValue GetStartTime() const;
102 * Returns the simple duration of this element.
104 * @return the simple duration in milliseconds or INDEFINITE.
106 nsSMILTimeValue GetSimpleDuration() const
108 return mSimpleDur;
112 * Methods for supporting hyperlinking
116 * Internal SMIL methods
120 * Returns the time to seek the document to when this element is targetted by
121 * a hyperlink.
123 * The behavior is defined here:
124 * http://www.w3.org/TR/smil-animation/#HyperlinkSemantics
126 * It is very similar to GetStartTime() with the exception that when the
127 * element is not active, the begin time of the *first* interval is returned.
129 * @return the time to seek the documen to in milliseconds or an unresolved
130 * time if there is no resolved interval.
132 nsSMILTimeValue GetHyperlinkTime() const;
135 * Adds an instance time object this element's list of instance times.
136 * These instance times are used when creating intervals.
138 * This method is typically called by an nsSMILTimeValueSpec.
140 * @param aInstanceTime The time to add, expressed in container time.
141 * @param aIsBegin true if the time to be added represents a begin
142 * time or false if it represents an end time.
144 void AddInstanceTime(nsSMILInstanceTime* aInstanceTime, bool aIsBegin);
147 * Requests this element update the given instance time.
149 * This method is typically called by a child nsSMILTimeValueSpec.
151 * @param aInstanceTime The instance time to update.
152 * @param aUpdatedTime The time to update aInstanceTime with.
153 * @param aDependentTime The instance time upon which aInstanceTime should be
154 * based.
155 * @param aIsBegin true if the time to be updated represents a begin
156 * instance time or false if it represents an end
157 * instance time.
159 void UpdateInstanceTime(nsSMILInstanceTime* aInstanceTime,
160 nsSMILTimeValue& aUpdatedTime,
161 bool aIsBegin);
164 * Removes an instance time object from this element's list of instance times.
166 * This method is typically called by a child nsSMILTimeValueSpec.
168 * @param aInstanceTime The instance time to remove.
169 * @param aIsBegin true if the time to be removed represents a begin
170 * time or false if it represents an end time.
172 void RemoveInstanceTime(nsSMILInstanceTime* aInstanceTime, bool aIsBegin);
175 * Removes all the instance times associated with the given
176 * nsSMILTimeValueSpec object. Used when an ID assignment changes and hence
177 * all the previously associated instance times become invalid.
179 * @param aSpec The nsSMILTimeValueSpec object whose created
180 * nsSMILInstanceTime's should be removed.
181 * @param aIsBegin true if the times to be removed represent begin
182 * times or false if they are end times.
184 void RemoveInstanceTimesForCreator(const nsSMILTimeValueSpec* aSpec,
185 bool aIsBegin);
188 * Sets the object that will be called by this timed element each time it is
189 * sampled.
191 * In Schmitz's model it is possible to associate several time clients with
192 * a timed element but for now we only allow one.
194 * @param aClient The time client to associate. Any previous time client
195 * will be disassociated and no longer sampled. Setting this
196 * to nullptr will simply disassociate the previous client, if
197 * any.
199 void SetTimeClient(nsSMILAnimationFunction* aClient);
202 * Samples the object at the given container time. Timing intervals are
203 * updated and if this element is active at the given time the associated time
204 * client will be sampled with the appropriate simple time.
206 * @param aContainerTime The container time at which to sample.
208 void SampleAt(nsSMILTime aContainerTime);
211 * Performs a special sample for the end of an interval. Such a sample should
212 * only advance the timed element (and any dependent elements) to the waiting
213 * or postactive state. It should not cause a transition to the active state.
214 * Transition to the active state is only performed on a regular SampleAt.
216 * This allows all interval ends at a given time to be processed first and
217 * hence the new interval can be established based on full information of the
218 * available instance times.
220 * @param aContainerTime The container time at which to sample.
222 void SampleEndAt(nsSMILTime aContainerTime);
225 * Informs the timed element that its time container has changed time
226 * relative to document time. The timed element therefore needs to update its
227 * dependent elements (which may belong to a different time container) so they
228 * can re-resolve their times.
230 void HandleContainerTimeChange();
233 * Resets this timed element's accumulated times and intervals back to start
234 * up state.
236 * This is used for backwards seeking where rather than accumulating
237 * historical timing state and winding it back, we reset the element and seek
238 * forwards.
240 void Rewind();
243 * Marks this element as disabled or not. If the element is disabled, it
244 * will ignore any future samples and discard any accumulated timing state.
246 * This is used by SVG to "turn off" timed elements when the associated
247 * animation element has failing conditional processing tests.
249 * Returns true if the disabled state of the timed element was changed
250 * as a result of this call (i.e. it was not a redundant call).
252 bool SetIsDisabled(bool aIsDisabled);
255 * Attempts to set an attribute on this timed element.
257 * @param aAttribute The name of the attribute to set. The namespace of this
258 * attribute is not specified as it is checked by the host
259 * element. Only attributes in the namespace defined for
260 * SMIL attributes in the host language are passed to the
261 * timed element.
262 * @param aValue The attribute value.
263 * @param aResult The nsAttrValue object that may be used for storing the
264 * parsed result.
265 * @param aContextNode The element to use for context when resolving
266 * references to other elements.
267 * @param[out] aParseResult The result of parsing the attribute. Will be set
268 * to NS_OK if parsing is successful.
270 * @return true if the given attribute is a timing attribute, false
271 * otherwise.
273 bool SetAttr(nsIAtom* aAttribute, const nsAString& aValue,
274 nsAttrValue& aResult, Element* aContextNode,
275 nsresult* aParseResult = nullptr);
278 * Attempts to unset an attribute on this timed element.
280 * @param aAttribute The name of the attribute to set. As with SetAttr the
281 * namespace of the attribute is not specified (see
282 * SetAttr).
284 * @return true if the given attribute is a timing attribute, false
285 * otherwise.
287 bool UnsetAttr(nsIAtom* aAttribute);
290 * Adds a syncbase dependency to the list of dependents that will be notified
291 * when this timed element creates, deletes, or updates its current interval.
293 * @param aDependent The nsSMILTimeValueSpec object to notify. A raw pointer
294 * to this object will be stored. Therefore it is necessary
295 * for the object to be explicitly unregistered (with
296 * RemoveDependent) when it is destroyed.
298 void AddDependent(nsSMILTimeValueSpec& aDependent);
301 * Removes a syncbase dependency from the list of dependents that are notified
302 * when the current interval is modified.
304 * @param aDependent The nsSMILTimeValueSpec object to unregister.
306 void RemoveDependent(nsSMILTimeValueSpec& aDependent);
309 * Determines if this timed element is dependent on the given timed element's
310 * begin time for the interval currently in effect. Whilst the element is in
311 * the active state this is the current interval and in the postactive or
312 * waiting state this is the previous interval if one exists. In all other
313 * cases the element is not considered a time dependent of any other element.
315 * @param aOther The potential syncbase element.
316 * @return true if this timed element's begin time for the currently
317 * effective interval is directly or indirectly derived from aOther, false
318 * otherwise.
320 bool IsTimeDependent(const nsSMILTimedElement& aOther) const;
323 * Called when the timed element has been bound to the document so that
324 * references from this timed element to other elements can be resolved.
326 * @param aContextNode The node which provides the necessary context for
327 * resolving references. This is typically the element in
328 * the host language that owns this timed element. Should
329 * not be null.
331 void BindToTree(nsIContent* aContextNode);
334 * Called when the target of the animation has changed so that event
335 * registrations can be updated.
337 void HandleTargetElementChange(mozilla::dom::Element* aNewTarget);
340 * Called when the timed element has been removed from a document so that
341 * references to other elements can be broken.
343 void DissolveReferences() { Unlink(); }
345 // Cycle collection
346 void Traverse(nsCycleCollectionTraversalCallback* aCallback);
347 void Unlink();
349 typedef bool (*RemovalTestFunction)(nsSMILInstanceTime* aInstance);
351 protected:
352 // Typedefs
353 typedef nsTArray<nsAutoPtr<nsSMILTimeValueSpec> > TimeValueSpecList;
354 typedef nsTArray<nsRefPtr<nsSMILInstanceTime> > InstanceTimeList;
355 typedef nsTArray<nsAutoPtr<nsSMILInterval> > IntervalList;
356 typedef nsPtrHashKey<nsSMILTimeValueSpec> TimeValueSpecPtrKey;
357 typedef nsTHashtable<TimeValueSpecPtrKey> TimeValueSpecHashSet;
359 // Helper classes
360 class InstanceTimeComparator {
361 public:
362 bool Equals(const nsSMILInstanceTime* aElem1,
363 const nsSMILInstanceTime* aElem2) const;
364 bool LessThan(const nsSMILInstanceTime* aElem1,
365 const nsSMILInstanceTime* aElem2) const;
368 struct NotifyTimeDependentsParams {
369 nsSMILTimedElement* mTimedElement;
370 nsSMILTimeContainer* mTimeContainer;
373 // Templated helper functions
374 template <class TestFunctor>
375 void RemoveInstanceTimes(InstanceTimeList& aArray, TestFunctor& aTest);
378 // Implementation helpers
381 nsresult SetBeginSpec(const nsAString& aBeginSpec,
382 Element* aContextNode,
383 RemovalTestFunction aRemove);
384 nsresult SetEndSpec(const nsAString& aEndSpec,
385 Element* aContextNode,
386 RemovalTestFunction aRemove);
387 nsresult SetSimpleDuration(const nsAString& aDurSpec);
388 nsresult SetMin(const nsAString& aMinSpec);
389 nsresult SetMax(const nsAString& aMaxSpec);
390 nsresult SetRestart(const nsAString& aRestartSpec);
391 nsresult SetRepeatCount(const nsAString& aRepeatCountSpec);
392 nsresult SetRepeatDur(const nsAString& aRepeatDurSpec);
393 nsresult SetFillMode(const nsAString& aFillModeSpec);
395 void UnsetBeginSpec(RemovalTestFunction aRemove);
396 void UnsetEndSpec(RemovalTestFunction aRemove);
397 void UnsetSimpleDuration();
398 void UnsetMin();
399 void UnsetMax();
400 void UnsetRestart();
401 void UnsetRepeatCount();
402 void UnsetRepeatDur();
403 void UnsetFillMode();
405 nsresult SetBeginOrEndSpec(const nsAString& aSpec,
406 Element* aContextNode,
407 bool aIsBegin,
408 RemovalTestFunction aRemove);
409 void ClearSpecs(TimeValueSpecList& aSpecs,
410 InstanceTimeList& aInstances,
411 RemovalTestFunction aRemove);
412 void ClearIntervals();
413 void DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly);
416 * Helper function to check for an early end and, if necessary, update the
417 * current interval accordingly.
419 * See SMIL 3.0, section 5.4.5, Element life cycle, "Active Time - Playing an
420 * interval" for a description of ending early.
422 * @param aSampleTime The current sample time. Early ends should only be
423 * applied at the last possible moment (i.e. if they are at
424 * or before the current sample time) and only if the
425 * current interval is not already ending.
426 * @return true if the end time of the current interval was updated,
427 * false otherwise.
429 bool ApplyEarlyEnd(const nsSMILTimeValue& aSampleTime);
432 * Clears certain state in response to the element restarting.
434 * This state is described in SMIL 3.0, section 5.4.3, Resetting element state
436 void Reset();
439 * Clears all accumulated timing state except for those instance times for
440 * which aRemove does not return true.
442 * Unlike the Reset method which only clears instance times, this clears the
443 * element's state, intervals (including current interval), and tells the
444 * client animation function to stop applying a result. In effect, it returns
445 * the element to its initial state but preserves any instance times excluded
446 * by the passed-in function.
448 void ClearTimingState(RemovalTestFunction aRemove);
451 * Recreates timing state by re-applying begin/end attributes specified on
452 * the associated animation element.
454 * Note that this does not completely restore the information cleared by
455 * ClearTimingState since it leaves the element in the startup state.
456 * The element state will be updated on the next sample.
458 void RebuildTimingState(RemovalTestFunction aRemove);
461 * Completes a seek operation by sending appropriate events and, in the case
462 * of a backwards seek, updating the state of timing information that was
463 * previously considered historical.
465 void DoPostSeek();
468 * Unmarks instance times that were previously preserved because they were
469 * considered important historical milestones but are no longer such because
470 * a backwards seek has been performed.
472 void UnpreserveInstanceTimes(InstanceTimeList& aList);
475 * Helper function to iterate through this element's accumulated timing
476 * information (specifically old nsSMILIntervals and nsSMILTimeInstanceTimes)
477 * and discard items that are no longer needed or exceed some threshold of
478 * accumulated state.
480 void FilterHistory();
482 // Helper functions for FilterHistory to clear old nsSMILIntervals and
483 // nsSMILInstanceTimes respectively.
484 void FilterIntervals();
485 void FilterInstanceTimes(InstanceTimeList& aList);
488 * Calculates the next acceptable interval for this element after the
489 * specified interval, or, if no previous interval is specified, it will be
490 * the first interval with an end time after t=0.
492 * @see SMILANIM 3.6.8
494 * @param aPrevInterval The previous interval used. If supplied, the first
495 * interval that begins after aPrevInterval will be
496 * returned. May be nullptr.
497 * @param aReplacedInterval The interval that is being updated (if any). This
498 * used to ensure we don't return interval endpoints
499 * that are dependent on themselves. May be nullptr.
500 * @param aFixedBeginTime The time to use for the start of the interval. This
501 * is used when only the endpoint of the interval
502 * should be updated such as when the animation is in
503 * the ACTIVE state. May be nullptr.
504 * @param[out] aResult The next interval. Will be unchanged if no suitable
505 * interval was found (in which case false will be
506 * returned).
507 * @return true if a suitable interval was found, false otherwise.
509 bool GetNextInterval(const nsSMILInterval* aPrevInterval,
510 const nsSMILInterval* aReplacedInterval,
511 const nsSMILInstanceTime* aFixedBeginTime,
512 nsSMILInterval& aResult) const;
513 nsSMILInstanceTime* GetNextGreater(const InstanceTimeList& aList,
514 const nsSMILTimeValue& aBase,
515 int32_t& aPosition) const;
516 nsSMILInstanceTime* GetNextGreaterOrEqual(const InstanceTimeList& aList,
517 const nsSMILTimeValue& aBase,
518 int32_t& aPosition) const;
519 nsSMILTimeValue CalcActiveEnd(const nsSMILTimeValue& aBegin,
520 const nsSMILTimeValue& aEnd) const;
521 nsSMILTimeValue GetRepeatDuration() const;
522 nsSMILTimeValue ApplyMinAndMax(const nsSMILTimeValue& aDuration) const;
523 nsSMILTime ActiveTimeToSimpleTime(nsSMILTime aActiveTime,
524 uint32_t& aRepeatIteration);
525 nsSMILInstanceTime* CheckForEarlyEnd(
526 const nsSMILTimeValue& aContainerTime) const;
527 void UpdateCurrentInterval(bool aForceChangeNotice = false);
528 void SampleSimpleTime(nsSMILTime aActiveTime);
529 void SampleFillValue();
530 nsresult AddInstanceTimeFromCurrentTime(nsSMILTime aCurrentTime,
531 double aOffsetSeconds, bool aIsBegin);
532 void RegisterMilestone();
533 bool GetNextMilestone(nsSMILMilestone& aNextMilestone) const;
535 // Notification methods. Note that these notifications can result in nested
536 // calls to this same object. Therefore,
537 // (i) we should not perform notification until this object is in
538 // a consistent state to receive callbacks, and
539 // (ii) after calling these methods we must assume that the state of the
540 // element may have changed.
541 void NotifyNewInterval();
542 void NotifyChangedInterval(nsSMILInterval* aInterval,
543 bool aBeginObjectChanged,
544 bool aEndObjectChanged);
546 void FireTimeEventAsync(uint32_t aMsg, int32_t aDetail);
547 const nsSMILInstanceTime* GetEffectiveBeginInstance() const;
548 const nsSMILInterval* GetPreviousInterval() const;
549 bool HasPlayed() const { return !mOldIntervals.IsEmpty(); }
550 bool HasClientInFillRange() const;
551 bool EndHasEventConditions() const;
552 bool AreEndTimesDependentOn(
553 const nsSMILInstanceTime* aBase) const;
555 // Reset the current interval by first passing ownership to a temporary
556 // variable so that if Unlink() results in us receiving a callback,
557 // mCurrentInterval will be nullptr and we will be in a consistent state.
558 void ResetCurrentInterval()
560 if (mCurrentInterval) {
561 // Transfer ownership to temp var. (This sets mCurrentInterval to null.)
562 nsAutoPtr<nsSMILInterval> interval(mozilla::Move(mCurrentInterval));
563 interval->Unlink();
567 // Hashtable callback methods
568 static PLDHashOperator NotifyNewIntervalCallback(
569 TimeValueSpecPtrKey* aKey, void* aData);
572 // Members
574 mozilla::dom::SVGAnimationElement* mAnimationElement; // [weak] won't outlive
575 // owner
576 TimeValueSpecList mBeginSpecs; // [strong]
577 TimeValueSpecList mEndSpecs; // [strong]
579 nsSMILTimeValue mSimpleDur;
581 nsSMILRepeatCount mRepeatCount;
582 nsSMILTimeValue mRepeatDur;
584 nsSMILTimeValue mMin;
585 nsSMILTimeValue mMax;
587 enum nsSMILFillMode
589 FILL_REMOVE,
590 FILL_FREEZE
592 nsSMILFillMode mFillMode;
593 static nsAttrValue::EnumTable sFillModeTable[];
595 enum nsSMILRestartMode
597 RESTART_ALWAYS,
598 RESTART_WHENNOTACTIVE,
599 RESTART_NEVER
601 nsSMILRestartMode mRestartMode;
602 static nsAttrValue::EnumTable sRestartModeTable[];
604 InstanceTimeList mBeginInstances;
605 InstanceTimeList mEndInstances;
606 uint32_t mInstanceSerialIndex;
608 nsSMILAnimationFunction* mClient;
609 nsAutoPtr<nsSMILInterval> mCurrentInterval;
610 IntervalList mOldIntervals;
611 uint32_t mCurrentRepeatIteration;
612 nsSMILMilestone mPrevRegisteredMilestone;
613 static const nsSMILMilestone sMaxMilestone;
614 static const uint8_t sMaxNumIntervals;
615 static const uint8_t sMaxNumInstanceTimes;
617 // Set of dependent time value specs to be notified when establishing a new
618 // current interval. Change notifications and delete notifications are handled
619 // by the interval.
621 // [weak] The nsSMILTimeValueSpec objects register themselves and unregister
622 // on destruction. Likewise, we notify them when we are destroyed.
623 TimeValueSpecHashSet mTimeDependents;
626 * The state of the element in its life-cycle. These states are based on the
627 * element life-cycle described in SMILANIM 3.6.8
629 enum nsSMILElementState
631 STATE_STARTUP,
632 STATE_WAITING,
633 STATE_ACTIVE,
634 STATE_POSTACTIVE
636 nsSMILElementState mElementState;
638 enum nsSMILSeekState
640 SEEK_NOT_SEEKING,
641 SEEK_FORWARD_FROM_ACTIVE,
642 SEEK_FORWARD_FROM_INACTIVE,
643 SEEK_BACKWARD_FROM_ACTIVE,
644 SEEK_BACKWARD_FROM_INACTIVE
646 nsSMILSeekState mSeekState;
648 // Used to batch updates to the timing model
649 class AutoIntervalUpdateBatcher;
650 bool mDeferIntervalUpdates;
651 bool mDoDeferredUpdate; // Set if an update to the current interval was
652 // requested while mDeferIntervalUpdates was set
653 bool mIsDisabled;
655 // Stack-based helper class to call UpdateCurrentInterval when it is destroyed
656 class AutoIntervalUpdater;
658 // Recursion depth checking
659 uint8_t mDeleteCount;
660 uint8_t mUpdateIntervalRecursionDepth;
661 static const uint8_t sMaxUpdateIntervalRecursionDepth;
664 inline void
665 ImplCycleCollectionUnlink(nsSMILTimedElement& aField)
667 aField.Unlink();
670 inline void
671 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
672 nsSMILTimedElement& aField,
673 const char* aName,
674 uint32_t aFlags = 0)
676 aField.Traverse(&aCallback);
679 #endif // NS_SMILTIMEDELEMENT_H_