michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef NS_SMILTIMECONTAINER_H_ michael@0: #define NS_SMILTIMECONTAINER_H_ michael@0: michael@0: #include "mozilla/dom/SVGAnimationElement.h" michael@0: #include "nscore.h" michael@0: #include "nsSMILTypes.h" michael@0: #include "nsTPriorityQueue.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsSMILMilestone.h" michael@0: michael@0: class nsSMILTimeValue; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // nsSMILTimeContainer michael@0: // michael@0: // Common base class for a time base that can be paused, resumed, and sampled. michael@0: // michael@0: class nsSMILTimeContainer michael@0: { michael@0: public: michael@0: nsSMILTimeContainer(); michael@0: virtual ~nsSMILTimeContainer(); michael@0: michael@0: /* michael@0: * Pause request types. michael@0: */ michael@0: enum { michael@0: PAUSE_BEGIN = 1, // Paused because timeline has yet to begin. michael@0: PAUSE_SCRIPT = 2, // Paused by script. michael@0: PAUSE_PAGEHIDE = 4, // Paused because our doc is hidden. michael@0: PAUSE_USERPREF = 8, // Paused because animations are disabled in prefs. michael@0: PAUSE_IMAGE = 16 // Paused becuase we're in an image that's suspended. michael@0: }; michael@0: michael@0: /* michael@0: * Cause the time container to record its begin time. michael@0: */ michael@0: void Begin(); michael@0: michael@0: /* michael@0: * Pause this time container michael@0: * michael@0: * @param aType The source of the pause request. Successive calls to Pause michael@0: * with the same aType will be ignored. The container will remain paused until michael@0: * each call to Pause of a given aType has been matched by at least one call michael@0: * to Resume with the same aType. michael@0: */ michael@0: virtual void Pause(uint32_t aType); michael@0: michael@0: /* michael@0: * Resume this time container michael@0: * michael@0: * param @aType The source of the resume request. Clears the pause flag for michael@0: * this particular type of pause request. When all pause flags have been michael@0: * cleared the time container will be resumed. michael@0: */ michael@0: virtual void Resume(uint32_t aType); michael@0: michael@0: /** michael@0: * Returns true if this time container is paused by the specified type. michael@0: * Note that the time container may also be paused by other types; this method michael@0: * does not test if aType is the exclusive pause source. michael@0: * michael@0: * @param @aType The pause source to test for. michael@0: * @return true if this container is paused by aType. michael@0: */ michael@0: bool IsPausedByType(uint32_t aType) const { return mPauseState & aType; } michael@0: michael@0: /** michael@0: * Returns true if this time container is paused. michael@0: * Generally you should test for a specific type of pausing using michael@0: * IsPausedByType. michael@0: * michael@0: * @return true if this container is paused, false otherwise. michael@0: */ michael@0: bool IsPaused() const { return mPauseState != 0; } michael@0: michael@0: /* michael@0: * Return the time elapsed since this time container's begin time (expressed michael@0: * in parent time) minus any accumulated offset from pausing. michael@0: */ michael@0: nsSMILTime GetCurrentTime() const; michael@0: michael@0: /* michael@0: * Seek the document timeline to the specified time. michael@0: * michael@0: * @param aSeekTo The time to seek to, expressed in this time container's time michael@0: * base (i.e. the same units as GetCurrentTime). michael@0: */ michael@0: void SetCurrentTime(nsSMILTime aSeekTo); michael@0: michael@0: /* michael@0: * Return the current time for the parent time container if any. michael@0: */ michael@0: virtual nsSMILTime GetParentTime() const; michael@0: michael@0: /* michael@0: * Convert container time to parent time. michael@0: * michael@0: * @param aContainerTime The container time to convert. michael@0: * @return The equivalent parent time or indefinite if the container is michael@0: * paused and the time is in the future. michael@0: */ michael@0: nsSMILTimeValue ContainerToParentTime(nsSMILTime aContainerTime) const; michael@0: michael@0: /* michael@0: * Convert from parent time to container time. michael@0: * michael@0: * @param aParentTime The parent time to convert. michael@0: * @return The equivalent container time or indefinite if the container is michael@0: * paused and aParentTime is after the time when the pause began. michael@0: */ michael@0: nsSMILTimeValue ParentToContainerTime(nsSMILTime aParentTime) const; michael@0: michael@0: /* michael@0: * If the container is paused, causes the pause time to be updated to the michael@0: * current parent time. This should be called before updating michael@0: * cross-container dependencies that will call ContainerToParentTime in order michael@0: * to provide more intuitive results. michael@0: */ michael@0: void SyncPauseTime(); michael@0: michael@0: /* michael@0: * Updates the current time of this time container and calls DoSample to michael@0: * perform any sample-operations. michael@0: */ michael@0: void Sample(); michael@0: michael@0: /* michael@0: * Return if this time container should be sampled or can be skipped. michael@0: * michael@0: * This is most useful as an optimisation for skipping time containers that michael@0: * don't require a sample. michael@0: */ michael@0: bool NeedsSample() const { return !mPauseState || mNeedsPauseSample; } michael@0: michael@0: /* michael@0: * Indicates if the elements of this time container need to be rewound. michael@0: * This occurs during a backwards seek. michael@0: */ michael@0: bool NeedsRewind() const { return mNeedsRewind; } michael@0: void ClearNeedsRewind() { mNeedsRewind = false; } michael@0: michael@0: /* michael@0: * Indicates the time container is currently processing a SetCurrentTime michael@0: * request and appropriate seek behaviour should be applied by child elements michael@0: * (e.g. not firing time events). michael@0: */ michael@0: bool IsSeeking() const { return mIsSeeking; } michael@0: void MarkSeekFinished() { mIsSeeking = false; } michael@0: michael@0: /* michael@0: * Sets the parent time container. michael@0: * michael@0: * The callee still retains ownership of the time container. michael@0: */ michael@0: nsresult SetParent(nsSMILTimeContainer* aParent); michael@0: michael@0: /* michael@0: * Registers an element for a sample at the given time. michael@0: * michael@0: * @param aMilestone The milestone to register in container time. michael@0: * @param aElement The timebase element that needs a sample at michael@0: * aMilestone. michael@0: * @return true if the element was successfully added, false otherwise. michael@0: */ michael@0: bool AddMilestone(const nsSMILMilestone& aMilestone, michael@0: mozilla::dom::SVGAnimationElement& aElement); michael@0: michael@0: /* michael@0: * Resets the list of milestones. michael@0: */ michael@0: void ClearMilestones(); michael@0: michael@0: /* michael@0: * Returns the next significant transition from amongst the registered michael@0: * milestones. michael@0: * michael@0: * @param[out] aNextMilestone The next milestone with time in parent time. michael@0: * michael@0: * @return true if there exists another milestone, false otherwise in michael@0: * which case aNextMilestone will be unmodified. michael@0: */ michael@0: bool GetNextMilestoneInParentTime(nsSMILMilestone& aNextMilestone) const; michael@0: michael@0: typedef nsTArray > AnimElemArray; michael@0: michael@0: /* michael@0: * Removes and returns the timebase elements from the start of the list of michael@0: * timebase elements that match the given time. michael@0: * michael@0: * @param aMilestone The milestone time to match in parent time. This michael@0: * must be <= GetNextMilestoneInParentTime. michael@0: * @param[out] aMatchedElements The array to which matching elements will be michael@0: * appended. michael@0: * @return true if one or more elements match, false otherwise. michael@0: */ michael@0: bool PopMilestoneElementsAtMilestone(const nsSMILMilestone& aMilestone, michael@0: AnimElemArray& aMatchedElements); michael@0: michael@0: // Cycle-collection support michael@0: void Traverse(nsCycleCollectionTraversalCallback* aCallback); michael@0: void Unlink(); michael@0: michael@0: protected: michael@0: /* michael@0: * Per-sample operations to be performed whenever Sample() is called and michael@0: * NeedsSample() is true. Called after updating mCurrentTime; michael@0: */ michael@0: virtual void DoSample() { } michael@0: michael@0: /* michael@0: * Adding and removing child containers is not implemented in the base class michael@0: * because not all subclasses need this. michael@0: */ michael@0: michael@0: /* michael@0: * Adds a child time container. michael@0: */ michael@0: virtual nsresult AddChild(nsSMILTimeContainer& aChild) michael@0: { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /* michael@0: * Removes a child time container. michael@0: */ michael@0: virtual void RemoveChild(nsSMILTimeContainer& aChild) { } michael@0: michael@0: /* michael@0: * Implementation helper to update the current time. michael@0: */ michael@0: void UpdateCurrentTime(); michael@0: michael@0: /* michael@0: * Implementation helper to notify timed elements with dependencies that the michael@0: * container time has changed with respect to the document time. michael@0: */ michael@0: void NotifyTimeChange(); michael@0: michael@0: // The parent time container, if any michael@0: nsSMILTimeContainer* mParent; michael@0: michael@0: // The current time established at the last call to Sample() michael@0: nsSMILTime mCurrentTime; michael@0: michael@0: // The number of milliseconds for which the container has been paused michael@0: // (excluding the current pause interval if the container is currently michael@0: // paused). michael@0: // michael@0: // Current time = parent time - mParentOffset michael@0: // michael@0: nsSMILTime mParentOffset; michael@0: michael@0: // The timestamp in parent time when the container was paused michael@0: nsSMILTime mPauseStart; michael@0: michael@0: // Whether or not a pause sample is required michael@0: bool mNeedsPauseSample; michael@0: michael@0: bool mNeedsRewind; // Backwards seek performed michael@0: bool mIsSeeking; // Currently in the middle of a seek operation michael@0: michael@0: // A bitfield of the pause state for all pause requests michael@0: uint32_t mPauseState; michael@0: michael@0: struct MilestoneEntry michael@0: { michael@0: MilestoneEntry(nsSMILMilestone aMilestone, michael@0: mozilla::dom::SVGAnimationElement& aElement) michael@0: : mMilestone(aMilestone), mTimebase(&aElement) michael@0: { } michael@0: michael@0: bool operator<(const MilestoneEntry& aOther) const michael@0: { michael@0: return mMilestone < aOther.mMilestone; michael@0: } michael@0: michael@0: nsSMILMilestone mMilestone; // In container time. michael@0: nsRefPtr mTimebase; michael@0: }; michael@0: michael@0: // Queue of elements with registered milestones. Used to update the model with michael@0: // significant transitions that occur between two samples. Since timed element michael@0: // re-register their milestones when they're sampled this is reset once we've michael@0: // taken care of the milestones before the current sample time but before we michael@0: // actually do the full sample. michael@0: nsTPriorityQueue mMilestoneEntries; michael@0: }; michael@0: michael@0: #endif // NS_SMILTIMECONTAINER_H_