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