SMILTimedElement.h (24990B)
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_SMILTIMEDELEMENT_H_ 8 #define DOM_SMIL_SMILTIMEDELEMENT_H_ 9 10 #include <limits> 11 #include <utility> 12 13 #include "mozilla/EventForwards.h" 14 #include "mozilla/SMILInstanceTime.h" 15 #include "mozilla/SMILInterval.h" 16 #include "mozilla/SMILMilestone.h" 17 #include "mozilla/SMILRepeatCount.h" 18 #include "mozilla/SMILTimeValueSpec.h" 19 #include "mozilla/SMILTypes.h" 20 #include "mozilla/UniquePtr.h" 21 #include "nsAttrValue.h" 22 #include "nsHashKeys.h" 23 #include "nsTArray.h" 24 #include "nsTHashtable.h" 25 26 class nsAtom; 27 28 namespace mozilla { 29 30 class SMILAnimationFunction; 31 class SMILTimeContainer; 32 class SMILTimeValue; 33 34 namespace dom { 35 class SVGAnimationElement; 36 } // namespace dom 37 38 //---------------------------------------------------------------------- 39 // SMILTimedElement 40 41 class SMILTimedElement { 42 public: 43 SMILTimedElement(); 44 ~SMILTimedElement(); 45 46 using Element = dom::Element; 47 48 /* 49 * Sets the owning animation element which this class uses to convert between 50 * container times and to register timebase elements. 51 */ 52 void SetAnimationElement(mozilla::dom::SVGAnimationElement* aElement); 53 54 /* 55 * Returns the time container with which this timed element is associated or 56 * nullptr if it is not associated with a time container. 57 */ 58 SMILTimeContainer* GetTimeContainer(); 59 60 /* 61 * Returns the element targeted by the animation element. Needed for 62 * registering event listeners against the appropriate element. 63 */ 64 Element* GetTargetElement(); 65 66 /** 67 * Methods for supporting the ElementTimeControl interface. 68 */ 69 70 /* 71 * Adds a new begin instance time at the current container time plus or minus 72 * the specified offset. 73 * 74 * @param aOffsetSeconds A real number specifying the number of seconds to add 75 * to the current container time. 76 * @return NS_OK if the operation succeeeded, or an error code otherwise. 77 */ 78 nsresult BeginElementAt(double aOffsetSeconds); 79 80 /* 81 * Adds a new end instance time at the current container time plus or minus 82 * the specified offset. 83 * 84 * @param aOffsetSeconds A real number specifying the number of seconds to add 85 * to the current container time. 86 * @return NS_OK if the operation succeeeded, or an error code otherwise. 87 */ 88 nsresult EndElementAt(double aOffsetSeconds); 89 90 /** 91 * Methods for supporting the SVGAnimationElement interface. 92 */ 93 94 /** 95 * According to SVG 1.1 SE this returns 96 * 97 * the begin time, in seconds, for this animation element's current 98 * interval, if it exists, regardless of whether the interval has begun yet. 99 * 100 * @return the start time as defined above in milliseconds or an unresolved 101 * time if there is no current interval. 102 */ 103 SMILTimeValue GetStartTime() const; 104 105 /** 106 * Returns the simple duration of this element. 107 * 108 * @return the simple duration in milliseconds or INDEFINITE. 109 */ 110 SMILTimeValue GetSimpleDuration() const { return mSimpleDur; } 111 112 /** 113 * Methods for supporting hyperlinking 114 */ 115 116 /** 117 * Internal SMIL methods 118 */ 119 120 /** 121 * Returns the time to seek the document to when this element is targetted by 122 * a hyperlink. 123 * 124 * The behavior is defined here: 125 * http://www.w3.org/TR/smil-animation/#HyperlinkSemantics 126 * 127 * It is very similar to GetStartTime() with the exception that when the 128 * element is not active, the begin time of the *first* interval is returned. 129 * 130 * @return the time to seek the documen to in milliseconds or an unresolved 131 * time if there is no resolved interval. 132 */ 133 SMILTimeValue GetHyperlinkTime() const; 134 135 /** 136 * Adds an instance time object this element's list of instance times. 137 * These instance times are used when creating intervals. 138 * 139 * This method is typically called by an SMILTimeValueSpec. 140 * 141 * @param aInstanceTime The time to add, expressed in container time. 142 * @param aIsBegin true if the time to be added represents a begin 143 * time or false if it represents an end time. 144 */ 145 void AddInstanceTime(SMILInstanceTime* aInstanceTime, bool aIsBegin); 146 147 /** 148 * Requests this element update the given instance time. 149 * 150 * This method is typically called by a child SMILTimeValueSpec. 151 * 152 * @param aInstanceTime The instance time to update. 153 * @param aUpdatedTime The time to update aInstanceTime with. 154 * @param aDependentTime The instance time upon which aInstanceTime should be 155 * based. 156 * @param aIsBegin true if the time to be updated represents a begin 157 * instance time or false if it represents an end 158 * instance time. 159 */ 160 void UpdateInstanceTime(SMILInstanceTime* aInstanceTime, 161 SMILTimeValue& aUpdatedTime, bool aIsBegin); 162 163 /** 164 * Removes an instance time object from this element's list of instance times. 165 * 166 * This method is typically called by a child SMILTimeValueSpec. 167 * 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. 171 */ 172 void RemoveInstanceTime(SMILInstanceTime* aInstanceTime, bool aIsBegin); 173 174 /** 175 * Removes all the instance times associated with the given 176 * SMILTimeValueSpec object. Used when an ID assignment changes and hence 177 * all the previously associated instance times become invalid. 178 * 179 * @param aCreator The SMILTimeValueSpec object whose created 180 * SMILInstanceTime'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. 183 */ 184 void RemoveInstanceTimesForCreator(const SMILTimeValueSpec* aCreator, 185 bool aIsBegin); 186 187 /** 188 * Sets the object that will be called by this timed element each time it is 189 * sampled. 190 * 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. 193 * 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, 197 * if any. 198 */ 199 void SetTimeClient(SMILAnimationFunction* aClient); 200 201 /** 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. 205 * 206 * @param aContainerTime The container time at which to sample. 207 */ 208 void SampleAt(SMILTime aContainerTime); 209 210 /** 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. 215 * 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. 219 * 220 * @param aContainerTime The container time at which to sample. 221 */ 222 void SampleEndAt(SMILTime aContainerTime); 223 224 /** 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. 229 */ 230 void HandleContainerTimeChange(); 231 232 /** 233 * Resets this timed element's accumulated times and intervals back to start 234 * up state. 235 * 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. 239 */ 240 void Rewind(); 241 242 /** 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. 245 * 246 * This is used by SVG to "turn off" timed elements when the associated 247 * animation element has failing conditional processing tests. 248 * 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). 251 */ 252 bool SetIsDisabled(bool aIsDisabled); 253 254 /** 255 * Attempts to set an attribute on this timed element. 256 * 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 aContextElement 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. 269 * 270 * @return true if the given attribute is a timing attribute, false 271 * otherwise. 272 */ 273 bool SetAttr(nsAtom* aAttribute, const nsAString& aValue, 274 nsAttrValue& aResult, Element& aContextElement, 275 nsresult* aParseResult = nullptr); 276 277 /** 278 * Attempts to unset an attribute on this timed element. 279 * 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). 283 * 284 * @return true if the given attribute is a timing attribute, false 285 * otherwise. 286 */ 287 bool UnsetAttr(nsAtom* aAttribute); 288 289 /** 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. 292 * 293 * @param aDependent The SMILTimeValueSpec 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. 297 */ 298 void AddDependent(SMILTimeValueSpec& aDependent); 299 300 /** 301 * Removes a syncbase dependency from the list of dependents that are notified 302 * when the current interval is modified. 303 * 304 * @param aDependent The SMILTimeValueSpec object to unregister. 305 */ 306 void RemoveDependent(SMILTimeValueSpec& aDependent); 307 308 /** 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. 314 * 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. 319 */ 320 bool IsTimeDependent(const SMILTimedElement& aOther) const; 321 322 /** 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. 325 * 326 * @param aContextElement The element which provides the necessary context for 327 * resolving references. This is typically the element 328 * in the host language that owns this timed element. 329 */ 330 void BindToTree(Element& aContextElement); 331 332 /** 333 * Called when the target of the animation has changed so that event 334 * registrations can be updated. 335 */ 336 void HandleTargetElementChange(Element* aNewTarget); 337 338 /** 339 * Called when the timed element has been removed from a document so that 340 * references to other elements can be broken. 341 */ 342 void DissolveReferences() { Unlink(); } 343 344 // Cycle collection 345 void Traverse(nsCycleCollectionTraversalCallback* aCallback); 346 void Unlink(); 347 348 using RemovalTestFunction = bool (*)(SMILInstanceTime* aInstance); 349 350 protected: 351 // Typedefs 352 using TimeValueSpecList = nsTArray<UniquePtr<SMILTimeValueSpec>>; 353 using InstanceTimeList = nsTArray<RefPtr<SMILInstanceTime>>; 354 using IntervalList = nsTArray<UniquePtr<SMILInterval>>; 355 using TimeValueSpecPtrKey = nsPtrHashKey<SMILTimeValueSpec>; 356 using TimeValueSpecHashSet = nsTHashtable<TimeValueSpecPtrKey>; 357 358 // Helper classes 359 class InstanceTimeComparator { 360 public: 361 bool Equals(const SMILInstanceTime* aElem1, 362 const SMILInstanceTime* aElem2) const; 363 bool LessThan(const SMILInstanceTime* aElem1, 364 const SMILInstanceTime* aElem2) const; 365 }; 366 367 // Templated helper functions 368 template <class TestFunctor> 369 void RemoveInstanceTimes(InstanceTimeList& aArray, TestFunctor& aTest); 370 371 // 372 // Implementation helpers 373 // 374 375 nsresult SetBeginSpec(const nsAString& aBeginSpec, Element& aContextElement, 376 RemovalTestFunction aRemove); 377 nsresult SetEndSpec(const nsAString& aEndSpec, Element& aContextElement, 378 RemovalTestFunction aRemove); 379 nsresult SetSimpleDuration(const nsAString& aDurSpec); 380 nsresult SetMin(const nsAString& aMinSpec); 381 nsresult SetMax(const nsAString& aMaxSpec); 382 nsresult SetRestart(const nsAString& aRestartSpec); 383 nsresult SetRepeatCount(const nsAString& aRepeatCountSpec); 384 nsresult SetRepeatDur(const nsAString& aRepeatDurSpec); 385 nsresult SetFillMode(const nsAString& aFillModeSpec); 386 387 void UnsetBeginSpec(RemovalTestFunction aRemove); 388 void UnsetEndSpec(RemovalTestFunction aRemove); 389 void UnsetSimpleDuration(); 390 void UnsetMin(); 391 void UnsetMax(); 392 void UnsetRestart(); 393 void UnsetRepeatCount(); 394 void UnsetRepeatDur(); 395 void UnsetFillMode(); 396 397 nsresult SetBeginOrEndSpec(const nsAString& aSpec, Element& aContextElement, 398 bool aIsBegin, RemovalTestFunction aRemove); 399 void ClearSpecs(TimeValueSpecList& aSpecs, InstanceTimeList& aInstances, 400 RemovalTestFunction aRemove); 401 void ClearIntervals(); 402 void DoSampleAt(SMILTime aContainerTime, bool aEndOnly); 403 404 /** 405 * Helper function to check for an early end and, if necessary, update the 406 * current interval accordingly. 407 * 408 * See SMIL 3.0, section 5.4.5, Element life cycle, "Active Time - Playing an 409 * interval" for a description of ending early. 410 * 411 * @param aSampleTime The current sample time. Early ends should only be 412 * applied at the last possible moment (i.e. if they are at 413 * or before the current sample time) and only if the 414 * current interval is not already ending. 415 * @return true if the end time of the current interval was updated, 416 * false otherwise. 417 */ 418 bool ApplyEarlyEnd(const SMILTimeValue& aSampleTime); 419 420 /** 421 * Clears certain state in response to the element restarting. 422 * 423 * This state is described in SMIL 3.0, section 5.4.3, Resetting element state 424 */ 425 void Reset(); 426 427 /** 428 * Clears all accumulated timing state except for those instance times for 429 * which aRemove does not return true. 430 * 431 * Unlike the Reset method which only clears instance times, this clears the 432 * element's state, intervals (including current interval), and tells the 433 * client animation function to stop applying a result. In effect, it returns 434 * the element to its initial state but preserves any instance times excluded 435 * by the passed-in function. 436 */ 437 void ClearTimingState(RemovalTestFunction aRemove); 438 439 /** 440 * Recreates timing state by re-applying begin/end attributes specified on 441 * the associated animation element. 442 * 443 * Note that this does not completely restore the information cleared by 444 * ClearTimingState since it leaves the element in the startup state. 445 * The element state will be updated on the next sample. 446 */ 447 void RebuildTimingState(RemovalTestFunction aRemove); 448 449 /** 450 * Completes a seek operation by sending appropriate events and, in the case 451 * of a backwards seek, updating the state of timing information that was 452 * previously considered historical. 453 */ 454 void DoPostSeek(); 455 456 /** 457 * Unmarks instance times that were previously preserved because they were 458 * considered important historical milestones but are no longer such because 459 * a backwards seek has been performed. 460 */ 461 void UnpreserveInstanceTimes(InstanceTimeList& aList); 462 463 /** 464 * Helper function to iterate through this element's accumulated timing 465 * information (specifically old SMILIntervals and SMILTimeInstanceTimes) 466 * and discard items that are no longer needed or exceed some threshold of 467 * accumulated state. 468 */ 469 void FilterHistory(); 470 471 // Helper functions for FilterHistory to clear old SMILIntervals and 472 // SMILInstanceTimes respectively. 473 void FilterIntervals(); 474 void FilterInstanceTimes(InstanceTimeList& aList); 475 476 /** 477 * Calculates the next acceptable interval for this element after the 478 * specified interval, or, if no previous interval is specified, it will be 479 * the first interval with an end time after t=0. 480 * 481 * @see SMILANIM 3.6.8 482 * 483 * @param aPrevInterval The previous interval used. If supplied, the first 484 * interval that begins after aPrevInterval will be 485 * returned. May be nullptr. 486 * @param aReplacedInterval The interval that is being updated (if any). This 487 * used to ensure we don't return interval endpoints 488 * that are dependent on themselves. May be nullptr. 489 * @param aFixedBeginTime The time to use for the start of the interval. This 490 * is used when only the endpoint of the interval 491 * should be updated such as when the animation is in 492 * the ACTIVE state. May be nullptr. 493 * @param[out] aResult The next interval. Will be unchanged if no suitable 494 * interval was found (in which case false will be 495 * returned). 496 * @return true if a suitable interval was found, false otherwise. 497 */ 498 bool GetNextInterval(const SMILInterval* aPrevInterval, 499 const SMILInterval* aReplacedInterval, 500 const SMILInstanceTime* aFixedBeginTime, 501 SMILInterval& aResult) const; 502 SMILInstanceTime* GetNextGreater(const InstanceTimeList& aList, 503 const SMILTimeValue& aBase, 504 int32_t& aPosition) const; 505 SMILInstanceTime* GetNextGreaterOrEqual(const InstanceTimeList& aList, 506 const SMILTimeValue& aBase, 507 int32_t& aPosition) const; 508 SMILTimeValue CalcActiveEnd(const SMILTimeValue& aBegin, 509 const SMILTimeValue& aEnd) const; 510 SMILTimeValue GetRepeatDuration() const; 511 SMILTimeValue ApplyMinAndMax(const SMILTimeValue& aDuration) const; 512 SMILTime ActiveTimeToSimpleTime(SMILTime aActiveTime, 513 uint32_t& aRepeatIteration); 514 SMILInstanceTime* CheckForEarlyEnd(const SMILTimeValue& aContainerTime) const; 515 void UpdateCurrentInterval(bool aForceChangeNotice = false); 516 void SampleSimpleTime(SMILTime aActiveTime); 517 void SampleFillValue(); 518 void AddInstanceTimeFromCurrentTime(SMILTime aCurrentTime, 519 double aOffsetSeconds, bool aIsBegin); 520 void RegisterMilestone(); 521 bool GetNextMilestone(SMILMilestone& aNextMilestone) const; 522 523 // Notification methods. Note that these notifications can result in nested 524 // calls to this same object. Therefore, 525 // (i) we should not perform notification until this object is in 526 // a consistent state to receive callbacks, and 527 // (ii) after calling these methods we must assume that the state of the 528 // element may have changed. 529 void NotifyNewInterval(); 530 void NotifyChangedInterval(SMILInterval* aInterval, bool aBeginObjectChanged, 531 bool aEndObjectChanged); 532 533 void FireTimeEventAsync(EventMessage aMsg, int32_t aDetail); 534 const SMILInstanceTime* GetEffectiveBeginInstance() const; 535 const SMILInterval* GetPreviousInterval() const; 536 bool HasPlayed() const { return !mOldIntervals.IsEmpty(); } 537 bool HasClientInFillRange() const; 538 bool EndHasEventConditions() const; 539 bool AreEndTimesDependentOn(const SMILInstanceTime* aBase) const; 540 541 // Reset the current interval by first passing ownership to a temporary 542 // variable so that if Unlink() results in us receiving a callback, 543 // mCurrentInterval will be nullptr and we will be in a consistent state. 544 void ResetCurrentInterval() { 545 if (mCurrentInterval) { 546 // Transfer ownership to temp var. (This sets mCurrentInterval to null.) 547 auto interval = std::move(mCurrentInterval); 548 interval->Unlink(); 549 } 550 } 551 552 // 553 // Members 554 // 555 mozilla::dom::SVGAnimationElement* mAnimationElement; // [weak] won't outlive 556 // owner 557 TimeValueSpecList mBeginSpecs; // [strong] 558 TimeValueSpecList mEndSpecs; // [strong] 559 560 SMILTimeValue mSimpleDur; 561 562 SMILRepeatCount mRepeatCount; 563 SMILTimeValue mRepeatDur; 564 565 SMILTimeValue mMin; 566 SMILTimeValue mMax; 567 568 enum SMILFillMode : uint8_t { FILL_REMOVE, FILL_FREEZE }; 569 SMILFillMode mFillMode; 570 static constexpr nsAttrValue::EnumTableEntry sFillModeTable[] = { 571 {"remove", FILL_REMOVE}, 572 {"freeze", FILL_FREEZE}, 573 }; 574 575 enum SMILRestartMode : uint8_t { 576 RESTART_ALWAYS, 577 RESTART_WHENNOTACTIVE, 578 RESTART_NEVER 579 }; 580 SMILRestartMode mRestartMode; 581 static constexpr nsAttrValue::EnumTableEntry sRestartModeTable[] = { 582 {"always", RESTART_ALWAYS}, 583 {"whenNotActive", RESTART_WHENNOTACTIVE}, 584 {"never", RESTART_NEVER}, 585 }; 586 587 InstanceTimeList mBeginInstances; 588 InstanceTimeList mEndInstances; 589 uint32_t mInstanceSerialIndex; 590 591 SMILAnimationFunction* mClient; 592 UniquePtr<SMILInterval> mCurrentInterval; 593 IntervalList mOldIntervals; 594 uint32_t mCurrentRepeatIteration; 595 SMILMilestone mPrevRegisteredMilestone; 596 static constexpr SMILMilestone sMaxMilestone = { 597 std::numeric_limits<SMILTime>::max(), false}; 598 static const uint8_t sMaxNumIntervals; 599 static const uint8_t sMaxNumInstanceTimes; 600 601 // Set of dependent time value specs to be notified when establishing a new 602 // current interval. Change notifications and delete notifications are handled 603 // by the interval. 604 // 605 // [weak] The SMILTimeValueSpec objects register themselves and unregister 606 // on destruction. Likewise, we notify them when we are destroyed. 607 TimeValueSpecHashSet mTimeDependents; 608 609 /** 610 * The state of the element in its life-cycle. These states are based on the 611 * element life-cycle described in SMILANIM 3.6.8 612 */ 613 enum SMILElementState { 614 STATE_STARTUP, 615 STATE_WAITING, 616 STATE_ACTIVE, 617 STATE_POSTACTIVE 618 }; 619 SMILElementState mElementState; 620 621 enum SMILSeekState { 622 SEEK_NOT_SEEKING, 623 SEEK_FORWARD_FROM_ACTIVE, 624 SEEK_FORWARD_FROM_INACTIVE, 625 SEEK_BACKWARD_FROM_ACTIVE, 626 SEEK_BACKWARD_FROM_INACTIVE 627 }; 628 SMILSeekState mSeekState; 629 630 // Used to batch updates to the timing model 631 class AutoIntervalUpdateBatcher; 632 bool mDeferIntervalUpdates; 633 bool mDoDeferredUpdate; // Set if an update to the current interval was 634 // requested while mDeferIntervalUpdates was set 635 bool mIsDisabled; 636 637 // Stack-based helper class to call UpdateCurrentInterval when it is destroyed 638 class AutoIntervalUpdater; 639 640 // Recursion depth checking 641 uint8_t mDeleteCount; 642 uint8_t mUpdateIntervalRecursionDepth; 643 static const uint8_t sMaxUpdateIntervalRecursionDepth; 644 }; 645 646 inline void ImplCycleCollectionUnlink(SMILTimedElement& aField) { 647 aField.Unlink(); 648 } 649 650 inline void ImplCycleCollectionTraverse( 651 nsCycleCollectionTraversalCallback& aCallback, SMILTimedElement& aField, 652 const char* aName, uint32_t aFlags = 0) { 653 aField.Traverse(&aCallback); 654 } 655 656 } // namespace mozilla 657 658 #endif // DOM_SMIL_SMILTIMEDELEMENT_H_