DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (31ec81b5d7bb)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/* -*- 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);

  /**
   * 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();

  /**
   * Number of times to loop the image.
   * @note -1 means forever.
   */
  void SetLoopCount(int32_t aLoopCount);

  /**
   * 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 0.
   */
  uint32_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 mLoopCount;

  //! 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_ */