LCOV - code coverage report
Current view: top level - image - FrameAnimator.h (source / functions) Hit Total Coverage
Test: output.info Lines: 25 36 69.4 %
Date: 2017-07-14 16:53:18 Functions: 11 19 57.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       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 mozilla_image_FrameAnimator_h
       8             : #define mozilla_image_FrameAnimator_h
       9             : 
      10             : #include "mozilla/Maybe.h"
      11             : #include "mozilla/MemoryReporting.h"
      12             : #include "mozilla/TimeStamp.h"
      13             : #include "gfxTypes.h"
      14             : #include "imgFrame.h"
      15             : #include "nsCOMPtr.h"
      16             : #include "nsRect.h"
      17             : #include "SurfaceCache.h"
      18             : #include "gfxPrefs.h"
      19             : 
      20             : namespace mozilla {
      21             : namespace image {
      22             : 
      23             : class RasterImage;
      24             : class DrawableSurface;
      25             : 
      26           0 : class AnimationState
      27             : {
      28             : public:
      29           2 :   explicit AnimationState(uint16_t aAnimationMode)
      30           2 :     : mFrameCount(0)
      31             :     , mCurrentAnimationFrameIndex(0)
      32             :     , mLoopRemainingCount(-1)
      33             :     , mLoopCount(-1)
      34             :     , mFirstFrameTimeout(FrameTimeout::FromRawMilliseconds(0))
      35             :     , mAnimationMode(aAnimationMode)
      36             :     , mHasBeenDecoded(false)
      37             :     , mIsCurrentlyDecoded(false)
      38             :     , mCompositedFrameInvalid(false)
      39           2 :     , mDiscarded(false)
      40           2 :   { }
      41             : 
      42             :   /**
      43             :    * Call this whenever a decode completes, a decode starts, or the image is
      44             :    * discarded. It will update the internal state. Specifically mDiscarded,
      45             :    * mCompositedFrameInvalid, and mIsCurrentlyDecoded. If aAllowInvalidation
      46             :    * is true then returns a rect to invalidate.
      47             :    */
      48             :   const gfx::IntRect UpdateState(bool aAnimationFinished,
      49             :                             RasterImage *aImage,
      50             :                             const gfx::IntSize& aSize,
      51             :                             bool aAllowInvalidation = true);
      52             : private:
      53             :   const gfx::IntRect UpdateStateInternal(LookupResult& aResult,
      54             :                                     bool aAnimationFinished,
      55             :                                     const gfx::IntSize& aSize,
      56             :                                     bool aAllowInvalidation = true);
      57             : 
      58             : public:
      59             :   /**
      60             :    * Call when a decode of this image has been completed.
      61             :    */
      62             :   void NotifyDecodeComplete();
      63             : 
      64             :   /**
      65             :    * Returns true if this image has been fully decoded before.
      66             :    */
      67           0 :   bool GetHasBeenDecoded() { return mHasBeenDecoded; }
      68             : 
      69             :   /**
      70             :    * Returns true if this image has been discarded and a decoded has not yet
      71             :    * been created to redecode it.
      72             :    */
      73          20 :   bool IsDiscarded() { return mDiscarded; }
      74             : 
      75             :   /**
      76             :    * Sets the composited frame as valid or invalid.
      77             :    */
      78             :   void SetCompositedFrameInvalid(bool aInvalid) {
      79             :     MOZ_ASSERT(!aInvalid || gfxPrefs::ImageMemAnimatedDiscardable());
      80             :     mCompositedFrameInvalid = aInvalid;
      81             :   }
      82             : 
      83             :   /**
      84             :    * Returns whether the composited frame is valid to draw to the screen.
      85             :    */
      86           0 :   bool GetCompositedFrameInvalid() {
      87           0 :     return mCompositedFrameInvalid;
      88             :   }
      89             : 
      90             :   /**
      91             :    * Returns whether the image is currently full decoded..
      92             :    */
      93           0 :   bool GetIsCurrentlyDecoded() {
      94           0 :     return mIsCurrentlyDecoded;
      95             :   }
      96             : 
      97             :   /**
      98             :    * Call when you need to re-start animating. Ensures we start from the first
      99             :    * frame.
     100             :    */
     101             :   void ResetAnimation();
     102             : 
     103             :   /**
     104             :    * The animation mode of the image.
     105             :    *
     106             :    * Constants defined in imgIContainer.idl.
     107             :    */
     108             :   void SetAnimationMode(uint16_t aAnimationMode);
     109             : 
     110             :   /// Update the number of frames of animation this image is known to have.
     111             :   void UpdateKnownFrameCount(uint32_t aFrameCount);
     112             : 
     113             :   /// @return the number of frames of animation we know about so far.
     114          62 :   uint32_t KnownFrameCount() const { return mFrameCount; }
     115             : 
     116             :   /// @return the number of frames this animation has, if we know for sure.
     117             :   /// (In other words, if decoding is finished.) Otherwise, returns Nothing().
     118             :   Maybe<uint32_t> FrameCount() const;
     119             : 
     120             :   /**
     121             :    * Get or set the area of the image to invalidate when we loop around to the
     122             :    * first frame.
     123             :    */
     124             :   void SetFirstFrameRefreshArea(const gfx::IntRect& aRefreshArea);
     125           0 :   gfx::IntRect FirstFrameRefreshArea() const { return mFirstFrameRefreshArea; }
     126             : 
     127             :   /**
     128             :    * If the animation frame time has not yet been set, set it to
     129             :    * TimeStamp::Now().
     130             :    */
     131             :   void InitAnimationFrameTimeIfNecessary();
     132             : 
     133             :   /**
     134             :    * Set the animation frame time to @aTime.
     135             :    */
     136             :   void SetAnimationFrameTime(const TimeStamp& aTime);
     137             : 
     138             :   /**
     139             :    * The current frame we're on, from 0 to (numFrames - 1).
     140             :    */
     141             :   uint32_t GetCurrentAnimationFrameIndex() const;
     142             : 
     143             :   /*
     144             :    * Set number of times to loop the image.
     145             :    * @note -1 means loop forever.
     146             :    */
     147           4 :   void SetLoopCount(int32_t aLoopCount) { mLoopCount = aLoopCount; }
     148          22 :   int32_t LoopCount() const { return mLoopCount; }
     149             : 
     150             :   /// Set the @aLength of a single loop through this image.
     151           2 :   void SetLoopLength(FrameTimeout aLength) { mLoopLength = Some(aLength); }
     152             : 
     153             :   /**
     154             :    * @return the length of a single loop of this image. If this image is not
     155             :    * finished decoding, is not animated, or it is animated but does not loop,
     156             :    * returns FrameTimeout::Forever().
     157             :    */
     158             :   FrameTimeout LoopLength() const;
     159             : 
     160             :   /*
     161             :    * Get or set the timeout for the first frame. This is used to allow animation
     162             :    * scheduling even before a full decode runs for this image.
     163             :    */
     164           4 :   void SetFirstFrameTimeout(FrameTimeout aTimeout) { mFirstFrameTimeout = aTimeout; }
     165           6 :   FrameTimeout FirstFrameTimeout() const { return mFirstFrameTimeout; }
     166             : 
     167             : private:
     168             :   friend class FrameAnimator;
     169             : 
     170             :   //! Area of the first frame that needs to be redrawn on subsequent loops.
     171             :   gfx::IntRect mFirstFrameRefreshArea;
     172             : 
     173             :   //! the time that the animation advanced to the current frame
     174             :   TimeStamp mCurrentAnimationFrameTime;
     175             : 
     176             :   //! The number of frames of animation this image has.
     177             :   uint32_t mFrameCount;
     178             : 
     179             :   //! The current frame index we're on, in the range [0, mFrameCount).
     180             :   uint32_t mCurrentAnimationFrameIndex;
     181             : 
     182             :   //! number of loops remaining before animation stops (-1 no stop)
     183             :   int32_t mLoopRemainingCount;
     184             : 
     185             :   //! The total number of loops for the image.
     186             :   int32_t mLoopCount;
     187             : 
     188             :   //! The length of a single loop through this image.
     189             :   Maybe<FrameTimeout> mLoopLength;
     190             : 
     191             :   //! The timeout for the first frame of this image.
     192             :   FrameTimeout mFirstFrameTimeout;
     193             : 
     194             :   //! The animation mode of this image. Constants defined in imgIContainer.
     195             :   uint16_t mAnimationMode;
     196             : 
     197             :   /**
     198             :    * The following four bools (mHasBeenDecoded, mIsCurrentlyDecoded,
     199             :    * mCompositedFrameInvalid, mDiscarded) track the state of the image with
     200             :    * regards to decoding. They all start out false, including mDiscarded,
     201             :    * because we want to treat being discarded differently from "not yet decoded
     202             :    * for the first time".
     203             :    *
     204             :    * (When we are decoding the image for the first time we want to show the
     205             :    * image at the speed of data coming in from the network or the speed
     206             :    * specified in the image file, whichever is slower. But when redecoding we
     207             :    * want to show nothing until the frame for the current time has been
     208             :    * decoded. The prevents the user from seeing the image "fast forward"
     209             :    * to the expected spot.)
     210             :    *
     211             :    * When the image is decoded for the first time mHasBeenDecoded and
     212             :    * mIsCurrentlyDecoded get set to true. When the image is discarded
     213             :    * mIsCurrentlyDecoded gets set to false, and mCompositedFrameInvalid
     214             :    * & mDiscarded get set to true. When we create a decoder to redecode the
     215             :    * image mDiscarded gets set to false. mCompositedFrameInvalid gets set to
     216             :    * false when we are able to advance to the frame that should be showing
     217             :    * for the current time. mIsCurrentlyDecoded gets set to true when the
     218             :    * redecode finishes.
     219             :    */
     220             : 
     221             :   //! Whether this image has been decoded at least once.
     222             :   bool mHasBeenDecoded;
     223             : 
     224             :   //! Whether this image is currently fully decoded.
     225             :   bool mIsCurrentlyDecoded;
     226             : 
     227             :   //! Whether the composited frame is valid to draw to the screen, note that
     228             :   //! the composited frame can exist and be filled with image data but not
     229             :   //! valid to draw to the screen.
     230             :   bool mCompositedFrameInvalid;
     231             : 
     232             :   //! Whether this image is currently discarded. Only set to true after the
     233             :   //! image has been decoded at least once.
     234             :   bool mDiscarded;
     235             : };
     236             : 
     237             : /**
     238             :  * RefreshResult is used to let callers know how the state of the animation
     239             :  * changed during a call to FrameAnimator::RequestRefresh().
     240             :  */
     241             : struct RefreshResult
     242             : {
     243          42 :   RefreshResult()
     244          42 :     : mFrameAdvanced(false)
     245          42 :     , mAnimationFinished(false)
     246          42 :   { }
     247             : 
     248             :   /// Merges another RefreshResult's changes into this RefreshResult.
     249          22 :   void Accumulate(const RefreshResult& aOther)
     250             :   {
     251          22 :     mFrameAdvanced = mFrameAdvanced || aOther.mFrameAdvanced;
     252          22 :     mAnimationFinished = mAnimationFinished || aOther.mAnimationFinished;
     253          22 :     mDirtyRect = mDirtyRect.Union(aOther.mDirtyRect);
     254          22 :   }
     255             : 
     256             :   // The region of the image that has changed.
     257             :   gfx::IntRect mDirtyRect;
     258             : 
     259             :   // If true, we changed frames at least once. Note that, due to looping, we
     260             :   // could still have ended up on the same frame!
     261             :   bool mFrameAdvanced : 1;
     262             : 
     263             :   // Whether the animation has finished playing.
     264             :   bool mAnimationFinished : 1;
     265             : };
     266             : 
     267             : class FrameAnimator
     268             : {
     269             : public:
     270           2 :   FrameAnimator(RasterImage* aImage, const gfx::IntSize& aSize)
     271           2 :     : mImage(aImage)
     272             :     , mSize(aSize)
     273           2 :     , mLastCompositedFrameIndex(-1)
     274             :   {
     275           2 :      MOZ_COUNT_CTOR(FrameAnimator);
     276           2 :   }
     277             : 
     278           0 :   ~FrameAnimator()
     279           0 :   {
     280           0 :     MOZ_COUNT_DTOR(FrameAnimator);
     281           0 :   }
     282             : 
     283             :   /**
     284             :    * Re-evaluate what frame we're supposed to be on, and do whatever blending
     285             :    * is necessary to get us to that frame.
     286             :    *
     287             :    * Returns the result of that blending, including whether the current frame
     288             :    * changed and what the resulting dirty rectangle is.
     289             :    */
     290             :   RefreshResult RequestRefresh(AnimationState& aState,
     291             :                                const TimeStamp& aTime,
     292             :                                bool aAnimationFinished);
     293             : 
     294             :   /**
     295             :    * Get the full frame for the current frame of the animation (it may or may
     296             :    * not have required compositing). It may not be available because it hasn't
     297             :    * been decoded yet, in which case we return an empty LookupResult.
     298             :    */
     299             :   LookupResult GetCompositedFrame(AnimationState& aState);
     300             : 
     301             :   /**
     302             :    * Collect an accounting of the memory occupied by the compositing surfaces we
     303             :    * use during animation playback. All of the actual animation frames are
     304             :    * stored in the SurfaceCache, so we don't need to report them here.
     305             :    */
     306             :   void CollectSizeOfCompositingSurfaces(nsTArray<SurfaceMemoryCounter>& aCounters,
     307             :                                         MallocSizeOf aMallocSizeOf) const;
     308             : 
     309             : private: // methods
     310             :   /**
     311             :    * Advances the animation. Typically, this will advance a single frame, but it
     312             :    * may advance multiple frames. This may happen if we have infrequently
     313             :    * "ticking" refresh drivers (e.g. in background tabs), or extremely short-
     314             :    * lived animation frames.
     315             :    *
     316             :    * @param aTime the time that the animation should advance to. This will
     317             :    *              typically be <= TimeStamp::Now().
     318             :    *
     319             :    * @returns a RefreshResult that shows whether the frame was successfully
     320             :    *          advanced, and its resulting dirty rect.
     321             :    */
     322             :   RefreshResult AdvanceFrame(AnimationState& aState,
     323             :                              DrawableSurface& aFrames,
     324             :                              TimeStamp aTime);
     325             : 
     326             :   /**
     327             :    * Get the @aIndex-th frame in the frame index, ignoring results of blending.
     328             :    */
     329             :   RawAccessFrameRef GetRawFrame(DrawableSurface& aFrames,
     330             :                                 uint32_t aFrameNum) const;
     331             : 
     332             :   /// @return the given frame's timeout if it is available
     333             :   Maybe<FrameTimeout> GetTimeoutForFrame(AnimationState& aState,
     334             :                                          DrawableSurface& aFrames,
     335             :                                          uint32_t aFrameNum) const;
     336             : 
     337             :   /**
     338             :    * Get the time the frame we're currently displaying is supposed to end.
     339             :    *
     340             :    * In the error case (like if the requested frame is not currently
     341             :    * decoded), returns None().
     342             :    */
     343             :   Maybe<TimeStamp> GetCurrentImgFrameEndTime(AnimationState& aState,
     344             :                                              DrawableSurface& aFrames) const;
     345             : 
     346             :   bool DoBlend(DrawableSurface& aFrames,
     347             :                gfx::IntRect* aDirtyRect,
     348             :                uint32_t aPrevFrameIndex,
     349             :                uint32_t aNextFrameIndex);
     350             : 
     351             :   /** Clears an area of <aFrame> with transparent black.
     352             :    *
     353             :    * @param aFrameData Target Frame data
     354             :    * @param aFrameRect The rectangle of the data pointed ot by aFrameData
     355             :    *
     356             :    * @note Does also clears the transparency mask
     357             :    */
     358             :   static void ClearFrame(uint8_t* aFrameData, const gfx::IntRect& aFrameRect);
     359             : 
     360             :   //! @overload
     361             :   static void ClearFrame(uint8_t* aFrameData, const gfx::IntRect& aFrameRect,
     362             :                          const gfx::IntRect& aRectToClear);
     363             : 
     364             :   //! Copy one frame's image and mask into another
     365             :   static bool CopyFrameImage(const uint8_t* aDataSrc, const gfx::IntRect& aRectSrc,
     366             :                              uint8_t* aDataDest, const gfx::IntRect& aRectDest);
     367             : 
     368             :   /**
     369             :    * Draws one frame's image to into another, at the position specified by
     370             :    * aSrcRect.
     371             :    *
     372             :    * @aSrcData the raw data of the current frame being drawn
     373             :    * @aSrcRect the size of the source frame, and the position of that frame in
     374             :    *           the composition frame
     375             :    * @aSrcPaletteLength the length (in bytes) of the palette at the beginning
     376             :    *                    of the source data (0 if image is not paletted)
     377             :    * @aSrcHasAlpha whether the source data represents an image with alpha
     378             :    * @aDstPixels the raw data of the composition frame where the current frame
     379             :    *             is drawn into (32-bit ARGB)
     380             :    * @aDstRect the size of the composition frame
     381             :    * @aBlendMethod the blend method for how to blend src on the composition
     382             :    * frame.
     383             :    */
     384             :   static nsresult DrawFrameTo(const uint8_t* aSrcData,
     385             :                               const gfx::IntRect& aSrcRect,
     386             :                               uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
     387             :                               uint8_t* aDstPixels, const gfx::IntRect& aDstRect,
     388             :                               BlendMethod aBlendMethod,
     389             :                               const Maybe<gfx::IntRect>& aBlendRect);
     390             : 
     391             : private: // data
     392             :   //! A weak pointer to our owning image.
     393             :   RasterImage* mImage;
     394             : 
     395             :   //! The intrinsic size of the image.
     396             :   gfx::IntSize mSize;
     397             : 
     398             :   /** For managing blending of frames
     399             :    *
     400             :    * Some animations will use the compositingFrame to composite images
     401             :    * and just hand this back to the caller when it is time to draw the frame.
     402             :    * NOTE: When clearing compositingFrame, remember to set
     403             :    *       lastCompositedFrameIndex to -1.  Code assume that if
     404             :    *       lastCompositedFrameIndex >= 0 then compositingFrame exists.
     405             :    */
     406             :   RawAccessFrameRef mCompositingFrame;
     407             : 
     408             :   /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
     409             :    *
     410             :    * The Previous Frame (all frames composited up to the current) needs to be
     411             :    * stored in cases where the image specifies it wants the last frame back
     412             :    * when it's done with the current frame.
     413             :    */
     414             :   RawAccessFrameRef mCompositingPrevFrame;
     415             : 
     416             :   //! Track the last composited frame for Optimizations (See DoComposite code)
     417             :   int32_t mLastCompositedFrameIndex;
     418             : };
     419             : 
     420             : } // namespace image
     421             : } // namespace mozilla
     422             : 
     423             : #endif // mozilla_image_FrameAnimator_h

Generated by: LCOV version 1.13