michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * 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 mozilla_imagelib_FrameAnimator_h_ michael@0: #define mozilla_imagelib_FrameAnimator_h_ michael@0: michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "nsRect.h" michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: michael@0: class FrameBlender; michael@0: michael@0: class FrameAnimator michael@0: { michael@0: public: michael@0: FrameAnimator(FrameBlender& aBlender, uint16_t aAnimationMode); michael@0: michael@0: /** michael@0: * Return value from RequestRefresh. Tells callers what happened in that call michael@0: * to RequestRefresh. michael@0: */ michael@0: struct RefreshResult michael@0: { michael@0: // The dirty rectangle to be re-drawn after this RequestRefresh(). michael@0: nsIntRect dirtyRect; michael@0: michael@0: // Whether any frame changed, and hence the dirty rect was set. michael@0: bool frameAdvanced : 1; michael@0: michael@0: // Whether the animation has finished playing. michael@0: bool animationFinished : 1; michael@0: michael@0: // Whether an error has occurred when trying to advance a frame. Note that michael@0: // errors do not, on their own, end the animation. michael@0: bool error : 1; michael@0: michael@0: RefreshResult() michael@0: : frameAdvanced(false) michael@0: , animationFinished(false) michael@0: , error(false) michael@0: {} michael@0: michael@0: void Accumulate(const RefreshResult& other) michael@0: { michael@0: frameAdvanced = frameAdvanced || other.frameAdvanced; michael@0: animationFinished = animationFinished || other.animationFinished; michael@0: error = error || other.error; michael@0: dirtyRect = dirtyRect.Union(other.dirtyRect); michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * Re-evaluate what frame we're supposed to be on, and do whatever blending michael@0: * is necessary to get us to that frame. michael@0: * michael@0: * Returns the result of that blending, including whether the current frame michael@0: * changed and what the resulting dirty rectangle is. michael@0: */ michael@0: RefreshResult RequestRefresh(const mozilla::TimeStamp& aTime); michael@0: michael@0: /** michael@0: * Call when this image is finished decoding so we know that there aren't any michael@0: * more frames coming. michael@0: */ michael@0: void SetDoneDecoding(bool aDone); michael@0: michael@0: /** michael@0: * Call when you need to re-start animating. Ensures we start from the first michael@0: * frame. michael@0: */ michael@0: void ResetAnimation(); michael@0: michael@0: /** michael@0: * The animation mode of the image. michael@0: * michael@0: * Constants defined in imgIContainer.idl. michael@0: */ michael@0: void SetAnimationMode(uint16_t aAnimationMode); michael@0: michael@0: /** michael@0: * Set the area to refresh when we loop around to the first frame. michael@0: */ michael@0: void SetFirstFrameRefreshArea(const nsIntRect& aRect); michael@0: michael@0: /** michael@0: * Union the area to refresh when we loop around to the first frame with this michael@0: * rect. michael@0: */ michael@0: void UnionFirstFrameRefreshArea(const nsIntRect& aRect); michael@0: michael@0: /** michael@0: * If the animation frame time has not yet been set, set it to michael@0: * TimeStamp::Now(). michael@0: */ michael@0: void InitAnimationFrameTimeIfNecessary(); michael@0: michael@0: /** michael@0: * Set the animation frame time to @aTime. michael@0: */ michael@0: void SetAnimationFrameTime(const TimeStamp& aTime); michael@0: michael@0: /** michael@0: * The current frame we're on, from 0 to (numFrames - 1). michael@0: */ michael@0: uint32_t GetCurrentAnimationFrameIndex() const; michael@0: michael@0: /** michael@0: * Get the area we refresh when we loop around to the first frame. michael@0: */ michael@0: nsIntRect GetFirstFrameRefreshArea() const; michael@0: michael@0: private: // methods michael@0: /** michael@0: * Gets the length of a single loop of this image, in milliseconds. michael@0: * michael@0: * If this image is not finished decoding, is not animated, or it is animated michael@0: * but does not loop, returns -1. Can return 0 in the case of an animated image michael@0: * that has a 0ms delay between its frames and does not loop. michael@0: */ michael@0: int32_t GetSingleLoopTime() const; michael@0: michael@0: /** michael@0: * Advances the animation. Typically, this will advance a single frame, but it michael@0: * may advance multiple frames. This may happen if we have infrequently michael@0: * "ticking" refresh drivers (e.g. in background tabs), or extremely short- michael@0: * lived animation frames. michael@0: * michael@0: * @param aTime the time that the animation should advance to. This will michael@0: * typically be <= TimeStamp::Now(). michael@0: * michael@0: * @returns a RefreshResult that shows whether the frame was successfully michael@0: * advanced, and its resulting dirty rect. michael@0: */ michael@0: RefreshResult AdvanceFrame(mozilla::TimeStamp aTime); michael@0: michael@0: /** michael@0: * Get the time the frame we're currently displaying is supposed to end. michael@0: * michael@0: * In the error case, returns an "infinity" timestamp. michael@0: */ michael@0: mozilla::TimeStamp GetCurrentImgFrameEndTime() const; michael@0: michael@0: private: // data michael@0: //! Area of the first frame that needs to be redrawn on subsequent loops. michael@0: nsIntRect mFirstFrameRefreshArea; michael@0: michael@0: //! the time that the animation advanced to the current frame michael@0: TimeStamp mCurrentAnimationFrameTime; michael@0: michael@0: //! The current frame index we're on. 0 to (numFrames - 1). michael@0: uint32_t mCurrentAnimationFrameIndex; michael@0: michael@0: //! number of loops remaining before animation stops (-1 no stop) michael@0: int32_t mLoopCounter; michael@0: michael@0: //! All the frames of the image, shared with our owner michael@0: FrameBlender& mFrameBlender; michael@0: michael@0: //! The animation mode of this image. Constants defined in imgIContainer. michael@0: uint16_t mAnimationMode; michael@0: michael@0: //! Whether this image is done being decoded. michael@0: bool mDoneDecoding; michael@0: }; michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: #endif /* mozilla_imagelib_FrameAnimator_h_ */